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

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

Issue 2751523005: MD Settings: bump iron-list version. (Closed)
Patch Set: Created 3 years, 9 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 ITEM_WIDTH = 0; 7 var ITEM_WIDTH = 0;
8 var ITEM_HEIGHT = 1; 8 var ITEM_HEIGHT = 1;
9 var SECRET_TABINDEX = -100; 9 var SECRET_TABINDEX = -100;
10 10
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 }, 105 },
106 106
107 /** 107 /**
108 * When `true`, multiple items may be selected at once (in this case, 108 * When `true`, multiple items may be selected at once (in this case,
109 * `selected` is an array of currently selected items). When `false`, 109 * `selected` is an array of currently selected items). When `false`,
110 * only one item may be selected at a time. 110 * only one item may be selected at a time.
111 */ 111 */
112 multiSelection: { 112 multiSelection: {
113 type: Boolean, 113 type: Boolean,
114 value: false 114 value: false
115 },
116
117 /**
118 * The offset top from the scrolling element to the iron-list element.
119 * This value can be computed using the position returned by `getBoundingC lientRect()`
120 * although it's preferred to use a constant value when possible.
121 *
122 * This property is useful when an external scrolling element is used and there's
123 * some offset between the scrolling element and the list.
124 * For example: a header is placed above the list.
125 */
126 scrollOffset: {
127 type: Number,
128 value: 0
115 } 129 }
116 }, 130 },
117 131
118 observers: [ 132 observers: [
119 '_itemsChanged(items.*)', 133 '_itemsChanged(items.*)',
120 '_selectionEnabledChanged(selectionEnabled)', 134 '_selectionEnabledChanged(selectionEnabled)',
121 '_multiSelectionChanged(multiSelection)', 135 '_multiSelectionChanged(multiSelection)',
122 '_setOverflow(scrollTarget)' 136 '_setOverflow(scrollTarget, scrollOffset)'
123 ], 137 ],
124 138
125 behaviors: [ 139 behaviors: [
126 Polymer.Templatizer, 140 Polymer.Templatizer,
127 Polymer.IronResizableBehavior, 141 Polymer.IronResizableBehavior,
128 Polymer.IronA11yKeysBehavior, 142 Polymer.IronA11yKeysBehavior,
129 Polymer.IronScrollTargetBehavior 143 Polymer.IronScrollTargetBehavior
130 ], 144 ],
131 145
132 keyBindings: { 146 keyBindings: {
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 318
305 /** 319 /**
306 * The height of the physical content that isn't on the screen. 320 * The height of the physical content that isn't on the screen.
307 */ 321 */
308 get _hiddenContentSize() { 322 get _hiddenContentSize() {
309 var size = this.grid ? this._physicalRows * this._rowHeight : this._physic alSize; 323 var size = this.grid ? this._physicalRows * this._rowHeight : this._physic alSize;
310 return size - this._viewportHeight; 324 return size - this._viewportHeight;
311 }, 325 },
312 326
313 /** 327 /**
328 * The parent node for the _userTemplate.
329 */
330 get _itemsParent() {
331 return Polymer.dom(Polymer.dom(this._userTemplate).parentNode);
332 },
333
334 /**
314 * The maximum scroll top value. 335 * The maximum scroll top value.
315 */ 336 */
316 get _maxScrollTop() { 337 get _maxScrollTop() {
317 return this._estScrollHeight - this._viewportHeight + this._scrollerPaddin gTop; 338 return this._estScrollHeight - this._viewportHeight + this._scrollOffset;
318 }, 339 },
319 340
320 /** 341 /**
321 * The lowest n-th value for an item such that it can be rendered in `_physi calStart`. 342 * The lowest n-th value for an item such that it can be rendered in `_physi calStart`.
322 */ 343 */
323 _minVirtualStart: 0, 344 _minVirtualStart: 0,
324 345
325 /** 346 /**
326 * The largest n-th value for an item such that it can be rendered in `_phys icalStart`. 347 * The largest n-th value for an item such that it can be rendered in `_phys icalStart`.
327 */ 348 */
328 get _maxVirtualStart() { 349 get _maxVirtualStart() {
329 return Math.max(0, this._virtualCount - this._physicalCount); 350 return Math.max(0, this._virtualCount - this._physicalCount);
330 }, 351 },
331 352
332 /** 353 /**
333 * The n-th item rendered in the `_physicalStart` tile. 354 * The n-th item rendered in the `_physicalStart` tile.
334 */ 355 */
335 _virtualStartVal: 0, 356 _virtualStartVal: 0,
336 357
337 set _virtualStart(val) { 358 set _virtualStart(val) {
338 this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._min VirtualStart, val)); 359 val = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val) );
360 if (this.grid) {
361 val = val - (val % this._itemsPerRow);
362 }
363 this._virtualStartVal = val;
339 }, 364 },
340 365
341 get _virtualStart() { 366 get _virtualStart() {
342 return this._virtualStartVal || 0; 367 return this._virtualStartVal || 0;
343 }, 368 },
344 369
345 /** 370 /**
346 * The k-th tile that is at the top of the scrolling list. 371 * The k-th tile that is at the top of the scrolling list.
347 */ 372 */
348 _physicalStartVal: 0, 373 _physicalStartVal: 0,
349 374
350 set _physicalStart(val) { 375 set _physicalStart(val) {
351 this._physicalStartVal = val % this._physicalCount; 376 val = val % this._physicalCount;
352 if (this._physicalStartVal < 0) { 377 if (val < 0) {
353 this._physicalStartVal = this._physicalCount + this._physicalStartVal; 378 val = this._physicalCount + val;
354 } 379 }
380 if (this.grid) {
381 val = val - (val % this._itemsPerRow);
382 }
383 this._physicalStartVal = val;
355 this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this ._physicalCount; 384 this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this ._physicalCount;
356 }, 385 },
357 386
358 get _physicalStart() { 387 get _physicalStart() {
359 return this._physicalStartVal || 0; 388 return this._physicalStartVal || 0;
360 }, 389 },
361 390
362 /** 391 /**
363 * The number of tiles in the DOM. 392 * The number of tiles in the DOM.
364 */ 393 */
(...skipping 17 matching lines...) Expand all
382 * An optimal physical size such that we will have enough physical items 411 * An optimal physical size such that we will have enough physical items
383 * to fill up the viewport and recycle when the user scrolls. 412 * to fill up the viewport and recycle when the user scrolls.
384 * 413 *
385 * This default value assumes that we will at least have the equivalent 414 * This default value assumes that we will at least have the equivalent
386 * to a viewport of physical items above and below the user's viewport. 415 * to a viewport of physical items above and below the user's viewport.
387 */ 416 */
388 get _optPhysicalSize() { 417 get _optPhysicalSize() {
389 if (this.grid) { 418 if (this.grid) {
390 return this._estRowsInView * this._rowHeight * this._maxPages; 419 return this._estRowsInView * this._rowHeight * this._maxPages;
391 } 420 }
392 return this._viewportHeight * this._maxPages; 421 return this._viewportHeight === 0 ? Infinity : this._viewportHeight * this ._maxPages;
393 }, 422 },
394 423
395 /** 424 /**
396 * True if the current list is visible. 425 * True if the current list is visible.
397 */ 426 */
398 get _isVisible() { 427 get _isVisible() {
399 return Boolean(this.offsetWidth || this.offsetHeight); 428 return Boolean(this.offsetWidth || this.offsetHeight);
400 }, 429 },
401 430
402 /** 431 /**
403 * Gets the index of the first visible item in the viewport. 432 * Gets the index of the first visible item in the viewport.
404 * 433 *
405 * @type {number} 434 * @type {number}
406 */ 435 */
407 get firstVisibleIndex() { 436 get firstVisibleIndex() {
408 if (this._firstVisibleIndexVal === null) { 437 var idx = this._firstVisibleIndexVal;
409 var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddin gTop); 438 if (idx == null) {
439 var physicalOffset = this._physicalTop + this._scrollOffset;
410 440
411 this._firstVisibleIndexVal = this._iterateItems( 441 idx = this._iterateItems(function(pidx, vidx) {
412 function(pidx, vidx) { 442 physicalOffset += this._getPhysicalSizeIncrement(pidx);
413 physicalOffset += this._getPhysicalSizeIncrement(pidx);
414 443
415 if (physicalOffset > this._scrollPosition) { 444 if (physicalOffset > this._scrollPosition) {
416 return this.grid ? vidx - (vidx % this._itemsPerRow) : vidx; 445 return this.grid ? vidx - (vidx % this._itemsPerRow) : vidx;
417 } 446 }
418 // Handle a partially rendered final row in grid mode 447 // Handle a partially rendered final row in grid mode
419 if (this.grid && this._virtualCount - 1 === vidx) { 448 if (this.grid && this._virtualCount - 1 === vidx) {
420 return vidx - (vidx % this._itemsPerRow); 449 return vidx - (vidx % this._itemsPerRow);
421 } 450 }
422 }) || 0; 451 }) || 0;
452 this._firstVisibleIndexVal = idx;
423 } 453 }
424 return this._firstVisibleIndexVal; 454 return idx;
425 }, 455 },
426 456
427 /** 457 /**
428 * Gets the index of the last visible item in the viewport. 458 * Gets the index of the last visible item in the viewport.
429 * 459 *
430 * @type {number} 460 * @type {number}
431 */ 461 */
432 get lastVisibleIndex() { 462 get lastVisibleIndex() {
433 if (this._lastVisibleIndexVal === null) { 463 var idx = this._lastVisibleIndexVal;
464 if (idx == null) {
434 if (this.grid) { 465 if (this.grid) {
435 var lastIndex = this.firstVisibleIndex + this._estRowsInView * this._i temsPerRow - 1; 466 idx = Math.min(this._virtualCount,
436 this._lastVisibleIndexVal = Math.min(this._virtualCount, lastIndex); 467 this.firstVisibleIndex + this._estRowsInView * this._itemsPerRow - 1);
437 } else { 468 } else {
438 var physicalOffset = this._physicalTop; 469 var physicalOffset = this._physicalTop + this._scrollOffset;
439 this._iterateItems(function(pidx, vidx) { 470 this._iterateItems(function(pidx, vidx) {
440 if (physicalOffset < this._scrollBottom) { 471 if (physicalOffset < this._scrollBottom) {
441 this._lastVisibleIndexVal = vidx; 472 idx = vidx;
442 } else {
443 // Break _iterateItems
444 return true;
445 } 473 }
446 physicalOffset += this._getPhysicalSizeIncrement(pidx); 474 physicalOffset += this._getPhysicalSizeIncrement(pidx);
447 }); 475 });
448 } 476 }
477 this._lastVisibleIndexVal = idx;
449 } 478 }
450 return this._lastVisibleIndexVal; 479 return idx;
451 }, 480 },
452 481
453 get _defaultScrollTarget() { 482 get _defaultScrollTarget() {
454 return this; 483 return this;
455 }, 484 },
456 485
457 get _virtualRowCount() { 486 get _virtualRowCount() {
458 return Math.ceil(this._virtualCount / this._itemsPerRow); 487 return Math.ceil(this._virtualCount / this._itemsPerRow);
459 }, 488 },
460 489
461 get _estRowsInView() { 490 get _estRowsInView() {
462 return Math.ceil(this._viewportHeight / this._rowHeight); 491 return Math.ceil(this._viewportHeight / this._rowHeight);
463 }, 492 },
464 493
465 get _physicalRows() { 494 get _physicalRows() {
466 return Math.ceil(this._physicalCount / this._itemsPerRow); 495 return Math.ceil(this._physicalCount / this._itemsPerRow);
467 }, 496 },
468 497
498 get _scrollOffset() {
499 return this._scrollerPaddingTop + this.scrollOffset;
500 },
501
469 ready: function() { 502 ready: function() {
470 this.addEventListener('focus', this._didFocus.bind(this), true); 503 this.addEventListener('focus', this._didFocus.bind(this), true);
471 }, 504 },
472 505
473 attached: function() { 506 attached: function() {
474 if (this._physicalCount === 0) { 507 if (this._physicalCount === 0) {
475 this._debounceTemplate(this._render); 508 this._debounceTemplate(this._render);
476 } 509 }
477 // `iron-resize` is fired when the list is attached if the event is added 510 // `iron-resize` is fired when the list is attached if the event is added
478 // before attached causing unnecessary work. 511 // before attached causing unnecessary work.
479 this.listen(this, 'iron-resize', '_resizeHandler'); 512 this.listen(this, 'iron-resize', '_resizeHandler');
480 }, 513 },
481 514
482 detached: function() { 515 detached: function() {
483 this.unlisten(this, 'iron-resize', '_resizeHandler'); 516 this.unlisten(this, 'iron-resize', '_resizeHandler');
484 }, 517 },
485 518
486 /** 519 /**
487 * Set the overflow property if this element has its own scrolling region 520 * Set the overflow property if this element has its own scrolling region
488 */ 521 */
489 _setOverflow: function(scrollTarget) { 522 _setOverflow: function(scrollTarget) {
490 this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : ''; 523 this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
491 this.style.overflow = scrollTarget === this ? 'auto' : ''; 524 this.style.overflow = scrollTarget === this ? 'auto' : '';
525 // Clear cache.
526 this._lastVisibleIndexVal = null;
527 this._firstVisibleIndexVal = null;
528 this._debounceTemplate(this._render);
492 }, 529 },
493 530
494 /** 531 /**
495 * Invoke this method if you dynamically update the viewport's 532 * Invoke this method if you dynamically update the viewport's
496 * size or CSS padding. 533 * size or CSS padding.
497 * 534 *
498 * @method updateViewportBoundaries 535 * @method updateViewportBoundaries
499 */ 536 */
500 updateViewportBoundaries: function() { 537 updateViewportBoundaries: function() {
538 var styles = window.getComputedStyle(this);
501 this._scrollerPaddingTop = this.scrollTarget === this ? 0 : 539 this._scrollerPaddingTop = this.scrollTarget === this ? 0 :
502 parseInt(window.getComputedStyle(this)['padding-top'], 10); 540 parseInt(styles['padding-top'], 10);
541 this._isRTL = Boolean(styles.direction === 'rtl');
503 this._viewportWidth = this.$.items.offsetWidth; 542 this._viewportWidth = this.$.items.offsetWidth;
504 this._viewportHeight = this._scrollTargetHeight; 543 this._viewportHeight = this._scrollTargetHeight;
505 this.grid && this._updateGridMetrics(); 544 this.grid && this._updateGridMetrics();
506 }, 545 },
507 546
508 /** 547 /**
509 * Recycles the physical items when needed. 548 * Recycles the physical items when needed.
510 */ 549 */
511 _scrollHandler: function() { 550 _scrollHandler: function() {
512 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop)) ; 551 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop)) ;
513 var delta = scrollTop - this._scrollPosition; 552 var delta = scrollTop - this._scrollPosition;
514 var isScrollingDown = delta >= 0; 553 var isScrollingDown = delta >= 0;
515 // Track the current scroll position. 554 // Track the current scroll position.
516 this._scrollPosition = scrollTop; 555 this._scrollPosition = scrollTop;
517 // Clear indexes. 556 // Clear indexes.
518 this._firstVisibleIndexVal = null; 557 this._firstVisibleIndexVal = null;
519 this._lastVisibleIndexVal = null; 558 this._lastVisibleIndexVal = null;
520 559
521 // Random access. 560 // Random access.
522 if (Math.abs(delta) > this._physicalSize) { 561 if (Math.abs(delta) > this._physicalSize) {
523 var idxAdjustment = Math.round(delta / this._physicalAverage) * this._i temsPerRow 562 delta = delta - this._scrollOffset;
563 var idxAdjustment = Math.round(delta / this._physicalAverage) * this._it emsPerRow;
524 this._physicalTop = this._physicalTop + delta; 564 this._physicalTop = this._physicalTop + delta;
525 this._virtualStart = this._virtualStart + idxAdjustment; 565 this._virtualStart = this._virtualStart + idxAdjustment;
526 this._physicalStart = this._physicalStart + idxAdjustment; 566 this._physicalStart = this._physicalStart + idxAdjustment;
527 this._update(); 567 this._update();
528 } else { 568 } else {
529 var reusables = this._getReusables(isScrollingDown); 569 var reusables = this._getReusables(isScrollingDown);
530 if (isScrollingDown) { 570 if (isScrollingDown) {
531 this._physicalTop = reusables.physicalTop; 571 this._physicalTop = reusables.physicalTop;
532 this._virtualStart = this._virtualStart + reusables.indexes.length; 572 this._virtualStart = this._virtualStart + reusables.indexes.length;
533 this._physicalStart = this._physicalStart + reusables.indexes.length; 573 this._physicalStart = this._physicalStart + reusables.indexes.length;
(...skipping 15 matching lines...) Expand all
549 * 589 *
550 * @param {boolean} fromTop If the potential reusable items are above the sc rolling region. 590 * @param {boolean} fromTop If the potential reusable items are above the sc rolling region.
551 */ 591 */
552 _getReusables: function(fromTop) { 592 _getReusables: function(fromTop) {
553 var ith, lastIth, offsetContent, physicalItemHeight; 593 var ith, lastIth, offsetContent, physicalItemHeight;
554 var idxs = []; 594 var idxs = [];
555 var protectedOffsetContent = this._hiddenContentSize * this._ratio; 595 var protectedOffsetContent = this._hiddenContentSize * this._ratio;
556 var virtualStart = this._virtualStart; 596 var virtualStart = this._virtualStart;
557 var virtualEnd = this._virtualEnd; 597 var virtualEnd = this._virtualEnd;
558 var physicalCount = this._physicalCount; 598 var physicalCount = this._physicalCount;
559 var physicalTop = this._physicalTop + this._scrollerPaddingTop; 599 var top = this._physicalTop + this._scrollOffset;
600 var bottom = this._physicalBottom + this._scrollOffset;
560 var scrollTop = this._scrollTop; 601 var scrollTop = this._scrollTop;
561 var scrollBottom = this._scrollBottom; 602 var scrollBottom = this._scrollBottom;
562 603
563 if (fromTop) { 604 if (fromTop) {
564 ith = this._physicalStart; 605 ith = this._physicalStart;
565 lastIth = this._physicalEnd; 606 lastIth = this._physicalEnd;
566 offsetContent = scrollTop - physicalTop; 607 offsetContent = scrollTop - top;
567 } else { 608 } else {
568 ith = this._physicalEnd; 609 ith = this._physicalEnd;
569 lastIth = this._physicalStart; 610 lastIth = this._physicalStart;
570 offsetContent = this._physicalBottom - scrollBottom; 611 offsetContent = bottom - scrollBottom;
571 } 612 }
572 while (true) { 613 while (true) {
573 physicalItemHeight = this._getPhysicalSizeIncrement(ith); 614 physicalItemHeight = this._getPhysicalSizeIncrement(ith);
574 offsetContent = offsetContent - physicalItemHeight; 615 offsetContent = offsetContent - physicalItemHeight;
575 if (idxs.length >= physicalCount || offsetContent <= protectedOffsetCont ent) { 616 if (idxs.length >= physicalCount || offsetContent <= protectedOffsetCont ent) {
576 break; 617 break;
577 } 618 }
578 if (fromTop) { 619 if (fromTop) {
579 // Check that index is within the valid range. 620 // Check that index is within the valid range.
580 if (virtualEnd + idxs.length + 1 >= this._virtualCount) { 621 if (virtualEnd + idxs.length + 1 >= this._virtualCount) {
581 break; 622 break;
582 } 623 }
583 // Check that the index is not visible. 624 // Check that the index is not visible.
584 if (physicalTop + physicalItemHeight >= scrollTop) { 625 if (top + physicalItemHeight >= scrollTop - this._scrollOffset) {
585 break; 626 break;
586 } 627 }
587 idxs.push(ith); 628 idxs.push(ith);
588 physicalTop = physicalTop + physicalItemHeight; 629 top = top + physicalItemHeight;
589 ith = (ith + 1) % physicalCount; 630 ith = (ith + 1) % physicalCount;
590 } else { 631 } else {
591 // Check that index is within the valid range. 632 // Check that index is within the valid range.
592 if (virtualStart - idxs.length <= 0) { 633 if (virtualStart - idxs.length <= 0) {
593 break; 634 break;
594 } 635 }
595 // Check that the index is not visible. 636 // Check that the index is not visible.
596 if (physicalTop + this._physicalSize - physicalItemHeight <= scrollBot tom) { 637 if (top + this._physicalSize - physicalItemHeight <= scrollBottom) {
597 break; 638 break;
598 } 639 }
599 idxs.push(ith); 640 idxs.push(ith);
600 physicalTop = physicalTop - physicalItemHeight; 641 top = top - physicalItemHeight;
601 ith = (ith === 0) ? physicalCount - 1 : ith - 1; 642 ith = (ith === 0) ? physicalCount - 1 : ith - 1;
602 } 643 }
603 } 644 }
604 return { indexes: idxs, physicalTop: physicalTop - this._scrollerPaddingTo p }; 645 return { indexes: idxs, physicalTop: top - this._scrollOffset };
605 }, 646 },
606 647
607 /** 648 /**
608 * Update the list of items, starting from the `_virtualStart` item. 649 * Update the list of items, starting from the `_virtualStart` item.
609 * @param {!Array<number>=} itemSet 650 * @param {!Array<number>=} itemSet
610 * @param {!Array<number>=} movingUp 651 * @param {!Array<number>=} movingUp
611 */ 652 */
612 _update: function(itemSet, movingUp) { 653 _update: function(itemSet, movingUp) {
613 if (itemSet && itemSet.length === 0) { 654 if (itemSet && itemSet.length === 0) {
614 return; 655 return;
(...skipping 21 matching lines...) Expand all
636 _createPool: function(size) { 677 _createPool: function(size) {
637 var physicalItems = new Array(size); 678 var physicalItems = new Array(size);
638 679
639 this._ensureTemplatized(); 680 this._ensureTemplatized();
640 681
641 for (var i = 0; i < size; i++) { 682 for (var i = 0; i < size; i++) {
642 var inst = this.stamp(null); 683 var inst = this.stamp(null);
643 // First element child is item; Safari doesn't support children[0] 684 // First element child is item; Safari doesn't support children[0]
644 // on a doc fragment. 685 // on a doc fragment.
645 physicalItems[i] = inst.root.querySelector('*'); 686 physicalItems[i] = inst.root.querySelector('*');
646 Polymer.dom(this).appendChild(inst.root); 687 this._itemsParent.appendChild(inst.root);
647 } 688 }
648 return physicalItems; 689 return physicalItems;
649 }, 690 },
650 691
651 /** 692 /**
652 * Increases the pool of physical items only if needed. 693 * Increases the pool of physical items only if needed.
653 * 694 *
654 * @return {boolean} True if the pool was increased. 695 * @return {boolean} True if the pool was increased.
655 */ 696 */
656 _increasePoolIfNeeded: function() { 697 _increasePoolIfNeeded: function() {
657 // Base case 1: the list has no height.
658 if (this._viewportHeight === 0) {
659 return false;
660 }
661 var self = this; 698 var self = this;
662 var isClientFull = this._physicalBottom >= this._scrollBottom && 699 var isClientFull = this._physicalBottom + this._scrollOffset >= this._scro llBottom &&
663 this._physicalTop <= this._scrollPosition; 700 this._physicalTop - this._scrollOffset <= this._scrollPosition;
664 701 // Base case 1: if the physical size is optimal and the list's client heig ht is full
665 // Base case 2: if the physical size is optimal and the list's client heig ht is full
666 // with physical items, don't increase the pool. 702 // with physical items, don't increase the pool.
667 if (this._physicalSize >= this._optPhysicalSize && isClientFull) { 703 if (this._physicalSize >= this._optPhysicalSize && isClientFull) {
668 return false; 704 return false;
669 } 705 }
670 var maxPoolSize = Math.round(this._physicalCount * 0.5); 706 var maxPoolSize = Math.round(this._physicalCount * 0.5);
671 // Increase the pool synchronously until the client is filled. 707 // Increase the pool synchronously until the client is filled.
672 if (!isClientFull) { 708 if (!isClientFull) {
673 this._debounceTemplate(this._increasePool.bind(this, maxPoolSize)); 709 this._debounceTemplate(this._increasePool.bind(this, maxPoolSize));
674 return true; 710 return true;
675 } 711 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 _ensureTemplatized: function() { 785 _ensureTemplatized: function() {
750 if (!this.ctor) { 786 if (!this.ctor) {
751 // Template instance props that should be excluded from forwarding 787 // Template instance props that should be excluded from forwarding
752 var props = {}; 788 var props = {};
753 props.__key__ = true; 789 props.__key__ = true;
754 props[this.as] = true; 790 props[this.as] = true;
755 props[this.indexAs] = true; 791 props[this.indexAs] = true;
756 props[this.selectedAs] = true; 792 props[this.selectedAs] = true;
757 props.tabIndex = true; 793 props.tabIndex = true;
758 this._instanceProps = props; 794 this._instanceProps = props;
759 this._userTemplate = Polymer.dom(this).querySelector('template'); 795 this._userTemplate = this.queryEffectiveChildren('template');
760 796
761 if (this._userTemplate) { 797 if (this._userTemplate) {
762 this.templatize(this._userTemplate); 798 this.templatize(this._userTemplate);
763 } else { 799 } else {
764 console.warn('iron-list requires a template to be provided in light-do m'); 800 console.warn('iron-list requires a template to be provided in light-do m');
765 } 801 }
766 } 802 }
767 }, 803 },
768 804
769 /** 805 /**
(...skipping 14 matching lines...) Expand all
784 path.slice(this.as.length + 1), value); 820 path.slice(this.as.length + 1), value);
785 } 821 }
786 }, 822 },
787 823
788 /** 824 /**
789 * Implements extension point from Templatizer mixin 825 * Implements extension point from Templatizer mixin
790 * Called as side-effect of a host property change, responsible for 826 * Called as side-effect of a host property change, responsible for
791 * notifying parent path change on each row. 827 * notifying parent path change on each row.
792 */ 828 */
793 _forwardParentProp: function(prop, value) { 829 _forwardParentProp: function(prop, value) {
794 if (this._physicalItems) { 830 (this._physicalItems || [])
795 this._physicalItems.forEach(function(item) { 831 .concat([this._offscreenFocusedItem, this._focusBackfillItem])
796 item._templateInstance[prop] = value; 832 .forEach(function(item) {
797 }, this); 833 if (item) {
798 } 834 item._templateInstance[prop] = value;
835 }
836 });
799 }, 837 },
800 838
801 /** 839 /**
802 * Implements extension point from Templatizer 840 * Implements extension point from Templatizer
803 * Called as side-effect of a host path change, responsible for 841 * Called as side-effect of a host path change, responsible for
804 * notifying parent.<path> path change on each row. 842 * notifying parent.<path> path change on each row.
805 */ 843 */
806 _forwardParentPath: function(path, value) { 844 _forwardParentPath: function(path, value) {
807 if (this._physicalItems) { 845 (this._physicalItems || [])
808 this._physicalItems.forEach(function(item) { 846 .concat([this._offscreenFocusedItem, this._focusBackfillItem])
809 item._templateInstance.notifyPath(path, value, true); 847 .forEach(function(item) {
810 }, this); 848 if (item) {
811 } 849 item._templateInstance.notifyPath(path, value, true);
850 }
851 });
812 }, 852 },
813 853
814 /** 854 /**
815 * Called as a side effect of a host items.<key>.<path> path change, 855 * Called as a side effect of a host items.<key>.<path> path change,
816 * responsible for notifying item.<path> changes. 856 * responsible for notifying item.<path> changes.
817 */ 857 */
818 _forwardItemPath: function(path, value) { 858 _forwardItemPath: function(path, value) {
819 if (!this._physicalIndexForKey) { 859 if (!this._physicalIndexForKey) {
820 return; 860 return;
821 } 861 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 this._physicalTop = 0; 899 this._physicalTop = 0;
860 this._virtualCount = this.items ? this.items.length : 0; 900 this._virtualCount = this.items ? this.items.length : 0;
861 this._collection = this.items ? Polymer.Collection.get(this.items) : nul l; 901 this._collection = this.items ? Polymer.Collection.get(this.items) : nul l;
862 this._physicalIndexForKey = {}; 902 this._physicalIndexForKey = {};
863 this._firstVisibleIndexVal = null; 903 this._firstVisibleIndexVal = null;
864 this._lastVisibleIndexVal = null; 904 this._lastVisibleIndexVal = null;
865 this._physicalCount = this._physicalCount || 0; 905 this._physicalCount = this._physicalCount || 0;
866 this._physicalItems = this._physicalItems || []; 906 this._physicalItems = this._physicalItems || [];
867 this._physicalSizes = this._physicalSizes || []; 907 this._physicalSizes = this._physicalSizes || [];
868 this._physicalStart = 0; 908 this._physicalStart = 0;
869 this._resetScrollPosition(0); 909 if (this._scrollTop > this._scrollOffset) {
910 this._resetScrollPosition(0);
911 }
870 this._removeFocusedItem(); 912 this._removeFocusedItem();
871 this._debounceTemplate(this._render); 913 this._debounceTemplate(this._render);
872 914
873 } else if (change.path === 'items.splices') { 915 } else if (change.path === 'items.splices') {
874 this._adjustVirtualIndex(change.value.indexSplices); 916 this._adjustVirtualIndex(change.value.indexSplices);
875 this._virtualCount = this.items ? this.items.length : 0; 917 this._virtualCount = this.items ? this.items.length : 0;
876 918
877 this._debounceTemplate(this._render); 919 this._debounceTemplate(this._render);
878
879 } else { 920 } else {
880 this._forwardItemPath(change.path.split('.').slice(1).join('.'), change. value); 921 this._forwardItemPath(change.path.split('.').slice(1).join('.'), change. value);
881 } 922 }
882 }, 923 },
883 924
884 /** 925 /**
885 * @param {!Array<!PolymerSplice>} splices 926 * @param {!Array<!PolymerSplice>} splices
886 */ 927 */
887 _adjustVirtualIndex: function(splices) { 928 _adjustVirtualIndex: function(splices) {
888 splices.forEach(function(splice) { 929 splices.forEach(function(splice) {
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1033 1074
1034 var y = this._physicalTop; 1075 var y = this._physicalTop;
1035 1076
1036 if (this.grid) { 1077 if (this.grid) {
1037 var totalItemWidth = this._itemsPerRow * this._itemWidth; 1078 var totalItemWidth = this._itemsPerRow * this._itemWidth;
1038 var rowOffset = (this._viewportWidth - totalItemWidth) / 2; 1079 var rowOffset = (this._viewportWidth - totalItemWidth) / 2;
1039 1080
1040 this._iterateItems(function(pidx, vidx) { 1081 this._iterateItems(function(pidx, vidx) {
1041 var modulus = vidx % this._itemsPerRow; 1082 var modulus = vidx % this._itemsPerRow;
1042 var x = Math.floor((modulus * this._itemWidth) + rowOffset); 1083 var x = Math.floor((modulus * this._itemWidth) + rowOffset);
1084 if (this._isRTL) {
1085 x = x * -1;
1086 }
1043 this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]); 1087 this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]);
1044 if (this._shouldRenderNextRow(vidx)) { 1088 if (this._shouldRenderNextRow(vidx)) {
1045 y += this._rowHeight; 1089 y += this._rowHeight;
1046 } 1090 }
1047 }); 1091 });
1048 } else { 1092 } else {
1049 this._iterateItems(function(pidx, vidx) { 1093 this._iterateItems(function(pidx, vidx) {
1050 this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]); 1094 this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
1051 y += this._physicalSizes[pidx]; 1095 y += this._physicalSizes[pidx];
1052 }); 1096 });
(...skipping 21 matching lines...) Expand all
1074 _shouldRenderNextRow: function(vidx) { 1118 _shouldRenderNextRow: function(vidx) {
1075 return vidx % this._itemsPerRow === this._itemsPerRow - 1; 1119 return vidx % this._itemsPerRow === this._itemsPerRow - 1;
1076 }, 1120 },
1077 1121
1078 /** 1122 /**
1079 * Adjusts the scroll position when it was overestimated. 1123 * Adjusts the scroll position when it was overestimated.
1080 */ 1124 */
1081 _adjustScrollPosition: function() { 1125 _adjustScrollPosition: function() {
1082 var deltaHeight = this._virtualStart === 0 ? this._physicalTop : 1126 var deltaHeight = this._virtualStart === 0 ? this._physicalTop :
1083 Math.min(this._scrollPosition + this._physicalTop, 0); 1127 Math.min(this._scrollPosition + this._physicalTop, 0);
1084 1128 // Note: the delta can be positive or negative.
1085 if (deltaHeight) { 1129 if (deltaHeight !== 0) {
1086 this._physicalTop = this._physicalTop - deltaHeight; 1130 this._physicalTop = this._physicalTop - deltaHeight;
1131 var scrollTop = this._scrollTop;
1087 // juking scroll position during interial scrolling on iOS is no bueno 1132 // juking scroll position during interial scrolling on iOS is no bueno
1088 if (!IOS_TOUCH_SCROLLING && this._physicalTop !== 0) { 1133 if (!IOS_TOUCH_SCROLLING && scrollTop > 0) {
1089 this._resetScrollPosition(this._scrollTop - deltaHeight); 1134 this._resetScrollPosition(scrollTop - deltaHeight);
1090 } 1135 }
1091 } 1136 }
1092 }, 1137 },
1093 1138
1094 /** 1139 /**
1095 * Sets the position of the scroll. 1140 * Sets the position of the scroll.
1096 */ 1141 */
1097 _resetScrollPosition: function(pos) { 1142 _resetScrollPosition: function(pos) {
1098 if (this.scrollTarget) { 1143 if (this.scrollTarget && pos >= 0) {
1099 this._scrollTop = pos; 1144 this._scrollTop = pos;
1100 this._scrollPosition = this._scrollTop; 1145 this._scrollPosition = this._scrollTop;
1101 } 1146 }
1102 }, 1147 },
1103 1148
1104 /** 1149 /**
1105 * Sets the scroll height, that's the height of the content, 1150 * Sets the scroll height, that's the height of the content,
1106 * 1151 *
1107 * @param {boolean=} forceUpdate If true, updates the height no matter what. 1152 * @param {boolean=} forceUpdate If true, updates the height no matter what.
1108 */ 1153 */
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1140 * Scroll to a specific index in the virtual list regardless 1185 * Scroll to a specific index in the virtual list regardless
1141 * of the physical items in the DOM tree. 1186 * of the physical items in the DOM tree.
1142 * 1187 *
1143 * @method scrollToIndex 1188 * @method scrollToIndex
1144 * @param {number} idx The index of the item 1189 * @param {number} idx The index of the item
1145 */ 1190 */
1146 scrollToIndex: function(idx) { 1191 scrollToIndex: function(idx) {
1147 if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) { 1192 if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) {
1148 return; 1193 return;
1149 } 1194 }
1150
1151 Polymer.dom.flush(); 1195 Polymer.dom.flush();
1152 // Items should have been rendered prior scrolling to an index. 1196 // Items should have been rendered prior scrolling to an index.
1153 if (this._physicalCount === 0) { 1197 if (this._physicalCount === 0) {
1154 return; 1198 return;
1155 } 1199 }
1156 idx = Math.min(Math.max(idx, 0), this._virtualCount-1); 1200 idx = Math.min(Math.max(idx, 0), this._virtualCount-1);
1157 // Update the virtual start only when needed. 1201 // Update the virtual start only when needed.
1158 if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) { 1202 if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
1159 this._virtualStart = this.grid ? (idx - this._itemsPerRow * 2) : (idx - 1); 1203 this._virtualStart = this.grid ? (idx - this._itemsPerRow * 2) : (idx - 1);
1160 } 1204 }
1161 this._manageFocus(); 1205 this._manageFocus();
1162 this._assignModels(); 1206 this._assignModels();
1163 this._updateMetrics(); 1207 this._updateMetrics();
1164 // Estimate new physical offset. 1208 // Estimate new physical offset.
1165 this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage; 1209 this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
1166 1210
1167 var currentTopItem = this._physicalStart; 1211 var currentTopItem = this._physicalStart;
1168 var currentVirtualItem = this._virtualStart; 1212 var currentVirtualItem = this._virtualStart;
1169 var targetOffsetTop = 0; 1213 var targetOffsetTop = 0;
1170 var hiddenContentSize = this._hiddenContentSize; 1214 var hiddenContentSize = this._hiddenContentSize;
1171 // scroll to the item as much as we can. 1215 // scroll to the item as much as we can.
1172 while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) { 1216 while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) {
1173 targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(curre ntTopItem); 1217 targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(curre ntTopItem);
1174 currentTopItem = (currentTopItem + 1) % this._physicalCount; 1218 currentTopItem = (currentTopItem + 1) % this._physicalCount;
1175 currentVirtualItem++; 1219 currentVirtualItem++;
1176 } 1220 }
1177 this._updateScrollerSize(true); 1221 this._updateScrollerSize(true);
1178 this._positionItems(); 1222 this._positionItems();
1179 this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + t argetOffsetTop); 1223 this._resetScrollPosition(this._physicalTop + this._scrollOffset + targetO ffsetTop);
1180 this._increasePoolIfNeeded(); 1224 this._increasePoolIfNeeded();
1181 // clear cached visible index. 1225 // clear cached visible index.
1182 this._firstVisibleIndexVal = null; 1226 this._firstVisibleIndexVal = null;
1183 this._lastVisibleIndexVal = null; 1227 this._lastVisibleIndexVal = null;
1184 }, 1228 },
1185 1229
1186 /** 1230 /**
1187 * Reset the physical average and the average count. 1231 * Reset the physical average and the average count.
1188 */ 1232 */
1189 _resetAverage: function() { 1233 _resetAverage: function() {
1190 this._physicalAverage = 0; 1234 this._physicalAverage = 0;
1191 this._physicalAverageCount = 0; 1235 this._physicalAverageCount = 0;
1192 }, 1236 },
1193 1237
1194 /** 1238 /**
1195 * A handler for the `iron-resize` event triggered by `IronResizableBehavior ` 1239 * A handler for the `iron-resize` event triggered by `IronResizableBehavior `
1196 * when the element is resized. 1240 * when the element is resized.
1197 */ 1241 */
1198 _resizeHandler: function() { 1242 _resizeHandler: function() {
1199 // iOS fires the resize event when the address bar slides up 1243 this._debounceTemplate(function() {
1200 var delta = Math.abs(this._viewportHeight - this._scrollTargetHeight); 1244 // Skip the resize event on touch devices when the address bar slides up .
1201 if (IOS && delta > 0 && delta < 100) { 1245 var delta = Math.abs(this._viewportHeight - this._scrollTargetHeight);
1202 return;
1203 }
1204 // In Desktop Safari 9.0.3, if the scroll bars are always shown,
1205 // changing the scroll position from a resize handler would result in
1206 // the scroll position being reset. Waiting 1ms fixes the issue.
1207 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() {
1208 this.updateViewportBoundaries(); 1246 this.updateViewportBoundaries();
1209 this._render(); 1247 if (('ontouchstart' in window || navigator.maxTouchPoints > 0) && delta > 0 && delta < 100) {
1248 return;
1249 }
1210 if (this._isVisible) { 1250 if (this._isVisible) {
1251 // Reinstall the scroll event listener.
1211 this.toggleScrollListener(true); 1252 this.toggleScrollListener(true);
1212 if (this._physicalCount > 0) { 1253 this._resetAverage();
1213 this._resetAverage(); 1254 this._render();
1214 this.scrollToIndex(this.firstVisibleIndex);
1215 }
1216 } else { 1255 } else {
1256 // Uninstall the scroll event listener.
1217 this.toggleScrollListener(false); 1257 this.toggleScrollListener(false);
1218 } 1258 }
1219 }.bind(this), 1)); 1259 }.bind(this));
1220 }, 1260 },
1221 1261
1222 _getModelFromItem: function(item) { 1262 _getModelFromItem: function(item) {
1223 var key = this._collection.getKey(item); 1263 var key = this._collection.getKey(item);
1224 var pidx = this._physicalIndexForKey[key]; 1264 var pidx = this._physicalIndexForKey[key];
1225 1265
1226 if (pidx != null) { 1266 if (pidx != null) {
1227 return this._physicalItems[pidx]._templateInstance; 1267 return this._physicalItems[pidx]._templateInstance;
1228 } 1268 }
1229 return null; 1269 return null;
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1336 /** 1376 /**
1337 * Select an item from an event object. 1377 * Select an item from an event object.
1338 */ 1378 */
1339 _selectionHandler: function(e) { 1379 _selectionHandler: function(e) {
1340 var model = this.modelForElement(e.target); 1380 var model = this.modelForElement(e.target);
1341 if (!model) { 1381 if (!model) {
1342 return; 1382 return;
1343 } 1383 }
1344 var modelTabIndex, activeElTabIndex; 1384 var modelTabIndex, activeElTabIndex;
1345 var target = Polymer.dom(e).path[0]; 1385 var target = Polymer.dom(e).path[0];
1346 var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).ac tiveElement; 1386 var itemsHost = this._itemsParent.node.domHost;
1387 var activeEl = Polymer.dom(itemsHost ? itemsHost.root : document).activeEl ement;
1347 var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.i ndexAs])]; 1388 var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.i ndexAs])];
1348 // Safari does not focus certain form controls via mouse 1389 // Safari does not focus certain form controls via mouse
1349 // https://bugs.webkit.org/show_bug.cgi?id=118043 1390 // https://bugs.webkit.org/show_bug.cgi?id=118043
1350 if (target.localName === 'input' || 1391 if (target.localName === 'input' ||
1351 target.localName === 'button' || 1392 target.localName === 'button' ||
1352 target.localName === 'select') { 1393 target.localName === 'select') {
1353 return; 1394 return;
1354 } 1395 }
1355 // Set a temporary tabindex 1396 // Set a temporary tabindex
1356 modelTabIndex = model.tabIndex; 1397 modelTabIndex = model.tabIndex;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
1449 } 1490 }
1450 // restore the tab index 1491 // restore the tab index
1451 model.tabIndex = 0; 1492 model.tabIndex = 0;
1452 // focus the focusable element 1493 // focus the focusable element
1453 this._focusedIndex = idx; 1494 this._focusedIndex = idx;
1454 focusable && focusable.focus(); 1495 focusable && focusable.focus();
1455 }, 1496 },
1456 1497
1457 _removeFocusedItem: function() { 1498 _removeFocusedItem: function() {
1458 if (this._offscreenFocusedItem) { 1499 if (this._offscreenFocusedItem) {
1459 Polymer.dom(this).removeChild(this._offscreenFocusedItem); 1500 this._itemsParent.removeChild(this._offscreenFocusedItem);
1460 } 1501 }
1461 this._offscreenFocusedItem = null; 1502 this._offscreenFocusedItem = null;
1462 this._focusBackfillItem = null; 1503 this._focusBackfillItem = null;
1463 this._focusedItem = null; 1504 this._focusedItem = null;
1464 this._focusedIndex = -1; 1505 this._focusedIndex = -1;
1465 }, 1506 },
1466 1507
1467 _createFocusBackfillItem: function() { 1508 _createFocusBackfillItem: function() {
1468 var fidx = this._focusedIndex; 1509 var fidx = this._focusedIndex;
1469 var pidx = this._getPhysicalIndex(fidx); 1510 var pidx = this._getPhysicalIndex(fidx);
1470 1511
1471 if (this._offscreenFocusedItem || pidx == null || fidx < 0) { 1512 if (this._offscreenFocusedItem || pidx == null || fidx < 0) {
1472 return; 1513 return;
1473 } 1514 }
1474 if (!this._focusBackfillItem) { 1515 if (!this._focusBackfillItem) {
1475 // Create a physical item. 1516 // Create a physical item.
1476 var stampedTemplate = this.stamp(null); 1517 var stampedTemplate = this.stamp(null);
1477 this._focusBackfillItem = stampedTemplate.root.querySelector('*'); 1518 this._focusBackfillItem = stampedTemplate.root.querySelector('*');
1478 Polymer.dom(this).appendChild(stampedTemplate.root); 1519 this._itemsParent.appendChild(stampedTemplate.root);
1479 } 1520 }
1480 // Set the offcreen focused physical item. 1521 // Set the offcreen focused physical item.
1481 this._offscreenFocusedItem = this._physicalItems[pidx]; 1522 this._offscreenFocusedItem = this._physicalItems[pidx];
1482 this._offscreenFocusedItem._templateInstance.tabIndex = 0; 1523 this._offscreenFocusedItem._templateInstance.tabIndex = 0;
1483 this._physicalItems[pidx] = this._focusBackfillItem; 1524 this._physicalItems[pidx] = this._focusBackfillItem;
1484 // Hide the focused physical. 1525 // Hide the focused physical.
1485 this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem); 1526 this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
1486 }, 1527 },
1487 1528
1488 _restoreFocusedItem: function() { 1529 _restoreFocusedItem: function() {
1489 var pidx, fidx = this._focusedIndex; 1530 var pidx, fidx = this._focusedIndex;
1490 1531
1491 if (!this._offscreenFocusedItem || this._focusedIndex < 0) { 1532 if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
1492 return; 1533 return;
1493 } 1534 }
1494 // Assign models to the focused index. 1535 // Assign models to the focused index.
1495 this._assignModels(); 1536 this._assignModels();
1496 // Get the new physical index for the focused index. 1537 // Get the new physical index for the focused index.
1497 pidx = this._getPhysicalIndex(fidx); 1538 pidx = this._getPhysicalIndex(fidx);
1498 1539
1499 if (pidx != null) { 1540 var onScreenItem = this._physicalItems[pidx];
1541 if (!onScreenItem) {
1542 return;
1543 }
1544 var onScreenInstance = onScreenItem._templateInstance;
1545 var offScreenInstance = this._offscreenFocusedItem._templateInstance;
1546 // Restores the physical item only when it has the same model
1547 // as the offscreen one. Use key for comparison since users can set
1548 // a new item via set('items.idx').
1549 if (onScreenInstance.__key__ === offScreenInstance.__key__) {
1500 // Flip the focus backfill. 1550 // Flip the focus backfill.
1501 this._focusBackfillItem = this._physicalItems[pidx]; 1551 this._focusBackfillItem = onScreenItem;
1502 this._focusBackfillItem._templateInstance.tabIndex = -1; 1552 onScreenInstance.tabIndex = -1;
1503 // Restore the focused physical item. 1553 // Restore the focused physical item.
1504 this._physicalItems[pidx] = this._offscreenFocusedItem; 1554 this._physicalItems[pidx] = this._offscreenFocusedItem;
1505 // Reset the offscreen focused item.
1506 this._offscreenFocusedItem = null;
1507 // Hide the physical item that backfills. 1555 // Hide the physical item that backfills.
1508 this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem); 1556 this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem);
1557 } else {
1558 this._focusBackfillItem = null;
1509 } 1559 }
1560 this._offscreenFocusedItem = null;
1510 }, 1561 },
1511 1562
1512 _didFocus: function(e) { 1563 _didFocus: function(e) {
1513 var targetModel = this.modelForElement(e.target); 1564 var targetModel = this.modelForElement(e.target);
1514 var focusedModel = this._focusedItem ? this._focusedItem._templateInstance : null; 1565 var focusedModel = this._focusedItem ? this._focusedItem._templateInstance : null;
1515 var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null; 1566 var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null;
1516 var fidx = this._focusedIndex; 1567 var fidx = this._focusedIndex;
1517 1568
1518 if (!targetModel || !focusedModel) { 1569 if (!targetModel || !focusedModel) {
1519 return; 1570 return;
(...skipping 28 matching lines...) Expand all
1548 this._focusPhysicalItem(this._focusedIndex + 1); 1599 this._focusPhysicalItem(this._focusedIndex + 1);
1549 }, 1600 },
1550 1601
1551 _didEnter: function(e) { 1602 _didEnter: function(e) {
1552 this._focusPhysicalItem(this._focusedIndex); 1603 this._focusPhysicalItem(this._focusedIndex);
1553 this._selectionHandler(e.detail.keyboardEvent); 1604 this._selectionHandler(e.detail.keyboardEvent);
1554 } 1605 }
1555 }); 1606 });
1556 1607
1557 })(); 1608 })();
OLDNEW
« no previous file with comments | « third_party/polymer/v1_0/components-chromium/iron-list/iron-list.html ('k') | third_party/polymer/v1_0/components_summary.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698