Skip to content
Snippets Groups Projects
gmap.module 40.8 KiB
Newer Older
  gmap_widget_setup($element['polystyle'], 'overlayedit_polystyle', $element['#map']);
  $element['polystyle']['polystyle_apply'] = array(
    '#tree' => FALSE,
    '#type' => 'checkbox',
    '#title' => t('Use for new and changed polygons'),
    '#default_value' => FALSE,
  );
  gmap_widget_setup($element['polystyle']['polystyle_apply'], 'overlayedit_polystyle_apply', $element['#map']);

  return $element;
}

/**
 * Alignment selector #process function.
 */
function process_gmap_align($element) {
  $element['#type'] = 'select';
  gmap_widget_setup($element, 'align');
  $element['#options'] = drupal_map_assoc(array('None', 'Right', 'Left', 'Center'));
  $element['#theme'] = 'gmap_align';
  return $element;
}

/**
 * Address widget #process function.
 */
function process_gmap_address($element) {
  $element['#type'] = 'textfield';
  gmap_widget_setup($element, 'address');
  $element['#theme'] = 'gmap_address';
  return $element;
}

/**
 * Marker chooser #process function.
 */
function process_gmap_markerchooser($element) {
  $element['#type'] = 'select';
  $element['#options'] = gmap_get_marker_titles();
  return $element;
}

/**
 * Overlay editor theme function.
 */
function theme_gmap_overlay_edit($element) {
  $path = drupal_get_path('module', 'gmap');
  drupal_add_js($path .'/js/gmap.js');
  drupal_add_js($path .'/js/gmap_shapes.js');
  drupal_add_js($path .'/js/overlay_edit.js');
  return theme('select', $element);
}

/**
 * Perform some normalization on the map object
 * to prevent errors.
 */
function gmap_map_cleanup(&$map) {
  // Google is picky about this one.
  $map['zoom'] = (int)$map['zoom'];
  // Normalize latitude / longitude
  if ($map['latlong']) {
    $map['latlon'] = $map['latlong'];
    unset($map['latlong']);
  }
  if (isset($map['latlon']) && (!isset($map['latitude']) || !isset($map['longitude']))) {
    list($map['latitude'], $map['longitude']) = explode(',', $map['latlon']);
  }
  unset($map['latlon']);

  foreach ($map['baselayers'] as $k => $v) {
    if (!$v) {
      unset($map['baselayers'][$k]);
    }
  }
}

function theme_gmap_coord($element) {
  //drupal_add_js
  return theme('textfield', $element);
}

function theme_gmap_macrotext($element) {
  drupal_add_js(drupal_get_path('module', 'gmap') .'/js/macro.js');
  // @@@
  drupal_add_js(drupal_get_path('module', 'gmap') .'/js/macrobuilder.js');
  return theme('textarea', $element);
}

function theme_gmap_address($element) {
  drupal_add_js(drupal_get_path('module', 'gmap') .'/js/address.js');
  return theme('textfield', $element);
}

function theme_gmap_align($element) {
  drupal_add_js(drupal_get_path('module', 'gmap') .'/js/align.js');
  return theme('select', $element);
}

/**
 * Gmap element theme hook
 */
