OLD | NEW |
| (Empty) |
1 <!-- | |
2 @license | |
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | |
4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
7 Code distributed by Google as part of the polymer project is also | |
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
9 --> | |
10 | |
11 <link rel="import" href="../polymer/polymer.html"> | |
12 <link rel="import" href="../iron-selector/iron-multi-selectable.html"> | |
13 <link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html
"> | |
14 | |
15 <script> | |
16 | |
17 /** | |
18 * `Polymer.IronMenuBehavior` implements accessible menu behavior. | |
19 * | |
20 * @demo demo/index.html | |
21 * @polymerBehavior Polymer.IronMenuBehavior | |
22 */ | |
23 Polymer.IronMenuBehaviorImpl = { | |
24 | |
25 properties: { | |
26 | |
27 /** | |
28 * Returns the currently focused item. | |
29 * | |
30 * @attribute focusedItem | |
31 * @type Object | |
32 */ | |
33 focusedItem: { | |
34 observer: '_focusedItemChanged', | |
35 readOnly: true, | |
36 type: Object | |
37 }, | |
38 | |
39 /** | |
40 * The attribute to use on menu items to look up the item title. Typing th
e first | |
41 * letter of an item when the menu is open focuses that item. If unset, `t
extContent` | |
42 * will be used. | |
43 * | |
44 * @attribute attrForItemTitle | |
45 * @type String | |
46 */ | |
47 attrForItemTitle: { | |
48 type: String | |
49 } | |
50 }, | |
51 | |
52 hostAttributes: { | |
53 'role': 'menu', | |
54 'tabindex': '0' | |
55 }, | |
56 | |
57 observers: [ | |
58 '_updateMultiselectable(multi)' | |
59 ], | |
60 | |
61 listeners: { | |
62 'focus': '_onFocus', | |
63 'keydown': '_onKeydown' | |
64 }, | |
65 | |
66 keyBindings: { | |
67 'up': '_onUpKey', | |
68 'down': '_onDownKey', | |
69 'esc': '_onEscKey', | |
70 'enter': '_onEnterKey', | |
71 'shift+tab:keydown': '_onShiftTabDown' | |
72 }, | |
73 | |
74 _updateMultiselectable: function(multi) { | |
75 if (multi) { | |
76 this.setAttribute('aria-multiselectable', 'true'); | |
77 } else { | |
78 this.removeAttribute('aria-multiselectable'); | |
79 } | |
80 }, | |
81 | |
82 _onShiftTabDown: function() { | |
83 var oldTabIndex; | |
84 | |
85 Polymer.IronMenuBehaviorImpl._shiftTabPressed = true; | |
86 | |
87 oldTabIndex = this.getAttribute('tabindex'); | |
88 | |
89 this.setAttribute('tabindex', '-1'); | |
90 | |
91 this.async(function() { | |
92 this.setAttribute('tabindex', oldTabIndex); | |
93 Polymer.IronMenuBehaviorImpl._shiftTabPressed = false; | |
94 // Note: polymer/polymer#1305 | |
95 }, 1); | |
96 }, | |
97 | |
98 _applySelection: function(item, isSelected) { | |
99 if (isSelected) { | |
100 item.setAttribute('aria-selected', 'true'); | |
101 } else { | |
102 item.removeAttribute('aria-selected'); | |
103 } | |
104 | |
105 Polymer.IronSelectableBehavior._applySelection.apply(this, arguments); | |
106 }, | |
107 | |
108 _focusedItemChanged: function(focusedItem, old) { | |
109 old && old.setAttribute('tabindex', '-1'); | |
110 if (focusedItem) { | |
111 focusedItem.setAttribute('tabindex', '0'); | |
112 focusedItem.focus(); | |
113 } | |
114 }, | |
115 | |
116 select: function(value) { | |
117 if (this._defaultFocusAsync) { | |
118 this.cancelAsync(this._defaultFocusAsync); | |
119 this._defaultFocusAsync = null; | |
120 } | |
121 var item = this._valueToItem(value); | |
122 this._setFocusedItem(item); | |
123 Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments); | |
124 }, | |
125 | |
126 _onFocus: function(event) { | |
127 if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) { | |
128 return; | |
129 } | |
130 // do not focus the menu itself | |
131 this.blur(); | |
132 // clear the cached focus item | |
133 this._setFocusedItem(null); | |
134 this._defaultFocusAsync = this.async(function() { | |
135 // focus the selected item when the menu receives focus, or the first it
em | |
136 // if no item is selected | |
137 var selectedItem = this.multi ? (this.selectedItems && this.selectedItem
s[0]) : this.selectedItem; | |
138 if (selectedItem) { | |
139 this._setFocusedItem(selectedItem); | |
140 } else { | |
141 this._setFocusedItem(this.items[0]); | |
142 } | |
143 // async 100ms to wait for `select` to get called from `_itemActivate` | |
144 }, 100); | |
145 }, | |
146 | |
147 _onUpKey: function() { | |
148 // up and down arrows moves the focus | |
149 this._focusPrevious(); | |
150 }, | |
151 | |
152 _onDownKey: function() { | |
153 this._focusNext(); | |
154 }, | |
155 | |
156 _onEscKey: function() { | |
157 // esc blurs the control | |
158 this.focusedItem.blur(); | |
159 }, | |
160 | |
161 _onEnterKey: function(event) { | |
162 // enter activates the item unless it is disabled | |
163 this._activateFocused(event.detail.keyboardEvent); | |
164 }, | |
165 | |
166 _onKeydown: function(event) { | |
167 if (this.keyboardEventMatchesKeys(event, 'up down esc enter')) { | |
168 return; | |
169 } | |
170 | |
171 // all other keys focus the menu item starting with that character | |
172 this._focusWithKeyboardEvent(event); | |
173 }, | |
174 | |
175 _focusWithKeyboardEvent: function(event) { | |
176 for (var i = 0, item; item = this.items[i]; i++) { | |
177 var attr = this.attrForItemTitle || 'textContent'; | |
178 var title = item[attr] || item.getAttribute(attr); | |
179 if (title && title.trim().charAt(0).toLowerCase() === String.fromCharCod
e(event.keyCode).toLowerCase()) { | |
180 this._setFocusedItem(item); | |
181 break; | |
182 } | |
183 } | |
184 }, | |
185 | |
186 _activateFocused: function(event) { | |
187 if (!this.focusedItem.hasAttribute('disabled')) { | |
188 this._activateHandler(event); | |
189 } | |
190 }, | |
191 | |
192 _focusPrevious: function() { | |
193 var length = this.items.length; | |
194 var index = (Number(this.indexOf(this.focusedItem)) - 1 + length) % length
; | |
195 this._setFocusedItem(this.items[index]); | |
196 }, | |
197 | |
198 _focusNext: function() { | |
199 var index = (Number(this.indexOf(this.focusedItem)) + 1) % this.items.leng
th; | |
200 this._setFocusedItem(this.items[index]); | |
201 } | |
202 | |
203 }; | |
204 | |
205 Polymer.IronMenuBehaviorImpl._shiftTabPressed = false; | |
206 | |
207 /** @polymerBehavior Polymer.IronMenuBehavior */ | |
208 Polymer.IronMenuBehavior = [ | |
209 Polymer.IronMultiSelectableBehavior, | |
210 Polymer.IronA11yKeysBehavior, | |
211 Polymer.IronMenuBehaviorImpl | |
212 ]; | |
213 | |
214 </script> | |
OLD | NEW |