Merge pull request #1725 from tonio/a11y-enhanced-zoomcontrol

Enhance controls accessibility
This commit is contained in:
Antoine Abt
2014-02-20 17:15:12 +01:00
6 changed files with 182 additions and 200 deletions

View File

@@ -3,28 +3,15 @@
text-align: right; text-align: right;
bottom: 0; bottom: 0;
right: 0; right: 0;
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
padding: 6px; padding: 6px;
color: #000000;
color: rgba(238,238,238,1);
background: rgba(0,60,136,0.3);
} }
.ol-attribution a { .ol-attribution a {
text-decoration: none; text-decoration: none;
}
/* rgba is not supported on IE <= 8, fall back to black text so that it's readable */
.ol-attribution {
color: #000000;
}
.ol-attribution:not([ie8andbelow]) {
color: #eeeeee;
background: rgba(0,60,136,0.3);
}
/* white links are unreadable on IE <= 8 with no background, fall back to blue links */
.ol-attribution a {
color: #7b98bc; color: #7b98bc;
} color: rgba(255,255,255,1);
.ol-attribution a:not([ie8andbelow]) {
color: white;
} }
.ol-attribution ul { .ol-attribution ul {
@@ -46,65 +33,7 @@
padding-top: 2px; padding-top: 2px;
white-space: nowrap; white-space: nowrap;
} }
.ol-full-screen {
/* IE <= 8 doesn't support rgba, fall back to a light grey */
background: #eee;
border-radius: 4px;
padding: 2px;
position: absolute;
right: 8px;
top: 8px;
}
.ol-full-screen:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a light grey */
background: rgba(255,255,255,0.4);
}
@media print {
.ol-full-screen {
display: none;
}
}
.ol-full-screen a {
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background: #7b98bc;
color: white;
display: block;
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
font-size: 18px;
font-weight: bold;
height: 22px;
line-height: 19px;
margin: 1px;
padding: 0;
text-align: center;
text-decoration: none;
width: 22px;
}
.ol-full-screen a:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background: rgba(0,60,136,0.5);
}
a.ol-full-screen-false:after {
content: "\2194";
}
a.ol-full-screen-true:after {
content: "\00d7";
}
.ol-full-screen div {
border-radius: 2px;
}
.ol-full-screen div a {
border-radius: 2px;
}
.ol-full-screen a:hover {
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background: #4c6079;
}
.ol-full-screen a:hover:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background: rgba(0,60,136,0.7);
}
.ol-logo { .ol-logo {
bottom: 0; bottom: 0;
left: 0; left: 0;
@@ -127,24 +56,19 @@ a.ol-full-screen-true:after {
} }
.ol-scale-line { .ol-scale-line {
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background: #95b9e6; background: #95b9e6;
background: rgba(0,60,136,0.3);
border-radius: 4px; border-radius: 4px;
bottom: 8px; bottom: 8px;
left: 8px; left: 8px;
padding: 2px; padding: 2px;
position: absolute; position: absolute;
} }
.ol-scale-line:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background: rgba(0,60,136,0.3);
}
.ol-scale-line-inner { .ol-scale-line-inner {
border: 1px solid #eeeeee; border: 1px solid #eeeeee;
border-top: none; border-top: none;
color: #eeeeee; color: #eeeeee;
font-size: 10px; font-size: 10px;
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
text-align: center; text-align: center;
margin: 1px; margin: 1px;
padding: 0px 2px; padding: 0px 2px;
@@ -162,76 +86,158 @@ a.ol-full-screen-true:after {
-webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-tap-highlight-color: rgba(0,0,0,0);
} }
.ol-zoom { .ol-zoom,
.ol-zoom-extent,
.ol-full-screen {
position: absolute; position: absolute;
top: 8px;
left: 8px;
/* IE <= 8 doesn't support rgba, fall back to a light grey */
background-color: #eee; background-color: #eee;
background-color: rgba(255,255,255,0.4);
border-radius: 4px; border-radius: 4px;
padding: 2px; padding: 2px;
} }
/* IE <= 8 doesn't support rgba, fall back to a light grey */ .ol-zoom:hover,
.ol-zoom:not([ie8andbelow]) { .ol-zoom-extent:hover,
background-color: rgba(255,255,255,0.4); .ol-full-screen:hover {
background-color: rgba(255,255,255,0.6);
}
.ol-zoom {
top: .5em;
left: .5em;
}
.ol-zoom-extent {
top: 4.643em;
left: .5em;
}
.ol-full-screen {
right: .5em;
top: .5em;
} }
@media print { @media print {
.ol-zoom { .ol-zoom,
.ol-zoom-extent,
.ol-full-screen {
display: none; display: none;
} }
} }
.ol-zoom a { .ol-zoom button,
.ol-zoom-extent button,
.ol-full-screen button {
display: block; display: block;
margin: 1px; margin: 1px;
padding: 0; padding: 0;
color: white; color: white;
font-size: 18px; font-size: 1.14em;
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
text-align: center; text-align: center;
height: 22px; height: 1.375em;
width: 22px; width: 1.375em;
line-height: 19px; line-height: .4em;
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background-color: #7b98bc; background-color: #7b98bc;
}
.ol-zoom a:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a light blue */
background-color: rgba(0,60,136,0.5); background-color: rgba(0,60,136,0.5);
border: none;
} }
.ol-touch .ol-zoom a { .ol-zoom button::-moz-focus-inner,
font-size: 20px; .ol-zoom-extent button::-moz-focus-inner,
height: 30px; .ol-full-screen button::-moz-focus-inner {
width: 30px; border: none;
line-height: 26px; padding: 0;
} }
.ol-zoom a:hover { .ol-zoom-extent button {
color: #fff; line-height: 1.4em;
}
.ol-touch .ol-zoom button,
.ol-touch .ol-full-screen button,
.ol-touch .ol-zoom-extent button {
font-size: 1.5em;
}
.ol-touch .ol-zoom-extent {
top: 5.5em;
}
.ol-zoom button:hover,
.ol-zoom button:focus,
.ol-zoom-extent button:hover,
.ol-zoom-extent button:focus,
.ol-full-screen button:hover,
.ol-full-screen button:focus {
text-decoration: none; text-decoration: none;
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */
background-color: #4c6079; background-color: #4c6079;
}
.ol-zoom a:hover:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */
background-color: rgba(0,60,136,0.7); background-color: rgba(0,60,136,0.7);
} }
.ol-zoom-extent button:after {
content: "E";
}
.ol-zoom-in { .ol-zoom-in {
border-radius: 2px 2px 0 0; border-radius: 2px 2px 0 0;
} }
.ol-zoom-out { .ol-zoom-out {
border-radius: 0 0 2px 2px; border-radius: 0 0 2px 2px;
} }
button.ol-full-screen-false:after {
content: "\2194";
}
button.ol-full-screen-true:after {
content: "\00d7";
}
/* invisible but not hidden */
.ol-has-tooltip [role=tooltip] {
position: absolute;
clip: rect(1px 1px 1px 1px); /* < IE8 */
clip: rect(1px, 1px, 1px, 1px);
padding: 0;
border: 0;
height: 1px;
width: 1px;
overflow: hidden;
font-weight: normal;
font-size: 14px;
text-shadow: 0 0 2px #fff;
}
/* show a tooltip offset to below and right */
.ol-has-tooltip:hover [role=tooltip], .ol-has-tooltip:focus [role=tooltip] {
clip: auto;
padding: 0 .4em;
font-size: .8em;
height: 1.2em;
width: auto;
line-height: 1.2em;
z-index: 1100;
max-height: 100px;
white-space: nowrap;
display: inline-block;
background: #FFF;
background: rgba(255,255,255,0.6);
color: #000;
border: 3px solid rgba(255,255,255,0);
border-left-width: 0;
border-radius: 0 4px 4px 0;
bottom: .3em;
left: 2.2em;
}
.ol-touch .ol-has-tooltip:hover [role=tooltip],
.ol-touch .ol-has-tooltip:focus [role=tooltip] {
display: none;
}
.ol-zoom .ol-has-tooltip:hover [role=tooltip],
.ol-zoom .ol-has-tooltip:focus [role=tooltip] {
bottom: 1.1em;
}
.ol-full-screen .ol-has-tooltip:hover [role=tooltip],
.ol-full-screen .ol-has-tooltip:focus [role=tooltip] {
right: 2.2em;
left: auto;
border-radius: 4px 0 0 4px;
}
.ol-zoomslider { .ol-zoomslider {
position: absolute; position: absolute;
top: 67px; top: 67px;
left: 8px; left: 8px;
/* IE <= 8 doesn't support rgba, fall back to a light grey */
background: #eee; background: #eee;
background: rgba(255, 255, 255, 0.4);
border-radius: 4px; border-radius: 4px;
width: 28px; width: 28px;
height: 200px; height: 200px;
@@ -240,79 +246,24 @@ a.ol-full-screen-true:after {
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.ol-zoomslider:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a light grey */
background: rgba(255, 255, 255, 0.4);
}
.ol-zoomslider-thumb { .ol-zoomslider-thumb {
position: absolute; position: absolute;
display: block; display: block;
padding: 0; padding: 0;
margin: 2px; margin: 2px;
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */
background: #7b98bc; background: #7b98bc;
background: rgba(0,60,136,0.5);
border-radius: 2px; border-radius: 2px;
outline: none; outline: none;
overflow: hidden; overflow: hidden;
height: 20px; height: 20px;
width: 24px; width: 24px;
} }
.ol-zoomslider-thumb:not([ie8andbelow]) { .ol-zoom-extent button,
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */ .ol-attribution,
background: rgba(0,60,136,0.5); .ol-full-screen button,
} .ol-scale-line-inner,
.ol-zoom-extent { .ol-zoom button,
position: absolute; .ol-has-tooltip [role=tooltip] {
/* IE <= 8 doesn't support rgba, fall back to a light grey */
background: #eee;
border-radius: 4px;
left: 8px;
padding: 2px;
top: 65px;
}
.ol-zoom-extent:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a light grey */
background: rgba(255,255,255,0.4);
}
@media print {
.ol-zoom-extent {
display: none;
}
}
.ol-zoom-extent a {
display: block;
margin: 1px;
padding: 0;
color: white;
font-size: 16px;
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif; font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
font-weight: bold;
text-decoration: none;
text-align: center;
height: 22px;
width: 22px;
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */
background-color: #7b98bc;
border-radius: 2px;
}
.ol-zoom-extent a:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */
background-color: rgba(0, 60, 136, 0.5);
}
.ol-touch .ol-zoom-extent a {
font-size: 20px;
height: 30px;
width: 30px;
line-height: 26px;
}
.ol-zoom-extent a:hover {
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */
background-color: #4c6079;
}
.ol-zoom-extent a:hover:not([ie8andbelow]) {
/* IE <= 8 doesn't support rgba, fall back to a lighter blue */
background-color: rgba(0, 60, 136, 0.7);
}
.ol-zoom-extent a:after {
content: "E";
} }

