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.github.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/CONTRIBUTORS.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/PATENTS.txt
10 <link rel=
"import" href=
"../polymer/polymer.html">
11 <link rel=
"import" href=
"iron-selection.html">
15 /** @polymerBehavior */
16 Polymer
.IronSelectableBehavior
= {
21 * If you want to use the attribute value of an element for `selected` instead of the index,
22 * set this to the name of the attribute.
24 * @attribute attrForSelected
33 * Gets or sets the selected element. The default is to use the index of the item.
44 * Returns the currently selected item.
46 * @attribute selectedItem
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.
60 * @attribute activateEvent
67 observer
: '_activateEventChanged'
71 * This is a CSS selector sting. If this is set, only items that matches the CSS selector
74 * @attribute selectable
80 * The class to set on elements when selected.
82 * @attribute selectedClass
87 value
: 'iron-selected'
91 * The attribute to set on elements when selected.
93 * @attribute selectedAttribute
104 '_updateSelected(attrForSelected, selected)'
107 excludedLocalNames
: {
111 created: function() {
112 this._bindFilterItem
= this._filterItem
.bind(this);
113 this._selection
= new Polymer
.IronSelection(this._applySelection
.bind(this));
116 attached: function() {
117 this._observer
= this._observeItems(this);
118 this._contentObserver
= this._observeContent(this);
121 detached: function() {
122 if (this._observer
) {
123 this._observer
.disconnect();
125 if (this._contentObserver
) {
126 this._contentObserver
.disconnect();
128 this._removeListener(this.activateEvent
);
132 * Returns an array of selectable items.
138 var nodes
= Polymer
.dom(this).queryDistributedElements(this.selectable
|| '*');
139 return Array
.prototype.filter
.call(nodes
, this._bindFilterItem
);
143 * Returns the index of the given item.
146 * @param {Object} item
147 * @returns Returns the index of the item
149 indexOf: function(item
) {
150 return this.items
.indexOf(item
);
154 * Selects the given value.
157 * @param {string} value the value to select.
159 select: function(value
) {
160 this.selected
= value
;
164 * Selects the previous item.
166 * @method selectPrevious
168 selectPrevious: function() {
169 var length
= this.items
.length
;
170 var index
= (Number(this._valueToIndex(this.selected
)) - 1 + length
) % length
;
171 this.selected
= this._indexToValue(index
);
175 * Selects the next item.
179 selectNext: function() {
180 var index
= (Number(this._valueToIndex(this.selected
)) + 1) % this.items
.length
;
181 this.selected
= this._indexToValue(index
);
184 _addListener: function(eventName
) {
185 this.listen(this, eventName
, '_activateHandler');
188 _removeListener: function(eventName
) {
189 // There is no unlisten yet...
190 // https://github.com/Polymer/polymer/issues/1639
191 //this.removeEventListener(eventName, this._bindActivateHandler);
194 _activateEventChanged: function(eventName
, old
) {
195 this._removeListener(old
);
196 this._addListener(eventName
);
199 _updateSelected: function() {
200 this._selectSelected(this.selected
);
203 _selectSelected: function(selected
) {
204 this._selection
.select(this._valueToItem(this.selected
));
207 _filterItem: function(node
) {
208 return !this.excludedLocalNames
[node
.localName
];
211 _valueToItem: function(value
) {
212 return (value
== null) ? null : this.items
[this._valueToIndex(value
)];
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
) {
223 return Number(value
);
227 _indexToValue: function(index
) {
228 if (this.attrForSelected
) {
229 var item
= this.items
[index
];
231 return this._valueForItem(item
);
238 _valueForItem: function(item
) {
239 return item
[this.attrForSelected
] || item
.getAttribute(this.attrForSelected
);
242 _applySelection: function(item
, isSelected
) {
243 if (this.selectedClass
) {
244 this.toggleClass(this.selectedClass
, isSelected
, item
);
246 if (this.selectedAttribute
) {
247 this.toggleAttribute(this.selectedAttribute
, isSelected
, item
);
249 this._selectionChange();
250 this.fire('iron-' + (isSelected
? 'select' : 'deselect'), {item
: item
});
253 _selectionChange: function() {
254 this._setSelectedItem(this._selection
.get());
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
);
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();
272 observer
.observe(node
, {
279 _activateHandler: function(e
) {
280 // TODO: remove this when https://github.com/Polymer/polymer/issues/1639 is fixed so we
281 // can just remove the old event listener.
282 if (e
.type
!== this.activateEvent
) {
286 var items
= this.items
;
287 while (t
&& t
!= this) {
288 var i
= items
.indexOf(t
);
290 var value
= this._indexToValue(i
);
291 this._itemActivate(value
, t
);
298 _itemActivate: function(value
, item
) {
299 if (!this.fire('iron-activate',
300 {selected
: value
, item
: item
}, {cancelable
: true}).defaultPrevented
) {