1/*jslint white: false */ 2/*jslint forin: true */ 3/*global OpenLayers Drupal $ document jQuery window */ 4 5/** 6 * @file 7 * This file holds the main javascript API for OpenLayers. It is 8 * responsable for loading and displaying the map. 9 * 10 * @ingroup openlayers 11 */ 12 13/** 14 * This is a workaround for a bug involving IE and VML support. 15 * See the Drupal Book page describing this problem: 16 * http://drupal.org/node/613002 17 */ 18 19document.namespaces; 20 21(function($) { 22 23Drupal.settings.openlayers = {}; 24Drupal.settings.openlayers.maps = {}; 25 26/** 27 * Minimal OpenLayers map bootstrap. 28 * All additional operations occur in additional Drupal behaviors. 29 */ 30Drupal.behaviors.openlayers = { 31 'attach': function(context, settings) { 32 Drupal.openlayers.loadProjections(context, settings); 33 34 if (typeof(Drupal.settings.openlayers) === 'object' && 35 Drupal.settings.openlayers.maps && 36 !$(context).data('openlayers')) { 37 $('.openlayers-map').once('openlayers-map', function() { 38 // By setting the stop_render variable to TRUE, this will 39 // halt the render process. If set, one could remove this setting 40 // then call Drupal.attachBehaviors again to get it started 41 var map_id = $(this).attr('id'); 42 if (Drupal.settings.openlayers.maps[map_id] && Drupal.settings.openlayers.maps[map_id].stop_render != true) { 43 var map = Drupal.settings.openlayers.maps[map_id]; 44 45 if(map.default_layer===null){ 46 Drupal.openlayers.console.error("Map configuration is invalid as it lacks a base layer."); 47 } 48 49 // Use try..catch for error handling. 50 try { 51 // Set OpenLayers language based on document language, 52 // rather than browser language 53 OpenLayers.Lang.setCode($('html').attr('lang')); 54 55 var options = {}; 56 // This is necessary because the input JSON cannot contain objects 57 options.projection = new OpenLayers.Projection(map.projection); 58 options.displayProjection = new OpenLayers.Projection(map.displayProjection); 59 60 // Restrict map to its extent (usually projection extent). 61 options.maxExtent = OpenLayers.Bounds.fromArray(map.maxExtent); 62 63 options.maxResolution = 'auto'; 64 options.controls = []; 65 66 // Change image, CSS, and proxy paths if specified 67 if (map.image_path) { 68 OpenLayers.ImgPath = Drupal.openlayers.relatePath(map.image_path, 69 Drupal.settings.basePath); 70 } 71 if (map.css_path) { 72 options.theme = Drupal.openlayers.relatePath(map.css_path, 73 Drupal.settings.basePath); 74 } 75 if (map.proxy_host) { 76 OpenLayers.ProxyHost = Drupal.openlayers.relatePath(map.proxy_host, 77 Drupal.settings.basePath); 78 } 79 80 // Initialize openlayers map 81 var openlayers = new OpenLayers.Map(map_id, options); 82 83 // Run the layer addition first 84 Drupal.openlayers.addLayers(map, openlayers); 85 86 // Ensure redraw as maps stays blank until first zoom otherwise (observed with EPSG:2056) 87 openlayers.moveTo(openlayers.getCenter(), openlayers.getZoom(), { 88 forceZoomChange: true 89 }); 90 91 // Attach data to map DOM object 92 $(this).data('openlayers', {'map': map, 'openlayers': openlayers}); 93 94 // Finally, attach behaviors 95 Drupal.attachBehaviors(this); 96 97 if ($.browser.msie) { 98 $(window).load(function() { 99 openlayers.render(map.id); 100 }); 101 } else { 102 openlayers.render(map.id); 103 } 104 } 105 catch (e) { 106 var errorMessage = e.name + ': ' + e.message; 107 if (typeof console != 'undefined') { 108 Drupal.openlayers.console.log(errorMessage); 109 } 110 else { 111 $(this).text('Error during map rendering: ' + errorMessage); 112 } 113 } 114 } 115 }); 116 } 117 } 118}; 119 120/** 121 * Collection of helper methods. 122 */ 123Drupal.openlayers = { 124 // Determine path based on format. 125 'relatePath': function(path, basePath) { 126 // Check for a full URL or an absolute path. 127 if (path.indexOf('://') >= 0 || path.indexOf('/') == 0) { 128 return path; 129 } 130 else { 131 return basePath + path; 132 } 133 }, 134 /* 135 * Redraw Vectors. 136 * This is necessary because various version of IE cannot draw vectors on 137 * $(document).ready() 138 */ 139 'redrawVectors': function() { 140 $(window).load( 141 function() { 142 var map; 143 for (map in Drupal.settings.openlayers.maps) {
144 $.each($('#' + map).data('openlayers') 145 .openlayers.getLayersByClass('OpenLayers.Layer.Vector'), 146 function(i, layer) { 147 layer.redraw(); 148 } 149 ); 150 } 151 } 152 ); 153 }, 154 /** 155 * Add layers to the map 156 * 157 * @param map Drupal settings object for the map. 158 * @param openlayers OpenLayers Map Object. 159 */ 160 'addLayers': function(map, openlayers) { 161 162 var sorted = []; 163 for (var name in map.layers) { 164 sorted.push({'name': name, 'weight': map.layers[name].weight, 'isBaseLayer': map.layers[name].isBaseLayer }); 165 } 166 167 sorted.sort(function(a, b) { 168 var x = parseInt(a.weight, 10), y = parseInt(b.weight, 10); 169 return ((a.isBaseLayer && x < y) ? -1 : ((b.isBaseLayer || x > y) ? 1 : 0)); 170 }); 171 172 for (var i = 0; i < sorted.length; ++i) { 173 var layer, 174 name = sorted[i].name, 175 options = map.layers[name]; 176 177 // Add reference to our layer ID 178 options.drupalID = name; 179 // Ensure that the layer handler is available 180 if (options.layer_handler !== undefined && 181 Drupal.openlayers.layer[options.layer_handler] !== undefined) { 182 layer = Drupal.openlayers.layer[options.layer_handler](map.layers[name].title, map, options); 183 184 layer.visibility = !!(!map.layer_activated || map.layer_activated[name]); 185 186 if (layer.isBaseLayer === false) { 187 layer.displayInLayerSwitcher = (!map.layer_switcher || map.layer_switcher[name]); 188 } 189 190 openlayers.addLayer(layer); 191 } 192 } 193 194 openlayers.setBaseLayer(openlayers.getLayersBy('drupalID', map.default_layer)[0]); 195 196 // Set the restricted extent if wanted. 197 // Prevents the map from being panned outside of a specfic bounding box. 198 if (typeof map.center.restrict !== 'undefined' && map.center.restrict.restrictextent) { 199 var desiredRestriction = OpenLayers.Bounds.fromString( 200 map.center.restrict.restrictedExtent 201 ).transform(new OpenLayers.Projection('EPSG:3857'), openlayers.projection); 202 203 if(desiredRestriction.left>=openlayers.maxExtent.left && desiredRestriction.right<=openlayers.maxExtent.right 204 && desiredRestriction.top<=openlayers.maxExtent.top && desiredRestriction.bottom>=openlayers.maxExtent.bottom){ 205 206 openlayers.restrictedExtent = desiredRestriction; 207 } else { 208 // Given the map to set the restricted extent is not dependent on the map projection 209 // it does allow to set an extent outwith the valid bound of the map projection. As a 210 // result no valid data could be requested and thus the wrong extent needs to be ignored. 211 Drupal.openlayers.console.error("Restricted bounds ignored as not within projection bounds."); 212 } 213 } 214 215 // Zoom & center 216 if (map.center.initial) { 217 var center = OpenLayers.LonLat.fromString(map.center.initial.centerpoint).transform( 218 new OpenLayers.Projection('EPSG:4326'), 219 new OpenLayers.Projection(map.projection)); 220 var zoom = parseInt(map.center.initial.zoom, 10); 221 openlayers.setCenter(center, zoom, false, false); 222 } 223 }, 224 /** 225 * Abstraction of OpenLayer's feature adding syntax to work with Drupal output. 226 * Ideally this should be rolled into the PHP code, because we don't want to manually 227 * parse WKT 228 */ 229 'addFeatures': function(map, layer, features) { 230 var newFeatures = []; 231 232 // Go through features 233 for (var key in features) { 234 var feature = features[key]; 235 var newFeatureObject = this.objectFromFeature(feature); 236 237 // If we have successfully extracted geometry add additional 238 // properties and queue it for addition to the layer 239 if (newFeatureObject) { 240 var newFeatureSet = []; 241 242 // Check to see if it is a new feature, or an array of new features. 243 if (typeof(newFeatureObject[0]) === 'undefined') { 244 newFeatureSet[0] = newFeatureObject; 245 } 246 else { 247 newFeatureSet = newFeatureObject; 248 } 249 250 // Go through new features 251 for (var i = 0; i < newFeatureSet.length; i++) { 252 var newFeature = newFeatureSet[i]; 253 254 // Transform the geometry if the 'projection' property is different from the map projection 255 if (feature.projection) { 256 if (feature.projection !== map.projection) { 257 var featureProjection = new OpenLayers.Projection(feature.projection); 258 var mapProjection = new OpenLayers.Projection(map.projection); 259 newFeature.geometry.transform(featureProjection, mapProjection); 260 } 261 } 262 263 // Add attribute data 264 if (feature.attributes) { 265 // Attributes belong to features, not single component geometries 266 // of them. But we're creating a geometry for each component for 267 // better performance and clustering support. Let's call these 268 // "pseudofeatures". 269 // 270 // In order to identify the real feature each geometry belongs to 271 // we then add a 'fid' parameter to the "pseudofeature". 272 // NOTE: 'drupalFID' is only unique within a single layer. 273 newFeature.attributes = feature.attributes; 274 newFeature.data = feature.attributes; 275 newFeature.drupalFID = key; 276 } 277 278 // Add style information 279 if (feature.style) { 280 newFeature.style = jQuery.extend({}, 281 OpenLayers.Feature.Vector.style['default'], 282 feature.style); 283 } 284 285 // Push new features 286 newFeatures.push(newFeature); 287 } 288 } 289 } 290 291 // Add new features if there are any 292 if (newFeatures.length !== 0) { 293 layer.addFeatures(newFeatures); 294 } 295 }, 296 297 'getStyleMap': function(map, layername) { 298 if (map.styles) { 299 var stylesAdded = {}; 300 301 // Grab and map base styles. 302 for (var style in map.styles) { 303 stylesAdded[style] = new OpenLayers.Style(map.styles[style]); 304 } 305 306 // Implement layer-specific styles. First default, then select. 307 if (map.layer_styles !== undefined && map.layer_styles[layername]) { 308 var style = map.layer_styles[layername]; 309 stylesAdded['default'] = new OpenLayers.Style(map.styles[style]); 310 } 311 if (map.layer_styles_select !== undefined && map.layer_styles_select[layern
311ame]) { 312 var style = map.layer_styles_select[layername]; 313 stylesAdded['select'] = new OpenLayers.Style(map.styles[style]); 314 } 315 if (map.layer_styles_temporary !== undefined && map.layer_styles_temporary[layername]) { 316 var style = map.layer_styles_temporary[layername]; 317 stylesAdded['temporary'] = new OpenLayers.Style(map.styles[style]); 318 } 319 320 return new OpenLayers.StyleMap(stylesAdded); 321 } 322 else { 323 return new OpenLayers.StyleMap({ 324 'default': new OpenLayers.Style({ 325 pointRadius: 5, 326 fillColor: '#ffcc66', 327 strokeColor: '#ff9933', 328 strokeWidth: 4, 329 fillOpacity: 0.5 330 }), 331 'select': new OpenLayers.Style({ 332 fillColor: '#66ccff', 333 strokeColor: '#3399ff' 334 }) 335 }); 336 } 337 }, 338 339 'objectFromFeature': function(feature) { 340 var wktFormat = new OpenLayers.Format.WKT(); 341 // Extract geometry either from wkt property or lon/lat properties 342 if (feature.wkt) { 343 return wktFormat.read(feature.wkt); 344 } 345 else if (feature.lon) { 346 return wktFormat.read('POINT(' + feature.lon + ' ' + feature.lat + ')'); 347 } 348 }, 349 350 /** 351 * Add Behavior. 352 * 353 * This is a wrapper around adding behaviors for OpenLayers. 354 * a module does not have to use this, but it helps cut 355 * down on code. 356 * 357 * @param id 358 * The identifier of the behavior that is attached to 359 * the map. 360 * @param attach 361 * The callback function for the attach part of the 362 * Drupal behavior. 363 * @param detach 364 * The callback function for the detach part of the 365 * Drupal behavior. 366 */ 367 'addBehavior': function(id, attach, detach) { 368 // Add as a Drupal behavior. Add a prefix, just to be safe. 369 Drupal.behaviors['openlayers_auto_' + id] = { 370 attach: function (context, settings) { 371 var data = $(context).data('openlayers'); 372 373 // Ensure that there is a map and that the appropriate 374 // behavior exists. Need "data &&" to avoid js crash 375 // when data is empty 376 var localBehavior = data && data.map.behaviors[id]; 377 378 // Ensure scope in the attach callback 379 var that = this; 380 if (localBehavior) { 381 $(context).once('openlayers-' + id, function () { 382 attach.apply(that, [data, data.map.behaviors[id], context, settings]); 383 }); 384 } 385 }, 386 // Maybe we need a little more handling here. 387 detach: detach 388 }; 389 }, 390 391 /** 392 * Add Control. 393 * 394 * This is a wrapper around adding controls to maps. It 395 * is not needed but saves some code. 396 */ 397 'addControl': function(openlayers, controlName, options) { 398 var control = new OpenLayers.Control[controlName](options); 399 openlayers.addControl(control); 400 control.activate(); 401 return control; 402 }, 403 404 /** 405 * Instructs the Proj4js module to make projection definitions available 406 * to Proj4js and thus OpenLayers, too. 407 * 408 * Triggering the initialization of Proj4js this way guarantees projection 409 * definitions are available. 410 */ 411 'loadProjections': function(context, settings){ 412 // Proj4js is not necessarily present as we only load it when OpenLayers 413 // can't handle the projections is use without its help. 414 if(Drupal.behaviors.proj4js){ 415 Drupal.behaviors.proj4js.attach(context, settings); 416 } 417 }, 418 419 /** 420 * Logging implementation that logs using the browser's logging API. 421 * Falls back to doing nothing in case no such API is available. Simulates 422 * the presece of Firebug's console API in Drupal.openlayers.console. 423 */ 424 'console': (function(){ 425 var api = {}; 426 var logger; 427 if(typeof(console)==="object" && typeof(console.log)==="function"){ 428 logger = function(){ 429 // Use console.log as fallback for missing parts of API if present. 430 console.log.apply(console, arguments); 431 } 432 } else { 433 logger = function (){ 434 // Ignore call as no logging facility is available. 435 }; 436 } 437 jQuery(["log", "debug", "info", "warn", "exception", "assert", "dir", 438 "dirxml", "trace", "group", "groupEnd", "groupCollapsed", "profile", 439 "profileEnd", "count", "clear", "time", "timeEnd", "timeStamp", "table", 440 "error"]).each(function(index, functionName){ 441 if(typeof(console)!=="object" || typeof(console[functionName])!=="function"){ 442 // Use fallback as browser does not provide implementation. 443 api[functionName] = logger; 444 } else { 445 api[functionName] = function(){ 446 // Use browsers implementation. 447 console[functionName].apply(console, arguments); 448 }; 449 } 450 }); 451 return api; 452 })() 453}; 454 455Drupal.openlayers.layer = {}; 456})(jQuery); 457; 458 459/** 460 * @file 461 * Layer handler for XYZ layers 462 */ 463
464/** 465 * Openlayer layer handler for XYZ layer 466 */ 467Drupal.openlayers.layer.xyz = function(title, map, options) { 468 if (OpenLayers.Util.isArray(options.maxExtent)) { 469 options.maxExtent = OpenLayers.Bounds.fromArray(options.maxExtent); 470 } 471 472 // Legacy goodnes 473 if (typeof options.base_url == 'string' && typeof options.url == 'undefined') { 474 options.url = options.base_url; 475 } 476 477 // Server resolutions are very particular in OL 2.11 478 var r = options.serverResolutions; 479 if (r == null || typeof r == 'undefined' || r.length == 0) { 480 options.serverResolutions = null; 481 } 482 483 // Wrap Date Line does not seem to work for 2.10. This may 484 // have something to do with our extent definitions. 485 if (OpenLayers.VERSION_NUMBER.indexOf('2.10') >= 0) { 486 options.wrapDateLine = null; 487 } 488 489 options.projection = new OpenLayers.Projection(options.projection); 490 491 return new OpenLayers.Layer.XYZ(title, options.url, options); 492}; 493; 494/** 495 * @file 496 * JS Implementation of OpenLayers behavior. 497 */ 498 499/** 500 * Attribution Behavior. Implements the Attribution OpenLayers 501 * Control. 502 */ 503Drupal.openlayers.addBehavior('openlayers_behavior_attribution', function (data, options) { 504 Drupal.openlayers.addControl(data.openlayers, 'Attribution', options); 505}); 506; 507 508/** 509 * OpenLayers Views Vector Layer Handler 510 */ 511Drupal.openlayers.layer.openlayers_views_vector = function(title, map, options) { 512 // Note, so that we do not pass all the features along to the Layer 513 // options, we use the options.options to give to Layer 514 options.options.drupalID = options.drupalID; 515 516 // Create projection 517 options.projection = new OpenLayers.Projection(options.projection); 518 // Get style map 519 options.options.styleMap = Drupal.openlayers.getStyleMap(map, options.drupalID); 520 // Create layer object 521 var layer = new OpenLayers.Layer.Vector(title, options.options); 522 523 // Add features if there are any 524 if (options.features) { 525 Drupal.openlayers.addFeatures(map, layer, options.features); 526 } 527 528 return layer; 529}; 530; 531/** 532 * @file 533 * OpenLayers Behavior implementation for clustering. 534 */ 535 536/** 537 * OpenLayers Cluster Behavior. 538 */ 539Drupal.openlayers.addBehavior('openlayers_behavior_cluster', function (data, options) { 540 var map = data.openlayers; 541 var layers = []; 542 for (var i in options.clusterlayer) { 543 var selectedLayer = map.getLayersBy('drupalID', options.clusterlayer[i]); 544 if (selectedLayer[0] instanceof OpenLayers.Layer.Vector) { 545 layers.push(selectedLayer[0]); 546 } 547 } 548 549 // Cluster chosen layers 550 jQuery(layers).each(function(index, layer){ 551 var cluster = new OpenLayers.Strategy.Cluster(options); 552 layer.addOptions({ 'strategies': [cluster] }); 553 cluster.setLayer(layer); 554 cluster.features = layer.features.slice(); 555 cluster.activate(); 556 cluster.cluster(); 557 558 var showLabel = ""; 559 if (options.display_cluster_numbers) { 560 showLabel = "${count}"; 561 } 562 563 // Define styleMap rules, which set pointRadius size, color and labeling 564 // based on the number of points in each cluster. 565 var style = new OpenLayers.Style(); 566 567 // Style for an individual feature (which is not clustered) 568 var ruleIndividual = new OpenLayers.Rule({ 569 filter: new OpenLayers.Filter.Comparison({ 570 type: OpenLayers.Filter.Comparison.LESS_THAN, 571 property: "count", 572 value: 2 573 }), 574 // Apply the style you've selected for this layer for the individual points 575 symbolizer: layer.styleMap.styles["default"].defaultStyle 576 }); 577 // Define three rules to style the cluster features. 578 var ruleSmall = new OpenLayers.Rule({ 579 filter: new OpenLayers.Filter.Comparison({ 580 type: OpenLayers.Filter.Comparison.BETWEEN, 581 property: "count", 582 lowerBoundary: 2, 583 upperBoundary: options.middle_lower_bound 584 }), 585 symbolizer: { 586 fillColor: options.low_color, 587 strokeColor: options.low_color, 588 fillOpacity: 0.8, 589 pointRadius: 10, 590 label: showLabel, 591 labelOutlineWidth: 1, 592 fontColor: "#000000", 593 fontOpacity: 0.8, 594 fontSize: "12px" 595 } 596 }); 597 var ruleMedium = new OpenLayers.Rule({ 598 filter: new OpenLayers.Filter.Comparison({ 599 type: OpenLayers.Filter.Comparison.BETWEEN, 600 property: "count", 601 lowerBoundary: options.middle_lower_bound, 602 upperBoundary: options.middle_upper_bound 603 }), 604 symbolizer: { 605 fillColor: options.middle_color, 606 strokeColor: options.middle_color, 607 fillOpacity: 0.8, 608 pointRadius: 16, 609 label: showLabel, 610 labelOutlineWidth: 1, 611 fontColor: "#000000", 612 fontOpacity: 0.8, 613 fontSize: "12px" 614 } 615 }); 616 var ruleBig = new OpenLayers.Rule({ 617 filter: new OpenLayers.Filter.Comparison({ 618 type: OpenLayers.Filter.Comparison.GREATER_THAN, 619 property: "count", 620 value: options.middle_upper_bound 621 }), 622 symbolizer: { 623 fillColor: options.high_color, 624 strokeColor: options.high_color, 625 fillOpacity: 0.8, 626 pointRadius: 22, 627 label: showLabel, 628 labelOutlineWidth: 1, 629 fontColor: "#000000", 630 fontOpacity: 0.8, 631 fontSize: "12px" 632 } 633 }); 634 var ruleElse = new OpenLayers.Rule({ 635 filter: new OpenLayers.Filter.Comparison({ 636 type: OpenLayers.Filter.Comparison.EQUAL_TO, 637 property: "count", 638 value: undefined 639 }), 640 symbolizer: layer.styleMap.styles["default"].defaultStyle, 641 elseFilter: true 642 }); 643 644 style.addRules([ruleIndividual, ruleSmall, ruleMedium, ruleBig, ruleElse]); 645 var styleMap = new OpenLayers.StyleMap(style); 646 647 layer.styleMap = styleMap; 648 layer.redraw(); 649 }); 650}); 651 652/**
653 * Override of callback used by 'popup' behaviour to support clusters 654 */ 655Drupal.theme.openlayersPopup = function (feature) { 656 if (feature.cluster) { 657 var output = ''; 658 var visited = []; // to keep track of already-visited items 659 var classes = []; 660 661 for (var i = 0; i < feature.cluster.length; i++) { 662 var pf = feature.cluster[i]; // pseudo-feature 663 if (typeof pf.drupalFID != 'undefined') { 664 var mapwide_id = feature.layer.drupalID + pf.drupalFID; 665 if (mapwide_id in visited) continue; 666 visited[mapwide_id] = true; 667 } 668 669 classes = ['openlayers-popup', 'openlayers-popup-feature']; 670 if (i == 0) { 671 classes.push('first'); 672 } 673 if (i == (feature.cluster.length - 1)) { 674 classes.push('last'); 675 } 676 677 output += '<div class="'+classes.join(' ')+'">' + 678 Drupal.theme.prototype.openlayersPopup(pf) + '</div>'; 679 } 680 return output; 681 } 682 else { 683 return Drupal.theme.prototype.openlayersPopup(feature); 684 } 685}; 686; 687/** 688 * @file 689 * JS Implementation of OpenLayers behavior. 690 */ 691 692/** 693 * Attribution Behavior 694 */ 695Drupal.openlayers.addBehavior('openlayers_behavior_fullscreen', function (data, options) { 696 // Create new panel control and add. 697 var fullscreenPanel = new OpenLayers.Control.Panel({ 698 displayClass: 'openlayers_behavior_fullscreen_button_panel' 699 }); 700 data.openlayers.addControl(fullscreenPanel); 701 702 // Create toggleing control and cutton. 703 var toggler = OpenLayers.Function.bind( 704 Drupal.openlayers.fullscreenToggle, data); 705 var button = new OpenLayers.Control.Button({ 706 displayClass: 'openlayers_behavior_fullscreen_button', 707 title: Drupal.t('Fullscreen'), 708 trigger: toggler 709 }); 710 fullscreenPanel.addControls([button]); 711 712 // Make fullscreen by default if activited. 713 if (options.activated == true) { 714 toggler(); 715 } 716}); 717 718/** 719 * Toggling function for FullScreen control. 720 */ 721Drupal.openlayers.fullscreenToggle = function () { 722 var $map = jQuery(this.openlayers.div); 723 var extent = this.openlayers.getExtent(); 724 725 $map.parent().toggleClass('openlayers_map_fullscreen'); 726 $map.toggleClass('openlayers_map_fullscreen'); 727 $map.data('openlayers').openlayers.updateSize(); 728 $map.data('openlayers').openlayers.zoomToExtent(extent, true); 729}; 730; 731 732/** 733 * @file 734 * JS Implementation of OpenLayers behavior. 735 */ 736 737/** 738 * Keyboard Defaults Behavior. Implements the KeyboardDefaults OpenLayers 739 * Control. 740 */ 741Drupal.openlayers.addBehavior('openlayers_behavior_keyboarddefaults', function (data, options) { 742 Drupal.openlayers.addControl(data.openlayers, 'KeyboardDefaults'); 743}); 744; 745/** 746 * @file 747 * JS Implementation of OpenLayers behavior. 748 */ 749 750/** 751 * Navigation Behavior 752 */ 753Drupal.openlayers.addBehavior('openlayers_behavior_navigation', function (data, options) { 754 options.documentDrag = !!options.documentDrag; 755 Drupal.openlayers.addControl(data.openlayers, 'Navigation', options); 756}); 757; 758/** 759 * @file 760 * JS Implementation of OpenLayers behavior. 761 */ 762 763/** 764 * Pan Zoom Bar Behavior 765 */ 766Drupal.openlayers.addBehavior('openlayers_behavior_panzoombar', function (data, options) { 767 Drupal.openlayers.addControl(data.openlayers, 'PanZoomBar', options); 768}); 769;
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.