1 2/** 3 * @file 4 * Drupal to Google Maps API bridge. 5 */ 6 7/*global jQuery, Drupal, GLatLng, GSmallZoomControl, GLargeMapControl, GMap2 */ 8/*global GMapTypeControl, GSmallMapControl, G_HYBRID_MAP, G_NORMAL_MAP */ 9/*global G_PHYSICAL_MAP, G_SATELLITE_MAP, GHierarchicalMapTypeControl */ 10/*global GKeyboardHandler, GLatLngBounds, GMenuMapTypeControl, GEvent */ 11/*global GOverviewMapControl, GScaleControl, GUnload */ 12 13(function () { // BEGIN closure 14 var handlers = {}; 15 var maps = {}; 16 var ajaxoffset = 0; 17 18 Drupal.gmap = { 19 20 /** 21 * Retrieve a map object for use by a non-widget. 22 * Use this if you need to be able to fire events against a certain map 23 * which you have the mapid for. 24 * Be a good GMap citizen! Remember to send change()s after modifying variables! 25 */ 26 getMap: function (mapid) { 27 if (maps[mapid]) { 28 return maps[mapid]; 29 } 30 else { 31 // Perhaps the user passed a widget id instead? 32 mapid = mapid.split('-').slice(1, -1).join('-'); 33 if (maps[mapid]) { 34 return maps[mapid]; 35 } 36 } 37 return false; 38 }, 39 40 unloadMap: function (mapid) { 41 delete maps[mapid]; 42 }, 43 44 addHandler: function (handler, callback) { 45 if (!handlers[handler]) { 46 handlers[handler] = []; 47 } 48 handlers[handler].push(callback); 49 }, 50 51 globalChange: function (name, userdata) { 52 for (var mapid in Drupal.settings.gmap) { 53 if (Drupal.settings.gmap.hasOwnProperty(mapid)) { 54 // Skip maps that are set up but not shown, etc. 55 if (maps[mapid]) { 56 maps[mapid].change(name, -1, userdata); 57 } 58 } 59 } 60 }, 61 62 setup: function (settings) { 63 var obj = this; 64 65 var initcallback = function (mapid) { 66 return (function () { 67 maps[mapid].change("bootstrap_options", -1); 68 maps[mapid].change("boot", -1); 69 maps[mapid].change("init", -1); 70 // Send some changed events to fire up the rest of the initial settings.. 71 maps[mapid].change("maptypechange", -1); 72 maps[mapid].change("controltypechange", -1); 73 maps[mapid].change("alignchange", -1); 74 // Set ready to put the event system into action. 75 maps[mapid].ready = true; 76 maps[mapid].change("ready", -1); 77 }); 78 }; 79 80 if (settings || (Drupal.settings && Drupal.settings.gmap)) { 81 var mapid = obj.id.split('-'); 82 if (Drupal.settings['gmap_remap_widgets']) { 83 if (Drupal.settings['gmap_remap_widgets'][obj.id]) { 84 jQuery.each(Drupal.settings['gmap_remap_widgets'][obj.id].classes, function() { 85 jQuery(obj).addClass(this); 86 }); 87 mapid = Drupal.settings['gmap_remap_widgets'][obj.id].id.split('-'); 88 } 89 } 90 var instanceid = mapid.pop(); 91 mapid.shift(); 92 mapid = mapid.join('-'); 93 var control = instanceid.replace(/\d+$/, ''); 94 95 // Lazy init the map object. 96 if (!maps[mapid]) { 97 if (settings) { 98 maps[mapid] = new Drupal.gmap.map(settings); 99 } 100 else { 101 maps[mapid] = new Drupal.gmap.map(Drupal.settings.gmap[mapid]); 102 } 103 // Prepare the initialization callback. 104 var callback = initcallback(mapid); 105 setTimeout(callback, 0); 106 } 107 108 if (handlers[control]) { 109 for (var i = 0; i < handlers[control].length; i++) { 110 handlers[control][i].call(maps[mapid], obj); 111 } 112 } 113 else { 114 // Element with wrong class? 115 } 116 } 117 } 118 }; 119 120 jQuery.fn.createGMap = function (settings, mapid) { 121 return this.each(function () { 122 if (!mapid) { 123 mapid = 'auto' + ajaxoffset + 'ajax'; 124 ajaxoffset++; 125 } 126 settings.id = mapid; 127 jQuery(this) 128 .attr('id', 'gmap-' + mapid + '-gmap0') 129 .css('width', settings.width) 130 .css('height', settings.height) 131 .addClass('gmap-control') 132 .addClass('gmap-gmap') 133 .addClass('gmap') 134 .addClass('gmap-map') 135 .addClass('gmap-' + mapid + '-gmap') 136 .addClass('gmap-processed') 137 .each(function() {Drupal.gmap.setup.call(this, settings)}); 138 }); 139 }; 140 141})(); // END closure 142 143Drupal.gmap.factory = {}; 144 145Drupal.gmap.map = function (v) { 146 this.vars = v; 147 this.map = undefined; 148 this.ready = false;
149 var _bindings = {}; 150 151 /** 152 * Register interest in a change. 153 */ 154 this.bind = function (name, callback) { 155 if (!_bindings[name]) { 156 _bindings[name] = []; 157 } 158 return _bindings[name].push(callback) - 1; 159 }; 160 161 /** 162 * Change notification. 163 * Interested parties can act on changes. 164 */ 165 this.change = function (name, id, userdata) { 166 var c; 167 if (_bindings[name]) { 168 for (c = 0; c < _bindings[name].length; c++) { 169 if (c !== id) { 170 _bindings[name][c](userdata); 171 } 172 } 173 } 174 if (name !== 'all') { 175 this.change('all', -1, name, userdata); 176 } 177 }; 178 179 /** 180 * Deferred change notification. 181 * This will cause a change notification to be tacked on to the *end* of the event queue. 182 */ 183 this.deferChange = function (name, id, userdata) { 184 var obj = this; 185 // This will move the function call to the end of the event loop. 186 setTimeout(function () { 187 obj.change(name, id, userdata); 188 }, 0); 189 }; 190 191 this.getMapTypeName = function(type) { 192 if (type == 'map' || type == 'roadmap') return 'Map'; 193 if (type == 'hybrid') return 'Hybrid'; 194 if (type == 'physical' || type == 'terrain') return 'Physical'; 195 if (type == 'satellite') return 'Satellite'; 196 }; 197 198 this.getMapTypeId = function(type) { 199 if (type == 'Map' || type == 'Roadmap') return google.maps.MapTypeId.ROADMAP; 200 if (type == 'Hybrid') return google.maps.MapTypeId.HYBRID; 201 if (type == 'Physical' || type == 'Terrain') return google.maps.MapTypeId.TERRAIN; 202 if (type == 'Satellite') return google.maps.MapTypeId.SATELLITE; 203 }; 204}; 205 206//////////////////////////////////////// 207// Map widget // 208//////////////////////////////////////// 209Drupal.gmap.addHandler('gmap', function (elem) { 210 var obj = this; 211 var _ib = {}; 212 213 // Respond to incoming zooms 214 _ib.zoom = obj.bind("zoom", function (zoom) { 215 obj.map.setZoom(obj.vars.zoom); 216 }); 217 218 // Respond to incoming moves 219 _ib.move = obj.bind("move", function () { 220 obj.map.panTo(new google.maps.LatLng(obj.vars.latitude, obj.vars.longitude)); 221 }); 222 223 // Respond to incoming width changes. 224 _ib.width = obj.bind("widthchange", function (w) { 225 obj.map.getDiv().style.width = w; 226 google.maps.event.trigger(obj.map); 227 }); 228 // Send out outgoing width changes. 229 // N/A 230 // Respond to incoming height changes. 231 _ib.height = obj.bind("heightchange", function (h) { 232 obj.map.getDiv().style.height = h; 233 google.maps.event.trigger(obj.map); 234 }); 235 // Send out outgoing height changes. 236 // N/A 237 238 // Respond to incoming control type changes. 239 _ib.ctc = obj.bind("controltypechange", function () { 240 if (obj.vars.controltype === 'Small') { 241 obj.map.setOptions({navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL}}); 242 } 243 else if (obj.vars.controltype === 'Large') { 244 obj.map.setOptions({navigationControlOptions: {style: google.maps.NavigationControlStyle.ZOOM_PAN}}); 245 } 246 else if (obj.vars.controltype === 'Android') { 247 obj.map.setOptions({navigationControlOptions: {style: google.maps.NavigationControlStyle.ANDROID}}); 248 } 249 }); 250 // Send out outgoing control type changes. 251 // N/A 252 253 // Respond to incoming map type changes. 254 _ib.mtc = obj.bind("maptypechange", function () { 255 obj.map.setMapTypeId(obj.getMapTypeId(obj.vars.maptype)); 256 }); 257 // Send out outgoing map type changes. 258 // N/A 259 260 obj.bind("bootstrap_options", function () { 261 // Bootup options. 262 var opts = {}; // Object literal google.maps.MapOptions 263 obj.opts = opts; 264 265 // Disable default UI for custom options 266 opts.disableDefaultUI = false; 267 268 // Set draggable property 269 if (obj.vars.behavior.nodrag) { 270 opts.draggable = false; 271 } 272 else if (obj.vars.behavior.nokeyboard) { 273 opts.keyboardShortcuts = false; 274 } 275 276 // Set default map type (set to road map if nothing selected) 277 switch (obj.vars.maptype) { 278 case 'Hybrid': 279 opts.mapTypeId = google.maps.MapTypeId.HYBRID; 280 break; 281 case 'Physical': 282 opts.mapTypeId = google.maps.MapTypeId.TERRAIN; 283 break; 284 case 'Satellite': 285 opts.mapTypeId = google.maps.MapTypeId.SATELLITE; 286 break; 287 case 'Map': 288 default: 289 opts.mapTypeId = google.maps.MapTypeId.ROADMAP; 290 break; 291 } 292 293 // Null out the enabled types. 294 opts.mapTypeIds = []; 295 296 if (obj.vars.baselayers.Map) { 297 opts.mapTypeIds.push(google.maps.MapTypeId.ROADMAP); 298 } 299 if (obj.vars.baselayers.Hybrid) { 300 opts.mapTypeIds.push(google.maps.MapTypeId.HYBRID); 301 } 302 if (obj.vars.baselayers.Physical) { 303 opts.mapTypeIds.push(google.maps.MapTypeId.TERRAIN); 304 } 305 if (obj.vars.baselayers.Satellite) { 306 opts.mapTypeIds.push(google.maps.MapTypeId.SATELLITE); 307 } 308 309 if (obj.vars.draggableCursor) { 310 opts.draggableCursor = obj.vars.draggableCursor; 311 } 312 if (obj.vars.draggingCursor) { 313 opts.draggingCursor = obj.vars.draggingCursor; 314 } 315 if (obj.vars.backgroundColor) { 316 opts.backgroundColor = obj.vars.backgroundColor; 317 } 318 319 // Map type control 320 opts.mapTypeControl = true; 321 opts.mapTypeControlOptions = {}; 322 if (obj.vars.mtc === 'standard') { 323 opts.mapTypeControlOptions.style = google.maps.MapTypeControlStyle.DEFAULT; 324 } 325 else if (obj.vars.mtc === 'horiz') { 326 opts.mapTypeControlOptions.style = google.maps.MapTypeControlStyle.HORIZONTAL_BAR; 327 } 328 else if (obj.vars.mtc === 'menu') { 329 opts.mapTypeControlOptions.style = google.maps.MapTypeControlStyle.DROPDOWN_MENU; 330 } 331 else if (obj.vars.mtc === 'none') { 332 opts.mapTypeControl = false;
333 } 334 335 // Navigation control type 336 if (obj.vars.controltype !== 'None') { 337 opts.navigationControl = true; 338 } 339 if (obj.vars.controltype === 'Small') { 340 opts.navigationControlOptions = {style: google.maps.NavigationControlStyle.SMALL}; 341 } 342 else if (obj.vars.controltype === 'Large') { 343 opts.navigationControlOptions = {style: google.maps.NavigationControlStyle.ZOOM_PAN}; 344 } 345 346 // Set scale control visibility 347 opts.scaleControl = obj.vars.behavior.scale; 348 349 // Scroll wheel control 350 if (obj.vars.behavior.nomousezoom) { 351 opts.scrollwheel = false; 352 } 353 // Disable double-click zoom 354 if (obj.vars.behavior.nocontzoom) { 355 opts.disableDoubleClickZoom = true; 356 } 357 358 opts.zoomControl = true; 359 opts.cameraControl = false; 360 361 }); 362 363 obj.bind("boot", function () { 364 obj.map = new google.maps.Map(elem, obj.opts); 365 //console.log(obj.map); 366 }); 367 368 obj.bind("init", function () { 369 var map = obj.map; 370 371 // Not implemented in API v3 372 // if (obj.vars.behavior.overview) { 373 // map.addControl(new GOverviewMapControl()); 374 // } 375 // if (obj.vars.behavior.googlebar) { 376 // map.enableGoogleBar(); 377 // } 378 379 if (obj.vars.extent) { 380 var c = obj.vars.extent; 381 var extent = new google.maps.LatLngBounds(new google.maps.LatLng(c[0][0], c[0][1]), new google.maps.LatLng(c[1][0], c[1][1])); 382 obj.vars.latitude = extent.getCenter().lat(); 383 obj.vars.longitude = extent.getCenter().lng(); 384 obj.vars.zoom = map.getBoundsZoomLevel(extent); 385 } 386 if (obj.vars.behavior.collapsehack) { 387 // Modify collapsable fieldsets to make maps check dom state when the resize handle 388 // is clicked. This may not necessarily be the correct thing to do in all themes, 389 // hence it being a behavior. 390 setTimeout(function () { 391 var r = function () { 392 google.maps.event.trigger(map); 393 map.setCenter(new google.maps.LatLng(obj.vars.latitude, obj.vars.longitude), obj.vars.zoom); 394 }; 395 jQuery(elem).parents('fieldset.collapsible').children('legend').children('a').click(r); 396 jQuery('.vertical-tab-button', jQuery(elem).parents('.vertical-tabs')).children('a').click(r); 397 jQuery(window).bind('hashchange', r); 398 // Would be nice, but doesn't work. 399 //$(elem).parents('fieldset.collapsible').children('.fieldset-wrapper').scroll(r); 400 }, 0); 401 } 402 map.setCenter(new google.maps.LatLng(obj.vars.latitude, obj.vars.longitude)); 403 map.setZoom(obj.vars.zoom); 404 405 // Send out outgoing zooms 406 google.maps.event.addListener(map, "zoom_changed", function () { 407 obj.vars.zoom = map.getZoom(); 408 obj.change("zoom", _ib.zoom); 409 }); 410 411 // Send out outgoing moves 412 google.maps.event.addListener(map, "center_changed", function () { 413 var coord = map.getCenter(); 414 obj.vars.latitude = coord.lat(); 415 obj.vars.longitude = coord.lng(); 416 obj.change("move", _ib.move); 417 }); 418 419 // Send out outgoing map type changes. 420 google.maps.event.addListener(map, "maptypeid_changed", function () { 421 // If the map isn't ready yet, ignore it. 422 if (obj.ready) { 423 obj.vars.maptype = obj.getMapTypeName(map.getMapTypeId()); 424 obj.change("maptypechange", _ib.mtc); 425 } 426 }); 427 428 /* 429 google.maps.event.addListener(map, 'click', function(event) { 430 alert(Drupal.gmap.getIcon("big blue", 0)); 431 var marker = new google.maps.Marker({ 432 position: event.latLng, 433 map: map 434 }); 435 google.maps.event.addListener(marker, 'click', function() { 436 marker.setMap(null); 437 }); 438 }); 439 */ 440 }); 441}); 442 443//////////////////////////////////////// 444// Zoom widget // 445//////////////////////////////////////// 446Drupal.gmap.addHandler('zoom', function (elem) { 447 var obj = this; 448 // Respond to incoming zooms 449 var binding = obj.bind("zoom", function () { 450 elem.value = obj.vars.zoom; 451 }); 452 // Send out outgoing zooms 453 jQuery(elem).change(function () { 454 obj.vars.zoom = parseInt(elem.value, 10); 455 obj.change("zoom", binding); 456 }); 457}); 458 459//////////////////////////////////////// 460// Latitude widget // 461//////////////////////////////////////// 462Drupal.gmap.addHandler('latitude', function (elem) { 463// var obj = this; 464// // Respond to incoming movements. 465// var binding = obj.bind("move", function () { 466// elem.value = '' + obj.vars.latitude; 467// }); 468// // Send out outgoing movements. 469// $(elem).change(function () { 470// obj.vars.latitude = Number(this.value); 471// obj.change("move", binding); 472// }); 473}); 474 475//////////////////////////////////////// 476// Longitude widget // 477//////////////////////////////////////// 478Drupal.gmap.addHandler('longitude', function (elem) { 479// var obj = this; 480// // Respond to incoming movements. 481// var binding = obj.bind("move", function () { 482// elem.value = '' + obj.vars.longitude; 483// }); 484// // Send out outgoing movements. 485// $(elem).change(function () { 486// obj.vars.longitude = Number(this.value); 487// obj.change("move", binding); 488// }); 489}); 490 491//////////////////////////////////////// 492// Latlon widget // 493//////////////////////////////////////// 494Drupal.gmap.addHandler('latlon', function (elem) { 495 var obj = this; 496 // Respond to incoming movements. 497 var binding = obj.bind("move", function () { 498 elem.value = '' + obj.vars.latitude + ',' + obj.vars.longitude; 499 }); 500 // Send out outgoing movements. 501 jQuery(elem).change(function () { 502 var t = this.value.split(','); 503 obj.vars.latitude = Number(t[0]); 504 obj.vars.longitude = Number(t[1]); 505 obj.change("move", binding); 506 }); 507}); 508 509//////////////////////////////////////// 510// Maptype widget // 511//////////////////////////////////////// 512Drupal.gmap.addHandler('maptype', function (elem) { 513 var obj = this; 514 // Respond to incoming movements. 515 var binding = obj.bind("maptypechange", function () { 516 elem.value = obj.vars.maptype; 517 }); 518 // Send out outgoing movements. 519 jQuery(elem).change(function () { 520 obj.vars.maptype = elem.value; 521 obj.change("maptypechange", binding); 522 }); 523}); 524 525(function () { // BEGIN CLOSURE 526 var re = /([0-9.]+)\s*(em|ex|px|in|cm|mm|pt|pc|%)/; 527 var normalize = function (str) { 528 var ar; 529 if ((ar = re.exec(str.toLowerCase()))) { 530 return ar[1] + ar[2]; 531 } 532 return null; 533 }; 534 535 //////////////////////////////////////// 536 // Width widget // 537 //////////////////////////////////////// 538 Drupal.gmap.addHandler('width', function (elem) { 539 var obj = this; 540 // Respond to incoming width changes. 541 var binding = obj.bind("widthchange", function (w) { 542 elem.value = normalize(w); 543 }); 544 // Send out outgoing width changes. 545 jQuery(elem).change(function () { 546 var n; 547 if ((n = normalize(elem.value))) { 548 elem.value = n; 549 obj.change('widthchange', binding, n); 550 } 551 }); 552 obj.bind('init', function () { 553 jQuery(elem).change(); 554 }); 555 }); 556 557 //////////////////////////////////////// 558 // Height widget // 559 //////////////////////////////////////// 560 Drupal.gmap.addHandler('height', function (elem) { 561 var obj = this; 562 // Respond to incoming height changes. 563 var binding = obj.bind("heightchange", function (h) { 564 elem.value = normalize(h); 565 }); 566 // Send out outgoing height changes. 567 jQuery(elem).change(function () { 568 var n; 569 if ((n = normalize(elem.value))) { 570 elem.value = n; 571 obj.change('heightchange', binding, n); 572 } 573 }); 574 obj.bind('init', function () { 575 jQuery(elem).change(); 576 }); 577 }); 578})(); // END CLOSURE 579 580//////////////////////////////////////// 581// Control type widget // 582//////////////////////////////////////// 583Drupal.gmap.addHandler('controltype', function (elem) { 584 var obj = this; 585 // Respond to incoming height changes. 586 var binding = obj.bind("controltypechange", function () { 587 elem.value = obj.vars.controltype; 588 }); 589 // Send out outgoing height changes. 590 jQuery(elem).change(function () { 591 obj.vars.controltype = elem.value 592 obj.change("controltypechange", binding); 593 }); 594}); 595 596// // Map cleanup. 597// if (Drupal.jsEnabled) { 598// $(document).unload(GUnload); 599// } 600 601Drupal.behaviors.GMap = { 602 attach: function (context, settings) { 603 if (Drupal.settings && Drupal.settings['gmap_remap_widgets']) { 604 jQuery.each(Drupal.settings['gmap_remap_widgets'], function(key, val) { 605 jQuery('#'+ key).addClass('gmap-control'); 606 }); 607 } 608 jQuery('.gmap-gmap:not(.gmap-processed)', context).addClass('gmap-processed').each(function () {Drupal.gmap.setup.call(this)}); 609 jQuery('.gmap-control:not(.gmap-processed)', context).addClass('gmap-processed').each(function () {Drupal.gmap.setup.call(this)}); 610 }, 611 detach: function (context, settings) { 612 jQuery('.gmap-processed', context).each(function (element) { 613 //find mapid 614 var id = jQuery(this).attr('id'); 615 var mapid = id.split('-', 2); 616 617 //unload map 618 Drupal.gmap.unloadMap(mapid[1]); 619 }); 620 } 621}; 622;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.