function theme_gmap($element) {
  _gmap_doheader();

    // The default mapid is #map.
  if (isset($element['#settings']['id'])) {
    // Settings overrides it.
    $mapid = $element['#settings']['id'];
  }
  if (!$mapid) {
    // Hmm, no mapid. Generate one.
    $mapid = gmap_get_auto_mapid();
  // Push the mapid back into #map.
  $element['#map'] = $mapid;
  gmap_widget_setup($element, 'gmap', $mapid);
  if (!$element['#settings']) {
    $element['#settings'] = array();
  }

  // Push the mapid back into #settings.
  $element['#settings']['id'] = $mapid;

  $map = array_merge(gmap_defaults(), $element['#settings']);
  gmap_map_cleanup($map);

  switch (strtolower($map['align'])) {
    case 'left':
      $element['#attributes']['class'] += ' gmap-left';
      break;
    case 'right':
      $element['#attributes']['class'] += ' gmap-right';
      break;
    case 'center':
    case 'centre':
      $element['#attributes']['class'] += ' gmap-center';
  }

  $style = array();
  $style[] = 'width: '. $map['width'];
  $style[] = 'height: '. $map['height'];

  $element['#attributes']['class'] = trim($element['#attributes']['class'] .'gmap gmap-map gmap-'. $mapid .'-gmap');

  // Some markup parsers (IE) don't handle empty inners well. Use the space to let users know javascript is required.
  // @@@ Bevan sez: Google static maps could be useful here.
  // @@@ Bdragon sez: Yeah, would be nice, but hard to guarantee functionality. Not everyone uses the static markerloader.
  $o = '<div style="'. implode('; ', $style) .';" id="'. $element['#id'] .'"'. drupal_attributes($element['#attributes']) .'>'. t('Javascript is required to view this map.') .'</div>';

  // $map can be manipulated by reference.
  foreach (module_implements('gmap') as $module) {
    call_user_func_array($module .'_gmap', array('pre_theme_map', &$map));
  }

  // Inline settings extend.
  $o .= '<script type="text/javascript">'."\n";
  $o .= "/* <![CDATA[ */\n";
  $o .= 'jQuery.extend(true, Drupal, { settings: '. drupal_to_js(array('gmap' => array($element['#map'] => $map))) ." });\n";
  $o .= "/* ]]> */\n";
  $o .= "</script>\n";
  return $o;
}

/**
 * Set up widget.
 * This function will change a form element's ID so it is found
 * by the GMap handlers system.
 * @param &$element
 *   The form element to modify.
 * @param $type
 *   The gmap widget type to map to.
 * @param $map
 *   The map id. If not defined, $element['#map'] will be used.
 * @return
 *   None.
 */
function gmap_widget_setup(&$element, $type, $map=NULL) {
  if (!$map) {
    if (isset($element['#map'])) {
      $map = $element['#map'];
    }
    else {
      // Hmm, missing #map. Try to figure it out.
      if (isset($element['#settings']['id'])) {
        $map = $element['#settings']['id'];
      }
    }
  }
Brandon Bergren's avatar
Brandon Bergren committed
  if (!isset($element['#attributes']['class'])) {
    $element['#attributes']['class'] = '';
  }
  $element['#attributes']['class'] = trim(implode(' ', array(
    $element['#attributes']['class'],
    'gmap-control',
    'gmap-'. $type,
  )));
  $element['#id'] = gmap_get_id($map, $type);
  $element['#map'] = $map;
}

/**
 * Get a CSS id for a map and type.
 * Since CSS ids have to be unique, GMap related IDs are assigned by
 * this function.
 */
function gmap_get_id($map, $type) {
  static $serial = array();
  if (!isset($serial[$map])) {
    $serial[$map] = array();
  }
  if (!isset($serial[$map][$type])) {
    $serial[$map][$type] = -1;
  }
  $serial[$map][$type]++;
  return 'gmap-'. $map .'-'. $type . $serial[$map][$type];
}

/**
 * Generate a dynamic map identifier.
 */
function gmap_get_auto_mapid() {
  static $auto = 0;
  $auto++;
  return 'auto'. $auto .'map';
}

/**
 * Get the list of marker titles.
 */
function gmap_get_marker_titles($reset = FALSE) {
  static $titles;
  if (is_array($titles) && !$reset) {
    return $titles;
  }

  $titles = cache_get('gmap_marker_titles');
  if ($titles) {
    $titles = $titles->data;
  }

  if ($reset || !$titles) {
    require_once(drupal_get_path('module', 'gmap') .'/gmap_markerinfo.inc');
    $titles = _gmap_get_marker_titles();
  }
  cache_set('gmap_marker_titles', $titles, 'cache');
  return $titles;
}

/**
 * Get the JSON icon data for all the default markers.
 */
function gmap_get_icondata($reset = FALSE) {
  static $icons;
  if (is_array($icons) && !$reset) {
    return $icons;
  }

  $icons = cache_get('gmap_icondata');
  if ($icons) {
    $icons = $icons->data;
  }

  if ($reset || !$icons) {
    require_once(drupal_get_path('module', 'gmap') .'/gmap_markerinfo.inc');
    $icons = _gmap_get_icondata();
  }
  cache_set('gmap_icondata', $icons, 'cache');
  return $icons;
}

/**
 * Utility function to allow high-precision decimals to work with the SQL layer.
 * Use concatenation. (Apparently unquoted %s is bad.)
 */
function gmap_decimal($num) {
  // Paraphrased from postgresql documentation:
  //
  // Numbers in SQL can be in one of these forms:
  //   digits
  //   digits.[digits][e[+-]digits]
  //   [digits].digits[e[+-]digits]
  //   digitse[+-]digits
  // where "digits" is one or more decimal digits.

  // Trim extra whitespace
  $num = trim($num);
  // Check if we're in an acceptable form.
  if (preg_match('/^[+\-]?((\d+)|(\d+\.\d*)|(\d*\.\d+))(e[+\-]?\d+)?$/', $num)===1) {
    // Good, we can pass that right along.
    return $num;
  }
  // Otherwise, cast to float, possibly losing precision.
  return (float) $num;
}

/**
 * Utility function to use the google maps geocoder server side.
 * This is an easy, quick way to geocode a single address.
 * Note: This is a REMOTE CALL TO GOOGLE. Do NOT use this where performance matters,
 * as it could possibly take several seconds for this function to return.
 * See http://www.google.com/apis/maps/documentation/reference.html#GGeoStatusCode
 *  for a description of the possible status codes.
 */
function gmap_geocode($address, $tld = 'com') {
  $key = variable_get('googlemap_api_key', '');
  if (module_exists('keys_api')) {
    $key = keys_api_get_key('gmap', $_SERVER['HTTP_HOST']);
  }
  $data = drupal_http_request('http://maps.google.'. $tld .'/maps/geo?q='. drupal_urlencode($address) .'&output=csv&key='. $key);
  if ($data->code == 200) {
    $r = explode(',', $data->data);
    return array(
      'status' => (int)$r[0],
      'accuracy' => (int)$r[1],
      'latitude' => $r[2],
      'longitude' => $r[3],
    );
  }
  // Non 200 is G_GEO_SERVER_ERROR (500).
  return array(
    'status' => 500,
  );
}

/**
 * Simple way to draw a map from inside a theme.
 * @param $latitude
 *   Latitude of marker.
 * @param $longitude
 *   Longitude of marker.
 * @param $markername
 *   Marker to use.
 *   '' will fall back to google's default marker.
 * @param $info
 *   What to show in the bubble when the marker is clicked.
 *   Leave blank if you don't want a bubble.
 * @param $zoom
 *   Map zoom.
 *   'default' will use the default zoom from the settings page.
 *   3 is usually a good value to use.
 * @param $width
 *   Map width.
 *   'default' will use the default width from the settings page.
 * @param $height
 *   Map height.
 *   'default' will use the default height from the settings page.
 * @param $autoshow
 *   If set to TRUE, automatically show the marker bubble.
 * @param $map
 *   Override parts of the map array.
 *   If you need to do much with this, you should probabaly be putting together
 *   the map array manually.
 */
function gmap_simple_map($latitude, $longitude, $markername = '', $info = '', $zoom = 'auto', $width = 'default', $height = 'default', $autoshow = FALSE, $map = array()) {
  $settings = array(
    'id' => gmap_get_auto_mapid(),
    'latitude' => $latitude,   // Center the map
    'longitude' => $longitude, // on the marker.
  );
  if ($zoom != 'default') {
    $settings['zoom'] = $zoom;
  }
  if ($width != 'default') {
    $settings['width'] = $width;
  }
  if ($height != 'default') {
    $settings['height'] = $height;
  }

  $settings['markers'] = array(array(
    'latitude' => $latitude,
    'longitude' => $longitude,
    'markername' => $markername,
    'offset' => 0,
  ));

  if (!empty($info)) {
    $settings['markers'][0]['text'] = $info;
  }

  if ($autoshow) {
    $settings['markers'][0]['autoclick'] = TRUE;
  }

  if (!empty($map)) {
    $settings = array_merge($settings, $map);
  }

  return theme('gmap', array('#settings' => $settings));
}

/**
 * Implementation of hook_keys_service(). (from the keys api)
 */
function gmap_keys_service() {
  return array(
    'gmap' => array(
      'name' => t('Gmap'),
      'description' => t('Google Maps API Key'),
    ),
  );
}