| 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 |