Remove gmap_views.module -- views support is now built in using the new conventions.
[project/gmap.git] / gmap.module
CommitLineData
bba8e92a
BB
1<?php
2// $Id$
3
4/**
5 * @file
6 * GMap Filters is a module to include Google Map in a module
7 *
8 * GMap filter allows the insertion of a googlemap in a module. It has
9 * a page to creat a macro and then a filter to convet the macro into the
10 * html and javascript code required to insert a google map.
11 */
12
bba8e92a
BB
13// Current minimum version: 2.113
14// Minimum version last changed on: June 9 2008
15// Reason: G_SATELLITE_3D_MAP support in gmap_addons. See http://code.google.com/apis/earth/.
16//
17// See http://groups.google.com/group/Google-Maps-API/web/api-version-changes
18// for details on using other version numbers.
19define('GMAP_API_VERSION', '2.115');
20
21/**
22 * Get the defaults for a gmap.
23 */
24function gmap_defaults() {
25 $defaults = array(
26 'width' => '300px',
27 'height' => '200px',
28 'zoom' => 3,
29 'maxzoom' => 14,
30 'controltype' => 'Small',
31 'align' => 'None',
32 'latlong' => '40,0',
33 'maptype' => 'Map',
34 'mtc' => 'standard',
35 'baselayers' => array('Map', 'Satellite', 'Hybrid'),
36 'styles' => array(
8d78d11a
BB
37 'line_default' => array('0000ff', 5, 45, '', 0, 0),
38 'poly_default' => array('000000', 3, 25, 'ff0000', 45),
bba8e92a
BB
39 ),
40 'line_colors' => array('#00cc00', '#ff0000', '#0000ff'),
41 );
42 $defaults['behavior'] = array();
43 $m = array();
44 $behaviors = module_invoke_all('gmap', 'behaviors', $m);
45 foreach ($behaviors as $k => $v) {
46 $defaults['behavior'][$k] = $v['default'];
47 }
48 $defaults = array_merge($defaults, variable_get('gmap_default', array()));
49 return $defaults;
50}
51
52/**
efcf783f
BB
53 * Implementation of hook_theme().
54 */
55function gmap_theme() {
56 return array(
efcf783f
BB
57 'views_view_gmap' => array('arguments' => array('element')),
58 'gmap_views_marker_label' => array('arguments' => array('element')),
ad3f15d1 59 'gmap_marker_popup' => array('arguments' => array('label')),
efcf783f
BB
60 'gmap_overlay_edit' => array('arguments' => array('element')),
61 'gmap_coord' => array('arguments' => array('element')),
62 'gmap_macrotext' => array('arguments' => array('element')),
63 'gmap_dimension' => array('arguments' => array('element')),
64 'gmap_address' => array('arguments' => array('element')),
65 'gmap_align' => array('arguments' => array('element')),
620d466e 66 'gmap_style' => array('arguments' => array('element')),
efcf783f
BB
67 'gmap' => array('arguments' => array('element')),
68 );
69}
70
71/**
bba8e92a
BB
72 * Implementation of hook_gmap().
73 */
74function gmap_gmap($op, &$map) {
75 switch ($op) {
76 case 'macro':
77 return array(
78 'points' => array(
79 'multiple' => TRUE,
80 ),
81 'markers' => array(
82 'multiple' => TRUE,
83 ),
84 'feed' => array(
85 'multiple' => TRUE,
86 ),
87 );
88 case 'pre_theme_map':
89 $path = drupal_get_path('module', 'gmap') .'/js/';
90 // Activate markers if needed
0a5ee8df 91 if ((isset($map['behavior']['dynmarkers']) && $map['behavior']['dynmarkers']) || !empty($map['markers'])) {
213fc656
BB
92 // The marker data is not a real file. Work around this fact.
93 static $header_set = FALSE;
94 if (!$header_set) {
95 $header_set = TRUE;
96 drupal_add_js("/* GMap markers enabled. */</script>\n<script type=". '"text/javascript" src="'. url('map/markerdata.js') .'">', 'inline', 'header', FALSE, TRUE, FALSE);
bba8e92a
BB
97 }
98 drupal_add_js($path .'icon.js');
99 drupal_add_js($path .'marker.js');
100 drupal_add_js($path . variable_get('gmap_mm_type', 'gmap') .'_marker.js');
101 }
620d466e 102 if (isset($map['behavior']['locpick']) && $map['behavior']['locpick']) {
bba8e92a
BB
103 drupal_add_js($path .'locpick.js');
104 }
105 if (variable_get('gmap_load_zoom_plugin', TRUE) && !$map['behavior']['nomousezoom']) {
106 drupal_add_js(drupal_get_path('module', 'gmap') .'/thirdparty/mousewheel.js');
107 }
0a5ee8df 108 if (!empty($map['markers']) || !empty($map['lines'])) {
bba8e92a
BB
109 drupal_add_js($path .'markerloader_static.js');
110 }
0a5ee8df 111 if (!empty($map['shapes'])) {
bba8e92a
BB
112 drupal_add_js($path .'shapeloader_static.js');
113 drupal_add_js($path .'gmap_shapes.js');
114 }
0a5ee8df 115 if (isset($map['feed']) && is_array($map['feed'])) {
bba8e92a
BB
116 drupal_add_js($path .'markerloader_georss.js');
117 }
118 break;
119 case 'macro_multiple':
120 return array('points', 'markers', 'feed', 'circle', 'rpolygon', 'polygon', 'line');
121 case 'behaviors':
122 return array(
123 'locpick' => array(
124 'title' => t('Location chooser'),
125 'default' => FALSE,
126 'help' => t('Used to activate location choosing using a gmap.'),
127 'internal' => TRUE,
128 ),
129 'nodrag' => array(
130 'title' => t('Disable dragging'),
131 'default' => FALSE,
132 'help' => t('Remove the ability for the user to drag the map. If dragging is disabled, keyboard shortcuts are implicitly disabled.'),
133 ),
134 'nokeyboard' => array(
135 'title' => t('Disable keyboard'),
136 'default' => TRUE,
137 'help' => t('Disable the keyboard shortcuts.'),
138 ),
139 'nomousezoom' => array(
140 'title' => t('Disable mousezoom'),
141 'default' => FALSE,
142 'help' => t('Disable using the scroll wheel to zoom the map.'),
143 ),
144 'autozoom' => array(
145 'title' => t('Use AutoZoom'),
146 'default' => FALSE,
147 'help' => t('Automatically zoom the map to fit all markers when markers are added.'),
148 ),
149 'dynmarkers' => array(
150 'title' => t('Unconditionally enable marker interface'),
151 'default' => FALSE,
152 'help' => t('Load the marker loader system even if no markers to load are detected. Useful if you are injecting markers from somewhere else.'),
153 ),
154 'overview' => array(
155 'title' => t('Enable Overview Map'),
156 'default' => FALSE,
157 'help' => t('Enable the "overview map" in the bottom right corner.'),
158 'previewable' => TRUE,
159 ),
160/* 'notype' => array(
161 'title' => t('Disable map type control'),
162 'default' => FALSE,
163 'help' => t('Removes the map type control from the upper right corner. Recommended for very narrow maps.'),
164 'previewable' => TRUE,
165 ), */
166 'collapsehack' => array(
167 'title' => t('Work around bugs when maps appear in collapsible fieldsets'),
168 'default' => FALSE,
169 'help' => t('Enabling this will work around some issues that can occur when maps appear inside collapsible fieldsets.'),
170 ),
171 // Note to myself, who keeps forgetting what a scale control actually IS.:
172 // |------------ 1mi ------------|
173 'scale' => array(
174 'title' => t('Add scale control to map.'),
175 'default' => FALSE,
176 'help' => t('Adds a scale control to the map in the default position.'),
177 'previewable' => TRUE,
178 ),
179 );
180 break;
181
182 case 'baselayers':
183 $map['Google']['Map'] = array(
184 'title' => t('Map: Standard street map.'),
185 'default' => TRUE,
186 'help' => t('The standard default street map. Internal name: G_NORMAL_MAP'),
187 );
188 $map['Google']['Satellite'] = array(
189 'title' => t('Satellite: Standard satellite map.'),
190 'default' => TRUE,
191 'help' => t('Satellite view without street overlay. Internal name: G_SATELLITE_MAP'),
192 );
193 $map['Google']['Hybrid'] = array(
194 'title' => t('Hybrid: Hybrid satellite map.'),
195 'default' => TRUE,
196 'help' => t('Satellite view with street overlay. Internal name: G_HYBRID_MAP'),
197 );
198 $map['Google']['Physical'] = array(
199 'title' => t('Terrain: Physical feature map.'),
200 'default' => FALSE,
201 'help' => t('Map with physical data (terrain, vegetation.) Internal name: G_PHYSICAL_MAP'),
202 );
203 break;
204 }
205}
206
207/**
208 * Set up the HTML header for GMap.
209 */
210function _gmap_doheader() {
211 static $gmap_initialized = FALSE;
212 if ($gmap_initialized) {
213 return;
214 }
215 $gmap_path = drupal_get_path('module', 'gmap');
216 drupal_add_css($gmap_path .'/gmap.css');
217 drupal_add_js($gmap_path .'/js/gmap.js');
218 $mm = variable_get('gmap_mm_type', 'gmap');
219 if ($mm=='clusterer') {
220 drupal_add_js($gmap_path .'/js/icon.js');
221 drupal_add_js($gmap_path .'/thirdparty/Clusterer2.js');
222 }
223 drupal_add_js($gmap_path .'/js/marker.js');
224 drupal_add_js($gmap_path .'/js/'. $mm .'_marker.js');
225 $mms = variable_get('gmap_markermanager', array());
226 if (empty($mms[$mm])) {
227 $mms[$mm] = array();
228 }
229 drupal_add_js(array('gmap_markermanager' => $mms[$mm]), 'setting');
230// @@@
231drupal_add_js($gmap_path .'/js/poly.js');
54cbe9f0 232 $key = gmap_get_key();
bba8e92a
BB
233 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>');
234
235 drupal_add_js(array(
236 'gmap_init' => array(
237 'querypath' => base_path() .'map/query',
238 ),
239 ), 'setting');
240
241 $gmap_initialized = TRUE;
242}
243
244/**
245 * Parse a macro style definition.
246 * Example: #111111/1/100/#111111/1
247 */
248function _gmap_parse_style($style) {
249 $styles = explode('/', $style);
250
251 // @@@ Todo: Fix up old xmaps stuff. Possibly detect by looking for array length 7?
252
253 // Strip off # signs, they get added by code.
254 if (isset($styles[0]) && substr($styles[0], 0, 1) == '#') {
255 $styles[0] = substr($styles[0], 1);
256 }
257 if (isset($styles[3]) && substr($styles[3], 0, 1) == '#') {
258 $styles[3] = substr($styles[3], 1);
259 }
260
261 // Assume anything > 0 and < 1.1 was an old representation.
262 if ($styles[2] > 0 && $styles[2] < 1.1) {
263 $styles[2] = $styles[2] * 100;
264 }
265 if (isset($styles[4])) {
266 if ($styles[4] > 0 && $styles[4] < 1.1) {
267 $styles[4] = $styles[4] * 100;
268 }
269 }
270
271 return $styles;
272}
273
274/**
275 * Convert a macro string into a GMap array.
276 *
277 * @param $instring
278 * Macro to process.
279 * @param $ver
280 * Version to treat macro as.
281 * Set to 1 when processing very old macros, otherwise leave as is.
282 * @return
283 * A GMap array.
284 */
285function gmap_parse_macro($instring, $ver = 2) {
286 // Get a list of keys that are "multiple."
287 $m = array();
288 $multiple = module_invoke_all('gmap', 'macro_multiple', $m);
289
290 // Remove leading and trailing tags
291 if (substr(trim($instring), -1)==']') {
292 $instring = substr(trim($instring), 0, -1);
293 }
294 if (substr($instring, 0, 5)=='[gmap') {
295 $instring = substr($instring, 6);
296 }
297
298 // Chop the macro into an array
299 $temp = explode('|', $instring);
300 $m = array();
301 foreach ($temp as $row) {
302 $offset = strpos($row, '=');
303 if ($offset !== FALSE) {
304 $k = trim(substr($row, 0, $offset));
305 $r = trim(substr($row, $offset+1));
306 if (in_array($k, $multiple)) {
307 // Things that can appear multiple times
308 if (!isset($m[$k])) {
309 $m[$k] = array();
310 }
311 $m[$k][] = $r;
312 }
313 else {
314 $m[$k] = $r;
315 }
316 }
317 }
318
319 // Synonyms
d78c4b65 320 if (isset($m['type'])) {
bba8e92a
BB
321 $m['maptype'] = $m['type'];
322 unset($m['type']);
323 }
324 if ($m['control']) {
325 $m['controltype'] = $m['control'];
326 unset($m['control']);
327 }
328
d78c4b65 329 if (isset($m['feed']) && is_array($m['feed'])) {
bba8e92a
BB
330 foreach ($m['feed'] as $k => $v) {
331 $temp = explode('::', $v);
332 // Normalize url
333 if (substr($temp[1], 0, 1) == '/') {
334 $temp[1] = substr($temp[1], 1);
335 }
336 $temp[1] = url($temp[1]);
337 $m['feed'][$k] = array(
338 'markername' => $temp[0],
339 'url' => $temp[1],
340 );
341 }
342 }
343
344 // Merge points and markers
d78c4b65
BB
345 if (!isset($m['points']) || !is_array($m['points'])) $m['points'] = array();
346 if (!isset($m['markers']) || !is_array($m['markers'])) $m['markers'] = array();
bba8e92a
BB
347 $m['markers-temp'] = array_merge($m['points'], $m['markers']);
348 unset($m['points']);
349 unset($m['markers']);
350
351 // all shapes in 1 array
d78c4b65 352 if (isset($m['circle']) && is_array($m['circle'])) {
bba8e92a
BB
353 foreach ($m['circle'] as $shape) {
354 $s = array('type' => 'circle');
355 $cp = strpos($shape, ':');
8d78d11a 356 if ($cp !== FALSE) {
bba8e92a
BB
357 $stylestr = substr($shape, 0, $cp);
358 $s['style'] = _gmap_parse_style($stylestr);
359 $shape = substr($shape, $cp+1);
360 }
361 $tmp = explode('+', $shape);
362 $s['radius'] = $tmp[1] ? $tmp[1] : 100;
363 if ($tmp[2]) $s['numpoints'] = trim($tmp[2]);
364 $tmp = _gmap_str2coord($tmp[0]);
365 $s['center'] = $tmp[0];
366 $m['shapes'][] = $s;
367 }
368 unset($m['circle']);
369 }
370 // Fixup legacy lines.
d78c4b65 371 if (isset($m['line1'])) {
4922bb48 372 $def = gmap_defaults();
bba8e92a 373 if (!isset($m['line'])) $m['line'] = array();
4922bb48 374 $m['line'][] = $def['line_colors'][0] .':'. $m['line1'];
bba8e92a
BB
375 unset($m['line1']);
376 }
d78c4b65 377 if (isset($m['line2'])) {
4922bb48 378 $def = gmap_defaults();
bba8e92a 379 if (!isset($m['line'])) $m['line'] = array();
4922bb48 380 $m['line'][] = $def['line_colors'][1] .':'. $m['line3'];
bba8e92a
BB
381 unset($m['line2']);
382 }
d78c4b65 383 if (isset($m['line3'])) {
4922bb48 384 $def = gmap_defaults();
bba8e92a 385 if (!isset($m['line'])) $m['line'] = array();
4922bb48 386 $m['line'][] = $def['line_colors'][2] .':'. $m['line3'];
bba8e92a
BB
387 unset($m['line3']);
388 }
389
d78c4b65 390 if (isset($m['line']) && is_array($m['line'])) {
bba8e92a
BB
391 foreach ($m['line'] as $shape) {
392 $s = array('type' => 'line');
393 $cp = strpos($shape, ':');
8d78d11a 394 if ($cp != FALSE) {
bba8e92a
BB
395 $stylestr = substr($shape, 0, $cp);
396 $s['style'] = _gmap_parse_style($stylestr);
397 $shape = substr($shape, $cp+1);
398 }
399 $s['points'] = _gmap_str2coord($shape);
400 $m['shapes'][] = $s;
401 }
402 unset($m['line']);
403 }
d78c4b65 404 if (isset($m['rpolygon']) && is_array($m['rpolygon'])) {
bba8e92a
BB
405 foreach ($m['rpolygon'] as $shape) {
406 $s = array('type' => 'rpolygon');
407 $cp = strpos($shape, ':');
8d78d11a 408 if ($cp !== FALSE) {
bba8e92a
BB
409 $stylestr = substr($shape, 0, $cp);
410 $s['style'] = _gmap_parse_style($stylestr);
411 $shape = substr($shape, $cp+1);
412 }
413 $tmp = explode('+', $shape);
414 if ($tmp[2]) {
415 $s['numpoints'] = (int)trim($tmp[2]);
416 $tmp = array_slice($tmp, 0, 2);
417 }
418 $shape = implode('+', $tmp);
419 $tmp = _gmap_str2coord($shape);
420 $s['center'] = $tmp[0];
421 $s['point2'] = $tmp[1];
422 $m['shapes'][] = $s;
423 }
424 unset($m['rpolygon']);
425 }
d78c4b65 426 if (isset($m['polygon']) && is_array($m['polygon'])) {
bba8e92a
BB
427 foreach ($m['polygon'] as $shape) {
428 $s = array('type' => 'polygon');
429 $cp = strpos($shape, ':');
8d78d11a 430 if ($cp !== FALSE) {
bba8e92a
BB
431 $stylestr = substr($shape, 0, $cp);
432 $s['style'] = _gmap_parse_style($stylestr);
433 $shape = substr($shape, $cp+1);
434 }
435 $s['points'] = _gmap_str2coord($shape);
436 $m['shapes'][] = $s;
437 }
438 unset($m['polygon']);
439 }
440
441 // Version 1 -> 2 conversion
442 if ($ver == 1) {
443 // Zoom is flipped
d78c4b65 444 if (isset($m['zoom'])) {
bba8e92a
BB
445 $m['zoom'] = 18 - $m['zoom'];
446 if ($m['zoom'] < 1) {
447 $m['zoom'] = 1;
448 }
449 }
450 }
451
452 // Center -> latitude and longitude
d78c4b65 453 if (isset($m['center']) && is_array($m['center'])) {
bba8e92a
BB
454 list($m['latitude'], $m['longitude']) = explode(',', $m['center']);
455 unset($m['center']);
456 }
457
458 // Behavior
d78c4b65 459 if (isset($m['behaviour'])) {
bba8e92a
BB
460 $m['behavior'] = $m['behaviour'];
461 unset($m['behaviour']);
462 }
d78c4b65 463 if (isset($m['behavior'])) {
ca5b46da
BB
464 $sep = ' ';
465 if (strpos($m['behavior'], ',') !== FALSE) {
466 // In some places, commas were used to seperate behaviors.
467 // This was originally an accident, but it's easy enough to support.
468 $sep = ',';
469 }
470 $m['behavior-temp'] = explode($sep, $m['behavior']);
bba8e92a
BB
471 $m['behavior'] = array();
472 foreach ($m['behavior-temp'] as $v) {
473 $m['behavior'][substr($v, 1)] = (substr($v, 0, 1) == '+') ? TRUE : FALSE;
474 }
475 unset($m['behavior-temp']);
476 }
477
478 // tcontrol now is mtc.
d78c4b65 479 if (isset($m['tcontrol'])) {
bba8e92a
BB
480 if (strtolower(trim($m['tcontrol'])) == 'on') {
481 $m['mtc'] = 'standard';
482 }
483 else {
484 $m['mtc'] = 'none';
485 }
486 unset($m['tcontrol']);
487 }
488
489 // notype also controls mtc.
8d78d11a 490 if (isset($m['behavior']['notype'])) {
bba8e92a
BB
491 if ($m['behavior']['notype']) {
492 $m['mtc']= 'none';
493 }
494 unset($m['behavior']['notype']);
495 }
496
497 // Stuff that was converted to behavior flags
498
499 // Scale control.
d78c4b65 500 if (isset($m['scontrol'])) {
bba8e92a
BB
501 if (strtolower(trim($m['scontrol'])) == 'on') {
502 $m['behavior']['scale'] = TRUE;
503 }
504 else {
505 $m['behavior']['scale'] = FALSE;
506 }
507 unset($m['scontrol']);
508 }
509
510 // Draggability.
d78c4b65 511 if (isset($m['drag'])) {
bba8e92a
BB
512 if (strtolower(trim($m['drag'])) == 'yes') {
513 $m['behavior']['nodrag'] = FALSE;
514 }
515 else {
516 $m['behavior']['nodrag'] = TRUE;
517 }
518 unset($m['drag']);
519 }
520
521 // Markers fixup
522 foreach ($m['markers-temp'] as $t) {
523 unset($markername);
524 // Named?
525 if (strpos($t, '::')) { // Single : gets handled below.
526 list($markername, $t) = explode('::', $t, 2);
527 }
528 // Break down into points
529 $points = explode('+', $t);
530 $offset = -1;
531 foreach ($points as $point) {
532 $marker = array();
533 $offset++;
534 $marker['options'] = array();
535 // Labelled?
536 // @@@ Gmap allows both a tooltip and a popup, how to represent?
537 if (strpos($point, ':')) {
538 list($point, $marker['text']) = explode(':', $point, 2);
539 $marker['text'] = theme('gmap_marker_popup', $marker['text']);
540 }
541 if (strpos($point, '%')) {
542 list($point, $addons) = explode('%', $point, 2);
543 $motemp = explode('%', $addons);
544 foreach ($motemp as $option) {
8d78d11a 545 $marker['options'][trim($option)] = TRUE;
bba8e92a
BB
546 }
547 }
548 list($marker['latitude'], $marker['longitude']) = explode(',', $point, 2);
549 // Named markers get an offset too.
550 if (isset($markername)) {
551 $marker['markername'] = $markername;
552 $marker['offset'] = $offset;
553 }
554 $m['markers'][] = $marker;
555 }
556 }
557 unset($m['markers-temp']);
558
559 // Assign an id if one wasn't specified.
d78c4b65 560 if (!isset($m['id'])) {
bba8e92a
BB
561 $m['id'] = gmap_get_auto_mapid();
562 }
563
564 // The macro can now be manipulated by reference.
565 foreach (module_implements('gmap') as $module) {
566 $additions = call_user_func_array($module .'_gmap', array('parse_macro', &$m));
567 if (!empty($additions)) {
568 foreach ($additions as $k => $v) {
569 $m[$k] = $v;
570 }
571 }
572 }
573 return $m;
574}
575
576/**
577 * Parse "x.xxxxx , y.yyyyyy (+ x.xxxxx, y.yyyyy ...)" into an array of points.
578 */
579function _gmap_str2coord($str) {
580 // Explode along + axis
581 $arr = explode('+', $str);
582 // Explode along , axis
583 $points = array();
584 foreach ($arr as $pt) {
585 list($lat, $lon) = explode(',', $pt);
586 $points[] = array((float)trim($lat), (float)trim($lon));
587 }
588 return $points;
589}
590
591/**
592 * Theme a marker popup.
593 * This will get called for markers embedded in macros.
594 */
595function theme_gmap_marker_popup($label) {
596 return $label;
597}
598
599/**
600 * Location chooser utility function.
601 *
602 * Creates a map that can be interactively used to fill a form with a
603 * location (latitude, longitude and zoom level).
604 *
605 * Note: This is a utility function designed for location.module, there is no
606 * guarantee it will not be removed eventually.
607 *
608 * @param $map
609 * Either a macro to use as the base map for setting a location, or an already set map associative array.
610 * @param $form
611 * A formset associative array. Cannot be more than one deep.
612 * @param $fields
613 * An associative array for the field names. 'latitude', 'longitude'=>name of respective array, 'address' is optional.
614 * @return
615 * A string with the google map code to be inserted onto the page.
616 *
617 */
618function gmap_set_location($map, &$form, $fields) {
619 static $ctr = 0;
620 $ctr++;
621 if (!is_array($map)) {
622 $map = array_merge(gmap_defaults(), gmap_parse_macro($map));
623 }
624 $id = 'loc'. $ctr;
625 $map['id'] = $id;
626
627 // This is a locpick map.
628 $map['behavior']['locpick'] = TRUE;
629
630 $element = array(
631 '#type' => 'gmap',
632 '#map' => $map['id'],
633 '#settings' => $map,
634 );
635
636 $form[$fields['latitude']]['#map']=$id;
637 gmap_widget_setup($form[$fields['latitude']], 'locpick_latitude');
638
639 $form[$fields['longitude']]['#map']=$id;
640 gmap_widget_setup($form[$fields['longitude']], 'locpick_longitude');
641
642 if (isset($fields['address'])) {
643 $form[$fields['address']]['#map'] = $id;
644 gmap_widget_setup($form[$fields['address']], 'locpick_address');
645 }
646 return theme('gmap', $element);
647}
648
649/**
650 * Handle filter preparation.
651 */
652function _gmap_prepare($intext) {
653 $out = FALSE;
654 $matches = array();
655 preg_match_all('/\[gmap([^\[\]]+ )* \] /x', $intext, $matches);
656 $i = 0;
657
658 while (isset($matches[1][$i])) {
659 $out[0][$i] = $matches[0][$i];
660 if ($matches[1][$i][0] == '1') {
661 $ver = 1;
662 $matches[1][$i] = substr($matches[0][$i], 1);
663 }
664 else {
665 $ver = 2;
666 }
667 $map = array('#settings' => gmap_parse_macro($matches[1][$i], $ver));
668 $out[1][$i] = theme('gmap', $map);
669 $i++;
670 } // endwhile process macro
671 return $out;
672}
673
674/**
675 * Make sure a string is a valid css dimension.
676 */
677function gmap_todim($instring) {
678 $s = strtolower($instring);
679 $matches = array();
680 if (preg_match('/([\d.]+)\s*(em|ex|px|in|cm|mm|pt|pc|%)/', $s, $matches)) {
681 return $matches[1] . $matches[2];
682 }
683 else {
684 return FALSE;
685 }
686}
687
688/**
689 * Ensure a textfield is a valid css dimension string.
690 */
691function gmap_dimension_validate(&$elem) {
692 if (!gmap_todim($elem['#value'])) {
693 form_error($elem, t('The specified value is not a valid CSS dimension.'));
694 }
695}
696
697/**
698 * Implementation of hook_filter().
699 */
700function gmap_filter($op, $delta = 0, $format = -1, $text = '') {
701 switch ($op) {
702 case 'list':
703 return (array(0 => t('GMap filter')));
704
705 case 'name':
706 return t('Google map filter');
707
708 case 'description':
709 return t('converts a google map macro into the html required for inserting a google map.');
710
711 case 'process':
712 $gmaps = _gmap_prepare($text); //returns an array of $tables[0] = table macro $table[1]= table html
713 if ($gmaps) { // there are table macros in this node
714 return str_replace($gmaps[0], $gmaps[1], $text);
715 }
716 else {
717 return $text;
718 }
719
720 case 'prepare':
721 return $text;
722
723 case 'no cache':
724 return TRUE; // @@@ Possibly improve efficiency in the future?
725 }
726}
727
728/**
729 * Implementation of hook_filter_tips().
730 */
8d78d11a 731function gmap_filter_tips($delta, $format, $long = FALSE) {
bba8e92a
BB
732 if (user_access('create macro')) { // only display macro if user can create one
733 return t('Insert Google Map macro.') .'<a href="'. url('map/macro') .'" target="_blank" >'. t('Create a macro') .'</a>';
734 }
735 else {
736 return t('Insert Google Map macro.');
737 }
738}
739
740/**
741 * Implementation of hook_menu().
742 */
1e85d651
BB
743function gmap_menu() {
744 $items['admin/settings/gmap'] = array(
745 'title' => 'GMap',
746 'description' => 'Configure GMap settings',
747 'page callback' => 'drupal_get_form',
748 'page arguments' => array('gmap_admin_settings'),
749 'file' => 'gmap_settings_ui.inc',
750 'access arguments' => array('administer site configuration'),
751 'type' => MENU_NORMAL_ITEM,
752 );
753 $items['map/query'] = array(
754 'type' => MENU_CALLBACK,
755 'access arguments' => array('access content'),
756 'page callback' => 'gmap_json_query',
757 );
758 $items['map/markerdata.js'] = array(
759 'type' => MENU_CALLBACK,
760 'access arguments' => array('access content'),
761 'page callback' => 'gmap_markerdata_js',
762 );
763 return $items;
bba8e92a
BB
764}
765
766/**
767 * Generate the markerdata file.
768 */
769function gmap_markerdata_js() {
770 drupal_set_header('Content-Type: text/javascript');
771 echo "// GMap marker image data.\n";
772 echo "Drupal.gmap.iconpath = ". drupal_to_js(base_path() . drupal_get_path('module', 'gmap') .'/markers') .";\n";
773 echo "Drupal.gmap.icondata = ". drupal_to_js(gmap_get_icondata()) .";\n";
774}
775
776
777/**
778 * JSON request interface.
779 */
780function gmap_json_query() {
781 if (arg(2)=='markers') {
782 drupal_set_header('Content-Type: text/javascript');
783 echo drupal_to_js(array(
784 'path' => base_path() . drupal_get_path('module', 'gmap') .'/markers',
785 'markers' => gmap_get_icondata(TRUE),
786 ));
787 exit();
788 }
789}
790
791/**
bba8e92a
BB
792 * Implementation of hook_elements().
793 */
794function gmap_elements() {
795 return array(
796 'gmap' => array(
797 '#input' => FALSE, // This isn't a *form* input!!
798 '#settings' => array_merge(gmap_defaults(), array(
799 'points' => array(),
800 'pointsOverlays' => array(),
801 'lines' => array(),
802 )),
bba8e92a
BB
803 ),
804 'gmap_macrotext' => array(
805 '#input' => TRUE,
806 '#cols' => 60,
807 '#rows' => 5,
f2b2bee5
BB
808 '#gmap_newtype' => 'textarea',
809 '#theme' => 'gmap_macrotext',
810 '#process' => array('process_gmap_textfield'),
bba8e92a 811 ),
620d466e 812 'gmap_overlay_edit' => array('#input' => TRUE, '#process' => array('process_gmap_overlay_edit')),
ad3f15d1
BB
813 'gmap_style' => array('#input' => TRUE, '#tree' => TRUE, '#gmap_style_type' => 'poly', '#process' => array('process_gmap_style')),
814 'gmap_address' => array('#input' => FALSE, '#process' => array('process_gmap_address')),
815 'gmap_align' => array('#input' => TRUE, '#process' => array('process_gmap_align')),
f2b2bee5
BB
816 'gmap_latitude' => array('#input' => TRUE, '#gmap_newtype' => 'textfield', '#process' => array('process_gmap_textfield')),
817 'gmap_longitude' => array('#input' => TRUE, '#gmap_newtype' => 'textfield', '#process' => array('process_gmap_textfield')),
818 'gmap_latlon' => array('#input' => TRUE, '#gmap_newtype' => 'textfield', '#process' => array('process_gmap_textfield')),
ad3f15d1 819 'gmap_markerchooser' => array('#input' => TRUE, '#process' => array('process_gmap_markerchooser')),
f2b2bee5 820 'gmap_dimension' => array('#input' => TRUE, '#theme' => 'textfield', '#element_validate' => array('gmap_dimension_validate')),
bba8e92a
BB
821 );
822}
823
824/**
bba8e92a
BB
825 * Generic gmap control #process function.
826 */
ad3f15d1
BB
827//function process_gmap_control($element, $edit, $fieldtype, $control, $theme='') {
828function process_gmap_control($element, $edit, &$form_state, $complete_form) {
829//dpm($element);
bba8e92a
BB
830 $element['#type'] = $fieldtype;
831 gmap_widget_setup($element, $control);
ab8d1353 832/*
bba8e92a
BB
833 if (!empty($theme)) {
834 $element['#theme'] = $theme;
835 }
836 else {
837 $element['#theme'] = 'gmap_'. $control;
ab8d1353 838 } */
bba8e92a
BB
839 return $element;
840}
841
ad3f15d1 842// @@@ Finish debugging.
f2b2bee5 843// @@@ Rename this to something more appropriate.
ad3f15d1
BB
844function process_gmap_textfield($element, $edit, &$form_state, $complete_form) {
845 $control = substr($element['#type'], 5);
ab8d1353 846//dpm($element);
f2b2bee5
BB
847 $element['#type'] = $element['#gmap_newtype'];
848 unset($element['#gmap_newtype']);
ad3f15d1 849 gmap_widget_setup($element, $control);
ab8d1353 850 /*if (!empty($theme)) {
ad3f15d1
BB
851 $element['#theme'] = $theme;
852 }
853 else {
854 $element['#theme'] = 'gmap_'. $control;
ab8d1353
BB
855 }*/
856//dpm($element);
ad3f15d1
BB
857 return $element;
858}
859
bba8e92a
BB
860/**
861 * Style fieldset #process function.
862 */
863function process_gmap_style($element) {
864 $isline = ($element['#gmap_style_type'] == 'line');
865 // Stroke color
866 $element[0] = array(
867 '#type' => 'textfield',
868 '#size' => 6,
869 '#maxlength' => 6,
870 '#field_prefix' => '#',
871 '#title' => t('Stroke color'),
872 '#value' => $element['#value'][0],
873 '#attributes' => array('class' => 'gmap_style'),
874 );
875 // Stroke weight
876 $element[1] = array(
877 '#type' => 'textfield',
878 '#title' => t('Stroke weight'),
879 '#description' => t('Thickness of line, in pixels.'),
880 '#size' => 3,
881 '#maxlength' => 3,
882 '#field_suffix' => t('px'),
883 '#value' => $element['#value'][1],
884 '#attributes' => array('class' => 'gmap_style'),
885 );
886 // Stroke opacity
887 $element[2] = array(
888 '#type' => 'textfield',
889 '#title' => t('Stroke opacity'),
890 '#size' => 3,
891 '#maxlength' => 3,
892 '#field_suffix' => '%',
893 '#value' => $element['#value'][2],
894 '#attributes' => array('class' => 'gmap_style'),
895 );
896 // Fill color
897 $element[3] = array(
898 '#type' => 'textfield',
899 '#title' => t('Fill color'),
900 '#description' => t('Hex color value for fill color. Example: #<em>00AA33</em>'),
901 '#size' => 6,
902 '#maxlength' => 6,
903 '#field_prefix' => '#',
904 '#value' => $element['#value'][3],
905 '#disabled' => $isline,
906 '#attributes' => array('class' => 'gmap_style'),
907 );
908 $element[4] = array(
909 '#type' => 'textfield',
910 '#title' => t('Fill opacity'),
911 '#description' => t('Opacity of fill, from 0 to 100%.'),
912 '#size' => 3,
913 '#maxlength' => 3,
914 '#field_suffix' => '%',
915 '#value' => $element['#value'][4],
916 '#disabled' => $isline,
917 '#attributes' => array('class' => 'gmap_style'),
918 );
919 return $element;
920}
921
922/**
923 * Theme a gmap_style fieldset.
924 */
925function theme_gmap_style($element) {
926 // Fieldsets print #value at the end, so we need to empty it out.
927 // Otherwise, it puts "Array" at the end of the fieldset.
928 $element['#value'] = '';
929 return theme('fieldset', $element, $element['#children']);
930}
931
932/**
933 * Overlay editor #process function.
934 */
935function process_gmap_overlay_edit($element) {
936 // Conver the root element into a fieldset.
937 $element['#type'] = 'fieldset';
938 if (!$element['#title']) {
939 $element['#title'] = t('Overlay editor');
940 }
941 $element['#tree'] = TRUE;
942
943 $element['mapclicktype'] = array(
944 '#type' => 'select',
945 '#title' => t('Click map'),
946 '#map' => $element['#map'],
947 '#options' => array(
948 'Points' => t('Points'),
949 'Lines' => t('Lines'),
950 'Circles' => t('Circles'),
951 'GPolygon' => t('Filled Polygons'),
952 ),
953 );
954 gmap_widget_setup($element['mapclicktype'], 'overlayedit_mapclicktype');
955 $element['markerclicktype'] = array(
956 '#type' => 'select',
957 '#title' => t('Click marker / segment'),
958 '#map' => $element['#map'],
959 '#options' => array(
960 'Remove' => t('Remove'),
961// 'updatestyle' => t('Update Styles'),
962// 'removestyle' => t('Remove Styles'),
963 'Edit Info' => t('Edit Info'),
964 ),
965 );
966 gmap_widget_setup($element['markerclicktype'], 'overlayedit_markerclicktype');
967
968 $element['marker'] = array(
969 '#type' => 'select',
970 '#map' => $element['#map'],
971 '#options' => gmap_get_marker_titles(),
972 '#title' => t('Marker'),
973 '#theme' => 'gmap_overlay_edit',
974 );
975 gmap_widget_setup($element['marker'], 'overlayedit');
976
977 $element['linestyle'] = array(
978 '#type' => 'gmap_style',
979 '#title' => t('Line style'),
980 '#gmap_style_type' => 'line',
8d78d11a 981 '#default_value' => array('0000ff', 5, 45, '', ''), // @@@
bba8e92a
BB
982 );
983 gmap_widget_setup($element['linestyle'], 'overlayedit_linestyle', $element['#map']);
984 $element['linestyle']['linestyle_apply'] = array(
985 '#tree' => FALSE,
986 '#type' => 'checkbox',
987 '#title' => t('Use for new and changed lines'),
988 '#default_value' => FALSE,
989 );
990 gmap_widget_setup($element['linestyle']['linestyle_apply'], 'overlayedit_linestyle_apply', $element['#map']);
991
992 $element['polystyle'] = array(
993 '#type' => 'gmap_style',
994 '#title' => t('Polygon style'),
995 '#gmap_style_type' => 'poly',
8d78d11a 996 '#default_value' => array('000000', 3, 25, 'ff0000', 45), // @@@
bba8e92a
BB
997 );
998 gmap_widget_setup($element['polystyle'], 'overlayedit_polystyle', $element['#map']);
999 $element['polystyle']['polystyle_apply'] = array(
1000 '#tree' => FALSE,
1001 '#type' => 'checkbox',
1002 '#title' => t('Use for new and changed polygons'),
1003 '#default_value' => FALSE,
1004 );
1005 gmap_widget_setup($element['polystyle']['polystyle_apply'], 'overlayedit_polystyle_apply', $element['#map']);
1006
1007 return $element;
1008}
1009
1010/**
1011 * Alignment selector #process function.
1012 */
1013function process_gmap_align($element) {
1014 $element['#type'] = 'select';
1015 gmap_widget_setup($element, 'align');
1016 $element['#options'] = drupal_map_assoc(array('None', 'Right', 'Left', 'Center'));
1017 $element['#theme'] = 'gmap_align';
1018 return $element;
1019}
1020
1021/**
1022 * Address widget #process function.
1023 */
1024function process_gmap_address($element) {
1025 $element['#type'] = 'textfield';
1026 gmap_widget_setup($element, 'address');
1027 $element['#theme'] = 'gmap_address';
1028 return $element;
1029}
1030
1031/**
1032 * Marker chooser #process function.
1033 */
1034function process_gmap_markerchooser($element) {
1035 $element['#type'] = 'select';
1036 $element['#options'] = gmap_get_marker_titles();
1037 return $element;
1038}
1039
1040/**
1041 * Overlay editor theme function.
1042 */
1043function theme_gmap_overlay_edit($element) {
1044 $path = drupal_get_path('module', 'gmap');
1045 drupal_add_js($path .'/js/gmap.js');
1046 drupal_add_js($path .'/js/gmap_shapes.js');
1047 drupal_add_js($path .'/js/overlay_edit.js');
1048 return theme('select', $element);
1049}
1050
1051/**
1052 * Perform some normalization on the map object
1053 * to prevent errors.
1054 */
1055function gmap_map_cleanup(&$map) {
1056 // Google is picky about this one.
1057 $map['zoom'] = (int)$map['zoom'];
1058 // Normalize latitude / longitude
1059 if ($map['latlong']) {
1060 $map['latlon'] = $map['latlong'];
1061 unset($map['latlong']);
1062 }
1063 if (isset($map['latlon']) && (!isset($map['latitude']) || !isset($map['longitude']))) {
1064 list($map['latitude'], $map['longitude']) = explode(',', $map['latlon']);
1065 }
1066 unset($map['latlon']);
1067
1068 foreach ($map['baselayers'] as $k => $v) {
1069 if (!$v) {
1070 unset($map['baselayers'][$k]);
1071 }
1072 }
1073}
1074
1075function theme_gmap_coord($element) {
1076 //drupal_add_js
1077 return theme('textfield', $element);
1078}
1079
1080function theme_gmap_macrotext($element) {
1081 drupal_add_js(drupal_get_path('module', 'gmap') .'/js/macro.js');
1082 // @@@
1083 drupal_add_js(drupal_get_path('module', 'gmap') .'/js/macrobuilder.js');
1084 return theme('textarea', $element);
1085}
1086
1087function theme_gmap_address($element) {
1088 drupal_add_js(drupal_get_path('module', 'gmap') .'/js/address.js');
1089 return theme('textfield', $element);
1090}
1091
1092function theme_gmap_align($element) {
1093 drupal_add_js(drupal_get_path('module', 'gmap') .'/js/align.js');
1094 return theme('select', $element);
1095}
1096
1097/**
1098 * Gmap element theme hook
1099 */
1100function theme_gmap($element) {
1101 _gmap_doheader();
1102
cbdee739 1103 $mapid = FALSE;
647d2d1b 1104 if (isset($element['#map']) && $element['#map']) {
cbdee739 1105 // The default mapid is #map.
f2b2bee5 1106 $mapid = $element['#map'];
bba8e92a 1107 }
cbdee739
BB
1108 if (isset($element['#settings']['id'])) {
1109 // Settings overrides it.
1110 $mapid = $element['#settings']['id'];
1111 }
1112 if (!$mapid) {
1113 // Hmm, no mapid. Generate one.
1114 $mapid = gmap_get_auto_mapid();
f2b2bee5 1115 }
cbdee739
BB
1116 // Push the mapid back into #map.
1117 $element['#map'] = $mapid;
f2b2bee5 1118
cbdee739 1119 gmap_widget_setup($element, 'gmap', $mapid);
f2b2bee5 1120
bba8e92a
BB
1121 if (!$element['#settings']) {
1122 $element['#settings'] = array();
1123 }
cbdee739
BB
1124
1125 // Push the mapid back into #settings.
1126 $element['#settings']['id'] = $mapid;
1127
bba8e92a
BB
1128 $map = array_merge(gmap_defaults(), $element['#settings']);
1129 gmap_map_cleanup($map);
1130
1131 switch (strtolower($map['align'])) {
1132 case 'left':
1133 $element['#attributes']['class'] += ' gmap-left';
1134 break;
1135 case 'right':
1136 $element['#attributes']['class'] += ' gmap-right';
1137 break;
1138 case 'center':
1139 case 'centre':
1140 $element['#attributes']['class'] += ' gmap-center';
1141 }
1142
1143 $style = array();
1144 $style[] = 'width: '. $map['width'];
1145 $style[] = 'height: '. $map['height'];
1146
cbdee739 1147 $element['#attributes']['class'] = trim($element['#attributes']['class'] .'gmap gmap-map gmap-'. $mapid .'-gmap');
bba8e92a
BB
1148
1149 // Some markup parsers (IE) don't handle empty inners well. Use the space to let users know javascript is required.
1150 // @@@ Bevan sez: Google static maps could be useful here.
1151 // @@@ Bdragon sez: Yeah, would be nice, but hard to guarantee functionality. Not everyone uses the static markerloader.
39fe719b 1152 $o = '<div style="'. implode('; ', $style) .';" id="'. $element['#id'] .'"'. drupal_attributes($element['#attributes']) .'>'. t('Javascript is required to view this map.') .'</div>';
bba8e92a
BB
1153
1154 // $map can be manipulated by reference.
1155 foreach (module_implements('gmap') as $module) {
1156 call_user_func_array($module .'_gmap', array('pre_theme_map', &$map));
1157 }
1158
1159 // Inline settings extend.
1160 $o .= '<script type="text/javascript">'."\n";
1161 $o .= "/* <![CDATA[ */\n";
ea62c4d0 1162 $o .= 'jQuery.extend(true, Drupal, { settings: '. drupal_to_js(array('gmap' => array($element['#map'] => $map))) ." });\n";
bba8e92a
BB
1163 $o .= "/* ]]> */\n";
1164 $o .= "</script>\n";
1165 return $o;
1166}
1167
1168/**
1169 * Set up widget.
1170 * This function will change a form element's ID so it is found
1171 * by the GMap handlers system.
1172 * @param &$element
1173 * The form element to modify.
1174 * @param $type
1175 * The gmap widget type to map to.
1176 * @param $map
1177 * The map id. If not defined, $element['#map'] will be used.
1178 * @return
1179 * None.
1180 */
1181function gmap_widget_setup(&$element, $type, $map=NULL) {
1182 if (!$map) {
1183 if (isset($element['#map'])) {
1184 $map = $element['#map'];
1185 }
1186 else {
1187 // Hmm, missing #map. Try to figure it out.
1188 if (isset($element['#settings']['id'])) {
1189 $map = $element['#settings']['id'];
1190 }
1191 }
1192 }
620d466e
BB
1193 if (!isset($element['#attributes']['class'])) {
1194 $element['#attributes']['class'] = '';
1195 }
bba8e92a
BB
1196 $element['#attributes']['class'] = trim(implode(' ', array(
1197 $element['#attributes']['class'],
1198 'gmap-control',
1199 'gmap-'. $type,
1200 )));
1201 $element['#id'] = gmap_get_id($map, $type);
bba8e92a
BB
1202 $element['#map'] = $map;
1203}
1204
1205/**
1206 * Get a CSS id for a map and type.
1207 * Since CSS ids have to be unique, GMap related IDs are assigned by
1208 * this function.
1209 */
1210function gmap_get_id($map, $type) {
1211 static $serial = array();
1212 if (!isset($serial[$map])) {
1213 $serial[$map] = array();
1214 }
1215 if (!isset($serial[$map][$type])) {
1216 $serial[$map][$type] = -1;
1217 }
1218 $serial[$map][$type]++;
1219 return 'gmap-'. $map .'-'. $type . $serial[$map][$type];
1220}
1221
1222/**
1223 * Generate a dynamic map identifier.
1224 */
1225function gmap_get_auto_mapid() {
1226 static $auto = 0;
1227 $auto++;
1228 return 'auto'. $auto .'map';
1229}
1230
1231/**
1232 * Get the list of marker titles.
1233 */
1234function gmap_get_marker_titles($reset = FALSE) {
1235 static $titles;
1236 if (is_array($titles) && !$reset) {
1237 return $titles;
1238 }
1239
1240 $titles = cache_get('gmap_marker_titles');
1241 if ($titles) {
1e85d651 1242 $titles = $titles->data;
bba8e92a
BB
1243 }
1244
1245 if ($reset || !$titles) {
1246 require_once(drupal_get_path('module', 'gmap') .'/gmap_markerinfo.inc');
1247 $titles = _gmap_get_marker_titles();
1248 }
1e85d651 1249 cache_set('gmap_marker_titles', $titles, 'cache');
bba8e92a
BB
1250 return $titles;
1251}
1252
1253/**
1254 * Get the JSON icon data for all the default markers.
1255 */
1256function gmap_get_icondata($reset = FALSE) {
1257 static $icons;
1258 if (is_array($icons) && !$reset) {
1259 return $icons;
1260 }
1261
1262 $icons = cache_get('gmap_icondata');
1263 if ($icons) {
1e85d651 1264 $icons = $icons->data;
bba8e92a
BB
1265 }
1266
1267 if ($reset || !$icons) {
1268 require_once(drupal_get_path('module', 'gmap') .'/gmap_markerinfo.inc');
1269 $icons = _gmap_get_icondata();
1270 }
1e85d651 1271 cache_set('gmap_icondata', $icons, 'cache');
bba8e92a
BB
1272 return $icons;
1273}
1274
1275/**
1276 * Utility function to allow high-precision decimals to work with the SQL layer.
1277 * Use concatenation. (Apparently unquoted %s is bad.)
1278 */
1279function gmap_decimal($num) {
1280 // Paraphrased from postgresql documentation:
1281 //
1282 // Numbers in SQL can be in one of these forms:
1283 // digits
1284 // digits.[digits][e[+-]digits]
1285 // [digits].digits[e[+-]digits]
1286 // digitse[+-]digits
1287 // where "digits" is one or more decimal digits.
1288
1289 // Trim extra whitespace
1290 $num = trim($num);
1291 // Check if we're in an acceptable form.
1292 if (preg_match('/^[+\-]?((\d+)|(\d+\.\d*)|(\d*\.\d+))(e[+\-]?\d+)?$/', $num)===1) {
1293 // Good, we can pass that right along.
1294 return $num;
1295 }
1296 // Otherwise, cast to float, possibly losing precision.
1297 return (float) $num;
1298}
1299
1300/**
1301 * Utility function to use the google maps geocoder server side.
1302 * This is an easy, quick way to geocode a single address.
1303 * Note: This is a REMOTE CALL TO GOOGLE. Do NOT use this where performance matters,
1304 * as it could possibly take several seconds for this function to return.
1305 * See http://www.google.com/apis/maps/documentation/reference.html#GGeoStatusCode
1306 * for a description of the possible status codes.
1307 */
1308function gmap_geocode($address, $tld = 'com') {
54cbe9f0 1309 $key = gmap_get_key();
bba8e92a
BB
1310 $data = drupal_http_request('http://maps.google.'. $tld .'/maps/geo?q='. drupal_urlencode($address) .'&output=csv&key='. $key);
1311 if ($data->code == 200) {
1312 $r = explode(',', $data->data);
1313 return array(
1314 'status' => (int)$r[0],
1315 'accuracy' => (int)$r[1],
1316 'latitude' => $r[2],
1317 'longitude' => $r[3],
1318 );
1319 }
1320 // Non 200 is G_GEO_SERVER_ERROR (500).
1321 return array(
1322 'status' => 500,
1323 );
1324}
1325
1326/**
1327 * Simple way to draw a map from inside a theme.
1328 * @param $latitude
1329 * Latitude of marker.
1330 * @param $longitude
1331 * Longitude of marker.
1332 * @param $markername
1333 * Marker to use.
1334 * '' will fall back to google's default marker.
1335 * @param $info
1336 * What to show in the bubble when the marker is clicked.
1337 * Leave blank if you don't want a bubble.
1338 * @param $zoom
1339 * Map zoom.
1340 * 'default' will use the default zoom from the settings page.
1341 * 3 is usually a good value to use.
1342 * @param $width
1343 * Map width.
1344 * 'default' will use the default width from the settings page.
1345 * @param $height
1346 * Map height.
1347 * 'default' will use the default height from the settings page.
1348 * @param $autoshow
1349 * If set to TRUE, automatically show the marker bubble.
1350 * @param $map
1351 * Override parts of the map array.
1352 * If you need to do much with this, you should probabaly be putting together
1353 * the map array manually.
1354 */
1355function gmap_simple_map($latitude, $longitude, $markername = '', $info = '', $zoom = 'auto', $width = 'default', $height = 'default', $autoshow = FALSE, $map = array()) {
1356 $settings = array(
1357 'id' => gmap_get_auto_mapid(),
1358 'latitude' => $latitude, // Center the map
1359 'longitude' => $longitude, // on the marker.
1360 );
1361 if ($zoom != 'default') {
1362 $settings['zoom'] = $zoom;
1363 }
1364 if ($width != 'default') {
1365 $settings['width'] = $width;
1366 }
1367 if ($height != 'default') {
1368 $settings['height'] = $height;
1369 }
1370
1371 $settings['markers'] = array(array(
1372 'latitude' => $latitude,
1373 'longitude' => $longitude,
1374 'markername' => $markername,
1375 'offset' => 0,
1376 ));
1377
1378 if (!empty($info)) {
1379 $settings['markers'][0]['text'] = $info;
1380 }
1381
1382 if ($autoshow) {
1383 $settings['markers'][0]['autoclick'] = TRUE;
1384 }
1385
1386 if (!empty($map)) {
1387 $settings = array_merge($settings, $map);
1388 }
1389
1390 return theme('gmap', array('#settings' => $settings));
1391}
1392
1393/**
1394 * Implementation of hook_keys_service(). (from the keys api)
1395 */
1396function gmap_keys_service() {
1397 return array(
1398 'gmap' => array(
1399 'name' => t('Gmap'),
1400 'description' => t('Google Maps API Key'),
1401 ),
1402 );
1403}
54cbe9f0
BB
1404
1405/**
1406 * Retrieve the Google Maps key that is in use for the site.
1407 */
1408function gmap_get_key() {
1409 $key = variable_get('googlemap_api_key', '');
1410 if (module_exists('keys_api')) {
1411 $key = keys_api_get_key('gmap', $_SERVER['HTTP_HOST']);
1412 }
1413 return $key;
1414}
647d2d1b
BB
1415
1416/**
1417 * Implementation of hook_views_plugins().
1418 */
1419function gmap_views_plugins() {
1420 return array(
1421 'module' => 'gmap',
1422 'style' => array(
1423 'gmap' => array(
1424 'title' => t('GMap'),
1425 'help' => t('Displays rows as a map.'),
1426 'handler' => 'gmap_plugin_style_gmap',
1427 'theme' => 'gmap_view_gmap',
1428 'uses row plugin' => TRUE,
1429 'uses options' => TRUE,
1430 'type' => 'normal',
1431 ),
1432 ),
1433 );
1434}