3 /** @polymerBehavior */
4 Polymer.IronSelectableBehavior = {
7 * Fired when iron-selector is activated (selected or deselected).
8 * It is fired before the selected items are changed.
9 * Cancel the event to abort selection.
11 * @event iron-activate
15 * Fired when an item is selected
21 * Fired when an item is deselected
23 * @event iron-deselect
30 * If you want to use the attribute value of an element for `selected` instead of the index,
31 * set this to the name of the attribute.
33 * @attribute attrForSelected
42 * Gets or sets the selected element. The default is to use the index of the item.
53 * Returns the currently selected item.
55 * @attribute selectedItem
65 * The event that fires from items when they are selected. Selectable
66 * will listen for this event from items and update the selection state.
67 * Set to empty string to listen to no events.
69 * @attribute activateEvent
76 observer: '_activateEventChanged'
80 * This is a CSS selector string. If this is set, only items that match the CSS selector
83 * @attribute selectable
89 * The class to set on elements when selected.
91 * @attribute selectedClass
96 value: 'iron-selected'
100 * The attribute to set on elements when selected.
102 * @attribute selectedAttribute
111 * The set of excluded elements where the key is the `localName`
112 * of the element that will be ignored from the item list.
115 * @default {template: 1}
118 excludedLocalNames: {
129 '_updateSelected(attrForSelected, selected)'
132 created: function() {
133 this._bindFilterItem = this._filterItem.bind(this);
134 this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
137 attached: function() {
138 this._observer = this._observeItems(this);
139 this._contentObserver = this._observeContent(this);
142 detached: function() {
143 if (this._observer) {
144 this._observer.disconnect();
146 if (this._contentObserver) {
147 this._contentObserver.disconnect();
149 this._removeListener(this.activateEvent);
153 * Returns an array of selectable items.
159 var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
160 return Array.prototype.filter.call(nodes, this._bindFilterItem);
164 * Returns the index of the given item.
167 * @param {Object} item
168 * @returns Returns the index of the item
170 indexOf: function(item) {
171 return this.items.indexOf(item);
175 * Selects the given value.
178 * @param {string} value the value to select.
180 select: function(value) {
181 this.selected = value;
185 * Selects the previous item.
187 * @method selectPrevious
189 selectPrevious: function() {
190 var length = this.items.length;
191 var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
192 this.selected = this._indexToValue(index);
196 * Selects the next item.
200 selectNext: function() {
201 var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
202 this.selected = this._indexToValue(index);
205 _addListener: function(eventName) {
206 this.listen(this, eventName, '_activateHandler');
209 _removeListener: function(eventName) {
210 this.unlisten(this, eventName, '_activateHandler');
213 _activateEventChanged: function(eventName, old) {
214 this._removeListener(old);
215 this._addListener(eventName);
218 _updateSelected: function() {
219 this._selectSelected(this.selected);
222 _selectSelected: function(selected) {
223 this._selection.select(this._valueToItem(this.selected));
226 _filterItem: function(node) {
227 return !this.excludedLocalNames[node.localName];
230 _valueToItem: function(value) {
231 return (value == null) ? null : this.items[this._valueToIndex(value)];
234 _valueToIndex: function(value) {
235 if (this.attrForSelected) {
236 for (var i = 0, item; item = this.items[i]; i++) {
237 if (this._valueForItem(item) == value) {
242 return Number(value);
246 _indexToValue: function(index) {
247 if (this.attrForSelected) {
248 var item = this.items[index];
250 return this._valueForItem(item);
257 _valueForItem: function(item) {
258 return item[this.attrForSelected] || item.getAttribute(this.attrForSelected);
261 _applySelection: function(item, isSelected) {
262 if (this.selectedClass) {
263 this.toggleClass(this.selectedClass, isSelected, item);
265 if (this.selectedAttribute) {
266 this.toggleAttribute(this.selectedAttribute, isSelected, item);
268 this._selectionChange();
269 this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {item: item});
272 _selectionChange: function() {
273 this._setSelectedItem(this._selection.get());
276 // observe content changes under the given node.
277 _observeContent: function(node) {
278 var content = node.querySelector('content');
279 if (content && content.parentElement === node) {
280 return this._observeItems(node.domHost);
284 // observe items change under the given node.
285 _observeItems: function(node) {
286 var observer = new MutationObserver(function() {
287 if (this.selected != null) {
288 this._updateSelected();
291 observer.observe(node, {
298 _activateHandler: function(e) {
300 var items = this.items;
301 while (t && t != this) {
302 var i = items.indexOf(t);
304 var value = this._indexToValue(i);
305 this._itemActivate(value, t);
312 _itemActivate: function(value, item) {
313 if (!this.fire('iron-activate',
314 {selected: value, item: item}, {cancelable: true}).defaultPrevented) {