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