Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js

Issue 2386533002: MD History: update iron-list and dependencies for better scroll performance (Closed)
Patch Set: test "fixes" Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 ITEM_WIDTH = 0;
8 var ITEM_HEIGHT = 1;
8 var SECRET_TABINDEX = -100; 9 var SECRET_TABINDEX = -100;
9 10
10 Polymer({ 11 Polymer({
11 12
12 is: 'iron-list', 13 is: 'iron-list',
13 14
14 properties: { 15 properties: {
15 16
16 /** 17 /**
17 * An array containing items determining how many instances of the templat e 18 * An array containing items determining how many instances of the templat e
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 230
230 /** 231 /**
231 * A Polymer collection for the items. 232 * A Polymer collection for the items.
232 * @type {?Polymer.Collection} 233 * @type {?Polymer.Collection}
233 */ 234 */
234 _collection: null, 235 _collection: null,
235 236
236 /** 237 /**
237 * The max number of pages to render. One page is equivalent to the height o f the list. 238 * The max number of pages to render. One page is equivalent to the height o f the list.
238 */ 239 */
239 _maxPages: 3, 240 _maxPages: 2,
240 241
241 /** 242 /**
242 * The currently focused physical item. 243 * The currently focused physical item.
243 */ 244 */
244 _focusedItem: null, 245 _focusedItem: null,
245 246
246 /** 247 /**
247 * The index of the `_focusedItem`. 248 * The index of the `_focusedItem`.
248 */ 249 */
249 _focusedIndex: -1, 250 _focusedIndex: -1,
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 * This default value assumes that we will at least have the equivalent 385 * This default value assumes that we will at least have the equivalent
385 * to a viewport of physical items above and below the user's viewport. 386 * to a viewport of physical items above and below the user's viewport.
386 */ 387 */
387 get _optPhysicalSize() { 388 get _optPhysicalSize() {
388 if (this.grid) { 389 if (this.grid) {
389 return this._estRowsInView * this._rowHeight * this._maxPages; 390 return this._estRowsInView * this._rowHeight * this._maxPages;
390 } 391 }
391 return this._viewportHeight * this._maxPages; 392 return this._viewportHeight * this._maxPages;
392 }, 393 },
393 394
394 get _optPhysicalCount() {
395 return this._estRowsInView * this._itemsPerRow * this._maxPages;
396 },
397
398 /** 395 /**
399 * True if the current list is visible. 396 * True if the current list is visible.
400 */ 397 */
401 get _isVisible() { 398 get _isVisible() {
402 return Boolean(this.offsetWidth || this.offsetHeight); 399 return Boolean(this.offsetWidth || this.offsetHeight);
403 }, 400 },
404 401
405 /** 402 /**
406 * Gets the index of the first visible item in the viewport. 403 * Gets the index of the first visible item in the viewport.
407 * 404 *
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 464
468 get _physicalRows() { 465 get _physicalRows() {
469 return Math.ceil(this._physicalCount / this._itemsPerRow); 466 return Math.ceil(this._physicalCount / this._itemsPerRow);
470 }, 467 },
471 468
472 ready: function() { 469 ready: function() {
473 this.addEventListener('focus', this._didFocus.bind(this), true); 470 this.addEventListener('focus', this._didFocus.bind(this), true);
474 }, 471 },
475 472
476 attached: function() { 473 attached: function() {
477 this.updateViewportBoundaries();
478 if (this._physicalCount === 0) { 474 if (this._physicalCount === 0) {
479 this._debounceTemplate(this._render); 475 this._debounceTemplate(this._render);
480 } 476 }
481 // `iron-resize` is fired when the list is attached if the event is added 477 // `iron-resize` is fired when the list is attached if the event is added
482 // before attached causing unnecessary work. 478 // before attached causing unnecessary work.
483 this.listen(this, 'iron-resize', '_resizeHandler'); 479 this.listen(this, 'iron-resize', '_resizeHandler');
484 }, 480 },
485 481
486 detached: function() { 482 detached: function() {
487 this.unlisten(this, 'iron-resize', '_resizeHandler'); 483 this.unlisten(this, 'iron-resize', '_resizeHandler');
488 }, 484 },
489 485
490 /** 486 /**
491 * Set the overflow property if this element has its own scrolling region 487 * Set the overflow property if this element has its own scrolling region
492 */ 488 */
493 _setOverflow: function(scrollTarget) { 489 _setOverflow: function(scrollTarget) {
494 this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : ''; 490 this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
495 this.style.overflow = scrollTarget === this ? 'auto' : ''; 491 this.style.overflow = scrollTarget === this ? 'auto' : '';
496 }, 492 },
497 493
498 /** 494 /**
499 * Invoke this method if you dynamically update the viewport's 495 * Invoke this method if you dynamically update the viewport's
500 * size or CSS padding. 496 * size or CSS padding.
501 * 497 *
502 * @method updateViewportBoundaries 498 * @method updateViewportBoundaries
503 */ 499 */
504 updateViewportBoundaries: function() { 500 updateViewportBoundaries: function() {
505 this._scrollerPaddingTop = this.scrollTarget === this ? 0 : 501 this._scrollerPaddingTop = this.scrollTarget === this ? 0 :
506 parseInt(window.getComputedStyle(this)['padding-top'], 10); 502 parseInt(window.getComputedStyle(this)['padding-top'], 10);
503 this._viewportWidth = this.$.items.offsetWidth;
504 this._viewportHeight = this._scrollTargetHeight;
505 this.grid && this._updateGridMetrics();
506 },
507 507
508 this._viewportHeight = this._scrollTargetHeight; 508 /**
509 if (this.grid) { 509 * Recycles the physical items when needed.
510 this._updateGridMetrics(); 510 */
511 _scrollHandler: function() {
512 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop)) ;
513 var delta = scrollTop - this._scrollPosition;
514 var isScrollingDown = delta >= 0;
515 // Track the current scroll position.
516 this._scrollPosition = scrollTop;
517 // Clear indexes.
518 this._firstVisibleIndexVal = null;
519 this._lastVisibleIndexVal = null;
520
521 // Random access.
522 if (Math.abs(delta) > this._physicalSize) {
523 var idxAdjustment = Math.round(delta / this._physicalAverage) * this._i temsPerRow
524 this._physicalTop = this._physicalTop + delta;
525 this._virtualStart = this._virtualStart + idxAdjustment;
526 this._physicalStart = this._physicalStart + idxAdjustment;
527 this._update();
528 } else {
529 var reusables = this._getReusables(isScrollingDown);
530 if (isScrollingDown) {
531 this._physicalTop = reusables.physicalTop;
532 this._virtualStart = this._virtualStart + reusables.indexes.length;
533 this._physicalStart = this._physicalStart + reusables.indexes.length;
534 } else {
535 this._virtualStart = this._virtualStart - reusables.indexes.length;
536 this._physicalStart = this._physicalStart - reusables.indexes.length;
537 }
538 if (reusables.indexes.length === 0) {
539 this._increasePoolIfNeeded();
540 } else {
541 this._update(reusables.indexes, isScrollingDown ? null : reusables.ind exes);
542 }
511 } 543 }
512 }, 544 },
513 545
514 /** 546 /**
515 * Update the models, the position of the 547 * Returns an object that contains the indexes of the physical items
516 * items in the viewport and recycle tiles as needed. 548 * that might be reused and the physicalTop.
549 *
550 * @param {boolean} fromTop If the potential reusable items are above the sc rolling region.
517 */ 551 */
518 _scrollHandler: function() { 552 _getReusables: function(fromTop) {
519 // clamp the `scrollTop` value 553 var ith, lastIth, offsetContent, physicalItemHeight;
520 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop)) ; 554 var idxs = [];
521 var delta = scrollTop - this._scrollPosition; 555 var protectedOffsetContent = this._hiddenContentSize * this._ratio;
522 var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBotto m; 556 var virtualStart = this._virtualStart;
523 var ratio = this._ratio; 557 var virtualEnd = this._virtualEnd;
524 var recycledTiles = 0; 558 var physicalCount = this._physicalCount;
525 var hiddenContentSize = this._hiddenContentSize; 559 var physicalTop = this._physicalTop;
526 var currentRatio = ratio; 560 var scrollTop = this._scrollTop;
527 var movingUp = []; 561 var scrollBottom = this._scrollBottom;
528 562
529 // track the last `scrollTop` 563 if (fromTop) {
530 this._scrollPosition = scrollTop; 564 ith = this._physicalStart;
531 565 lastIth = this._physicalEnd;
532 // clear cached visible indexes 566 offsetContent = scrollTop - physicalTop;
533 this._firstVisibleIndexVal = null; 567 } else {
534 this._lastVisibleIndexVal = null; 568 ith = this._physicalEnd;
535 569 lastIth = this._physicalStart;
536 scrollBottom = this._scrollBottom; 570 offsetContent = this._physicalBottom - scrollBottom;
537 physicalBottom = this._physicalBottom;
538
539 // random access
540 if (Math.abs(delta) > this._physicalSize) {
541 this._physicalTop += delta;
542 recycledTiles = Math.round(delta / this._physicalAverage);
543 } 571 }
544 // scroll up 572 while (true) {
545 else if (delta < 0) { 573 physicalItemHeight = this._getPhysicalSizeIncrement(ith);
546 var topSpace = scrollTop - this._physicalTop; 574 offsetContent = offsetContent - physicalItemHeight;
547 var virtualStart = this._virtualStart; 575 if (idxs.length >= physicalCount || offsetContent <= protectedOffsetCont ent) {
548 576 break;
549 recycledTileSet = [];
550
551 kth = this._physicalEnd;
552 currentRatio = topSpace / hiddenContentSize;
553
554 // move tiles from bottom to top
555 while (
556 // approximate `currentRatio` to `ratio`
557 currentRatio < ratio &&
558 // recycle less physical items than the total
559 recycledTiles < this._physicalCount &&
560 // ensure that these recycled tiles are needed
561 virtualStart - recycledTiles > 0 &&
562 // ensure that the tile is not visible
563 physicalBottom - this._getPhysicalSizeIncrement(kth) > scrollBottom
564 ) {
565
566 tileHeight = this._getPhysicalSizeIncrement(kth);
567 currentRatio += tileHeight / hiddenContentSize;
568 physicalBottom -= tileHeight;
569 recycledTileSet.push(kth);
570 recycledTiles++;
571 kth = (kth === 0) ? this._physicalCount - 1 : kth - 1;
572 } 577 }
573 578 if (fromTop) {
574 movingUp = recycledTileSet; 579 // Check that index is within the valid range.
575 recycledTiles = -recycledTiles; 580 if (virtualEnd + idxs.length + 1 >= this._virtualCount) {
576 } 581 break;
577 // scroll down 582 }
578 else if (delta > 0) { 583 // Check that the index is not visible.
579 var bottomSpace = physicalBottom - scrollBottom; 584 if (physicalTop + physicalItemHeight >= scrollTop) {
580 var virtualEnd = this._virtualEnd; 585 break;
581 var lastVirtualItemIndex = this._virtualCount-1; 586 }
582 587 idxs.push(ith);
583 recycledTileSet = []; 588 physicalTop = physicalTop + physicalItemHeight;
584 589 ith = (ith + 1) % physicalCount;
585 kth = this._physicalStart; 590 } else {
586 currentRatio = bottomSpace / hiddenContentSize; 591 // Check that index is within the valid range.
587 592 if (virtualStart - idxs.length <= 0) {
588 // move tiles from top to bottom 593 break;
589 while ( 594 }
590 // approximate `currentRatio` to `ratio` 595 // Check that the index is not visible.
591 currentRatio < ratio && 596 if (physicalTop + this._physicalSize - physicalItemHeight <= scrollBot tom) {
592 // recycle less physical items than the total 597 break;
593 recycledTiles < this._physicalCount && 598 }
594 // ensure that these recycled tiles are needed 599 idxs.push(ith);
595 virtualEnd + recycledTiles < lastVirtualItemIndex && 600 physicalTop = physicalTop - physicalItemHeight;
596 // ensure that the tile is not visible 601 ith = (ith === 0) ? physicalCount - 1 : ith - 1;
597 this._physicalTop + this._getPhysicalSizeIncrement(kth) < scrollTop
598 ) {
599
600 tileHeight = this._getPhysicalSizeIncrement(kth);
601 currentRatio += tileHeight / hiddenContentSize;
602
603 this._physicalTop += tileHeight;
604 recycledTileSet.push(kth);
605 recycledTiles++;
606 kth = (kth + 1) % this._physicalCount;
607 } 602 }
608 } 603 }
609 604 return { indexes: idxs, physicalTop: physicalTop };
610 if (recycledTiles === 0) {
611 // Try to increase the pool if the list's client isn't filled up with ph ysical items
612 if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
613 this._increasePoolIfNeeded();
614 }
615 } else {
616 this._virtualStart = this._virtualStart + recycledTiles;
617 this._physicalStart = this._physicalStart + recycledTiles;
618 this._update(recycledTileSet, movingUp);
619 }
620 }, 605 },
621 606
622 /** 607 /**
623 * Update the list of items, starting from the `_virtualStart` item. 608 * Update the list of items, starting from the `_virtualStart` item.
624 * @param {!Array<number>=} itemSet 609 * @param {!Array<number>=} itemSet
625 * @param {!Array<number>=} movingUp 610 * @param {!Array<number>=} movingUp
626 */ 611 */
627 _update: function(itemSet, movingUp) { 612 _update: function(itemSet, movingUp) {
613 if (itemSet && itemSet.length === 0) {
614 return;
615 }
628 this._manageFocus(); 616 this._manageFocus();
629 this._assignModels(itemSet); 617 this._assignModels(itemSet);
630 this._updateMetrics(itemSet); 618 this._updateMetrics(itemSet);
631 // Adjust offset after measuring. 619 // Adjust offset after measuring.
632 if (movingUp) { 620 if (movingUp) {
633 while (movingUp.length) { 621 while (movingUp.length) {
634 var idx = movingUp.pop(); 622 var idx = movingUp.pop();
635 this._physicalTop -= this._getPhysicalSizeIncrement(idx); 623 this._physicalTop -= this._getPhysicalSizeIncrement(idx);
636 } 624 }
637 } 625 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 if (this._physicalStart > this._physicalEnd && 717 if (this._physicalStart > this._physicalEnd &&
730 this._isIndexRendered(this._focusedIndex) && 718 this._isIndexRendered(this._focusedIndex) &&
731 this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) { 719 this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
732 this._physicalStart = this._physicalStart + delta; 720 this._physicalStart = this._physicalStart + delta;
733 } 721 }
734 this._update(); 722 this._update();
735 this._templateCost = (window.performance.now() - ts) / delta; 723 this._templateCost = (window.performance.now() - ts) / delta;
736 }, 724 },
737 725
738 /** 726 /**
739 * Render a new list of items. 727 * Renders the a new list.
740 */ 728 */
741 _render: function() { 729 _render: function() {
742 if (this.isAttached && this._isVisible) { 730 if (this.isAttached && this._isVisible) {
743 if (this._physicalCount === 0) { 731 if (this._physicalCount === 0) {
732 this.updateViewportBoundaries();
744 this._increasePool(DEFAULT_PHYSICAL_COUNT); 733 this._increasePool(DEFAULT_PHYSICAL_COUNT);
745 } else { 734 } else {
735 // Try to recycle nodes
736 var reusables = this._getReusables(true);
737 this._physicalTop = reusables.physicalTop;
738 this._virtualStart = this._virtualStart + reusables.indexes.length;
739 this._physicalStart = this._physicalStart + reusables.indexes.length;
740 this._update(reusables.indexes);
746 this._update(); 741 this._update();
747 } 742 }
748 } 743 }
749 }, 744 },
750 745
751 /** 746 /**
752 * Templetizes the user template. 747 * Templetizes the user template.
753 */ 748 */
754 _ensureTemplatized: function() { 749 _ensureTemplatized: function() {
755 if (!this.ctor) { 750 if (!this.ctor) {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
871 this._physicalItems = this._physicalItems || []; 866 this._physicalItems = this._physicalItems || [];
872 this._physicalSizes = this._physicalSizes || []; 867 this._physicalSizes = this._physicalSizes || [];
873 this._physicalStart = 0; 868 this._physicalStart = 0;
874 this._resetScrollPosition(0); 869 this._resetScrollPosition(0);
875 this._removeFocusedItem(); 870 this._removeFocusedItem();
876 this._debounceTemplate(this._render); 871 this._debounceTemplate(this._render);
877 872
878 } else if (change.path === 'items.splices') { 873 } else if (change.path === 'items.splices') {
879 this._adjustVirtualIndex(change.value.indexSplices); 874 this._adjustVirtualIndex(change.value.indexSplices);
880 this._virtualCount = this.items ? this.items.length : 0; 875 this._virtualCount = this.items ? this.items.length : 0;
876
881 this._debounceTemplate(this._render); 877 this._debounceTemplate(this._render);
882 878
883 } else { 879 } else {
884 this._forwardItemPath(change.path.split('.').slice(1).join('.'), change. value); 880 this._forwardItemPath(change.path.split('.').slice(1).join('.'), change. value);
885 } 881 }
886 }, 882 },
887 883
888 /** 884 /**
889 * @param {!Array<!PolymerSplice>} splices 885 * @param {!Array<!PolymerSplice>} splices
890 */ 886 */
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
965 961
966 /** 962 /**
967 * Assigns the data models to a given set of items. 963 * Assigns the data models to a given set of items.
968 * @param {!Array<number>=} itemSet 964 * @param {!Array<number>=} itemSet
969 */ 965 */
970 _assignModels: function(itemSet) { 966 _assignModels: function(itemSet) {
971 this._iterateItems(function(pidx, vidx) { 967 this._iterateItems(function(pidx, vidx) {
972 var el = this._physicalItems[pidx]; 968 var el = this._physicalItems[pidx];
973 var inst = el._templateInstance; 969 var inst = el._templateInstance;
974 var item = this.items && this.items[vidx]; 970 var item = this.items && this.items[vidx];
975
976 if (item != null) { 971 if (item != null) {
977 inst[this.as] = item; 972 inst[this.as] = item;
978 inst.__key__ = this._collection.getKey(item); 973 inst.__key__ = this._collection.getKey(item);
979 inst[this.selectedAs] = /** @type {!ArraySelectorElement} */ (this.$.s elector).isSelected(item); 974 inst[this.selectedAs] = /** @type {!ArraySelectorElement} */ (this.$.s elector).isSelected(item);
980 inst[this.indexAs] = vidx; 975 inst[this.indexAs] = vidx;
981 inst.tabIndex = this._focusedIndex === vidx ? 0 : -1; 976 inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
982 this._physicalIndexForKey[inst.__key__] = pidx; 977 this._physicalIndexForKey[inst.__key__] = pidx;
983 el.removeAttribute('hidden'); 978 el.removeAttribute('hidden');
984 } else { 979 } else {
985 inst.__key__ = null; 980 inst.__key__ = null;
(...skipping 11 matching lines...) Expand all
997 // Make sure we distributed all the physical items 992 // Make sure we distributed all the physical items
998 // so we can measure them. 993 // so we can measure them.
999 Polymer.dom.flush(); 994 Polymer.dom.flush();
1000 995
1001 var newPhysicalSize = 0; 996 var newPhysicalSize = 0;
1002 var oldPhysicalSize = 0; 997 var oldPhysicalSize = 0;
1003 var prevAvgCount = this._physicalAverageCount; 998 var prevAvgCount = this._physicalAverageCount;
1004 var prevPhysicalAvg = this._physicalAverage; 999 var prevPhysicalAvg = this._physicalAverage;
1005 1000
1006 this._iterateItems(function(pidx, vidx) { 1001 this._iterateItems(function(pidx, vidx) {
1007
1008 oldPhysicalSize += this._physicalSizes[pidx] || 0; 1002 oldPhysicalSize += this._physicalSizes[pidx] || 0;
1009 this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight; 1003 this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight;
1010 newPhysicalSize += this._physicalSizes[pidx]; 1004 newPhysicalSize += this._physicalSizes[pidx];
1011 this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0; 1005 this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0;
1012
1013 }, itemSet); 1006 }, itemSet);
1014 1007
1015 this._viewportHeight = this._scrollTargetHeight;
1016 if (this.grid) { 1008 if (this.grid) {
1017 this._updateGridMetrics(); 1009 this._updateGridMetrics();
1018 this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight; 1010 this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight;
1019 } else { 1011 } else {
1020 this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalS ize; 1012 this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalS ize;
1021 } 1013 }
1022
1023 // Update the average if it measured something. 1014 // Update the average if it measured something.
1024 if (this._physicalAverageCount !== prevAvgCount) { 1015 if (this._physicalAverageCount !== prevAvgCount) {
1025 this._physicalAverage = Math.round( 1016 this._physicalAverage = Math.round(
1026 ((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) / 1017 ((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) /
1027 this._physicalAverageCount); 1018 this._physicalAverageCount);
1028 } 1019 }
1029 }, 1020 },
1030 1021
1031 _updateGridMetrics: function() { 1022 _updateGridMetrics: function() {
1032 this._viewportWidth = this.$.items.offsetWidth; 1023 this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoun dingClientRect().width : 200;
1033 // Set item width to the value of the _physicalItems offsetWidth 1024 this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetH eight : 200;
1034 this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoun dingClientRect().width : DEFAULT_GRID_SIZE;
1035 // Set row height to the value of the _physicalItems offsetHeight
1036 this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetH eight : DEFAULT_GRID_SIZE;
1037 // If in grid mode compute how many items with exist in each row
1038 this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / thi s._itemWidth) : this._itemsPerRow; 1025 this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / thi s._itemWidth) : this._itemsPerRow;
1039 }, 1026 },
1040 1027
1041 /** 1028 /**
1042 * Updates the position of the physical items. 1029 * Updates the position of the physical items.
1043 */ 1030 */
1044 _positionItems: function() { 1031 _positionItems: function() {
1045 this._adjustScrollPosition(); 1032 this._adjustScrollPosition();
1046 1033
1047 var y = this._physicalTop; 1034 var y = this._physicalTop;
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1212 // iOS fires the resize event when the address bar slides up 1199 // iOS fires the resize event when the address bar slides up
1213 if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100 ) { 1200 if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100 ) {
1214 return; 1201 return;
1215 } 1202 }
1216 // In Desktop Safari 9.0.3, if the scroll bars are always shown, 1203 // In Desktop Safari 9.0.3, if the scroll bars are always shown,
1217 // changing the scroll position from a resize handler would result in 1204 // changing the scroll position from a resize handler would result in
1218 // the scroll position being reset. Waiting 1ms fixes the issue. 1205 // the scroll position being reset. Waiting 1ms fixes the issue.
1219 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() { 1206 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() {
1220 this.updateViewportBoundaries(); 1207 this.updateViewportBoundaries();
1221 this._render(); 1208 this._render();
1222 1209 if (this._isVisible) {
1223 if (this._physicalCount > 0 && this._isVisible) { 1210 this.toggleScrollListener(true);
1224 this._resetAverage(); 1211 if (this._physicalCount > 0) {
1225 this.scrollToIndex(this.firstVisibleIndex); 1212 this._resetAverage();
1213 this.scrollToIndex(this.firstVisibleIndex);
1214 }
1215 } else {
1216 this.toggleScrollListener(false);
1226 } 1217 }
1227 }.bind(this), 1)); 1218 }.bind(this), 1));
1228 }, 1219 },
1229 1220
1230 _getModelFromItem: function(item) { 1221 _getModelFromItem: function(item) {
1231 var key = this._collection.getKey(item); 1222 var key = this._collection.getKey(item);
1232 var pidx = this._physicalIndexForKey[key]; 1223 var pidx = this._physicalIndexForKey[key];
1233 1224
1234 if (pidx != null) { 1225 if (pidx != null) {
1235 return this._physicalItems[pidx]._templateInstance; 1226 return this._physicalItems[pidx]._templateInstance;
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1358 if (target.localName === 'input' || 1349 if (target.localName === 'input' ||
1359 target.localName === 'button' || 1350 target.localName === 'button' ||
1360 target.localName === 'select') { 1351 target.localName === 'select') {
1361 return; 1352 return;
1362 } 1353 }
1363 // Set a temporary tabindex 1354 // Set a temporary tabindex
1364 modelTabIndex = model.tabIndex; 1355 modelTabIndex = model.tabIndex;
1365 model.tabIndex = SECRET_TABINDEX; 1356 model.tabIndex = SECRET_TABINDEX;
1366 activeElTabIndex = activeEl ? activeEl.tabIndex : -1; 1357 activeElTabIndex = activeEl ? activeEl.tabIndex : -1;
1367 model.tabIndex = modelTabIndex; 1358 model.tabIndex = modelTabIndex;
1368
1369 // Only select the item if the tap wasn't on a focusable child 1359 // Only select the item if the tap wasn't on a focusable child
1370 // or the element bound to `tabIndex` 1360 // or the element bound to `tabIndex`
1371 if (activeEl && physicalItem !== activeEl && physicalItem.contains(activeE l) && activeElTabIndex !== SECRET_TABINDEX) { 1361 if (activeEl && physicalItem !== activeEl && physicalItem.contains(activeE l) && activeElTabIndex !== SECRET_TABINDEX) {
1372 return; 1362 return;
1373 } 1363 }
1374 this.toggleSelectionForItem(model[this.as]); 1364 this.toggleSelectionForItem(model[this.as]);
1375 }, 1365 },
1376 1366
1377 _multiSelectionChanged: function(multiSelection) { 1367 _multiSelectionChanged: function(multiSelection) {
1378 this.clearSelection(); 1368 this.clearSelection();
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1439 } 1429 }
1440 this._restoreFocusedItem(); 1430 this._restoreFocusedItem();
1441 // scroll to index to make sure it's rendered 1431 // scroll to index to make sure it's rendered
1442 if (!this._isIndexRendered(idx)) { 1432 if (!this._isIndexRendered(idx)) {
1443 this.scrollToIndex(idx); 1433 this.scrollToIndex(idx);
1444 } 1434 }
1445 1435
1446 var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)]; 1436 var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
1447 var model = physicalItem._templateInstance; 1437 var model = physicalItem._templateInstance;
1448 var focusable; 1438 var focusable;
1449
1450 // set a secret tab index 1439 // set a secret tab index
1451 model.tabIndex = SECRET_TABINDEX; 1440 model.tabIndex = SECRET_TABINDEX;
1452 // check if focusable element is the physical item 1441 // check if focusable element is the physical item
1453 if (physicalItem.tabIndex === SECRET_TABINDEX) { 1442 if (physicalItem.tabIndex === SECRET_TABINDEX) {
1454 focusable = physicalItem; 1443 focusable = physicalItem;
1455 } 1444 }
1456 // search for the element which tabindex is bound to the secret tab index 1445 // search for the element which tabindex is bound to the secret tab index
1457 if (!focusable) { 1446 if (!focusable) {
1458 focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECR ET_TABINDEX + '"]'); 1447 focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECR ET_TABINDEX + '"]');
1459 } 1448 }
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1561 this._focusPhysicalItem(this._focusedIndex + 1); 1550 this._focusPhysicalItem(this._focusedIndex + 1);
1562 }, 1551 },
1563 1552
1564 _didEnter: function(e) { 1553 _didEnter: function(e) {
1565 this._focusPhysicalItem(this._focusedIndex); 1554 this._focusPhysicalItem(this._focusedIndex);
1566 this._selectionHandler(e.detail.keyboardEvent); 1555 this._selectionHandler(e.detail.keyboardEvent);
1567 } 1556 }
1568 }); 1557 });
1569 1558
1570 })(); 1559 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698