xref: /plugin/openlayersmap/script.js (revision 433c5225bf984b2784682e1f696dd05d0db87d58)
1/*
2 * Copyright (c) 2008-2014 Mark C. Prins <mprins@users.sf.net>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/**
18 * @fileoverview Javascript voor OpenLayers plugin.
19 *
20 * @requires {lib/OpenLayers.js} or a full openlayers build
21 * @author Mark C. Prins <mprins@users.sf.net>
22 *
23 */
24
25/**
26 * Openlayers selectcontrol.
27 *
28 * @type {OpenLayers.Control.SelectFeature}
29 * @private
30 */
31var selectControl;
32
33/**
34 * handle feature select event.
35 *
36 * @param {OpenLayers.Feature.Vector}
37 *            selFeature the selected feature
38 */
39function onFeatureSelect(selFeature) {
40	// 'this' is selectFeature control
41	var pPos = selFeature.geometry.getBounds().getCenterLonLat();
42	// != OpenLayers.Geometry.Point
43	if (selFeature.geometry.CLASS_NAME === "OpenLayers.Geometry.LineString") {
44		try {
45			// for lines make the popup show at the cursor position
46			pPos = selFeature.layer.map.getLonLatFromViewPortPx(this.handlers.feature.evt.xy);
47		} catch (anErr) {
48			OpenLayers.Console.warn("unable to get event position; reverting to boundingbox center.");
49			pPos = selFeature.geometry.getBounds().getCenterLonLat();
50		}
51	}
52
53	var pContent = '<div class="spacer">&nbsp;</div>';
54	if (selFeature.data.rowId !== undefined) {
55		pContent += '<span class="rowId">' + selFeature.data.rowId + ': </span>';
56	}
57	if (selFeature.data.name !== undefined) {
58		pContent += '<span class="txt">' + selFeature.data.name + '</span>';
59	}
60	if (selFeature.data.ele !== undefined) {
61		pContent += '<div class="ele">elevation: ' + selFeature.data.ele + '</div>';
62	}
63	if (selFeature.data.type !== undefined) {
64		pContent += '<div>' + selFeature.data.type + '</div>';
65	}
66	if (selFeature.data.time !== undefined) {
67		pContent += '<div class="time">time: ' + selFeature.data.time + '</div>';
68	}
69	if (selFeature.data.description !== undefined) {
70		pContent += '<div class="desc">' + selFeature.data.description + '</div>';
71	}
72	// mapillary layer
73	if (selFeature.attributes.location !== undefined) {
74		pContent += '<div class="desc">' + selFeature.data.location + '</div>';
75	}
76	if (selFeature.attributes.image !== undefined) {
77		pContent += '<img class="img" src=' + selFeature.data.image + ' width="320" />';
78	}
79	if (selFeature.attributes.ca !== undefined) {
80		pContent += '<div class="coord"><img src="' + DOKU_BASE + 'lib/plugins/openlayersmapoverlays/icons/arrow-up-20.png'
81				+ '" width="16" height="16" style="transform:rotate(' + selFeature.data.ca + 'deg)" /></div>';
82	}
83	if (selFeature.attributes.img !== undefined) {
84		pContent += '<div class="coord"><img src="' + selFeature.attributes.img
85				+ '" width="16" height="16" style="transform:rotate(' + selFeature.attributes.angle + 'deg)" />'
86				+ '(lat;lon:' + selFeature.data.latlon + ')</div>';
87	}
88	if (pContent.length > 0) {
89		// only show when there is something to show...
90		var popup = new OpenLayersMap.Popup.FramedCloud("olPopup", pPos, null, pContent, null, true, function() {
91			selectControl.unselect(selFeature);
92			jQuery('#' + selectControl.layer.map.div.id).focus();
93		});
94		selFeature.popup = popup;
95		selFeature.layer.map.addPopup(popup);
96		jQuery('#olPopup').attr("tabindex", -1).focus();
97	}
98}
99
100/**
101 * handle feature unselect event. remove & destroy the popup.
102 *
103 * @param {OpenLayers.Feature.Vector}
104 *            selFeature the un-selected feature
105 */
106function onFeatureUnselect(selFeature) {
107	if (selFeature.popup !== null) {
108		selFeature.layer.map.removePopup(selFeature.popup);
109		selFeature.popup.destroy();
110		selFeature.popup = null;
111	}
112}
113/**
114 * Test for css support in the browser by sniffing for a css class we added
115 * using javascript added by the action plugin; this is an edge case because
116 * browsers that support javascript generally support css as well.
117 *
118 * @returns {Boolean} true when the browser supports css (and implicitly
119 *          javascript)
120 */
121function olTestCSSsupport() {
122	return (jQuery('.olCSSsupported').length > 0);
123}
124
125/**
126 * Creates a DocumentFragment to insert into the dom.
127 *
128 * @param mapid
129 *            id for the map div
130 * @param width
131 *            width for the map div
132 * @param height
133 *            height for the map div
134 * @returns a {DocumentFragment} element that can be injected into the dom
135 */
136function olCreateMaptag(mapid, width, height) {
137	var mEl = '<div id="' + mapid + '-olContainer" class="olContainer olWebOnly">'
138	// map
139	+ '<div id="' + mapid + '" tabindex="0" style="width:' + width + ';height:' + height + ';" class="olMap"></div>'
140	// statusbar
141	+ '<div id="' + mapid + '-olStatusBar" style="width:' + width + ';" class="olStatusBarContainer">' + '  <div id="'
142			+ mapid + '-statusbar-scale" class="olStatusBar olStatusBarScale">scale</div>' + '  <div id="' + mapid
143			+ '-statusbar-mouseposition" class="olStatusBar olStatusBarMouseposition"></div>' + '  <div id="' + mapid
144			+ '-statusbar-projection" class="olStatusBar olStatusBarProjection">proj</div>' + '  <div id="' + mapid
145			+ '-statusbar-text" class="olStatusBar olStatusBarText">txt</div>' + '</div>'
146			//
147			+ '</div>',
148	// fragment
149	frag = document.createDocumentFragment(),
150	// temp node
151	temp = document.createElement('div');
152	temp.innerHTML = mEl;
153	while (temp.firstChild) {
154		frag.appendChild(temp.firstChild);
155	}
156	return frag;
157}
158
159/**
160 * Create the map based on the params given.
161 *
162 * @param {Object}
163 *            mapOpts MapOptions hash {id:'olmap', width:500px, height:500px,
164 *            lat:6710200, lon:506500, zoom:13, statusbar:1, controls:1,
165 *            poihoverstyle:1, baselyr:'', kmlfile:'', gpxfile:'', geojsonfile,
166 *            summary:''}
167 * @param {Array}
168 *            OLmapPOI array with POI's [ {lat:6710300,lon:506000,txt:'instap
169 *            punt',angle:180,opacity:.9,img:'', rowId:n},... ]);
170 *
171 * @return {OpenLayers.Map} the created map
172 */
173function createMap(mapOpts, OLmapPOI) {
174	if (!olEnable) {
175		return;
176	}
177	if (!olTestCSSsupport()) {
178		olEnable = false;
179		return;
180	}
181	OpenLayers.ImgPath = DOKU_BASE + 'lib/plugins/openlayersmap/lib/img/';
182	OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
183
184	// find map element location
185	var cleartag = document.getElementById(mapOpts.id + '-clearer');
186	if (cleartag === null) {
187		return;
188	}
189	// create map element and add to document
190	var fragment = olCreateMaptag(mapOpts.id, mapOpts.width, mapOpts.height);
191	cleartag.parentNode.insertBefore(fragment, cleartag);
192
193	/** dynamic map extent. */
194	var extent = new OpenLayers.Bounds(),
195
196	/** map. */
197	m = new OpenLayers.Map({
198		div : mapOpts.id,
199		projection : 'EPSG:900913',
200		displayProjection : new OpenLayers.Projection("EPSG:4326"),
201		numZoomLevels : 22,
202		controls : [],
203		theme : null
204	});
205
206	if (osmEnable) {
207		/* add OSM map layers */
208		m.addLayer(new OpenLayers.Layer.OSM());
209
210		/* open cycle map */
211		m.addLayer(new OpenLayersMap.Layer.OCM());
212		m.addLayer(new OpenLayersMap.Layer.OCM("transport", [
213				"http://a.tile2.opencyclemap.org/transport/${z}/${x}/${y}.png",
214				"http://b.tile2.opencyclemap.org/transport/${z}/${x}/${y}.png",
215				"http://c.tile2.opencyclemap.org/transport/${z}/${x}/${y}.png" ], {
216			visibility : mapOpts.baselyr === "transport"
217		}));
218		m.addLayer(new OpenLayersMap.Layer.OCM("landscape", [
219				"http://a.tile3.opencyclemap.org/landscape/${z}/${x}/${y}.png",
220				"http://b.tile3.opencyclemap.org/landscape/${z}/${x}/${y}.png",
221				"http://c.tile3.opencyclemap.org/landscape/${z}/${x}/${y}.png" ], {
222			visibility : mapOpts.baselyr === "landscape"
223		}));
224
225		m.addLayer(new OpenLayers.Layer.OSM(
226				"hike and bike map", "http://toolserver.org/tiles/hikebike/${z}/${x}/${y}.png", {
227					visibility : mapOpts.baselyr === "hike and bike map",
228					tileOptions : {
229						crossOriginKeyword : null
230					}
231				}));
232	}
233	/*
234	 * add MapQuest map layers, see:
235	 * http://developer.mapquest.com/web/products/open/map
236	 */
237	if (mqEnable) {
238		m.addLayer(new OpenLayersMap.Layer.MapQuest());
239		m.addLayer(new OpenLayersMap.Layer.MapQuest("mapquest sat", [
240				"//otile1-s.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.jpg",
241				"//otile2-s.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.jpg",
242				"//otile3-s.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.jpg",
243				"//otile4-s.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.jpg" ], {
244			// note that global coverage is provided at zoom levels 0-11. Zoom
245			// Levels 12+ are provided only in the United States (lower 48).
246			numZoomLevels : 12,
247			visibility : mapOpts.baselyr === "mapquest sat"
248		}));
249
250	}
251
252	if (gEnable) {
253		/* load google maps */
254		try {
255			m.addLayer(new OpenLayers.Layer.Google("google relief", {
256				type : google.maps.MapTypeId.TERRAIN,
257				numZoomLevels : 16,
258				animationEnabled : true,
259				visibility : mapOpts.baselyr === "google relief"
260			}));
261			m.addLayer(new OpenLayers.Layer.Google("google sat", {
262				type : google.maps.MapTypeId.SATELLITE,
263				animationEnabled : true,
264				visibility : mapOpts.baselyr === "google sat"
265			}));
266			m.addLayer(new OpenLayers.Layer.Google("google hybrid", {
267				type : google.maps.MapTypeId.HYBRID,
268				animationEnabled : true,
269				visibility : mapOpts.baselyr === "google hybrid"
270			}));
271			m.addLayer(new OpenLayers.Layer.Google("google road", {
272				animationEnabled : true,
273				visibility : mapOpts.baselyr === "google road"
274			}));
275		} catch (ol_err1) {
276			Openlayers.Console.userError('Error loading Google maps' + ol_err1);
277		}
278	}
279
280	if (bEnable && bApiKey !== '') {
281		try {
282			/* add Bing tiles */
283			m.addLayer(new OpenLayers.Layer.Bing({
284				key : bApiKey,
285				type : "Road",
286				name : "bing road",
287				visibility : mapOpts.baselyr === "bing road",
288				wrapDateLine : true,
289				attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
290						+ 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
291						+ '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
292			}));
293			m.addLayer(new OpenLayers.Layer.Bing({
294				key : bApiKey,
295				type : "Aerial",
296				name : "bing sat",
297				visibility : mapOpts.baselyr === "bing sat",
298				wrapDateLine : true,
299				attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
300						+ 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
301						+ '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
302			}));
303			m.addLayer(new OpenLayers.Layer.Bing({
304				key : bApiKey,
305				type : "AerialWithLabels",
306				name : "bing hybrid",
307				visibility : mapOpts.baselyr === "bing hybrid",
308				wrapDateLine : true,
309				attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
310						+ 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
311						+ '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
312			}));
313		} catch (ol_errBing) {
314			Openlayers.Console.userError('Error loading Bing maps: ' + ol_errBing);
315		}
316	}
317
318	m.setCenter(new OpenLayers.LonLat(mapOpts.lon, mapOpts.lat).transform(m.displayProjection, m.projection),
319			mapOpts.zoom);
320	extent.extend(m.getExtent());
321
322	// change/set alternative baselyr
323	try {
324		m.setBaseLayer(((m.getLayersByName(mapOpts.baselyr))[0]));
325	} catch (ol_err4) {
326		m.setBaseLayer(m.layers[0]);
327	}
328
329	m.addControls([ new OpenLayers.Control.ScaleLine({
330		geodesic : true
331	}), new OpenLayers.Control.KeyboardDefaults({
332		observeElement : mapOpts.id
333	}), new OpenLayers.Control.Navigation() ]);
334
335	if (mapOpts.statusbar === 1) {
336		// statusbar control: mouse pos.
337		m.addControl(new OpenLayers.Control.MousePosition({
338			'div' : OpenLayers.Util.getElement(mapOpts.id + '-statusbar-mouseposition')
339		}));
340		// statusbar control: scale
341		m.addControl(new OpenLayers.Control.Scale(mapOpts.id + '-statusbar-scale'));
342		// statusbar control: attribution
343		m.addControl(new OpenLayers.Control.Attribution({
344			'div' : OpenLayers.Util.getElement(mapOpts.id + '-statusbar-text')
345		}));
346		// statusbar control: projection
347		OpenLayers.Util.getElement(mapOpts.id + '-statusbar-projection').innerHTML = m.displayProjection;
348	} else {
349		OpenLayers.Util.getElement(mapOpts.id + '-olStatusBar').display = 'none';
350	}
351
352	if (OLmapPOI.length > 0) {
353		var markers = new OpenLayers.Layer.Vector("POI", {
354			styleMap : new OpenLayers.StyleMap({
355				"default" : {
356					cursor : "help",
357					externalGraphic : "${img}",
358					graphicHeight : 16,
359					graphicWidth : 16,
360					// graphicXOffset : 0,
361					// graphicYOffset : -8,
362					graphicOpacity : "${opacity}",
363					rotation : "${angle}",
364					backgroundGraphic : DOKU_BASE + "lib/plugins/openlayersmap/icons/marker_shadow.png",
365					// backgroundXOffset : 0,
366					// backgroundYOffset : -4,
367					backgroundRotation : "${angle}",
368					pointRadius : 10,
369					labelXOffset : 8,
370					labelYOffset : 8,
371					labelAlign : "lb",
372					label : "${label}",
373					// fontColor : "",
374					fontFamily : "monospace",
375					fontSize : "12px",
376					fontWeight : "bold"
377				},
378				"select" : {
379					cursor : "help",
380					externalGraphic : DOKU_BASE + "lib/plugins/openlayersmap/icons/marker-red.png",
381					graphicHeight : 16,
382					graphicWidth : 16,
383					// graphicXOffset : 0,
384					// graphicYOffset : -8,
385					graphicOpacity : 1.0,
386					rotation : "${angle}"
387				}
388			}),
389			isBaseLayer : false,
390			rendererOptions : {
391				yOrdering : true
392			}
393		});
394		m.addLayer(markers);
395		var features = [];
396		for (var j = 0; j < OLmapPOI.length; j++) {
397			var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(OLmapPOI[j].lon, OLmapPOI[j].lat)
398					.transform(m.displayProjection, m.projection), {
399				angle : OLmapPOI[j].angle,
400				opacity : OLmapPOI[j].opacity,
401				img : DOKU_BASE + "lib/plugins/openlayersmap/icons/" + OLmapPOI[j].img,
402				label : OLmapPOI[j].rowId
403			});
404			var _latlon = OLmapPOI[j].lon + 'º;' + OLmapPOI[j].lat + 'º';
405			if (mapOpts.displayformat === 'DMS') {
406				_latlon = OpenLayers.Util.getFormattedLonLat(OLmapPOI[j].lon, 'lon') + ';'
407						+ OpenLayers.Util.getFormattedLonLat(OLmapPOI[j].lat, 'lat');
408			}
409			feat.data = {
410				name : OLmapPOI[j].txt,
411				rowId : OLmapPOI[j].rowId,
412				latlon : _latlon
413			};
414			features.push(feat);
415		}
416		markers.addFeatures(features);
417		extent.extend(markers.getDataExtent());
418		m.zoomToExtent(extent);
419	}
420
421	/* GPX layer */
422	if (mapOpts.gpxfile.length > 0) {
423		var layerGPX = new OpenLayers.Layer.Vector("GPS route", {
424			protocol : new OpenLayers.Protocol.HTTP({
425				url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.gpxfile,
426				format : new OpenLayers.Format.GPX({
427					extractWaypoints : true,
428					extractTracks : true,
429					extractStyles : true,
430					extractAttributes : true,
431					handleHeight : true,
432					maxDepth : 3
433				})
434			}),
435			style : {
436				strokeColor : "#0000FF",
437				strokeWidth : 3,
438				strokeOpacity : 0.7,
439				pointRadius : 4,
440				fillColor : "#0099FF",
441				fillOpacity : 0.7
442			// , label:"${name}"
443			},
444			projection : new OpenLayers.Projection("EPSG:4326"),
445			strategies : [ new OpenLayers.Strategy.Fixed() ]
446		});
447		m.addLayer(layerGPX);
448		layerGPX.events.register('loadend', m, function() {
449			extent.extend(layerGPX.getDataExtent());
450			m.zoomToExtent(extent);
451		});
452	}
453
454	/* GeoJSON layer */
455	if (mapOpts.geojsonfile.length > 0) {
456		var layerGJS = new OpenLayers.Layer.Vector("json data", {
457			protocol : new OpenLayers.Protocol.HTTP({
458				url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.geojsonfile,
459				format : new OpenLayers.Format.GeoJSON({
460					ignoreExtraDims : true
461				})
462			}),
463			style : {
464				strokeColor : "#FF00FF",
465				strokeWidth : 3,
466				strokeOpacity : 0.7,
467				pointRadius : 4,
468				fillColor : "#FF99FF",
469				fillOpacity : 0.7
470			// , label:"${name}"
471			},
472			projection : new OpenLayers.Projection("EPSG:4326"),
473			strategies : [ new OpenLayers.Strategy.Fixed() ]
474		});
475		m.addLayer(layerGJS);
476		layerGJS.events.register('loadend', m, function() {
477			extent.extend(layerGJS.getDataExtent());
478			m.zoomToExtent(extent);
479		});
480	}
481
482	/* KML layer */
483	if (mapOpts.kmlfile.length > 0) {
484		var layerKML = new OpenLayers.Layer.Vector("KML file", {
485			protocol : new OpenLayers.Protocol.HTTP({
486				url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.kmlfile,
487				format : new OpenLayers.Format.KML({
488					extractStyles : true,
489					extractAttributes : true,
490					maxDepth : 3
491				})
492			}),
493			style : {
494				label : "${name}"
495			},
496			projection : new OpenLayers.Projection("EPSG:4326"),
497			strategies : [ new OpenLayers.Strategy.Fixed() ]
498		});
499		m.addLayer(layerKML);
500		layerKML.events.register('loadend', m, function() {
501			extent.extend(layerKML.getDataExtent());
502			m.zoomToExtent(extent);
503		});
504	}
505
506	// selectcontrol for layers
507	if ((m.getLayersByClass('OpenLayers.Layer.GML').length > 0)
508			|| m.getLayersByClass('OpenLayers.Layer.Vector').length > 0) {
509		selectControl = new OpenLayers.Control.SelectFeature((m.getLayersByClass('OpenLayers.Layer.Vector')).concat(m
510				.getLayersByClass('OpenLayers.Layer.GML')), {
511			hover : mapOpts.poihoverstyle,
512			onSelect : onFeatureSelect,
513			onUnselect : onFeatureUnselect
514		});
515		m.addControl(selectControl);
516		selectControl.activate();
517
518		// keyboard select control
519		var iControl = new OpenLayersMap.Control.KeyboardClick({
520			observeElement : mapOpts.id,
521			selectControl : selectControl
522		});
523		m.addControl(iControl);
524	}
525
526	if (mapOpts.controls === 1) {
527		/* add base controls to map */
528		m.addControls([ new OpenLayersMap.Control.LayerSwitcher(), new OpenLayers.Control.Graticule({
529			visible : false
530		}), new OpenLayersMap.Control.OverviewMap({
531			mapOptions : {
532				theme : null
533			}
534		}), new OpenLayersMap.Control.Zoom(), new OpenLayersMap.Control.Fullscreen() ]);
535
536		// add hillshade, since this is off by default only add when we have a
537		// layerswitcher
538		m.addLayer(new OpenLayers.Layer.OSM("Hillshade", "http://toolserver.org/~cmarqu/hill/${z}/${x}/${y}.png", {
539			isBaseLayer : false,
540			transparent : true,
541			visibility : false,
542			displayOutsideMaxExtent : true,
543			attribution : '',
544			tileOptions : {
545				crossOriginKeyword : null
546			}
547		}));
548	}
549
550	return m;
551}
552
553/** init. */
554function olInit() {
555	if (olEnable) {
556		var _i = 0;
557		// create the maps in the page
558		for (_i = 0; _i < olMapData.length; _i++) {
559			var _id = olMapData[_i].mapOpts.id;
560			olMaps[_id] = createMap(olMapData[_i].mapOpts, olMapData[_i].poi);
561
562			// set max-width on help pop-over
563			jQuery('#' + _id).parent().parent().find('.olMapHelp').css('max-width', olMapData[_i].mapOpts.width);
564
565			// shrink the map width to fit inside page container
566			var _w = jQuery('#' + _id + '-olContainer').parent().innerWidth();
567			if (parseInt(olMapData[_i].mapOpts.width) > _w) {
568				jQuery('#' + _id).width(_w);
569				jQuery('#' + _id + '-olStatusBar').width(_w);
570				jQuery('#' + _id).parent().parent().find('.olMapHelp').width(_w);
571				olMaps[_id].updateSize();
572			}
573		}
574
575		// hide the table(s) with POI by giving it a print-only style
576		jQuery('.olPOItableSpan').addClass('olPrintOnly');
577		// hide the static map image(s) by giving it a print only style
578		jQuery('.olStaticMap').addClass('olPrintOnly');
579		// add help button with toggle.
580		jQuery('.olWebOnly > .olMap')
581				.prepend(
582						'<div class="olMapHelpButtonDiv">'
583								+ '<button onclick="jQuery(\'.olMapHelp\').toggle(500);" class="olMapHelpButton olHasTooltip"><span>'
584								+ OpenLayers.i18n("toggle_help") + '</span>?</button></div>');
585		// toggle to switch dynamic vs. static map
586		jQuery('.olMapHelp').before(
587				'<div class="a11y"><button onclick="jQuery(\'.olPrintOnly\').toggle();jQuery(\'.olWebOnly\').toggle();">'
588						+ OpenLayers.i18n("toggle_dynamic_map") + '</button></div>');
589	}
590}
591
592/**
593 * ol api flag.
594 *
595 * @type {Boolean}
596 */
597var olEnable = false,
598/**
599 * An array with data for each map in the page.
600 *
601 * @type {Array}
602 */
603olMapData = [],
604/**
605 * Holds a reference to all of the maps on this page with the map's id as key.
606 * Can be used as an extension point.
607 *
608 * @type {Object}
609 */
610olMaps = new Object(),
611/**
612 * MapQuest tiles flag.
613 *
614 * @type {Boolean}
615 */
616mqEnable = false,
617/**
618 * google map api flag.
619 *
620 * @type {Boolean}
621 */
622gEnable = false,
623/**
624 * Bing tiles flag.
625 *
626 * @type {Boolean}
627 */
628bEnable = false,
629/**
630 * Bing API key.
631 *
632 * @type {String}
633 */
634bApiKey = '',
635/**
636 * MapQuest API key.
637 *
638 * @type {String}
639 */
640mqApiKey = '',
641/**
642 * Google API key.
643 *
644 * @type {String}
645 */
646gApiKey = '',
647/**
648 * OSM tiles flag.
649 *
650 * @type {Boolean}
651 */
652osmEnable = true,
653/**
654 * CSS support flag.
655 *
656 * @type {Boolean}
657 */
658olCSSEnable = true;
659
660/* register olInit to run with onload event. */
661jQuery(olInit);
662