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

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

Issue 1862213002: Roll third_party/polymer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 PromiseResolver is a helper class that allows creating a 6 * @fileoverview PromiseResolver is a helper class that allows creating a
7 * Promise that will be fulfilled (resolved or rejected) some time later. 7 * Promise that will be fulfilled (resolved or rejected) some time later.
8 * 8 *
9 * Example: 9 * Example:
10 * var resolver = new PromiseResolver(); 10 * var resolver = new PromiseResolver();
(...skipping 2158 matching lines...) Expand 10 before | Expand all | Expand 10 after
2169 * @demo demo/scrolling-region.html Scrolling Region 2169 * @demo demo/scrolling-region.html Scrolling Region
2170 * @demo demo/document.html Document Element 2170 * @demo demo/document.html Document Element
2171 * @polymerBehavior 2171 * @polymerBehavior
2172 */ 2172 */
2173 Polymer.IronScrollTargetBehavior = { 2173 Polymer.IronScrollTargetBehavior = {
2174 2174
2175 properties: { 2175 properties: {
2176 2176
2177 /** 2177 /**
2178 * Specifies the element that will handle the scroll event 2178 * Specifies the element that will handle the scroll event
2179 * on the behalf of the current element. This is typically a reference to an `Element`, 2179 * on the behalf of the current element. This is typically a reference to an element,
2180 * but there are a few more posibilities: 2180 * but there are a few more posibilities:
2181 * 2181 *
2182 * ### Elements id 2182 * ### Elements id
2183 * 2183 *
2184 *```html 2184 *```html
2185 * <div id="scrollable-element" style="overflow-y: auto;"> 2185 * <div id="scrollable-element" style="overflow: auto;">
2186 * <x-element scroll-target="scrollable-element"> 2186 * <x-element scroll-target="scrollable-element">
2187 * Content 2187 * \x3c!-- Content--\x3e
2188 * </x-element> 2188 * </x-element>
2189 * </div> 2189 * </div>
2190 *``` 2190 *```
2191 * In this case, `scrollTarget` will point to the outer div element. Alter natively, 2191 * In this case, the `scrollTarget` will point to the outer div element.
2192 * you can set the property programatically: 2192 *
2193 * ### Document scrolling
2194 *
2195 * For document scrolling, you can use the reserved word `document`:
2196 *
2197 *```html
2198 * <x-element scroll-target="document">
2199 * \x3c!-- Content --\x3e
2200 * </x-element>
2201 *```
2202 *
2203 * ### Elements reference
2193 * 2204 *
2194 *```js 2205 *```js
2195 * appHeader.scrollTarget = document.querySelector('#scrollable-element'); 2206 * appHeader.scrollTarget = document.querySelector('#scrollable-element');
2196 *``` 2207 *```
2197 * 2208 *
2198 * @type {HTMLElement} 2209 * @type {HTMLElement}
2199 */ 2210 */
2200 scrollTarget: { 2211 scrollTarget: {
2201 type: HTMLElement, 2212 type: HTMLElement,
2202 value: function() { 2213 value: function() {
2203 return this._defaultScrollTarget; 2214 return this._defaultScrollTarget;
2204 } 2215 }
2205 } 2216 }
2206 }, 2217 },
2207 2218
2208 observers: [ 2219 observers: [
2209 '_scrollTargetChanged(scrollTarget, isAttached)' 2220 '_scrollTargetChanged(scrollTarget, isAttached)'
2210 ], 2221 ],
2211 2222
2212 _scrollTargetChanged: function(scrollTarget, isAttached) { 2223 _scrollTargetChanged: function(scrollTarget, isAttached) {
2213 // Remove lister to the current scroll target 2224 var eventTarget;
2225
2214 if (this._oldScrollTarget) { 2226 if (this._oldScrollTarget) {
2215 if (this._oldScrollTarget === this._doc) { 2227 eventTarget = this._oldScrollTarget === this._doc ? window : this._oldSc rollTarget;
2216 window.removeEventListener('scroll', this._boundScrollHandler); 2228 eventTarget.removeEventListener('scroll', this._boundScrollHandler);
2217 } else if (this._oldScrollTarget.removeEventListener) {
2218 this._oldScrollTarget.removeEventListener('scroll', this._boundScrollH andler);
2219 }
2220 this._oldScrollTarget = null; 2229 this._oldScrollTarget = null;
2221 } 2230 }
2222 if (isAttached) {
2223 // Support element id references
2224 if (typeof scrollTarget === 'string') {
2225 2231
2226 var host = this.domHost; 2232 if (!isAttached) {
2227 this.scrollTarget = host && host.$ ? host.$[scrollTarget] : 2233 return;
2228 Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget); 2234 }
2235 // Support element id references
2236 if (scrollTarget === 'document') {
2229 2237
2230 } else if (this._scrollHandler) { 2238 this.scrollTarget = this._doc;
2231 2239
2232 this._boundScrollHandler = this._boundScrollHandler || this._scrollHan dler.bind(this); 2240 } else if (typeof scrollTarget === 'string') {
2233 // Add a new listener 2241
2234 if (scrollTarget === this._doc) { 2242 this.scrollTarget = this.domHost ? this.domHost.$[scrollTarget] :
2235 window.addEventListener('scroll', this._boundScrollHandler); 2243 Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
2236 if (this._scrollTop !== 0 || this._scrollLeft !== 0) { 2244
2237 this._scrollHandler(); 2245 } else if (this._isValidScrollTarget()) {
2238 } 2246
2239 } else if (scrollTarget && scrollTarget.addEventListener) { 2247 eventTarget = scrollTarget === this._doc ? window : scrollTarget;
2240 scrollTarget.addEventListener('scroll', this._boundScrollHandler); 2248 this._boundScrollHandler = this._boundScrollHandler || this._scrollHandl er.bind(this);
2241 } 2249 this._oldScrollTarget = scrollTarget;
2242 this._oldScrollTarget = scrollTarget; 2250
2243 } 2251 eventTarget.addEventListener('scroll', this._boundScrollHandler);
2244 } 2252 }
2245 }, 2253 },
2246 2254
2247 /** 2255 /**
2248 * Runs on every scroll event. Consumer of this behavior may want to overrid e this method. 2256 * Runs on every scroll event. Consumer of this behavior may override this m ethod.
2249 * 2257 *
2250 * @protected 2258 * @protected
2251 */ 2259 */
2252 _scrollHandler: function scrollHandler() {}, 2260 _scrollHandler: function scrollHandler() {},
2253 2261
2254 /** 2262 /**
2255 * The default scroll target. Consumers of this behavior may want to customi ze 2263 * The default scroll target. Consumers of this behavior may want to customi ze
2256 * the default scroll target. 2264 * the default scroll target.
2257 * 2265 *
2258 * @type {Element} 2266 * @type {Element}
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
2465 '_setOverflow(scrollTarget)' 2473 '_setOverflow(scrollTarget)'
2466 ], 2474 ],
2467 2475
2468 behaviors: [ 2476 behaviors: [
2469 Polymer.Templatizer, 2477 Polymer.Templatizer,
2470 Polymer.IronResizableBehavior, 2478 Polymer.IronResizableBehavior,
2471 Polymer.IronA11yKeysBehavior, 2479 Polymer.IronA11yKeysBehavior,
2472 Polymer.IronScrollTargetBehavior 2480 Polymer.IronScrollTargetBehavior
2473 ], 2481 ],
2474 2482
2475 listeners: {
2476 'iron-resize': '_resizeHandler'
2477 },
2478
2479 keyBindings: { 2483 keyBindings: {
2480 'up': '_didMoveUp', 2484 'up': '_didMoveUp',
2481 'down': '_didMoveDown', 2485 'down': '_didMoveDown',
2482 'enter': '_didEnter' 2486 'enter': '_didEnter'
2483 }, 2487 },
2484 2488
2485 /** 2489 /**
2486 * The ratio of hidden tiles that should remain in the scroll direction. 2490 * The ratio of hidden tiles that should remain in the scroll direction.
2487 * Recommended value ~0.5, so it will distribute tiles evely in both directi ons. 2491 * Recommended value ~0.5, so it will distribute tiles evely in both directi ons.
2488 */ 2492 */
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
2772 return this; 2776 return this;
2773 }, 2777 },
2774 2778
2775 ready: function() { 2779 ready: function() {
2776 this.addEventListener('focus', this._didFocus.bind(this), true); 2780 this.addEventListener('focus', this._didFocus.bind(this), true);
2777 }, 2781 },
2778 2782
2779 attached: function() { 2783 attached: function() {
2780 this.updateViewportBoundaries(); 2784 this.updateViewportBoundaries();
2781 this._render(); 2785 this._render();
2786 // `iron-resize` is fired when the list is attached if the event is added
2787 // before attached causing unnecessary work.
2788 this.listen(this, 'iron-resize', '_resizeHandler');
2782 }, 2789 },
2783 2790
2784 detached: function() { 2791 detached: function() {
2785 this._itemsRendered = false; 2792 this._itemsRendered = false;
2793 this.unlisten(this, 'iron-resize', '_resizeHandler');
2786 }, 2794 },
2787 2795
2788 /** 2796 /**
2789 * Set the overflow property if this element has its own scrolling region 2797 * Set the overflow property if this element has its own scrolling region
2790 */ 2798 */
2791 _setOverflow: function(scrollTarget) { 2799 _setOverflow: function(scrollTarget) {
2792 this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : ''; 2800 this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
2793 this.style.overflow = scrollTarget === this ? 'auto' : ''; 2801 this.style.overflow = scrollTarget === this ? 'auto' : '';
2794 }, 2802 },
2795 2803
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
2896 currentRatio += tileHeight / hiddenContentSize; 2904 currentRatio += tileHeight / hiddenContentSize;
2897 2905
2898 this._physicalTop += tileHeight; 2906 this._physicalTop += tileHeight;
2899 recycledTileSet.push(kth); 2907 recycledTileSet.push(kth);
2900 recycledTiles++; 2908 recycledTiles++;
2901 kth = (kth + 1) % this._physicalCount; 2909 kth = (kth + 1) % this._physicalCount;
2902 } 2910 }
2903 } 2911 }
2904 2912
2905 if (recycledTiles === 0) { 2913 if (recycledTiles === 0) {
2906 // If the list ever reach this case, the physical average is not signifi cant enough 2914 // Try to increase the pool if the list's client height isn't filled up with physical items
2907 // to create all the items needed to cover the entire viewport.
2908 // e.g. A few items have a height that differs from the average by serve ral order of magnitude.
2909 if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) { 2915 if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
2910 this.async(this._increasePool.bind(this, 1)); 2916 this._increasePoolIfNeeded();
2911 } 2917 }
2912 } else { 2918 } else {
2913 this._virtualStart = this._virtualStart + recycledTiles; 2919 this._virtualStart = this._virtualStart + recycledTiles;
2914 this._physicalStart = this._physicalStart + recycledTiles; 2920 this._physicalStart = this._physicalStart + recycledTiles;
2915 this._update(recycledTileSet, movingUp); 2921 this._update(recycledTileSet, movingUp);
2916 } 2922 }
2917 }, 2923 },
2918 2924
2919 /** 2925 /**
2920 * Update the list of items, starting from the `_virtualStart` item. 2926 * Update the list of items, starting from the `_virtualStart` item.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2955 // First element child is item; Safari doesn't support children[0] 2961 // First element child is item; Safari doesn't support children[0]
2956 // on a doc fragment 2962 // on a doc fragment
2957 physicalItems[i] = inst.root.querySelector('*'); 2963 physicalItems[i] = inst.root.querySelector('*');
2958 Polymer.dom(this).appendChild(inst.root); 2964 Polymer.dom(this).appendChild(inst.root);
2959 } 2965 }
2960 return physicalItems; 2966 return physicalItems;
2961 }, 2967 },
2962 2968
2963 /** 2969 /**
2964 * Increases the pool of physical items only if needed. 2970 * Increases the pool of physical items only if needed.
2965 * This function will allocate additional physical items 2971 *
2966 * if the physical size is shorter than `_optPhysicalSize` 2972 * @return {boolean} True if the pool was increased.
2967 */ 2973 */
2968 _increasePoolIfNeeded: function() { 2974 _increasePoolIfNeeded: function() {
2969 if (this._viewportSize === 0 || this._physicalSize >= this._optPhysicalSiz e) { 2975 // Base case 1: the list has no size.
2976 if (this._viewportSize === 0) {
2970 return false; 2977 return false;
2971 } 2978 }
2972 // 0 <= `currentPage` <= `_maxPages` 2979 // Base case 2: If the physical size is optimal and the list's client heig ht is full
2980 // with physical items, don't increase the pool.
2981 var isClientHeightFull = this._physicalBottom >= this._scrollBottom && thi s._physicalTop <= this._scrollPosition;
2982 if (this._physicalSize >= this._optPhysicalSize && isClientHeightFull) {
2983 return false;
2984 }
2985 // this value should range between [0 <= `currentPage` <= `_maxPages`]
2973 var currentPage = Math.floor(this._physicalSize / this._viewportSize); 2986 var currentPage = Math.floor(this._physicalSize / this._viewportSize);
2987
2974 if (currentPage === 0) { 2988 if (currentPage === 0) {
2975 // fill the first page 2989 // fill the first page
2976 this._debounceTemplate(this._increasePool.bind(this, Math.round(this._ph ysicalCount * 0.5))); 2990 this._debounceTemplate(this._increasePool.bind(this, Math.round(this._ph ysicalCount * 0.5)));
2977 } else if (this._lastPage !== currentPage) { 2991 } else if (this._lastPage !== currentPage && isClientHeightFull) {
2978 // paint the page and defer the next increase 2992 // paint the page and defer the next increase
2979 // wait 16ms which is rough enough to get paint cycle. 2993 // wait 16ms which is rough enough to get paint cycle.
2980 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increa sePool.bind(this, 1), 16)); 2994 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increa sePool.bind(this, 1), 16));
2981 } else { 2995 } else {
2982 // fill the rest of the pages 2996 // fill the rest of the pages
2983 this._debounceTemplate(this._increasePool.bind(this, 1)); 2997 this._debounceTemplate(this._increasePool.bind(this, 1));
2984 } 2998 }
2999
2985 this._lastPage = currentPage; 3000 this._lastPage = currentPage;
3001
2986 return true; 3002 return true;
2987 }, 3003 },
2988 3004
2989 /** 3005 /**
2990 * Increases the pool size. 3006 * Increases the pool size.
2991 */ 3007 */
2992 _increasePool: function(missingItems) { 3008 _increasePool: function(missingItems) {
2993 var nextPhysicalCount = Math.min( 3009 var nextPhysicalCount = Math.min(
2994 this._physicalCount + missingItems, 3010 this._physicalCount + missingItems,
2995 this._virtualCount - this._virtualStart, 3011 this._virtualCount - this._virtualStart,
(...skipping 25 matching lines...) Expand all
3021 /** 3037 /**
3022 * Render a new list of items. This method does exactly the same as `update` , 3038 * Render a new list of items. This method does exactly the same as `update` ,
3023 * but it also ensures that only one `update` cycle is created. 3039 * but it also ensures that only one `update` cycle is created.
3024 */ 3040 */
3025 _render: function() { 3041 _render: function() {
3026 var requiresUpdate = this._virtualCount > 0 || this._physicalCount > 0; 3042 var requiresUpdate = this._virtualCount > 0 || this._physicalCount > 0;
3027 3043
3028 if (this.isAttached && !this._itemsRendered && this._isVisible && requires Update) { 3044 if (this.isAttached && !this._itemsRendered && this._isVisible && requires Update) {
3029 this._lastPage = 0; 3045 this._lastPage = 0;
3030 this._update(); 3046 this._update();
3031 this._scrollHandler();
3032 this._itemsRendered = true; 3047 this._itemsRendered = true;
3033 } 3048 }
3034 }, 3049 },
3035 3050
3036 /** 3051 /**
3037 * Templetizes the user template. 3052 * Templetizes the user template.
3038 */ 3053 */
3039 _ensureTemplatized: function() { 3054 _ensureTemplatized: function() {
3040 if (!this.ctor) { 3055 if (!this.ctor) {
3041 // Template instance props that should be excluded from forwarding 3056 // Template instance props that should be excluded from forwarding
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
3116 var idx = this._physicalIndexForKey[key]; 3131 var idx = this._physicalIndexForKey[key];
3117 var el = this._physicalItems[idx]; 3132 var el = this._physicalItems[idx];
3118 3133
3119 3134
3120 if (idx === this._focusedIndex && this._offscreenFocusedItem) { 3135 if (idx === this._focusedIndex && this._offscreenFocusedItem) {
3121 el = this._offscreenFocusedItem; 3136 el = this._offscreenFocusedItem;
3122 } 3137 }
3123 if (!el) { 3138 if (!el) {
3124 return; 3139 return;
3125 } 3140 }
3126 3141
3127 inst = el._templateInstance; 3142 inst = el._templateInstance;
3128 3143
3129 if (inst.__key__ !== key) { 3144 if (inst.__key__ !== key) {
3130 return; 3145 return;
3131 } 3146 }
3132 if (dot >= 0) { 3147 if (dot >= 0) {
3133 path = this.as + '.' + path.substring(dot+1); 3148 path = this.as + '.' + path.substring(dot+1);
3134 inst.notifyPath(path, value, true); 3149 inst.notifyPath(path, value, true);
3135 } else { 3150 } else {
3136 inst[this.as] = value; 3151 inst[this.as] = value;
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
3400 while (currentVirtualItem < idx && targetOffsetTop < hiddenContentSize) { 3415 while (currentVirtualItem < idx && targetOffsetTop < hiddenContentSize) {
3401 targetOffsetTop = targetOffsetTop + this._physicalSizes[currentTopItem]; 3416 targetOffsetTop = targetOffsetTop + this._physicalSizes[currentTopItem];
3402 currentTopItem = (currentTopItem + 1) % this._physicalCount; 3417 currentTopItem = (currentTopItem + 1) % this._physicalCount;
3403 currentVirtualItem++; 3418 currentVirtualItem++;
3404 } 3419 }
3405 // update the scroller size 3420 // update the scroller size
3406 this._updateScrollerSize(true); 3421 this._updateScrollerSize(true);
3407 // update the position of the items 3422 // update the position of the items
3408 this._positionItems(); 3423 this._positionItems();
3409 // set the new scroll position 3424 // set the new scroll position
3410 this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + t argetOffsetTop + 1); 3425 this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + t argetOffsetTop);
3411 // increase the pool of physical items if needed 3426 // increase the pool of physical items if needed
3412 this._increasePoolIfNeeded(); 3427 this._increasePoolIfNeeded();
3413 // clear cached visible index 3428 // clear cached visible index
3414 this._firstVisibleIndexVal = null; 3429 this._firstVisibleIndexVal = null;
3415 this._lastVisibleIndexVal = null; 3430 this._lastVisibleIndexVal = null;
3416 }, 3431 },
3417 3432
3418 /** 3433 /**
3419 * Reset the physical average and the average count. 3434 * Reset the physical average and the average count.
3420 */ 3435 */
3421 _resetAverage: function() { 3436 _resetAverage: function() {
3422 this._physicalAverage = 0; 3437 this._physicalAverage = 0;
3423 this._physicalAverageCount = 0; 3438 this._physicalAverageCount = 0;
3424 }, 3439 },
3425 3440
3426 /** 3441 /**
3427 * A handler for the `iron-resize` event triggered by `IronResizableBehavior ` 3442 * A handler for the `iron-resize` event triggered by `IronResizableBehavior `
3428 * when the element is resized. 3443 * when the element is resized.
3429 */ 3444 */
3430 _resizeHandler: function() { 3445 _resizeHandler: function() {
3431 // iOS fires the resize event when the address bar slides up 3446 // iOS fires the resize event when the address bar slides up
3432 if (IOS && Math.abs(this._viewportSize - this._scrollTargetHeight) < 100) { 3447 if (IOS && Math.abs(this._viewportSize - this._scrollTargetHeight) < 100) {
3433 return; 3448 return;
3434 } 3449 }
3435 this._debounceTemplate(function() { 3450 // In Desktop Safari 9.0.3, if the scroll bars are always shown,
3436 this._render(); 3451 // changing the scroll position from a resize handler would result in
3437 if (this._itemsRendered && this._physicalItems && this._isVisible) { 3452 // the scroll position being reset. Waiting 1ms fixes the issue.
3438 this._resetAverage(); 3453 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate',
3439 this.updateViewportBoundaries(); 3454 function() {
3440 this.scrollToIndex(this.firstVisibleIndex); 3455 this._render();
3441 } 3456
3442 }); 3457 if (this._itemsRendered && this._physicalItems && this._isVisible) {
3458 this._resetAverage();
3459 this.updateViewportBoundaries();
3460 this.scrollToIndex(this.firstVisibleIndex);
3461 }
3462 }.bind(this), 1));
3443 }, 3463 },
3444 3464
3445 _getModelFromItem: function(item) { 3465 _getModelFromItem: function(item) {
3446 var key = this._collection.getKey(item); 3466 var key = this._collection.getKey(item);
3447 var pidx = this._physicalIndexForKey[key]; 3467 var pidx = this._physicalIndexForKey[key];
3448 3468
3449 if (pidx != null) { 3469 if (pidx != null) {
3450 return this._physicalItems[pidx]._templateInstance; 3470 return this._physicalItems[pidx]._templateInstance;
3451 } 3471 }
3452 return null; 3472 return null;
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
3754 this._focusPhysicalItem(this._focusedIndex + 1); 3774 this._focusPhysicalItem(this._focusedIndex + 1);
3755 }, 3775 },
3756 3776
3757 _didEnter: function(e) { 3777 _didEnter: function(e) {
3758 this._focusPhysicalItem(this._focusedIndex); 3778 this._focusPhysicalItem(this._focusedIndex);
3759 this._selectionHandler(e.detail.keyboardEvent); 3779 this._selectionHandler(e.detail.keyboardEvent);
3760 } 3780 }
3761 }); 3781 });
3762 3782
3763 })(); 3783 })();
3764 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
3765 // Use of this source code is governed by a BSD-style license that can be
3766 // found in the LICENSE file.
3767
3768 /**
3769 * @fileoverview Assertion support.
3770 */
3771
3772 /**
3773 * Verify |condition| is truthy and return |condition| if so.
3774 * @template T
3775 * @param {T} condition A condition to check for truthiness. Note that this
3776 * may be used to test whether a value is defined or not, and we don't want
3777 * to force a cast to Boolean.
3778 * @param {string=} opt_message A message to show on failure.
3779 * @return {T} A non-null |condition|.
3780 */
3781 function assert(condition, opt_message) {
3782 if (!condition) {
3783 var message = 'Assertion failed';
3784 if (opt_message)
3785 message = message + ': ' + opt_message;
3786 var error = new Error(message);
3787 var global = function() { return this; }();
3788 if (global.traceAssertionsForTesting)
3789 console.warn(error.stack);
3790 throw error;
3791 }
3792 return condition;
3793 }
3794
3795 /**
3796 * Call this from places in the code that should never be reached.
3797 *
3798 * For example, handling all the values of enum with a switch() like this:
3799 *
3800 * function getValueFromEnum(enum) {
3801 * switch (enum) {
3802 * case ENUM_FIRST_OF_TWO:
3803 * return first
3804 * case ENUM_LAST_OF_TWO:
3805 * return last;
3806 * }
3807 * assertNotReached();
3808 * return document;
3809 * }
3810 *
3811 * This code should only be hit in the case of serious programmer error or
3812 * unexpected input.
3813 *
3814 * @param {string=} opt_message A message to show when this is hit.
3815 */
3816 function assertNotReached(opt_message) {
3817 assert(false, opt_message || 'Unreachable code hit');
3818 }
3819
3820 /**
3821 * @param {*} value The value to check.
3822 * @param {function(new: T, ...)} type A user-defined constructor.
3823 * @param {string=} opt_message A message to show when this is hit.
3824 * @return {T}
3825 * @template T
3826 */
3827 function assertInstanceof(value, type, opt_message) {
3828 // We don't use assert immediately here so that we avoid constructing an error
3829 // message if we don't have to.
3830 if (!(value instanceof type)) {
3831 assertNotReached(opt_message || 'Value ' + value +
3832 ' is not a[n] ' + (type.name || typeof type));
3833 }
3834 return value;
3835 };
3836 // Copyright 2015 The Chromium Authors. All rights reserved. 3784 // Copyright 2015 The Chromium Authors. All rights reserved.
3837 // Use of this source code is governed by a BSD-style license that can be 3785 // Use of this source code is governed by a BSD-style license that can be
3838 // found in the LICENSE file. 3786 // found in the LICENSE file.
3839 3787
3840 cr.define('downloads', function() { 3788 cr.define('downloads', function() {
3841 /** 3789 /**
3842 * @param {string} chromeSendName 3790 * @param {string} chromeSendName
3843 * @return {function(string):void} A chrome.send() callback with curried name. 3791 * @return {function(string):void} A chrome.send() callback with curried name.
3844 */ 3792 */
3845 function chromeSendWithId(chromeSendName) { 3793 function chromeSendWithId(chromeSendName) {
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
3959 show: chromeSendWithId('show'), 3907 show: chromeSendWithId('show'),
3960 3908
3961 /** Undo download removal. */ 3909 /** Undo download removal. */
3962 undo: chrome.send.bind(chrome, 'undo'), 3910 undo: chrome.send.bind(chrome, 'undo'),
3963 }; 3911 };
3964 3912
3965 cr.addSingletonGetter(ActionService); 3913 cr.addSingletonGetter(ActionService);
3966 3914
3967 return {ActionService: ActionService}; 3915 return {ActionService: ActionService};
3968 }); 3916 });
3917 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
3918 // Use of this source code is governed by a BSD-style license that can be
3919 // found in the LICENSE file.
3920
3921 /**
3922 * @fileoverview Assertion support.
3923 */
3924
3925 /**
3926 * Verify |condition| is truthy and return |condition| if so.
3927 * @template T
3928 * @param {T} condition A condition to check for truthiness. Note that this
3929 * may be used to test whether a value is defined or not, and we don't want
3930 * to force a cast to Boolean.
3931 * @param {string=} opt_message A message to show on failure.
3932 * @return {T} A non-null |condition|.
3933 */
3934 function assert(condition, opt_message) {
3935 if (!condition) {
3936 var message = 'Assertion failed';
3937 if (opt_message)
3938 message = message + ': ' + opt_message;
3939 var error = new Error(message);
3940 var global = function() { return this; }();
3941 if (global.traceAssertionsForTesting)
3942 console.warn(error.stack);
3943 throw error;
3944 }
3945 return condition;
3946 }
3947
3948 /**
3949 * Call this from places in the code that should never be reached.
3950 *
3951 * For example, handling all the values of enum with a switch() like this:
3952 *
3953 * function getValueFromEnum(enum) {
3954 * switch (enum) {
3955 * case ENUM_FIRST_OF_TWO:
3956 * return first
3957 * case ENUM_LAST_OF_TWO:
3958 * return last;
3959 * }
3960 * assertNotReached();
3961 * return document;
3962 * }
3963 *
3964 * This code should only be hit in the case of serious programmer error or
3965 * unexpected input.
3966 *
3967 * @param {string=} opt_message A message to show when this is hit.
3968 */
3969 function assertNotReached(opt_message) {
3970 assert(false, opt_message || 'Unreachable code hit');
3971 }
3972
3973 /**
3974 * @param {*} value The value to check.
3975 * @param {function(new: T, ...)} type A user-defined constructor.
3976 * @param {string=} opt_message A message to show when this is hit.
3977 * @return {T}
3978 * @template T
3979 */
3980 function assertInstanceof(value, type, opt_message) {
3981 // We don't use assert immediately here so that we avoid constructing an error
3982 // message if we don't have to.
3983 if (!(value instanceof type)) {
3984 assertNotReached(opt_message || 'Value ' + value +
3985 ' is not a[n] ' + (type.name || typeof type));
3986 }
3987 return value;
3988 };
3969 // Copyright 2015 The Chromium Authors. All rights reserved. 3989 // Copyright 2015 The Chromium Authors. All rights reserved.
3970 // Use of this source code is governed by a BSD-style license that can be 3990 // Use of this source code is governed by a BSD-style license that can be
3971 // found in the LICENSE file. 3991 // found in the LICENSE file.
3972 3992
3973 cr.define('downloads', function() { 3993 cr.define('downloads', function() {
3974 /** 3994 /**
3975 * Explains why a download is in DANGEROUS state. 3995 * Explains why a download is in DANGEROUS state.
3976 * @enum {string} 3996 * @enum {string}
3977 */ 3997 */
3978 var DangerType = { 3998 var DangerType = {
(...skipping 2571 matching lines...) Expand 10 before | Expand all | Expand 10 after
6550 * Fired when the list of selectable items changes (e.g., items are 6570 * Fired when the list of selectable items changes (e.g., items are
6551 * added or removed). The detail of the event is a list of mutation 6571 * added or removed). The detail of the event is a list of mutation
6552 * records that describe what changed. 6572 * records that describe what changed.
6553 * 6573 *
6554 * @event iron-items-changed 6574 * @event iron-items-changed
6555 */ 6575 */
6556 6576
6557 properties: { 6577 properties: {
6558 6578
6559 /** 6579 /**
6560 * If you want to use the attribute value of an element for `selected` ins tead of the index, 6580 * If you want to use an attribute value or property of an element for
6561 * set this to the name of the attribute. 6581 * `selected` instead of the index, set this to the name of the attribute
6582 * or property. Hyphenated values are converted to camel case when used to
6583 * look up the property of a selectable element. Camel cased values are
6584 * *not* converted to hyphenated values for attribute lookup. It's
6585 * recommended that you provide the hyphenated form of the name so that
6586 * selection works in both cases. (Use `attr-or-property-name` instead of
6587 * `attrOrPropertyName`.)
6562 */ 6588 */
6563 attrForSelected: { 6589 attrForSelected: {
6564 type: String, 6590 type: String,
6565 value: null 6591 value: null
6566 }, 6592 },
6567 6593
6568 /** 6594 /**
6569 * Gets or sets the selected element. The default is to use the index of t he item. 6595 * Gets or sets the selected element. The default is to use the index of t he item.
6570 * @type {string|number} 6596 * @type {string|number}
6571 */ 6597 */
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
6792 var item = this.items[index]; 6818 var item = this.items[index];
6793 if (item) { 6819 if (item) {
6794 return this._valueForItem(item); 6820 return this._valueForItem(item);
6795 } 6821 }
6796 } else { 6822 } else {
6797 return index; 6823 return index;
6798 } 6824 }
6799 }, 6825 },
6800 6826
6801 _valueForItem: function(item) { 6827 _valueForItem: function(item) {
6802 var propValue = item[this.attrForSelected]; 6828 var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected) ];
6803 return propValue != undefined ? propValue : item.getAttribute(this.attrFor Selected); 6829 return propValue != undefined ? propValue : item.getAttribute(this.attrFor Selected);
6804 }, 6830 },
6805 6831
6806 _applySelection: function(item, isSelected) { 6832 _applySelection: function(item, isSelected) {
6807 if (this.selectedClass) { 6833 if (this.selectedClass) {
6808 this.toggleClass(this.selectedClass, isSelected, item); 6834 this.toggleClass(this.selectedClass, isSelected, item);
6809 } 6835 }
6810 if (this.selectedAttribute) { 6836 if (this.selectedAttribute) {
6811 this.toggleAttribute(this.selectedAttribute, isSelected, item); 6837 this.toggleAttribute(this.selectedAttribute, isSelected, item);
6812 } 6838 }
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
6885 */ 6911 */
6886 selectedItems: { 6912 selectedItems: {
6887 type: Array, 6913 type: Array,
6888 readOnly: true, 6914 readOnly: true,
6889 notify: true 6915 notify: true
6890 }, 6916 },
6891 6917
6892 }, 6918 },
6893 6919
6894 observers: [ 6920 observers: [
6895 '_updateSelected(selectedValues)' 6921 '_updateSelected(selectedValues.splices)'
6896 ], 6922 ],
6897 6923
6898 /** 6924 /**
6899 * Selects the given value. If the `multi` property is true, then the select ed state of the 6925 * Selects the given value. If the `multi` property is true, then the select ed state of the
6900 * `value` will be toggled; otherwise the `value` will be selected. 6926 * `value` will be toggled; otherwise the `value` will be selected.
6901 * 6927 *
6902 * @method select 6928 * @method select
6903 * @param {string|number} value the value to select. 6929 * @param {string|number} value the value to select.
6904 */ 6930 */
6905 select: function(value) { 6931 select: function(value) {
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
7046 this._resetTabindices(); 7072 this._resetTabindices();
7047 }, 7073 },
7048 7074
7049 /** 7075 /**
7050 * Selects the given value. If the `multi` property is true, then the select ed state of the 7076 * Selects the given value. If the `multi` property is true, then the select ed state of the
7051 * `value` will be toggled; otherwise the `value` will be selected. 7077 * `value` will be toggled; otherwise the `value` will be selected.
7052 * 7078 *
7053 * @param {string|number} value the value to select. 7079 * @param {string|number} value the value to select.
7054 */ 7080 */
7055 select: function(value) { 7081 select: function(value) {
7082 // Cancel automatically focusing a default item if the menu received focus
7083 // through a user action selecting a particular item.
7056 if (this._defaultFocusAsync) { 7084 if (this._defaultFocusAsync) {
7057 this.cancelAsync(this._defaultFocusAsync); 7085 this.cancelAsync(this._defaultFocusAsync);
7058 this._defaultFocusAsync = null; 7086 this._defaultFocusAsync = null;
7059 } 7087 }
7060 var item = this._valueToItem(value); 7088 var item = this._valueToItem(value);
7061 if (item && item.hasAttribute('disabled')) return; 7089 if (item && item.hasAttribute('disabled')) return;
7062 this._setFocusedItem(item); 7090 this._setFocusedItem(item);
7063 Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments); 7091 Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
7064 }, 7092 },
7065 7093
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
7216 } 7244 }
7217 7245
7218 // Do not focus the selected tab if the deepest target is part of the 7246 // Do not focus the selected tab if the deepest target is part of the
7219 // menu element's local DOM and is focusable. 7247 // menu element's local DOM and is focusable.
7220 var rootTarget = /** @type {?HTMLElement} */( 7248 var rootTarget = /** @type {?HTMLElement} */(
7221 Polymer.dom(event).rootTarget); 7249 Polymer.dom(event).rootTarget);
7222 if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && ! this.isLightDescendant(rootTarget)) { 7250 if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && ! this.isLightDescendant(rootTarget)) {
7223 return; 7251 return;
7224 } 7252 }
7225 7253
7226 this.blur();
7227
7228 // clear the cached focus item 7254 // clear the cached focus item
7229 this._defaultFocusAsync = this.async(function() { 7255 this._defaultFocusAsync = this.async(function() {
7230 // focus the selected item when the menu receives focus, or the first it em 7256 // focus the selected item when the menu receives focus, or the first it em
7231 // if no item is selected 7257 // if no item is selected
7232 var selectedItem = this.multi ? (this.selectedItems && this.selectedItem s[0]) : this.selectedItem; 7258 var selectedItem = this.multi ? (this.selectedItems && this.selectedItem s[0]) : this.selectedItem;
7233 7259
7234 this._setFocusedItem(null); 7260 this._setFocusedItem(null);
7235 7261
7236 if (selectedItem) { 7262 if (selectedItem) {
7237 this._setFocusedItem(selectedItem); 7263 this._setFocusedItem(selectedItem);
7238 } else { 7264 } else if (this.items[0]) {
7239 this._setFocusedItem(this.items[0]); 7265 this._setFocusedItem(this.items[0]);
7240 } 7266 }
7241 // async 1ms to wait for `select` to get called from `_itemActivate` 7267 });
7242 }, 1);
7243 }, 7268 },
7244 7269
7245 /** 7270 /**
7246 * Handler that is called when the up key is pressed. 7271 * Handler that is called when the up key is pressed.
7247 * 7272 *
7248 * @param {CustomEvent} event A key combination event. 7273 * @param {CustomEvent} event A key combination event.
7249 */ 7274 */
7250 _onUpKey: function(event) { 7275 _onUpKey: function(event) {
7251 // up and down arrows moves the focus 7276 // up and down arrows moves the focus
7252 this._focusPrevious(); 7277 this._focusPrevious();
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
7562 if (!positionedBy.horizontally) { 7587 if (!positionedBy.horizontally) {
7563 var left = this._fitLeft - rect.left + (this._fitWidth - rect.width) / 2 ; 7588 var left = this._fitLeft - rect.left + (this._fitWidth - rect.width) / 2 ;
7564 this.style.left = left + 'px'; 7589 this.style.left = left + 'px';
7565 } 7590 }
7566 } 7591 }
7567 7592
7568 }; 7593 };
7569 /** 7594 /**
7570 * @struct 7595 * @struct
7571 * @constructor 7596 * @constructor
7597 * @private
7572 */ 7598 */
7573 Polymer.IronOverlayManagerClass = function() { 7599 Polymer.IronOverlayManagerClass = function() {
7600 /**
7601 * Used to keep track of the opened overlays.
7602 * @private {Array<Element>}
7603 */
7574 this._overlays = []; 7604 this._overlays = [];
7575 // Used to keep track of the last focused node before an overlay gets opened . 7605
7576 this._lastFocusedNodes = []; 7606 /**
7577 7607 * iframes have a default z-index of 100,
7578 /** 7608 * so this default should be at least that.
7579 * iframes have a default z-index of 100, so this default should be at least
7580 * that.
7581 * @private {number} 7609 * @private {number}
7582 */ 7610 */
7583 this._minimumZ = 101; 7611 this._minimumZ = 101;
7584 7612
7585 this._backdrops = []; 7613 /**
7586 7614 * Memoized backdrop element.
7615 * @private {Element|null}
7616 */
7587 this._backdropElement = null; 7617 this._backdropElement = null;
7588 Object.defineProperty(this, 'backdropElement', { 7618
7589 get: function() { 7619 // Listen to mousedown or touchstart to be sure to be the first to capture
7590 if (!this._backdropElement) { 7620 // clicks outside the overlay.
7591 this._backdropElement = document.createElement('iron-overlay-backdrop' ); 7621 var clickEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown';
7592 } 7622 document.addEventListener(clickEvent, this._onCaptureClick.bind(this), true) ;
7593 return this._backdropElement; 7623 document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
7594 }.bind(this) 7624 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true );
7595 }); 7625 };
7626
7627 Polymer.IronOverlayManagerClass.prototype = {
7628
7629 constructor: Polymer.IronOverlayManagerClass,
7630
7631 /**
7632 * The shared backdrop element.
7633 * @type {Element} backdropElement
7634 */
7635 get backdropElement() {
7636 if (!this._backdropElement) {
7637 this._backdropElement = document.createElement('iron-overlay-backdrop');
7638 }
7639 return this._backdropElement;
7640 },
7596 7641
7597 /** 7642 /**
7598 * The deepest active element. 7643 * The deepest active element.
7599 * returns {?Node} element the active element 7644 * @type {Element} activeElement the active element
7600 */ 7645 */
7601 this.deepActiveElement = null; 7646 get deepActiveElement() {
7602 Object.defineProperty(this, 'deepActiveElement', { 7647 // document.activeElement can be null
7603 get: function() { 7648 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
7604 var active = document.activeElement; 7649 // In case of null, default it to document.body.
7605 // document.activeElement can be null 7650 var active = document.activeElement || document.body;
7606 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeEleme nt 7651 while (active.root && Polymer.dom(active.root).activeElement) {
7607 while (active && active.root && Polymer.dom(active.root).activeElement) { 7652 active = Polymer.dom(active.root).activeElement;
7608 active = Polymer.dom(active.root).activeElement; 7653 }
7609 } 7654 return active;
7610 return active; 7655 },
7611 }.bind(this) 7656
7612 }); 7657 /**
7613 }; 7658 * Brings the overlay at the specified index to the front.
7614 7659 * @param {number} i
7615 /** 7660 * @private
7616 * If a node is contained in an overlay. 7661 */
7617 * @private 7662 _bringOverlayAtIndexToFront: function(i) {
7618 * @param {Node} node 7663 var overlay = this._overlays[i];
7619 * @returns {Boolean} 7664 var lastI = this._overlays.length - 1;
7620 */ 7665 // Ensure always-on-top overlay stays on top.
7621 Polymer.IronOverlayManagerClass.prototype._isChildOfOverlay = function(node) { 7666 if (!overlay.alwaysOnTop && this._overlays[lastI].alwaysOnTop) {
7622 while (node && node !== document.body) { 7667 lastI--;
7623 // Use logical parentNode, or native ShadowRoot host. 7668 }
7624 node = Polymer.dom(node).parentNode || node.host; 7669 // If already the top element, return.
7625 // Check if it is an overlay. 7670 if (!overlay || i >= lastI) {
7626 if (node && node.behaviors && node.behaviors.indexOf(Polymer.IronOverlayBe haviorImpl) !== -1) { 7671 return;
7627 return true; 7672 }
7628 } 7673 // Update z-index to be on top.
7629 } 7674 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
7630 return false; 7675 if (this._getZ(overlay) <= minimumZ) {
7631 }; 7676 this._applyOverlayZ(overlay, minimumZ);
7632 7677 }
7633 Polymer.IronOverlayManagerClass.prototype._applyOverlayZ = function(overlay, a boveZ) { 7678
7634 this._setZ(overlay, aboveZ + 2); 7679 // Shift other overlays behind the new on top.
7635 }; 7680 while (i < lastI) {
7636 7681 this._overlays[i] = this._overlays[i + 1];
7637 Polymer.IronOverlayManagerClass.prototype._setZ = function(element, z) { 7682 i++;
7638 element.style.zIndex = z; 7683 }
7639 }; 7684 this._overlays[lastI] = overlay;
7640 7685 },
7641 /** 7686
7642 * track overlays for z-index and focus managemant 7687 /**
7643 */ 7688 * Adds the overlay and updates its z-index if it's opened, or removes it if it's closed.
7644 Polymer.IronOverlayManagerClass.prototype.addOverlay = function(overlay) { 7689 * Also updates the backdrop z-index.
7645 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ); 7690 * @param {Element} overlay
7646 this._overlays.push(overlay); 7691 */
7647 var newZ = this.currentOverlayZ(); 7692 addOrRemoveOverlay: function(overlay) {
7648 if (newZ <= minimumZ) { 7693 if (overlay.opened) {
7649 this._applyOverlayZ(overlay, minimumZ); 7694 this.addOverlay(overlay);
7650 } 7695 } else {
7651 var element = this.deepActiveElement; 7696 this.removeOverlay(overlay);
7652 // If already in other overlay, don't reset focus there. 7697 }
7653 if (this._isChildOfOverlay(element)) { 7698 this.trackBackdrop();
7654 element = null; 7699 },
7655 } 7700
7656 this._lastFocusedNodes.push(element); 7701 /**
7657 }; 7702 * Tracks overlays for z-index and focus management.
7658 7703 * Ensures the last added overlay with always-on-top remains on top.
7659 Polymer.IronOverlayManagerClass.prototype.removeOverlay = function(overlay) { 7704 * @param {Element} overlay
7660 var i = this._overlays.indexOf(overlay); 7705 */
7661 if (i >= 0) { 7706 addOverlay: function(overlay) {
7707 var i = this._overlays.indexOf(overlay);
7708 if (i >= 0) {
7709 this._bringOverlayAtIndexToFront(i);
7710 return;
7711 }
7712 var insertionIndex = this._overlays.length;
7713 var currentOverlay = this._overlays[insertionIndex - 1];
7714 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
7715 var newZ = this._getZ(overlay);
7716
7717 // Ensure always-on-top overlay stays on top.
7718 if (currentOverlay && currentOverlay.alwaysOnTop && !overlay.alwaysOnTop) {
7719 // This bumps the z-index of +2.
7720 this._applyOverlayZ(currentOverlay, minimumZ);
7721 insertionIndex--;
7722 // Update minimumZ to match previous overlay's z-index.
7723 var previousOverlay = this._overlays[insertionIndex - 1];
7724 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
7725 }
7726
7727 // Update z-index and insert overlay.
7728 if (newZ <= minimumZ) {
7729 this._applyOverlayZ(overlay, minimumZ);
7730 }
7731 this._overlays.splice(insertionIndex, 0, overlay);
7732
7733 // Get focused node.
7734 var element = this.deepActiveElement;
7735 overlay.restoreFocusNode = this._overlayParent(element) ? null : element;
7736 },
7737
7738 /**
7739 * @param {Element} overlay
7740 */
7741 removeOverlay: function(overlay) {
7742 var i = this._overlays.indexOf(overlay);
7743 if (i === -1) {
7744 return;
7745 }
7662 this._overlays.splice(i, 1); 7746 this._overlays.splice(i, 1);
7663 this._setZ(overlay, ''); 7747
7664 7748 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null;
7665 var node = this._lastFocusedNodes[i]; 7749 overlay.restoreFocusNode = null;
7666 // Focus only if still contained in document.body 7750 // Focus back only if still contained in document.body
7667 if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deep Contains(node)) { 7751 if (node && Polymer.dom(document.body).deepContains(node)) {
7668 node.focus(); 7752 node.focus();
7669 } 7753 }
7670 this._lastFocusedNodes.splice(i, 1); 7754 },
7755
7756 /**
7757 * Returns the current overlay.
7758 * @return {Element|undefined}
7759 */
7760 currentOverlay: function() {
7761 var i = this._overlays.length - 1;
7762 return this._overlays[i];
7763 },
7764
7765 /**
7766 * Returns the current overlay z-index.
7767 * @return {number}
7768 */
7769 currentOverlayZ: function() {
7770 return this._getZ(this.currentOverlay());
7771 },
7772
7773 /**
7774 * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
7775 * This does not effect the z-index of any existing overlays.
7776 * @param {number} minimumZ
7777 */
7778 ensureMinimumZ: function(minimumZ) {
7779 this._minimumZ = Math.max(this._minimumZ, minimumZ);
7780 },
7781
7782 focusOverlay: function() {
7783 var current = /** @type {?} */ (this.currentOverlay());
7784 // We have to be careful to focus the next overlay _after_ any current
7785 // transitions are complete (due to the state being toggled prior to the
7786 // transition). Otherwise, we risk infinite recursion when a transitioning
7787 // (closed) overlay becomes the current overlay.
7788 //
7789 // NOTE: We make the assumption that any overlay that completes a transiti on
7790 // will call into focusOverlay to kick the process back off. Currently:
7791 // transitionend -> _applyFocus -> focusOverlay.
7792 if (current && !current.transitioning) {
7793 current._applyFocus();
7794 }
7795 },
7796
7797 /**
7798 * Updates the backdrop z-index.
7799 */
7800 trackBackdrop: function() {
7801 this.backdropElement.style.zIndex = this.backdropZ();
7802 },
7803
7804 /**
7805 * @return {Array<Element>}
7806 */
7807 getBackdrops: function() {
7808 var backdrops = [];
7809 for (var i = 0; i < this._overlays.length; i++) {
7810 if (this._overlays[i].withBackdrop) {
7811 backdrops.push(this._overlays[i]);
7812 }
7813 }
7814 return backdrops;
7815 },
7816
7817 /**
7818 * Returns the z-index for the backdrop.
7819 * @return {number}
7820 */
7821 backdropZ: function() {
7822 return this._getZ(this._overlayWithBackdrop()) - 1;
7823 },
7824
7825 /**
7826 * Returns the first opened overlay that has a backdrop.
7827 * @return {Element|undefined}
7828 * @private
7829 */
7830 _overlayWithBackdrop: function() {
7831 for (var i = 0; i < this._overlays.length; i++) {
7832 if (this._overlays[i].withBackdrop) {
7833 return this._overlays[i];
7834 }
7835 }
7836 },
7837
7838 /**
7839 * Calculates the minimum z-index for the overlay.
7840 * @param {Element=} overlay
7841 * @private
7842 */
7843 _getZ: function(overlay) {
7844 var z = this._minimumZ;
7845 if (overlay) {
7846 var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay) .zIndex);
7847 // Check if is a number
7848 // Number.isNaN not supported in IE 10+
7849 if (z1 === z1) {
7850 z = z1;
7851 }
7852 }
7853 return z;
7854 },
7855
7856 /**
7857 * @param {Element} element
7858 * @param {number|string} z
7859 * @private
7860 */
7861 _setZ: function(element, z) {
7862 element.style.zIndex = z;
7863 },
7864
7865 /**
7866 * @param {Element} overlay
7867 * @param {number} aboveZ
7868 * @private
7869 */
7870 _applyOverlayZ: function(overlay, aboveZ) {
7871 this._setZ(overlay, aboveZ + 2);
7872 },
7873
7874 /**
7875 * Returns the overlay containing the provided node. If the node is an overl ay,
7876 * it returns the node.
7877 * @param {Element=} node
7878 * @return {Element|undefined}
7879 * @private
7880 */
7881 _overlayParent: function(node) {
7882 while (node && node !== document.body) {
7883 // Check if it is an overlay.
7884 if (node._manager === this) {
7885 return node;
7886 }
7887 // Use logical parentNode, or native ShadowRoot host.
7888 node = Polymer.dom(node).parentNode || node.host;
7889 }
7890 },
7891
7892 /**
7893 * Returns the deepest overlay in the path.
7894 * @param {Array<Element>=} path
7895 * @return {Element|undefined}
7896 * @private
7897 */
7898 _overlayInPath: function(path) {
7899 path = path || [];
7900 for (var i = 0; i < path.length; i++) {
7901 if (path[i]._manager === this) {
7902 return path[i];
7903 }
7904 }
7905 },
7906
7907 /**
7908 * Ensures the click event is delegated to the right overlay.
7909 * @param {!Event} event
7910 * @private
7911 */
7912 _onCaptureClick: function(event) {
7913 var overlay = /** @type {?} */ (this.currentOverlay());
7914 // Check if clicked outside of top overlay.
7915 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
7916 overlay._onCaptureClick(event);
7917 }
7918 },
7919
7920 /**
7921 * Ensures the focus event is delegated to the right overlay.
7922 * @param {!Event} event
7923 * @private
7924 */
7925 _onCaptureFocus: function(event) {
7926 var overlay = /** @type {?} */ (this.currentOverlay());
7927 if (overlay) {
7928 overlay._onCaptureFocus(event);
7929 }
7930 },
7931
7932 /**
7933 * Ensures TAB and ESC keyboard events are delegated to the right overlay.
7934 * @param {!Event} event
7935 * @private
7936 */
7937 _onCaptureKeyDown: function(event) {
7938 var overlay = /** @type {?} */ (this.currentOverlay());
7939 if (overlay) {
7940 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
7941 overlay._onCaptureEsc(event);
7942 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
7943 overlay._onCaptureTab(event);
7944 }
7945 }
7671 } 7946 }
7672 }; 7947 };
7673 7948
7674 Polymer.IronOverlayManagerClass.prototype.currentOverlay = function() {
7675 var i = this._overlays.length - 1;
7676 while (this._overlays[i] && !this._overlays[i].opened) {
7677 --i;
7678 }
7679 return this._overlays[i];
7680 };
7681
7682 Polymer.IronOverlayManagerClass.prototype.currentOverlayZ = function() {
7683 return this._getOverlayZ(this.currentOverlay());
7684 };
7685
7686 /**
7687 * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
7688 * This does not effect the z-index of any existing overlays.
7689 *
7690 * @param {number} minimumZ
7691 */
7692 Polymer.IronOverlayManagerClass.prototype.ensureMinimumZ = function(minimumZ) {
7693 this._minimumZ = Math.max(this._minimumZ, minimumZ);
7694 };
7695
7696 Polymer.IronOverlayManagerClass.prototype.focusOverlay = function() {
7697 var current = this.currentOverlay();
7698 // We have to be careful to focus the next overlay _after_ any current
7699 // transitions are complete (due to the state being toggled prior to the
7700 // transition). Otherwise, we risk infinite recursion when a transitioning
7701 // (closed) overlay becomes the current overlay.
7702 //
7703 // NOTE: We make the assumption that any overlay that completes a transition
7704 // will call into focusOverlay to kick the process back off. Currently:
7705 // transitionend -> _applyFocus -> focusOverlay.
7706 if (current && !current.transitioning) {
7707 current._applyFocus();
7708 }
7709 };
7710
7711 Polymer.IronOverlayManagerClass.prototype.trackBackdrop = function(element) {
7712 // backdrops contains the overlays with a backdrop that are currently
7713 // visible
7714 var index = this._backdrops.indexOf(element);
7715 if (element.opened && element.withBackdrop) {
7716 // no duplicates
7717 if (index === -1) {
7718 this._backdrops.push(element);
7719 }
7720 } else if (index >= 0) {
7721 this._backdrops.splice(index, 1);
7722 }
7723 };
7724
7725 Polymer.IronOverlayManagerClass.prototype.getBackdrops = function() {
7726 return this._backdrops;
7727 };
7728
7729 /**
7730 * Returns the z-index for the backdrop.
7731 */
7732 Polymer.IronOverlayManagerClass.prototype.backdropZ = function() {
7733 return this._getOverlayZ(this._overlayWithBackdrop()) - 1;
7734 };
7735
7736 /**
7737 * Returns the first opened overlay that has a backdrop.
7738 */
7739 Polymer.IronOverlayManagerClass.prototype._overlayWithBackdrop = function() {
7740 for (var i = 0; i < this._overlays.length; i++) {
7741 if (this._overlays[i].opened && this._overlays[i].withBackdrop) {
7742 return this._overlays[i];
7743 }
7744 }
7745 };
7746
7747 /**
7748 * Calculates the minimum z-index for the overlay.
7749 */
7750 Polymer.IronOverlayManagerClass.prototype._getOverlayZ = function(overlay) {
7751 var z = this._minimumZ;
7752 if (overlay) {
7753 var z1 = Number(window.getComputedStyle(overlay).zIndex);
7754 // Check if is a number
7755 // Number.isNaN not supported in IE 10+
7756 if (z1 === z1) {
7757 z = z1;
7758 }
7759 }
7760 return z;
7761 };
7762
7763 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); 7949 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
7764 (function() { 7950 (function() {
7765 7951
7766 Polymer({ 7952 Polymer({
7767 7953
7768 is: 'iron-overlay-backdrop', 7954 is: 'iron-overlay-backdrop',
7769 7955
7770 properties: { 7956 properties: {
7771 7957
7772 /** 7958 /**
(...skipping 14 matching lines...) Expand all
7787 }, 7973 },
7788 7974
7789 listeners: { 7975 listeners: {
7790 'transitionend' : '_onTransitionend' 7976 'transitionend' : '_onTransitionend'
7791 }, 7977 },
7792 7978
7793 /** 7979 /**
7794 * Appends the backdrop to document body and sets its `z-index` to be below the latest overlay. 7980 * Appends the backdrop to document body and sets its `z-index` to be below the latest overlay.
7795 */ 7981 */
7796 prepare: function() { 7982 prepare: function() {
7797 // Always update z-index
7798 this.style.zIndex = this._manager.backdropZ();
7799 if (!this.parentNode) { 7983 if (!this.parentNode) {
7800 Polymer.dom(document.body).appendChild(this); 7984 Polymer.dom(document.body).appendChild(this);
7801 } 7985 }
7802 }, 7986 },
7803 7987
7804 /** 7988 /**
7805 * Shows the backdrop if needed. 7989 * Shows the backdrop if needed.
7806 */ 7990 */
7807 open: function() { 7991 open: function() {
7808 // only need to make the backdrop visible if this is called by the first o verlay with a backdrop 7992 // only need to make the backdrop visible if this is called by the first o verlay with a backdrop
7809 if (this._manager.getBackdrops().length < 2) { 7993 if (this._manager.getBackdrops().length < 2) {
7810 this._setOpened(true); 7994 this._setOpened(true);
7811 } 7995 }
7812 }, 7996 },
7813 7997
7814 /** 7998 /**
7815 * Hides the backdrop if needed. 7999 * Hides the backdrop if needed.
7816 */ 8000 */
7817 close: function() { 8001 close: function() {
7818 // Always update z-index
7819 this.style.zIndex = this._manager.backdropZ();
7820 // close only if no element with backdrop is left 8002 // close only if no element with backdrop is left
7821 if (this._manager.getBackdrops().length === 0) { 8003 if (this._manager.getBackdrops().length === 0) {
7822 // Read style before setting opened. 8004 // Read style before setting opened.
7823 var cs = getComputedStyle(this); 8005 var cs = getComputedStyle(this);
7824 var noAnimation = (cs.transitionDuration === '0s' || cs.opacity == 0); 8006 var noAnimation = (cs.transitionDuration === '0s' || cs.opacity == 0);
7825 this._setOpened(false); 8007 this._setOpened(false);
7826 // In case of no animations, complete 8008 // In case of no animations, complete
7827 if (noAnimation) { 8009 if (noAnimation) {
7828 this.complete(); 8010 this.complete();
7829 } 8011 }
(...skipping 12 matching lines...) Expand all
7842 8024
7843 _onTransitionend: function (event) { 8025 _onTransitionend: function (event) {
7844 if (event && event.target === this) { 8026 if (event && event.target === this) {
7845 this.complete(); 8027 this.complete();
7846 } 8028 }
7847 } 8029 }
7848 8030
7849 }); 8031 });
7850 8032
7851 })(); 8033 })();
8034 // IIFE to help scripts concatenation.
8035 (function() {
8036 'use strict';
8037
7852 /** 8038 /**
7853 Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or shown, and displays 8039 Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or shown, and displays
7854 on top of other content. It includes an optional backdrop, and can be used to im plement a variety 8040 on top of other content. It includes an optional backdrop, and can be used to im plement a variety
7855 of UI controls including dialogs and drop downs. Multiple overlays may be displa yed at once. 8041 of UI controls including dialogs and drop downs. Multiple overlays may be displa yed at once.
7856 8042
7857 ### Closing and canceling 8043 ### Closing and canceling
7858 8044
7859 A dialog may be hidden by closing or canceling. The difference between close and cancel is user 8045 A dialog may be hidden by closing or canceling. The difference between close and cancel is user
7860 intent. Closing generally implies that the user acknowledged the content on the overlay. By default, 8046 intent. Closing generally implies that the user acknowledged the content on the overlay. By default,
7861 it will cancel whenever the user taps outside it or presses the escape key. This behavior is 8047 it will cancel whenever the user taps outside it or presses the escape key. This behavior is
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
7945 /** 8131 /**
7946 * Returns the reason this dialog was last closed. 8132 * Returns the reason this dialog was last closed.
7947 */ 8133 */
7948 closingReason: { 8134 closingReason: {
7949 // was a getter before, but needs to be a property so other 8135 // was a getter before, but needs to be a property so other
7950 // behaviors can override this. 8136 // behaviors can override this.
7951 type: Object 8137 type: Object
7952 }, 8138 },
7953 8139
7954 /** 8140 /**
7955 * The HTMLElement that will be firing relevant KeyboardEvents.
7956 * Used for capturing esc and tab. Overridden from `IronA11yKeysBehavior`.
7957 */
7958 keyEventTarget: {
7959 type: Object,
7960 value: document
7961 },
7962
7963 /**
7964 * Set to true to enable restoring of focus when overlay is closed. 8141 * Set to true to enable restoring of focus when overlay is closed.
7965 */ 8142 */
7966 restoreFocusOnClose: { 8143 restoreFocusOnClose: {
7967 type: Boolean, 8144 type: Boolean,
7968 value: false 8145 value: false
7969 }, 8146 },
7970 8147
8148 /**
8149 * Set to true to keep overlay always on top.
8150 */
8151 alwaysOnTop: {
8152 type: Boolean
8153 },
8154
8155 /**
8156 * Shortcut to access to the overlay manager.
8157 * @private
8158 * @type {Polymer.IronOverlayManagerClass}
8159 */
7971 _manager: { 8160 _manager: {
7972 type: Object, 8161 type: Object,
7973 value: Polymer.IronOverlayManager 8162 value: Polymer.IronOverlayManager
7974 }, 8163 },
7975 8164
7976 _boundOnCaptureClick: {
7977 type: Function,
7978 value: function() {
7979 return this._onCaptureClick.bind(this);
7980 }
7981 },
7982
7983 _boundOnCaptureFocus: {
7984 type: Function,
7985 value: function() {
7986 return this._onCaptureFocus.bind(this);
7987 }
7988 },
7989
7990 /** 8165 /**
7991 * The node being focused. 8166 * The node being focused.
7992 * @type {?Node} 8167 * @type {?Node}
7993 */ 8168 */
7994 _focusedChild: { 8169 _focusedChild: {
7995 type: Object 8170 type: Object
7996 } 8171 }
7997 8172
7998 }, 8173 },
7999 8174
8000 keyBindings: {
8001 'esc': '__onEsc',
8002 'tab': '__onTab'
8003 },
8004
8005 listeners: { 8175 listeners: {
8006 'iron-resize': '_onIronResize' 8176 'iron-resize': '_onIronResize'
8007 }, 8177 },
8008 8178
8009 /** 8179 /**
8010 * The backdrop element. 8180 * The backdrop element.
8011 * @type {Node} 8181 * @type {Element}
8012 */ 8182 */
8013 get backdropElement() { 8183 get backdropElement() {
8014 return this._manager.backdropElement; 8184 return this._manager.backdropElement;
8015 }, 8185 },
8016 8186
8017 /** 8187 /**
8018 * Returns the node to give focus to. 8188 * Returns the node to give focus to.
8019 * @type {Node} 8189 * @type {Node}
8020 */ 8190 */
8021 get _focusNode() { 8191 get _focusNode() {
8022 return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]' ) || this; 8192 return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]' ) || this;
8023 }, 8193 },
8024 8194
8025 /** 8195 /**
8026 * Array of nodes that can receive focus (overlay included), ordered by `tab index`. 8196 * Array of nodes that can receive focus (overlay included), ordered by `tab index`.
8027 * This is used to retrieve which is the first and last focusable nodes in o rder 8197 * This is used to retrieve which is the first and last focusable nodes in o rder
8028 * to wrap the focus for overlays `with-backdrop`. 8198 * to wrap the focus for overlays `with-backdrop`.
8029 * 8199 *
8030 * If you know what is your content (specifically the first and last focusab le children), 8200 * If you know what is your content (specifically the first and last focusab le children),
8031 * you can override this method to return only `[firstFocusable, lastFocusab le];` 8201 * you can override this method to return only `[firstFocusable, lastFocusab le];`
8032 * @type {[Node]} 8202 * @type {Array<Node>}
8033 * @protected 8203 * @protected
8034 */ 8204 */
8035 get _focusableNodes() { 8205 get _focusableNodes() {
8036 // Elements that can be focused even if they have [disabled] attribute. 8206 // Elements that can be focused even if they have [disabled] attribute.
8037 var FOCUSABLE_WITH_DISABLED = [ 8207 var FOCUSABLE_WITH_DISABLED = [
8038 'a[href]', 8208 'a[href]',
8039 'area[href]', 8209 'area[href]',
8040 'iframe', 8210 'iframe',
8041 '[tabindex]', 8211 '[tabindex]',
8042 '[contentEditable=true]' 8212 '[contentEditable=true]'
(...skipping 25 matching lines...) Expand all
8068 return 0; 8238 return 0;
8069 } 8239 }
8070 if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) { 8240 if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
8071 return 1; 8241 return 1;
8072 } 8242 }
8073 return -1; 8243 return -1;
8074 }); 8244 });
8075 }, 8245 },
8076 8246
8077 ready: function() { 8247 ready: function() {
8248 // Used to skip calls to notifyResize and refit while the overlay is anima ting.
8249 this.__isAnimating = false;
8078 // with-backdrop needs tabindex to be set in order to trap the focus. 8250 // with-backdrop needs tabindex to be set in order to trap the focus.
8079 // If it is not set, IronOverlayBehavior will set it, and remove it if wit h-backdrop = false. 8251 // If it is not set, IronOverlayBehavior will set it, and remove it if wit h-backdrop = false.
8080 this.__shouldRemoveTabIndex = false; 8252 this.__shouldRemoveTabIndex = false;
8081 // Used for wrapping the focus on TAB / Shift+TAB. 8253 // Used for wrapping the focus on TAB / Shift+TAB.
8082 this.__firstFocusableNode = this.__lastFocusableNode = null; 8254 this.__firstFocusableNode = this.__lastFocusableNode = null;
8255 // Used for requestAnimationFrame when opened changes.
8256 this.__openChangedAsync = null;
8257 // Used for requestAnimationFrame when iron-resize is fired.
8258 this.__onIronResizeAsync = null;
8083 this._ensureSetup(); 8259 this._ensureSetup();
8084 }, 8260 },
8085 8261
8086 attached: function() { 8262 attached: function() {
8087 // Call _openedChanged here so that position can be computed correctly. 8263 // Call _openedChanged here so that position can be computed correctly.
8088 if (this.opened) { 8264 if (this.opened) {
8089 this._openedChanged(); 8265 this._openedChanged();
8090 } 8266 }
8091 this._observer = Polymer.dom(this).observeNodes(this._onNodesChange); 8267 this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
8092 }, 8268 },
8093 8269
8094 detached: function() { 8270 detached: function() {
8095 Polymer.dom(this).unobserveNodes(this._observer); 8271 Polymer.dom(this).unobserveNodes(this._observer);
8096 this._observer = null; 8272 this._observer = null;
8097 this.opened = false; 8273 this.opened = false;
8098 this._manager.trackBackdrop(this); 8274 if (this.withBackdrop) {
8099 this._manager.removeOverlay(this); 8275 // Allow user interactions right away.
8276 this.backdropElement.close();
8277 }
8100 }, 8278 },
8101 8279
8102 /** 8280 /**
8103 * Toggle the opened state of the overlay. 8281 * Toggle the opened state of the overlay.
8104 */ 8282 */
8105 toggle: function() { 8283 toggle: function() {
8106 this._setCanceled(false); 8284 this._setCanceled(false);
8107 this.opened = !this.opened; 8285 this.opened = !this.opened;
8108 }, 8286 },
8109 8287
8110 /** 8288 /**
8111 * Open the overlay. 8289 * Open the overlay.
8112 */ 8290 */
8113 open: function() { 8291 open: function() {
8114 this._setCanceled(false); 8292 this._setCanceled(false);
8115 this.opened = true; 8293 this.opened = true;
8116 }, 8294 },
8117 8295
8118 /** 8296 /**
8119 * Close the overlay. 8297 * Close the overlay.
8120 */ 8298 */
8121 close: function() { 8299 close: function() {
8122 this._setCanceled(false); 8300 this._setCanceled(false);
8123 this.opened = false; 8301 this.opened = false;
8124 }, 8302 },
8125 8303
8126 /** 8304 /**
8127 * Cancels the overlay. 8305 * Cancels the overlay.
8128 * @param {?Event} event The original event 8306 * @param {Event=} event The original event
8129 */ 8307 */
8130 cancel: function(event) { 8308 cancel: function(event) {
8131 var cancelEvent = this.fire('iron-overlay-canceled', event, {cancelable: t rue}); 8309 var cancelEvent = this.fire('iron-overlay-canceled', event, {cancelable: t rue});
8132 if (cancelEvent.defaultPrevented) { 8310 if (cancelEvent.defaultPrevented) {
8133 return; 8311 return;
8134 } 8312 }
8135 8313
8136 this._setCanceled(true); 8314 this._setCanceled(true);
8137 this.opened = false; 8315 this.opened = false;
8138 }, 8316 },
(...skipping 12 matching lines...) Expand all
8151 this.removeAttribute('aria-hidden'); 8329 this.removeAttribute('aria-hidden');
8152 } else { 8330 } else {
8153 this.setAttribute('aria-hidden', 'true'); 8331 this.setAttribute('aria-hidden', 'true');
8154 } 8332 }
8155 8333
8156 // wait to call after ready only if we're initially open 8334 // wait to call after ready only if we're initially open
8157 if (!this._overlaySetup) { 8335 if (!this._overlaySetup) {
8158 return; 8336 return;
8159 } 8337 }
8160 8338
8161 this._manager.trackBackdrop(this); 8339 this._manager.addOrRemoveOverlay(this);
8162 8340
8341 this.__isAnimating = true;
8342
8343 // requestAnimationFrame for non-blocking rendering
8344 if (this.__openChangedAsync) {
8345 cancelAnimationFrame(this.__openChangedAsync);
8346 }
8163 if (this.opened) { 8347 if (this.opened) {
8164 this._prepareRenderOpened(); 8348 if (this.withBackdrop) {
8349 this.backdropElement.prepare();
8350 }
8351 this.__openChangedAsync = requestAnimationFrame(function() {
8352 this.__openChangedAsync = null;
8353 this._prepareRenderOpened();
8354 this._renderOpened();
8355 }.bind(this));
8356 } else {
8357 this._renderClosed();
8165 } 8358 }
8166
8167 if (this._openChangedAsync) {
8168 this.cancelAsync(this._openChangedAsync);
8169 }
8170 // Async here to allow overlay layer to become visible, and to avoid
8171 // listeners to immediately close via a click.
8172 this._openChangedAsync = this.async(function() {
8173 // overlay becomes visible here
8174 this.style.display = '';
8175 // Force layout to ensure transition will go. Set offsetWidth to itself
8176 // so that compilers won't remove it.
8177 this.offsetWidth = this.offsetWidth;
8178 if (this.opened) {
8179 this._renderOpened();
8180 } else {
8181 this._renderClosed();
8182 }
8183 this._toggleListeners();
8184 this._openChangedAsync = null;
8185 }, 1);
8186 }, 8359 },
8187 8360
8188 _canceledChanged: function() { 8361 _canceledChanged: function() {
8189 this.closingReason = this.closingReason || {}; 8362 this.closingReason = this.closingReason || {};
8190 this.closingReason.canceled = this.canceled; 8363 this.closingReason.canceled = this.canceled;
8191 }, 8364 },
8192 8365
8193 _withBackdropChanged: function() { 8366 _withBackdropChanged: function() {
8194 // If tabindex is already set, no need to override it. 8367 // If tabindex is already set, no need to override it.
8195 if (this.withBackdrop && !this.hasAttribute('tabindex')) { 8368 if (this.withBackdrop && !this.hasAttribute('tabindex')) {
8196 this.setAttribute('tabindex', '-1'); 8369 this.setAttribute('tabindex', '-1');
8197 this.__shouldRemoveTabIndex = true; 8370 this.__shouldRemoveTabIndex = true;
8198 } else if (this.__shouldRemoveTabIndex) { 8371 } else if (this.__shouldRemoveTabIndex) {
8199 this.removeAttribute('tabindex'); 8372 this.removeAttribute('tabindex');
8200 this.__shouldRemoveTabIndex = false; 8373 this.__shouldRemoveTabIndex = false;
8201 } 8374 }
8202 if (this.opened) { 8375 if (this.opened) {
8203 this._manager.trackBackdrop(this); 8376 this._manager.trackBackdrop();
8204 if (this.withBackdrop) { 8377 if (this.withBackdrop) {
8205 this.backdropElement.prepare(); 8378 this.backdropElement.prepare();
8206 // Give time to be added to document. 8379 // Give time to be added to document.
8207 this.async(function(){ 8380 this.async(function(){
8208 this.backdropElement.open(); 8381 this.backdropElement.open();
8209 }, 1); 8382 }, 1);
8210 } else { 8383 } else {
8211 this.backdropElement.close(); 8384 this.backdropElement.close();
8212 } 8385 }
8213 } 8386 }
8214 }, 8387 },
8215 8388
8216 _toggleListener: function(enable, node, event, boundListener, capture) { 8389 /**
8217 if (enable) { 8390 * tasks which must occur before opening; e.g. making the element visible.
8218 // enable document-wide tap recognizer 8391 * @protected
8219 if (event === 'tap') { 8392 */
8220 Polymer.Gestures.add(document, 'tap', null);
8221 }
8222 node.addEventListener(event, boundListener, capture);
8223 } else {
8224 // disable document-wide tap recognizer
8225 if (event === 'tap') {
8226 Polymer.Gestures.remove(document, 'tap', null);
8227 }
8228 node.removeEventListener(event, boundListener, capture);
8229 }
8230 },
8231
8232 _toggleListeners: function() {
8233 this._toggleListener(this.opened, document, 'tap', this._boundOnCaptureCli ck, true);
8234 this._toggleListener(this.opened, document, 'focus', this._boundOnCaptureF ocus, true);
8235 },
8236
8237 // tasks which must occur before opening; e.g. making the element visible
8238 _prepareRenderOpened: function() { 8393 _prepareRenderOpened: function() {
8239 8394
8240 this._manager.addOverlay(this);
8241
8242 // Needed to calculate the size of the overlay so that transitions on its size 8395 // Needed to calculate the size of the overlay so that transitions on its size
8243 // will have the correct starting points. 8396 // will have the correct starting points.
8244 this._preparePositioning(); 8397 this._preparePositioning();
8245 this.fit(); 8398 this.refit();
8246 this._finishPositioning(); 8399 this._finishPositioning();
8247 8400
8248 if (this.withBackdrop) {
8249 this.backdropElement.prepare();
8250 }
8251
8252 // Safari will apply the focus to the autofocus element when displayed for the first time, 8401 // Safari will apply the focus to the autofocus element when displayed for the first time,
8253 // so we blur it. Later, _applyFocus will set the focus if necessary. 8402 // so we blur it. Later, _applyFocus will set the focus if necessary.
8254 if (this.noAutoFocus && document.activeElement === this._focusNode) { 8403 if (this.noAutoFocus && document.activeElement === this._focusNode) {
8255 this._focusNode.blur(); 8404 this._focusNode.blur();
8256 } 8405 }
8257 }, 8406 },
8258 8407
8259 // tasks which cause the overlay to actually open; typically play an 8408 /**
8260 // animation 8409 * Tasks which cause the overlay to actually open; typically play an animati on.
8410 * @protected
8411 */
8261 _renderOpened: function() { 8412 _renderOpened: function() {
8262 if (this.withBackdrop) { 8413 if (this.withBackdrop) {
8263 this.backdropElement.open(); 8414 this.backdropElement.open();
8264 } 8415 }
8265 this._finishRenderOpened(); 8416 this._finishRenderOpened();
8266 }, 8417 },
8267 8418
8419 /**
8420 * Tasks which cause the overlay to actually close; typically play an animat ion.
8421 * @protected
8422 */
8268 _renderClosed: function() { 8423 _renderClosed: function() {
8269 if (this.withBackdrop) { 8424 if (this.withBackdrop) {
8270 this.backdropElement.close(); 8425 this.backdropElement.close();
8271 } 8426 }
8272 this._finishRenderClosed(); 8427 this._finishRenderClosed();
8273 }, 8428 },
8274 8429
8430 /**
8431 * Tasks to be performed at the end of open action. Will fire `iron-overlay- opened`.
8432 * @protected
8433 */
8275 _finishRenderOpened: function() { 8434 _finishRenderOpened: function() {
8276 // This ensures the overlay is visible before we set the focus
8277 // (by calling _onIronResize -> refit).
8278 this.notifyResize();
8279 // Focus the child node with [autofocus] 8435 // Focus the child node with [autofocus]
8280 this._applyFocus(); 8436 this._applyFocus();
8281 8437
8438 this.notifyResize();
8439 this.__isAnimating = false;
8282 this.fire('iron-overlay-opened'); 8440 this.fire('iron-overlay-opened');
8283 }, 8441 },
8284 8442
8443 /**
8444 * Tasks to be performed at the end of close action. Will fire `iron-overlay -closed`.
8445 * @protected
8446 */
8285 _finishRenderClosed: function() { 8447 _finishRenderClosed: function() {
8286 // Hide the overlay and remove the backdrop. 8448 // Hide the overlay and remove the backdrop.
8287 this.resetFit();
8288 this.style.display = 'none'; 8449 this.style.display = 'none';
8289 this._manager.removeOverlay(this); 8450 // Reset z-index only at the end of the animation.
8451 this.style.zIndex = '';
8290 8452
8291 this._applyFocus(); 8453 this._applyFocus();
8454
8292 this.notifyResize(); 8455 this.notifyResize();
8293 8456 this.__isAnimating = false;
8294 this.fire('iron-overlay-closed', this.closingReason); 8457 this.fire('iron-overlay-closed', this.closingReason);
8295 }, 8458 },
8296 8459
8297 _preparePositioning: function() { 8460 _preparePositioning: function() {
8298 this.style.transition = this.style.webkitTransition = 'none'; 8461 this.style.transition = this.style.webkitTransition = 'none';
8299 this.style.transform = this.style.webkitTransform = 'none'; 8462 this.style.transform = this.style.webkitTransform = 'none';
8300 this.style.display = ''; 8463 this.style.display = '';
8301 }, 8464 },
8302 8465
8303 _finishPositioning: function() { 8466 _finishPositioning: function() {
8467 // First, make it invisible & reactivate animations.
8304 this.style.display = 'none'; 8468 this.style.display = 'none';
8469 // Force reflow before re-enabling animations so that they don't start.
8470 // Set scrollTop to itself so that Closure Compiler doesn't remove this.
8471 this.scrollTop = this.scrollTop;
8472 this.style.transition = this.style.webkitTransition = '';
8305 this.style.transform = this.style.webkitTransform = ''; 8473 this.style.transform = this.style.webkitTransform = '';
8306 // Force layout layout to avoid application of transform. 8474 // Now that animations are enabled, make it visible again
8307 // Set offsetWidth to itself so that compilers won't remove it. 8475 this.style.display = '';
8308 this.offsetWidth = this.offsetWidth; 8476 // Force reflow, so that following animations are properly started.
8309 this.style.transition = this.style.webkitTransition = ''; 8477 // Set scrollTop to itself so that Closure Compiler doesn't remove this.
8478 this.scrollTop = this.scrollTop;
8310 }, 8479 },
8311 8480
8481 /**
8482 * Applies focus according to the opened state.
8483 * @protected
8484 */
8312 _applyFocus: function() { 8485 _applyFocus: function() {
8313 if (this.opened) { 8486 if (this.opened) {
8314 if (!this.noAutoFocus) { 8487 if (!this.noAutoFocus) {
8315 this._focusNode.focus(); 8488 this._focusNode.focus();
8316 } 8489 }
8317 } else { 8490 } else {
8318 this._focusNode.blur(); 8491 this._focusNode.blur();
8319 this._focusedChild = null; 8492 this._focusedChild = null;
8320 this._manager.focusOverlay(); 8493 this._manager.focusOverlay();
8321 } 8494 }
8322 }, 8495 },
8323 8496
8324 _onCaptureClick: function(event) {
8325 if (this._manager.currentOverlay() === this &&
8326 Polymer.dom(event).path.indexOf(this) === -1) {
8327 if (this.noCancelOnOutsideClick) {
8328 this._applyFocus();
8329 } else {
8330 this.cancel(event);
8331 }
8332 }
8333 },
8334
8335 _onCaptureFocus: function (event) {
8336 if (this._manager.currentOverlay() === this && this.withBackdrop) {
8337 var path = Polymer.dom(event).path;
8338 if (path.indexOf(this) === -1) {
8339 event.stopPropagation();
8340 this._applyFocus();
8341 } else {
8342 this._focusedChild = path[0];
8343 }
8344 }
8345 },
8346
8347 _onIronResize: function() {
8348 if (this.opened) {
8349 this.refit();
8350 }
8351 },
8352
8353 /** 8497 /**
8498 * Cancels (closes) the overlay. Call when click happens outside the overlay .
8499 * @param {!Event} event
8354 * @protected 8500 * @protected
8355 * Will call notifyResize if overlay is opened.
8356 * Can be overridden in order to avoid multiple observers on the same node.
8357 */ 8501 */
8358 _onNodesChange: function() { 8502 _onCaptureClick: function(event) {
8359 if (this.opened) { 8503 if (!this.noCancelOnOutsideClick) {
8360 this.notifyResize(); 8504 this.cancel(event);
8361 } 8505 }
8362 // Store it so we don't query too much.
8363 var focusableNodes = this._focusableNodes;
8364 this.__firstFocusableNode = focusableNodes[0];
8365 this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
8366 }, 8506 },
8367 8507
8368 __onEsc: function(event) { 8508 /**
8369 // Not opened or not on top, so return. 8509 * Keeps track of the focused child. If withBackdrop, traps focus within ove rlay.
8370 if (this._manager.currentOverlay() !== this) { 8510 * @param {!Event} event
8511 * @protected
8512 */
8513 _onCaptureFocus: function (event) {
8514 if (!this.withBackdrop) {
8371 return; 8515 return;
8372 } 8516 }
8517 var path = Polymer.dom(event).path;
8518 if (path.indexOf(this) === -1) {
8519 event.stopPropagation();
8520 this._applyFocus();
8521 } else {
8522 this._focusedChild = path[0];
8523 }
8524 },
8525
8526 /**
8527 * Handles the ESC key event and cancels (closes) the overlay.
8528 * @param {!Event} event
8529 * @protected
8530 */
8531 _onCaptureEsc: function(event) {
8373 if (!this.noCancelOnEscKey) { 8532 if (!this.noCancelOnEscKey) {
8374 this.cancel(event); 8533 this.cancel(event);
8375 } 8534 }
8376 }, 8535 },
8377 8536
8378 __onTab: function(event) { 8537 /**
8379 // Not opened or not on top, so return. 8538 * Handles TAB key events to track focus changes.
8380 if (this._manager.currentOverlay() !== this) { 8539 * Will wrap focus for overlays withBackdrop.
8381 return; 8540 * @param {!Event} event
8382 } 8541 * @protected
8542 */
8543 _onCaptureTab: function(event) {
8383 // TAB wraps from last to first focusable. 8544 // TAB wraps from last to first focusable.
8384 // Shift + TAB wraps from first to last focusable. 8545 // Shift + TAB wraps from first to last focusable.
8385 var shift = event.detail.keyboardEvent.shiftKey; 8546 var shift = event.shiftKey;
8386 var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusable Node; 8547 var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusable Node;
8387 var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNo de; 8548 var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNo de;
8388 if (this.withBackdrop && this._focusedChild === nodeToCheck) { 8549 if (this.withBackdrop && this._focusedChild === nodeToCheck) {
8389 // We set here the _focusedChild so that _onCaptureFocus will handle the 8550 // We set here the _focusedChild so that _onCaptureFocus will handle the
8390 // wrapping of the focus (the next event after tab is focus). 8551 // wrapping of the focus (the next event after tab is focus).
8391 this._focusedChild = nodeToSet; 8552 this._focusedChild = nodeToSet;
8392 } 8553 }
8554 },
8555
8556 /**
8557 * Refits if the overlay is opened and not animating.
8558 * @protected
8559 */
8560 _onIronResize: function() {
8561 if (this.__onIronResizeAsync) {
8562 cancelAnimationFrame(this.__onIronResizeAsync);
8563 this.__onIronResizeAsync = null;
8564 }
8565 if (this.opened && !this.__isAnimating) {
8566 this.__onIronResizeAsync = requestAnimationFrame(function() {
8567 this.__onIronResizeAsync = null;
8568 this.refit();
8569 }.bind(this));
8570 }
8571 },
8572
8573 /**
8574 * Will call notifyResize if overlay is opened.
8575 * Can be overridden in order to avoid multiple observers on the same node.
8576 * @protected
8577 */
8578 _onNodesChange: function() {
8579 if (this.opened && !this.__isAnimating) {
8580 this.notifyResize();
8581 }
8582 // Store it so we don't query too much.
8583 var focusableNodes = this._focusableNodes;
8584 this.__firstFocusableNode = focusableNodes[0];
8585 this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
8393 } 8586 }
8394 }; 8587 };
8395 8588
8396 /** @polymerBehavior */ 8589 /** @polymerBehavior */
8397 Polymer.IronOverlayBehavior = [Polymer.IronA11yKeysBehavior, Polymer.IronFitBe havior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl]; 8590 Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableB ehavior, Polymer.IronOverlayBehaviorImpl];
8398 8591
8399 /** 8592 /**
8400 * Fired after the `iron-overlay` opens. 8593 * Fired after the `iron-overlay` opens.
8401 * @event iron-overlay-opened 8594 * @event iron-overlay-opened
8402 */ 8595 */
8403 8596
8404 /** 8597 /**
8405 * Fired when the `iron-overlay` is canceled, but before it is closed. 8598 * Fired when the `iron-overlay` is canceled, but before it is closed.
8406 * Cancel the event to prevent the `iron-overlay` from closing. 8599 * Cancel the event to prevent the `iron-overlay` from closing.
8407 * @event iron-overlay-canceled 8600 * @event iron-overlay-canceled
8408 * @param {Event} event The closing of the `iron-overlay` can be prevented 8601 * @param {Event} event The closing of the `iron-overlay` can be prevented
8409 * by calling `event.preventDefault()`. The `event.detail` is the original even t that originated 8602 * by calling `event.preventDefault()`. The `event.detail` is the original even t that originated
8410 * the canceling (e.g. ESC keyboard event or click event outside the `iron-over lay`). 8603 * the canceling (e.g. ESC keyboard event or click event outside the `iron-over lay`).
8411 */ 8604 */
8412 8605
8413 /** 8606 /**
8414 * Fired after the `iron-overlay` closes. 8607 * Fired after the `iron-overlay` closes.
8415 * @event iron-overlay-closed 8608 * @event iron-overlay-closed
8416 * @param {{canceled: (boolean|undefined)}} closingReason Contains `canceled` ( whether the overlay was canceled). 8609 * @param {{canceled: (boolean|undefined)}} closingReason Contains `canceled` ( whether the overlay was canceled).
8417 */ 8610 */
8611
8612 })();
8418 /** 8613 /**
8419 * Use `Polymer.NeonAnimationBehavior` to implement an animation. 8614 * Use `Polymer.NeonAnimationBehavior` to implement an animation.
8420 * @polymerBehavior 8615 * @polymerBehavior
8421 */ 8616 */
8422 Polymer.NeonAnimationBehavior = { 8617 Polymer.NeonAnimationBehavior = {
8423 8618
8424 properties: { 8619 properties: {
8425 8620
8426 /** 8621 /**
8427 * Defines the animation timing. 8622 * Defines the animation timing.
8428 */ 8623 */
8429 animationTiming: { 8624 animationTiming: {
8430 type: Object, 8625 type: Object,
8431 value: function() { 8626 value: function() {
8432 return { 8627 return {
8433 duration: 500, 8628 duration: 500,
8434 easing: 'cubic-bezier(0.4, 0, 0.2, 1)', 8629 easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
8435 fill: 'both' 8630 fill: 'both'
8436 } 8631 }
8437 } 8632 }
8438 } 8633 }
8439 8634
8440 }, 8635 },
8441 8636
8442 registered: function() { 8637 /**
8443 new Polymer.IronMeta({type: 'animation', key: this.is, value: this.constru ctor}); 8638 * Can be used to determine that elements implement this behavior.
8444 }, 8639 */
8640 isNeonAnimation: true,
8445 8641
8446 /** 8642 /**
8447 * Do any animation configuration here. 8643 * Do any animation configuration here.
8448 */ 8644 */
8449 // configure: function(config) { 8645 // configure: function(config) {
8450 // }, 8646 // },
8451 8647
8452 /** 8648 /**
8453 * Returns the animation timing by mixing in properties from `config` to the defaults defined 8649 * Returns the animation timing by mixing in properties from `config` to the defaults defined
8454 * by the animation. 8650 * by the animation.
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
8653 }; 8849 };
8654 /** 8850 /**
8655 * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations. 8851 * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations.
8656 * 8852 *
8657 * @polymerBehavior Polymer.NeonAnimationRunnerBehavior 8853 * @polymerBehavior Polymer.NeonAnimationRunnerBehavior
8658 */ 8854 */
8659 Polymer.NeonAnimationRunnerBehaviorImpl = { 8855 Polymer.NeonAnimationRunnerBehaviorImpl = {
8660 8856
8661 properties: { 8857 properties: {
8662 8858
8663 _animationMeta: {
8664 type: Object,
8665 value: function() {
8666 return new Polymer.IronMeta({type: 'animation'});
8667 }
8668 },
8669
8670 /** @type {?Object} */ 8859 /** @type {?Object} */
8671 _player: { 8860 _player: {
8672 type: Object 8861 type: Object
8673 } 8862 }
8674 8863
8675 }, 8864 },
8676 8865
8677 _configureAnimationEffects: function(allConfigs) { 8866 _configureAnimationEffects: function(allConfigs) {
8678 var allAnimations = []; 8867 var allAnimations = [];
8679 if (allConfigs.length > 0) { 8868 if (allConfigs.length > 0) {
8680 for (var config, index = 0; config = allConfigs[index]; index++) { 8869 for (var config, index = 0; config = allConfigs[index]; index++) {
8681 var animationConstructor = this._animationMeta.byKey(config.name); 8870 var animation = document.createElement(config.name);
8682 if (animationConstructor) { 8871 // is this element actually a neon animation?
8683 var animation = animationConstructor && new animationConstructor(); 8872 if (animation.isNeonAnimation) {
8684 var effect = animation.configure(config); 8873 var effect = animation.configure(config);
8685 if (effect) { 8874 if (effect) {
8686 allAnimations.push({ 8875 allAnimations.push({
8687 animation: animation, 8876 animation: animation,
8688 config: config, 8877 config: config,
8689 effect: effect 8878 effect: effect
8690 }); 8879 });
8691 } 8880 }
8692 } else { 8881 } else {
8693 console.warn(this.is + ':', config.name, 'not found!'); 8882 console.warn(this.is + ':', config.name, 'not found!');
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
8911 if (this._composedTreeContains(distributedNodes[nodeIndex], child)) { 9100 if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
8912 return true; 9101 return true;
8913 } 9102 }
8914 } 9103 }
8915 } 9104 }
8916 9105
8917 return false; 9106 return false;
8918 }, 9107 },
8919 9108
8920 _scrollInteractionHandler: function(event) { 9109 _scrollInteractionHandler: function(event) {
9110 var scrolledElement =
9111 /** @type {HTMLElement} */(Polymer.dom(event).rootTarget);
8921 if (Polymer 9112 if (Polymer
8922 .IronDropdownScrollManager 9113 .IronDropdownScrollManager
8923 .elementIsScrollLocked(Polymer.dom(event).rootTarget)) { 9114 .elementIsScrollLocked(scrolledElement)) {
8924 if (event.type === 'keydown' && 9115 if (event.type === 'keydown' &&
8925 !Polymer.IronDropdownScrollManager._isScrollingKeypress(event)) { 9116 !Polymer.IronDropdownScrollManager._isScrollingKeypress(event)) {
8926 return; 9117 return;
8927 } 9118 }
8928 9119
8929 event.preventDefault(); 9120 event.preventDefault();
8930 } 9121 }
8931 }, 9122 },
8932 9123
8933 _lockScrollInteractions: function() { 9124 _lockScrollInteractions: function() {
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
9043 type: Number, 9234 type: Number,
9044 value: 0, 9235 value: 0,
9045 notify: true 9236 notify: true
9046 }, 9237 },
9047 9238
9048 /** 9239 /**
9049 * The element that should be used to position the dropdown when 9240 * The element that should be used to position the dropdown when
9050 * it is opened. 9241 * it is opened.
9051 */ 9242 */
9052 positionTarget: { 9243 positionTarget: {
9053 type: Object, 9244 type: Object
9054 observer: '_positionTargetChanged'
9055 }, 9245 },
9056 9246
9057 /** 9247 /**
9058 * An animation config. If provided, this will be used to animate the 9248 * An animation config. If provided, this will be used to animate the
9059 * opening of the dropdown. 9249 * opening of the dropdown.
9060 */ 9250 */
9061 openAnimationConfig: { 9251 openAnimationConfig: {
9062 type: Object 9252 type: Object
9063 }, 9253 },
9064 9254
(...skipping 24 matching lines...) Expand all
9089 9279
9090 /** 9280 /**
9091 * By default, the dropdown will constrain scrolling on the page 9281 * By default, the dropdown will constrain scrolling on the page
9092 * to itself when opened. 9282 * to itself when opened.
9093 * Set to true in order to prevent scroll from being constrained 9283 * Set to true in order to prevent scroll from being constrained
9094 * to the dropdown when it opens. 9284 * to the dropdown when it opens.
9095 */ 9285 */
9096 allowOutsideScroll: { 9286 allowOutsideScroll: {
9097 type: Boolean, 9287 type: Boolean,
9098 value: false 9288 value: false
9099 },
9100
9101 /**
9102 * We memoize the positionTarget bounding rectangle so that we can
9103 * limit the number of times it is queried per resize / relayout.
9104 * @type {?Object}
9105 */
9106 _positionRectMemo: {
9107 type: Object
9108 } 9289 }
9109 }, 9290 },
9110 9291
9111 listeners: { 9292 listeners: {
9112 'neon-animation-finish': '_onNeonAnimationFinish' 9293 'neon-animation-finish': '_onNeonAnimationFinish'
9113 }, 9294 },
9114 9295
9115 observers: [ 9296 observers: [
9116 '_updateOverlayPosition(verticalAlign, horizontalAlign, verticalOffset , horizontalOffset)' 9297 '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign , verticalOffset, horizontalOffset)'
9117 ], 9298 ],
9118 9299
9119 attached: function() { 9300 attached: function() {
9120 if (this.positionTarget === undefined) { 9301 this.positionTarget = this.positionTarget || this._defaultPositionTarg et;
9121 this.positionTarget = this._defaultPositionTarget; 9302 // Memoize this to avoid expensive calculations & relayouts.
9122 } 9303 this._isRTL = window.getComputedStyle(this).direction == 'rtl';
9123 }, 9304 },
9124 9305
9125 /** 9306 /**
9126 * The element that is contained by the dropdown, if any. 9307 * The element that is contained by the dropdown, if any.
9127 */ 9308 */
9128 get containedElement() { 9309 get containedElement() {
9129 return Polymer.dom(this.$.content).getDistributedNodes()[0]; 9310 return Polymer.dom(this.$.content).getDistributedNodes()[0];
9130 }, 9311 },
9131 9312
9132 /** 9313 /**
9133 * The element that should be focused when the dropdown opens. 9314 * The element that should be focused when the dropdown opens.
9134 * @deprecated 9315 * @deprecated
9135 */ 9316 */
9136 get _focusTarget() { 9317 get _focusTarget() {
9137 return this.focusTarget || this.containedElement; 9318 return this.focusTarget || this.containedElement;
9138 }, 9319 },
9139 9320
9140 /** 9321 /**
9141 * Whether the text direction is RTL
9142 */
9143 _isRTL: function() {
9144 return window.getComputedStyle(this).direction == 'rtl';
9145 },
9146
9147 /**
9148 * The element that should be used to position the dropdown when 9322 * The element that should be used to position the dropdown when
9149 * it opens, if no position target is configured. 9323 * it opens, if no position target is configured.
9150 */ 9324 */
9151 get _defaultPositionTarget() { 9325 get _defaultPositionTarget() {
9152 var parent = Polymer.dom(this).parentNode; 9326 var parent = Polymer.dom(this).parentNode;
9153 9327
9154 if (parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { 9328 if (parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
9155 parent = parent.host; 9329 parent = parent.host;
9156 } 9330 }
9157 9331
9158 return parent; 9332 return parent;
9159 }, 9333 },
9160 9334
9161 /** 9335 /**
9162 * The bounding rect of the position target. 9336 * The horizontal align value, accounting for the RTL/LTR text direction .
9163 */ 9337 */
9164 get _positionRect() { 9338 get _localeHorizontalAlign() {
9165 if (!this._positionRectMemo && this.positionTarget) { 9339 // In RTL, "left" becomes "right".
9166 this._positionRectMemo = this.positionTarget.getBoundingClientRect() ; 9340 if (this._isRTL) {
9341 return this.horizontalAlign === 'right' ? 'left' : 'right';
9342 } else {
9343 return this.horizontalAlign;
9167 } 9344 }
9168
9169 return this._positionRectMemo;
9170 }, 9345 },
9171 9346
9172 /** 9347 /**
9173 * The horizontal offset value used to position the dropdown. 9348 * The horizontal offset value used to position the dropdown.
9349 * @param {ClientRect} dropdownRect
9350 * @param {ClientRect} positionRect
9351 * @param {boolean=false} fromRight
9352 * @return {number} pixels
9353 * @private
9174 */ 9354 */
9175 get _horizontalAlignTargetValue() { 9355 _horizontalAlignTargetValue: function(dropdownRect, positionRect, fromRi ght) {
9176 var target; 9356 var target;
9177 9357 if (fromRight) {
9178 // In RTL, the direction flips, so what is "right" in LTR becomes "lef t". 9358 target = document.documentElement.clientWidth - positionRect.right - (this._fitWidth - dropdownRect.right);
9179 var isRTL = this._isRTL();
9180 if ((!isRTL && this.horizontalAlign === 'right') ||
9181 (isRTL && this.horizontalAlign === 'left')) {
9182 target = document.documentElement.clientWidth - this._positionRect.r ight;
9183 } else { 9359 } else {
9184 target = this._positionRect.left; 9360 target = positionRect.left - dropdownRect.left;
9185 } 9361 }
9186
9187 target += this.horizontalOffset; 9362 target += this.horizontalOffset;
9188 9363
9189 return Math.max(target, 0); 9364 return Math.max(target, 0);
9190 }, 9365 },
9191 9366
9192 /** 9367 /**
9193 * The vertical offset value used to position the dropdown. 9368 * The vertical offset value used to position the dropdown.
9369 * @param {ClientRect} dropdownRect
9370 * @param {ClientRect} positionRect
9371 * @param {boolean=false} fromBottom
9372 * @return {number} pixels
9373 * @private
9194 */ 9374 */
9195 get _verticalAlignTargetValue() { 9375 _verticalAlignTargetValue: function(dropdownRect, positionRect, fromBott om) {
9196 var target; 9376 var target;
9197 9377 if (fromBottom) {
9198 if (this.verticalAlign === 'bottom') { 9378 target = document.documentElement.clientHeight - positionRect.bottom - (this._fitHeight - dropdownRect.bottom);
9199 target = document.documentElement.clientHeight - this._positionRect. bottom;
9200 } else { 9379 } else {
9201 target = this._positionRect.top; 9380 target = positionRect.top - dropdownRect.top;
9202 } 9381 }
9203
9204 target += this.verticalOffset; 9382 target += this.verticalOffset;
9205 9383
9206 return Math.max(target, 0); 9384 return Math.max(target, 0);
9207 }, 9385 },
9208 9386
9209 /** 9387 /**
9210 * The horizontal align value, accounting for the RTL/LTR text direction .
9211 */
9212 get _localeHorizontalAlign() {
9213 // In RTL, "left" becomes "right".
9214 if (this._isRTL()) {
9215 return this.horizontalAlign === 'right' ? 'left' : 'right';
9216 } else {
9217 return this.horizontalAlign;
9218 }
9219 },
9220
9221 /**
9222 * Called when the value of `opened` changes. 9388 * Called when the value of `opened` changes.
9223 * 9389 *
9224 * @param {boolean} opened True if the dropdown is opened. 9390 * @param {boolean} opened True if the dropdown is opened.
9225 */ 9391 */
9226 _openedChanged: function(opened) { 9392 _openedChanged: function(opened) {
9227 if (opened && this.disabled) { 9393 if (opened && this.disabled) {
9228 this.cancel(); 9394 this.cancel();
9229 } else { 9395 } else {
9230 this.cancelAnimation(); 9396 this.cancelAnimation();
9231 this._prepareDropdown(); 9397 this.sizingTarget = this.containedElement || this.sizingTarget;
9398 this._updateAnimationConfig();
9232 Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments ); 9399 Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments );
9233 } 9400 }
9234 }, 9401 },
9235 9402
9236 /** 9403 /**
9237 * Overridden from `IronOverlayBehavior`. 9404 * Overridden from `IronOverlayBehavior`.
9238 */ 9405 */
9239 _renderOpened: function() { 9406 _renderOpened: function() {
9240 if (!this.allowOutsideScroll) { 9407 if (!this.allowOutsideScroll) {
9241 Polymer.IronDropdownScrollManager.pushScrollLock(this); 9408 Polymer.IronDropdownScrollManager.pushScrollLock(this);
9242 } 9409 }
9243 9410
9244 if (!this.noAnimations && this.animationConfig && this.animationConfig .open) { 9411 if (!this.noAnimations && this.animationConfig && this.animationConfig .open) {
9412 if (this.withBackdrop) {
9413 this.backdropElement.open();
9414 }
9245 this.$.contentWrapper.classList.add('animating'); 9415 this.$.contentWrapper.classList.add('animating');
9246 this.playAnimation('open'); 9416 this.playAnimation('open');
9247 } else { 9417 } else {
9248 Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments) ; 9418 Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments) ;
9249 } 9419 }
9250 }, 9420 },
9251 9421
9252 /** 9422 /**
9253 * Overridden from `IronOverlayBehavior`. 9423 * Overridden from `IronOverlayBehavior`.
9254 */ 9424 */
9255 _renderClosed: function() { 9425 _renderClosed: function() {
9256 Polymer.IronDropdownScrollManager.removeScrollLock(this); 9426 Polymer.IronDropdownScrollManager.removeScrollLock(this);
9257 if (!this.noAnimations && this.animationConfig && this.animationConfig .close) { 9427 if (!this.noAnimations && this.animationConfig && this.animationConfig .close) {
9428 if (this.withBackdrop) {
9429 this.backdropElement.close();
9430 }
9258 this.$.contentWrapper.classList.add('animating'); 9431 this.$.contentWrapper.classList.add('animating');
9259 this.playAnimation('close'); 9432 this.playAnimation('close');
9260 } else { 9433 } else {
9261 Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments) ; 9434 Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments) ;
9262 } 9435 }
9263 }, 9436 },
9264 9437
9265 /** 9438 /**
9266 * Called when animation finishes on the dropdown (when opening or 9439 * Called when animation finishes on the dropdown (when opening or
9267 * closing). Responsible for "completing" the process of opening or 9440 * closing). Responsible for "completing" the process of opening or
9268 * closing the dropdown by positioning it or setting its display to 9441 * closing the dropdown by positioning it or setting its display to
9269 * none. 9442 * none.
9270 */ 9443 */
9271 _onNeonAnimationFinish: function() { 9444 _onNeonAnimationFinish: function() {
9272 this.$.contentWrapper.classList.remove('animating'); 9445 this.$.contentWrapper.classList.remove('animating');
9273 if (this.opened) { 9446 if (this.opened) {
9274 Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this); 9447 Polymer.IronOverlayBehaviorImpl._finishRenderOpened.apply(this);
9275 } else { 9448 } else {
9276 Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this); 9449 Polymer.IronOverlayBehaviorImpl._finishRenderClosed.apply(this);
9277 } 9450 }
9278 }, 9451 },
9279 9452
9280 /** 9453 /**
9281 * Called when an `iron-resize` event fires.
9282 */
9283 _onIronResize: function() {
9284 var containedElement = this.containedElement;
9285 var scrollTop;
9286 var scrollLeft;
9287
9288 if (this.opened && containedElement) {
9289 scrollTop = containedElement.scrollTop;
9290 scrollLeft = containedElement.scrollLeft;
9291 }
9292
9293 if (this.opened) {
9294 this._updateOverlayPosition();
9295 }
9296
9297 Polymer.IronOverlayBehaviorImpl._onIronResize.apply(this, arguments);
9298
9299 if (this.opened && containedElement) {
9300 containedElement.scrollTop = scrollTop;
9301 containedElement.scrollLeft = scrollLeft;
9302 }
9303 },
9304
9305 /**
9306 * Called when the `positionTarget` property changes.
9307 */
9308 _positionTargetChanged: function() {
9309 this._updateOverlayPosition();
9310 },
9311
9312 /**
9313 * Constructs the final animation config from different properties used 9454 * Constructs the final animation config from different properties used
9314 * to configure specific parts of the opening and closing animations. 9455 * to configure specific parts of the opening and closing animations.
9315 */ 9456 */
9316 _updateAnimationConfig: function() { 9457 _updateAnimationConfig: function() {
9317 var animationConfig = {}; 9458 var animationConfig = {};
9318 var animations = []; 9459 var animations = [];
9319 9460
9320 if (this.openAnimationConfig) { 9461 if (this.openAnimationConfig) {
9321 // NOTE(cdata): When making `display:none` elements visible in Safar i, 9462 // NOTE(cdata): When making `display:none` elements visible in Safar i,
9322 // the element will paint once in a fully visible state, causing the 9463 // the element will paint once in a fully visible state, causing the
(...skipping 11 matching lines...) Expand all
9334 } 9475 }
9335 9476
9336 animations.forEach(function(animation) { 9477 animations.forEach(function(animation) {
9337 animation.node = this.containedElement; 9478 animation.node = this.containedElement;
9338 }, this); 9479 }, this);
9339 9480
9340 this.animationConfig = animationConfig; 9481 this.animationConfig = animationConfig;
9341 }, 9482 },
9342 9483
9343 /** 9484 /**
9344 * Prepares the dropdown for opening by updating measured layout
9345 * values.
9346 */
9347 _prepareDropdown: function() {
9348 this.sizingTarget = this.containedElement || this.sizingTarget;
9349 this._updateAnimationConfig();
9350 this._updateOverlayPosition();
9351 },
9352
9353 /**
9354 * Updates the overlay position based on configured horizontal 9485 * Updates the overlay position based on configured horizontal
9355 * and vertical alignment, and re-memoizes these values for the sake 9486 * and vertical alignment.
9356 * of behavior in `IronFitBehavior`.
9357 */ 9487 */
9358 _updateOverlayPosition: function() { 9488 _updateOverlayPosition: function() {
9359 this._positionRectMemo = null; 9489 if (this.isAttached) {
9360 9490 // This triggers iron-resize, and iron-overlay-behavior will call re fit if needed.
9361 if (!this.positionTarget) { 9491 this.notifyResize();
9362 return;
9363 }
9364
9365 this.style[this._localeHorizontalAlign] =
9366 this._horizontalAlignTargetValue + 'px';
9367
9368 this.style[this.verticalAlign] =
9369 this._verticalAlignTargetValue + 'px';
9370
9371 // NOTE(cdata): We re-memoize inline styles here, otherwise
9372 // calling `refit` from `IronFitBehavior` will reset inline styles
9373 // to whatever they were when the dropdown first opened.
9374 if (this._fitInfo) {
9375 this._fitInfo.inlineStyle[this.horizontalAlign] =
9376 this.style[this.horizontalAlign];
9377
9378 this._fitInfo.inlineStyle[this.verticalAlign] =
9379 this.style[this.verticalAlign];
9380 } 9492 }
9381 }, 9493 },
9382 9494
9383 /** 9495 /**
9496 * Useful to call this after the element, the window, or the `fitInfo`
9497 * element has been resized. Will maintain the scroll position.
9498 */
9499 refit: function () {
9500 if (!this.opened) {
9501 return
9502 }
9503 var containedElement = this.containedElement;
9504 var scrollTop;
9505 var scrollLeft;
9506
9507 if (containedElement) {
9508 scrollTop = containedElement.scrollTop;
9509 scrollLeft = containedElement.scrollLeft;
9510 }
9511 Polymer.IronFitBehavior.refit.apply(this, arguments);
9512
9513 if (containedElement) {
9514 containedElement.scrollTop = scrollTop;
9515 containedElement.scrollLeft = scrollLeft;
9516 }
9517 },
9518
9519 /**
9520 * Resets the target element's position and size constraints, and clear
9521 * the memoized data.
9522 */
9523 resetFit: function() {
9524 Polymer.IronFitBehavior.resetFit.apply(this, arguments);
9525
9526 var hAlign = this._localeHorizontalAlign;
9527 var vAlign = this.verticalAlign;
9528 // Set to 0, 0 in order to discover any offset caused by parent stacki ng contexts.
9529 this.style[hAlign] = this.style[vAlign] = '0px';
9530
9531 var dropdownRect = this.getBoundingClientRect();
9532 var positionRect = this.positionTarget.getBoundingClientRect();
9533 var horizontalValue = this._horizontalAlignTargetValue(dropdownRect, p ositionRect, hAlign === 'right');
9534 var verticalValue = this._verticalAlignTargetValue(dropdownRect, posit ionRect, vAlign === 'bottom');
9535
9536 this.style[hAlign] = horizontalValue + 'px';
9537 this.style[vAlign] = verticalValue + 'px';
9538 },
9539
9540 /**
9541 * Overridden from `IronFitBehavior`.
9542 * Ensure positionedBy has correct values for horizontally & vertically.
9543 */
9544 _discoverInfo: function() {
9545 Polymer.IronFitBehavior._discoverInfo.apply(this, arguments);
9546 // Note(valdrin): in Firefox, an element with style `position: fixed; bottom: 90vh; height: 20vh`
9547 // would have `getComputedStyle(element).top < 0` (instead of being `a uto`) http://jsbin.com/cofired/3/edit?html,output
9548 // This would cause IronFitBehavior's `constrain` to wrongly calculate sizes
9549 // (it would use `top` instead of `bottom`), so we ensure we give the correct values.
9550 this._fitInfo.positionedBy.horizontally = this._localeHorizontalAlign;
9551 this._fitInfo.positionedBy.vertically = this.verticalAlign;
9552 },
9553
9554 /**
9384 * Apply focus to focusTarget or containedElement 9555 * Apply focus to focusTarget or containedElement
9385 */ 9556 */
9386 _applyFocus: function () { 9557 _applyFocus: function () {
9387 var focusTarget = this.focusTarget || this.containedElement; 9558 var focusTarget = this.focusTarget || this.containedElement;
9388 if (focusTarget && this.opened && !this.noAutoFocus) { 9559 if (focusTarget && this.opened && !this.noAutoFocus) {
9389 focusTarget.focus(); 9560 focusTarget.focus();
9390 } else { 9561 } else {
9391 Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments); 9562 Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
9392 } 9563 }
9393 } 9564 }
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
9515 transform: 'translateY(0)' 9686 transform: 'translateY(0)'
9516 }, { 9687 }, {
9517 height: height / 2 + 'px', 9688 height: height / 2 + 'px',
9518 transform: 'translateY(-20px)' 9689 transform: 'translateY(-20px)'
9519 }], this.timingFromConfig(config)); 9690 }], this.timingFromConfig(config));
9520 9691
9521 return this._effect; 9692 return this._effect;
9522 } 9693 }
9523 }); 9694 });
9524 (function() { 9695 (function() {
9525 'use strict'; 9696 'use strict';
9526 9697
9527 var PaperMenuButton = Polymer({ 9698 var PaperMenuButton = Polymer({
9528 is: 'paper-menu-button', 9699 is: 'paper-menu-button',
9529 9700
9530 /** 9701 /**
9531 * Fired when the dropdown opens. 9702 * Fired when the dropdown opens.
9532 * 9703 *
9533 * @event paper-dropdown-open 9704 * @event paper-dropdown-open
9534 */ 9705 */
9535 9706
9536 /** 9707 /**
9537 * Fired when the dropdown closes. 9708 * Fired when the dropdown closes.
9538 * 9709 *
9539 * @event paper-dropdown-close 9710 * @event paper-dropdown-close
9540 */ 9711 */
9541 9712
9542 behaviors: [ 9713 behaviors: [
9543 Polymer.IronA11yKeysBehavior, 9714 Polymer.IronA11yKeysBehavior,
9544 Polymer.IronControlState 9715 Polymer.IronControlState
9545 ], 9716 ],
9546 9717
9547 properties: { 9718 properties: {
9548 9719 /**
9549 /** 9720 * True if the content is currently displayed.
9550 * True if the content is currently displayed. 9721 */
9551 */ 9722 opened: {
9552 opened: { 9723 type: Boolean,
9553 type: Boolean, 9724 value: false,
9554 value: false, 9725 notify: true,
9555 notify: true, 9726 observer: '_openedChanged'
9556 observer: '_openedChanged' 9727 },
9557 }, 9728
9558 9729 /**
9559 /** 9730 * The orientation against which to align the menu dropdown
9560 * The orientation against which to align the menu dropdown 9731 * horizontally relative to the dropdown trigger.
9561 * horizontally relative to the dropdown trigger. 9732 */
9562 */ 9733 horizontalAlign: {
9563 horizontalAlign: { 9734 type: String,
9564 type: String, 9735 value: 'left',
9565 value: 'left', 9736 reflectToAttribute: true
9566 reflectToAttribute: true 9737 },
9567 }, 9738
9568 9739 /**
9569 /** 9740 * The orientation against which to align the menu dropdown
9570 * The orientation against which to align the menu dropdown 9741 * vertically relative to the dropdown trigger.
9571 * vertically relative to the dropdown trigger. 9742 */
9572 */ 9743 verticalAlign: {
9573 verticalAlign: { 9744 type: String,
9574 type: String, 9745 value: 'top',
9575 value: 'top', 9746 reflectToAttribute: true
9576 reflectToAttribute: true 9747 },
9577 }, 9748
9578 9749 /**
9579 /** 9750 * A pixel value that will be added to the position calculated for the
9580 * A pixel value that will be added to the position calculated for the 9751 * given `horizontalAlign`. Use a negative value to offset to the
9581 * given `horizontalAlign`. Use a negative value to offset to the 9752 * left, or a positive value to offset to the right.
9582 * left, or a positive value to offset to the right. 9753 */
9583 */ 9754 horizontalOffset: {
9584 horizontalOffset: { 9755 type: Number,
9585 type: Number, 9756 value: 0,
9586 value: 0, 9757 notify: true
9587 notify: true 9758 },
9588 }, 9759
9589 9760 /**
9590 /** 9761 * A pixel value that will be added to the position calculated for the
9591 * A pixel value that will be added to the position calculated for the 9762 * given `verticalAlign`. Use a negative value to offset towards the
9592 * given `verticalAlign`. Use a negative value to offset towards the 9763 * top, or a positive value to offset towards the bottom.
9593 * top, or a positive value to offset towards the bottom. 9764 */
9594 */ 9765 verticalOffset: {
9595 verticalOffset: { 9766 type: Number,
9596 type: Number, 9767 value: 0,
9597 value: 0, 9768 notify: true
9598 notify: true 9769 },
9599 }, 9770
9600 9771 /**
9601 /** 9772 * Set to true to disable animations when opening and closing the
9602 * Set to true to disable animations when opening and closing the 9773 * dropdown.
9774 */
9775 noAnimations: {
9776 type: Boolean,
9777 value: false
9778 },
9779
9780 /**
9781 * Set to true to disable automatically closing the dropdown after
9782 * a selection has been made.
9783 */
9784 ignoreSelect: {
9785 type: Boolean,
9786 value: false
9787 },
9788
9789 /**
9790 * An animation config. If provided, this will be used to animate the
9791 * opening of the dropdown.
9792 */
9793 openAnimationConfig: {
9794 type: Object,
9795 value: function() {
9796 return [{
9797 name: 'fade-in-animation',
9798 timing: {
9799 delay: 100,
9800 duration: 200
9801 }
9802 }, {
9803 name: 'paper-menu-grow-width-animation',
9804 timing: {
9805 delay: 100,
9806 duration: 150,
9807 easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
9808 }
9809 }, {
9810 name: 'paper-menu-grow-height-animation',
9811 timing: {
9812 delay: 100,
9813 duration: 275,
9814 easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
9815 }
9816 }];
9817 }
9818 },
9819
9820 /**
9821 * An animation config. If provided, this will be used to animate the
9822 * closing of the dropdown.
9823 */
9824 closeAnimationConfig: {
9825 type: Object,
9826 value: function() {
9827 return [{
9828 name: 'fade-out-animation',
9829 timing: {
9830 duration: 150
9831 }
9832 }, {
9833 name: 'paper-menu-shrink-width-animation',
9834 timing: {
9835 delay: 100,
9836 duration: 50,
9837 easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
9838 }
9839 }, {
9840 name: 'paper-menu-shrink-height-animation',
9841 timing: {
9842 duration: 200,
9843 easing: 'ease-in'
9844 }
9845 }];
9846 }
9847 },
9848
9849 /**
9850 * This is the element intended to be bound as the focus target
9851 * for the `iron-dropdown` contained by `paper-menu-button`.
9852 */
9853 _dropdownContent: {
9854 type: Object
9855 }
9856 },
9857
9858 hostAttributes: {
9859 role: 'group',
9860 'aria-haspopup': 'true'
9861 },
9862
9863 listeners: {
9864 'iron-select': '_onIronSelect'
9865 },
9866
9867 /**
9868 * The content element that is contained by the menu button, if any.
9869 */
9870 get contentElement() {
9871 return Polymer.dom(this.$.content).getDistributedNodes()[0];
9872 },
9873
9874 /**
9875 * Toggles the drowpdown content between opened and closed.
9876 */
9877 toggle: function() {
9878 if (this.opened) {
9879 this.close();
9880 } else {
9881 this.open();
9882 }
9883 },
9884
9885 /**
9886 * Make the dropdown content appear as an overlay positioned relative
9887 * to the dropdown trigger.
9888 */
9889 open: function() {
9890 if (this.disabled) {
9891 return;
9892 }
9893
9894 this.$.dropdown.open();
9895 },
9896
9897 /**
9898 * Hide the dropdown content.
9899 */
9900 close: function() {
9901 this.$.dropdown.close();
9902 },
9903
9904 /**
9905 * When an `iron-select` event is received, the dropdown should
9906 * automatically close on the assumption that a value has been chosen.
9907 *
9908 * @param {CustomEvent} event A CustomEvent instance with type
9909 * set to `"iron-select"`.
9910 */
9911 _onIronSelect: function(event) {
9912 if (!this.ignoreSelect) {
9913 this.close();
9914 }
9915 },
9916
9917 /**
9918 * When the dropdown opens, the `paper-menu-button` fires `paper-open`.
9919 * When the dropdown closes, the `paper-menu-button` fires `paper-close` .
9920 *
9921 * @param {boolean} opened True if the dropdown is opened, otherwise fal se.
9922 * @param {boolean} oldOpened The previous value of `opened`.
9923 */
9924 _openedChanged: function(opened, oldOpened) {
9925 if (opened) {
9926 // TODO(cdata): Update this when we can measure changes in distribut ed
9927 // children in an idiomatic way.
9928 // We poke this property in case the element has changed. This will
9929 // cause the focus target for the `iron-dropdown` to be updated as
9930 // necessary:
9931 this._dropdownContent = this.contentElement;
9932 this.fire('paper-dropdown-open');
9933 } else if (oldOpened != null) {
9934 this.fire('paper-dropdown-close');
9935 }
9936 },
9937
9938 /**
9939 * If the dropdown is open when disabled becomes true, close the
9603 * dropdown. 9940 * dropdown.
9604 */ 9941 *
9605 noAnimations: { 9942 * @param {boolean} disabled True if disabled, otherwise false.
9606 type: Boolean, 9943 */
9607 value: false 9944 _disabledChanged: function(disabled) {
9608 }, 9945 Polymer.IronControlState._disabledChanged.apply(this, arguments);
9609 9946 if (disabled && this.opened) {
9610 /** 9947 this.close();
9611 * Set to true to disable automatically closing the dropdown after 9948 }
9612 * a selection has been made. 9949 },
9613 */ 9950
9614 ignoreSelect: { 9951 __onIronOverlayCanceled: function(event) {
9615 type: Boolean, 9952 var uiEvent = event.detail;
9616 value: false 9953 var target = Polymer.dom(uiEvent).rootTarget;
9617 }, 9954 var trigger = this.$.trigger;
9618 9955 var path = Polymer.dom(uiEvent).path;
9619 /** 9956
9620 * An animation config. If provided, this will be used to animate the 9957 if (path.indexOf(trigger) > -1) {
9621 * opening of the dropdown. 9958 event.preventDefault();
9622 */ 9959 }
9623 openAnimationConfig: {
9624 type: Object,
9625 value: function() {
9626 return [{
9627 name: 'fade-in-animation',
9628 timing: {
9629 delay: 100,
9630 duration: 200
9631 }
9632 }, {
9633 name: 'paper-menu-grow-width-animation',
9634 timing: {
9635 delay: 100,
9636 duration: 150,
9637 easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
9638 }
9639 }, {
9640 name: 'paper-menu-grow-height-animation',
9641 timing: {
9642 delay: 100,
9643 duration: 275,
9644 easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
9645 }
9646 }];
9647 }
9648 },
9649
9650 /**
9651 * An animation config. If provided, this will be used to animate the
9652 * closing of the dropdown.
9653 */
9654 closeAnimationConfig: {
9655 type: Object,
9656 value: function() {
9657 return [{
9658 name: 'fade-out-animation',
9659 timing: {
9660 duration: 150
9661 }
9662 }, {
9663 name: 'paper-menu-shrink-width-animation',
9664 timing: {
9665 delay: 100,
9666 duration: 50,
9667 easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
9668 }
9669 }, {
9670 name: 'paper-menu-shrink-height-animation',
9671 timing: {
9672 duration: 200,
9673 easing: 'ease-in'
9674 }
9675 }];
9676 }
9677 },
9678
9679 /**
9680 * This is the element intended to be bound as the focus target
9681 * for the `iron-dropdown` contained by `paper-menu-button`.
9682 */
9683 _dropdownContent: {
9684 type: Object
9685 } 9960 }
9686 }, 9961 });
9687 9962
9688 hostAttributes: { 9963 PaperMenuButton.ANIMATION_CUBIC_BEZIER = 'cubic-bezier(.3,.95,.5,1)';
9689 role: 'group', 9964 PaperMenuButton.MAX_ANIMATION_TIME_MS = 400;
9690 'aria-haspopup': 'true' 9965
9691 }, 9966 Polymer.PaperMenuButton = PaperMenuButton;
9692 9967 })();
9693 listeners: {
9694 'iron-select': '_onIronSelect'
9695 },
9696
9697 /**
9698 * The content element that is contained by the menu button, if any.
9699 */
9700 get contentElement() {
9701 return Polymer.dom(this.$.content).getDistributedNodes()[0];
9702 },
9703
9704 /**
9705 * Make the dropdown content appear as an overlay positioned relative
9706 * to the dropdown trigger.
9707 */
9708 open: function() {
9709 if (this.disabled) {
9710 return;
9711 }
9712
9713 this.$.dropdown.open();
9714 },
9715
9716 /**
9717 * Hide the dropdown content.
9718 */
9719 close: function() {
9720 this.$.dropdown.close();
9721 },
9722
9723 /**
9724 * When an `iron-select` event is received, the dropdown should
9725 * automatically close on the assumption that a value has been chosen.
9726 *
9727 * @param {CustomEvent} event A CustomEvent instance with type
9728 * set to `"iron-select"`.
9729 */
9730 _onIronSelect: function(event) {
9731 if (!this.ignoreSelect) {
9732 this.close();
9733 }
9734 },
9735
9736 /**
9737 * When the dropdown opens, the `paper-menu-button` fires `paper-open`.
9738 * When the dropdown closes, the `paper-menu-button` fires `paper-close`.
9739 *
9740 * @param {boolean} opened True if the dropdown is opened, otherwise false .
9741 * @param {boolean} oldOpened The previous value of `opened`.
9742 */
9743 _openedChanged: function(opened, oldOpened) {
9744 if (opened) {
9745 // TODO(cdata): Update this when we can measure changes in distributed
9746 // children in an idiomatic way.
9747 // We poke this property in case the element has changed. This will
9748 // cause the focus target for the `iron-dropdown` to be updated as
9749 // necessary:
9750 this._dropdownContent = this.contentElement;
9751 this.fire('paper-dropdown-open');
9752 } else if (oldOpened != null) {
9753 this.fire('paper-dropdown-close');
9754 }
9755 },
9756
9757 /**
9758 * If the dropdown is open when disabled becomes true, close the
9759 * dropdown.
9760 *
9761 * @param {boolean} disabled True if disabled, otherwise false.
9762 */
9763 _disabledChanged: function(disabled) {
9764 Polymer.IronControlState._disabledChanged.apply(this, arguments);
9765 if (disabled && this.opened) {
9766 this.close();
9767 }
9768 }
9769 });
9770
9771 PaperMenuButton.ANIMATION_CUBIC_BEZIER = 'cubic-bezier(.3,.95,.5,1)';
9772 PaperMenuButton.MAX_ANIMATION_TIME_MS = 400;
9773
9774 Polymer.PaperMenuButton = PaperMenuButton;
9775 })();
9776 Polymer({ 9968 Polymer({
9777 is: 'paper-icon-button', 9969 is: 'paper-icon-button',
9778 9970
9779 hostAttributes: { 9971 hostAttributes: {
9780 role: 'button', 9972 role: 'button',
9781 tabindex: '0' 9973 tabindex: '0'
9782 }, 9974 },
9783 9975
9784 behaviors: [ 9976 behaviors: [
9785 Polymer.PaperInkyFocusBehavior 9977 Polymer.PaperInkyFocusBehavior
(...skipping 28 matching lines...) Expand all
9814 10006
9815 _altChanged: function(newValue, oldValue) { 10007 _altChanged: function(newValue, oldValue) {
9816 var label = this.getAttribute('aria-label'); 10008 var label = this.getAttribute('aria-label');
9817 10009
9818 // Don't stomp over a user-set aria-label. 10010 // Don't stomp over a user-set aria-label.
9819 if (!label || oldValue == label) { 10011 if (!label || oldValue == label) {
9820 this.setAttribute('aria-label', newValue); 10012 this.setAttribute('aria-label', newValue);
9821 } 10013 }
9822 } 10014 }
9823 }); 10015 });
10016 (function() {
10017 'use strict';
10018
10019 Polymer.IronA11yAnnouncer = Polymer({
10020 is: 'iron-a11y-announcer',
10021
10022 properties: {
10023
10024 /**
10025 * The value of mode is used to set the `aria-live` attribute
10026 * for the element that will be announced. Valid values are: `off`,
10027 * `polite` and `assertive`.
10028 */
10029 mode: {
10030 type: String,
10031 value: 'polite'
10032 },
10033
10034 _text: {
10035 type: String,
10036 value: ''
10037 }
10038 },
10039
10040 created: function() {
10041 if (!Polymer.IronA11yAnnouncer.instance) {
10042 Polymer.IronA11yAnnouncer.instance = this;
10043 }
10044
10045 document.body.addEventListener('iron-announce', this._onIronAnnounce.b ind(this));
10046 },
10047
10048 /**
10049 * Cause a text string to be announced by screen readers.
10050 *
10051 * @param {string} text The text that should be announced.
10052 */
10053 announce: function(text) {
10054 this._text = '';
10055 this.async(function() {
10056 this._text = text;
10057 }, 100);
10058 },
10059
10060 _onIronAnnounce: function(event) {
10061 if (event.detail && event.detail.text) {
10062 this.announce(event.detail.text);
10063 }
10064 }
10065 });
10066
10067 Polymer.IronA11yAnnouncer.instance = null;
10068
10069 Polymer.IronA11yAnnouncer.requestAvailability = function() {
10070 if (!Polymer.IronA11yAnnouncer.instance) {
10071 Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y -announcer');
10072 }
10073
10074 document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
10075 };
10076 })();
9824 /** 10077 /**
9825 * `Use Polymer.IronValidatableBehavior` to implement an element that validate s user input. 10078 * `Use Polymer.IronValidatableBehavior` to implement an element that validate s user input.
9826 * Use the related `Polymer.IronValidatorBehavior` to add custom validation lo gic to an iron-input. 10079 * Use the related `Polymer.IronValidatorBehavior` to add custom validation lo gic to an iron-input.
9827 * 10080 *
9828 * By default, an `<iron-form>` element validates its fields when the user pre sses the submit button. 10081 * By default, an `<iron-form>` element validates its fields when the user pre sses the submit button.
9829 * To validate a form imperatively, call the form's `validate()` method, which in turn will 10082 * To validate a form imperatively, call the form's `validate()` method, which in turn will
9830 * call `validate()` on all its children. By using `Polymer.IronValidatableBeh avior`, your 10083 * call `validate()` on all its children. By using `Polymer.IronValidatableBeh avior`, your
9831 * custom element will get a public `validate()`, which 10084 * custom element will get a public `validate()`, which
9832 * will return the validity of the element, and a corresponding `invalid` attr ibute, 10085 * will return the validity of the element, and a corresponding `invalid` attr ibute,
9833 * which can be used for styling. 10086 * which can be used for styling.
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
9986 10239
9987 /** 10240 /**
9988 * Use this property instead of `value` for two-way data binding. 10241 * Use this property instead of `value` for two-way data binding.
9989 */ 10242 */
9990 bindValue: { 10243 bindValue: {
9991 observer: '_bindValueChanged', 10244 observer: '_bindValueChanged',
9992 type: String 10245 type: String
9993 }, 10246 },
9994 10247
9995 /** 10248 /**
9996 * Set to true to prevent the user from entering invalid input. The new in put characters are 10249 * Set to true to prevent the user from entering invalid input. If `allowe dPattern` is set,
9997 * matched with `allowedPattern` if it is set, otherwise it will use the ` type` attribute (only 10250 * any character typed by the user will be matched against that pattern, a nd rejected if it's not a match.
9998 * supported for `type=number`). 10251 * Pasted input will have each character checked individually; if any char acter
10252 * doesn't match `allowedPattern`, the entire pasted string will be reject ed.
10253 * If `allowedPattern` is not set, it will use the `type` attribute (only supported for `type=number`).
9999 */ 10254 */
10000 preventInvalidInput: { 10255 preventInvalidInput: {
10001 type: Boolean 10256 type: Boolean
10002 }, 10257 },
10003 10258
10004 /** 10259 /**
10005 * Regular expression expressing a set of characters to enforce the validi ty of input characters. 10260 * Regular expression that list the characters allowed as input.
10006 * The recommended value should follow this format: `[a-ZA-Z0-9.+-!;:]` th at list the characters 10261 * This pattern represents the allowed characters for the field; as the us er inputs text,
10007 * allowed as input. 10262 * each individual character will be checked against the pattern (rather t han checking
10263 * the entire value as a whole). The recommended format should be a list o f allowed characters;
10264 * for example, `[a-zA-Z0-9.+-!;:]`
10008 */ 10265 */
10009 allowedPattern: { 10266 allowedPattern: {
10010 type: String, 10267 type: String,
10011 observer: "_allowedPatternChanged" 10268 observer: "_allowedPatternChanged"
10012 }, 10269 },
10013 10270
10014 _previousValidInput: { 10271 _previousValidInput: {
10015 type: String, 10272 type: String,
10016 value: '' 10273 value: ''
10017 }, 10274 },
10018 10275
10019 _patternAlreadyChecked: { 10276 _patternAlreadyChecked: {
10020 type: Boolean, 10277 type: Boolean,
10021 value: false 10278 value: false
10022 } 10279 }
10023 10280
10024 }, 10281 },
10025 10282
10026 listeners: { 10283 listeners: {
10027 'input': '_onInput', 10284 'input': '_onInput',
10028 'keypress': '_onKeypress' 10285 'keypress': '_onKeypress'
10029 }, 10286 },
10030 10287
10288 registered: function() {
10289 // Feature detect whether we need to patch dispatchEvent (i.e. on FF and I E).
10290 if (!this._canDispatchEventOnDisabled()) {
10291 this._origDispatchEvent = this.dispatchEvent;
10292 this.dispatchEvent = this._dispatchEventFirefoxIE;
10293 }
10294 },
10295
10296 created: function() {
10297 Polymer.IronA11yAnnouncer.requestAvailability();
10298 },
10299
10300 _canDispatchEventOnDisabled: function() {
10301 var input = document.createElement('input');
10302 var canDispatch = false;
10303 input.disabled = true;
10304
10305 input.addEventListener('feature-check-dispatch-event', function() {
10306 canDispatch = true;
10307 });
10308
10309 try {
10310 input.dispatchEvent(new Event('feature-check-dispatch-event'));
10311 } catch(e) {}
10312
10313 return canDispatch;
10314 },
10315
10316 _dispatchEventFirefoxIE: function() {
10317 // Due to Firefox bug, events fired on disabled form controls can throw
10318 // errors; furthermore, neither IE nor Firefox will actually dispatch
10319 // events from disabled form controls; as such, we toggle disable around
10320 // the dispatch to allow notifying properties to notify
10321 // See issue #47 for details
10322 var disabled = this.disabled;
10323 this.disabled = false;
10324 this._origDispatchEvent.apply(this, arguments);
10325 this.disabled = disabled;
10326 },
10327
10031 get _patternRegExp() { 10328 get _patternRegExp() {
10032 var pattern; 10329 var pattern;
10033 if (this.allowedPattern) { 10330 if (this.allowedPattern) {
10034 pattern = new RegExp(this.allowedPattern); 10331 pattern = new RegExp(this.allowedPattern);
10035 } else { 10332 } else {
10036 switch (this.type) { 10333 switch (this.type) {
10037 case 'number': 10334 case 'number':
10038 pattern = /[0-9.,e-]/; 10335 pattern = /[0-9.,e-]/;
10039 break; 10336 break;
10040 } 10337 }
(...skipping 20 matching lines...) Expand all
10061 // Force to prevent invalid input when an `allowed-pattern` is set 10358 // Force to prevent invalid input when an `allowed-pattern` is set
10062 this.preventInvalidInput = this.allowedPattern ? true : false; 10359 this.preventInvalidInput = this.allowedPattern ? true : false;
10063 }, 10360 },
10064 10361
10065 _onInput: function() { 10362 _onInput: function() {
10066 // Need to validate each of the characters pasted if they haven't 10363 // Need to validate each of the characters pasted if they haven't
10067 // been validated inside `_onKeypress` already. 10364 // been validated inside `_onKeypress` already.
10068 if (this.preventInvalidInput && !this._patternAlreadyChecked) { 10365 if (this.preventInvalidInput && !this._patternAlreadyChecked) {
10069 var valid = this._checkPatternValidity(); 10366 var valid = this._checkPatternValidity();
10070 if (!valid) { 10367 if (!valid) {
10368 this._announceInvalidCharacter('Invalid string of characters not enter ed.');
10071 this.value = this._previousValidInput; 10369 this.value = this._previousValidInput;
10072 } 10370 }
10073 } 10371 }
10074 10372
10075 this.bindValue = this.value; 10373 this.bindValue = this.value;
10076 this._previousValidInput = this.value; 10374 this._previousValidInput = this.value;
10077 this._patternAlreadyChecked = false; 10375 this._patternAlreadyChecked = false;
10078 }, 10376 },
10079 10377
10080 _isPrintable: function(event) { 10378 _isPrintable: function(event) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
10121 // Handle special keys and backspace 10419 // Handle special keys and backspace
10122 if (event.metaKey || event.ctrlKey || event.altKey) 10420 if (event.metaKey || event.ctrlKey || event.altKey)
10123 return; 10421 return;
10124 10422
10125 // Check the pattern either here or in `_onInput`, but not in both. 10423 // Check the pattern either here or in `_onInput`, but not in both.
10126 this._patternAlreadyChecked = true; 10424 this._patternAlreadyChecked = true;
10127 10425
10128 var thisChar = String.fromCharCode(event.charCode); 10426 var thisChar = String.fromCharCode(event.charCode);
10129 if (this._isPrintable(event) && !regexp.test(thisChar)) { 10427 if (this._isPrintable(event) && !regexp.test(thisChar)) {
10130 event.preventDefault(); 10428 event.preventDefault();
10429 this._announceInvalidCharacter('Invalid character ' + thisChar + ' not e ntered.');
10131 } 10430 }
10132 }, 10431 },
10133 10432
10134 _checkPatternValidity: function() { 10433 _checkPatternValidity: function() {
10135 var regexp = this._patternRegExp; 10434 var regexp = this._patternRegExp;
10136 if (!regexp) { 10435 if (!regexp) {
10137 return true; 10436 return true;
10138 } 10437 }
10139 for (var i = 0; i < this.value.length; i++) { 10438 for (var i = 0; i < this.value.length; i++) {
10140 if (!regexp.test(this.value[i])) { 10439 if (!regexp.test(this.value[i])) {
10141 return false; 10440 return false;
10142 } 10441 }
10143 } 10442 }
10144 return true; 10443 return true;
10145 }, 10444 },
10146 10445
10147 /** 10446 /**
10148 * Returns true if `value` is valid. The validator provided in `validator` w ill be used first, 10447 * Returns true if `value` is valid. The validator provided in `validator` w ill be used first,
10149 * then any constraints. 10448 * then any constraints.
10150 * @return {boolean} True if the value is valid. 10449 * @return {boolean} True if the value is valid.
10151 */ 10450 */
10152 validate: function() { 10451 validate: function() {
10153 // Empty, non-required input is valid. 10452 // First, check what the browser thinks. Some inputs (like type=number)
10154 if (!this.required && this.value == '') { 10453 // behave weirdly and will set the value to "" if something invalid is
10155 this.invalid = false; 10454 // entered, but will set the validity correctly.
10156 return true; 10455 var valid = this.checkValidity();
10456
10457 // Only do extra checking if the browser thought this was valid.
10458 if (valid) {
10459 // Empty, required input is invalid
10460 if (this.required && this.value === '') {
10461 valid = false;
10462 } else if (this.hasValidator()) {
10463 valid = Polymer.IronValidatableBehavior.validate.call(this, this.value );
10464 }
10157 } 10465 }
10158 10466
10159 var valid; 10467 this.invalid = !valid;
10160 if (this.hasValidator()) {
10161 valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
10162 } else {
10163 valid = this.checkValidity();
10164 this.invalid = !valid;
10165 }
10166 this.fire('iron-input-validate'); 10468 this.fire('iron-input-validate');
10167 return valid; 10469 return valid;
10470 },
10471
10472 _announceInvalidCharacter: function(message) {
10473 this.fire('iron-announce', { text: message });
10168 } 10474 }
10169
10170 }); 10475 });
10171 10476
10172 /* 10477 /*
10173 The `iron-input-validate` event is fired whenever `validate()` is called. 10478 The `iron-input-validate` event is fired whenever `validate()` is called.
10174 @event iron-input-validate 10479 @event iron-input-validate
10175 */ 10480 */
10176 Polymer({ 10481 Polymer({
10177 is: 'paper-input-container', 10482 is: 'paper-input-container',
10178 10483
10179 properties: { 10484 properties: {
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
10296 get _inputElementValue() { 10601 get _inputElementValue() {
10297 return this._inputElement[this._propertyForValue] || this._inputElement.va lue; 10602 return this._inputElement[this._propertyForValue] || this._inputElement.va lue;
10298 }, 10603 },
10299 10604
10300 ready: function() { 10605 ready: function() {
10301 if (!this._addons) { 10606 if (!this._addons) {
10302 this._addons = []; 10607 this._addons = [];
10303 } 10608 }
10304 this.addEventListener('focus', this._boundOnFocus, true); 10609 this.addEventListener('focus', this._boundOnFocus, true);
10305 this.addEventListener('blur', this._boundOnBlur, true); 10610 this.addEventListener('blur', this._boundOnBlur, true);
10611 },
10612
10613 attached: function() {
10306 if (this.attrForValue) { 10614 if (this.attrForValue) {
10307 this._inputElement.addEventListener(this._valueChangedEvent, this._bound ValueChanged); 10615 this._inputElement.addEventListener(this._valueChangedEvent, this._bound ValueChanged);
10308 } else { 10616 } else {
10309 this.addEventListener('input', this._onInput); 10617 this.addEventListener('input', this._onInput);
10310 } 10618 }
10311 },
10312 10619
10313 attached: function() {
10314 // Only validate when attached if the input already has a value. 10620 // Only validate when attached if the input already has a value.
10315 if (this._inputElementValue != '') { 10621 if (this._inputElementValue != '') {
10316 this._handleValueAndAutoValidate(this._inputElement); 10622 this._handleValueAndAutoValidate(this._inputElement);
10317 } else { 10623 } else {
10318 this._handleValue(this._inputElement); 10624 this._handleValue(this._inputElement);
10319 } 10625 }
10320 }, 10626 },
10321 10627
10322 _onAddonAttached: function(event) { 10628 _onAddonAttached: function(event) {
10323 if (!this._addons) { 10629 if (!this._addons) {
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after
10862 // found in the LICENSE file. 11168 // found in the LICENSE file.
10863 11169
10864 // <include src="../../../../ui/webui/resources/js/i18n_template_no_process.js"> 11170 // <include src="../../../../ui/webui/resources/js/i18n_template_no_process.js">
10865 11171
10866 i18nTemplate.process(document, loadTimeData); 11172 i18nTemplate.process(document, loadTimeData);
10867 // Copyright 2015 The Chromium Authors. All rights reserved. 11173 // Copyright 2015 The Chromium Authors. All rights reserved.
10868 // Use of this source code is governed by a BSD-style license that can be 11174 // Use of this source code is governed by a BSD-style license that can be
10869 // found in the LICENSE file. 11175 // found in the LICENSE file.
10870 11176
10871 window.addEventListener('load', downloads.Manager.onLoad); 11177 window.addEventListener('load', downloads.Manager.onLoad);
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/md_downloads/vulcanized.html » ('j') | third_party/polymer/v1_0/bower.json » ('J')

Powered by Google App Engine
This is Rietveld 408576698