Index: third_party/polymer/v0_8/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html |
diff --git a/third_party/polymer/v0_8/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html b/third_party/polymer/v0_8/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ba571b603b1b202790e4eaa1c07fd80d7f7b18da |
--- /dev/null |
+++ b/third_party/polymer/v0_8/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html |
@@ -0,0 +1,418 @@ |
+<!-- |
+@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+0009': 'tab', |
+ 'U+001B': 'esc', |
+ 'U+0020': 'space', |
+ 'U+002A': '*', |
+ 'U+0030': '0', |
+ 'U+0031': '1', |
+ 'U+0032': '2', |
+ 'U+0033': '3', |
+ 'U+0034': '4', |
+ 'U+0035': '5', |
+ 'U+0036': '6', |
+ 'U+0037': '7', |
+ 'U+0038': '8', |
+ 'U+0039': '9', |
+ 'U+0041': 'a', |
+ 'U+0042': 'b', |
+ 'U+0043': 'c', |
+ 'U+0044': 'd', |
+ 'U+0045': 'e', |
+ 'U+0046': 'f', |
+ 'U+0047': 'g', |
+ 'U+0048': 'h', |
+ 'U+0049': 'i', |
+ 'U+004A': 'j', |
+ 'U+004B': 'k', |
+ 'U+004C': 'l', |
+ 'U+004D': 'm', |
+ 'U+004E': 'n', |
+ 'U+004F': 'o', |
+ 'U+0050': 'p', |
+ 'U+0051': 'q', |
+ 'U+0052': 'r', |
+ 'U+0053': 's', |
+ 'U+0054': 't', |
+ 'U+0055': 'u', |
+ 'U+0056': 'v', |
+ 'U+0057': 'w', |
+ 'U+0058': 'x', |
+ 'U+0059': 'y', |
+ 'U+005A': 'z', |
+ '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 = { |
+ 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)?/; |
+ |
+ function transformKey(key) { |
+ var validKey = ''; |
+ if (key) { |
+ var lKey = key.toLowerCase(); |
+ if (lKey.length == 1) { |
+ if (KEY_CHAR.test(lKey)) { |
+ validKey = lKey; |
+ } |
+ } else if (ARROW_KEY.test(lKey)) { |
+ validKey = lKey.replace('arrow', ''); |
+ } else if (SPACE_KEY.test(lKey)) { |
+ validKey = 'space'; |
+ } 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 (IDENT_CHAR.test(keyIdent)) { |
+ validKey = KEY_IDENTIFIER[keyIdent]; |
+ } 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(48 - keyCode); |
+ } else if (keyCode >= 96 && keyCode <= 105) { |
+ // num pad 0-9 |
+ validKey = String(96 - keyCode); |
+ } else { |
+ validKey = KEY_CODE[keyCode]; |
+ } |
+ } |
+ return validKey; |
+ } |
+ |
+ function normalizedKeyForEvent(keyEvent) { |
+ // fall back from .key, to .keyIdentifier, to .keyCode, and then to |
+ // .detail.key to support artificial keyboard events |
+ return transformKey(keyEvent.key) || |
+ transformKeyIdentifier(keyEvent.keyIdentifier) || |
+ transformKeyCode(keyEvent.keyCode) || |
+ transformKey(keyEvent.detail.key) || ''; |
+ } |
+ |
+ function keyComboMatchesEvent(keyCombo, keyEvent) { |
+ return normalizedKeyForEvent(keyEvent) === keyCombo.key && |
+ !!keyEvent.shiftKey === !!keyCombo.shiftKey && |
+ !!keyEvent.ctrlKey === !!keyCombo.ctrlKey && |
+ !!keyEvent.altKey === !!keyCombo.altKey && |
+ !!keyEvent.metaKey === !!keyCombo.metaKey; |
+ } |
+ |
+ function parseKeyComboString(keyComboString) { |
+ 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; |
+ } else { |
+ parsedKeyCombo.key = keyName; |
+ parsedKeyCombo.event = event || 'keydown'; |
+ } |
+ |
+ return parsedKeyCombo; |
+ }, { |
+ combo: keyComboString.split(':').shift() |
+ }); |
+ } |
+ |
+ function parseEventString(eventString) { |
+ return eventString.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 event to fire. |
+ * |
+ * Use the `key-event-target` attribute to set up event handlers on a specific |
+ * node. |
+ * The `keys-pressed` event will fire when one of the key combinations set with the |
+ * `keys` property is pressed. |
+ * |
+ * @polymerBehavior IronA11yKeysBehavior |
+ */ |
+ Polymer.IronA11yKeysBehavior = { |
+ properties: { |
+ /** |
+ * The HTMLElement that will be firing relevant KeyboardEvents. |
+ */ |
+ keyEventTarget: { |
+ type: Object, |
+ value: function() { |
+ return this; |
+ } |
+ }, |
+ |
+ _boundKeyHandlers: { |
+ value: function() { |
+ return []; |
+ } |
+ }, |
+ |
+ // We use this due to a limitation in IE10 where instances will have |
+ // own properties of everything on the "prototype". |
+ _imperativeKeyBindings: { |
+ value: function() { |
+ return {}; |
+ } |
+ } |
+ }, |
+ |
+ observers: [ |
+ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)' |
+ ], |
+ |
+ 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(); |
+ }, |
+ |
+ keyboardEventMatchesKeys: function(event, eventString) { |
+ var keyCombos = parseEventString(eventString); |
+ var index; |
+ |
+ for (index = 0; index < keyCombos.length; ++index) { |
+ if (keyComboMatchesEvent(keyCombos[index], 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]); |
+ } |
+ }, |
+ |
+ _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() { |
+ 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) { |
+ keyBindings.forEach(function(keyBinding) { |
+ var keyCombo = keyBinding[0]; |
+ var handlerName = keyBinding[1]; |
+ |
+ if (!event.defaultPrevented && keyComboMatchesEvent(keyCombo, event)) { |
+ this._triggerKeyHandler(keyCombo, handlerName, event); |
+ } |
+ }, this); |
+ }, |
+ |
+ _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) { |
+ var detail = Object.create(keyCombo); |
+ detail.keyboardEvent = keyboardEvent; |
+ |
+ this[handlerName].call(this, new CustomEvent(keyCombo.event, { |
+ detail: detail |
+ })); |
+ } |
+ }; |
+ })(); |
+</script> |