Add ICU message format support
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / iron-menu-behavior / iron-menu-behavior-extracted.js
blob178de15ea2c412f064826d74d0f97d34049185ea
3   /**
4    * `Polymer.IronMenuBehavior` implements accessible menu behavior.
5    *
6    * @demo demo/index.html
7    * @polymerBehavior Polymer.IronMenuBehavior
8    */
9   Polymer.IronMenuBehaviorImpl = {
11     properties: {
13       /**
14        * Returns the currently focused item.
15        *
16        * @attribute focusedItem
17        * @type Object
18        */
19       focusedItem: {
20         observer: '_focusedItemChanged',
21         readOnly: true,
22         type: Object
23       },
25       /**
26        * The attribute to use on menu items to look up the item title. Typing the first
27        * letter of an item when the menu is open focuses that item. If unset, `textContent`
28        * will be used.
29        *
30        * @attribute attrForItemTitle
31        * @type String
32        */
33       attrForItemTitle: {
34         type: String
35       }
36     },
38     hostAttributes: {
39       'role': 'menu',
40       'tabindex': '0'
41     },
43     observers: [
44       '_updateMultiselectable(multi)'
45     ],
47     listeners: {
48       'focus': '_onFocus',
49       'keydown': '_onKeydown'
50     },
52     keyBindings: {
53       'up': '_onUpKey',
54       'down': '_onDownKey',
55       'esc': '_onEscKey',
56       'enter': '_onEnterKey',
57       'shift+tab:keydown': '_onShiftTabDown'
58     },
60     _updateMultiselectable: function(multi) {
61       if (multi) {
62         this.setAttribute('aria-multiselectable', 'true');
63       } else {
64         this.removeAttribute('aria-multiselectable');
65       }
66     },
68     _onShiftTabDown: function() {
69       var oldTabIndex;
71       Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
73       oldTabIndex = this.getAttribute('tabindex');
75       this.setAttribute('tabindex', '-1');
77       this.async(function() {
78         this.setAttribute('tabindex', oldTabIndex);
79         Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
80       // Note: polymer/polymer#1305
81       }, 1);
82     },
84     _applySelection: function(item, isSelected) {
85       if (isSelected) {
86         item.setAttribute('aria-selected', 'true');
87       } else {
88         item.removeAttribute('aria-selected');
89       }
91       Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
92     },
94     _focusedItemChanged: function(focusedItem, old) {
95       old && old.setAttribute('tabindex', '-1');
96       if (focusedItem) {
97         focusedItem.setAttribute('tabindex', '0');
98         focusedItem.focus();
99       }
100     },
102     select: function(value) {
103       if (this._defaultFocusAsync) {
104         this.cancelAsync(this._defaultFocusAsync);
105         this._defaultFocusAsync = null;
106       }
107       var item = this._valueToItem(value);
108       this._setFocusedItem(item);
109       Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
110     },
112     _onFocus: function(event) {
113       if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
114         return;
115       }
116       // do not focus the menu itself
117       this.blur();
118       // clear the cached focus item
119       this._setFocusedItem(null);
120       this._defaultFocusAsync = this.async(function() {
121         // focus the selected item when the menu receives focus, or the first item
122         // if no item is selected
123         var selectedItem = this.multi ? (this.selectedItems && this.selectedItems[0]) : this.selectedItem;
124         if (selectedItem) {
125           this._setFocusedItem(selectedItem);
126         } else {
127           this._setFocusedItem(this.items[0]);
128         }
129       // async 100ms to wait for `select` to get called from `_itemActivate`
130       }, 100);
131     },
133     _onUpKey: function() {
134       // up and down arrows moves the focus
135       this._focusPrevious();
136     },
138     _onDownKey: function() {
139       this._focusNext();
140     },
142     _onEscKey: function() {
143       // esc blurs the control
144       this.focusedItem.blur();
145     },
147     _onEnterKey: function(event) {
148       // enter activates the item unless it is disabled
149       this._activateFocused(event.detail.keyboardEvent);
150     },
152     _onKeydown: function(event) {
153       if (this.keyboardEventMatchesKeys(event, 'up down esc enter')) {
154         return;
155       }
157       // all other keys focus the menu item starting with that character
158       this._focusWithKeyboardEvent(event);
159     },
161     _focusWithKeyboardEvent: function(event) {
162       for (var i = 0, item; item = this.items[i]; i++) {
163         var attr = this.attrForItemTitle || 'textContent';
164         var title = item[attr] || item.getAttribute(attr);
165         if (title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
166           this._setFocusedItem(item);
167           break;
168         }
169       }
170     },
172     _activateFocused: function(event) {
173       if (!this.focusedItem.hasAttribute('disabled')) {
174         this._activateHandler(event);
175       }
176     },
178     _focusPrevious: function() {
179       var length = this.items.length;
180       var index = (Number(this.indexOf(this.focusedItem)) - 1 + length) % length;
181       this._setFocusedItem(this.items[index]);
182     },
184     _focusNext: function() {
185       var index = (Number(this.indexOf(this.focusedItem)) + 1) % this.items.length;
186       this._setFocusedItem(this.items[index]);
187     }
189   };
191   Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
193   /** @polymerBehavior Polymer.IronMenuBehavior */
194   Polymer.IronMenuBehavior = [
195     Polymer.IronMultiSelectableBehavior,
196     Polymer.IronA11yKeysBehavior,
197     Polymer.IronMenuBehaviorImpl
198   ];