Files
openlayers/lib/OpenLayers/Control/LayerSwitcher.js
Tim Schaub 0b26fa9a5e Making it so dictionary keys are the English values for strings displayed in the UI.
By making dictionary keys be sensible strings, we make it so the i18n function returns something legible when there are no dictionaries included in a build.  This means that strings from the Graticule, Permalink, LayerSwitcher, and Scale controls will be displayed in English without having to include the English dictionary (as is the case in our full build).

Note that if you use the OpenLayers.i18n method in your applications, five of the dictionary keys have changed.  Use the following replacements:

 * "permalink" -> "Permalink"
 * "overlays" -> "Overlays"
 * "baseLayer" -> "Base Layer"
 * "scale" -> "Scale = 1 : ${scaleDenom}"
 * "graticule" -> "Graticule"

r=ahocevar (closes #3364)



git-svn-id: http://svn.openlayers.org/trunk/openlayers@12127 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
2011-06-24 20:12:12 +00:00

623 lines
19 KiB
JavaScript

/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
* @requires OpenLayers/Lang.js
* @requires Rico/Corner.js
*/
/**
* Class: OpenLayers.Control.LayerSwitcher
* The LayerSwitcher control displays a table of contents for the map. This
* allows the user interface to switch between BaseLasyers and to show or hide
* Overlays. By default the switcher is shown minimized on the right edge of
* the map, the user may expand it by clicking on the handle.
*
* To create the LayerSwitcher outside of the map, pass the Id of a html div
* as the first argument to the constructor.
*
* Inherits from:
* - <OpenLayers.Control>
*/
OpenLayers.Control.LayerSwitcher =
OpenLayers.Class(OpenLayers.Control, {
/**
* APIProperty: roundedCorner
* {Boolean} If true the Rico library is used for rounding the corners
* of the layer switcher div, defaults to true.
*/
roundedCorner: true,
/**
* APIProperty: roundedCornerColor
* {String} The color of the rounded corners, only applies if roundedCorner
* is true, defaults to "darkblue".
*/
roundedCornerColor: "darkblue",
/**
* Property: layerStates
* {Array(Object)} Basically a copy of the "state" of the map's layers
* the last time the control was drawn. We have this in order to avoid
* unnecessarily redrawing the control.
*/
layerStates: null,
// DOM Elements
/**
* Property: layersDiv
* {DOMElement}
*/
layersDiv: null,
/**
* Property: baseLayersDiv
* {DOMElement}
*/
baseLayersDiv: null,
/**
* Property: baseLayers
* {Array(<OpenLayers.Layer>)}
*/
baseLayers: null,
/**
* Property: dataLbl
* {DOMElement}
*/
dataLbl: null,
/**
* Property: dataLayersDiv
* {DOMElement}
*/
dataLayersDiv: null,
/**
* Property: dataLayers
* {Array(<OpenLayers.Layer>)}
*/
dataLayers: null,
/**
* Property: minimizeDiv
* {DOMElement}
*/
minimizeDiv: null,
/**
* Property: maximizeDiv
* {DOMElement}
*/
maximizeDiv: null,
/**
* APIProperty: ascending
* {Boolean}
*/
ascending: true,
/**
* Constructor: OpenLayers.Control.LayerSwitcher
*
* Parameters:
* options - {Object}
*/
initialize: function(options) {
OpenLayers.Control.prototype.initialize.apply(this, arguments);
this.layerStates = [];
},
/**
* APIMethod: destroy
*/
destroy: function() {
OpenLayers.Event.stopObservingElement(this.div);
OpenLayers.Event.stopObservingElement(this.minimizeDiv);
OpenLayers.Event.stopObservingElement(this.maximizeDiv);
//clear out layers info and unregister their events
this.clearLayersArray("base");
this.clearLayersArray("data");
this.map.events.un({
"addlayer": this.redraw,
"changelayer": this.redraw,
"removelayer": this.redraw,
"changebaselayer": this.redraw,
scope: this
});
OpenLayers.Control.prototype.destroy.apply(this, arguments);
},
/**
* Method: setMap
*
* Properties:
* map - {<OpenLayers.Map>}
*/
setMap: function(map) {
OpenLayers.Control.prototype.setMap.apply(this, arguments);
this.map.events.on({
"addlayer": this.redraw,
"changelayer": this.redraw,
"removelayer": this.redraw,
"changebaselayer": this.redraw,
scope: this
});
},
/**
* Method: draw
*
* Returns:
* {DOMElement} A reference to the DIV DOMElement containing the
* switcher tabs.
*/
draw: function() {
OpenLayers.Control.prototype.draw.apply(this);
// create layout divs
this.loadContents();
// set mode to minimize
if(!this.outsideViewport) {
this.minimizeControl();
}
// populate div with current info
this.redraw();
return this.div;
},
/**
* Method: clearLayersArray
* User specifies either "base" or "data". we then clear all the
* corresponding listeners, the div, and reinitialize a new array.
*
* Parameters:
* layersType - {String}
*/
clearLayersArray: function(layersType) {
var layers = this[layersType + "Layers"];
if (layers) {
for(var i=0, len=layers.length; i<len ; i++) {
var layer = layers[i];
OpenLayers.Event.stopObservingElement(layer.inputElem);
OpenLayers.Event.stopObservingElement(layer.labelSpan);
}
}
this[layersType + "LayersDiv"].innerHTML = "";
this[layersType + "Layers"] = [];
},
/**
* Method: checkRedraw
* Checks if the layer state has changed since the last redraw() call.
*
* Returns:
* {Boolean} The layer state changed since the last redraw() call.
*/
checkRedraw: function() {
var redraw = false;
if ( !this.layerStates.length ||
(this.map.layers.length != this.layerStates.length) ) {
redraw = true;
} else {
for (var i=0, len=this.layerStates.length; i<len; i++) {
var layerState = this.layerStates[i];
var layer = this.map.layers[i];
if ( (layerState.name != layer.name) ||
(layerState.inRange != layer.inRange) ||
(layerState.id != layer.id) ||
(layerState.visibility != layer.visibility) ) {
redraw = true;
break;
}
}
}
return redraw;
},
/**
* Method: redraw
* Goes through and takes the current state of the Map and rebuilds the
* control to display that state. Groups base layers into a
* radio-button group and lists each data layer with a checkbox.
*
* Returns:
* {DOMElement} A reference to the DIV DOMElement containing the control
*/
redraw: function() {
//if the state hasn't changed since last redraw, no need
// to do anything. Just return the existing div.
if (!this.checkRedraw()) {
return this.div;
}
//clear out previous layers
this.clearLayersArray("base");
this.clearLayersArray("data");
var containsOverlays = false;
var containsBaseLayers = false;
// Save state -- for checking layer if the map state changed.
// We save this before redrawing, because in the process of redrawing
// we will trigger more visibility changes, and we want to not redraw
// and enter an infinite loop.
var len = this.map.layers.length;
this.layerStates = new Array(len);
for (var i=0; i <len; i++) {
var layer = this.map.layers[i];
this.layerStates[i] = {
'name': layer.name,
'visibility': layer.visibility,
'inRange': layer.inRange,
'id': layer.id
};
}
var layers = this.map.layers.slice();
if (!this.ascending) { layers.reverse(); }
for(var i=0, len=layers.length; i<len; i++) {
var layer = layers[i];
var baseLayer = layer.isBaseLayer;
if (layer.displayInLayerSwitcher) {
if (baseLayer) {
containsBaseLayers = true;
} else {
containsOverlays = true;
}
// only check a baselayer if it is *the* baselayer, check data
// layers if they are visible
var checked = (baseLayer) ? (layer == this.map.baseLayer)
: layer.getVisibility();
// create input element
var inputElem = document.createElement("input");
inputElem.id = this.id + "_input_" + layer.name;
inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name;
inputElem.type = (baseLayer) ? "radio" : "checkbox";
inputElem.value = layer.name;
inputElem.checked = checked;
inputElem.defaultChecked = checked;
if (!baseLayer && !layer.inRange) {
inputElem.disabled = true;
}
var context = {
'inputElem': inputElem,
'layer': layer,
'layerSwitcher': this
};
OpenLayers.Event.observe(inputElem, "mouseup",
OpenLayers.Function.bindAsEventListener(this.onInputClick,
context)
);
// create span
var labelSpan = document.createElement("span");
OpenLayers.Element.addClass(labelSpan, "labelSpan");
if (!baseLayer && !layer.inRange) {
labelSpan.style.color = "gray";
}
labelSpan.innerHTML = layer.name;
labelSpan.style.verticalAlign = (baseLayer) ? "bottom"
: "baseline";
OpenLayers.Event.observe(labelSpan, "click",
OpenLayers.Function.bindAsEventListener(this.onInputClick,
context)
);
// create line break
var br = document.createElement("br");
var groupArray = (baseLayer) ? this.baseLayers
: this.dataLayers;
groupArray.push({
'layer': layer,
'inputElem': inputElem,
'labelSpan': labelSpan
});
var groupDiv = (baseLayer) ? this.baseLayersDiv
: this.dataLayersDiv;
groupDiv.appendChild(inputElem);
groupDiv.appendChild(labelSpan);
groupDiv.appendChild(br);
}
}
// if no overlays, dont display the overlay label
this.dataLbl.style.display = (containsOverlays) ? "" : "none";
// if no baselayers, dont display the baselayer label
this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";
return this.div;
},
/**
* Method:
* A label has been clicked, check or uncheck its corresponding input
*
* Parameters:
* e - {Event}
*
* Context:
* - {DOMElement} inputElem
* - {<OpenLayers.Control.LayerSwitcher>} layerSwitcher
* - {<OpenLayers.Layer>} layer
*/
onInputClick: function(e) {
if (!this.inputElem.disabled) {
if (this.inputElem.type == "radio") {
this.inputElem.checked = true;
this.layer.map.setBaseLayer(this.layer);
} else {
this.inputElem.checked = !this.inputElem.checked;
this.layerSwitcher.updateMap();
}
}
OpenLayers.Event.stop(e);
},
/**
* Method: onLayerClick
* Need to update the map accordingly whenever user clicks in either of
* the layers.
*
* Parameters:
* e - {Event}
*/
onLayerClick: function(e) {
this.updateMap();
},
/**
* Method: updateMap
* Cycles through the loaded data and base layer input arrays and makes
* the necessary calls to the Map object such that that the map's
* visual state corresponds to what the user has selected in
* the control.
*/
updateMap: function() {
// set the newly selected base layer
for(var i=0, len=this.baseLayers.length; i<len; i++) {
var layerEntry = this.baseLayers[i];
if (layerEntry.inputElem.checked) {
this.map.setBaseLayer(layerEntry.layer, false);
}
}
// set the correct visibilities for the overlays
for(var i=0, len=this.dataLayers.length; i<len; i++) {
var layerEntry = this.dataLayers[i];
layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
}
},
/**
* Method: maximizeControl
* Set up the labels and divs for the control
*
* Parameters:
* e - {Event}
*/
maximizeControl: function(e) {
// set the div's width and height to empty values, so
// the div dimensions can be controlled by CSS
this.div.style.width = "";
this.div.style.height = "";
this.showControls(false);
if (e != null) {
OpenLayers.Event.stop(e);
}
},
/**
* Method: minimizeControl
* Hide all the contents of the control, shrink the size,
* add the maximize icon
*
* Parameters:
* e - {Event}
*/
minimizeControl: function(e) {
// to minimize the control we set its div's width
// and height to 0px, we cannot just set "display"
// to "none" because it would hide the maximize
// div
this.div.style.width = "0px";
this.div.style.height = "0px";
this.showControls(true);
if (e != null) {
OpenLayers.Event.stop(e);
}
},
/**
* Method: showControls
* Hide/Show all LayerSwitcher controls depending on whether we are
* minimized or not
*
* Parameters:
* minimize - {Boolean}
*/
showControls: function(minimize) {
this.maximizeDiv.style.display = minimize ? "" : "none";
this.minimizeDiv.style.display = minimize ? "none" : "";
this.layersDiv.style.display = minimize ? "none" : "";
},
/**
* Method: loadContents
* Set up the labels and divs for the control
*/
loadContents: function() {
//configure main div
OpenLayers.Event.observe(this.div, "mouseup",
OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
OpenLayers.Event.observe(this.div, "click",
this.ignoreEvent);
OpenLayers.Event.observe(this.div, "mousedown",
OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);
// layers list div
this.layersDiv = document.createElement("div");
this.layersDiv.id = this.id + "_layersDiv";
OpenLayers.Element.addClass(this.layersDiv, "layersDiv");
this.baseLbl = document.createElement("div");
this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer");
OpenLayers.Element.addClass(this.baseLbl, "baseLbl");
this.baseLayersDiv = document.createElement("div");
OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv");
this.dataLbl = document.createElement("div");
this.dataLbl.innerHTML = OpenLayers.i18n("Overlays");
OpenLayers.Element.addClass(this.dataLbl, "dataLbl");
this.dataLayersDiv = document.createElement("div");
OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv");
if (this.ascending) {
this.layersDiv.appendChild(this.baseLbl);
this.layersDiv.appendChild(this.baseLayersDiv);
this.layersDiv.appendChild(this.dataLbl);
this.layersDiv.appendChild(this.dataLayersDiv);
} else {
this.layersDiv.appendChild(this.dataLbl);
this.layersDiv.appendChild(this.dataLayersDiv);
this.layersDiv.appendChild(this.baseLbl);
this.layersDiv.appendChild(this.baseLayersDiv);
}
this.div.appendChild(this.layersDiv);
if(this.roundedCorner) {
OpenLayers.Rico.Corner.round(this.div, {
corners: "tl bl",
bgColor: "transparent",
color: this.roundedCornerColor,
blend: false
});
OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75);
}
var imgLocation = OpenLayers.Util.getImagesLocation();
var sz = new OpenLayers.Size(18,18);
// maximize button div
var img = imgLocation + 'layer-switcher-maximize.png';
this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
"OpenLayers_Control_MaximizeDiv",
null,
sz,
img,
"absolute");
OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv");
this.maximizeDiv.style.display = "none";
OpenLayers.Event.observe(this.maximizeDiv, "click",
OpenLayers.Function.bindAsEventListener(this.maximizeControl, this)
);
this.div.appendChild(this.maximizeDiv);
// minimize button div
var img = imgLocation + 'layer-switcher-minimize.png';
var sz = new OpenLayers.Size(18,18);
this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
"OpenLayers_Control_MinimizeDiv",
null,
sz,
img,
"absolute");
OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv");
this.minimizeDiv.style.display = "none";
OpenLayers.Event.observe(this.minimizeDiv, "click",
OpenLayers.Function.bindAsEventListener(this.minimizeControl, this)
);
this.div.appendChild(this.minimizeDiv);
},
/**
* Method: ignoreEvent
*
* Parameters:
* evt - {Event}
*/
ignoreEvent: function(evt) {
OpenLayers.Event.stop(evt);
},
/**
* Method: mouseDown
* Register a local 'mouseDown' flag so that we'll know whether or not
* to ignore a mouseUp event
*
* Parameters:
* evt - {Event}
*/
mouseDown: function(evt) {
this.isMouseDown = true;
this.ignoreEvent(evt);
},
/**
* Method: mouseUp
* If the 'isMouseDown' flag has been set, that means that the drag was
* started from within the LayerSwitcher control, and thus we can
* ignore the mouseup. Otherwise, let the Event continue.
*
* Parameters:
* evt - {Event}
*/
mouseUp: function(evt) {
if (this.isMouseDown) {
this.isMouseDown = false;
this.ignoreEvent(evt);
}
},
CLASS_NAME: "OpenLayers.Control.LayerSwitcher"
});