View File

@@ -216,6 +216,7 @@
/** /**
* @typedef {Object} olx.control.FullScreenOptions * @typedef {Object} olx.control.FullScreenOptions
* @property {string|undefined} className CSS class name. Default is `ol-full-screen`. * @property {string|undefined} className CSS class name. Default is `ol-full-screen`.
* @property {string|undefined} tipLabel Text label to use for the button tip. Default is `Toggle full-screen`
* @property {boolean|undefined} keys Full keyboard access. * @property {boolean|undefined} keys Full keyboard access.
* @property {Element|undefined} target Target. * @property {Element|undefined} target Target.
* @todo stability experimental * @todo stability experimental
@@ -256,6 +257,8 @@
* @property {string|undefined} className CSS class name. Default is `ol-zoom`. * @property {string|undefined} className CSS class name. Default is `ol-zoom`.
* @property {string|undefined} zoomInLabel Text label to use for the zoom-in button. Default is `+` * @property {string|undefined} zoomInLabel Text label to use for the zoom-in button. Default is `+`
* @property {string|undefined} zoomOutLabel Text label to use for the zoom-out button. Default is `-` * @property {string|undefined} zoomOutLabel Text label to use for the zoom-out button. Default is `-`
* @property {string|undefined} zoomInTipLabel Text label to use for the button tip. Default is `Zoom in`
* @property {string|undefined} zoomOutTipLabel Text label to use for the button tip. Default is `Zoom out`
* @property {number|undefined} delta The zoom delta applied on each click. * @property {number|undefined} delta The zoom delta applied on each click.
* @property {Element|undefined} target Target. * @property {Element|undefined} target Target.
* @todo stability experimental * @todo stability experimental
@@ -273,6 +276,7 @@
* @typedef {Object} olx.control.ZoomToExtentOptions * @typedef {Object} olx.control.ZoomToExtentOptions
* @property {string|undefined} className Class name. Default is `ol-zoom-extent`. * @property {string|undefined} className Class name. Default is `ol-zoom-extent`.
* @property {Element|undefined} target Target. * @property {Element|undefined} target Target.
* @property {string|undefined} tipLabel Text label to use for the button tip. Default is `Zoom to extent`
* @property {ol.Extent|undefined} extent The extent to zoom to. If * @property {ol.Extent|undefined} extent The extent to zoom to. If
* undefined the validity extent of the view projection is used. * undefined the validity extent of the view projection is used.
* @todo stability experimental * @todo stability experimental

View File

@@ -17,6 +17,14 @@ ol.control.defaults = function(opt_options) {
var controls = new ol.Collection(); var controls = new ol.Collection();
var zoomControl = goog.isDef(options.zoom) ?
options.zoom : true;
if (zoomControl) {
var zoomControlOptions = goog.isDef(options.zoomOptions) ?
options.zoomOptions : undefined;
controls.push(new ol.control.Zoom(zoomControlOptions));
}
var attributionControl = goog.isDef(options.attribution) ? var attributionControl = goog.isDef(options.attribution) ?
options.attribution : true; options.attribution : true;
if (attributionControl) { if (attributionControl) {
@@ -33,14 +41,6 @@ ol.control.defaults = function(opt_options) {
controls.push(new ol.control.Logo(logoControlOptions)); controls.push(new ol.control.Logo(logoControlOptions));
} }
var zoomControl = goog.isDef(options.zoom) ?
options.zoom : true;
if (zoomControl) {
var zoomControlOptions = goog.isDef(options.zoomOptions) ?
options.zoomOptions : undefined;
controls.push(new ol.control.Zoom(zoomControlOptions));
}
return controls; return controls;
}; };

View File

@@ -36,11 +36,18 @@ ol.control.FullScreen = function(opt_options) {
this.cssClassName_ = goog.isDef(options.className) ? this.cssClassName_ = goog.isDef(options.className) ?
options.className : 'ol-full-screen'; options.className : 'ol-full-screen';
var aElement = goog.dom.createDom(goog.dom.TagName.A, { var tipLabel = goog.isDef(options.tipLabel) ?
'href': '#fullScreen', options.tipLabel : 'Toggle full-screen';
'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen() var tip = goog.dom.createDom(goog.dom.TagName.SPAN, {
'role' : 'tooltip'
}, tipLabel);
var button = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen() +
' ol-has-tooltip'
}); });
goog.events.listen(aElement, [ goog.dom.appendChild(button, tip);
goog.events.listen(button, [
goog.events.EventType.CLICK, goog.events.EventType.CLICK,
goog.events.EventType.TOUCHEND goog.events.EventType.TOUCHEND
], this.handleClick_, false, this); ], this.handleClick_, false, this);
@@ -51,7 +58,7 @@ ol.control.FullScreen = function(opt_options) {
var element = goog.dom.createDom(goog.dom.TagName.DIV, { var element = goog.dom.createDom(goog.dom.TagName.DIV, {
'class': this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + 'class': this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
(!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : '') (!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : '')
}, aElement); }, button);
goog.base(this, { goog.base(this, {
element: element, element: element,

View File

@@ -37,19 +37,33 @@ ol.control.Zoom = function(opt_options) {
var zoomOutLabel = goog.isDef(options.zoomOutLabel) ? var zoomOutLabel = goog.isDef(options.zoomOutLabel) ?
options.zoomOutLabel : '\u2212'; options.zoomOutLabel : '\u2212';
var inElement = goog.dom.createDom(goog.dom.TagName.A, { var zoomInTipLabel = goog.isDef(options.zoomTipLabel) ?
'href': '#zoomIn', options.zoomInTipLabel : 'Zoom in';
'class': className + '-in' var zoomOutTipLabel = goog.isDef(options.zoomOutTipLabel) ?
}, zoomInLabel); options.zoomOutTipLabel : 'Zoom out';
var tTipZoomIn = goog.dom.createDom(goog.dom.TagName.SPAN, {
'role' : 'tooltip'
}, zoomInTipLabel);
var inElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': className + '-in ol-has-tooltip',
'name' : 'ZoomIn',
'type' : 'button'
}, tTipZoomIn, zoomInLabel);
goog.events.listen(inElement, [ goog.events.listen(inElement, [
goog.events.EventType.TOUCHEND, goog.events.EventType.TOUCHEND,
goog.events.EventType.CLICK goog.events.EventType.CLICK
], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, delta), false, this); ], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, delta), false, this);
var outElement = goog.dom.createDom(goog.dom.TagName.A, { var tTipsZoomOut = goog.dom.createDom(goog.dom.TagName.SPAN, {
'href': '#zoomOut', 'role' : 'tooltip',
'class': className + '-out' 'type' : 'button'
}, zoomOutLabel); }, zoomOutTipLabel);
var outElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': className + '-out ol-has-tooltip',
'name' : 'ZoomOut'
}, tTipsZoomOut, zoomOutLabel);
goog.events.listen(outElement, [ goog.events.listen(outElement, [
goog.events.EventType.TOUCHEND, goog.events.EventType.TOUCHEND,
goog.events.EventType.CLICK goog.events.EventType.CLICK
@@ -80,8 +94,8 @@ goog.inherits(ol.control.Zoom, ol.control.Control);
* @private * @private
*/ */
ol.control.Zoom.prototype.zoomByDelta_ = function(delta, browserEvent) { ol.control.Zoom.prototype.zoomByDelta_ = function(delta, browserEvent) {
// prevent the anchor from getting appended to the url
browserEvent.preventDefault(); browserEvent.preventDefault();
// prevent the anchor from getting appended to the url
var map = this.getMap(); var map = this.getMap();
// FIXME works for View2D only // FIXME works for View2D only
var view = map.getView(); var view = map.getView();

View File

@@ -33,12 +33,18 @@ ol.control.ZoomToExtent = function(opt_options) {
var className = goog.isDef(options.className) ? options.className : var className = goog.isDef(options.className) ? options.className :
'ol-zoom-extent'; 'ol-zoom-extent';
var tipLabel = goog.isDef(options.tipLabel) ?
options.tipLabel : 'Fit to extent';
var tip = goog.dom.createDom(goog.dom.TagName.SPAN, {
'role' : 'tooltip'
}, tipLabel);
var element = goog.dom.createDom(goog.dom.TagName.DIV, { var element = goog.dom.createDom(goog.dom.TagName.DIV, {
'class': className + ' ' + ol.css.CLASS_UNSELECTABLE 'class': className + ' ' + ol.css.CLASS_UNSELECTABLE
}); });
var button = goog.dom.createDom(goog.dom.TagName.A, { var button = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'href': '#zoomExtent' 'class': 'ol-has-tooltip'
}); });
goog.dom.appendChild(button, tip);
goog.dom.appendChild(element, button); goog.dom.appendChild(element, button);
goog.events.listen(element, [ goog.events.listen(element, [
@@ -59,8 +65,8 @@ goog.inherits(ol.control.ZoomToExtent, ol.control.Control);
* @private * @private
*/ */
ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function(browserEvent) { ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function(browserEvent) {
// prevent #zoomExtent anchor from getting appended to the url
browserEvent.preventDefault(); browserEvent.preventDefault();
// prevent #zoomExtent anchor from getting appended to the url
var map = this.getMap(); var map = this.getMap();
var view = map.getView(); var view = map.getView();
goog.asserts.assert(goog.isDef(view)); goog.asserts.assert(goog.isDef(view));