Skip to content
gmap.module 40.2 KiB
Newer Older
webgeer's avatar
webgeer committed
<?php
webgeer's avatar
webgeer committed

/**
 * @file
 * GMap Filters is a module to include Google Map in a module
 *
 * GMap filter allows the insertion of a googlemap in a module.  It has
 * a page to creat a macro and then a filter to convet the macro into the
 * html and javascript code required to insert a google map.
 */

Brandon Bergren's avatar
Brandon Bergren committed
// @@@ Remove these and generalize lines. @@@
// These are now stored in the map defaults, but not all the code uses it yet.
define('GMAP_LINECOLOR1', '#00cc00');
define('GMAP_LINECOLOR2', '#ff0000');
define('GMAP_LINECOLOR3', '#0000ff');
// @@@ Remove these and generalize lines. @@@

Brandon Bergren's avatar
Brandon Bergren committed
// Current minimum version: 2.113
// Minimum version last changed on: June 9 2008
// Reason: G_SATELLITE_3D_MAP support in gmap_addons. See http://code.google.com/apis/earth/.
Brandon Bergren's avatar
Brandon Bergren committed
//
// See http://groups.google.com/group/Google-Maps-API/web/api-version-changes
// for details on using other version numbers.
Brandon Bergren's avatar
Brandon Bergren committed
define('GMAP_API_VERSION', '2.115');
webgeer's avatar
webgeer committed
/**
Brandon Bergren's avatar
Brandon Bergren committed
 * Get the defaults for a gmap.
webgeer's avatar
webgeer committed
 */
