Service workers: Allow HTTPS pages arrived at via HTTP redirect to use SW
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / iron-selector / iron-selectable-extracted.js
blob9b5a4b33b280d9373c35bf4587d6175b48a72ae9
1 /** @polymerBehavior */
2   Polymer.IronSelectableBehavior = {
4     properties: {
6       /**
7        * If you want to use the attribute value of an element for `selected` instead of the index,
8        * set this to the name of the attribute.
9        *
10        * @attribute attrForSelected
11        * @type {string}
12        */
13       attrForSelected: {
14         type: String,
15         value: null
16       },
18       /**
19        * Gets or sets the selected element. The default is to use the index of the item.
20        *
21        * @attribute selected
22        * @type {string}
23        */
24       selected: {
25         type: String,
26         notify: true
27       },
29       /**
30        * Returns the currently selected item.
31        *
32        * @attribute selectedItem
33        * @type {Object}
34        */
35       selectedItem: {
36         type: Object,
37         readOnly: true,
38         notify: true
39       },
41       /**
42        * The event that fires from items when they are selected. Selectable
43        * will listen for this event from items and update the selection state.
44        * Set to empty string to listen to no events.
45        *
46        * @attribute activateEvent
47        * @type {string}
48        * @default 'tap'
49        */
50       activateEvent: {
51         type: String,
52         value: 'tap',
53         observer: '_activateEventChanged'
54       },
56       /**
57        * This is a CSS selector sting.  If this is set, only items that matches the CSS selector
58        * are selectable.
59        *
60        * @attribute selectable
61        * @type {string}
62        */
63       selectable: String,
65       /**
66        * The class to set on elements when selected.
67        *
68        * @attribute selectedClass
69        * @type {string}
70        */
71       selectedClass: {
72         type: String,
73         value: 'iron-selected'
74       },
76       /**
77        * The attribute to set on elements when selected.
78        *
79        * @attribute selectedAttribute
80        * @type {string}
81        */
82       selectedAttribute: {
83         type: String,
84         value: null
85       }
87     },
89     observers: [
90       '_updateSelected(attrForSelected, selected)'
91     ],
93     excludedLocalNames: {
94       'template': 1
95     },
97     created: function() {
98       this._bindFilterItem = this._filterItem.bind(this);
99       this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
100     },
102     attached: function() {
103       this._observer = this._observeItems(this);
104       this._contentObserver = this._observeContent(this);
105     },
107     detached: function() {
108       if (this._observer) {
109         this._observer.disconnect();
110       }
111       if (this._contentObserver) {
112         this._contentObserver.disconnect();
113       }
114       this._removeListener(this.activateEvent);
115     },
117     /**
118      * Returns an array of selectable items.
119      *
120      * @property items
121      * @type Array
122      */
123     get items() {
124       var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
125       return Array.prototype.filter.call(nodes, this._bindFilterItem);
126     },
128     /**
129      * Returns the index of the given item.
130      *
131      * @method indexOf
132      * @param {Object} item
133      * @returns Returns the index of the item
134      */
135     indexOf: function(item) {
136       return this.items.indexOf(item);
137     },
139     /**
140      * Selects the given value.
141      *
142      * @method select
143      * @param {string} value the value to select.
144      */
145     select: function(value) {
146       this.selected = value;
147     },
149     /**
150      * Selects the previous item.
151      *
152      * @method selectPrevious
153      */
154     selectPrevious: function() {
155       var length = this.items.length;
156       var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
157       this.selected = this._indexToValue(index);
158     },
160     /**
161      * Selects the next item.
162      *
163      * @method selectNext
164      */
165     selectNext: function() {
166       var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
167       this.selected = this._indexToValue(index);
168     },
170     _addListener: function(eventName) {
171       this.listen(this, eventName, '_activateHandler');
172     },
174     _removeListener: function(eventName) {
175       // There is no unlisten yet...
176       // https://github.com/Polymer/polymer/issues/1639
177       //this.removeEventListener(eventName, this._bindActivateHandler);
178     },
180     _activateEventChanged: function(eventName, old) {
181       this._removeListener(old);
182       this._addListener(eventName);
183     },
185     _updateSelected: function() {
186       this._selectSelected(this.selected);
187     },
189     _selectSelected: function(selected) {
190       this._selection.select(this._valueToItem(this.selected));
191     },
193     _filterItem: function(node) {
194       return !this.excludedLocalNames[node.localName];
195     },
197     _valueToItem: function(value) {
198       return (value == null) ? null : this.items[this._valueToIndex(value)];
199     },
201     _valueToIndex: function(value) {
202       if (this.attrForSelected) {
203         for (var i = 0, item; item = this.items[i]; i++) {
204           if (this._valueForItem(item) == value) {
205             return i;
206           }
207         }
208       } else {
209         return Number(value);
210       }
211     },
213     _indexToValue: function(index) {
214       if (this.attrForSelected) {
215         var item = this.items[index];
216         if (item) {
217           return this._valueForItem(item);
218         }
219       } else {
220         return index;
221       }
222     },
224     _valueForItem: function(item) {
225       return item[this.attrForSelected] || item.getAttribute(this.attrForSelected);
226     },
228     _applySelection: function(item, isSelected) {
229       if (this.selectedClass) {
230         this.toggleClass(this.selectedClass, isSelected, item);
231       }
232       if (this.selectedAttribute) {
233         this.toggleAttribute(this.selectedAttribute, isSelected, item);
234       }
235       this._selectionChange();
236       this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {item: item});
237     },
239     _selectionChange: function() {
240       this._setSelectedItem(this._selection.get());
241     },
243     // observe content changes under the given node.
244     _observeContent: function(node) {
245       var content = node.querySelector('content');
246       if (content && content.parentElement === node) {
247         return this._observeItems(node.domHost);
248       }
249     },
251     // observe items change under the given node.
252     _observeItems: function(node) {
253       var observer = new MutationObserver(function() {
254         if (this.selected != null) {
255           this._updateSelected();
256         }
257       }.bind(this));
258       observer.observe(node, {
259         childList: true,
260         subtree: true
261       });
262       return observer;
263     },
265     _activateHandler: function(e) {
266       // TODO: remove this when https://github.com/Polymer/polymer/issues/1639 is fixed so we
267       // can just remove the old event listener.
268       if (e.type !== this.activateEvent) {
269         return;
270       }
271       var t = e.target;
272       var items = this.items;
273       while (t && t != this) {
274         var i = items.indexOf(t);
275         if (i >= 0) {
276           var value = this._indexToValue(i);
277           this._itemActivate(value, t);
278           return;
279         }
280         t = t.parentNode;
281       }
282     },
284     _itemActivate: function(value, item) {
285       if (!this.fire('iron-activate',
286           {selected: value, item: item}, {cancelable: true}).defaultPrevented) {
287         this.select(value);
288       }
289     }
291   };