? mapstraction
Index: mapstraction-map.tpl.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mapstraction/Attic/mapstraction-map.tpl.php,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 mapstraction-map.tpl.php
--- mapstraction-map.tpl.php	2 Mar 2010 19:40:39 -0000	1.1.2.2
+++ mapstraction-map.tpl.php	17 Jun 2010 05:55:46 -0000
@@ -7,6 +7,8 @@
  *
  * script code
  *   $api_script
+ * placeholder
+ *   $content
  * div attributes
  *   $width
  *   $height
@@ -14,4 +16,6 @@
  */
 ?>
 <?php print $api_script; ?>
-<div id="<?php print $map_id; ?>" style="width: <?php print $width; ?>; height: <?php print $height; ?>;"></div>
\ No newline at end of file
+<div id="<?php print $map_id; ?>" style="width: <?php print $width; ?>; height: <?php print $height; ?>;">
+  <?php print $content; ?>
+</div>
Index: mapstraction.apis.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mapstraction/mapstraction.apis.inc,v
retrieving revision 1.1.2.6.2.2
diff -u -p -r1.1.2.6.2.2 mapstraction.apis.inc
--- mapstraction.apis.inc	2 Jun 2010 17:51:37 -0000	1.1.2.6.2.2
+++ mapstraction.apis.inc	17 Jun 2010 05:55:46 -0000
@@ -18,6 +18,117 @@ function mapstraction_basic_render($sett
   return '<script type="text/javascript" src="' . $src . '"></script>';
 }
 
