| OLD | NEW |
| 1 <!-- | 1 <!-- |
| 2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | 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 | 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 | 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 | 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 | 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 | 7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
| 8 --> | 8 --> |
| 9 | 9 |
| 10 <link rel="import" href="../polymer/polymer.html"> | 10 <link rel="import" href="../polymer/polymer.html"> |
| 11 <link rel="import" href="iron-selection.html"> | 11 <link rel="import" href="iron-selection.html"> |
| 12 | 12 |
| 13 <script> | 13 <script> |
| 14 | 14 |
| 15 /** @polymerBehavior */ | 15 /** @polymerBehavior */ |
| 16 Polymer.IronSelectableBehavior = { | 16 Polymer.IronSelectableBehavior = { |
| 17 | 17 |
| 18 /** |
| 19 * Fired when iron-selector is activated (selected or deselected). |
| 20 * It is fired before the selected items are changed. |
| 21 * Cancel the event to abort selection. |
| 22 * |
| 23 * @event iron-activate |
| 24 */ |
| 25 |
| 26 /** |
| 27 * Fired when an item is selected |
| 28 * |
| 29 * @event iron-select |
| 30 */ |
| 31 |
| 32 /** |
| 33 * Fired when an item is deselected |
| 34 * |
| 35 * @event iron-deselect |
| 36 */ |
| 37 |
| 38 /** |
| 39 * Fired when the list of selectable items changes (e.g., items are |
| 40 * added or removed). The detail of the event is a list of mutation |
| 41 * records that describe what changed. |
| 42 * |
| 43 * @event iron-items-changed |
| 44 */ |
| 45 |
| 18 properties: { | 46 properties: { |
| 19 | 47 |
| 20 /** | 48 /** |
| 21 * If you want to use the attribute value of an element for `selected` ins
tead of the index, | 49 * 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. | 50 * set this to the name of the attribute. |
| 23 * | |
| 24 * @attribute attrForSelected | |
| 25 * @type {string} | |
| 26 */ | 51 */ |
| 27 attrForSelected: { | 52 attrForSelected: { |
| 28 type: String, | 53 type: String, |
| 29 value: null | 54 value: null |
| 30 }, | 55 }, |
| 31 | 56 |
| 32 /** | 57 /** |
| 33 * Gets or sets the selected element. The default is to use the index of t
he item. | 58 * 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 */ | 59 */ |
| 38 selected: { | 60 selected: { |
| 39 type: String, | 61 type: String, |
| 40 notify: true | 62 notify: true |
| 41 }, | 63 }, |
| 42 | 64 |
| 43 /** | 65 /** |
| 44 * Returns the currently selected item. | 66 * Returns the currently selected item. |
| 45 * | 67 * |
| 46 * @attribute selectedItem | 68 * @type {?Object} |
| 47 * @type {Object} | |
| 48 */ | 69 */ |
| 49 selectedItem: { | 70 selectedItem: { |
| 50 type: Object, | 71 type: Object, |
| 51 readOnly: true, | 72 readOnly: true, |
| 52 notify: true | 73 notify: true |
| 53 }, | 74 }, |
| 54 | 75 |
| 55 /** | 76 /** |
| 56 * The event that fires from items when they are selected. Selectable | 77 * The event that fires from items when they are selected. Selectable |
| 57 * will listen for this event from items and update the selection state. | 78 * will listen for this event from items and update the selection state. |
| 58 * Set to empty string to listen to no events. | 79 * Set to empty string to listen to no events. |
| 59 * | |
| 60 * @attribute activateEvent | |
| 61 * @type {string} | |
| 62 * @default 'tap' | |
| 63 */ | 80 */ |
| 64 activateEvent: { | 81 activateEvent: { |
| 65 type: String, | 82 type: String, |
| 66 value: 'tap', | 83 value: 'tap', |
| 67 observer: '_activateEventChanged' | 84 observer: '_activateEventChanged' |
| 68 }, | 85 }, |
| 69 | 86 |
| 70 /** | 87 /** |
| 71 * This is a CSS selector sting. If this is set, only items that matches
the CSS selector | 88 * This is a CSS selector string. If this is set, only items that match t
he CSS selector |
| 72 * are selectable. | 89 * are selectable. |
| 73 * | |
| 74 * @attribute selectable | |
| 75 * @type {string} | |
| 76 */ | 90 */ |
| 77 selectable: String, | 91 selectable: String, |
| 78 | 92 |
| 79 /** | 93 /** |
| 80 * The class to set on elements when selected. | 94 * The class to set on elements when selected. |
| 81 * | |
| 82 * @attribute selectedClass | |
| 83 * @type {string} | |
| 84 */ | 95 */ |
| 85 selectedClass: { | 96 selectedClass: { |
| 86 type: String, | 97 type: String, |
| 87 value: 'iron-selected' | 98 value: 'iron-selected' |
| 88 }, | 99 }, |
| 89 | 100 |
| 90 /** | 101 /** |
| 91 * The attribute to set on elements when selected. | 102 * The attribute to set on elements when selected. |
| 92 * | |
| 93 * @attribute selectedAttribute | |
| 94 * @type {string} | |
| 95 */ | 103 */ |
| 96 selectedAttribute: { | 104 selectedAttribute: { |
| 97 type: String, | 105 type: String, |
| 98 value: null | 106 value: null |
| 107 }, |
| 108 |
| 109 /** |
| 110 * The list of items from which a selection can be made. |
| 111 */ |
| 112 items: { |
| 113 type: Array, |
| 114 readOnly: true, |
| 115 value: function() { |
| 116 return []; |
| 117 } |
| 118 }, |
| 119 |
| 120 /** |
| 121 * The set of excluded elements where the key is the `localName` |
| 122 * of the element that will be ignored from the item list. |
| 123 * |
| 124 * @default {template: 1} |
| 125 */ |
| 126 _excludedLocalNames: { |
| 127 type: Object, |
| 128 value: function() { |
| 129 return { |
| 130 'template': 1 |
| 131 }; |
| 132 } |
| 99 } | 133 } |
| 100 | |
| 101 }, | 134 }, |
| 102 | 135 |
| 103 observers: [ | 136 observers: [ |
| 104 '_updateSelected(attrForSelected, selected)' | 137 '_updateSelected(attrForSelected, selected)' |
| 105 ], | 138 ], |
| 106 | 139 |
| 107 excludedLocalNames: { | |
| 108 'template': 1 | |
| 109 }, | |
| 110 | |
| 111 created: function() { | 140 created: function() { |
| 112 this._bindFilterItem = this._filterItem.bind(this); | 141 this._bindFilterItem = this._filterItem.bind(this); |
| 113 this._selection = new Polymer.IronSelection(this._applySelection.bind(this
)); | 142 this._selection = new Polymer.IronSelection(this._applySelection.bind(this
)); |
| 114 }, | 143 }, |
| 115 | 144 |
| 116 attached: function() { | 145 attached: function() { |
| 117 this._observer = this._observeItems(this); | 146 this._observer = this._observeItems(this); |
| 118 this._contentObserver = this._observeContent(this); | 147 this._updateItems(); |
| 148 if (!this._shouldUpdateSelection) { |
| 149 this._updateSelected(this.attrForSelected,this.selected) |
| 150 } |
| 151 this._addListener(this.activateEvent); |
| 119 }, | 152 }, |
| 120 | 153 |
| 121 detached: function() { | 154 detached: function() { |
| 122 if (this._observer) { | 155 if (this._observer) { |
| 123 this._observer.disconnect(); | 156 Polymer.dom(this).unobserveNodes(this._observer); |
| 124 } | |
| 125 if (this._contentObserver) { | |
| 126 this._contentObserver.disconnect(); | |
| 127 } | 157 } |
| 128 this._removeListener(this.activateEvent); | 158 this._removeListener(this.activateEvent); |
| 129 }, | 159 }, |
| 130 | 160 |
| 131 /** | 161 /** |
| 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. | 162 * Returns the index of the given item. |
| 144 * | 163 * |
| 145 * @method indexOf | 164 * @method indexOf |
| 146 * @param {Object} item | 165 * @param {Object} item |
| 147 * @returns Returns the index of the item | 166 * @returns Returns the index of the item |
| 148 */ | 167 */ |
| 149 indexOf: function(item) { | 168 indexOf: function(item) { |
| 150 return this.items.indexOf(item); | 169 return this.items.indexOf(item); |
| 151 }, | 170 }, |
| 152 | 171 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 174 /** | 193 /** |
| 175 * Selects the next item. | 194 * Selects the next item. |
| 176 * | 195 * |
| 177 * @method selectNext | 196 * @method selectNext |
| 178 */ | 197 */ |
| 179 selectNext: function() { | 198 selectNext: function() { |
| 180 var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.l
ength; | 199 var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.l
ength; |
| 181 this.selected = this._indexToValue(index); | 200 this.selected = this._indexToValue(index); |
| 182 }, | 201 }, |
| 183 | 202 |
| 203 get _shouldUpdateSelection() { |
| 204 return this.selected != null; |
| 205 }, |
| 206 |
| 184 _addListener: function(eventName) { | 207 _addListener: function(eventName) { |
| 185 this.listen(this, eventName, '_activateHandler'); | 208 this.listen(this, eventName, '_activateHandler'); |
| 186 }, | 209 }, |
| 187 | 210 |
| 188 _removeListener: function(eventName) { | 211 _removeListener: function(eventName) { |
| 189 // There is no unlisten yet... | 212 this.unlisten(this, eventName, '_activateHandler'); |
| 190 // https://github.com/Polymer/polymer/issues/1639 | |
| 191 //this.removeEventListener(eventName, this._bindActivateHandler); | |
| 192 }, | 213 }, |
| 193 | 214 |
| 194 _activateEventChanged: function(eventName, old) { | 215 _activateEventChanged: function(eventName, old) { |
| 195 this._removeListener(old); | 216 this._removeListener(old); |
| 196 this._addListener(eventName); | 217 this._addListener(eventName); |
| 197 }, | 218 }, |
| 198 | 219 |
| 220 _updateItems: function() { |
| 221 var nodes = Polymer.dom(this).queryDistributedElements(this.selectable ||
'*'); |
| 222 nodes = Array.prototype.filter.call(nodes, this._bindFilterItem); |
| 223 this._setItems(nodes); |
| 224 }, |
| 225 |
| 199 _updateSelected: function() { | 226 _updateSelected: function() { |
| 200 this._selectSelected(this.selected); | 227 this._selectSelected(this.selected); |
| 201 }, | 228 }, |
| 202 | 229 |
| 203 _selectSelected: function(selected) { | 230 _selectSelected: function(selected) { |
| 204 this._selection.select(this._valueToItem(this.selected)); | 231 this._selection.select(this._valueToItem(this.selected)); |
| 205 }, | 232 }, |
| 206 | 233 |
| 207 _filterItem: function(node) { | 234 _filterItem: function(node) { |
| 208 return !this.excludedLocalNames[node.localName]; | 235 return !this._excludedLocalNames[node.localName]; |
| 209 }, | 236 }, |
| 210 | 237 |
| 211 _valueToItem: function(value) { | 238 _valueToItem: function(value) { |
| 212 return (value == null) ? null : this.items[this._valueToIndex(value)]; | 239 return (value == null) ? null : this.items[this._valueToIndex(value)]; |
| 213 }, | 240 }, |
| 214 | 241 |
| 215 _valueToIndex: function(value) { | 242 _valueToIndex: function(value) { |
| 216 if (this.attrForSelected) { | 243 if (this.attrForSelected) { |
| 217 for (var i = 0, item; item = this.items[i]; i++) { | 244 for (var i = 0, item; item = this.items[i]; i++) { |
| 218 if (this._valueForItem(item) == value) { | 245 if (this._valueForItem(item) == value) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 247 this.toggleAttribute(this.selectedAttribute, isSelected, item); | 274 this.toggleAttribute(this.selectedAttribute, isSelected, item); |
| 248 } | 275 } |
| 249 this._selectionChange(); | 276 this._selectionChange(); |
| 250 this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {item: item}); | 277 this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {item: item}); |
| 251 }, | 278 }, |
| 252 | 279 |
| 253 _selectionChange: function() { | 280 _selectionChange: function() { |
| 254 this._setSelectedItem(this._selection.get()); | 281 this._setSelectedItem(this._selection.get()); |
| 255 }, | 282 }, |
| 256 | 283 |
| 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. | 284 // observe items change under the given node. |
| 266 _observeItems: function(node) { | 285 _observeItems: function(node) { |
| 267 var observer = new MutationObserver(function() { | 286 return Polymer.dom(node).observeNodes(function(mutations) { |
| 268 if (this.selected != null) { | 287 // Let other interested parties know about the change so that |
| 288 // we don't have to recreate mutation observers everywher. |
| 289 this.fire('iron-items-changed', mutations, { |
| 290 bubbles: false, |
| 291 cancelable: false |
| 292 }); |
| 293 |
| 294 this._updateItems(); |
| 295 |
| 296 if (this._shouldUpdateSelection) { |
| 269 this._updateSelected(); | 297 this._updateSelected(); |
| 270 } | 298 } |
| 271 }.bind(this)); | |
| 272 observer.observe(node, { | |
| 273 childList: true, | |
| 274 subtree: true | |
| 275 }); | 299 }); |
| 276 return observer; | |
| 277 }, | 300 }, |
| 278 | 301 |
| 279 _activateHandler: function(e) { | 302 _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; | 303 var t = e.target; |
| 286 var items = this.items; | 304 var items = this.items; |
| 287 while (t && t != this) { | 305 while (t && t != this) { |
| 288 var i = items.indexOf(t); | 306 var i = items.indexOf(t); |
| 289 if (i >= 0) { | 307 if (i >= 0) { |
| 290 var value = this._indexToValue(i); | 308 var value = this._indexToValue(i); |
| 291 this._itemActivate(value, t); | 309 this._itemActivate(value, t); |
| 292 return; | 310 return; |
| 293 } | 311 } |
| 294 t = t.parentNode; | 312 t = t.parentNode; |
| 295 } | 313 } |
| 296 }, | 314 }, |
| 297 | 315 |
| 298 _itemActivate: function(value, item) { | 316 _itemActivate: function(value, item) { |
| 299 if (!this.fire('iron-activate', | 317 if (!this.fire('iron-activate', |
| 300 {selected: value, item: item}, {cancelable: true}).defaultPrevented) { | 318 {selected: value, item: item}, {cancelable: true}).defaultPrevented) { |
| 301 this.select(value); | 319 this.select(value); |
| 302 } | 320 } |
| 303 } | 321 } |
| 304 | 322 |
| 305 }; | 323 }; |
| 306 | 324 |
| 307 </script> | 325 </script> |
| OLD | NEW |