Index: third_party/polymer/v0_8/components/iron-menu-behavior/iron-menu-behavior.html |
diff --git a/third_party/polymer/v0_8/components/iron-menu-behavior/iron-menu-behavior.html b/third_party/polymer/v0_8/components/iron-menu-behavior/iron-menu-behavior.html |
index 3339f70869c85349dcb01f6e5b9906dc84b1f36a..aa58c7fe6b558d93cb116d3c733147afdbf5265e 100644 |
--- a/third_party/polymer/v0_8/components/iron-menu-behavior/iron-menu-behavior.html |
+++ b/third_party/polymer/v0_8/components/iron-menu-behavior/iron-menu-behavior.html |
@@ -10,14 +10,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN |
<link rel="import" href="../polymer/polymer.html"> |
<link rel="import" href="../iron-selector/iron-multi-selectable.html"> |
- |
-<!-- |
-`Polymer.IronMenuBehavior` implements accessible menu behavior. |
---> |
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html"> |
<script> |
- Polymer.IronMenuBehavior = Polymer.IronMultiSelectableBehavior.concat({ |
+ /** |
+ * `Polymer.IronMenuBehavior` implements accessible menu behavior. |
+ * |
+ * @demo demo/index.html |
+ * @polymerBehavior Polymer.IronMenuBehavior |
+ */ |
+ Polymer.IronMenuBehaviorImpl = { |
properties: { |
@@ -44,24 +47,64 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN |
attrForItemTitle: { |
type: String |
} |
- |
}, |
- observers: [ |
- '_selectedItemsChanged(selectedItems)', |
- '_selectedItemChanged(selectedItem)' |
- ], |
- |
hostAttributes: { |
'role': 'menu', |
'tabindex': '0' |
}, |
+ observers: [ |
+ '_updateMultiselectable(multi)' |
+ ], |
+ |
listeners: { |
'focus': '_onFocus', |
'keydown': '_onKeydown' |
}, |
+ keyBindings: { |
+ 'up': '_onUpKey', |
+ 'down': '_onDownKey', |
+ 'esc': '_onEscKey', |
+ 'enter': '_onEnterKey', |
+ 'shift+tab:keydown': '_onShiftTabDown' |
+ }, |
+ |
+ _updateMultiselectable: function(multi) { |
+ if (multi) { |
+ this.setAttribute('aria-multiselectable', 'true'); |
+ } else { |
+ this.removeAttribute('aria-multiselectable'); |
+ } |
+ }, |
+ |
+ _onShiftTabDown: function() { |
+ var oldTabIndex; |
+ |
+ Polymer.IronMenuBehaviorImpl._shiftTabPressed = true; |
+ |
+ oldTabIndex = this.getAttribute('tabindex'); |
+ |
+ this.setAttribute('tabindex', '-1'); |
+ |
+ this.async(function() { |
+ this.setAttribute('tabindex', oldTabIndex); |
+ Polymer.IronMenuBehaviorImpl._shiftTabPressed = false; |
+ // Note: polymer/polymer#1305 |
+ }, 1); |
+ }, |
+ |
+ _applySelection: function(item, isSelected) { |
+ if (isSelected) { |
+ item.setAttribute('aria-selected', 'true'); |
+ } else { |
+ item.removeAttribute('aria-selected'); |
+ } |
+ |
+ Polymer.IronSelectableBehavior._applySelection.apply(this, arguments); |
+ }, |
+ |
_focusedItemChanged: function(focusedItem, old) { |
old && old.setAttribute('tabindex', '-1'); |
if (focusedItem) { |
@@ -70,59 +113,82 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN |
} |
}, |
- _selectedItemsChanged: function(selectedItems) { |
- this._setFocusedItem(selectedItems[0]); |
- }, |
- |
- _selectedItemChanged: function(selectedItem) { |
- this._setFocusedItem(selectedItem); |
+ select: function(value) { |
+ if (this._defaultFocusAsync) { |
+ this.cancelAsync(this._defaultFocusAsync); |
+ this._defaultFocusAsync = null; |
+ } |
+ var item = this._valueToItem(value); |
+ this._setFocusedItem(item); |
+ Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments); |
}, |
_onFocus: function(event) { |
+ if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) { |
+ return; |
+ } |
+ // do not focus the menu itself |
+ this.blur(); |
// clear the cached focus item |
this._setFocusedItem(null); |
- // focus the selected item when the menu receives focus, or the first item |
- // if no item is selected |
- var selectedItem = this.multi ? (this.selectedItems && this.selectedItems[0]) : this.selectedItem; |
- if (selectedItem) { |
- this._setFocusedItem(selectedItem); |
- } else { |
- this._setFocusedItem(this.items[0]); |
- } |
+ this._defaultFocusAsync = this.async(function() { |
+ // focus the selected item when the menu receives focus, or the first item |
+ // if no item is selected |
+ var selectedItem = this.multi ? (this.selectedItems && this.selectedItems[0]) : this.selectedItem; |
+ if (selectedItem) { |
+ this._setFocusedItem(selectedItem); |
+ } else { |
+ this._setFocusedItem(this.items[0]); |
+ } |
+ // async 100ms to wait for `select` to get called from `_itemActivate` |
+ }, 100); |
+ }, |
+ |
+ _onUpKey: function() { |
+ // up and down arrows moves the focus |
+ this._focusPrevious(); |
+ }, |
+ |
+ _onDownKey: function() { |
+ this._focusNext(); |
+ }, |
+ |
+ _onEscKey: function() { |
+ // esc blurs the control |
+ this.focusedItem.blur(); |
+ }, |
+ |
+ _onEnterKey: function(event) { |
+ // enter activates the item unless it is disabled |
+ this._activateFocused(event.detail.keyboardEvent); |
}, |
_onKeydown: function(event) { |
- // FIXME want to define these somewhere, core-a11y-keys? |
- var DOWN = 40; |
- var UP = 38; |
- var ESC = 27; |
- var ENTER = 13; |
- if (event.keyCode === DOWN) { |
- // up and down arrows moves the focus |
- this._focusNext(); |
- } else if (event.keyCode === UP) { |
- this._focusPrevious(); |
- } else if (event.keyCode === ESC) { |
- // esc blurs the control |
- this.focusedItem.blur(); |
- } else if (event.keyCode === ENTER) { |
- // enter activates the item unless it is disabled |
- if (!this.focusedItem.hasAttribute('disabled')) { |
- this._activateHandler(event); |
- } |
- } else { |
- // all other keys focus the menu item starting with that character |
- for (var i = 0, item; item = this.items[i]; i++) { |
- var attr = this.attrForItemTitle || 'textContent'; |
- var title = item[attr] || item.getAttribute(attr); |
- if (title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) { |
- this._setFocusedItem(item); |
- break; |
- } |
+ if (this.keyboardEventMatchesKeys(event, 'up down esc enter')) { |
+ return; |
+ } |
+ |
+ // all other keys focus the menu item starting with that character |
+ this._focusWithKeyboardEvent(event); |
+ }, |
+ |
+ _focusWithKeyboardEvent: function(event) { |
+ for (var i = 0, item; item = this.items[i]; i++) { |
+ var attr = this.attrForItemTitle || 'textContent'; |
+ var title = item[attr] || item.getAttribute(attr); |
+ if (title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) { |
+ this._setFocusedItem(item); |
+ break; |
} |
} |
}, |
+ _activateFocused: function(event) { |
+ if (!this.focusedItem.hasAttribute('disabled')) { |
+ this._activateHandler(event); |
+ } |
+ }, |
+ |
_focusPrevious: function() { |
var length = this.items.length; |
var index = (Number(this.indexOf(this.focusedItem)) - 1 + length) % length; |
@@ -134,6 +200,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN |
this._setFocusedItem(this.items[index]); |
} |
- }); |
+ }; |
+ |
+ Polymer.IronMenuBehaviorImpl._shiftTabPressed = false; |
+ |
+ /** @polymerBehavior Polymer.IronMenuBehavior */ |
+ Polymer.IronMenuBehavior = [ |
+ Polymer.IronMultiSelectableBehavior, |
+ Polymer.IronA11yKeysBehavior, |
+ Polymer.IronMenuBehaviorImpl |
+ ]; |
</script> |