+/**
+ * A basic content callback that informs the user that Javascript is required to view the map.
+ */
+function mapstraction_basic_content($settings, $api_id, $mapid, $rows) {
+  return t('Javascript must be enabled to view the map.');
+}
+
+/**
+ * Validate the view style options/settings form.
+ *
+ * Check width and height are in pixels.
+ */
+function mapstraction_googlestatic_validate_settings($form, &$form_state) {
+  // Make the relevent part of $form_state more convenient to access and modify.
+  $settings = &$form_state['values']['style_options'];
+  if (!isset($settings['controls']['googlestatic'])) {
+    // Initialize the area to store user input that has been validated and processed.
+    $settings['controls']['googlestatic'] = array();
+  }
+
+  // The suffix of the user input value should be px.
+  $px = 'px';
+  $substr_len = 0 - strlen($px);
+  foreach (array('width', 'height') as $d) {
+    $size = (Integer) substr($settings[$d], 0, $substr_len);
+    $suffix = substr($settings[$d], $substr_len);
+    // Size of 1 would also be invalid.  What use is a 1px map!?
+    if ($size > 1 && $suffix === $px) {
+      $settings['controls']['googlestatic'][$d] = $size;
+    }
+    else {
+      // The user input is not valid.
+      $message = t('Height and width must be in pixels (px) when using Google Static Maps.  For example; "<em>200px</em>".  Static maps use &lt;img&gt; tags.');
+      form_set_error('style_options_dimensions', $message);
+    }
+  }
+}
+
+/**
+ * Renders a google static image map.
+ *
+ * E.g. http://maps.google.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=14&size=512x512&maptype=roadmap&markers=color:blue|label:S|40.702147,-74.015794&markers=color:green|label:G|40.711614,-74.012318&markers=color:red|color:red|label:C|40.718217,-73.998284&sensor=false
+ * @see http://code.google.com/apis/maps/documentation/staticmaps/#URL_Parameters
+ */
+function mapstraction_googlestatic_content($settings, $provider, $id, $rows) {
+  // The validator already checked that the dimensions are in pixels, and saved them as integers.
+  $width = $settings['controls']['googlestatic']['width'];
+  $height = $settings['controls']['googlestatic']['height'];
+
+  // Force the <img> width="" and height="" attributes.
+  $attributes = compact('width', 'height');
+
+  // Start building the query string parameters.  'size' and 'sensor' are the only ones that are absolutely required.
+  $query = array(
+    // Set the size parameter for the image src="" URI.
+    'size' => "{$width}x{$height}",
+    // Sensor is used for mobile devices, but is not yet supported in mapstraction.
+    // @see http://code.google.com/apis/maps/documentation/staticmaps/#Sensor
+    'sensor' => 'false',
+  );
+
+  $markers = '';
+  foreach ($rows as $grouping) {
+    // @todo How to handle grouping on maps.  Color?  Label?
+    // @todo Use $grouping[title] for <img alt=""> text?
+    foreach($grouping['markers'] as $label => $row) {
+      $latitude = $row['latitude'];
+      $longitude = $row['longitude'];
+      if (is_numeric($label)) {
+        $label++;
+      }
+      // Build the query string for markers manually, since it is of the form;
+      //    markers=123,234&markers=345,456
+      // However drupal_query_string_encode() and url() only build query strings of the form;
+      //    markers[]=123,234&markers[]=345,456
+      $markers .= "&markers=label:$label|$latitude,$longitude"; 
+    }
+  }
+
+  // 'center' and 'zoom' parameters are only required if there are no markers.
+  if (empty($markers) || empty($settings['initial_point']['auto'])) {
+    // Force valid values out of potentially bad ones.
+    $latitude = (Integer) $settings['initial_point']['latitude'];
+    $longitude = (Integer) $settings['initial_point']['longitude'];
+    $query['center'] = "{$latitude},{$longitude}";
+    $query['zoom'] = (Integer) $settings['initial_point']['zoom'];
+  }
+
+  // Map mxn and google's type constants.
+  $type_map = array(
+    'mxn.Mapstraction.ROAD' => 'roadmap',
+    'mxn.Mapstraction.SATELLITE' => 'satellite',
+    'mxn.Mapstraction.HYBRID' => 'hybrid',
+    'mxn.Mapstraction.PHYSICAL' => 'terrain',
+  );
+  // There are no other types. Don't check the default maptype exists first.
+  $query['maptype'] = $type_map[$settings['controls']['default_maptype']];
+  
+  // Set the language.
+  $query['language'] = $GLOBALS['language']->language;
+
+  // Build the query string so that we can append our manually built markers parameters.
+  $query = drupal_query_string_encode($query) . $markers;
+
+  // Build the URI for the <img src="" />.
+  $source = url('http://maps.google.com/maps/api/staticmap', array('external' => TRUE, 'query' => $query));
+
+  // @todo set useful alt="" and title="" attributes. Perhaps from Views' style options/settings form?
+  return theme('image', $source, '', '', $attributes, FALSE);
+}
+
 function mapstraction_yahoo_render($settings) {
   $src = 'http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=' . variable_get('mapstraction_api_'. $api_id, '');
   return '<script type="text/javascript" src="' . $src . '"></script>';
Index: mapstraction.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mapstraction/mapstraction.module,v
retrieving revision 1.1.2.7.2.10
diff -u -p -r1.1.2.7.2.10 mapstraction.module
--- mapstraction.module	4 Jun 2010 23:04:06 -0000	1.1.2.7.2.10
+++ mapstraction.module	17 Jun 2010 05:55:46 -0000
@@ -14,7 +14,7 @@ function mapstraction_theme() {
   return array(
     'mapstraction-map' => array(
       'template' => 'mapstraction-map',
-      'arguments' => array('api_script' => NULL, 'map_id' => NULL, 'width' => NULL, 'height' => NULL),
+      'arguments' => array('api_script' => NULL, 'map_id' => NULL, 'width' => NULL, 'height' => NULL, 'content' => NULL),
     ),
   );  
 }
@@ -63,7 +63,7 @@ function mapstraction_admin_settings(){
   );
   
   foreach(mapstraction_apis(TRUE) as $key => $api){
-    if($api['has_key']){
+    if (!empty($api['has_key'])){
       $form['mapstraction_keys']['mapstraction_api_'. $key] = array(
         '#type' => 'textfield',
         '#title' => $api['title'],
@@ -110,67 +110,83 @@ function mapstraction_apis($full = FALSE
     'google' => array(
       'title' => t('Google Maps'),
       'render' => 'mapstraction_basic_render',
+      'content' => 'mapstraction_basic_content',
       'src' => 'http://maps.google.com/maps?file=api&v=2&key=%key',
       'has_key' => TRUE
     ),
     'googlev3' => array(
       'title' => t('Google Maps V3'),
       'render' => 'mapstraction_basic_render',
+      'content' => 'mapstraction_basic_content',
       'src' => 'http://maps.google.com/maps/api/js?sensor=false',
-      'has_key' => FALSE
+    ),
+    'googlestatic' => array(
+      'title' => t('Google Static Maps'),
+      'content' => 'mapstraction_googlestatic_content',
+      'validate settings' => 'mapstraction_googlestatic_validate_settings'
     ),
     'map24' => array(
       'title' => t('Map24'),
       'render' => 'mapstraction_basic_render',
+      'content' => 'mapstraction_basic_content',
       'src' => 'http://api.maptp.map24.com/ajax?appkey=%key',
       'has_key' => TRUE
     ),
     'multimap' => array(
       'title' => t('MultiMap'),
       'render' => 'mapstraction_basic_render',
+      'content' => 'mapstraction_basic_content',
       'src' => 'http://developer.multimap.com/API/maps/1.2/%key',
       'has_key' => TRUE
     ),
     'openspace' => array(
       'title' => t('OpenSpace'),
       'render' => 'mapstraction_basic_render',
+      'content' => 'mapstraction_basic_content',
       'src' => 'http://openspace.ordnancesurvey.co.uk/osmapapi/openspace.js?key=%key',
       'has_key' => TRUE
     ),
     'viamichelin' => array(
       'title' => t('ViaMichelin'),
       'render' => 'mapstraction_basic_render',
+      'content' => 'mapstraction_basic_content',
       'src' => 'http://api.viamichelin.com/apijs/js/api.js?VMApiKey=%key',
       'has_key' => TRUE
     ),
     'yahoo' => array(
       'title' => t('Yahoo Maps'),
       'render' => 'mapstraction_yahoo_render',
+      'content' => 'mapstraction_basic_content',
       'has_key' => TRUE
     ),
     'mapquest' => array(
       'title' => t('MapQuest'),
       'render' => 'mapstraction_basic_render',
+      'content' => 'mapstraction_basic_content',
       'src' => 'http://btilelog.beta.mapquest.com/tilelog/transaction?transaction=script&key=%key&itk=true&v=5.3.0_RC5&ipkg=controls1',
       'has_key' => TRUE
     ),
     'microsoft' => array(
       'title' => t('Microsoft Virtual Earth'),
       'render' => 'mapstraction_microsoft_render',
+      'content' => 'mapstraction_basic_content',
     ),
     'openlayers' => array(
       'title' => t('OpenLayers'),
       'render' => 'mapstraction_openlayers_render',
+      'content' => 'mapstraction_basic_content',
     ),
     'freeearth' => array(
       'title' => t('FreeEarth'),
       'render' => 'mapstraction_freeearth_render',
+      'content' => 'mapstraction_basic_content',
     ),
     'cloudmade' => array(
       'title' => t('CloudMade'),
       'api' => 'openlayers',
       'settings form' => 'mapstraction_cloudmade_settings_form',
       'render' => 'mapstraction_cloudmade_render',
+      'content' => 'mapstraction_basic_content',
       'has_key' => TRUE
     ),
   );
@@ -195,43 +211,56 @@ function mapstraction_apis($full = FALSE
 function mapstraction_render_map($id, $provider, $settings, $rows = array()) {
   $apis = mapstraction_apis(TRUE);
   $api = $apis[$provider];
-  
+
   // Allow the API definition to override the API name.
-  $provider = $api['api'] ? $api['api'] : $provider;
+  $provider = !empty($api['api']) ? $api['api'] : $provider;
 
   // append unique name space to id
   $mapid = 'mapstraction-' . $id;
-  
+
+  $api_script = '';
   module_load_include('inc', 'mapstraction', 'mapstraction.apis');
-  if (function_exists($api['render'])) {
+  if (!empty($api['render']) && function_exists($api['render'])) {
     $api_script = call_user_func_array($api['render'], array($settings, $provider, $mapid));
   }
-    
+
+  $content = '';
+  if (!empty($api['content']) && function_exists($api['content'])) {
+    $content = call_user_func_array($api['content'], array($settings, $provider, $mapid, $rows));
+  }
+
   // use the libraries module if available, otherwise load from the module directory
-  $library_path =
-    module_exists('libraries')
-      ? libraries_get_path('mapstraction') . '/source'
-      : drupal_get_path('module', 'mapstraction') . '/mapstraction/source';
-
-  // load mxn core and provivder specific JS. Not using parameter approach due to drupal_add_js()
-  drupal_add_js($library_path . '/mxn.js');
-  drupal_add_js($library_path . '/mxn.core.js');
-  drupal_add_js($library_path . '/mxn.'. $provider .'.core.js');
-  drupal_add_js(drupal_get_path('module', 'mapstraction') . '/mapstraction.drupal.js');
-
-  $map = array(
-    'mapId' => $mapid,
-    'apiName' => $provider,
-    'markers' => $rows,
-    'controls' => $settings['controls'],
-    'initialPoint' => $settings['initial_point'],
-    'behaviours' => $settings['behaviours'],
-    'overlays' => $settings['overlays'],
-  );
+  if (module_exists('libraries')) {
+    $library_path = libraries_get_path('mapstraction') . '/source';
+  }
+  else {
+    $library_path = drupal_get_path('module', 'mapstraction') . '/mapstraction/source';
+  }
+
+  // Static maps are not supported in the javascript library.
+  $filename = "$library_path/mxn.$provider.core.js";
+  if (file_exists("./$filename")) {
+    // Load mxn core and provivder specific JS. Not using parameter approach due to drupal_add_js().
+    // The order is important.
+    drupal_add_js("$library_path/mxn.js");
+    drupal_add_js("$library_path/mxn.core.js");
+    drupal_add_js($filename);
+    drupal_add_js(drupal_get_path('module', 'mapstraction') . '/mapstraction.drupal.js');
+
+    $map = array(
+      'mapId' => $mapid,
+      'apiName' => $provider,
+      'markers' => $rows,
+      'controls' => $settings['controls'],
+      'initialPoint' => $settings['initial_point'],
+      'behaviours' => $settings['behaviours'],
+      'overlays' => $settings['overlays'],
+    );
+
+    // Add the map to Drupal.settings object in JS.
+    drupal_add_js(array('mapstraction' => array($map)), 'setting');
+  }
 
-  // Add the map to Drupal.settings object in JS.
-  drupal_add_js(array('mapstraction' => array($map)), 'setting');
-  
   // assume px dimensions if no other measure provided
   if (is_numeric($settings['width'])){
     $settings['width'] = $settings['width'] . 'px';
@@ -239,8 +268,6 @@ function mapstraction_render_map($id, $p
   if (is_numeric($settings['height'])){
     $settings['height'] = $settings['height'] . 'px';
   }
-  
-  return theme('mapstraction-map', $api_script, $mapid, $settings['width'], $settings['height']);
-}
 
-?>
\ No newline at end of file
+  return theme('mapstraction-map', $api_script, $mapid, $settings['width'], $settings['height'], $content);
+}
Index: mapstraction_style_map.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mapstraction/mapstraction_style_map.inc,v
retrieving revision 1.1.2.13.2.12
diff -u -p -r1.1.2.13.2.12 mapstraction_style_map.inc
--- mapstraction_style_map.inc	6 Jun 2010 20:20:22 -0000	1.1.2.13.2.12
+++ mapstraction_style_map.inc	17 Jun 2010 05:55:47 -0000
@@ -58,7 +58,7 @@ class mapstraction_style_map extends vie
 
     foreach (mapstraction_apis(TRUE) as $key => $api) {
       module_load_include('inc', 'mapstraction', 'mapstraction.apis');
-      if (function_exists($api['settings form'])) {
+      if (isset($api['settings form']) && function_exists($api['settings form'])) {
         $form['api_settings'][$key] = $api['settings form']($this->options['api_settings'][$key], $key);
       }
     }
@@ -194,7 +194,7 @@ class mapstraction_style_map extends vie
       );
     }
     else {
-      $field_names[$field] = array('' => '--');
+      $field_names = array('' => '--');
       foreach ($handlers as $field => $handler) {
         if ($label = $handler->label()) {
           $field_names[$field] = $label;
@@ -234,6 +234,20 @@ class mapstraction_style_map extends vie
   }
 
   /**
+   * Options form validation handler.  Allow APIs to validate.
+   *
+   * @param string $form 
+   * @param string $form_state 
+   */
+  function options_validate($form, &$form_state) {
+    $api = $form_state['values']['style_options']['api'];
+    $function = "mapstraction_{$api}_validate_settings";
+    if (function_exists($function)) {
+      $function($form, &$form_state);
+    }
+  }
+
+  /**
    * Options form submit handler. Map zoom and maptype to a the controls group in the
    * form tree.
    *
@@ -273,7 +287,7 @@ class mapstraction_style_map extends vie
    * Return output that will render the view as a map
    */
   function render() {
-    if ($this->view->preview == TRUE && $this->view->live_preview) {
+    if (!empty($this->view->preview) && $this->view->preview && $this->view->live_preview) {
       return '<div class="messages error">Preview is disabled for the Mapstraction style plugin.</div>' . parent::render();
     }
     else {
