diff --git a/examples/accessible-panel.html b/examples/accessible-panel.html new file mode 100644 index 0000000000..d46d4fbfee --- /dev/null +++ b/examples/accessible-panel.html @@ -0,0 +1,130 @@ + + + + + + + Custom and accessible panel + + + + + + + +

Custom and accessible panel

+
+ panels, CSS, style, accessibility, button +
+

+ Create a custom and accessible panel, styled entirely with + CSS. +

+
+
+ +
+ +

An accessible panel: + +

+

+ +

By default a panel creates buttons as divs. In this example the + createControlMarkup panel function is overridden to create + a more accessible markup for the buttons. See the accessible-panel.js + source to see how this is done.

+ +

Note: in IE 8, when a button is pressed its content shifts by 1 pixel. + This is a known + IE8 bug, with known workarounds. No workaround is applied in this + example though.

+ +
+ + + diff --git a/examples/accessible-panel.js b/examples/accessible-panel.js new file mode 100644 index 0000000000..f982fc624b --- /dev/null +++ b/examples/accessible-panel.js @@ -0,0 +1,64 @@ +var lon = 5; +var lat = 40; +var zoom = 5; +var map, layer; + +function init() { + map = new OpenLayers.Map( 'map', { controls: [] } ); + layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", + "http://vmap0.tiles.osgeo.org/wms/vmap0", {layers: 'basic'} ); + map.addLayer(layer); + + vlayer = new OpenLayers.Layer.Vector( "Editable" ); + map.addLayer(vlayer); + + zb = new OpenLayers.Control.ZoomBox({ + title: "Zoom box: zoom clicking and dragging", + text: "Zoom" + }); + + var panel = new OpenLayers.Control.Panel({ + defaultControl: zb, + createControlMarkup: function(control) { + var button = document.createElement('button'), + iconSpan = document.createElement('span'), + textSpan = document.createElement('span'); + iconSpan.innerHTML = ' '; + button.appendChild(iconSpan); + if (control.text) { + textSpan.innerHTML = control.text; + } + button.appendChild(textSpan); + return button; + } + }); + + panel.addControls([ + zb, + new OpenLayers.Control.DrawFeature(vlayer, OpenLayers.Handler.Path, + {title:'Draw a feature', text: 'Draw'}), + new OpenLayers.Control.ZoomToMaxExtent({ + title:"Zoom to the max extent", + text: "World" + }) + ]); + + nav = new OpenLayers.Control.NavigationHistory({ + previousOptions: { + title: "Go to previous map position", + text: "Prev" + }, + nextOptions: { + title: "Go to next map position", + text: "Next" + }, + displayClass: "navHistory" + }); + // parent control must be added to the map + map.addControl(nav); + panel.addControls([nav.next, nav.previous]); + + map.addControl(panel); + + map.setCenter(new OpenLayers.LonLat(lon, lat), zoom); +} diff --git a/lib/OpenLayers/Control/LayerSwitcher.js b/lib/OpenLayers/Control/LayerSwitcher.js index a0e480e385..b1f2cc49cb 100644 --- a/lib/OpenLayers/Control/LayerSwitcher.js +++ b/lib/OpenLayers/Control/LayerSwitcher.js @@ -120,7 +120,7 @@ OpenLayers.Control.LayerSwitcher = initialize: function(options) { OpenLayers.Control.prototype.initialize.apply(this, arguments); this.layerStates = []; - + if(this.roundedCorner) { OpenLayers.Console.warn('roundedCorner option is deprecated'); } @@ -143,6 +143,7 @@ OpenLayers.Control.LayerSwitcher = changebaselayer: this.redraw, scope: this }); + this.events.unregister("buttonclick", this, this.onButtonClick); OpenLayers.Control.prototype.destroy.apply(this, arguments); }, @@ -157,13 +158,18 @@ OpenLayers.Control.LayerSwitcher = OpenLayers.Control.prototype.setMap.apply(this, arguments); this.map.events.on({ - buttonclick: this.onButtonClick, addlayer: this.redraw, changelayer: this.redraw, removelayer: this.redraw, changebaselayer: this.redraw, scope: this }); + if (this.outsideViewport) { + this.events.attachToElement(this.div); + this.events.register("buttonclick", this, this.onButtonClick); + } else { + this.map.events.register("buttonclick", this, this.onButtonClick); + } }, /** diff --git a/lib/OpenLayers/Control/Panel.js b/lib/OpenLayers/Control/Panel.js index b04f6c3863..f141671445 100644 --- a/lib/OpenLayers/Control/Panel.js +++ b/lib/OpenLayers/Control/Panel.js @@ -245,26 +245,58 @@ OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, { controls = [controls]; } this.controls = this.controls.concat(controls); - - // Give each control a panel_div which will be used later. - // Access to this div is via the panel_div attribute of the - // control added to the panel. - // Also, stop mousedowns and clicks, but don't stop mouseup, - // since they need to pass through. + for (var i=0, len=controls.length; i} The control to create the HTML + * markup for. + * + * Returns: + * {DOMElement} The markup. + */ + createControlMarkup: function(control) { + return document.createElement("div"); + }, /** * Method: addControlsToMap diff --git a/lib/OpenLayers/Events.js b/lib/OpenLayers/Events.js index 907ced8109..ea46bf3cba 100644 --- a/lib/OpenLayers/Events.js +++ b/lib/OpenLayers/Events.js @@ -20,6 +20,12 @@ OpenLayers.Event = { * element._eventCacheID */ observers: false, + + /** + * Constant: KEY_SPACE + * {int} + */ + KEY_SPACE: 32, /** * Constant: KEY_BACKSPACE @@ -388,7 +394,8 @@ OpenLayers.Events = OpenLayers.Class({ "mousedown", "mouseup", "mousemove", "click", "dblclick", "rightclick", "dblrightclick", "resize", "focus", "blur", - "touchstart", "touchmove", "touchend" + "touchstart", "touchmove", "touchend", + "keydown" ], /** diff --git a/lib/OpenLayers/Events/buttonclick.js b/lib/OpenLayers/Events/buttonclick.js index 351248bf0c..6520b83a0d 100644 --- a/lib/OpenLayers/Events/buttonclick.js +++ b/lib/OpenLayers/Events/buttonclick.js @@ -39,7 +39,7 @@ OpenLayers.Events.buttonclick = OpenLayers.Class({ */ events: [ 'mousedown', 'mouseup', 'click', 'dblclick', - 'touchstart', 'touchmove', 'touchend' + 'touchstart', 'touchmove', 'touchend', 'keydown' ], /** @@ -97,6 +97,31 @@ OpenLayers.Events.buttonclick = OpenLayers.Class({ delete this.target; }, + /** + * Method: getPressedButton + * Get the pressed button, if any. Returns undefined if no button + * was pressed. + * + * Arguments: + * element - {DOMElement} The event target. + * + * Returns: + * {DOMElement} The button element, or undefined. + */ + getPressedButton: function(element) { + var depth = 3, // limit the search depth + button; + do { + if(OpenLayers.Element.hasClass(element, "olButton")) { + // hit! + button = element; + break; + } + element = element.parentNode; + } while(--depth > 0 && element); + return button; + }, + /** * Method: buttonClick * Check if a button was clicked, and fire the buttonclick event @@ -108,15 +133,25 @@ OpenLayers.Events.buttonclick = OpenLayers.Class({ var propagate = true, element = OpenLayers.Event.element(evt); if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) { - if (element.nodeType === 3 || OpenLayers.Element.hasClass(element, "olAlphaImg")) { - element = element.parentNode; - } - if (OpenLayers.Element.hasClass(element, "olButton")) { - if (this.startEvt) { - if (this.completeRegEx.test(evt.type)) { - var pos = OpenLayers.Util.pagePosition(element); + // was a button pressed? + var button = this.getPressedButton(element); + if (button) { + if (evt.type === "keydown") { + switch (evt.keyCode) { + case OpenLayers.Event.KEY_RETURN: + case OpenLayers.Event.KEY_SPACE: this.target.triggerEvent("buttonclick", { - buttonElement: element, + buttonElement: button + }); + OpenLayers.Event.stop(evt); + propagate = false; + break; + } + } else if (this.startEvt) { + if (this.completeRegEx.test(evt.type)) { + var pos = OpenLayers.Util.pagePosition(button); + this.target.triggerEvent("buttonclick", { + buttonElement: button, buttonXY: { x: this.startEvt.clientX - pos[0], y: this.startEvt.clientY - pos[1] diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js index f934f80d65..cd32810be9 100644 --- a/lib/OpenLayers/Format/SLD/v1.js +++ b/lib/OpenLayers/Format/SLD/v1.js @@ -990,12 +990,14 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { }, "LabelPlacement": function(symbolizer) { var node = this.createElementNSPlus("sld:LabelPlacement"); - if (symbolizer.labelAnchorPointX != null || + // PointPlacement and LinePlacement are choices, so don't output both + if ((symbolizer.labelAnchorPointX != null || symbolizer.labelAnchorPointY != null || symbolizer.labelAlign != null || symbolizer.labelXOffset != null || symbolizer.labelYOffset != null || - symbolizer.labelRotation != null) { + symbolizer.labelRotation != null) && + symbolizer.labelPerpendicularOffset == null) { this.writeNode("PointPlacement", symbolizer, node); } if (symbolizer.labelPerpendicularOffset != null) { diff --git a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js index 49596be1c4..bee661311b 100644 --- a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js +++ b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js @@ -58,12 +58,9 @@ OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( }, "VendorOption": function(node, obj) { if (!obj.vendorOptions) { - obj.vendorOptions = []; + obj.vendorOptions = {}; } - obj.vendorOptions.push({ - name: node.getAttribute("name"), - value: this.getChildValue(node) - }); + obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node); } }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), @@ -130,8 +127,11 @@ OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( addVendorOptions: function(node, symbolizer) { var options = symbolizer.vendorOptions; if (options) { - for (var i=0, ii=options.length; i diff --git a/tests/Format/SLD/v1_0_0.html b/tests/Format/SLD/v1_0_0.html index af58c30c7d..a295a746b8 100644 --- a/tests/Format/SLD/v1_0_0.html +++ b/tests/Format/SLD/v1_0_0.html @@ -528,6 +528,7 @@ var format = new OpenLayers.Format.SLD.v1_0_0({ multipleSymbolizers: true }); + // labelPerpendicularOffset takes precedence over labelAlign var style = new OpenLayers.Style2({ rules: [ new OpenLayers.Rule({ @@ -538,7 +539,8 @@ }), new OpenLayers.Symbolizer.Text({ label: "${FOO}", - labelPerpendicularOffset: 10 + labelPerpendicularOffset: 10, + labelAlign: "rb" }) ] })