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

Side by Side Diff: chrome/browser/resources/md_downloads/crisper.js

Issue 1901343004: [Polymer] update third_party polymer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: new pull Created 4 years, 8 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
« no previous file with comments | « no previous file | chrome/browser/resources/md_downloads/vulcanized.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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);
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/md_downloads/vulcanized.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698