| OLD | NEW |
| 1 (function() { | 1 (function() { |
| 2 | 2 |
| 3 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/); | 3 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/); |
| 4 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8; | 4 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8; |
| 5 var DEFAULT_PHYSICAL_COUNT = 3; | 5 var DEFAULT_PHYSICAL_COUNT = 3; |
| 6 var HIDDEN_Y = '-10000px'; | 6 var HIDDEN_Y = '-10000px'; |
| 7 var DEFAULT_GRID_SIZE = 200; | 7 var DEFAULT_GRID_SIZE = 200; |
| 8 var SECRET_TABINDEX = -100; |
| 8 | 9 |
| 9 Polymer({ | 10 Polymer({ |
| 10 | 11 |
| 11 is: 'iron-list', | 12 is: 'iron-list', |
| 12 | 13 |
| 13 properties: { | 14 properties: { |
| 14 | 15 |
| 15 /** | 16 /** |
| 16 * An array containing items determining how many instances of the templat
e | 17 * An array containing items determining how many instances of the templat
e |
| 17 * to stamp and that that each template instance should bind to. | 18 * to stamp and that that each template instance should bind to. |
| (...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 829 var dot = path.indexOf('.'); | 830 var dot = path.indexOf('.'); |
| 830 var key = path.substring(0, dot < 0 ? path.length : dot); | 831 var key = path.substring(0, dot < 0 ? path.length : dot); |
| 831 var idx = this._physicalIndexForKey[key]; | 832 var idx = this._physicalIndexForKey[key]; |
| 832 var offscreenItem = this._offscreenFocusedItem; | 833 var offscreenItem = this._offscreenFocusedItem; |
| 833 var el = offscreenItem && offscreenItem._templateInstance.__key__ === key
? | 834 var el = offscreenItem && offscreenItem._templateInstance.__key__ === key
? |
| 834 offscreenItem : this._physicalItems[idx]; | 835 offscreenItem : this._physicalItems[idx]; |
| 835 | 836 |
| 836 if (!el || el._templateInstance.__key__ !== key) { | 837 if (!el || el._templateInstance.__key__ !== key) { |
| 837 return; | 838 return; |
| 838 } | 839 } |
| 839 | |
| 840 if (dot >= 0) { | 840 if (dot >= 0) { |
| 841 path = this.as + '.' + path.substring(dot+1); | 841 path = this.as + '.' + path.substring(dot+1); |
| 842 el._templateInstance.notifyPath(path, value, true); | 842 el._templateInstance.notifyPath(path, value, true); |
| 843 } else { | 843 } else { |
| 844 // Update selection if needed |
| 845 var currentItem = el._templateInstance[this.as]; |
| 846 if (Array.isArray(this.selectedItems)) { |
| 847 for (var i = 0; i < this.selectedItems.length; i++) { |
| 848 if (this.selectedItems[i] === currentItem) { |
| 849 this.set('selectedItems.' + i, value); |
| 850 break; |
| 851 } |
| 852 } |
| 853 } else if (this.selectedItem === currentItem) { |
| 854 this.set('selectedItem', value); |
| 855 } |
| 844 el._templateInstance[this.as] = value; | 856 el._templateInstance[this.as] = value; |
| 845 } | 857 } |
| 846 | |
| 847 }, | 858 }, |
| 848 | 859 |
| 849 /** | 860 /** |
| 850 * Called when the items have changed. That is, ressignments | 861 * Called when the items have changed. That is, ressignments |
| 851 * to `items`, splices or updates to a single item. | 862 * to `items`, splices or updates to a single item. |
| 852 */ | 863 */ |
| 853 _itemsChanged: function(change) { | 864 _itemsChanged: function(change) { |
| 854 if (change.path === 'items') { | 865 if (change.path === 'items') { |
| 855 // reset items | 866 // reset items |
| 856 this._virtualStart = 0; | 867 this._virtualStart = 0; |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 | 1035 |
| 1025 // update the average if we measured something | 1036 // update the average if we measured something |
| 1026 if (this._physicalAverageCount !== prevAvgCount) { | 1037 if (this._physicalAverageCount !== prevAvgCount) { |
| 1027 this._physicalAverage = Math.round( | 1038 this._physicalAverage = Math.round( |
| 1028 ((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) / | 1039 ((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) / |
| 1029 this._physicalAverageCount); | 1040 this._physicalAverageCount); |
| 1030 } | 1041 } |
| 1031 }, | 1042 }, |
| 1032 | 1043 |
| 1033 _updateGridMetrics: function() { | 1044 _updateGridMetrics: function() { |
| 1034 this._viewportWidth = this._scrollTargetWidth; | 1045 this._viewportWidth = this.$.items.offsetWidth; |
| 1035 // Set item width to the value of the _physicalItems offsetWidth | 1046 // Set item width to the value of the _physicalItems offsetWidth |
| 1036 this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].offsetW
idth : DEFAULT_GRID_SIZE; | 1047 this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoun
dingClientRect().width : DEFAULT_GRID_SIZE; |
| 1037 // Set row height to the value of the _physicalItems offsetHeight | 1048 // Set row height to the value of the _physicalItems offsetHeight |
| 1038 this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetH
eight : DEFAULT_GRID_SIZE; | 1049 this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetH
eight : DEFAULT_GRID_SIZE; |
| 1039 // If in grid mode compute how many items with exist in each row | 1050 // If in grid mode compute how many items with exist in each row |
| 1040 this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / thi
s._itemWidth) : this._itemsPerRow; | 1051 this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / thi
s._itemWidth) : this._itemsPerRow; |
| 1041 }, | 1052 }, |
| 1042 | 1053 |
| 1043 /** | 1054 /** |
| 1044 * Updates the position of the physical items. | 1055 * Updates the position of the physical items. |
| 1045 */ | 1056 */ |
| 1046 _positionItems: function() { | 1057 _positionItems: function() { |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1353 */ | 1364 */ |
| 1354 _selectionEnabledChanged: function(selectionEnabled) { | 1365 _selectionEnabledChanged: function(selectionEnabled) { |
| 1355 var handler = selectionEnabled ? this.listen : this.unlisten; | 1366 var handler = selectionEnabled ? this.listen : this.unlisten; |
| 1356 handler.call(this, this, 'tap', '_selectionHandler'); | 1367 handler.call(this, this, 'tap', '_selectionHandler'); |
| 1357 }, | 1368 }, |
| 1358 | 1369 |
| 1359 /** | 1370 /** |
| 1360 * Select an item from an event object. | 1371 * Select an item from an event object. |
| 1361 */ | 1372 */ |
| 1362 _selectionHandler: function(e) { | 1373 _selectionHandler: function(e) { |
| 1363 if (this.selectionEnabled) { | 1374 var model = this.modelForElement(e.target); |
| 1364 var model = this.modelForElement(e.target); | 1375 if (!model) { |
| 1365 if (model) { | 1376 return; |
| 1366 this.toggleSelectionForItem(model[this.as]); | |
| 1367 } | |
| 1368 } | 1377 } |
| 1378 var modelTabIndex, activeElTabIndex; |
| 1379 var target = Polymer.dom(e).path[0]; |
| 1380 var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).ac
tiveElement; |
| 1381 var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.i
ndexAs])]; |
| 1382 // Safari does not focus certain form controls via mouse |
| 1383 // https://bugs.webkit.org/show_bug.cgi?id=118043 |
| 1384 if (target.localName === 'input' || |
| 1385 target.localName === 'button' || |
| 1386 target.localName === 'select') { |
| 1387 return; |
| 1388 } |
| 1389 // Set a temporary tabindex |
| 1390 modelTabIndex = model.tabIndex; |
| 1391 model.tabIndex = SECRET_TABINDEX; |
| 1392 activeElTabIndex = activeEl ? activeEl.tabIndex : -1; |
| 1393 model.tabIndex = modelTabIndex; |
| 1394 // Only select the item if the tap wasn't on a focusable child |
| 1395 // or the element bound to `tabIndex` |
| 1396 if (activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SE
CRET_TABINDEX) { |
| 1397 return; |
| 1398 } |
| 1399 this.toggleSelectionForItem(model[this.as]); |
| 1369 }, | 1400 }, |
| 1370 | 1401 |
| 1371 _multiSelectionChanged: function(multiSelection) { | 1402 _multiSelectionChanged: function(multiSelection) { |
| 1372 this.clearSelection(); | 1403 this.clearSelection(); |
| 1373 this.$.selector.multi = multiSelection; | 1404 this.$.selector.multi = multiSelection; |
| 1374 }, | 1405 }, |
| 1375 | 1406 |
| 1376 /** | 1407 /** |
| 1377 * Updates the size of an item. | 1408 * Updates the size of an item. |
| 1378 * | 1409 * |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 if (idx < 0 || idx >= this._virtualCount) { | 1462 if (idx < 0 || idx >= this._virtualCount) { |
| 1432 return; | 1463 return; |
| 1433 } | 1464 } |
| 1434 this._restoreFocusedItem(); | 1465 this._restoreFocusedItem(); |
| 1435 // scroll to index to make sure it's rendered | 1466 // scroll to index to make sure it's rendered |
| 1436 if (!this._isIndexRendered(idx)) { | 1467 if (!this._isIndexRendered(idx)) { |
| 1437 this.scrollToIndex(idx); | 1468 this.scrollToIndex(idx); |
| 1438 } | 1469 } |
| 1439 | 1470 |
| 1440 var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)]; | 1471 var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)]; |
| 1441 var SECRET = ~(Math.random() * 100); | |
| 1442 var model = physicalItem._templateInstance; | 1472 var model = physicalItem._templateInstance; |
| 1443 var focusable; | 1473 var focusable; |
| 1444 | 1474 |
| 1445 // set a secret tab index | 1475 // set a secret tab index |
| 1446 model.tabIndex = SECRET; | 1476 model.tabIndex = SECRET_TABINDEX; |
| 1447 // check if focusable element is the physical item | 1477 // check if focusable element is the physical item |
| 1448 if (physicalItem.tabIndex === SECRET) { | 1478 if (physicalItem.tabIndex === SECRET_TABINDEX) { |
| 1449 focusable = physicalItem; | 1479 focusable = physicalItem; |
| 1450 } | 1480 } |
| 1451 // search for the element which tabindex is bound to the secret tab index | 1481 // search for the element which tabindex is bound to the secret tab index |
| 1452 if (!focusable) { | 1482 if (!focusable) { |
| 1453 focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECR
ET + '"]'); | 1483 focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECR
ET_TABINDEX + '"]'); |
| 1454 } | 1484 } |
| 1455 // restore the tab index | 1485 // restore the tab index |
| 1456 model.tabIndex = 0; | 1486 model.tabIndex = 0; |
| 1457 // focus the focusable element | 1487 // focus the focusable element |
| 1458 this._focusedIndex = idx; | 1488 this._focusedIndex = idx; |
| 1459 focusable && focusable.focus(); | 1489 focusable && focusable.focus(); |
| 1460 }, | 1490 }, |
| 1461 | 1491 |
| 1462 _removeFocusedItem: function() { | 1492 _removeFocusedItem: function() { |
| 1463 if (this._offscreenFocusedItem) { | 1493 if (this._offscreenFocusedItem) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1556 this._focusPhysicalItem(this._focusedIndex + 1); | 1586 this._focusPhysicalItem(this._focusedIndex + 1); |
| 1557 }, | 1587 }, |
| 1558 | 1588 |
| 1559 _didEnter: function(e) { | 1589 _didEnter: function(e) { |
| 1560 this._focusPhysicalItem(this._focusedIndex); | 1590 this._focusPhysicalItem(this._focusedIndex); |
| 1561 this._selectionHandler(e.detail.keyboardEvent); | 1591 this._selectionHandler(e.detail.keyboardEvent); |
| 1562 } | 1592 } |
| 1563 }); | 1593 }); |
| 1564 | 1594 |
| 1565 })(); | 1595 })(); |
| OLD | NEW |