Merge pull request #866 from marcjansen/866

LayerSwitcher generate bad ID when layername has spaces in it. (r=@ahocevar)
This commit is contained in:
Marc Jansen
2013-02-14 07:01:32 -08:00
2 changed files with 172 additions and 117 deletions
+123 -115
View File
@@ -3,27 +3,28 @@
* See license.txt in the OpenLayers distribution or repository for the * See license.txt in the OpenLayers distribution or repository for the
* full text of the license. */ * full text of the license. */
/** /**
* @requires OpenLayers/Control.js * @requires OpenLayers/Control.js
* @requires OpenLayers/Lang.js * @requires OpenLayers/Lang.js
* @requires OpenLayers/Console.js * @requires OpenLayers/Console.js
* @requires OpenLayers/Util.js
* @requires OpenLayers/Events/buttonclick.js * @requires OpenLayers/Events/buttonclick.js
*/ */
/** /**
* Class: OpenLayers.Control.LayerSwitcher * Class: OpenLayers.Control.LayerSwitcher
* The LayerSwitcher control displays a table of contents for the map. This * 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 * 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 * 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. * 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 * To create the LayerSwitcher outside of the map, pass the Id of a html div
* as the first argument to the constructor. * as the first argument to the constructor.
* *
* Inherits from: * Inherits from:
* - <OpenLayers.Control> * - <OpenLayers.Control>
*/ */
OpenLayers.Control.LayerSwitcher = OpenLayers.Control.LayerSwitcher =
OpenLayers.Class(OpenLayers.Control, { OpenLayers.Class(OpenLayers.Control, {
/** /**
@@ -37,104 +38,103 @@ OpenLayers.Control.LayerSwitcher =
*/ */
roundedCorner: false, roundedCorner: false,
/** /**
* APIProperty: roundedCornerColor * APIProperty: roundedCornerColor
* {String} The color of the rounded corners, only applies if roundedCorner * {String} The color of the rounded corners, only applies if roundedCorner
* is true, defaults to "darkblue". * is true, defaults to "darkblue".
*/ */
roundedCornerColor: "darkblue", roundedCornerColor: "darkblue",
/** /**
* Property: layerStates * Property: layerStates
* {Array(Object)} Basically a copy of the "state" of the map's layers * {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 * the last time the control was drawn. We have this in order to avoid
* unnecessarily redrawing the control. * unnecessarily redrawing the control.
*/ */
layerStates: null, layerStates: null,
// DOM Elements // DOM Elements
/** /**
* Property: layersDiv * Property: layersDiv
* {DOMElement} * {DOMElement}
*/ */
layersDiv: null, layersDiv: null,
/** /**
* Property: baseLayersDiv * Property: baseLayersDiv
* {DOMElement} * {DOMElement}
*/ */
baseLayersDiv: null, baseLayersDiv: null,
/** /**
* Property: baseLayers * Property: baseLayers
* {Array(Object)} * {Array(Object)}
*/ */
baseLayers: null, baseLayers: null,
/** /**
* Property: dataLbl * Property: dataLbl
* {DOMElement} * {DOMElement}
*/ */
dataLbl: null, dataLbl: null,
/** /**
* Property: dataLayersDiv * Property: dataLayersDiv
* {DOMElement} * {DOMElement}
*/ */
dataLayersDiv: null, dataLayersDiv: null,
/** /**
* Property: dataLayers * Property: dataLayers
* {Array(Object)} * {Array(Object)}
*/ */
dataLayers: null, dataLayers: null,
/** /**
* Property: minimizeDiv * Property: minimizeDiv
* {DOMElement} * {DOMElement}
*/ */
minimizeDiv: null, minimizeDiv: null,
/** /**
* Property: maximizeDiv * Property: maximizeDiv
* {DOMElement} * {DOMElement}
*/ */
maximizeDiv: null, maximizeDiv: null,
/** /**
* APIProperty: ascending * APIProperty: ascending
* {Boolean} * {Boolean}
*/ */
ascending: true, ascending: true,
/** /**
* Constructor: OpenLayers.Control.LayerSwitcher * Constructor: OpenLayers.Control.LayerSwitcher
* *
* Parameters: * Parameters:
* options - {Object} * options - {Object}
*/ */
initialize: function(options) { initialize: function(options) {
OpenLayers.Control.prototype.initialize.apply(this, arguments); OpenLayers.Control.prototype.initialize.apply(this, arguments);
this.layerStates = []; this.layerStates = [];
if(this.roundedCorner) { if(this.roundedCorner) {
OpenLayers.Console.warn('roundedCorner option is deprecated'); OpenLayers.Console.warn('roundedCorner option is deprecated');
} }
}, },
/** /**
* APIMethod: destroy * APIMethod: destroy
*/ */
destroy: function() { destroy: function() {
//clear out layers info and unregister their events //clear out layers info and unregister their events
this.clearLayersArray("base"); this.clearLayersArray("base");
this.clearLayersArray("data"); this.clearLayersArray("data");
this.map.events.un({ this.map.events.un({
buttonclick: this.onButtonClick, buttonclick: this.onButtonClick,
addlayer: this.redraw, addlayer: this.redraw,
@@ -144,15 +144,15 @@ OpenLayers.Control.LayerSwitcher =
scope: this scope: this
}); });
this.events.unregister("buttonclick", this, this.onButtonClick); this.events.unregister("buttonclick", this, this.onButtonClick);
OpenLayers.Control.prototype.destroy.apply(this, arguments); OpenLayers.Control.prototype.destroy.apply(this, arguments);
}, },
/** /**
* Method: setMap * Method: setMap
* *
* Properties: * Properties:
* map - {<OpenLayers.Map>} * map - {<OpenLayers.Map>}
*/ */
setMap: function(map) { setMap: function(map) {
OpenLayers.Control.prototype.setMap.apply(this, arguments); OpenLayers.Control.prototype.setMap.apply(this, arguments);
@@ -176,9 +176,9 @@ OpenLayers.Control.LayerSwitcher =
* Method: draw * Method: draw
* *
* Returns: * Returns:
* {DOMElement} A reference to the DIV DOMElement containing the * {DOMElement} A reference to the DIV DOMElement containing the
* switcher tabs. * switcher tabs.
*/ */
draw: function() { draw: function() {
OpenLayers.Control.prototype.draw.apply(this); OpenLayers.Control.prototype.draw.apply(this);
@@ -191,7 +191,7 @@ OpenLayers.Control.LayerSwitcher =
} }
// populate div with current info // populate div with current info
this.redraw(); this.redraw();
return this.div; return this.div;
}, },
@@ -224,13 +224,13 @@ OpenLayers.Control.LayerSwitcher =
} }
}, },
/** /**
* Method: clearLayersArray * Method: clearLayersArray
* User specifies either "base" or "data". we then clear all the * User specifies either "base" or "data". we then clear all the
* corresponding listeners, the div, and reinitialize a new array. * corresponding listeners, the div, and reinitialize a new array.
* *
* Parameters: * Parameters:
* layersType - {String} * layersType - {String}
*/ */
clearLayersArray: function(layersType) { clearLayersArray: function(layersType) {
this[layersType + "LayersDiv"].innerHTML = ""; this[layersType + "LayersDiv"].innerHTML = "";
@@ -241,9 +241,9 @@ OpenLayers.Control.LayerSwitcher =
/** /**
* Method: checkRedraw * Method: checkRedraw
* Checks if the layer state has changed since the last redraw() call. * Checks if the layer state has changed since the last redraw() call.
* *
* Returns: * Returns:
* {Boolean} The layer state changed since the last redraw() call. * {Boolean} The layer state changed since the last redraw() call.
*/ */
checkRedraw: function() { checkRedraw: function() {
var redraw = false; var redraw = false;
@@ -254,41 +254,41 @@ OpenLayers.Control.LayerSwitcher =
for (var i=0, len=this.layerStates.length; i<len; i++) { for (var i=0, len=this.layerStates.length; i<len; i++) {
var layerState = this.layerStates[i]; var layerState = this.layerStates[i];
var layer = this.map.layers[i]; var layer = this.map.layers[i];
if ( (layerState.name != layer.name) || if ( (layerState.name != layer.name) ||
(layerState.inRange != layer.inRange) || (layerState.inRange != layer.inRange) ||
(layerState.id != layer.id) || (layerState.id != layer.id) ||
(layerState.visibility != layer.visibility) ) { (layerState.visibility != layer.visibility) ) {
redraw = true; redraw = true;
break; break;
} }
} }
} }
return redraw; return redraw;
}, },
/** /**
* Method: redraw * Method: redraw
* Goes through and takes the current state of the Map and rebuilds the * Goes through and takes the current state of the Map and rebuilds the
* control to display that state. Groups base layers into a * control to display that state. Groups base layers into a
* radio-button group and lists each data layer with a checkbox. * radio-button group and lists each data layer with a checkbox.
* *
* Returns: * Returns:
* {DOMElement} A reference to the DIV DOMElement containing the control * {DOMElement} A reference to the DIV DOMElement containing the control
*/ */
redraw: function() { redraw: function() {
//if the state hasn't changed since last redraw, no need //if the state hasn't changed since last redraw, no need
// to do anything. Just return the existing div. // to do anything. Just return the existing div.
if (!this.checkRedraw()) { if (!this.checkRedraw()) {
return this.div; return this.div;
} }
//clear out previous layers //clear out previous layers
this.clearLayersArray("base"); this.clearLayersArray("base");
this.clearLayersArray("data"); this.clearLayersArray("data");
var containsOverlays = false; var containsOverlays = false;
var containsBaseLayers = false; var containsBaseLayers = false;
// Save state -- for checking layer if the map state changed. // Save state -- for checking layer if the map state changed.
// We save this before redrawing, because in the process of redrawing // We save this before redrawing, because in the process of redrawing
// we will trigger more visibility changes, and we want to not redraw // we will trigger more visibility changes, and we want to not redraw
@@ -298,12 +298,12 @@ OpenLayers.Control.LayerSwitcher =
for (var i=0; i <len; i++) { for (var i=0; i <len; i++) {
var layer = this.map.layers[i]; var layer = this.map.layers[i];
this.layerStates[i] = { this.layerStates[i] = {
'name': layer.name, 'name': layer.name,
'visibility': layer.visibility, 'visibility': layer.visibility,
'inRange': layer.inRange, 'inRange': layer.inRange,
'id': layer.id 'id': layer.id
}; };
} }
var layers = this.map.layers.slice(); var layers = this.map.layers.slice();
if (!this.ascending) { layers.reverse(); } if (!this.ascending) { layers.reverse(); }
@@ -317,16 +317,22 @@ OpenLayers.Control.LayerSwitcher =
containsBaseLayers = true; containsBaseLayers = true;
} else { } else {
containsOverlays = true; containsOverlays = true;
} }
// only check a baselayer if it is *the* baselayer, check data // only check a baselayer if it is *the* baselayer, check data
// layers if they are visible // layers if they are visible
var checked = (baseLayer) ? (layer == this.map.baseLayer) var checked = (baseLayer) ? (layer == this.map.baseLayer)
: layer.getVisibility(); : layer.getVisibility();
// create input element // create input element
var inputElem = document.createElement("input"); var inputElem = document.createElement("input"),
inputElem.id = this.id + "_input_" + layer.name; // The input shall have an id attribute so we can use
// labels to interact with them.
inputId = OpenLayers.Util.createUniqueID(
this.id + "_input_"
);
inputElem.id = inputId;
inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name;
inputElem.type = (baseLayer) ? "radio" : "checkbox"; inputElem.type = (baseLayer) ? "radio" : "checkbox";
inputElem.value = layer.name; inputElem.value = layer.name;
@@ -339,9 +345,11 @@ OpenLayers.Control.LayerSwitcher =
if (!baseLayer && !layer.inRange) { if (!baseLayer && !layer.inRange) {
inputElem.disabled = true; inputElem.disabled = true;
} }
// create span // create span
var labelSpan = document.createElement("label"); var labelSpan = document.createElement("label");
// this isn't the DOM attribute 'for', but an arbitrary name we
// use to find the appropriate input element in <onButtonClick>
labelSpan["for"] = inputElem.id; labelSpan["for"] = inputElem.id;
OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); OpenLayers.Element.addClass(labelSpan, "labelSpan olButton");
labelSpan._layer = layer.id; labelSpan._layer = layer.id;
@@ -350,12 +358,12 @@ OpenLayers.Control.LayerSwitcher =
labelSpan.style.color = "gray"; labelSpan.style.color = "gray";
} }
labelSpan.innerHTML = layer.name; labelSpan.innerHTML = layer.name;
labelSpan.style.verticalAlign = (baseLayer) ? "bottom" labelSpan.style.verticalAlign = (baseLayer) ? "bottom"
: "baseline"; : "baseline";
// create line break // create line break
var br = document.createElement("br"); var br = document.createElement("br");
var groupArray = (baseLayer) ? this.baseLayers var groupArray = (baseLayer) ? this.baseLayers
: this.dataLayers; : this.dataLayers;
groupArray.push({ groupArray.push({
@@ -363,8 +371,8 @@ OpenLayers.Control.LayerSwitcher =
'inputElem': inputElem, 'inputElem': inputElem,
'labelSpan': labelSpan 'labelSpan': labelSpan
}); });
var groupDiv = (baseLayer) ? this.baseLayersDiv var groupDiv = (baseLayer) ? this.baseLayersDiv
: this.dataLayersDiv; : this.dataLayersDiv;
groupDiv.appendChild(inputElem); groupDiv.appendChild(inputElem);
@@ -374,24 +382,24 @@ OpenLayers.Control.LayerSwitcher =
} }
// if no overlays, dont display the overlay label // if no overlays, dont display the overlay label
this.dataLbl.style.display = (containsOverlays) ? "" : "none"; this.dataLbl.style.display = (containsOverlays) ? "" : "none";
// if no baselayers, dont display the baselayer label // if no baselayers, dont display the baselayer label
this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";
return this.div; return this.div;
}, },
/** /**
* Method: updateMap * Method: updateMap
* Cycles through the loaded data and base layer input arrays and makes * 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 * the necessary calls to the Map object such that that the map's
* visual state corresponds to what the user has selected in * visual state corresponds to what the user has selected in
* the control. * the control.
*/ */
updateMap: function() { updateMap: function() {
// set the newly selected base layer // set the newly selected base layer
for(var i=0, len=this.baseLayers.length; i<len; i++) { for(var i=0, len=this.baseLayers.length; i<len; i++) {
var layerEntry = this.baseLayers[i]; var layerEntry = this.baseLayers[i];
if (layerEntry.inputElem.checked) { if (layerEntry.inputElem.checked) {
@@ -401,18 +409,18 @@ OpenLayers.Control.LayerSwitcher =
// set the correct visibilities for the overlays // set the correct visibilities for the overlays
for(var i=0, len=this.dataLayers.length; i<len; i++) { for(var i=0, len=this.dataLayers.length; i<len; i++) {
var layerEntry = this.dataLayers[i]; var layerEntry = this.dataLayers[i];
layerEntry.layer.setVisibility(layerEntry.inputElem.checked); layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
} }
}, },
/** /**
* Method: maximizeControl * Method: maximizeControl
* Set up the labels and divs for the control * Set up the labels and divs for the control
* *
* Parameters: * Parameters:
* e - {Event} * e - {Event}
*/ */
maximizeControl: function(e) { maximizeControl: function(e) {
@@ -424,17 +432,17 @@ OpenLayers.Control.LayerSwitcher =
this.showControls(false); this.showControls(false);
if (e != null) { if (e != null) {
OpenLayers.Event.stop(e); OpenLayers.Event.stop(e);
} }
}, },
/** /**
* Method: minimizeControl * Method: minimizeControl
* Hide all the contents of the control, shrink the size, * Hide all the contents of the control, shrink the size,
* add the maximize icon * add the maximize icon
* *
* Parameters: * Parameters:
* e - {Event} * e - {Event}
*/ */
minimizeControl: function(e) { minimizeControl: function(e) {
@@ -448,7 +456,7 @@ OpenLayers.Control.LayerSwitcher =
this.showControls(true); this.showControls(true);
if (e != null) { if (e != null) {
OpenLayers.Event.stop(e); OpenLayers.Event.stop(e);
} }
}, },
@@ -456,7 +464,7 @@ OpenLayers.Control.LayerSwitcher =
* Method: showControls * Method: showControls
* Hide/Show all LayerSwitcher controls depending on whether we are * Hide/Show all LayerSwitcher controls depending on whether we are
* minimized or not * minimized or not
* *
* Parameters: * Parameters:
* minimize - {Boolean} * minimize - {Boolean}
*/ */
@@ -467,14 +475,14 @@ OpenLayers.Control.LayerSwitcher =
this.layersDiv.style.display = minimize ? "none" : ""; this.layersDiv.style.display = minimize ? "none" : "";
}, },
/** /**
* Method: loadContents * Method: loadContents
* Set up the labels and divs for the control * Set up the labels and divs for the control
*/ */
loadContents: function() { loadContents: function() {
// layers list div // layers list div
this.layersDiv = document.createElement("div"); this.layersDiv = document.createElement("div");
this.layersDiv.id = this.id + "_layersDiv"; this.layersDiv.id = this.id + "_layersDiv";
OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); OpenLayers.Element.addClass(this.layersDiv, "layersDiv");
@@ -482,14 +490,14 @@ OpenLayers.Control.LayerSwitcher =
this.baseLbl = document.createElement("div"); this.baseLbl = document.createElement("div");
this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer");
OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); OpenLayers.Element.addClass(this.baseLbl, "baseLbl");
this.baseLayersDiv = document.createElement("div"); this.baseLayersDiv = document.createElement("div");
OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv");
this.dataLbl = document.createElement("div"); this.dataLbl = document.createElement("div");
this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); this.dataLbl.innerHTML = OpenLayers.i18n("Overlays");
OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); OpenLayers.Element.addClass(this.dataLbl, "dataLbl");
this.dataLayersDiv = document.createElement("div"); this.dataLayersDiv = document.createElement("div");
OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv");
@@ -503,8 +511,8 @@ OpenLayers.Control.LayerSwitcher =
this.layersDiv.appendChild(this.dataLayersDiv); this.layersDiv.appendChild(this.dataLayersDiv);
this.layersDiv.appendChild(this.baseLbl); this.layersDiv.appendChild(this.baseLbl);
this.layersDiv.appendChild(this.baseLayersDiv); this.layersDiv.appendChild(this.baseLayersDiv);
} }
this.div.appendChild(this.layersDiv); this.div.appendChild(this.layersDiv);
if(this.roundedCorner) { if(this.roundedCorner) {
@@ -520,29 +528,29 @@ OpenLayers.Control.LayerSwitcher =
// maximize button div // maximize button div
var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png');
this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
"OpenLayers_Control_MaximizeDiv", "OpenLayers_Control_MaximizeDiv",
null, null,
null, null,
img, img,
"absolute"); "absolute");
OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton");
this.maximizeDiv.style.display = "none"; this.maximizeDiv.style.display = "none";
this.div.appendChild(this.maximizeDiv); this.div.appendChild(this.maximizeDiv);
// minimize button div // minimize button div
var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png');
this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
"OpenLayers_Control_MinimizeDiv", "OpenLayers_Control_MinimizeDiv",
null, null,
null, null,
img, img,
"absolute"); "absolute");
OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton");
this.minimizeDiv.style.display = "none"; this.minimizeDiv.style.display = "none";
this.div.appendChild(this.minimizeDiv); this.div.appendChild(this.minimizeDiv);
}, },
CLASS_NAME: "OpenLayers.Control.LayerSwitcher" CLASS_NAME: "OpenLayers.Control.LayerSwitcher"
}); });
+49 -2
View File
@@ -88,13 +88,13 @@
control = new OpenLayers.Control.LayerSwitcher(); control = new OpenLayers.Control.LayerSwitcher();
map.addControl(control); map.addControl(control);
var wmsInput = OpenLayers.Util.getElement(control.id + "_input_" + layer.name); var wmsInput = control.div.childNodes[0].childNodes[1].childNodes[0];
t.ok(wmsInput != null, "correctly makes an input for wms layer"); t.ok(wmsInput != null, "correctly makes an input for wms layer");
t.eq(wmsInput.type, "radio", "wms correctly made a radio button"); t.eq(wmsInput.type, "radio", "wms correctly made a radio button");
t.eq(wmsInput.name, control.id + "_baseLayers", "wms correctly named"); t.eq(wmsInput.name, control.id + "_baseLayers", "wms correctly named");
t.eq(wmsInput.value, layer.name, "wms correctly valued"); t.eq(wmsInput.value, layer.name, "wms correctly valued");
var markersInput = OpenLayers.Util.getElement(control.id + "_input_" + markers.name); var markersInput = control.div.childNodes[0].childNodes[3].childNodes[0];
t.ok(markersInput != null, "correctly makes an input for markers layer"); t.ok(markersInput != null, "correctly makes an input for markers layer");
t.eq(markersInput.type, "checkbox", "wms correctly made a radio button"); t.eq(markersInput.type, "checkbox", "wms correctly made a radio button");
t.eq(markersInput.name, markers.name, "wms correctly named"); t.eq(markersInput.name, markers.name, "wms correctly named");
@@ -191,7 +191,54 @@
t.eq(control.div.childNodes[0].childNodes[0].style.display, "" , "Base layer display on when visble base layer"); t.eq(control.div.childNodes[0].childNodes[0].style.display, "" , "Base layer display on when visble base layer");
} }
// See e.g. https://github.com/openlayers/openlayers/issues/866
function test_Control_LayerSwitcher_validIds(t){
t.plan(2);
// setup
var layername = "Name with spaces & illegal characters * + ~ ` ' ? )",
map = new OpenLayers.Map("map", {
controls: [
new OpenLayers.Control.LayerSwitcher()
],
layers: [
new OpenLayers.Layer.WMS(
layername,
"../../img/blank.gif"
),
// add another layer with the same name, the generated id
// must be different
new OpenLayers.Layer.WMS(
layername,
"../../img/blank.gif"
)
]
});
var baselayerDiv = map.controls[0].div.childNodes[0].childNodes[1],
firstGeneratedInputId = baselayerDiv.childNodes[0].id,
secondGeneratedInputId = baselayerDiv.childNodes[1].id,
// legal ids start with a letter and are followed only by word
// characters (letters, digits, and underscores) plus the dash (-)
// This is only a subset of all allowed charcters inside of ids.
allowedIdChars = (/^[a-zA-Z]{1}[\w-]*$/g);
// tests
// validity
t.ok(
allowedIdChars.test(firstGeneratedInputId),
"id only contains letters, digits, underscores and dashes. It " +
"starts with a letter."
);
// uniqueness
t.ok(
firstGeneratedInputId !== secondGeneratedInputId,
"generated ids are different even for equal layernames"
);
// teardown
map.destroy();
}
</script> </script>
</head> </head>