Brandon Bergren's avatar
Brandon Bergren committed
function gmap_defaults() {
  $defaults = array(
Brandon Bergren's avatar
Brandon Bergren committed
    'width' => '300px',
    'height' => '200px',
    'zoom' => 3,
Brandon Bergren's avatar
Brandon Bergren committed
    'maxzoom' => 14,
Brandon Bergren's avatar
Brandon Bergren committed
    'controltype' => 'Small',
    'align' => 'None',
    'latlong' => '40,0',
    'maptype' => 'Map',
    'mtc' => 'standard',
    'baselayers' => array('Map', 'Satellite', 'Hybrid'),
    'styles' => array(
      'line_default' => array('0000ff', 5, 45, '', 0, 0),
      'poly_default' => array('000000', 3, 25, 'ff0000', 45),
    'line_colors' => array('#00cc00', '#ff0000', '#0000ff'),
  );
  $defaults['behavior'] = array();
  $m = array();
  $behaviors = module_invoke_all('gmap', 'behaviors', $m);
  foreach ($behaviors as $k => $v) {
    $defaults['behavior'][$k] = $v['default'];
  }
  $defaults = array_merge($defaults, variable_get('gmap_default', array()));
  return $defaults;
}

/**
 * Implementation of hook_gmap().
 */
function gmap_gmap($op, &$map) {
  switch ($op) {
    case 'macro':
      return array(
        'points' => array(
          'multiple' => TRUE,
        ),
        'markers' => array(
          'multiple' => TRUE,
        ),
        'feed' => array(
          'multiple' => TRUE,
        ),
      );
    case 'pre_theme_map':
      $path = drupal_get_path('module', 'gmap') .'/js/';
      // Activate markers if needed
      if ($map['behavior']['dynmarkers'] || !empty($map['markers'])) {
        // The marker data is not a real file. Work around this fact.
        static $header_set = FALSE;
        if (!$header_set) {
          $header_set = TRUE;
          drupal_add_js("/* GMap markers enabled. */</script>\n<script type=". '"text/javascript" src="'. url('map/markerdata.js') .'">', 'inline', 'header', FALSE, TRUE, FALSE);
        drupal_add_js($path .'icon.js');
        drupal_add_js($path .'marker.js');
        drupal_add_js($path . variable_get('gmap_mm_type', 'gmap') .'_marker.js');
      }
      if ($map['behavior']['locpick']) {
        drupal_add_js($path .'locpick.js');
      if (variable_get('gmap_load_zoom_plugin', TRUE) && !$map['behavior']['nomousezoom']) {
        drupal_add_js(drupal_get_path('module', 'gmap') .'/thirdparty/mousewheel.js');
      }
      if ($map['markers'] || $map['lines']) {
        drupal_add_js($path .'markerloader_static.js');
      }
      if ($map['shapes']) {
        drupal_add_js($path .'shapeloader_static.js');
        drupal_add_js($path .'gmap_shapes.js');
      }
      if (is_array($map['feed'])) {
        drupal_add_js($path .'markerloader_georss.js');
    case 'macro_multiple':
      return array('points', 'markers', 'feed', 'circle', 'rpolygon', 'polygon', 'line');
    case 'behaviors':
      return array(
        'locpick' => array(
          'title' => t('Location chooser'),
          'default' => FALSE,
          'help' => t('Used to activate location choosing using a gmap.'),
          'internal' => TRUE,
        ),
        'nodrag' => array(
          'title' => t('Disable dragging'),
          'default' => FALSE,
          'help' => t('Remove the ability for the user to drag the map. If dragging is disabled, keyboard shortcuts are implicitly disabled.'),
        ),
        'nokeyboard' => array(
          'title' => t('Disable keyboard'),
          'default' => TRUE,
          'help' => t('Disable the keyboard shortcuts.'),
        ),
        'nomousezoom' => array(
          'title' => t('Disable mousezoom'),
          'default' => FALSE,
          'help' => t('Disable using the scroll wheel to zoom the map.'),
        ),
        'autozoom' => array(
          'title' => t('Use AutoZoom'),
          'default' => FALSE,
          'help' => t('Automatically zoom the map to fit all markers when markers are added.'),
        ),
        'dynmarkers' => array(
          'title' => t('Unconditionally enable marker interface'),
          'default' => FALSE,
          'help' => t('Load the marker loader system even if no markers to load are detected. Useful if you are injecting markers from somewhere else.'),
        ),
Brandon Bergren's avatar
Brandon Bergren committed
        'overview' => array(
          'title' => t('Enable Overview Map'),
          'default' => FALSE,
          'help' => t('Enable the "overview map" in the bottom right corner.'),
Brandon Bergren's avatar
Brandon Bergren committed
        ),
          'title' => t('Disable map type control'),
          'default' => FALSE,
          'help' => t('Removes the map type control from the upper right corner. Recommended for very narrow maps.'),
Brandon Bergren's avatar
Brandon Bergren committed
        'collapsehack' => array(
          'title' => t('Work around bugs when maps appear in collapsible fieldsets'),
          'default' => FALSE,
          'help' => t('Enabling this will work around some issues that can occur when maps appear inside collapsible fieldsets.'),
        ),
Brandon Bergren's avatar
Brandon Bergren committed
        // Note to myself, who keeps forgetting what a scale control actually IS.:
        // |------------  1mi ------------|
        'scale' => array(
          'title' => t('Add scale control to map.'),
          'default' => FALSE,
          'help' => t('Adds a scale control to the map in the default position.'),
      break;

    case 'baselayers':
      $map['Google']['Map'] = array(
        'title' => t('Map: Standard street map.'),
        'default' => TRUE,
        'help' => t('The standard default street map. Internal name: G_NORMAL_MAP'),
      );
      $map['Google']['Satellite'] = array(
        'title' => t('Satellite: Standard satellite map.'),
        'default' => TRUE,
        'help' => t('Satellite view without street overlay. Internal name: G_SATELLITE_MAP'),
      );
      $map['Google']['Hybrid'] = array(
        'title' => t('Hybrid: Hybrid satellite map.'),
        'default' => TRUE,
        'help' => t('Satellite view with street overlay. Internal name: G_HYBRID_MAP'),
      );
      $map['Google']['Physical'] = array(
        'title' => t('Terrain: Physical feature map.'),
        'default' => FALSE,
        'help' => t('Map with physical data (terrain, vegetation.) Internal name: G_PHYSICAL_MAP'),
      );
      break;
Brandon Bergren's avatar
Brandon Bergren committed
}
webgeer's avatar
webgeer committed

Brandon Bergren's avatar
Brandon Bergren committed
/**
 * Set up the HTML header for GMap.
 */
function _gmap_doheader() {
Brandon Bergren's avatar
Brandon Bergren committed
  static $gmap_initialized = FALSE;
  if ($gmap_initialized) {
    return;
webgeer's avatar
webgeer committed
  }
  $gmap_path = drupal_get_path('module', 'gmap');
Brandon Bergren's avatar
Brandon Bergren committed
  drupal_add_css($gmap_path .'/gmap.css');
  drupal_add_js($gmap_path .'/js/gmap.js');
  $mm = variable_get('gmap_mm_type', 'gmap');
  if ($mm=='clusterer') {
    drupal_add_js($gmap_path .'/js/icon.js');
    drupal_add_js($gmap_path .'/thirdparty/Clusterer2.js');
  drupal_add_js($gmap_path .'/js/marker.js');
  drupal_add_js($gmap_path .'/js/'. $mm .'_marker.js');
Brandon Bergren's avatar
Brandon Bergren committed
  $mms = variable_get('gmap_markermanager', array());
  if (empty($mms[$mm])) {
    $mms[$mm] = array();
  }
  drupal_add_js(array('gmap_markermanager' => $mms[$mm]), 'setting');
Brandon Bergren's avatar
Brandon Bergren committed
// @@@
drupal_add_js($gmap_path .'/js/poly.js');
  $key = variable_get('googlemap_api_key', '');
  if (module_exists('keys_api')) {
Brandon Bergren's avatar
Brandon Bergren committed
    $key = keys_api_get_key('gmap', $_SERVER['HTTP_HOST']);
Brandon Bergren's avatar
Brandon Bergren committed
  drupal_set_html_head('<script src="'. check_url('http://maps.google.com/maps?file=api&v='. variable_get('gmap_api_version', GMAP_API_VERSION) .'&key='. $key) .'" type="text/javascript"></script>');

  drupal_add_js(array(
    'gmap_init' => array(
      'querypath' => base_path() .'map/query',
    ),
  ), 'setting');

Brandon Bergren's avatar
Brandon Bergren committed
  $gmap_initialized = TRUE;
/**
 * Parse a macro style definition.
 * Example: #111111/1/100/#111111/1
 */
function _gmap_parse_style($style) {
  $styles = explode('/', $style);

  // @@@ Todo: Fix up old xmaps stuff. Possibly detect by looking for array length 7?

  // Strip off # signs, they get added by code.
  if (isset($styles[0]) && substr($styles[0], 0, 1) == '#') {
    $styles[0] = substr($styles[0], 1);
  }
  if (isset($styles[3]) && substr($styles[3], 0, 1) == '#') {
    $styles[3] = substr($styles[3], 1);
  }

  // Assume anything > 0 and < 1.1 was an old representation.
  if ($styles[2] > 0 && $styles[2] < 1.1) {
    $styles[2] = $styles[2] * 100;
  }
  if (isset($styles[4])) {
    if ($styles[4] > 0 && $styles[4] < 1.1) {
      $styles[4] = $styles[4] * 100;
    }
  }

  return $styles;
}

webgeer's avatar
webgeer committed
/**
 * Convert a macro string into a GMap array.
webgeer's avatar
webgeer committed
 *
 * @param $instring
 *   Macro to process.
 * @param $ver
 *   Version to treat macro as.
 *   Set to 1 when processing very old macros, otherwise leave as is.
webgeer's avatar
webgeer committed
 * @return
webgeer's avatar
webgeer committed
 */
function gmap_parse_macro($instring, $ver = 2) {
  // Get a list of keys that are "multiple."
  $m = array();
  $multiple = module_invoke_all('gmap', 'macro_multiple', $m);
Brandon Bergren's avatar
Brandon Bergren committed
  // Remove leading and trailing tags
  if (substr(trim($instring), -1)==']') {
    $instring = substr(trim($instring), 0, -1);
webgeer's avatar
webgeer committed
  }
  if (substr($instring, 0, 5)=='[gmap') {
    $instring = substr($instring, 6);
webgeer's avatar
webgeer committed
  }
Brandon Bergren's avatar
Brandon Bergren committed
  // Chop the macro into an array
  $temp = explode('|', $instring);
Brandon Bergren's avatar
Brandon Bergren committed
  $m = array();
  foreach ($temp as $row) {
    $offset = strpos($row, '=');
Brandon Bergren's avatar
Brandon Bergren committed
    if ($offset !== FALSE) {
      $k = trim(substr($row, 0, $offset));
      $r = trim(substr($row, $offset+1));
Brandon Bergren's avatar
Brandon Bergren committed
      if (in_array($k, $multiple)) {
        // Things that can appear multiple times
        if (!isset($m[$k])) {
          $m[$k] = array();
        }
        $m[$k][] = $r;
Brandon Bergren's avatar
Brandon Bergren committed
        $m[$k] = $r;
Brandon Bergren's avatar
Brandon Bergren committed
  // Synonyms
  if ($m['type']) {
    $m['maptype'] = $m['type'];
    unset($m['type']);
  }
  if ($m['control']) {
    $m['controltype'] = $m['control'];
    unset($m['control']);
  }
Brandon Bergren's avatar
Brandon Bergren committed

Brandon Bergren's avatar
Brandon Bergren committed
  if (is_array($m['feed'])) {
    foreach ($m['feed'] as $k => $v) {
      $temp = explode('::', $v);
Brandon Bergren's avatar
Brandon Bergren committed
      // Normalize url
      if (substr($temp[1], 0, 1) == '/') {
        $temp[1] = substr($temp[1], 1);
Brandon Bergren's avatar
Brandon Bergren committed
      }
      $temp[1] = url($temp[1]);
      $m['feed'][$k] = array(
        'markername' => $temp[0],
        'url' => $temp[1],
      );
    }
  }
Brandon Bergren's avatar
Brandon Bergren committed

  // Merge points and markers
  if (!is_array($m['points'])) $m['points'] = array();
  if (!is_array($m['markers'])) $m['markers'] = array();
  $m['markers-temp'] = array_merge($m['points'], $m['markers']);
Brandon Bergren's avatar
Brandon Bergren committed
  unset($m['points']);
  unset($m['markers']);

  // all shapes in 1 array
  if ($m['circle']) {
    foreach ($m['circle'] as $shape) {
      $s = array('type' => 'circle');
      $cp = strpos($shape, ':');
      if ($cp !== FALSE) {
        $stylestr = substr($shape, 0, $cp);
        $s['style'] = _gmap_parse_style($stylestr);
        $shape = substr($shape, $cp+1);
      }
      $tmp = explode('+', $shape);
      $s['radius'] = $tmp[1] ? $tmp[1] : 100;
      if ($tmp[2]) $s['numpoints'] = trim($tmp[2]);
      $tmp = _gmap_str2coord($tmp[0]);
      $s['center'] = $tmp[0];
      $m['shapes'][] = $s;
    }
    unset($m['circle']);
  }
Brandon Bergren's avatar
Brandon Bergren committed
  // Fixup legacy lines.
  if ($m['line1']) {
    if (!isset($m['line'])) $m['line'] = array();
    $m['line'][] = GMAP_LINECOLOR1 .':'. $m['line1'];
    unset($m['line1']);
  }
  if ($m['line2']) {
    if (!isset($m['line'])) $m['line'] = array();
    $m['line'][] = GMAP_LINECOLOR2 .':'. $m['line3'];
    unset($m['line2']);
  }
  if ($m['line3']) {
    if (!isset($m['line'])) $m['line'] = array();
    $m['line'][] = GMAP_LINECOLOR3 .':'. $m['line3'];
    unset($m['line3']);
  }

  if ($m['line']) {
    foreach ($m['line'] as $shape) {
      $s = array('type' => 'line');
      $cp = strpos($shape, ':');
      if ($cp != FALSE) {
Brandon Bergren's avatar
Brandon Bergren committed
        $stylestr = substr($shape, 0, $cp);
        $s['style'] = _gmap_parse_style($stylestr);
Brandon Bergren's avatar
Brandon Bergren committed
        $shape = substr($shape, $cp+1);
      }
      $s['points'] = _gmap_str2coord($shape);
      $m['shapes'][] = $s;
    }
    unset($m['line']);
  }
  if ($m['rpolygon']) {
    foreach ($m['rpolygon'] as $shape) {
      $s = array('type' => 'rpolygon');
      $cp = strpos($shape, ':');
      if ($cp !== FALSE) {
        $stylestr = substr($shape, 0, $cp);
        $s['style'] = _gmap_parse_style($stylestr);
        $shape = substr($shape, $cp+1);
      }
      $tmp = explode('+', $shape);
      if ($tmp[2]) {
        $s['numpoints'] = (int)trim($tmp[2]);
        $tmp = array_slice($tmp, 0, 2);
      }
      $shape = implode('+', $tmp);
      $tmp = _gmap_str2coord($shape);
      $s['center'] = $tmp[0];
      $s['point2'] = $tmp[1];
      $m['shapes'][] = $s;
    }
    unset($m['rpolygon']);
  }
  if ($m['polygon']) {
    foreach ($m['polygon'] as $shape) {
      $s = array('type' => 'polygon');
      $cp = strpos($shape, ':');
      if ($cp !== FALSE) {
        $stylestr = substr($shape, 0, $cp);
        $s['style'] = _gmap_parse_style($stylestr);
        $shape = substr($shape, $cp+1);
      }
      $s['points'] = _gmap_str2coord($shape);
      $m['shapes'][] = $s;
    }
    unset($m['polygon']);
  }

Brandon Bergren's avatar
Brandon Bergren committed
  // Version 1 -> 2 conversion
  if ($ver == 1) {
Brandon Bergren's avatar
Brandon Bergren committed
    // Zoom is flipped
    if ($m['zoom']) {
      $m['zoom'] = 18 - $m['zoom'];
      if ($m['zoom'] < 1) {
        $m['zoom'] = 1;
      }
    }
  }

  // Center -> latitude and longitude
  if ($m['center']) {
    list($m['latitude'], $m['longitude']) = explode(',', $m['center']);
Brandon Bergren's avatar
Brandon Bergren committed
    unset($m['center']);
  }

Brandon Bergren's avatar
Brandon Bergren committed
  // Behavior
  if ($m['behaviour']) {
    $m['behavior'] = $m['behaviour'];
    unset($m['behaviour']);
  }
  if ($m['behavior']) {
    $m['behavior-temp'] = explode(' ', $m['behavior']);
Brandon Bergren's avatar
Brandon Bergren committed
    $m['behavior'] = array();
    foreach ($m['behavior-temp'] as $v) {
      $m['behavior'][substr($v, 1)] = (substr($v, 0, 1) == '+') ? TRUE : FALSE;
Brandon Bergren's avatar
Brandon Bergren committed
    }
    unset($m['behavior-temp']);
  }

Brandon Bergren's avatar
Brandon Bergren committed
  // tcontrol now is mtc.
Brandon Bergren's avatar
Brandon Bergren committed
  if ($m['tcontrol']) {
    if (strtolower(trim($m['tcontrol'])) == 'on') {
Brandon Bergren's avatar
Brandon Bergren committed
      $m['mtc'] = 'standard';
    }
    else {
      $m['mtc'] = 'none';
    }
    unset($m['tcontrol']);
  }

  // notype also controls mtc.
  if (isset($m['behavior']['notype'])) {
Brandon Bergren's avatar
Brandon Bergren committed
    if ($m['behavior']['notype']) {
      $m['mtc']= 'none';
    }
    unset($m['behavior']['notype']);
  }

  // Stuff that was converted to behavior flags

  // Scale control.
  if ($m['scontrol']) {
    if (strtolower(trim($m['scontrol'])) == 'on') {
      $m['behavior']['scale'] = TRUE;
    }
    else {
      $m['behavior']['scale'] = FALSE;
    }
    unset($m['scontrol']);
  }

  // Draggability.
  if ($m['drag']) {
    if (strtolower(trim($m['drag'])) == 'yes') {
      $m['behavior']['nodrag'] = FALSE;
Brandon Bergren's avatar
Brandon Bergren committed
    }
    else {
Brandon Bergren's avatar
Brandon Bergren committed
      $m['behavior']['nodrag'] = TRUE;
Brandon Bergren's avatar
Brandon Bergren committed
    }
Brandon Bergren's avatar
Brandon Bergren committed
    unset($m['drag']);
Brandon Bergren's avatar
Brandon Bergren committed
  }

Brandon Bergren's avatar
Brandon Bergren committed
  // Markers fixup
  foreach ($m['markers-temp'] as $t) {
    unset($markername);
    // Named?
    if (strpos($t, '::')) { // Single : gets handled below.
      list($markername, $t) = explode('::', $t, 2);
Brandon Bergren's avatar
Brandon Bergren committed
    }
    // Break down into points
    $points = explode('+', $t);
    $offset = -1;
Brandon Bergren's avatar
Brandon Bergren committed
    foreach ($points as $point) {
      $marker = array();
      $offset++;
Brandon Bergren's avatar
Brandon Bergren committed
      // Labelled?
      // @@@ Gmap allows both a tooltip and a popup, how to represent?
      if (strpos($point, ':')) {
        list($point, $marker['text']) = explode(':', $point, 2);
        $marker['text'] = theme('gmap_marker_popup', $marker['text']);
Brandon Bergren's avatar
Brandon Bergren committed
      }
      if (strpos($point, '%')) {
        list($point, $addons) = explode('%', $point, 2);
        $motemp = explode('%', $addons);
        foreach ($motemp as $option) {
          $marker['options'][trim($option)] = TRUE;
      list($marker['latitude'], $marker['longitude']) = explode(',', $point, 2);
Brandon Bergren's avatar
Brandon Bergren committed
      // Named markers get an offset too.
      if (isset($markername)) {
        $marker['markername'] = $markername;
        $marker['offset'] = $offset;
      }
      $m['markers'][] = $marker;
    }
  }
  unset($m['markers-temp']);

  // Assign an id if one wasn't specified.
  if (!$m['id']) {
    $m['id'] = gmap_get_auto_mapid();
  }

  // The macro can now be manipulated by reference.
  foreach (module_implements('gmap') as $module) {
    $additions = call_user_func_array($module .'_gmap', array('parse_macro', &$m));
    if (!empty($additions)) {
      foreach ($additions as $k => $v) {
        $m[$k] = $v;
      }
Brandon Bergren's avatar
Brandon Bergren committed
  return $m;
 * Parse "x.xxxxx , y.yyyyyy (+ x.xxxxx, y.yyyyy ...)" into an array of points.
 */
function _gmap_str2coord($str) {
  // Explode along + axis
  $arr = explode('+', $str);
  // Explode along , axis
  $points = array();
  foreach ($arr as $pt) {
    list($lat, $lon) = explode(',', $pt);
    $points[] = array((float)trim($lat), (float)trim($lon));
  }
  return $points;
}

/**
 * Theme a marker popup.
 * This will get called for markers embedded in macros.
 */
function theme_gmap_marker_popup($label) {
  return $label;
}

 * Location chooser utility function.
 *
 * Creates a map that can be interactively used to fill a form with a
 * location (latitude, longitude and zoom level).
 *
 * Note: This is a utility function designed for location.module, there is no
 * guarantee it will not be removed eventually.
webgeer's avatar
webgeer committed
 * @param $map
 * Either a macro to use as the base map for setting a location, or an already set map associative array.
 * @param $form
Brandon Bergren's avatar
Brandon Bergren committed
 * A formset associative array. Cannot be more than one deep.
webgeer's avatar
webgeer committed
 * @param $fields
 * An associative array for the field names.  'latitude', 'longitude'=>name of respective array, 'address' is optional.
 * @return
 * A string with the google map code to be inserted onto the page.
 *
 */
function gmap_set_location($map, &$form, $fields) {
  static $ctr = 0;
  $ctr++;
  if (!is_array($map)) {
    $map = array_merge(gmap_defaults(), gmap_parse_macro($map));
webgeer's avatar
webgeer committed
  }
  $id = 'loc'. $ctr;
Brandon Bergren's avatar
Brandon Bergren committed
  $map['id'] = $id;
  // This is a locpick map.
  $map['behavior']['locpick'] = TRUE;

Brandon Bergren's avatar
Brandon Bergren committed
  $element = array(
    '#type' => 'gmap',
    '#map' => $map['id'],
    '#settings' => $map,
  );

  $form[$fields['latitude']]['#map']=$id;
  gmap_widget_setup($form[$fields['latitude']], 'locpick_latitude');

  $form[$fields['longitude']]['#map']=$id;
  gmap_widget_setup($form[$fields['longitude']], 'locpick_longitude');
webgeer's avatar
webgeer committed
  if (isset($fields['address'])) {
    $form[$fields['address']]['#map'] = $id;
    gmap_widget_setup($form[$fields['address']], 'locpick_address');
webgeer's avatar
webgeer committed
  }
  return theme('gmap', $element);
/**
 * Handle filter preparation.
 */
webgeer's avatar
webgeer committed
function _gmap_prepare($intext) {
Brandon Bergren's avatar
Brandon Bergren committed
  preg_match_all('/\[gmap([^\[\]]+ )* \] /x', $intext, $matches);
webgeer's avatar
webgeer committed

  while (isset($matches[1][$i])) {
    $out[0][$i] = $matches[0][$i];
    if ($matches[1][$i][0] == '1') {
      $ver = 1;
      $matches[1][$i] = substr($matches[0][$i], 1);
webgeer's avatar
webgeer committed
    }
    else {
      $ver = 2;
webgeer's avatar
webgeer committed
    }
    $map = array('#settings' => gmap_parse_macro($matches[1][$i], $ver));
    $out[1][$i] = theme('gmap', $map);
webgeer's avatar
webgeer committed
    $i++;
  } // endwhile process macro
  return $out;
}

 * Make sure a string is a valid css dimension.
function gmap_todim($instring) {
  $s = strtolower($instring);
  $matches = array();
  if (preg_match('/([\d.]+)\s*(em|ex|px|in|cm|mm|pt|pc|%)/', $s, $matches)) {
    return $matches[1] . $matches[2];
    return FALSE;
/**
 * Ensure a textfield is a valid css dimension string.
 */
function gmap_dimension_validate(&$elem) {
  if (!gmap_todim($elem['#value'])) {
    form_error($elem, t('The specified value is not a valid CSS dimension.'));
  }
}

/**
 * Implementation of hook_filter().
 */
webgeer's avatar
webgeer committed
function gmap_filter($op, $delta = 0, $format = -1, $text = '') {
  switch ($op) {
    case 'list':
      return (array(0 => t('GMap filter')));

    case 'name':
      return t('Google map filter');

    case 'description':
      return t('converts a google map  macro into the html required for inserting a google map.');
webgeer's avatar
webgeer committed
    case 'process':
      $gmaps = _gmap_prepare($text);   //returns an array of $tables[0] = table macro $table[1]= table html
webgeer's avatar
webgeer committed
      if ($gmaps) {                    // there are table macros in this node
        return str_replace($gmaps[0], $gmaps[1], $text);
      }
      else {
        return $text;
      }

    case 'prepare':
      return $text;

      return TRUE; // @@@ Possibly improve efficiency in the future?
/**
 * Implementation of hook_filter_tips().
 */
function gmap_filter_tips($delta, $format, $long = FALSE) {
  if (user_access('create macro')) { // only display macro if user can create one
    return t('Insert Google Map macro.') .'<a href="'. url('map/macro') .'" target="_blank" >'. t('Create a macro') .'</a>';
  }
  else {
    return t('Insert Google Map macro.');
  }
/**
 * Implementation of hook_menu().
 */
webgeer's avatar
webgeer committed
function gmap_menu($may_cache) {
  if ($may_cache) {
    $items = array();
      'path' => 'map',
      'type' => MENU_ITEM_GROUPING,
      'title' => t('google maps'),
      'access' => user_access('create macro')||user_access('show user map')||user_access('show node map'),
Brandon Bergren's avatar
Brandon Bergren committed
    $items[] = array(
      'path' => 'admin/settings/gmap',
      'title' => t('GMap'),
      'description' => t('Configure GMap settings'),
      'callback' => 'drupal_get_form',
      'callback arguments' => 'gmap_admin_settings',
      'access' => user_access('administer site configuration'),
      'type' => MENU_NORMAL_ITEM,
    );
Brandon Bergren's avatar
Brandon Bergren committed
    $items[] = array(
      'path' => 'map/query',
      'type' => MENU_CALLBACK,
      'access' => user_access('access content'),
Brandon Bergren's avatar
Brandon Bergren committed
      'callback' => 'gmap_json_query',
    );
    $items[] = array(
      'path' => 'map/markerdata.js',
      'type' => MENU_CALLBACK,
      'access' => user_access('access content'),
      'callback' => 'gmap_markerdata_js',
    );
    return $items;
/**
 * Generate the markerdata file.
 */
function gmap_markerdata_js() {
  drupal_set_header('Content-Type: text/javascript');
  echo "// GMap marker image data.\n";
  echo "Drupal.gmap.iconpath = ". drupal_to_js(base_path() . drupal_get_path('module', 'gmap') .'/markers') .";\n";
  echo "Drupal.gmap.icondata = ". drupal_to_js(gmap_get_icondata()) .";\n";
}


Brandon Bergren's avatar
Brandon Bergren committed
/**
 * JSON request interface.
 */
function gmap_json_query() {
Brandon Bergren's avatar
Brandon Bergren committed
  if (arg(2)=='markers') {
    drupal_set_header('Content-Type: text/javascript');
      'path' => base_path() . drupal_get_path('module', 'gmap') .'/markers',
Brandon Bergren's avatar
Brandon Bergren committed
      'markers' => gmap_get_icondata(TRUE),
 * Settings page. (remove for d6)
Brandon Bergren's avatar
Brandon Bergren committed
function gmap_admin_settings() {
  require_once(drupal_get_path('module', 'gmap') .'/gmap_settings_ui.inc');
Brandon Bergren's avatar
Brandon Bergren committed
  return _gmap_admin_settings();
Brandon Bergren's avatar
Brandon Bergren committed
/**
 * Implementation of hook_elements().
 */
function gmap_elements() {
  return array(
    'gmap' => array(
      '#input' => FALSE, // This isn't a *form* input!!
      '#settings' => array_merge(gmap_defaults(), array(
Brandon Bergren's avatar
Brandon Bergren committed
        'points' => array(),
        'pointsOverlays' => array(),
        'lines' => array(),
Brandon Bergren's avatar
Brandon Bergren committed
      )),
      '#process' => array('expand_gmap' => array()),
    ),
Brandon Bergren's avatar
Brandon Bergren committed
    'gmap_macrotext' => array(
      '#input' => TRUE,
      '#cols' => 60,
      '#rows' => 5,
      '#process' => array(
        'process_gmap_control' => array('textarea', 'macrotext'),
Brandon Bergren's avatar
Brandon Bergren committed
      ),
    ),
Brandon Bergren's avatar
Brandon Bergren committed
    'gmap_overlay_edit' => array('#input' => FALSE, '#process' => array('process_gmap_overlay_edit' => array())),
    'gmap_style' => array('#input' => TRUE, '#tree' => TRUE, '#gmap_style_type' => 'poly', '#process' => array('process_gmap_style' => array())),
    'gmap_address' => array('#input' => FALSE, '#process' => array('process_gmap_address' => array())),
Brandon Bergren's avatar
Brandon Bergren committed
    'gmap_align' => array('#input' => TRUE, '#process' => array('process_gmap_align' => array())),
    'gmap_latitude' => array('#input' => TRUE, '#process' => array('process_gmap_control' => array('textfield', 'latitude', 'gmap_coord'))),
    'gmap_longitude' => array('#input' => TRUE, '#process' => array('process_gmap_control' => array('textfield', 'longitude', 'gmap_coord'))),
    'gmap_latlon' => array('#input' => TRUE, '#process' => array('process_gmap_control' => array('textfield', 'latlon', 'gmap_coord'))),
Brandon Bergren's avatar
Brandon Bergren committed
    'gmap_markerchooser' => array('#input' => TRUE, '#process' => array('process_gmap_markerchooser' => array())),
    'gmap_dimension' => array('#input' => TRUE, '#theme' => 'textfield', '#validate' => array('gmap_dimension_validate' => array())),
 * Gmap element #process function.
Brandon Bergren's avatar
Brandon Bergren committed
 */
function expand_gmap($element) {
  $mapid = 'map';
  if ($element['#map']) {
    $mapid = $element['#map'];
  }
Brandon Bergren's avatar
Brandon Bergren committed
  else {
    $element['#map'] = $mapid;
  }
  if (!$element['#settings']) {
    $element['#settings'] = array();
  }
  $element['#settings'] = array_merge(gmap_defaults(), array(
    'id' => $mapid,
Brandon Bergren's avatar
Brandon Bergren committed
    'points' => array(),
    'pointsOverlays' => array(),
  ), $element['#settings']);
Brandon Bergren's avatar
Brandon Bergren committed
  gmap_widget_setup($element, 'gmap');
Brandon Bergren's avatar
Brandon Bergren committed
  return $element;
}

/**
 * Generic gmap control #process function.
Brandon Bergren's avatar
Brandon Bergren committed
 */
function process_gmap_control($element, $edit, $fieldtype, $control, $theme='') {
    $element['#theme'] = 'gmap_'. $control;
/**
 * Style fieldset #process function.
 */
function process_gmap_style($element) {
  $isline = ($element['#gmap_style_type'] == 'line');
  // Stroke color
  $element[0] = array(
    '#type' => 'textfield',
    '#size' => 6,
    '#maxlength' => 6,
    '#field_prefix' => '#',
    '#title' => t('Stroke color'),
    '#value' => $element['#value'][0],
    '#attributes' => array('class' => 'gmap_style'),
  );
  // Stroke weight
  $element[1] = array(
    '#type' => 'textfield',
    '#title' => t('Stroke weight'),
    '#description' => t('Thickness of line, in pixels.'),
    '#size' => 3,
    '#maxlength' => 3,
    '#field_suffix' => t('px'),
    '#value' => $element['#value'][1],
    '#attributes' => array('class' => 'gmap_style'),
  );
  // Stroke opacity
  $element[2] = array(
    '#type' => 'textfield',
    '#title' => t('Stroke opacity'),
    '#size' => 3,
    '#maxlength' => 3,
    '#field_suffix' => '%',
    '#value' => $element['#value'][2],
    '#attributes' => array('class' => 'gmap_style'),
  );
  // Fill color
  $element[3] = array(
    '#type' => 'textfield',
    '#title' => t('Fill color'),
    '#description' => t('Hex color value for fill color. Example: #<em>00AA33</em>'),
    '#size' => 6,
    '#maxlength' => 6,
    '#field_prefix' => '#',
    '#value' => $element['#value'][3],
    '#disabled' => $isline,
    '#attributes' => array('class' => 'gmap_style'),
  );
  $element[4] = array(
    '#type' => 'textfield',
    '#title' => t('Fill opacity'),
    '#description' => t('Opacity of fill, from 0 to 100%.'),
    '#size' => 3,
    '#maxlength' => 3,
    '#field_suffix' => '%',
    '#value' => $element['#value'][4],
    '#disabled' => $isline,
    '#attributes' => array('class' => 'gmap_style'),
  );
  return $element;
}

/**
 * Theme a gmap_style fieldset.
 */
function theme_gmap_style($element) {
  // Fieldsets print #value at the end, so we need to empty it out.
  // Otherwise, it puts "Array" at the end of the fieldset.
  $element['#value'] = '';
  return theme('fieldset', $element, $element['#children']);
}

/**
 * Overlay editor #process function.
 */
Brandon Bergren's avatar
Brandon Bergren committed
function process_gmap_overlay_edit($element) {
Brandon Bergren's avatar
Brandon Bergren committed
  // Conver the root element into a fieldset.
  $element['#type'] = 'fieldset';
  if (!$element['#title']) {
    $element['#title'] = t('Overlay editor');
  }
  $element['#tree'] = TRUE;

Brandon Bergren's avatar
Brandon Bergren committed
  $element['mapclicktype'] = array(
    '#type' => 'select',
    '#title' => t('Click map'),
Brandon Bergren's avatar
Brandon Bergren committed
    '#map' => $element['#map'],
Brandon Bergren's avatar
Brandon Bergren committed
    '#options' => array(
      'Points' => t('Points'),
      'Lines' => t('Lines'),
      'Circles' => t('Circles'),
      'GPolygon' => t('Filled Polygons'),
Brandon Bergren's avatar
Brandon Bergren committed
    ),
  );
  gmap_widget_setup($element['mapclicktype'], 'overlayedit_mapclicktype');
Brandon Bergren's avatar
Brandon Bergren committed
  $element['markerclicktype'] = array(
    '#type' => 'select',
    '#title' => t('Click marker / segment'),
Brandon Bergren's avatar
Brandon Bergren committed
    '#map' => $element['#map'],
Brandon Bergren's avatar
Brandon Bergren committed
    '#options' => array(
      'Remove' => t('Remove'),
//      'updatestyle' => t('Update Styles'),
//      'removestyle' => t('Remove Styles'),
Brandon Bergren's avatar
Brandon Bergren committed
      'Edit Info' => t('Edit Info'),
    ),
  );
  gmap_widget_setup($element['markerclicktype'], 'overlayedit_markerclicktype');
Brandon Bergren's avatar
Brandon Bergren committed
  $element['marker'] = array(
    '#type' => 'select',
Brandon Bergren's avatar
Brandon Bergren committed
    '#map' => $element['#map'],
Brandon Bergren's avatar
Brandon Bergren committed
    '#options' => gmap_get_marker_titles(),
    '#title' => t('Marker'),
    '#theme' => 'gmap_overlay_edit',
  );
  gmap_widget_setup($element['marker'], 'overlayedit');

  $element['linestyle'] = array(
    '#type' => 'gmap_style',
    '#title' => t('Line style'),
    '#gmap_style_type' => 'line',
    '#default_value' => array('0000ff', 5, 45, '', ''), // @@@
Brandon Bergren's avatar
Brandon Bergren committed
  );
  gmap_widget_setup($element['linestyle'], 'overlayedit_linestyle', $element['#map']);
  $element['linestyle']['linestyle_apply'] = array(
    '#tree' => FALSE,
    '#type' => 'checkbox',
    '#title' => t('Use for new and changed lines'),
    '#default_value' => FALSE,
Brandon Bergren's avatar
Brandon Bergren committed
  );
  gmap_widget_setup($element['linestyle']['linestyle_apply'], 'overlayedit_linestyle_apply', $element['#map']);
Brandon Bergren's avatar
Brandon Bergren committed

  $element['polystyle'] = array(
    '#type' => 'gmap_style',
    '#title' => t('Polygon style'),