diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-04 14:17:57 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-05 10:05:06 +0000 |
commit | 39d357e3248f80abea0159765ff39554affb40db (patch) | |
tree | aba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html | |
parent | 87778abf5a1f89266f37d1321b92a21851d8244d (diff) | |
download | qtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz |
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2
Change-Id: I20d43c737f82764d857ada9a55586901b18b9243
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html')
-rw-r--r-- | chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html new file mode 100644 index 00000000000..35756c61e61 --- /dev/null +++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html @@ -0,0 +1,492 @@ +<!-- +@license +Copyright (c) 2015 The Polymer Project Authors. All rights reserved. +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt +Code distributed by Google as part of the polymer project is also +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt +--> + +<link rel="import" href="../polymer/polymer.html"> + +<script> + (function() { + 'use strict'; + + /** + * Chrome uses an older version of DOM Level 3 Keyboard Events + * + * Most keys are labeled as text, but some are Unicode codepoints. + * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html#KeySet-Set + */ + var KEY_IDENTIFIER = { + 'U+0008': 'backspace', + 'U+0009': 'tab', + 'U+001B': 'esc', + 'U+0020': 'space', + 'U+007F': 'del' + }; + + /** + * Special table for KeyboardEvent.keyCode. + * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even better + * than that. + * + * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode#Value_of_keyCode + */ + var KEY_CODE = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 27: 'esc', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 32: 'space', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 46: 'del', + 106: '*' + }; + + /** + * MODIFIER_KEYS maps the short name for modifier keys used in a key + * combo string to the property name that references those same keys + * in a KeyboardEvent instance. + */ + var MODIFIER_KEYS = { + 'shift': 'shiftKey', + 'ctrl': 'ctrlKey', + 'alt': 'altKey', + 'meta': 'metaKey' + }; + + /** + * KeyboardEvent.key is mostly represented by printable character made by + * the keyboard, with unprintable keys labeled nicely. + * + * However, on OS X, Alt+char can make a Unicode character that follows an + * Apple-specific mapping. In this case, we fall back to .keyCode. + */ + var KEY_CHAR = /[a-z0-9*]/; + + /** + * Matches a keyIdentifier string. + */ + var IDENT_CHAR = /U\+/; + + /** + * Matches arrow keys in Gecko 27.0+ + */ + var ARROW_KEY = /^arrow/; + + /** + * Matches space keys everywhere (notably including IE10's exceptional name + * `spacebar`). + */ + var SPACE_KEY = /^space(bar)?/; + + /** + * Matches ESC key. + * + * Value from: http://w3c.github.io/uievents-key/#key-Escape + */ + var ESC_KEY = /^escape$/; + + /** + * Transforms the key. + * @param {string} key The KeyBoardEvent.key + * @param {Boolean} [noSpecialChars] Limits the transformation to + * alpha-numeric characters. + */ + function transformKey(key, noSpecialChars) { + var validKey = ''; + if (key) { + var lKey = key.toLowerCase(); + if (lKey === ' ' || SPACE_KEY.test(lKey)) { + validKey = 'space'; + } else if (ESC_KEY.test(lKey)) { + validKey = 'esc'; + } else if (lKey.length == 1) { + if (!noSpecialChars || KEY_CHAR.test(lKey)) { + validKey = lKey; + } + } else if (ARROW_KEY.test(lKey)) { + validKey = lKey.replace('arrow', ''); + } else if (lKey == 'multiply') { + // numpad '*' can map to Multiply on IE/Windows + validKey = '*'; + } else { + validKey = lKey; + } + } + return validKey; + } + + function transformKeyIdentifier(keyIdent) { + var validKey = ''; + if (keyIdent) { + if (keyIdent in KEY_IDENTIFIER) { + validKey = KEY_IDENTIFIER[keyIdent]; + } else if (IDENT_CHAR.test(keyIdent)) { + keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16); + validKey = String.fromCharCode(keyIdent).toLowerCase(); + } else { + validKey = keyIdent.toLowerCase(); + } + } + return validKey; + } + + function transformKeyCode(keyCode) { + var validKey = ''; + if (Number(keyCode)) { + if (keyCode >= 65 && keyCode <= 90) { + // ascii a-z + // lowercase is 32 offset from uppercase + validKey = String.fromCharCode(32 + keyCode); + } else if (keyCode >= 112 && keyCode <= 123) { + // function keys f1-f12 + validKey = 'f' + (keyCode - 112); + } else if (keyCode >= 48 && keyCode <= 57) { + // top 0-9 keys + validKey = String(keyCode - 48); + } else if (keyCode >= 96 && keyCode <= 105) { + // num pad 0-9 + validKey = String(keyCode - 96); + } else { + validKey = KEY_CODE[keyCode]; + } + } + return validKey; + } + + /** + * Calculates the normalized key for a KeyboardEvent. + * @param {KeyboardEvent} keyEvent + * @param {Boolean} [noSpecialChars] Set to true to limit keyEvent.key + * transformation to alpha-numeric chars. This is useful with key + * combinations like shift + 2, which on FF for MacOS produces + * keyEvent.key = @ + * To get 2 returned, set noSpecialChars = true + * To get @ returned, set noSpecialChars = false + */ + function normalizedKeyForEvent(keyEvent, noSpecialChars) { + // Fall back from .key, to .keyIdentifier, to .keyCode, and then to + // .detail.key to support artificial keyboard events. + return transformKey(keyEvent.key, noSpecialChars) || + transformKeyIdentifier(keyEvent.keyIdentifier) || + transformKeyCode(keyEvent.keyCode) || + transformKey(keyEvent.detail ? keyEvent.detail.key : keyEvent.detail, noSpecialChars) || ''; + } + + function keyComboMatchesEvent(keyCombo, event) { + // For combos with modifiers we support only alpha-numeric keys + var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers); + return keyEvent === keyCombo.key && + (!keyCombo.hasModifiers || ( + !!event.shiftKey === !!keyCombo.shiftKey && + !!event.ctrlKey === !!keyCombo.ctrlKey && + !!event.altKey === !!keyCombo.altKey && + !!event.metaKey === !!keyCombo.metaKey) + ); + } + + function parseKeyComboString(keyComboString) { + if (keyComboString.length === 1) { + return { + combo: keyComboString, + key: keyComboString, + event: 'keydown' + }; + } + return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPart) { + var eventParts = keyComboPart.split(':'); + var keyName = eventParts[0]; + var event = eventParts[1]; + + if (keyName in MODIFIER_KEYS) { + parsedKeyCombo[MODIFIER_KEYS[keyName]] = true; + parsedKeyCombo.hasModifiers = true; + } else { + parsedKeyCombo.key = keyName; + parsedKeyCombo.event = event || 'keydown'; + } + + return parsedKeyCombo; + }, { + combo: keyComboString.split(':').shift() + }); + } + + function parseEventString(eventString) { + return eventString.trim().split(' ').map(function(keyComboString) { + return parseKeyComboString(keyComboString); + }); + } + + /** + * `Polymer.IronA11yKeysBehavior` provides a normalized interface for processing + * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding). + * The element takes care of browser differences with respect to Keyboard events + * and uses an expressive syntax to filter key presses. + * + * Use the `keyBindings` prototype property to express what combination of keys + * will trigger the callback. A key binding has the format + * `"KEY+MODIFIER:EVENT": "callback"` (`"KEY": "callback"` or + * `"KEY:EVENT": "callback"` are valid as well). Some examples: + * + * keyBindings: { + * 'space': '_onKeydown', // same as 'space:keydown' + * 'shift+tab': '_onKeydown', + * 'enter:keypress': '_onKeypress', + * 'esc:keyup': '_onKeyup' + * } + * + * The callback will receive with an event containing the following information in `event.detail`: + * + * _onKeydown: function(event) { + * console.log(event.detail.combo); // KEY+MODIFIER, e.g. "shift+tab" + * console.log(event.detail.key); // KEY only, e.g. "tab" + * console.log(event.detail.event); // EVENT, e.g. "keydown" + * console.log(event.detail.keyboardEvent); // the original KeyboardEvent + * } + * + * Use the `keyEventTarget` attribute to set up event handlers on a specific + * node. + * + * See the [demo source code](https://github.com/PolymerElements/iron-a11y-keys-behavior/blob/master/demo/x-key-aware.html) + * for an example. + * + * @demo demo/index.html + * @polymerBehavior + */ + Polymer.IronA11yKeysBehavior = { + properties: { + /** + * The EventTarget that will be firing relevant KeyboardEvents. Set it to + * `null` to disable the listeners. + * @type {?EventTarget} + */ + keyEventTarget: { + type: Object, + value: function() { + return this; + } + }, + + /** + * If true, this property will cause the implementing element to + * automatically stop propagation on any handled KeyboardEvents. + */ + stopKeyboardEventPropagation: { + type: Boolean, + value: false + }, + + _boundKeyHandlers: { + type: Array, + value: function() { + return []; + } + }, + + // We use this due to a limitation in IE10 where instances will have + // own properties of everything on the "prototype". + _imperativeKeyBindings: { + type: Object, + value: function() { + return {}; + } + } + }, + + observers: [ + '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)' + ], + + + /** + * To be used to express what combination of keys will trigger the relative + * callback. e.g. `keyBindings: { 'esc': '_onEscPressed'}` + * @type {Object} + */ + keyBindings: {}, + + registered: function() { + this._prepKeyBindings(); + }, + + attached: function() { + this._listenKeyEventListeners(); + }, + + detached: function() { + this._unlistenKeyEventListeners(); + }, + + /** + * Can be used to imperatively add a key binding to the implementing + * element. This is the imperative equivalent of declaring a keybinding + * in the `keyBindings` prototype property. + */ + addOwnKeyBinding: function(eventString, handlerName) { + this._imperativeKeyBindings[eventString] = handlerName; + this._prepKeyBindings(); + this._resetKeyEventListeners(); + }, + + /** + * When called, will remove all imperatively-added key bindings. + */ + removeOwnKeyBindings: function() { + this._imperativeKeyBindings = {}; + this._prepKeyBindings(); + this._resetKeyEventListeners(); + }, + + /** + * Returns true if a keyboard event matches `eventString`. + * + * @param {KeyboardEvent} event + * @param {string} eventString + * @return {boolean} + */ + keyboardEventMatchesKeys: function(event, eventString) { + var keyCombos = parseEventString(eventString); + for (var i = 0; i < keyCombos.length; ++i) { + if (keyComboMatchesEvent(keyCombos[i], event)) { + return true; + } + } + return false; + }, + + _collectKeyBindings: function() { + var keyBindings = this.behaviors.map(function(behavior) { + return behavior.keyBindings; + }); + + if (keyBindings.indexOf(this.keyBindings) === -1) { + keyBindings.push(this.keyBindings); + } + + return keyBindings; + }, + + _prepKeyBindings: function() { + this._keyBindings = {}; + + this._collectKeyBindings().forEach(function(keyBindings) { + for (var eventString in keyBindings) { + this._addKeyBinding(eventString, keyBindings[eventString]); + } + }, this); + + for (var eventString in this._imperativeKeyBindings) { + this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]); + } + + // Give precedence to combos with modifiers to be checked first. + for (var eventName in this._keyBindings) { + this._keyBindings[eventName].sort(function (kb1, kb2) { + var b1 = kb1[0].hasModifiers; + var b2 = kb2[0].hasModifiers; + return (b1 === b2) ? 0 : b1 ? -1 : 1; + }) + } + }, + + _addKeyBinding: function(eventString, handlerName) { + parseEventString(eventString).forEach(function(keyCombo) { + this._keyBindings[keyCombo.event] = + this._keyBindings[keyCombo.event] || []; + + this._keyBindings[keyCombo.event].push([ + keyCombo, + handlerName + ]); + }, this); + }, + + _resetKeyEventListeners: function() { + this._unlistenKeyEventListeners(); + + if (this.isAttached) { + this._listenKeyEventListeners(); + } + }, + + _listenKeyEventListeners: function() { + if (!this.keyEventTarget) { + return; + } + Object.keys(this._keyBindings).forEach(function(eventName) { + var keyBindings = this._keyBindings[eventName]; + var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings); + + this._boundKeyHandlers.push([this.keyEventTarget, eventName, boundKeyHandler]); + + this.keyEventTarget.addEventListener(eventName, boundKeyHandler); + }, this); + }, + + _unlistenKeyEventListeners: function() { + var keyHandlerTuple; + var keyEventTarget; + var eventName; + var boundKeyHandler; + + while (this._boundKeyHandlers.length) { + // My kingdom for block-scope binding and destructuring assignment.. + keyHandlerTuple = this._boundKeyHandlers.pop(); + keyEventTarget = keyHandlerTuple[0]; + eventName = keyHandlerTuple[1]; + boundKeyHandler = keyHandlerTuple[2]; + + keyEventTarget.removeEventListener(eventName, boundKeyHandler); + } + }, + + _onKeyBindingEvent: function(keyBindings, event) { + if (this.stopKeyboardEventPropagation) { + event.stopPropagation(); + } + + // if event has been already prevented, don't do anything + if (event.defaultPrevented) { + return; + } + + for (var i = 0; i < keyBindings.length; i++) { + var keyCombo = keyBindings[i][0]; + var handlerName = keyBindings[i][1]; + if (keyComboMatchesEvent(keyCombo, event)) { + this._triggerKeyHandler(keyCombo, handlerName, event); + // exit the loop if eventDefault was prevented + if (event.defaultPrevented) { + return; + } + } + } + }, + + _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) { + var detail = Object.create(keyCombo); + detail.keyboardEvent = keyboardEvent; + var event = new CustomEvent(keyCombo.event, { + detail: detail, + cancelable: true + }); + this[handlerName].call(this, event); + if (event.defaultPrevented) { + keyboardEvent.preventDefault(); + } + } + }; + })(); +</script> |