OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | |
3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
6 Code distributed by Google as part of the polymer project is also | |
7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
8 --> | |
9 | |
10 <link rel="import" href="../polymer/polymer.html"> | |
11 <link rel="import" href="iron-selection.html"> | |
12 | |
13 <script> | |
14 | |
15 /** @polymerBehavior */ | |
16 Polymer.IronSelectableBehavior = { | |
17 | |
18 properties: { | |
19 | |
20 /** | |
21 * If you want to use the attribute value of an element for `selected` ins
tead of the index, | |
22 * set this to the name of the attribute. | |
23 * | |
24 * @attribute attrForSelected | |
25 * @type {string} | |
26 */ | |
27 attrForSelected: { | |
28 type: String, | |
29 value: null | |
30 }, | |
31 | |
32 /** | |
33 * Gets or sets the selected element. The default is to use the index of t
he item. | |
34 * | |
35 * @attribute selected | |
36 * @type {string} | |
37 */ | |
38 selected: { | |
39 type: String, | |
40 notify: true | |
41 }, | |
42 | |
43 /** | |
44 * Returns the currently selected item. | |
45 * | |
46 * @attribute selectedItem | |
47 * @type {Object} | |
48 */ | |
49 selectedItem: { | |
50 type: Object, | |
51 readOnly: true, | |
52 notify: true | |
53 }, | |
54 | |
55 /** | |
56 * The event that fires from items when they are selected. Selectable | |
57 * will listen for this event from items and update the selection state. | |
58 * Set to empty string to listen to no events. | |
59 * | |
60 * @attribute activateEvent | |
61 * @type {string} | |
62 * @default 'tap' | |
63 */ | |
64 activateEvent: { | |
65 type: String, | |
66 value: 'tap', | |
67 observer: '_activateEventChanged' | |
68 }, | |
69 | |
70 /** | |
71 * This is a CSS selector sting. If this is set, only items that matches
the CSS selector | |
72 * are selectable. | |
73 * | |
74 * @attribute selectable | |
75 * @type {string} | |
76 */ | |
77 selectable: String, | |
78 | |
79 /** | |
80 * The class to set on elements when selected. | |
81 * | |
82 * @attribute selectedClass | |
83 * @type {string} | |
84 */ | |
85 selectedClass: { | |
86 type: String, | |
87 value: 'iron-selected' | |
88 }, | |
89 | |
90 /** | |
91 * The attribute to set on elements when selected. | |
92 * | |
93 * @attribute selectedAttribute | |
94 * @type {string} | |
95 */ | |
96 selectedAttribute: { | |
97 type: String, | |
98 value: null | |
99 } | |
100 | |
101 }, | |
102 | |
103 observers: [ | |
104 '_updateSelected(attrForSelected, selected)' | |
105 ], | |
106 | |
107 excludedLocalNames: { | |
108 'template': 1 | |
109 }, | |
110 | |
111 created: function() { | |
112 this._bindFilterItem = this._filterItem.bind(this); | |
113 this._selection = new Polymer.IronSelection(this._applySelection.bind(this
)); | |
114 }, | |
115 | |
116 attached: function() { | |
117 this._observer = this._observeItems(this); | |
118 this._contentObserver = this._observeContent(this); | |
119 }, | |
120 | |
121 detached: function() { | |
122 if (this._observer) { | |
123 this._observer.disconnect(); | |
124 } | |
125 if (this._contentObserver) { | |
126 this._contentObserver.disconnect(); | |
127 } | |
128 this._removeListener(this.activateEvent); | |
129 }, | |
130 | |
131 /** | |
132 * Returns an array of selectable items. | |
133 * | |
134 * @property items | |
135 * @type Array | |
136 */ | |
137 get items() { | |
138 var nodes = Polymer.dom(this).queryDistributedElements(this.selectable ||
'*'); | |
139 return Array.prototype.filter.call(nodes, this._bindFilterItem); | |
140 }, | |
141 | |
142 /** | |
143 * Returns the index of the given item. | |
144 * | |
145 * @method indexOf | |
146 * @param {Object} item | |
147 * @returns Returns the index of the item | |
148 */ | |
149 indexOf: function(item) { | |
150 return this.items.indexOf(item); | |
151 }, | |
152 | |
153 /** | |
154 * Selects the given value. | |
155 * | |
156 * @method select | |
157 * @param {string} value the value to select. | |
158 */ | |
159 select: function(value) { | |
160 this.selected = value; | |
161 }, | |
162 | |
163 /** | |
164 * Selects the previous item. | |
165 * | |
166 * @method selectPrevious | |
167 */ | |
168 selectPrevious: function() { | |
169 var length = this.items.length; | |
170 var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % len
gth; | |
171 this.selected = this._indexToValue(index); | |
172 }, | |
173 | |
174 /** | |
175 * Selects the next item. | |
176 * | |
177 * @method selectNext | |
178 */ | |
179 selectNext: function() { | |
180 var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.l
ength; | |
181 this.selected = this._indexToValue(index); | |
182 }, | |
183 | |
184 _addListener: function(eventName) { | |
185 this.listen(this, eventName, '_activateHandler'); | |
186 }, | |
187 | |
188 _removeListener: function(eventName) { | |
189 // There is no unlisten yet... | |
190 // https://github.com/Polymer/polymer/issues/1639 | |
191 //this.removeEventListener(eventName, this._bindActivateHandler); | |
192 }, | |
193 | |
194 _activateEventChanged: function(eventName, old) { | |
195 this._removeListener(old); | |
196 this._addListener(eventName); | |
197 }, | |
198 | |
199 _updateSelected: function() { | |
200 this._selectSelected(this.selected); | |
201 }, | |
202 | |
203 _selectSelected: function(selected) { | |
204 this._selection.select(this._valueToItem(this.selected)); | |
205 }, | |
206 | |
207 _filterItem: function(node) { | |
208 return !this.excludedLocalNames[node.localName]; | |
209 }, | |
210 | |
211 _valueToItem: function(value) { | |
212 return (value == null) ? null : this.items[this._valueToIndex(value)]; | |
213 }, | |
214 | |
215 _valueToIndex: function(value) { | |
216 if (this.attrForSelected) { | |
217 for (var i = 0, item; item = this.items[i]; i++) { | |
218 if (this._valueForItem(item) == value) { | |
219 return i; | |
220 } | |
221 } | |
222 } else { | |
223 return Number(value); | |
224 } | |
225 }, | |
226 | |
227 _indexToValue: function(index) { | |
228 if (this.attrForSelected) { | |
229 var item = this.items[index]; | |
230 if (item) { | |
231 return this._valueForItem(item); | |
232 } | |
233 } else { | |
234 return index; | |
235 } | |
236 }, | |
237 | |
238 _valueForItem: function(item) { | |
239 return item[this.attrForSelected] || item.getAttribute(this.attrForSelecte
d); | |
240 }, | |
241 | |
242 _applySelection: function(item, isSelected) { | |
243 if (this.selectedClass) { | |
244 this.toggleClass(this.selectedClass, isSelected, item); | |
245 } | |
246 if (this.selectedAttribute) { | |
247 this.toggleAttribute(this.selectedAttribute, isSelected, item); | |
248 } | |
249 this._selectionChange(); | |
250 this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {item: item}); | |
251 }, | |
252 | |
253 _selectionChange: function() { | |
254 this._setSelectedItem(this._selection.get()); | |
255 }, | |
256 | |
257 // observe content changes under the given node. | |
258 _observeContent: function(node) { | |
259 var content = node.querySelector('content'); | |
260 if (content && content.parentElement === node) { | |
261 return this._observeItems(node.domHost); | |
262 } | |
263 }, | |
264 | |
265 // observe items change under the given node. | |
266 _observeItems: function(node) { | |
267 var observer = new MutationObserver(function() { | |
268 if (this.selected != null) { | |
269 this._updateSelected(); | |
270 } | |
271 }.bind(this)); | |
272 observer.observe(node, { | |
273 childList: true, | |
274 subtree: true | |
275 }); | |
276 return observer; | |
277 }, | |
278 | |
279 _activateHandler: function(e) { | |
280 // TODO: remove this when https://github.com/Polymer/polymer/issues/1639 i
s fixed so we | |
281 // can just remove the old event listener. | |
282 if (e.type !== this.activateEvent) { | |
283 return; | |
284 } | |
285 var t = e.target; | |
286 var items = this.items; | |
287 while (t && t != this) { | |
288 var i = items.indexOf(t); | |
289 if (i >= 0) { | |
290 var value = this._indexToValue(i); | |
291 this._itemActivate(value, t); | |
292 return; | |
293 } | |
294 t = t.parentNode; | |
295 } | |
296 }, | |
297 | |
298 _itemActivate: function(value, item) { | |
299 if (!this.fire('iron-activate', | |
300 {selected: value, item: item}, {cancelable: true}).defaultPrevented) { | |
301 this.select(value); | |
302 } | |
303 } | |
304 | |
305 }; | |
306 | |
307 </script> | |
OLD | NEW |