| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Assertion support. | 6 * @fileoverview Assertion support. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Verify |condition| is truthy and return |condition| if so. | 10 * Verify |condition| is truthy and return |condition| if so. |
| (...skipping 2450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2461 */ | 2461 */ |
| 2462 _isValidScrollTarget: function() { | 2462 _isValidScrollTarget: function() { |
| 2463 return this.scrollTarget instanceof HTMLElement; | 2463 return this.scrollTarget instanceof HTMLElement; |
| 2464 } | 2464 } |
| 2465 }; | 2465 }; |
| 2466 (function() { | 2466 (function() { |
| 2467 | 2467 |
| 2468 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/); | 2468 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/); |
| 2469 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8; | 2469 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8; |
| 2470 var DEFAULT_PHYSICAL_COUNT = 3; | 2470 var DEFAULT_PHYSICAL_COUNT = 3; |
| 2471 var MAX_PHYSICAL_COUNT = 500; | |
| 2472 var HIDDEN_Y = '-10000px'; | 2471 var HIDDEN_Y = '-10000px'; |
| 2472 var DEFAULT_GRID_SIZE = 200; |
| 2473 | 2473 |
| 2474 Polymer({ | 2474 Polymer({ |
| 2475 | 2475 |
| 2476 is: 'iron-list', | 2476 is: 'iron-list', |
| 2477 | 2477 |
| 2478 properties: { | 2478 properties: { |
| 2479 | 2479 |
| 2480 /** | 2480 /** |
| 2481 * An array containing items determining how many instances of the templat
e | 2481 * An array containing items determining how many instances of the templat
e |
| 2482 * to stamp and that that each template instance should bind to. | 2482 * to stamp and that that each template instance should bind to. |
| 2483 */ | 2483 */ |
| 2484 items: { | 2484 items: { |
| 2485 type: Array | 2485 type: Array |
| 2486 }, | 2486 }, |
| 2487 | 2487 |
| 2488 /** | 2488 /** |
| 2489 * The max count of physical items the pool can extend to. |
| 2490 */ |
| 2491 maxPhysicalCount: { |
| 2492 type: Number, |
| 2493 value: 500 |
| 2494 }, |
| 2495 |
| 2496 /** |
| 2489 * The name of the variable to add to the binding scope for the array | 2497 * The name of the variable to add to the binding scope for the array |
| 2490 * element associated with a given template instance. | 2498 * element associated with a given template instance. |
| 2491 */ | 2499 */ |
| 2492 as: { | 2500 as: { |
| 2493 type: String, | 2501 type: String, |
| 2494 value: 'item' | 2502 value: 'item' |
| 2495 }, | 2503 }, |
| 2496 | 2504 |
| 2497 /** | 2505 /** |
| 2498 * The name of the variable to add to the binding scope with the index | 2506 * The name of the variable to add to the binding scope with the index |
| 2499 * for the row. | 2507 * for the row. |
| 2500 */ | 2508 */ |
| 2501 indexAs: { | 2509 indexAs: { |
| 2502 type: String, | 2510 type: String, |
| 2503 value: 'index' | 2511 value: 'index' |
| 2504 }, | 2512 }, |
| 2505 | 2513 |
| 2506 /** | 2514 /** |
| 2507 * The name of the variable to add to the binding scope to indicate | 2515 * The name of the variable to add to the binding scope to indicate |
| 2508 * if the row is selected. | 2516 * if the row is selected. |
| 2509 */ | 2517 */ |
| 2510 selectedAs: { | 2518 selectedAs: { |
| 2511 type: String, | 2519 type: String, |
| 2512 value: 'selected' | 2520 value: 'selected' |
| 2513 }, | 2521 }, |
| 2514 | 2522 |
| 2515 /** | 2523 /** |
| 2524 * When true, the list is rendered as a grid. Grid items must have |
| 2525 * fixed width and height set via CSS. e.g. |
| 2526 * |
| 2527 * ```html |
| 2528 * <iron-list grid> |
| 2529 * <template> |
| 2530 * <div style="width: 100px; height: 100px;"> 100x100 </div> |
| 2531 * </template> |
| 2532 * </iron-list> |
| 2533 * ``` |
| 2534 */ |
| 2535 grid: { |
| 2536 type: Boolean, |
| 2537 value: false, |
| 2538 reflectToAttribute: true |
| 2539 }, |
| 2540 |
| 2541 /** |
| 2516 * When true, tapping a row will select the item, placing its data model | 2542 * When true, tapping a row will select the item, placing its data model |
| 2517 * in the set of selected items retrievable via the selection property. | 2543 * in the set of selected items retrievable via the selection property. |
| 2518 * | 2544 * |
| 2519 * Note that tapping focusable elements within the list item will not | 2545 * Note that tapping focusable elements within the list item will not |
| 2520 * result in selection, since they are presumed to have their * own action
. | 2546 * result in selection, since they are presumed to have their * own action
. |
| 2521 */ | 2547 */ |
| 2522 selectionEnabled: { | 2548 selectionEnabled: { |
| 2523 type: Boolean, | 2549 type: Boolean, |
| 2524 value: false | 2550 value: false |
| 2525 }, | 2551 }, |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2625 _estScrollHeight: 0, | 2651 _estScrollHeight: 0, |
| 2626 | 2652 |
| 2627 /** | 2653 /** |
| 2628 * The scroll height of the dom node | 2654 * The scroll height of the dom node |
| 2629 */ | 2655 */ |
| 2630 _scrollHeight: 0, | 2656 _scrollHeight: 0, |
| 2631 | 2657 |
| 2632 /** | 2658 /** |
| 2633 * The height of the list. This is referred as the viewport in the context o
f list. | 2659 * The height of the list. This is referred as the viewport in the context o
f list. |
| 2634 */ | 2660 */ |
| 2635 _viewportSize: 0, | 2661 _viewportHeight: 0, |
| 2662 |
| 2663 /** |
| 2664 * The width of the list. This is referred as the viewport in the context of
list. |
| 2665 */ |
| 2666 _viewportWidth: 0, |
| 2636 | 2667 |
| 2637 /** | 2668 /** |
| 2638 * An array of DOM nodes that are currently in the tree | 2669 * An array of DOM nodes that are currently in the tree |
| 2639 * @type {?Array<!TemplatizerNode>} | 2670 * @type {?Array<!TemplatizerNode>} |
| 2640 */ | 2671 */ |
| 2641 _physicalItems: null, | 2672 _physicalItems: null, |
| 2642 | 2673 |
| 2643 /** | 2674 /** |
| 2644 * An array of heights for each item in `_physicalItems` | 2675 * An array of heights for each item in `_physicalItems` |
| 2645 * @type {?Array<number>} | 2676 * @type {?Array<number>} |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2698 */ | 2729 */ |
| 2699 _offscreenFocusedItem: null, | 2730 _offscreenFocusedItem: null, |
| 2700 | 2731 |
| 2701 /** | 2732 /** |
| 2702 * The item that backfills the `_offscreenFocusedItem` in the physical items | 2733 * The item that backfills the `_offscreenFocusedItem` in the physical items |
| 2703 * list when that item is moved offscreen. | 2734 * list when that item is moved offscreen. |
| 2704 */ | 2735 */ |
| 2705 _focusBackfillItem: null, | 2736 _focusBackfillItem: null, |
| 2706 | 2737 |
| 2707 /** | 2738 /** |
| 2739 * The maximum items per row |
| 2740 */ |
| 2741 _itemsPerRow: 1, |
| 2742 |
| 2743 /** |
| 2744 * The width of each grid item |
| 2745 */ |
| 2746 _itemWidth: 0, |
| 2747 |
| 2748 /** |
| 2749 * The height of the row in grid layout. |
| 2750 */ |
| 2751 _rowHeight: 0, |
| 2752 |
| 2753 /** |
| 2708 * The bottom of the physical content. | 2754 * The bottom of the physical content. |
| 2709 */ | 2755 */ |
| 2710 get _physicalBottom() { | 2756 get _physicalBottom() { |
| 2711 return this._physicalTop + this._physicalSize; | 2757 return this._physicalTop + this._physicalSize; |
| 2712 }, | 2758 }, |
| 2713 | 2759 |
| 2714 /** | 2760 /** |
| 2715 * The bottom of the scroll. | 2761 * The bottom of the scroll. |
| 2716 */ | 2762 */ |
| 2717 get _scrollBottom() { | 2763 get _scrollBottom() { |
| 2718 return this._scrollPosition + this._viewportSize; | 2764 return this._scrollPosition + this._viewportHeight; |
| 2719 }, | 2765 }, |
| 2720 | 2766 |
| 2721 /** | 2767 /** |
| 2722 * The n-th item rendered in the last physical item. | 2768 * The n-th item rendered in the last physical item. |
| 2723 */ | 2769 */ |
| 2724 get _virtualEnd() { | 2770 get _virtualEnd() { |
| 2725 return this._virtualStart + this._physicalCount - 1; | 2771 return this._virtualStart + this._physicalCount - 1; |
| 2726 }, | 2772 }, |
| 2727 | 2773 |
| 2728 /** | 2774 /** |
| 2729 * The height of the physical content that isn't on the screen. | 2775 * The height of the physical content that isn't on the screen. |
| 2730 */ | 2776 */ |
| 2731 get _hiddenContentSize() { | 2777 get _hiddenContentSize() { |
| 2732 return this._physicalSize - this._viewportSize; | 2778 var size = this.grid ? this._physicalRows * this._rowHeight : this._physic
alSize; |
| 2779 return size - this._viewportHeight; |
| 2733 }, | 2780 }, |
| 2734 | 2781 |
| 2735 /** | 2782 /** |
| 2736 * The maximum scroll top value. | 2783 * The maximum scroll top value. |
| 2737 */ | 2784 */ |
| 2738 get _maxScrollTop() { | 2785 get _maxScrollTop() { |
| 2739 return this._estScrollHeight - this._viewportSize + this._scrollerPaddingT
op; | 2786 return this._estScrollHeight - this._viewportHeight + this._scrollerPaddin
gTop; |
| 2740 }, | 2787 }, |
| 2741 | 2788 |
| 2742 /** | 2789 /** |
| 2743 * The lowest n-th value for an item such that it can be rendered in `_physi
calStart`. | 2790 * The lowest n-th value for an item such that it can be rendered in `_physi
calStart`. |
| 2744 */ | 2791 */ |
| 2745 _minVirtualStart: 0, | 2792 _minVirtualStart: 0, |
| 2746 | 2793 |
| 2747 /** | 2794 /** |
| 2748 * The largest n-th value for an item such that it can be rendered in `_phys
icalStart`. | 2795 * The largest n-th value for an item such that it can be rendered in `_phys
icalStart`. |
| 2749 */ | 2796 */ |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2801 _physicalEnd: 0, | 2848 _physicalEnd: 0, |
| 2802 | 2849 |
| 2803 /** | 2850 /** |
| 2804 * An optimal physical size such that we will have enough physical items | 2851 * An optimal physical size such that we will have enough physical items |
| 2805 * to fill up the viewport and recycle when the user scrolls. | 2852 * to fill up the viewport and recycle when the user scrolls. |
| 2806 * | 2853 * |
| 2807 * This default value assumes that we will at least have the equivalent | 2854 * This default value assumes that we will at least have the equivalent |
| 2808 * to a viewport of physical items above and below the user's viewport. | 2855 * to a viewport of physical items above and below the user's viewport. |
| 2809 */ | 2856 */ |
| 2810 get _optPhysicalSize() { | 2857 get _optPhysicalSize() { |
| 2811 return this._viewportSize * this._maxPages; | 2858 if (this.grid) { |
| 2859 return this._estRowsInView * this._rowHeight * this._maxPages; |
| 2860 } |
| 2861 return this._viewportHeight * this._maxPages; |
| 2862 }, |
| 2863 |
| 2864 get _optPhysicalCount() { |
| 2865 return this._estRowsInView * this._itemsPerRow * this._maxPages; |
| 2812 }, | 2866 }, |
| 2813 | 2867 |
| 2814 /** | 2868 /** |
| 2815 * True if the current list is visible. | 2869 * True if the current list is visible. |
| 2816 */ | 2870 */ |
| 2817 get _isVisible() { | 2871 get _isVisible() { |
| 2818 return this.scrollTarget && Boolean(this.scrollTarget.offsetWidth || this.
scrollTarget.offsetHeight); | 2872 return this.scrollTarget && Boolean(this.scrollTarget.offsetWidth || this.
scrollTarget.offsetHeight); |
| 2819 }, | 2873 }, |
| 2820 | 2874 |
| 2821 /** | 2875 /** |
| 2822 * Gets the index of the first visible item in the viewport. | 2876 * Gets the index of the first visible item in the viewport. |
| 2823 * | 2877 * |
| 2824 * @type {number} | 2878 * @type {number} |
| 2825 */ | 2879 */ |
| 2826 get firstVisibleIndex() { | 2880 get firstVisibleIndex() { |
| 2827 if (this._firstVisibleIndexVal === null) { | 2881 if (this._firstVisibleIndexVal === null) { |
| 2828 var physicalOffset = this._physicalTop + this._scrollerPaddingTop; | 2882 var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddin
gTop); |
| 2829 | 2883 |
| 2830 this._firstVisibleIndexVal = this._iterateItems( | 2884 this._firstVisibleIndexVal = this._iterateItems( |
| 2831 function(pidx, vidx) { | 2885 function(pidx, vidx) { |
| 2832 physicalOffset += this._physicalSizes[pidx]; | 2886 physicalOffset += this._getPhysicalSizeIncrement(pidx); |
| 2887 |
| 2833 if (physicalOffset > this._scrollPosition) { | 2888 if (physicalOffset > this._scrollPosition) { |
| 2834 return vidx; | 2889 return this.grid ? vidx - (vidx % this._itemsPerRow) : vidx; |
| 2890 } |
| 2891 |
| 2892 // Handle a partially rendered final row in grid mode |
| 2893 if (this.grid && this._virtualCount - 1 === vidx) { |
| 2894 return vidx - (vidx % this._itemsPerRow); |
| 2835 } | 2895 } |
| 2836 }) || 0; | 2896 }) || 0; |
| 2837 } | 2897 } |
| 2838 return this._firstVisibleIndexVal; | 2898 return this._firstVisibleIndexVal; |
| 2839 }, | 2899 }, |
| 2840 | 2900 |
| 2841 /** | 2901 /** |
| 2842 * Gets the index of the last visible item in the viewport. | 2902 * Gets the index of the last visible item in the viewport. |
| 2843 * | 2903 * |
| 2844 * @type {number} | 2904 * @type {number} |
| 2845 */ | 2905 */ |
| 2846 get lastVisibleIndex() { | 2906 get lastVisibleIndex() { |
| 2847 if (this._lastVisibleIndexVal === null) { | 2907 if (this._lastVisibleIndexVal === null) { |
| 2848 var physicalOffset = this._physicalTop; | 2908 if (this.grid) { |
| 2909 var lastIndex = this.firstVisibleIndex + this._estRowsInView * this._i
temsPerRow - 1; |
| 2910 this._lastVisibleIndexVal = lastIndex > this._virtualCount ? this._vir
tualCount : lastIndex; |
| 2911 } else { |
| 2912 var physicalOffset = this._physicalTop; |
| 2849 | 2913 |
| 2850 this._iterateItems(function(pidx, vidx) { | 2914 this._iterateItems(function(pidx, vidx) { |
| 2851 physicalOffset += this._physicalSizes[pidx]; | 2915 physicalOffset += this._getPhysicalSizeIncrement(pidx); |
| 2852 | 2916 |
| 2853 if (physicalOffset <= this._scrollBottom) { | 2917 if(physicalOffset <= this._scrollBottom) { |
| 2854 this._lastVisibleIndexVal = vidx; | 2918 if (this.grid) { |
| 2855 } | 2919 var lastIndex = vidx - vidx % this._itemsPerRow + this._itemsPer
Row - 1; |
| 2856 }); | 2920 this._lastVisibleIndexVal = lastIndex > this._virtualCount ? thi
s._virtualCount : lastIndex; |
| 2921 } else { |
| 2922 this._lastVisibleIndexVal = vidx; |
| 2923 } |
| 2924 } |
| 2925 }); |
| 2926 } |
| 2857 } | 2927 } |
| 2858 return this._lastVisibleIndexVal; | 2928 return this._lastVisibleIndexVal; |
| 2859 }, | 2929 }, |
| 2860 | 2930 |
| 2861 get _defaultScrollTarget() { | 2931 get _defaultScrollTarget() { |
| 2862 return this; | 2932 return this; |
| 2863 }, | 2933 }, |
| 2934 get _virtualRowCount() { |
| 2935 return Math.ceil(this._virtualCount / this._itemsPerRow); |
| 2936 }, |
| 2937 |
| 2938 get _estRowsInView() { |
| 2939 return Math.ceil(this._viewportHeight / this._rowHeight); |
| 2940 }, |
| 2941 |
| 2942 get _physicalRows() { |
| 2943 return Math.ceil(this._physicalCount / this._itemsPerRow); |
| 2944 }, |
| 2864 | 2945 |
| 2865 ready: function() { | 2946 ready: function() { |
| 2866 this.addEventListener('focus', this._didFocus.bind(this), true); | 2947 this.addEventListener('focus', this._didFocus.bind(this), true); |
| 2867 }, | 2948 }, |
| 2868 | 2949 |
| 2869 attached: function() { | 2950 attached: function() { |
| 2870 this.updateViewportBoundaries(); | 2951 this.updateViewportBoundaries(); |
| 2871 this._render(); | 2952 this._render(); |
| 2872 // `iron-resize` is fired when the list is attached if the event is added | 2953 // `iron-resize` is fired when the list is attached if the event is added |
| 2873 // before attached causing unnecessary work. | 2954 // before attached causing unnecessary work. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2890 /** | 2971 /** |
| 2891 * Invoke this method if you dynamically update the viewport's | 2972 * Invoke this method if you dynamically update the viewport's |
| 2892 * size or CSS padding. | 2973 * size or CSS padding. |
| 2893 * | 2974 * |
| 2894 * @method updateViewportBoundaries | 2975 * @method updateViewportBoundaries |
| 2895 */ | 2976 */ |
| 2896 updateViewportBoundaries: function() { | 2977 updateViewportBoundaries: function() { |
| 2897 this._scrollerPaddingTop = this.scrollTarget === this ? 0 : | 2978 this._scrollerPaddingTop = this.scrollTarget === this ? 0 : |
| 2898 parseInt(window.getComputedStyle(this)['padding-top'], 10); | 2979 parseInt(window.getComputedStyle(this)['padding-top'], 10); |
| 2899 | 2980 |
| 2900 this._viewportSize = this._scrollTargetHeight; | 2981 this._viewportHeight = this._scrollTargetHeight; |
| 2982 if (this.grid) { |
| 2983 this._updateGridMetrics(); |
| 2984 } |
| 2901 }, | 2985 }, |
| 2902 | 2986 |
| 2903 /** | 2987 /** |
| 2904 * Update the models, the position of the | 2988 * Update the models, the position of the |
| 2905 * items in the viewport and recycle tiles as needed. | 2989 * items in the viewport and recycle tiles as needed. |
| 2906 */ | 2990 */ |
| 2907 _scrollHandler: function() { | 2991 _scrollHandler: function() { |
| 2908 // clamp the `scrollTop` value | 2992 // clamp the `scrollTop` value |
| 2909 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop))
; | 2993 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop))
; |
| 2910 var delta = scrollTop - this._scrollPosition; | 2994 var delta = scrollTop - this._scrollPosition; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2942 | 3026 |
| 2943 // move tiles from bottom to top | 3027 // move tiles from bottom to top |
| 2944 while ( | 3028 while ( |
| 2945 // approximate `currentRatio` to `ratio` | 3029 // approximate `currentRatio` to `ratio` |
| 2946 currentRatio < ratio && | 3030 currentRatio < ratio && |
| 2947 // recycle less physical items than the total | 3031 // recycle less physical items than the total |
| 2948 recycledTiles < this._physicalCount && | 3032 recycledTiles < this._physicalCount && |
| 2949 // ensure that these recycled tiles are needed | 3033 // ensure that these recycled tiles are needed |
| 2950 virtualStart - recycledTiles > 0 && | 3034 virtualStart - recycledTiles > 0 && |
| 2951 // ensure that the tile is not visible | 3035 // ensure that the tile is not visible |
| 2952 physicalBottom - this._physicalSizes[kth] > scrollBottom | 3036 physicalBottom - this._getPhysicalSizeIncrement(kth) > scrollBottom |
| 2953 ) { | 3037 ) { |
| 2954 | 3038 |
| 2955 tileHeight = this._physicalSizes[kth]; | 3039 tileHeight = this._getPhysicalSizeIncrement(kth); |
| 2956 currentRatio += tileHeight / hiddenContentSize; | 3040 currentRatio += tileHeight / hiddenContentSize; |
| 2957 physicalBottom -= tileHeight; | 3041 physicalBottom -= tileHeight; |
| 2958 recycledTileSet.push(kth); | 3042 recycledTileSet.push(kth); |
| 2959 recycledTiles++; | 3043 recycledTiles++; |
| 2960 kth = (kth === 0) ? this._physicalCount - 1 : kth - 1; | 3044 kth = (kth === 0) ? this._physicalCount - 1 : kth - 1; |
| 2961 } | 3045 } |
| 2962 | 3046 |
| 2963 movingUp = recycledTileSet; | 3047 movingUp = recycledTileSet; |
| 2964 recycledTiles = -recycledTiles; | 3048 recycledTiles = -recycledTiles; |
| 2965 } | 3049 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2976 | 3060 |
| 2977 // move tiles from top to bottom | 3061 // move tiles from top to bottom |
| 2978 while ( | 3062 while ( |
| 2979 // approximate `currentRatio` to `ratio` | 3063 // approximate `currentRatio` to `ratio` |
| 2980 currentRatio < ratio && | 3064 currentRatio < ratio && |
| 2981 // recycle less physical items than the total | 3065 // recycle less physical items than the total |
| 2982 recycledTiles < this._physicalCount && | 3066 recycledTiles < this._physicalCount && |
| 2983 // ensure that these recycled tiles are needed | 3067 // ensure that these recycled tiles are needed |
| 2984 virtualEnd + recycledTiles < lastVirtualItemIndex && | 3068 virtualEnd + recycledTiles < lastVirtualItemIndex && |
| 2985 // ensure that the tile is not visible | 3069 // ensure that the tile is not visible |
| 2986 this._physicalTop + this._physicalSizes[kth] < scrollTop | 3070 this._physicalTop + this._getPhysicalSizeIncrement(kth) < scrollTop |
| 2987 ) { | 3071 ) { |
| 2988 | 3072 |
| 2989 tileHeight = this._physicalSizes[kth]; | 3073 tileHeight = this._getPhysicalSizeIncrement(kth); |
| 2990 currentRatio += tileHeight / hiddenContentSize; | 3074 currentRatio += tileHeight / hiddenContentSize; |
| 2991 | 3075 |
| 2992 this._physicalTop += tileHeight; | 3076 this._physicalTop += tileHeight; |
| 2993 recycledTileSet.push(kth); | 3077 recycledTileSet.push(kth); |
| 2994 recycledTiles++; | 3078 recycledTiles++; |
| 2995 kth = (kth + 1) % this._physicalCount; | 3079 kth = (kth + 1) % this._physicalCount; |
| 2996 } | 3080 } |
| 2997 } | 3081 } |
| 2998 | 3082 |
| 2999 if (recycledTiles === 0) { | 3083 if (recycledTiles === 0) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3016 _update: function(itemSet, movingUp) { | 3100 _update: function(itemSet, movingUp) { |
| 3017 // manage focus | 3101 // manage focus |
| 3018 this._manageFocus(); | 3102 this._manageFocus(); |
| 3019 // update models | 3103 // update models |
| 3020 this._assignModels(itemSet); | 3104 this._assignModels(itemSet); |
| 3021 // measure heights | 3105 // measure heights |
| 3022 this._updateMetrics(itemSet); | 3106 this._updateMetrics(itemSet); |
| 3023 // adjust offset after measuring | 3107 // adjust offset after measuring |
| 3024 if (movingUp) { | 3108 if (movingUp) { |
| 3025 while (movingUp.length) { | 3109 while (movingUp.length) { |
| 3026 this._physicalTop -= this._physicalSizes[movingUp.pop()]; | 3110 var idx = movingUp.pop(); |
| 3111 this._physicalTop -= this._getPhysicalSizeIncrement(idx); |
| 3027 } | 3112 } |
| 3028 } | 3113 } |
| 3029 // update the position of the items | 3114 // update the position of the items |
| 3030 this._positionItems(); | 3115 this._positionItems(); |
| 3031 // set the scroller size | 3116 // set the scroller size |
| 3032 this._updateScrollerSize(); | 3117 this._updateScrollerSize(); |
| 3033 // increase the pool of physical items | 3118 // increase the pool of physical items |
| 3034 this._increasePoolIfNeeded(); | 3119 this._increasePoolIfNeeded(); |
| 3035 }, | 3120 }, |
| 3036 | 3121 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3051 } | 3136 } |
| 3052 return physicalItems; | 3137 return physicalItems; |
| 3053 }, | 3138 }, |
| 3054 | 3139 |
| 3055 /** | 3140 /** |
| 3056 * Increases the pool of physical items only if needed. | 3141 * Increases the pool of physical items only if needed. |
| 3057 * | 3142 * |
| 3058 * @return {boolean} True if the pool was increased. | 3143 * @return {boolean} True if the pool was increased. |
| 3059 */ | 3144 */ |
| 3060 _increasePoolIfNeeded: function() { | 3145 _increasePoolIfNeeded: function() { |
| 3061 // Base case 1: the list has no size. | 3146 // Base case 1: the list has no height. |
| 3062 if (this._viewportSize === 0) { | 3147 if (this._viewportHeight === 0) { |
| 3063 return false; | 3148 return false; |
| 3064 } | 3149 } |
| 3065 // Base case 2: If the physical size is optimal and the list's client heig
ht is full | 3150 // Base case 2: If the physical size is optimal and the list's client heig
ht is full |
| 3066 // with physical items, don't increase the pool. | 3151 // with physical items, don't increase the pool. |
| 3067 var isClientHeightFull = this._physicalBottom >= this._scrollBottom && thi
s._physicalTop <= this._scrollPosition; | 3152 var isClientHeightFull = this._physicalBottom >= this._scrollBottom && thi
s._physicalTop <= this._scrollPosition; |
| 3068 if (this._physicalSize >= this._optPhysicalSize && isClientHeightFull) { | 3153 if (this._physicalSize >= this._optPhysicalSize && isClientHeightFull) { |
| 3069 return false; | 3154 return false; |
| 3070 } | 3155 } |
| 3071 // this value should range between [0 <= `currentPage` <= `_maxPages`] | 3156 // this value should range between [0 <= `currentPage` <= `_maxPages`] |
| 3072 var currentPage = Math.floor(this._physicalSize / this._viewportSize); | 3157 var currentPage = Math.floor(this._physicalSize / this._viewportHeight); |
| 3073 | 3158 |
| 3074 if (currentPage === 0) { | 3159 if (currentPage === 0) { |
| 3075 // fill the first page | 3160 // fill the first page |
| 3076 this._debounceTemplate(this._increasePool.bind(this, Math.round(this._ph
ysicalCount * 0.5))); | 3161 this._debounceTemplate(this._increasePool.bind(this, Math.round(this._ph
ysicalCount * 0.5))); |
| 3077 } else if (this._lastPage !== currentPage && isClientHeightFull) { | 3162 } else if (this._lastPage !== currentPage && isClientHeightFull) { |
| 3078 // paint the page and defer the next increase | 3163 // paint the page and defer the next increase |
| 3079 // wait 16ms which is rough enough to get paint cycle. | 3164 // wait 16ms which is rough enough to get paint cycle. |
| 3080 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increa
sePool.bind(this, 1), 16)); | 3165 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increa
sePool.bind(this, this._itemsPerRow), 16)); |
| 3081 } else { | 3166 } else { |
| 3082 // fill the rest of the pages | 3167 // fill the rest of the pages |
| 3083 this._debounceTemplate(this._increasePool.bind(this, 1)); | 3168 this._debounceTemplate(this._increasePool.bind(this, this._itemsPerRow))
; |
| 3084 } | 3169 } |
| 3085 | 3170 |
| 3086 this._lastPage = currentPage; | 3171 this._lastPage = currentPage; |
| 3087 | 3172 |
| 3088 return true; | 3173 return true; |
| 3089 }, | 3174 }, |
| 3090 | 3175 |
| 3091 /** | 3176 /** |
| 3092 * Increases the pool size. | 3177 * Increases the pool size. |
| 3093 */ | 3178 */ |
| 3094 _increasePool: function(missingItems) { | 3179 _increasePool: function(missingItems) { |
| 3095 var nextPhysicalCount = Math.min( | 3180 var nextPhysicalCount = Math.min( |
| 3096 this._physicalCount + missingItems, | 3181 this._physicalCount + missingItems, |
| 3097 this._virtualCount - this._virtualStart, | 3182 this._virtualCount - this._virtualStart, |
| 3098 MAX_PHYSICAL_COUNT | 3183 Math.max(this.maxPhysicalCount, DEFAULT_PHYSICAL_COUNT) |
| 3099 ); | 3184 ); |
| 3100 var prevPhysicalCount = this._physicalCount; | 3185 var prevPhysicalCount = this._physicalCount; |
| 3101 var delta = nextPhysicalCount - prevPhysicalCount; | 3186 var delta = nextPhysicalCount - prevPhysicalCount; |
| 3102 | 3187 |
| 3103 if (delta <= 0) { | 3188 if (delta <= 0) { |
| 3104 return; | 3189 return; |
| 3105 } | 3190 } |
| 3106 | 3191 |
| 3107 [].push.apply(this._physicalItems, this._createPool(delta)); | 3192 [].push.apply(this._physicalItems, this._createPool(delta)); |
| 3108 [].push.apply(this._physicalSizes, new Array(delta)); | 3193 [].push.apply(this._physicalSizes, new Array(delta)); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3313 * | 3398 * |
| 3314 * @param {!function(number, number)} fn | 3399 * @param {!function(number, number)} fn |
| 3315 * @param {!Array<number>=} itemSet | 3400 * @param {!Array<number>=} itemSet |
| 3316 */ | 3401 */ |
| 3317 _iterateItems: function(fn, itemSet) { | 3402 _iterateItems: function(fn, itemSet) { |
| 3318 var pidx, vidx, rtn, i; | 3403 var pidx, vidx, rtn, i; |
| 3319 | 3404 |
| 3320 if (arguments.length === 2 && itemSet) { | 3405 if (arguments.length === 2 && itemSet) { |
| 3321 for (i = 0; i < itemSet.length; i++) { | 3406 for (i = 0; i < itemSet.length; i++) { |
| 3322 pidx = itemSet[i]; | 3407 pidx = itemSet[i]; |
| 3323 if (pidx >= this._physicalStart) { | 3408 vidx = this._computeVidx(pidx); |
| 3324 vidx = this._virtualStart + (pidx - this._physicalStart); | |
| 3325 } else { | |
| 3326 vidx = this._virtualStart + (this._physicalCount - this._physicalSta
rt) + pidx; | |
| 3327 } | |
| 3328 if ((rtn = fn.call(this, pidx, vidx)) != null) { | 3409 if ((rtn = fn.call(this, pidx, vidx)) != null) { |
| 3329 return rtn; | 3410 return rtn; |
| 3330 } | 3411 } |
| 3331 } | 3412 } |
| 3332 } else { | 3413 } else { |
| 3333 pidx = this._physicalStart; | 3414 pidx = this._physicalStart; |
| 3334 vidx = this._virtualStart; | 3415 vidx = this._virtualStart; |
| 3335 | 3416 |
| 3336 for (; pidx < this._physicalCount; pidx++, vidx++) { | 3417 for (; pidx < this._physicalCount; pidx++, vidx++) { |
| 3337 if ((rtn = fn.call(this, pidx, vidx)) != null) { | 3418 if ((rtn = fn.call(this, pidx, vidx)) != null) { |
| 3338 return rtn; | 3419 return rtn; |
| 3339 } | 3420 } |
| 3340 } | 3421 } |
| 3341 for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) { | 3422 for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) { |
| 3342 if ((rtn = fn.call(this, pidx, vidx)) != null) { | 3423 if ((rtn = fn.call(this, pidx, vidx)) != null) { |
| 3343 return rtn; | 3424 return rtn; |
| 3344 } | 3425 } |
| 3345 } | 3426 } |
| 3346 } | 3427 } |
| 3347 }, | 3428 }, |
| 3348 | 3429 |
| 3349 /** | 3430 /** |
| 3431 * Returns the virtual index for a given physical index |
| 3432 * |
| 3433 * @param {number} pidx Physical index |
| 3434 * @return {number} |
| 3435 */ |
| 3436 _computeVidx: function(pidx) { |
| 3437 if (pidx >= this._physicalStart) { |
| 3438 return this._virtualStart + (pidx - this._physicalStart); |
| 3439 } |
| 3440 return this._virtualStart + (this._physicalCount - this._physicalStart) +
pidx; |
| 3441 }, |
| 3442 |
| 3443 /** |
| 3350 * Assigns the data models to a given set of items. | 3444 * Assigns the data models to a given set of items. |
| 3351 * @param {!Array<number>=} itemSet | 3445 * @param {!Array<number>=} itemSet |
| 3352 */ | 3446 */ |
| 3353 _assignModels: function(itemSet) { | 3447 _assignModels: function(itemSet) { |
| 3354 this._iterateItems(function(pidx, vidx) { | 3448 this._iterateItems(function(pidx, vidx) { |
| 3355 var el = this._physicalItems[pidx]; | 3449 var el = this._physicalItems[pidx]; |
| 3356 var inst = el._templateInstance; | 3450 var inst = el._templateInstance; |
| 3357 var item = this.items && this.items[vidx]; | 3451 var item = this.items && this.items[vidx]; |
| 3358 | 3452 |
| 3359 if (item != null) { | 3453 if (item != null) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3388 | 3482 |
| 3389 this._iterateItems(function(pidx, vidx) { | 3483 this._iterateItems(function(pidx, vidx) { |
| 3390 | 3484 |
| 3391 oldPhysicalSize += this._physicalSizes[pidx] || 0; | 3485 oldPhysicalSize += this._physicalSizes[pidx] || 0; |
| 3392 this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight; | 3486 this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight; |
| 3393 newPhysicalSize += this._physicalSizes[pidx]; | 3487 newPhysicalSize += this._physicalSizes[pidx]; |
| 3394 this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0; | 3488 this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0; |
| 3395 | 3489 |
| 3396 }, itemSet); | 3490 }, itemSet); |
| 3397 | 3491 |
| 3398 this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSiz
e; | 3492 this._viewportHeight = this._scrollTargetHeight; |
| 3399 this._viewportSize = this._scrollTargetHeight; | 3493 if (this.grid) { |
| 3494 this._updateGridMetrics(); |
| 3495 this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow)
* this._rowHeight; |
| 3496 } else { |
| 3497 this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalS
ize; |
| 3498 } |
| 3400 | 3499 |
| 3401 // update the average if we measured something | 3500 // update the average if we measured something |
| 3402 if (this._physicalAverageCount !== prevAvgCount) { | 3501 if (this._physicalAverageCount !== prevAvgCount) { |
| 3403 this._physicalAverage = Math.round( | 3502 this._physicalAverage = Math.round( |
| 3404 ((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) / | 3503 ((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) / |
| 3405 this._physicalAverageCount); | 3504 this._physicalAverageCount); |
| 3406 } | 3505 } |
| 3407 }, | 3506 }, |
| 3408 | 3507 |
| 3508 _updateGridMetrics: function() { |
| 3509 this._viewportWidth = this._scrollTargetWidth; |
| 3510 // Set item width to the value of the _physicalItems offsetWidth |
| 3511 this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].offsetW
idth : DEFAULT_GRID_SIZE; |
| 3512 // Set row height to the value of the _physicalItems offsetHeight |
| 3513 this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetH
eight : DEFAULT_GRID_SIZE; |
| 3514 // If in grid mode compute how many items with exist in each row |
| 3515 this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / thi
s._itemWidth) : this._itemsPerRow; |
| 3516 }, |
| 3517 |
| 3409 /** | 3518 /** |
| 3410 * Updates the position of the physical items. | 3519 * Updates the position of the physical items. |
| 3411 */ | 3520 */ |
| 3412 _positionItems: function() { | 3521 _positionItems: function() { |
| 3413 this._adjustScrollPosition(); | 3522 this._adjustScrollPosition(); |
| 3414 | 3523 |
| 3415 var y = this._physicalTop; | 3524 var y = this._physicalTop; |
| 3416 | 3525 |
| 3417 this._iterateItems(function(pidx) { | 3526 if (this.grid) { |
| 3418 this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]); | 3527 var totalItemWidth = this._itemsPerRow * this._itemWidth; |
| 3419 y += this._physicalSizes[pidx]; | 3528 var rowOffset = (this._viewportWidth - totalItemWidth) / 2; |
| 3420 }); | 3529 |
| 3530 this._iterateItems(function(pidx, vidx) { |
| 3531 |
| 3532 var modulus = vidx % this._itemsPerRow; |
| 3533 var x = Math.floor((modulus * this._itemWidth) + rowOffset); |
| 3534 |
| 3535 this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]); |
| 3536 |
| 3537 if (this._shouldRenderNextRow(vidx)) { |
| 3538 y += this._rowHeight; |
| 3539 } |
| 3540 |
| 3541 }); |
| 3542 } else { |
| 3543 this._iterateItems(function(pidx, vidx) { |
| 3544 |
| 3545 this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]); |
| 3546 y += this._physicalSizes[pidx]; |
| 3547 |
| 3548 }); |
| 3549 } |
| 3550 }, |
| 3551 |
| 3552 _getPhysicalSizeIncrement: function(pidx) { |
| 3553 if (!this.grid) { |
| 3554 return this._physicalSizes[pidx]; |
| 3555 } |
| 3556 if (this._computeVidx(pidx) % this._itemsPerRow !== this._itemsPerRow - 1)
{ |
| 3557 return 0; |
| 3558 } |
| 3559 return this._rowHeight; |
| 3421 }, | 3560 }, |
| 3422 | 3561 |
| 3423 /** | 3562 /** |
| 3563 * Returns, based on the current index, |
| 3564 * whether or not the next index will need |
| 3565 * to be rendered on a new row. |
| 3566 * |
| 3567 * @param {number} vidx Virtual index |
| 3568 * @return {boolean} |
| 3569 */ |
| 3570 _shouldRenderNextRow: function(vidx) { |
| 3571 return vidx % this._itemsPerRow === this._itemsPerRow - 1; |
| 3572 }, |
| 3573 |
| 3574 /** |
| 3424 * Adjusts the scroll position when it was overestimated. | 3575 * Adjusts the scroll position when it was overestimated. |
| 3425 */ | 3576 */ |
| 3426 _adjustScrollPosition: function() { | 3577 _adjustScrollPosition: function() { |
| 3427 var deltaHeight = this._virtualStart === 0 ? this._physicalTop : | 3578 var deltaHeight = this._virtualStart === 0 ? this._physicalTop : |
| 3428 Math.min(this._scrollPosition + this._physicalTop, 0); | 3579 Math.min(this._scrollPosition + this._physicalTop, 0); |
| 3429 | 3580 |
| 3430 if (deltaHeight) { | 3581 if (deltaHeight) { |
| 3431 this._physicalTop = this._physicalTop - deltaHeight; | 3582 this._physicalTop = this._physicalTop - deltaHeight; |
| 3432 // juking scroll position during interial scrolling on iOS is no bueno | 3583 // juking scroll position during interial scrolling on iOS is no bueno |
| 3433 if (!IOS_TOUCH_SCROLLING) { | 3584 if (!IOS_TOUCH_SCROLLING) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3445 this._scrollPosition = this._scrollTop; | 3596 this._scrollPosition = this._scrollTop; |
| 3446 } | 3597 } |
| 3447 }, | 3598 }, |
| 3448 | 3599 |
| 3449 /** | 3600 /** |
| 3450 * Sets the scroll height, that's the height of the content, | 3601 * Sets the scroll height, that's the height of the content, |
| 3451 * | 3602 * |
| 3452 * @param {boolean=} forceUpdate If true, updates the height no matter what. | 3603 * @param {boolean=} forceUpdate If true, updates the height no matter what. |
| 3453 */ | 3604 */ |
| 3454 _updateScrollerSize: function(forceUpdate) { | 3605 _updateScrollerSize: function(forceUpdate) { |
| 3455 this._estScrollHeight = (this._physicalBottom + | 3606 if (this.grid) { |
| 3456 Math.max(this._virtualCount - this._physicalCount - this._virtualStart
, 0) * this._physicalAverage); | 3607 this._estScrollHeight = this._virtualRowCount * this._rowHeight; |
| 3608 } else { |
| 3609 this._estScrollHeight = (this._physicalBottom + |
| 3610 Math.max(this._virtualCount - this._physicalCount - this._virtualSta
rt, 0) * this._physicalAverage); |
| 3611 } |
| 3457 | 3612 |
| 3458 forceUpdate = forceUpdate || this._scrollHeight === 0; | 3613 forceUpdate = forceUpdate || this._scrollHeight === 0; |
| 3459 forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight
- this._physicalSize; | 3614 forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight
- this._physicalSize; |
| 3615 forceUpdate = forceUpdate || this.grid && this.$.items.style.height < this
._estScrollHeight; |
| 3460 | 3616 |
| 3461 // amortize height adjustment, so it won't trigger repaints very often | 3617 // amortize height adjustment, so it won't trigger repaints very often |
| 3462 if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >=
this._optPhysicalSize) { | 3618 if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >=
this._optPhysicalSize) { |
| 3463 this.$.items.style.height = this._estScrollHeight + 'px'; | 3619 this.$.items.style.height = this._estScrollHeight + 'px'; |
| 3464 this._scrollHeight = this._estScrollHeight; | 3620 this._scrollHeight = this._estScrollHeight; |
| 3465 } | 3621 } |
| 3466 }, | 3622 }, |
| 3467 /** | 3623 /** |
| 3468 * Scroll to a specific item in the virtual list regardless | 3624 * Scroll to a specific item in the virtual list regardless |
| 3469 * of the physical items in the DOM tree. | 3625 * of the physical items in the DOM tree. |
| 3470 * | 3626 * |
| 3471 * @method scrollToIndex | 3627 * @method scrollToIndex |
| 3472 * @param {number} idx The index of the item | 3628 * @param {number} idx The index of the item |
| 3473 */ | 3629 */ |
| 3474 scrollToIndex: function(idx) { | 3630 scrollToIndex: function(idx) { |
| 3475 if (typeof idx !== 'number') { | 3631 if (typeof idx !== 'number') { |
| 3476 return; | 3632 return; |
| 3477 } | 3633 } |
| 3478 | 3634 |
| 3479 Polymer.dom.flush(); | 3635 Polymer.dom.flush(); |
| 3480 | 3636 |
| 3481 idx = Math.min(Math.max(idx, 0), this._virtualCount-1); | 3637 idx = Math.min(Math.max(idx, 0), this._virtualCount-1); |
| 3482 // update the virtual start only when needed | 3638 // update the virtual start only when needed |
| 3483 if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) { | 3639 if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) { |
| 3484 this._virtualStart = idx - 1; | 3640 this._virtualStart = this.grid ? (idx - this._itemsPerRow * 2) : (idx -
1); |
| 3485 } | 3641 } |
| 3486 // manage focus | 3642 // manage focus |
| 3487 this._manageFocus(); | 3643 this._manageFocus(); |
| 3488 // assign new models | 3644 // assign new models |
| 3489 this._assignModels(); | 3645 this._assignModels(); |
| 3490 // measure the new sizes | 3646 // measure the new sizes |
| 3491 this._updateMetrics(); | 3647 this._updateMetrics(); |
| 3648 |
| 3492 // estimate new physical offset | 3649 // estimate new physical offset |
| 3493 this._physicalTop = this._virtualStart * this._physicalAverage; | 3650 var estPhysicalTop = Math.floor(this._virtualStart / this._itemsPerRow) *
this._physicalAverage; |
| 3651 this._physicalTop = estPhysicalTop; |
| 3494 | 3652 |
| 3495 var currentTopItem = this._physicalStart; | 3653 var currentTopItem = this._physicalStart; |
| 3496 var currentVirtualItem = this._virtualStart; | 3654 var currentVirtualItem = this._virtualStart; |
| 3497 var targetOffsetTop = 0; | 3655 var targetOffsetTop = 0; |
| 3498 var hiddenContentSize = this._hiddenContentSize; | 3656 var hiddenContentSize = this._hiddenContentSize; |
| 3499 | 3657 |
| 3500 // scroll to the item as much as we can | 3658 // scroll to the item as much as we can |
| 3501 while (currentVirtualItem < idx && targetOffsetTop < hiddenContentSize) { | 3659 while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) { |
| 3502 targetOffsetTop = targetOffsetTop + this._physicalSizes[currentTopItem]; | 3660 targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(curre
ntTopItem); |
| 3503 currentTopItem = (currentTopItem + 1) % this._physicalCount; | 3661 currentTopItem = (currentTopItem + 1) % this._physicalCount; |
| 3504 currentVirtualItem++; | 3662 currentVirtualItem++; |
| 3505 } | 3663 } |
| 3506 // update the scroller size | 3664 // update the scroller size |
| 3507 this._updateScrollerSize(true); | 3665 this._updateScrollerSize(true); |
| 3508 // update the position of the items | 3666 // update the position of the items |
| 3509 this._positionItems(); | 3667 this._positionItems(); |
| 3510 // set the new scroll position | 3668 // set the new scroll position |
| 3511 this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + t
argetOffsetTop); | 3669 this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + t
argetOffsetTop); |
| 3512 // increase the pool of physical items if needed | 3670 // increase the pool of physical items if needed |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3523 this._physicalAverage = 0; | 3681 this._physicalAverage = 0; |
| 3524 this._physicalAverageCount = 0; | 3682 this._physicalAverageCount = 0; |
| 3525 }, | 3683 }, |
| 3526 | 3684 |
| 3527 /** | 3685 /** |
| 3528 * A handler for the `iron-resize` event triggered by `IronResizableBehavior
` | 3686 * A handler for the `iron-resize` event triggered by `IronResizableBehavior
` |
| 3529 * when the element is resized. | 3687 * when the element is resized. |
| 3530 */ | 3688 */ |
| 3531 _resizeHandler: function() { | 3689 _resizeHandler: function() { |
| 3532 // iOS fires the resize event when the address bar slides up | 3690 // iOS fires the resize event when the address bar slides up |
| 3533 if (IOS && Math.abs(this._viewportSize - this._scrollTargetHeight) < 100)
{ | 3691 if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100
) { |
| 3534 return; | 3692 return; |
| 3535 } | 3693 } |
| 3536 // In Desktop Safari 9.0.3, if the scroll bars are always shown, | 3694 // In Desktop Safari 9.0.3, if the scroll bars are always shown, |
| 3537 // changing the scroll position from a resize handler would result in | 3695 // changing the scroll position from a resize handler would result in |
| 3538 // the scroll position being reset. Waiting 1ms fixes the issue. | 3696 // the scroll position being reset. Waiting 1ms fixes the issue. |
| 3539 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', | 3697 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() { |
| 3540 function() { | 3698 this.updateViewportBoundaries(); |
| 3541 this._render(); | 3699 this._render(); |
| 3542 | 3700 |
| 3543 if (this._itemsRendered && this._physicalItems && this._isVisible) { | 3701 if (this._itemsRendered && this._physicalItems && this._isVisible) { |
| 3544 this._resetAverage(); | 3702 this._resetAverage(); |
| 3545 this.updateViewportBoundaries(); | 3703 this.scrollToIndex(this.firstVisibleIndex); |
| 3546 this.scrollToIndex(this.firstVisibleIndex); | 3704 } |
| 3547 } | 3705 }.bind(this), 1)); |
| 3548 }.bind(this), 1)); | |
| 3549 }, | 3706 }, |
| 3550 | 3707 |
| 3551 _getModelFromItem: function(item) { | 3708 _getModelFromItem: function(item) { |
| 3552 var key = this._collection.getKey(item); | 3709 var key = this._collection.getKey(item); |
| 3553 var pidx = this._physicalIndexForKey[key]; | 3710 var pidx = this._physicalIndexForKey[key]; |
| 3554 | 3711 |
| 3555 if (pidx != null) { | 3712 if (pidx != null) { |
| 3556 return this._physicalItems[pidx]._templateInstance; | 3713 return this._physicalItems[pidx]._templateInstance; |
| 3557 } | 3714 } |
| 3558 return null; | 3715 return null; |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3849 if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) { | 4006 if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) { |
| 3850 this._update(); | 4007 this._update(); |
| 3851 } | 4008 } |
| 3852 } | 4009 } |
| 3853 }, | 4010 }, |
| 3854 | 4011 |
| 3855 _didMoveUp: function() { | 4012 _didMoveUp: function() { |
| 3856 this._focusPhysicalItem(this._focusedIndex - 1); | 4013 this._focusPhysicalItem(this._focusedIndex - 1); |
| 3857 }, | 4014 }, |
| 3858 | 4015 |
| 3859 _didMoveDown: function() { | 4016 _didMoveDown: function(e) { |
| 4017 // disable scroll when pressing the down key |
| 4018 e.detail.keyboardEvent.preventDefault(); |
| 3860 this._focusPhysicalItem(this._focusedIndex + 1); | 4019 this._focusPhysicalItem(this._focusedIndex + 1); |
| 3861 }, | 4020 }, |
| 3862 | 4021 |
| 3863 _didEnter: function(e) { | 4022 _didEnter: function(e) { |
| 3864 this._focusPhysicalItem(this._focusedIndex); | 4023 this._focusPhysicalItem(this._focusedIndex); |
| 3865 this._selectionHandler(e.detail.keyboardEvent); | 4024 this._selectionHandler(e.detail.keyboardEvent); |
| 3866 } | 4025 } |
| 3867 }); | 4026 }); |
| 3868 | 4027 |
| 3869 })(); | 4028 })(); |
| (...skipping 3277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7147 * Given a KeyboardEvent, this method will focus the appropriate item in the | 7306 * Given a KeyboardEvent, this method will focus the appropriate item in the |
| 7148 * menu (if there is a relevant item, and it is possible to focus it). | 7307 * menu (if there is a relevant item, and it is possible to focus it). |
| 7149 * | 7308 * |
| 7150 * @param {KeyboardEvent} event A KeyboardEvent. | 7309 * @param {KeyboardEvent} event A KeyboardEvent. |
| 7151 */ | 7310 */ |
| 7152 _focusWithKeyboardEvent: function(event) { | 7311 _focusWithKeyboardEvent: function(event) { |
| 7153 for (var i = 0, item; item = this.items[i]; i++) { | 7312 for (var i = 0, item; item = this.items[i]; i++) { |
| 7154 var attr = this.attrForItemTitle || 'textContent'; | 7313 var attr = this.attrForItemTitle || 'textContent'; |
| 7155 var title = item[attr] || item.getAttribute(attr); | 7314 var title = item[attr] || item.getAttribute(attr); |
| 7156 | 7315 |
| 7157 if (title && title.trim().charAt(0).toLowerCase() === String.fromCharCod
e(event.keyCode).toLowerCase()) { | 7316 if (!item.hasAttribute('disabled') && title && |
| 7317 title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.k
eyCode).toLowerCase()) { |
| 7158 this._setFocusedItem(item); | 7318 this._setFocusedItem(item); |
| 7159 break; | 7319 break; |
| 7160 } | 7320 } |
| 7161 } | 7321 } |
| 7162 }, | 7322 }, |
| 7163 | 7323 |
| 7164 /** | 7324 /** |
| 7165 * Focuses the previous item (relative to the currently focused item) in the | 7325 * Focuses the previous item (relative to the currently focused item) in the |
| 7166 * menu. | 7326 * menu, disabled items will be skipped. |
| 7167 */ | 7327 */ |
| 7168 _focusPrevious: function() { | 7328 _focusPrevious: function() { |
| 7169 var length = this.items.length; | 7329 var length = this.items.length; |
| 7170 var index = (Number(this.indexOf(this.focusedItem)) - 1 + length) % length
; | 7330 var curFocusIndex = Number(this.indexOf(this.focusedItem)); |
| 7171 this._setFocusedItem(this.items[index]); | 7331 for (var i = 1; i < length; i++) { |
| 7332 var item = this.items[(curFocusIndex - i + length) % length]; |
| 7333 if (!item.hasAttribute('disabled')) { |
| 7334 this._setFocusedItem(item); |
| 7335 return; |
| 7336 } |
| 7337 } |
| 7172 }, | 7338 }, |
| 7173 | 7339 |
| 7174 /** | 7340 /** |
| 7175 * Focuses the next item (relative to the currently focused item) in the | 7341 * Focuses the next item (relative to the currently focused item) in the |
| 7176 * menu. | 7342 * menu, disabled items will be skipped. |
| 7177 */ | 7343 */ |
| 7178 _focusNext: function() { | 7344 _focusNext: function() { |
| 7179 var index = (Number(this.indexOf(this.focusedItem)) + 1) % this.items.leng
th; | 7345 var length = this.items.length; |
| 7180 this._setFocusedItem(this.items[index]); | 7346 var curFocusIndex = Number(this.indexOf(this.focusedItem)); |
| 7347 for (var i = 1; i < length; i++) { |
| 7348 var item = this.items[(curFocusIndex + i) % length]; |
| 7349 if (!item.hasAttribute('disabled')) { |
| 7350 this._setFocusedItem(item); |
| 7351 return; |
| 7352 } |
| 7353 } |
| 7181 }, | 7354 }, |
| 7182 | 7355 |
| 7183 /** | 7356 /** |
| 7184 * Mutates items in the menu based on provided selection details, so that | 7357 * Mutates items in the menu based on provided selection details, so that |
| 7185 * all items correctly reflect selection state. | 7358 * all items correctly reflect selection state. |
| 7186 * | 7359 * |
| 7187 * @param {Element} item An item in the menu. | 7360 * @param {Element} item An item in the menu. |
| 7188 * @param {boolean} isSelected True if the item should be shown in a | 7361 * @param {boolean} isSelected True if the item should be shown in a |
| 7189 * selected state, otherwise false. | 7362 * selected state, otherwise false. |
| 7190 */ | 7363 */ |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7279 this._defaultFocusAsync = this.async(function() { | 7452 this._defaultFocusAsync = this.async(function() { |
| 7280 // focus the selected item when the menu receives focus, or the first it
em | 7453 // focus the selected item when the menu receives focus, or the first it
em |
| 7281 // if no item is selected | 7454 // if no item is selected |
| 7282 var selectedItem = this.multi ? (this.selectedItems && this.selectedItem
s[0]) : this.selectedItem; | 7455 var selectedItem = this.multi ? (this.selectedItems && this.selectedItem
s[0]) : this.selectedItem; |
| 7283 | 7456 |
| 7284 this._setFocusedItem(null); | 7457 this._setFocusedItem(null); |
| 7285 | 7458 |
| 7286 if (selectedItem) { | 7459 if (selectedItem) { |
| 7287 this._setFocusedItem(selectedItem); | 7460 this._setFocusedItem(selectedItem); |
| 7288 } else if (this.items[0]) { | 7461 } else if (this.items[0]) { |
| 7289 this._setFocusedItem(this.items[0]); | 7462 // We find the first none-disabled item (if one exists) |
| 7463 this._focusNext(); |
| 7290 } | 7464 } |
| 7291 }); | 7465 }); |
| 7292 }, | 7466 }, |
| 7293 | 7467 |
| 7294 /** | 7468 /** |
| 7295 * Handler that is called when the up key is pressed. | 7469 * Handler that is called when the up key is pressed. |
| 7296 * | 7470 * |
| 7297 * @param {CustomEvent} event A key combination event. | 7471 * @param {CustomEvent} event A key combination event. |
| 7298 */ | 7472 */ |
| 7299 _onUpKey: function(event) { | 7473 _onUpKey: function(event) { |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7647 document.addEventListener('focus', this._onCaptureFocus.bind(this), true); | 7821 document.addEventListener('focus', this._onCaptureFocus.bind(this), true); |
| 7648 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true
); | 7822 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true
); |
| 7649 }; | 7823 }; |
| 7650 | 7824 |
| 7651 Polymer.IronOverlayManagerClass.prototype = { | 7825 Polymer.IronOverlayManagerClass.prototype = { |
| 7652 | 7826 |
| 7653 constructor: Polymer.IronOverlayManagerClass, | 7827 constructor: Polymer.IronOverlayManagerClass, |
| 7654 | 7828 |
| 7655 /** | 7829 /** |
| 7656 * The shared backdrop element. | 7830 * The shared backdrop element. |
| 7657 * @type {Element} backdropElement | 7831 * @type {!Element} backdropElement |
| 7658 */ | 7832 */ |
| 7659 get backdropElement() { | 7833 get backdropElement() { |
| 7660 if (!this._backdropElement) { | 7834 if (!this._backdropElement) { |
| 7661 this._backdropElement = document.createElement('iron-overlay-backdrop'); | 7835 this._backdropElement = document.createElement('iron-overlay-backdrop'); |
| 7662 } | 7836 } |
| 7663 return this._backdropElement; | 7837 return this._backdropElement; |
| 7664 }, | 7838 }, |
| 7665 | 7839 |
| 7666 /** | 7840 /** |
| 7667 * The deepest active element. | 7841 * The deepest active element. |
| 7668 * @type {Element} activeElement the active element | 7842 * @type {!Element} activeElement the active element |
| 7669 */ | 7843 */ |
| 7670 get deepActiveElement() { | 7844 get deepActiveElement() { |
| 7671 // document.activeElement can be null | 7845 // document.activeElement can be null |
| 7672 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement | 7846 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement |
| 7673 // In case of null, default it to document.body. | 7847 // In case of null, default it to document.body. |
| 7674 var active = document.activeElement || document.body; | 7848 var active = document.activeElement || document.body; |
| 7675 while (active.root && Polymer.dom(active.root).activeElement) { | 7849 while (active.root && Polymer.dom(active.root).activeElement) { |
| 7676 active = Polymer.dom(active.root).activeElement; | 7850 active = Polymer.dom(active.root).activeElement; |
| 7677 } | 7851 } |
| 7678 return active; | 7852 return active; |
| 7679 }, | 7853 }, |
| 7680 | 7854 |
| 7681 /** | 7855 /** |
| 7682 * Brings the overlay at the specified index to the front. | 7856 * Brings the overlay at the specified index to the front. |
| 7683 * @param {number} i | 7857 * @param {number} i |
| 7684 * @private | 7858 * @private |
| 7685 */ | 7859 */ |
| 7686 _bringOverlayAtIndexToFront: function(i) { | 7860 _bringOverlayAtIndexToFront: function(i) { |
| 7687 var overlay = this._overlays[i]; | 7861 var overlay = this._overlays[i]; |
| 7862 if (!overlay) { |
| 7863 return; |
| 7864 } |
| 7688 var lastI = this._overlays.length - 1; | 7865 var lastI = this._overlays.length - 1; |
| 7866 var currentOverlay = this._overlays[lastI]; |
| 7689 // Ensure always-on-top overlay stays on top. | 7867 // Ensure always-on-top overlay stays on top. |
| 7690 if (!overlay.alwaysOnTop && this._overlays[lastI].alwaysOnTop) { | 7868 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { |
| 7691 lastI--; | 7869 lastI--; |
| 7692 } | 7870 } |
| 7693 // If already the top element, return. | 7871 // If already the top element, return. |
| 7694 if (!overlay || i >= lastI) { | 7872 if (i >= lastI) { |
| 7695 return; | 7873 return; |
| 7696 } | 7874 } |
| 7697 // Update z-index to be on top. | 7875 // Update z-index to be on top. |
| 7698 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ); | 7876 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ); |
| 7699 if (this._getZ(overlay) <= minimumZ) { | 7877 if (this._getZ(overlay) <= minimumZ) { |
| 7700 this._applyOverlayZ(overlay, minimumZ); | 7878 this._applyOverlayZ(overlay, minimumZ); |
| 7701 } | 7879 } |
| 7702 | 7880 |
| 7703 // Shift other overlays behind the new on top. | 7881 // Shift other overlays behind the new on top. |
| 7704 while (i < lastI) { | 7882 while (i < lastI) { |
| 7705 this._overlays[i] = this._overlays[i + 1]; | 7883 this._overlays[i] = this._overlays[i + 1]; |
| 7706 i++; | 7884 i++; |
| 7707 } | 7885 } |
| 7708 this._overlays[lastI] = overlay; | 7886 this._overlays[lastI] = overlay; |
| 7709 }, | 7887 }, |
| 7710 | 7888 |
| 7711 /** | 7889 /** |
| 7712 * Adds the overlay and updates its z-index if it's opened, or removes it if
it's closed. | 7890 * Adds the overlay and updates its z-index if it's opened, or removes it if
it's closed. |
| 7713 * Also updates the backdrop z-index. | 7891 * Also updates the backdrop z-index. |
| 7714 * @param {Element} overlay | 7892 * @param {!Element} overlay |
| 7715 */ | 7893 */ |
| 7716 addOrRemoveOverlay: function(overlay) { | 7894 addOrRemoveOverlay: function(overlay) { |
| 7717 if (overlay.opened) { | 7895 if (overlay.opened) { |
| 7718 this.addOverlay(overlay); | 7896 this.addOverlay(overlay); |
| 7719 } else { | 7897 } else { |
| 7720 this.removeOverlay(overlay); | 7898 this.removeOverlay(overlay); |
| 7721 } | 7899 } |
| 7722 this.trackBackdrop(); | 7900 this.trackBackdrop(); |
| 7723 }, | 7901 }, |
| 7724 | 7902 |
| 7725 /** | 7903 /** |
| 7726 * Tracks overlays for z-index and focus management. | 7904 * Tracks overlays for z-index and focus management. |
| 7727 * Ensures the last added overlay with always-on-top remains on top. | 7905 * Ensures the last added overlay with always-on-top remains on top. |
| 7728 * @param {Element} overlay | 7906 * @param {!Element} overlay |
| 7729 */ | 7907 */ |
| 7730 addOverlay: function(overlay) { | 7908 addOverlay: function(overlay) { |
| 7731 var i = this._overlays.indexOf(overlay); | 7909 var i = this._overlays.indexOf(overlay); |
| 7732 if (i >= 0) { | 7910 if (i >= 0) { |
| 7733 this._bringOverlayAtIndexToFront(i); | 7911 this._bringOverlayAtIndexToFront(i); |
| 7734 return; | 7912 return; |
| 7735 } | 7913 } |
| 7736 var insertionIndex = this._overlays.length; | 7914 var insertionIndex = this._overlays.length; |
| 7737 var currentOverlay = this._overlays[insertionIndex - 1]; | 7915 var currentOverlay = this._overlays[insertionIndex - 1]; |
| 7738 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); | 7916 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); |
| 7739 var newZ = this._getZ(overlay); | 7917 var newZ = this._getZ(overlay); |
| 7740 | 7918 |
| 7741 // Ensure always-on-top overlay stays on top. | 7919 // Ensure always-on-top overlay stays on top. |
| 7742 if (currentOverlay && currentOverlay.alwaysOnTop && !overlay.alwaysOnTop)
{ | 7920 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { |
| 7743 // This bumps the z-index of +2. | 7921 // This bumps the z-index of +2. |
| 7744 this._applyOverlayZ(currentOverlay, minimumZ); | 7922 this._applyOverlayZ(currentOverlay, minimumZ); |
| 7745 insertionIndex--; | 7923 insertionIndex--; |
| 7746 // Update minimumZ to match previous overlay's z-index. | 7924 // Update minimumZ to match previous overlay's z-index. |
| 7747 var previousOverlay = this._overlays[insertionIndex - 1]; | 7925 var previousOverlay = this._overlays[insertionIndex - 1]; |
| 7748 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); | 7926 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); |
| 7749 } | 7927 } |
| 7750 | 7928 |
| 7751 // Update z-index and insert overlay. | 7929 // Update z-index and insert overlay. |
| 7752 if (newZ <= minimumZ) { | 7930 if (newZ <= minimumZ) { |
| 7753 this._applyOverlayZ(overlay, minimumZ); | 7931 this._applyOverlayZ(overlay, minimumZ); |
| 7754 } | 7932 } |
| 7755 this._overlays.splice(insertionIndex, 0, overlay); | 7933 this._overlays.splice(insertionIndex, 0, overlay); |
| 7756 | 7934 |
| 7757 // Get focused node. | 7935 // Get focused node. |
| 7758 var element = this.deepActiveElement; | 7936 var element = this.deepActiveElement; |
| 7759 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; | 7937 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; |
| 7760 }, | 7938 }, |
| 7761 | 7939 |
| 7762 /** | 7940 /** |
| 7763 * @param {Element} overlay | 7941 * @param {!Element} overlay |
| 7764 */ | 7942 */ |
| 7765 removeOverlay: function(overlay) { | 7943 removeOverlay: function(overlay) { |
| 7766 var i = this._overlays.indexOf(overlay); | 7944 var i = this._overlays.indexOf(overlay); |
| 7767 if (i === -1) { | 7945 if (i === -1) { |
| 7768 return; | 7946 return; |
| 7769 } | 7947 } |
| 7770 this._overlays.splice(i, 1); | 7948 this._overlays.splice(i, 1); |
| 7771 | 7949 |
| 7772 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; | 7950 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; |
| 7773 overlay.restoreFocusNode = null; | 7951 overlay.restoreFocusNode = null; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7871 // Check if is a number | 8049 // Check if is a number |
| 7872 // Number.isNaN not supported in IE 10+ | 8050 // Number.isNaN not supported in IE 10+ |
| 7873 if (z1 === z1) { | 8051 if (z1 === z1) { |
| 7874 z = z1; | 8052 z = z1; |
| 7875 } | 8053 } |
| 7876 } | 8054 } |
| 7877 return z; | 8055 return z; |
| 7878 }, | 8056 }, |
| 7879 | 8057 |
| 7880 /** | 8058 /** |
| 7881 * @param {Element} element | 8059 * @param {!Element} element |
| 7882 * @param {number|string} z | 8060 * @param {number|string} z |
| 7883 * @private | 8061 * @private |
| 7884 */ | 8062 */ |
| 7885 _setZ: function(element, z) { | 8063 _setZ: function(element, z) { |
| 7886 element.style.zIndex = z; | 8064 element.style.zIndex = z; |
| 7887 }, | 8065 }, |
| 7888 | 8066 |
| 7889 /** | 8067 /** |
| 7890 * @param {Element} overlay | 8068 * @param {!Element} overlay |
| 7891 * @param {number} aboveZ | 8069 * @param {number} aboveZ |
| 7892 * @private | 8070 * @private |
| 7893 */ | 8071 */ |
| 7894 _applyOverlayZ: function(overlay, aboveZ) { | 8072 _applyOverlayZ: function(overlay, aboveZ) { |
| 7895 this._setZ(overlay, aboveZ + 2); | 8073 this._setZ(overlay, aboveZ + 2); |
| 7896 }, | 8074 }, |
| 7897 | 8075 |
| 7898 /** | 8076 /** |
| 7899 * Returns the overlay containing the provided node. If the node is an overl
ay, | 8077 * Returns the overlay containing the provided node. If the node is an overl
ay, |
| 7900 * it returns the node. | 8078 * it returns the node. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7960 */ | 8138 */ |
| 7961 _onCaptureKeyDown: function(event) { | 8139 _onCaptureKeyDown: function(event) { |
| 7962 var overlay = /** @type {?} */ (this.currentOverlay()); | 8140 var overlay = /** @type {?} */ (this.currentOverlay()); |
| 7963 if (overlay) { | 8141 if (overlay) { |
| 7964 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc'))
{ | 8142 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc'))
{ |
| 7965 overlay._onCaptureEsc(event); | 8143 overlay._onCaptureEsc(event); |
| 7966 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,
'tab')) { | 8144 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,
'tab')) { |
| 7967 overlay._onCaptureTab(event); | 8145 overlay._onCaptureTab(event); |
| 7968 } | 8146 } |
| 7969 } | 8147 } |
| 8148 }, |
| 8149 |
| 8150 /** |
| 8151 * Returns if the overlay1 should be behind overlay2. |
| 8152 * @param {!Element} overlay1 |
| 8153 * @param {!Element} overlay2 |
| 8154 * @return {boolean} |
| 8155 * @private |
| 8156 */ |
| 8157 _shouldBeBehindOverlay: function(overlay1, overlay2) { |
| 8158 var o1 = /** @type {?} */ (overlay1); |
| 8159 var o2 = /** @type {?} */ (overlay2); |
| 8160 return !o1.alwaysOnTop && o2.alwaysOnTop; |
| 7970 } | 8161 } |
| 7971 }; | 8162 }; |
| 7972 | 8163 |
| 7973 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); | 8164 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); |
| 7974 (function() { | 8165 (function() { |
| 7975 | 8166 |
| 7976 Polymer({ | 8167 Polymer({ |
| 7977 | 8168 |
| 7978 is: 'iron-overlay-backdrop', | 8169 is: 'iron-overlay-backdrop', |
| 7979 | 8170 |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8359 if (!this._overlaySetup) { | 8550 if (!this._overlaySetup) { |
| 8360 return; | 8551 return; |
| 8361 } | 8552 } |
| 8362 | 8553 |
| 8363 this._manager.addOrRemoveOverlay(this); | 8554 this._manager.addOrRemoveOverlay(this); |
| 8364 | 8555 |
| 8365 this.__isAnimating = true; | 8556 this.__isAnimating = true; |
| 8366 | 8557 |
| 8367 // requestAnimationFrame for non-blocking rendering | 8558 // requestAnimationFrame for non-blocking rendering |
| 8368 if (this.__openChangedAsync) { | 8559 if (this.__openChangedAsync) { |
| 8369 cancelAnimationFrame(this.__openChangedAsync); | 8560 window.cancelAnimationFrame(this.__openChangedAsync); |
| 8370 } | 8561 } |
| 8371 if (this.opened) { | 8562 if (this.opened) { |
| 8372 if (this.withBackdrop) { | 8563 if (this.withBackdrop) { |
| 8373 this.backdropElement.prepare(); | 8564 this.backdropElement.prepare(); |
| 8374 } | 8565 } |
| 8375 this.__openChangedAsync = requestAnimationFrame(function() { | 8566 this.__openChangedAsync = window.requestAnimationFrame(function() { |
| 8376 this.__openChangedAsync = null; | 8567 this.__openChangedAsync = null; |
| 8377 this._prepareRenderOpened(); | 8568 this._prepareRenderOpened(); |
| 8378 this._renderOpened(); | 8569 this._renderOpened(); |
| 8379 }.bind(this)); | 8570 }.bind(this)); |
| 8380 } else { | 8571 } else { |
| 8381 this._renderClosed(); | 8572 this._renderClosed(); |
| 8382 } | 8573 } |
| 8383 }, | 8574 }, |
| 8384 | 8575 |
| 8385 _canceledChanged: function() { | 8576 _canceledChanged: function() { |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8576 this._focusedChild = nodeToSet; | 8767 this._focusedChild = nodeToSet; |
| 8577 } | 8768 } |
| 8578 }, | 8769 }, |
| 8579 | 8770 |
| 8580 /** | 8771 /** |
| 8581 * Refits if the overlay is opened and not animating. | 8772 * Refits if the overlay is opened and not animating. |
| 8582 * @protected | 8773 * @protected |
| 8583 */ | 8774 */ |
| 8584 _onIronResize: function() { | 8775 _onIronResize: function() { |
| 8585 if (this.__onIronResizeAsync) { | 8776 if (this.__onIronResizeAsync) { |
| 8586 cancelAnimationFrame(this.__onIronResizeAsync); | 8777 window.cancelAnimationFrame(this.__onIronResizeAsync); |
| 8587 this.__onIronResizeAsync = null; | 8778 this.__onIronResizeAsync = null; |
| 8588 } | 8779 } |
| 8589 if (this.opened && !this.__isAnimating) { | 8780 if (this.opened && !this.__isAnimating) { |
| 8590 this.__onIronResizeAsync = requestAnimationFrame(function() { | 8781 this.__onIronResizeAsync = window.requestAnimationFrame(function() { |
| 8591 this.__onIronResizeAsync = null; | 8782 this.__onIronResizeAsync = null; |
| 8592 this.refit(); | 8783 this.refit(); |
| 8593 }.bind(this)); | 8784 }.bind(this)); |
| 8594 } | 8785 } |
| 8595 }, | 8786 }, |
| 8596 | 8787 |
| 8597 /** | 8788 /** |
| 8598 * Will call notifyResize if overlay is opened. | 8789 * Will call notifyResize if overlay is opened. |
| 8599 * Can be overridden in order to avoid multiple observers on the same node. | 8790 * Can be overridden in order to avoid multiple observers on the same node. |
| 8600 * @protected | 8791 * @protected |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8651 return { | 8842 return { |
| 8652 duration: 500, | 8843 duration: 500, |
| 8653 easing: 'cubic-bezier(0.4, 0, 0.2, 1)', | 8844 easing: 'cubic-bezier(0.4, 0, 0.2, 1)', |
| 8654 fill: 'both' | 8845 fill: 'both' |
| 8655 } | 8846 } |
| 8656 } | 8847 } |
| 8657 } | 8848 } |
| 8658 | 8849 |
| 8659 }, | 8850 }, |
| 8660 | 8851 |
| 8661 registered: function() { | 8852 /** |
| 8662 new Polymer.IronMeta({type: 'animation', key: this.is, value: this.constru
ctor}); | 8853 * Can be used to determine that elements implement this behavior. |
| 8663 }, | 8854 */ |
| 8855 isNeonAnimation: true, |
| 8664 | 8856 |
| 8665 /** | 8857 /** |
| 8666 * Do any animation configuration here. | 8858 * Do any animation configuration here. |
| 8667 */ | 8859 */ |
| 8668 // configure: function(config) { | 8860 // configure: function(config) { |
| 8669 // }, | 8861 // }, |
| 8670 | 8862 |
| 8671 /** | 8863 /** |
| 8672 * Returns the animation timing by mixing in properties from `config` to the
defaults defined | 8864 * Returns the animation timing by mixing in properties from `config` to the
defaults defined |
| 8673 * by the animation. | 8865 * by the animation. |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8872 }; | 9064 }; |
| 8873 /** | 9065 /** |
| 8874 * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations. | 9066 * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations. |
| 8875 * | 9067 * |
| 8876 * @polymerBehavior Polymer.NeonAnimationRunnerBehavior | 9068 * @polymerBehavior Polymer.NeonAnimationRunnerBehavior |
| 8877 */ | 9069 */ |
| 8878 Polymer.NeonAnimationRunnerBehaviorImpl = { | 9070 Polymer.NeonAnimationRunnerBehaviorImpl = { |
| 8879 | 9071 |
| 8880 properties: { | 9072 properties: { |
| 8881 | 9073 |
| 8882 _animationMeta: { | |
| 8883 type: Object, | |
| 8884 value: function() { | |
| 8885 return new Polymer.IronMeta({type: 'animation'}); | |
| 8886 } | |
| 8887 }, | |
| 8888 | |
| 8889 /** @type {?Object} */ | 9074 /** @type {?Object} */ |
| 8890 _player: { | 9075 _player: { |
| 8891 type: Object | 9076 type: Object |
| 8892 } | 9077 } |
| 8893 | 9078 |
| 8894 }, | 9079 }, |
| 8895 | 9080 |
| 8896 _configureAnimationEffects: function(allConfigs) { | 9081 _configureAnimationEffects: function(allConfigs) { |
| 8897 var allAnimations = []; | 9082 var allAnimations = []; |
| 8898 if (allConfigs.length > 0) { | 9083 if (allConfigs.length > 0) { |
| 8899 for (var config, index = 0; config = allConfigs[index]; index++) { | 9084 for (var config, index = 0; config = allConfigs[index]; index++) { |
| 8900 var animationConstructor = this._animationMeta.byKey(config.name); | 9085 var animation = document.createElement(config.name); |
| 8901 if (animationConstructor) { | 9086 // is this element actually a neon animation? |
| 8902 var animation = animationConstructor && new animationConstructor(); | 9087 if (animation.isNeonAnimation) { |
| 8903 var effect = animation.configure(config); | 9088 var effect = animation.configure(config); |
| 8904 if (effect) { | 9089 if (effect) { |
| 8905 allAnimations.push({ | 9090 allAnimations.push({ |
| 8906 animation: animation, | 9091 animation: animation, |
| 8907 config: config, | 9092 config: config, |
| 8908 effect: effect | 9093 effect: effect |
| 8909 }); | 9094 }); |
| 8910 } | 9095 } |
| 8911 } else { | 9096 } else { |
| 8912 console.warn(this.is + ':', config.name, 'not found!'); | 9097 Polymer.Base._warn(this.is + ':', config.name, 'not found!'); |
| 8913 } | 9098 } |
| 8914 } | 9099 } |
| 8915 } | 9100 } |
| 8916 return allAnimations; | 9101 return allAnimations; |
| 8917 }, | 9102 }, |
| 8918 | 9103 |
| 8919 _runAnimationEffects: function(allEffects) { | 9104 _runAnimationEffects: function(allEffects) { |
| 8920 return document.timeline.play(new GroupEffect(allEffects)); | 9105 return document.timeline.play(new GroupEffect(allEffects)); |
| 8921 }, | 9106 }, |
| 8922 | 9107 |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9321 | 9506 |
| 9322 listeners: { | 9507 listeners: { |
| 9323 'neon-animation-finish': '_onNeonAnimationFinish' | 9508 'neon-animation-finish': '_onNeonAnimationFinish' |
| 9324 }, | 9509 }, |
| 9325 | 9510 |
| 9326 observers: [ | 9511 observers: [ |
| 9327 '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign
, verticalOffset, horizontalOffset)' | 9512 '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign
, verticalOffset, horizontalOffset)' |
| 9328 ], | 9513 ], |
| 9329 | 9514 |
| 9330 attached: function() { | 9515 attached: function() { |
| 9331 this.positionTarget = this.positionTarget || this._defaultPositionTarg
et; | |
| 9332 // Memoize this to avoid expensive calculations & relayouts. | 9516 // Memoize this to avoid expensive calculations & relayouts. |
| 9333 this._isRTL = window.getComputedStyle(this).direction == 'rtl'; | 9517 this._isRTL = window.getComputedStyle(this).direction == 'rtl'; |
| 9518 this.positionTarget = this.positionTarget || this._defaultPositionTarg
et; |
| 9334 }, | 9519 }, |
| 9335 | 9520 |
| 9336 /** | 9521 /** |
| 9337 * The element that is contained by the dropdown, if any. | 9522 * The element that is contained by the dropdown, if any. |
| 9338 */ | 9523 */ |
| 9339 get containedElement() { | 9524 get containedElement() { |
| 9340 return Polymer.dom(this.$.content).getDistributedNodes()[0]; | 9525 return Polymer.dom(this.$.content).getDistributedNodes()[0]; |
| 9341 }, | 9526 }, |
| 9342 | 9527 |
| 9343 /** | 9528 /** |
| (...skipping 27 matching lines...) Expand all Loading... |
| 9371 return this.horizontalAlign === 'right' ? 'left' : 'right'; | 9556 return this.horizontalAlign === 'right' ? 'left' : 'right'; |
| 9372 } else { | 9557 } else { |
| 9373 return this.horizontalAlign; | 9558 return this.horizontalAlign; |
| 9374 } | 9559 } |
| 9375 }, | 9560 }, |
| 9376 | 9561 |
| 9377 /** | 9562 /** |
| 9378 * The horizontal offset value used to position the dropdown. | 9563 * The horizontal offset value used to position the dropdown. |
| 9379 * @param {ClientRect} dropdownRect | 9564 * @param {ClientRect} dropdownRect |
| 9380 * @param {ClientRect} positionRect | 9565 * @param {ClientRect} positionRect |
| 9381 * @param {boolean=false} fromRight | 9566 * @param {boolean=} fromRight |
| 9382 * @return {number} pixels | 9567 * @return {number} pixels |
| 9383 * @private | 9568 * @private |
| 9384 */ | 9569 */ |
| 9385 _horizontalAlignTargetValue: function(dropdownRect, positionRect, fromRi
ght) { | 9570 _horizontalAlignTargetValue: function(dropdownRect, positionRect, fromRi
ght) { |
| 9386 var target; | 9571 var target; |
| 9387 if (fromRight) { | 9572 if (fromRight) { |
| 9388 target = document.documentElement.clientWidth - positionRect.right -
(this._fitWidth - dropdownRect.right); | 9573 target = document.documentElement.clientWidth - positionRect.right -
(this._fitWidth - dropdownRect.right); |
| 9389 } else { | 9574 } else { |
| 9390 target = positionRect.left - dropdownRect.left; | 9575 target = positionRect.left - dropdownRect.left; |
| 9391 } | 9576 } |
| 9392 target += this.horizontalOffset; | 9577 target += this.horizontalOffset; |
| 9393 | 9578 |
| 9394 return Math.max(target, 0); | 9579 return Math.max(target, 0); |
| 9395 }, | 9580 }, |
| 9396 | 9581 |
| 9397 /** | 9582 /** |
| 9398 * The vertical offset value used to position the dropdown. | 9583 * The vertical offset value used to position the dropdown. |
| 9399 * @param {ClientRect} dropdownRect | 9584 * @param {ClientRect} dropdownRect |
| 9400 * @param {ClientRect} positionRect | 9585 * @param {ClientRect} positionRect |
| 9401 * @param {boolean=false} fromBottom | 9586 * @param {boolean=} fromBottom |
| 9402 * @return {number} pixels | 9587 * @return {number} pixels |
| 9403 * @private | 9588 * @private |
| 9404 */ | 9589 */ |
| 9405 _verticalAlignTargetValue: function(dropdownRect, positionRect, fromBott
om) { | 9590 _verticalAlignTargetValue: function(dropdownRect, positionRect, fromBott
om) { |
| 9406 var target; | 9591 var target; |
| 9407 if (fromBottom) { | 9592 if (fromBottom) { |
| 9408 target = document.documentElement.clientHeight - positionRect.bottom
- (this._fitHeight - dropdownRect.bottom); | 9593 target = document.documentElement.clientHeight - positionRect.bottom
- (this._fitHeight - dropdownRect.bottom); |
| 9409 } else { | 9594 } else { |
| 9410 target = positionRect.top - dropdownRect.top; | 9595 target = positionRect.top - dropdownRect.top; |
| 9411 } | 9596 } |
| 9412 target += this.verticalOffset; | 9597 target += this.verticalOffset; |
| 9413 | 9598 |
| 9414 return Math.max(target, 0); | 9599 return Math.max(target, 0); |
| 9415 }, | 9600 }, |
| 9416 | 9601 |
| 9417 /** | 9602 /** |
| 9418 * Called when the value of `opened` changes. | 9603 * Called when the value of `opened` changes. |
| 9419 * | 9604 * Overridden from `IronOverlayBehavior` |
| 9420 * @param {boolean} opened True if the dropdown is opened. | |
| 9421 */ | 9605 */ |
| 9422 _openedChanged: function(opened) { | 9606 _openedChanged: function() { |
| 9423 if (opened && this.disabled) { | 9607 if (this.opened && this.disabled) { |
| 9424 this.cancel(); | 9608 this.cancel(); |
| 9425 } else { | 9609 } else { |
| 9426 this.cancelAnimation(); | 9610 this.cancelAnimation(); |
| 9427 this.sizingTarget = this.containedElement || this.sizingTarget; | 9611 this.sizingTarget = this.containedElement || this.sizingTarget; |
| 9428 this._updateAnimationConfig(); | 9612 this._updateAnimationConfig(); |
| 9613 if (this.opened && !this.allowOutsideScroll) { |
| 9614 Polymer.IronDropdownScrollManager.pushScrollLock(this); |
| 9615 } else { |
| 9616 Polymer.IronDropdownScrollManager.removeScrollLock(this); |
| 9617 } |
| 9429 Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments
); | 9618 Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments
); |
| 9430 } | 9619 } |
| 9431 }, | 9620 }, |
| 9432 | 9621 |
| 9433 /** | 9622 /** |
| 9434 * Overridden from `IronOverlayBehavior`. | 9623 * Overridden from `IronOverlayBehavior`. |
| 9435 */ | 9624 */ |
| 9436 _renderOpened: function() { | 9625 _renderOpened: function() { |
| 9437 if (!this.allowOutsideScroll) { | |
| 9438 Polymer.IronDropdownScrollManager.pushScrollLock(this); | |
| 9439 } | |
| 9440 | |
| 9441 if (!this.noAnimations && this.animationConfig && this.animationConfig
.open) { | 9626 if (!this.noAnimations && this.animationConfig && this.animationConfig
.open) { |
| 9442 if (this.withBackdrop) { | 9627 if (this.withBackdrop) { |
| 9443 this.backdropElement.open(); | 9628 this.backdropElement.open(); |
| 9444 } | 9629 } |
| 9445 this.$.contentWrapper.classList.add('animating'); | 9630 this.$.contentWrapper.classList.add('animating'); |
| 9446 this.playAnimation('open'); | 9631 this.playAnimation('open'); |
| 9447 } else { | 9632 } else { |
| 9448 Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments)
; | 9633 Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments)
; |
| 9449 } | 9634 } |
| 9450 }, | 9635 }, |
| 9451 | 9636 |
| 9452 /** | 9637 /** |
| 9453 * Overridden from `IronOverlayBehavior`. | 9638 * Overridden from `IronOverlayBehavior`. |
| 9454 */ | 9639 */ |
| 9455 _renderClosed: function() { | 9640 _renderClosed: function() { |
| 9456 Polymer.IronDropdownScrollManager.removeScrollLock(this); | |
| 9457 if (!this.noAnimations && this.animationConfig && this.animationConfig
.close) { | 9641 if (!this.noAnimations && this.animationConfig && this.animationConfig
.close) { |
| 9458 if (this.withBackdrop) { | 9642 if (this.withBackdrop) { |
| 9459 this.backdropElement.close(); | 9643 this.backdropElement.close(); |
| 9460 } | 9644 } |
| 9461 this.$.contentWrapper.classList.add('animating'); | 9645 this.$.contentWrapper.classList.add('animating'); |
| 9462 this.playAnimation('close'); | 9646 this.playAnimation('close'); |
| 9463 } else { | 9647 } else { |
| 9464 Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments)
; | 9648 Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments)
; |
| 9465 } | 9649 } |
| 9466 }, | 9650 }, |
| (...skipping 1725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11192 Manager.get().updateItem_(index, data); | 11376 Manager.get().updateItem_(index, data); |
| 11193 }; | 11377 }; |
| 11194 | 11378 |
| 11195 return {Manager: Manager}; | 11379 return {Manager: Manager}; |
| 11196 }); | 11380 }); |
| 11197 // Copyright 2015 The Chromium Authors. All rights reserved. | 11381 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 11198 // Use of this source code is governed by a BSD-style license that can be | 11382 // Use of this source code is governed by a BSD-style license that can be |
| 11199 // found in the LICENSE file. | 11383 // found in the LICENSE file. |
| 11200 | 11384 |
| 11201 window.addEventListener('load', downloads.Manager.onLoad); | 11385 window.addEventListener('load', downloads.Manager.onLoad); |
| OLD | NEW |