Commit 2c8502d3 authored by dpapad's avatar dpapad Committed by Commit Bot

WebUI: Update Polymer iron-collapse, iron-overlay-behavior to 2.x.

Bug: 738611
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: I7f3649304443c82c7604d4ba4c9e2ef0b966c5f1
Reviewed-on: https://chromium-review.googlesource.com/919643Reviewed-by: default avatarHector Carmona <hcarmona@chromium.org>
Commit-Queue: Demetrios Papadopoulos <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#536919}
parent bed68dfd
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
height: 270px; height: 270px;
} }
iron-dropdown .dropdown-content { iron-dropdown [slot='dropdown-content'] {
background-color: white; background-color: white;
box-shadow: 0 2px 6px var(--paper-grey-500); box-shadow: 0 2px 6px var(--paper-grey-500);
min-width: 128px; min-width: 128px;
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
</paper-input-container> </paper-input-container>
<iron-dropdown horizontal-align="left" vertical-align="top" <iron-dropdown horizontal-align="left" vertical-align="top"
vertical-offset="35"> vertical-offset="35">
<div class="dropdown-content"> <div slot="dropdown-content">
<template is="dom-repeat" items="[[items]]" <template is="dom-repeat" items="[[items]]"
filter="[[filterItems_(searchTerm_)]]"> filter="[[filterItems_(searchTerm_)]]">
<button class="list-item" on-tap="onSelect_">[[item]]</button> <button class="list-item" on-tap="onSelect_">[[item]]</button>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"iron-behaviors": "PolymerElements/iron-behaviors#1.0.17", "iron-behaviors": "PolymerElements/iron-behaviors#1.0.17",
"iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#1.0.5", "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#1.0.5",
"iron-collapse": "PolymerElements/iron-collapse#2.1.0", "iron-collapse": "PolymerElements/iron-collapse#2.1.0",
"iron-dropdown": "PolymerElements/iron-dropdown#1.5.2", "iron-dropdown": "PolymerElements/iron-dropdown#2.1.0",
"iron-fit-behavior": "PolymerElements/iron-fit-behavior#1.2.5", "iron-fit-behavior": "PolymerElements/iron-fit-behavior#1.2.5",
"iron-flex-layout": "PolymerElements/iron-flex-layout#1.3.1", "iron-flex-layout": "PolymerElements/iron-flex-layout#1.3.1",
"iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#1.0.6", "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#1.0.6",
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
"iron-media-query": "PolymerElements/iron-media-query#2.0.0", "iron-media-query": "PolymerElements/iron-media-query#2.0.0",
"iron-menu-behavior": "PolymerElements/iron-menu-behavior#1.3.0", "iron-menu-behavior": "PolymerElements/iron-menu-behavior#1.3.0",
"iron-meta": "PolymerElements/iron-meta#1.1.2", "iron-meta": "PolymerElements/iron-meta#1.1.2",
"iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#1.10.2", "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#2.3.2",
"iron-pages": "PolymerElements/iron-pages#1.0.8", "iron-pages": "PolymerElements/iron-pages#1.0.8",
"iron-range-behavior": "PolymerElements/iron-range-behavior#1.0.6", "iron-range-behavior": "PolymerElements/iron-range-behavior#1.0.6",
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#1.0.5", "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#1.0.5",
......
...@@ -9,14 +9,14 @@ import("//third_party/closure_compiler/compile_js.gni") ...@@ -9,14 +9,14 @@ import("//third_party/closure_compiler/compile_js.gni")
js_library("iron-dropdown-extracted") { js_library("iron-dropdown-extracted") {
deps = [ deps = [
":iron-dropdown-scroll-manager-extracted", ":iron-dropdown-scroll-manager-extracted",
"../iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
"../iron-behaviors:iron-control-state-extracted", "../iron-behaviors:iron-control-state-extracted",
"../iron-overlay-behavior:iron-overlay-behavior-extracted", "../iron-overlay-behavior:iron-overlay-behavior-extracted",
"../iron-resizable-behavior:iron-resizable-behavior-extracted",
"../neon-animation:neon-animation-runner-behavior-extracted", "../neon-animation:neon-animation-runner-behavior-extracted",
"../neon-animation/animations:opaque-animation-extracted",
] ]
} }
js_library("iron-dropdown-scroll-manager-extracted") { js_library("iron-dropdown-scroll-manager-extracted") {
deps = [
"../iron-overlay-behavior:iron-scroll-manager-extracted",
]
} }
{ {
"name": "iron-dropdown", "name": "iron-dropdown",
"version": "1.5.2", "version": "2.1.0",
"description": "An unstyled element that works similarly to a native browser select", "description": "An unstyled element that works similarly to a native browser select",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
...@@ -19,20 +19,44 @@ ...@@ -19,20 +19,44 @@
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"homepage": "https://github.com/PolymerElements/iron-dropdown", "homepage": "https://github.com/PolymerElements/iron-dropdown",
"dependencies": { "dependencies": {
"polymer": "polymer/polymer#^1.1.0", "polymer": "Polymer/polymer#1.9 - 2",
"iron-behaviors": "polymerelements/iron-behaviors#^1.0.0", "iron-behaviors": "PolymerElements/iron-behaviors#1 - 2",
"iron-overlay-behavior": "polymerelements/iron-overlay-behavior#^1.8.6", "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^2.2.0",
"iron-resizable-behavior": "polymerelements/iron-resizable-behavior#^1.0.0", "neon-animation": "PolymerElements/neon-animation#1 - 2"
"neon-animation": "polymerelements/neon-animation#^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"iron-component-page": "polymerelements/iron-component-page#^1.0.0", "iron-component-page": "PolymerElements/iron-component-page#1 - 2",
"test-fixture": "polymerelements/test-fixture#^1.0.0", "iron-demo-helpers": "PolymerElements/iron-demo-helpers#1 - 2",
"iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0", "iron-test-helpers": "PolymerElements/iron-test-helpers#1 - 2",
"paper-styles": "polymerelements/paper-styles#^1.0.0", "web-animations-js": "web-animations/web-animations-js#^2.2.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0", "iron-image": "PolymerElements/iron-image#1 - 2",
"web-component-tester": "^4.0.0", "web-component-tester": "^6.0.0",
"iron-image": "polymerelements/iron-image#^1.0.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
}, },
"ignore": [] "variants": {
"1.x": {
"dependencies": {
"polymer": "Polymer/polymer#^1.9",
"iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
"iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^2.2.0",
"neon-animation": "PolymerElements/neon-animation#^1.0.0"
},
"devDependencies": {
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
"iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
"iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
"web-animations-js": "web-animations/web-animations-js#^2.2.0",
"iron-image": "PolymerElements/iron-image#^1.0.0",
"web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
},
"resolutions": {
"webcomponentsjs": "^0.7"
}
}
},
"ignore": [],
"resolutions": {
"webcomponentsjs": "^1.0.0"
}
} }
...@@ -8,11 +8,8 @@ ...@@ -8,11 +8,8 @@
{ {
'target_name': 'iron-dropdown-extracted', 'target_name': 'iron-dropdown-extracted',
'dependencies': [ 'dependencies': [
'../iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
'../iron-behaviors/compiled_resources2.gyp:iron-control-state-extracted', '../iron-behaviors/compiled_resources2.gyp:iron-control-state-extracted',
'../iron-overlay-behavior/compiled_resources2.gyp:iron-overlay-behavior-extracted', '../iron-overlay-behavior/compiled_resources2.gyp:iron-overlay-behavior-extracted',
'../iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted',
'../neon-animation/animations/compiled_resources2.gyp:opaque-animation-extracted',
'../neon-animation/compiled_resources2.gyp:neon-animation-runner-behavior-extracted', '../neon-animation/compiled_resources2.gyp:neon-animation-runner-behavior-extracted',
'iron-dropdown-scroll-manager-extracted', 'iron-dropdown-scroll-manager-extracted',
], ],
...@@ -20,6 +17,9 @@ ...@@ -20,6 +17,9 @@
}, },
{ {
'target_name': 'iron-dropdown-scroll-manager-extracted', 'target_name': 'iron-dropdown-scroll-manager-extracted',
'dependencies': [
'../iron-overlay-behavior/compiled_resources2.gyp:iron-scroll-manager-extracted',
],
'includes': ['../../../../closure_compiler/compile_js2.gypi'], 'includes': ['../../../../closure_compiler/compile_js2.gypi'],
}, },
], ],
......
...@@ -36,7 +36,9 @@ ...@@ -36,7 +36,9 @@
/** /**
* An animation config. If provided, this will be used to animate the * An animation config. If provided, this will be used to animate the
* opening of the dropdown. * opening of the dropdown. Pass an Array for multiple animations.
* See `neon-animation` documentation for more animation configuration
* details.
*/ */
openAnimationConfig: { openAnimationConfig: {
type: Object type: Object
...@@ -44,7 +46,9 @@ ...@@ -44,7 +46,9 @@
/** /**
* An animation config. If provided, this will be used to animate the * An animation config. If provided, this will be used to animate the
* closing of the dropdown. * closing of the dropdown. Pass an Array for multiple animations.
* See `neon-animation` documentation for more animation configuration
* details.
*/ */
closeAnimationConfig: { closeAnimationConfig: {
type: Object type: Object
...@@ -72,22 +76,13 @@ ...@@ -72,22 +76,13 @@
* to itself when opened. * to itself when opened.
* Set to true in order to prevent scroll from being constrained * Set to true in order to prevent scroll from being constrained
* to the dropdown when it opens. * to the dropdown when it opens.
* This property is a shortcut to set `scrollAction` to lock or refit.
* Prefer directly setting the `scrollAction` property.
*/ */
allowOutsideScroll: { allowOutsideScroll: {
type: Boolean, type: Boolean,
value: false value: false,
}, observer: '_allowOutsideScrollChanged'
/**
* Callback for scroll events.
* @type {Function}
* @private
*/
_boundOnCaptureScroll: {
type: Function,
value: function() {
return this._onCaptureScroll.bind(this);
}
} }
}, },
...@@ -103,35 +98,31 @@ ...@@ -103,35 +98,31 @@
* The element that is contained by the dropdown, if any. * The element that is contained by the dropdown, if any.
*/ */
get containedElement() { get containedElement() {
return Polymer.dom(this.$.content).getDistributedNodes()[0]; // Polymer 2.x returns slot.assignedNodes which can contain text nodes.
}, var nodes = Polymer.dom(this.$.content).getDistributedNodes();
for (var i = 0, l = nodes.length; i < l; i++) {
/** if (nodes[i].nodeType === Node.ELEMENT_NODE) {
* The element that should be focused when the dropdown opens. return nodes[i];
* @deprecated }
*/ }
get _focusTarget() {
return this.focusTarget || this.containedElement;
}, },
ready: function() { ready: function() {
// Memoized scrolling position, used to block scrolling outside. // Ensure scrollAction is set.
this._scrollTop = 0; if (!this.scrollAction) {
this._scrollLeft = 0; this.scrollAction = this.allowOutsideScroll ? 'refit' : 'lock';
// Used to perform a non-blocking refit on scroll. }
this._refitOnScrollRAF = null; this._readied = true;
}, },
attached: function () { attached: function () {
if (!this.sizingTarget || this.sizingTarget === this) { if (!this.sizingTarget || this.sizingTarget === this) {
this.sizingTarget = this.containedElement; this.sizingTarget = this.containedElement || this;
} }
}, },
detached: function() { detached: function() {
this.cancelAnimation(); this.cancelAnimation();
document.removeEventListener('scroll', this._boundOnCaptureScroll);
Polymer.IronDropdownScrollManager.removeScrollLock(this);
}, },
/** /**
...@@ -144,14 +135,6 @@ ...@@ -144,14 +135,6 @@
} else { } else {
this.cancelAnimation(); this.cancelAnimation();
this._updateAnimationConfig(); this._updateAnimationConfig();
this._saveScrollPosition();
if (this.opened) {
document.addEventListener('scroll', this._boundOnCaptureScroll);
!this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScrollLock(this);
} else {
document.removeEventListener('scroll', this._boundOnCaptureScroll);
Polymer.IronDropdownScrollManager.removeScrollLock(this);
}
Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments); Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
} }
}, },
...@@ -172,7 +155,6 @@ ...@@ -172,7 +155,6 @@
* Overridden from `IronOverlayBehavior`. * Overridden from `IronOverlayBehavior`.
*/ */
_renderClosed: function() { _renderClosed: function() {
if (!this.noAnimations && this.animationConfig.close) { if (!this.noAnimations && this.animationConfig.close) {
this.$.contentWrapper.classList.add('animating'); this.$.contentWrapper.classList.add('animating');
this.playAnimation('close'); this.playAnimation('close');
...@@ -195,56 +177,17 @@ ...@@ -195,56 +177,17 @@
this._finishRenderClosed(); this._finishRenderClosed();
} }
}, },
_onCaptureScroll: function() {
if (!this.allowOutsideScroll) {
this._restoreScrollPosition();
} else {
this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrollRAF);
this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(this));
}
},
/**
* Memoizes the scroll position of the outside scrolling element.
* @private
*/
_saveScrollPosition: function() {
if (document.scrollingElement) {
this._scrollTop = document.scrollingElement.scrollTop;
this._scrollLeft = document.scrollingElement.scrollLeft;
} else {
// Since we don't know if is the body or html, get max.
this._scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
this._scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
}
},
/**
* Resets the scroll position of the outside scrolling element.
* @private
*/
_restoreScrollPosition: function() {
if (document.scrollingElement) {
document.scrollingElement.scrollTop = this._scrollTop;
document.scrollingElement.scrollLeft = this._scrollLeft;
} else {
// Since we don't know if is the body or html, set both.
document.documentElement.scrollTop = this._scrollTop;
document.documentElement.scrollLeft = this._scrollLeft;
document.body.scrollTop = this._scrollTop;
document.body.scrollLeft = this._scrollLeft;
}
},
/** /**
* Constructs the final animation config from different properties used * Constructs the final animation config from different properties used
* to configure specific parts of the opening and closing animations. * to configure specific parts of the opening and closing animations.
*/ */
_updateAnimationConfig: function() { _updateAnimationConfig: function() {
var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []); // Update the animation node to be the containedElement.
var animationNode = this.containedElement;
var animations = [].concat(this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
for (var i = 0; i < animations.length; i++) { for (var i = 0; i < animations.length; i++) {
animations[i].node = this.containedElement; animations[i].node = animationNode;
} }
this.animationConfig = { this.animationConfig = {
open: this.openAnimationConfig, open: this.openAnimationConfig,
...@@ -263,10 +206,26 @@ ...@@ -263,10 +206,26 @@
} }
}, },
/**
* Sets scrollAction according to the value of allowOutsideScroll.
* Prefer setting directly scrollAction.
*/
_allowOutsideScrollChanged: function(allowOutsideScroll) {
// Wait until initial values are all set.
if (!this._readied) {
return;
}
if (!allowOutsideScroll) {
this.scrollAction = 'lock';
} else if (!this.scrollAction || this.scrollAction === 'lock') {
this.scrollAction = 'refit';
}
},
/** /**
* Apply focus to focusTarget or containedElement * Apply focus to focusTarget or containedElement
*/ */
_applyFocus: function () { _applyFocus: function() {
var focusTarget = this.focusTarget || this.containedElement; var focusTarget = this.focusTarget || this.containedElement;
if (focusTarget && this.opened && !this.noAutoFocus) { if (focusTarget && this.opened && !this.noAutoFocus) {
focusTarget.focus(); focusTarget.focus();
......
(function() { (function() {
'use strict'; 'use strict';
// Used to calculate the scroll direction during touch events.
var LAST_TOUCH_POSITION = {
pageX: 0,
pageY: 0
};
// Used to avoid computing event.path and filter scrollable nodes (better perf).
var ROOT_TARGET = null;
var SCROLLABLE_NODES = [];
/** /**
* The IronDropdownScrollManager is intended to provide a central source * IronDropdownScrollManager is deprecated, use IronScrollManager instead.
* of authority and control over which elements in a document are currently
* allowed to scroll.
*/ */
Polymer.IronDropdownScrollManager = Polymer.IronScrollManager;
Polymer.IronDropdownScrollManager = {
/**
* The current element that defines the DOM boundaries of the
* scroll lock. This is always the most recently locking element.
*/
get currentLockingElement() {
return this._lockingElements[this._lockingElements.length - 1];
},
/**
* Returns true if the provided element is "scroll locked", which is to
* say that it cannot be scrolled via pointer or keyboard interactions.
*
* @param {HTMLElement} element An HTML element instance which may or may
* not be scroll locked.
*/
elementIsScrollLocked: function(element) {
var currentLockingElement = this.currentLockingElement;
if (currentLockingElement === undefined)
return false;
var scrollLocked;
if (this._hasCachedLockedElement(element)) {
return true;
}
if (this._hasCachedUnlockedElement(element)) {
return false;
}
scrollLocked = !!currentLockingElement &&
currentLockingElement !== element &&
!this._composedTreeContains(currentLockingElement, element);
if (scrollLocked) {
this._lockedElementCache.push(element);
} else {
this._unlockedElementCache.push(element);
}
return scrollLocked;
},
/**
* Push an element onto the current scroll lock stack. The most recently
* pushed element and its children will be considered scrollable. All
* other elements will not be scrollable.
*
* Scroll locking is implemented as a stack so that cases such as
* dropdowns within dropdowns are handled well.
*
* @param {HTMLElement} element The element that should lock scroll.
*/
pushScrollLock: function(element) {
// Prevent pushing the same element twice
if (this._lockingElements.indexOf(element) >= 0) {
return;
}
if (this._lockingElements.length === 0) {
this._lockScrollInteractions();
}
this._lockingElements.push(element);
this._lockedElementCache = [];
this._unlockedElementCache = [];
},
/**
* Remove an element from the scroll lock stack. The element being
* removed does not need to be the most recently pushed element. However,
* the scroll lock constraints only change when the most recently pushed
* element is removed.
*
* @param {HTMLElement} element The element to remove from the scroll
* lock stack.
*/
removeScrollLock: function(element) {
var index = this._lockingElements.indexOf(element);
if (index === -1) {
return;
}
this._lockingElements.splice(index, 1);
this._lockedElementCache = [];
this._unlockedElementCache = [];
if (this._lockingElements.length === 0) {
this._unlockScrollInteractions();
}
},
_lockingElements: [],
_lockedElementCache: null,
_unlockedElementCache: null,
_hasCachedLockedElement: function(element) {
return this._lockedElementCache.indexOf(element) > -1;
},
_hasCachedUnlockedElement: function(element) {
return this._unlockedElementCache.indexOf(element) > -1;
},
_composedTreeContains: function(element, child) {
// NOTE(cdata): This method iterates over content elements and their
// corresponding distributed nodes to implement a contains-like method
// that pierces through the composed tree of the ShadowDOM. Results of
// this operation are cached (elsewhere) on a per-scroll-lock basis, to
// guard against potentially expensive lookups happening repeatedly as
// a user scrolls / touchmoves.
var contentElements;
var distributedNodes;
var contentIndex;
var nodeIndex;
if (element.contains(child)) {
return true;
}
contentElements = Polymer.dom(element).querySelectorAll('content');
for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
return true;
}
}
}
return false;
},
_scrollInteractionHandler: function(event) {
// Avoid canceling an event with cancelable=false, e.g. scrolling is in
// progress and cannot be interrupted.
if (event.cancelable && this._shouldPreventScrolling(event)) {
event.preventDefault();
}
// If event has targetTouches (touch event), update last touch position.
if (event.targetTouches) {
var touch = event.targetTouches[0];
LAST_TOUCH_POSITION.pageX = touch.pageX;
LAST_TOUCH_POSITION.pageY = touch.pageY;
}
},
_lockScrollInteractions: function() {
this._boundScrollHandler = this._boundScrollHandler ||
this._scrollInteractionHandler.bind(this);
// Modern `wheel` event for mouse wheel scrolling:
document.addEventListener('wheel', this._boundScrollHandler, true);
// Older, non-standard `mousewheel` event for some FF:
document.addEventListener('mousewheel', this._boundScrollHandler, true);
// IE:
document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true);
// Save the SCROLLABLE_NODES on touchstart, to be used on touchmove.
document.addEventListener('touchstart', this._boundScrollHandler, true);
// Mobile devices can scroll on touch move:
document.addEventListener('touchmove', this._boundScrollHandler, true);
},
_unlockScrollInteractions: function() {
document.removeEventListener('wheel', this._boundScrollHandler, true);
document.removeEventListener('mousewheel', this._boundScrollHandler, true);
document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, true);
document.removeEventListener('touchstart', this._boundScrollHandler, true);
document.removeEventListener('touchmove', this._boundScrollHandler, true);
},
/**
* Returns true if the event causes scroll outside the current locking
* element, e.g. pointer/keyboard interactions, or scroll "leaking"
* outside the locking element when it is already at its scroll boundaries.
* @param {!Event} event
* @return {boolean}
* @private
*/
_shouldPreventScrolling: function(event) {
// Update if root target changed. For touch events, ensure we don't
// update during touchmove.
var target = Polymer.dom(event).rootTarget;
if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
ROOT_TARGET = target;
SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
}
// Prevent event if no scrollable nodes.
if (!SCROLLABLE_NODES.length) {
return true;
}
// Don't prevent touchstart event inside the locking element when it has
// scrollable nodes.
if (event.type === 'touchstart') {
return false;
}
// Get deltaX/Y.
var info = this._getScrollInfo(event);
// Prevent if there is no child that can scroll.
return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY);
},
/**
* Returns an array of scrollable nodes up to the current locking element,
* which is included too if scrollable.
* @param {!Array<Node>} nodes
* @return {Array<Node>} scrollables
* @private
*/
_getScrollableNodes: function(nodes) {
var scrollables = [];
var lockingIndex = nodes.indexOf(this.currentLockingElement);
// Loop from root target to locking element (included).
for (var i = 0; i <= lockingIndex; i++) {
var node = nodes[i];
// Skip document fragments.
if (node.nodeType === 11) {
continue;
}
// Check inline style before checking computed style.
var style = node.style;
if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
style = window.getComputedStyle(node);
}
if (style.overflow === 'scroll' || style.overflow === 'auto') {
scrollables.push(node);
}
}
return scrollables;
},
/**
* Returns the node that is scrolling. If there is no scrolling,
* returns undefined.
* @param {!Array<Node>} nodes
* @param {number} deltaX Scroll delta on the x-axis
* @param {number} deltaY Scroll delta on the y-axis
* @return {Node|undefined}
* @private
*/
_getScrollingNode: function(nodes, deltaX, deltaY) {
// No scroll.
if (!deltaX && !deltaY) {
return;
}
// Check only one axis according to where there is more scroll.
// Prefer vertical to horizontal.
var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
var canScroll = false;
if (verticalScroll) {
// delta < 0 is scroll up, delta > 0 is scroll down.
canScroll = deltaY < 0 ? node.scrollTop > 0 :
node.scrollTop < node.scrollHeight - node.clientHeight;
} else {
// delta < 0 is scroll left, delta > 0 is scroll right.
canScroll = deltaX < 0 ? node.scrollLeft > 0 :
node.scrollLeft < node.scrollWidth - node.clientWidth;
}
if (canScroll) {
return node;
}
}
},
/**
* Returns scroll `deltaX` and `deltaY`.
* @param {!Event} event The scroll event
* @return {{
* deltaX: number The x-axis scroll delta (positive: scroll right,
* negative: scroll left, 0: no scroll),
* deltaY: number The y-axis scroll delta (positive: scroll down,
* negative: scroll up, 0: no scroll)
* }} info
* @private
*/
_getScrollInfo: function(event) {
var info = {
deltaX: event.deltaX,
deltaY: event.deltaY
};
// Already available.
if ('deltaX' in event) {
// do nothing, values are already good.
}
// Safari has scroll info in `wheelDeltaX/Y`.
else if ('wheelDeltaX' in event) {
info.deltaX = -event.wheelDeltaX;
info.deltaY = -event.wheelDeltaY;
}
// Firefox has scroll info in `detail` and `axis`.
else if ('axis' in event) {
info.deltaX = event.axis === 1 ? event.detail : 0;
info.deltaY = event.axis === 2 ? event.detail : 0;
}
// On mobile devices, calculate scroll direction.
else if (event.targetTouches) {
var touch = event.targetTouches[0];
// Touch moves from right to left => scrolling goes right.
info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
// Touch moves from down to up => scrolling goes down.
info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
}
return info;
}
};
})(); })();
\ No newline at end of file
...@@ -6,6 +6,6 @@ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt ...@@ -6,6 +6,6 @@ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--><html><head><link rel="import" href="../polymer/polymer.html"> --><html><head><link rel="import" href="../iron-overlay-behavior/iron-scroll-manager.html">
</head><body><script src="iron-dropdown-scroll-manager-extracted.js"></script></body></html> </head><body><script src="iron-dropdown-scroll-manager-extracted.js"></script></body></html>
\ No newline at end of file
...@@ -7,17 +7,15 @@ The complete set of contributors may be found at http://polymer.github.io/CONTRI ...@@ -7,17 +7,15 @@ The complete set of contributors may be found at http://polymer.github.io/CONTRI
Code distributed by Google as part of the polymer project is also Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--><html><head><link rel="import" href="../polymer/polymer.html"> --><html><head><link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
<link rel="import" href="../iron-behaviors/iron-control-state.html"> <link rel="import" href="../iron-behaviors/iron-control-state.html">
<link rel="import" href="../iron-overlay-behavior/iron-overlay-behavior.html"> <link rel="import" href="../iron-overlay-behavior/iron-overlay-behavior.html">
<link rel="import" href="../neon-animation/neon-animation-runner-behavior.html"> <link rel="import" href="../neon-animation/neon-animation-runner-behavior.html">
<link rel="import" href="../neon-animation/animations/opaque-animation.html"> <!--TODO remove this import -->
<link rel="import" href="iron-dropdown-scroll-manager.html"> <link rel="import" href="iron-dropdown-scroll-manager.html">
<!-- <!--
`<iron-dropdown>` is a generalized element that is useful when you have `<iron-dropdown>` is a generalized element that is useful when you have
hidden content (`.dropdown-content`) that is revealed due to some change in hidden content (`dropdown-content`) that is revealed due to some change in
state that should cause it to do so. state that should cause it to do so.
Note that this is a low-level element intended to be used as part of other Note that this is a low-level element intended to be used as part of other
...@@ -27,14 +25,14 @@ Examples of elements that might be implemented using an `iron-dropdown` ...@@ -27,14 +25,14 @@ Examples of elements that might be implemented using an `iron-dropdown`
include comboboxes, menubuttons, selects. The list goes on. include comboboxes, menubuttons, selects. The list goes on.
The `<iron-dropdown>` element exposes attributes that allow the position The `<iron-dropdown>` element exposes attributes that allow the position
of the `.dropdown-content` relative to the `.dropdown-trigger` to be of the `dropdown-content` relative to the `dropdown-trigger` to be
configured. configured.
<iron-dropdown horizontal-align="right" vertical-align="top"> <iron-dropdown horizontal-align="right" vertical-align="top">
<div class="dropdown-content">Hello!</div> <div slot="dropdown-content">Hello!</div>
</iron-dropdown> </iron-dropdown>
In the above example, the `<div>` with class `.dropdown-content` will be In the above example, the `<div>` assigned to the `dropdown-content` slot will be
hidden until the dropdown element has `opened` set to true, or when the `open` hidden until the dropdown element has `opened` set to true, or when the `open`
method is called on the element. method is called on the element.
...@@ -48,17 +46,17 @@ method is called on the element. ...@@ -48,17 +46,17 @@ method is called on the element.
position: fixed; position: fixed;
} }
#contentWrapper ::content > * { #contentWrapper ::slotted(*) {
overflow: auto; overflow: auto;
} }
#contentWrapper.animating ::content > * { #contentWrapper.animating ::slotted(*) {
overflow: hidden; overflow: hidden;
} }
</style> </style>
<div id="contentWrapper"> <div id="contentWrapper">
<content id="content" select=".dropdown-content"></content> <slot id="content" name="dropdown-content"></slot>
</div> </div>
</template> </template>
......
...@@ -16,6 +16,7 @@ js_library("iron-overlay-behavior-extracted") { ...@@ -16,6 +16,7 @@ js_library("iron-overlay-behavior-extracted") {
deps = [ deps = [
":iron-focusables-helper-extracted", ":iron-focusables-helper-extracted",
":iron-overlay-manager-extracted", ":iron-overlay-manager-extracted",
":iron-scroll-manager-extracted",
"../iron-fit-behavior:iron-fit-behavior-extracted", "../iron-fit-behavior:iron-fit-behavior-extracted",
"../iron-resizable-behavior:iron-resizable-behavior-extracted", "../iron-resizable-behavior:iron-resizable-behavior-extracted",
] ]
...@@ -27,3 +28,6 @@ js_library("iron-overlay-manager-extracted") { ...@@ -27,3 +28,6 @@ js_library("iron-overlay-manager-extracted") {
"../iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted", "../iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
] ]
} }
js_library("iron-scroll-manager-extracted") {
}
{ {
"name": "iron-overlay-behavior", "name": "iron-overlay-behavior",
"version": "1.10.2", "version": "2.3.2",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "Provides a behavior for making an element an overlay", "description": "Provides a behavior for making an element an overlay",
"private": true, "private": true,
...@@ -19,19 +19,42 @@ ...@@ -19,19 +19,42 @@
"url": "git://github.com/PolymerElements/iron-overlay-behavior.git" "url": "git://github.com/PolymerElements/iron-overlay-behavior.git"
}, },
"dependencies": { "dependencies": {
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0", "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#1 - 2",
"iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0", "iron-fit-behavior": "PolymerElements/iron-fit-behavior#1 - 2",
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0", "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#1 - 2",
"polymer": "Polymer/polymer#^1.1.0" "polymer": "Polymer/polymer#1.9 - 2"
}, },
"devDependencies": { "devDependencies": {
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0", "iron-component-page": "PolymerElements/iron-component-page#1 - 2",
"iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0", "iron-demo-helpers": "PolymerElements/iron-demo-helpers#1 - 2",
"iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0", "iron-flex-layout": "PolymerElements/iron-flex-layout#1 - 2",
"iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0", "iron-test-helpers": "PolymerElements/iron-test-helpers#1 - 2",
"paper-styles": "PolymerElements/paper-styles#^1.0.2", "web-component-tester": "^6.0.0",
"web-component-tester": "^4.0.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"ignore": [] "variants": {
"1.x": {
"dependencies": {
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
"iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0",
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
"polymer": "Polymer/polymer#^1.9"
},
"devDependencies": {
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
"iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
"iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
"iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
"web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
},
"resolutions": {
"webcomponentsjs": "^0.7"
}
}
},
"ignore": [],
"resolutions": {
"webcomponentsjs": "^1.0.0"
}
} }
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
'../iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted', '../iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted',
'iron-focusables-helper-extracted', 'iron-focusables-helper-extracted',
'iron-overlay-manager-extracted', 'iron-overlay-manager-extracted',
'iron-scroll-manager-extracted',
], ],
'includes': ['../../../../closure_compiler/compile_js2.gypi'], 'includes': ['../../../../closure_compiler/compile_js2.gypi'],
}, },
...@@ -31,5 +32,9 @@ ...@@ -31,5 +32,9 @@
], ],
'includes': ['../../../../closure_compiler/compile_js2.gypi'], 'includes': ['../../../../closure_compiler/compile_js2.gypi'],
}, },
{
'target_name': 'iron-scroll-manager-extracted',
'includes': ['../../../../closure_compiler/compile_js2.gypi'],
},
], ],
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* It searches the tabbable nodes in the light and shadow dom of the chidren, * It searches the tabbable nodes in the light and shadow dom of the chidren,
* sorting the result by tabindex. * sorting the result by tabindex.
* @param {!Node} node * @param {!Node} node
* @return {Array<HTMLElement>} * @return {!Array<!HTMLElement>}
*/ */
getTabbableNodes: function(node) { getTabbableNodes: function(node) {
var result = []; var result = [];
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
* Returns if the `result` array needs to be sorted by tabindex. * Returns if the `result` array needs to be sorted by tabindex.
* @param {!Node} node The starting point for the search; added to `result` * @param {!Node} node The starting point for the search; added to `result`
* if tabbable. * if tabbable.
* @param {!Array<HTMLElement>} result * @param {!Array<!HTMLElement>} result
* @return {boolean} * @return {boolean}
* @private * @private
*/ */
...@@ -93,9 +93,9 @@ ...@@ -93,9 +93,9 @@
if (node.nodeType !== Node.ELEMENT_NODE || !this._isVisible(node)) { if (node.nodeType !== Node.ELEMENT_NODE || !this._isVisible(node)) {
return false; return false;
} }
var element = /** @type {HTMLElement} */ (node); var element = /** @type {!HTMLElement} */ (node);
var tabIndex = this._normalizedTabIndex(element); var tabIndex = this._normalizedTabIndex(element);
var needsSortByTabIndex = tabIndex > 0; var needsSort = tabIndex > 0;
if (tabIndex >= 0) { if (tabIndex >= 0) {
result.push(element); result.push(element);
} }
...@@ -114,7 +114,7 @@ ...@@ -114,7 +114,7 @@
// </div> // </div>
// TODO(valdrin) support ShadowDOM v1 when upgrading to Polymer v2.0. // TODO(valdrin) support ShadowDOM v1 when upgrading to Polymer v2.0.
var children; var children;
if (element.localName === 'content') { if (element.localName === 'content' || element.localName === 'slot') {
children = Polymer.dom(element).getDistributedNodes(); children = Polymer.dom(element).getDistributedNodes();
} else { } else {
// Use shadow root if possible, will check for distributed nodes. // Use shadow root if possible, will check for distributed nodes.
...@@ -122,10 +122,9 @@ ...@@ -122,10 +122,9 @@
} }
for (var i = 0; i < children.length; i++) { for (var i = 0; i < children.length; i++) {
// Ensure method is always invoked to collect tabbable children. // Ensure method is always invoked to collect tabbable children.
var needsSort = this._collectTabbableNodes(children[i], result); needsSort = this._collectTabbableNodes(children[i], result) || needsSort;
needsSortByTabIndex = needsSortByTabIndex || needsSort;
} }
return needsSortByTabIndex; return needsSort;
}, },
/** /**
...@@ -147,8 +146,8 @@ ...@@ -147,8 +146,8 @@
/** /**
* Sorts an array of tabbable elements by tabindex. Returns a new array. * Sorts an array of tabbable elements by tabindex. Returns a new array.
* @param {!Array<HTMLElement>} tabbables * @param {!Array<!HTMLElement>} tabbables
* @return {Array<HTMLElement>} * @return {!Array<!HTMLElement>}
* @private * @private
*/ */
_sortByTabIndex: function(tabbables) { _sortByTabIndex: function(tabbables) {
...@@ -166,9 +165,9 @@ ...@@ -166,9 +165,9 @@
/** /**
* Merge sort iterator, merges the two arrays into one, sorted by tab index. * Merge sort iterator, merges the two arrays into one, sorted by tab index.
* @param {!Array<HTMLElement>} left * @param {!Array<!HTMLElement>} left
* @param {!Array<HTMLElement>} right * @param {!Array<!HTMLElement>} right
* @return {Array<HTMLElement>} * @return {!Array<!HTMLElement>}
* @private * @private
*/ */
_mergeSortByTabIndex: function(left, right) { _mergeSortByTabIndex: function(left, right) {
......
...@@ -38,17 +38,17 @@ Custom property | Description | Default ...@@ -38,17 +38,17 @@ Custom property | Description | Default
opacity: 0; opacity: 0;
transition: opacity 0.2s; transition: opacity 0.2s;
pointer-events: none; pointer-events: none;
@apply(--iron-overlay-backdrop); @apply --iron-overlay-backdrop;
} }
:host(.opened) { :host(.opened) {
opacity: var(--iron-overlay-backdrop-opacity, 0.6); opacity: var(--iron-overlay-backdrop-opacity, 0.6);
pointer-events: auto; pointer-events: auto;
@apply(--iron-overlay-backdrop-opened); @apply --iron-overlay-backdrop-opened;
} }
</style> </style>
<content></content> <slot></slot>
</template> </template>
</dom-module> </dom-module>
......
...@@ -79,6 +79,15 @@ ...@@ -79,6 +79,15 @@
value: false value: false
}, },
/**
* Set to true to allow clicks to go through overlays.
* When the user clicks outside this overlay, the click may
* close the overlay below.
*/
allowClickThrough: {
type: Boolean
},
/** /**
* Set to true to keep overlay always on top. * Set to true to keep overlay always on top.
*/ */
...@@ -86,10 +95,21 @@ ...@@ -86,10 +95,21 @@
type: Boolean type: Boolean
}, },
/**
* Determines which action to perform when scroll outside an opened overlay happens.
* Possible values:
* lock - blocks scrolling from happening,
* refit - computes the new position on the overlay
* cancel - causes the overlay to close
*/
scrollAction: {
type: String
},
/** /**
* Shortcut to access to the overlay manager. * Shortcut to access to the overlay manager.
* @private * @private
* @type {Polymer.IronOverlayManagerClass} * @type {!Polymer.IronOverlayManagerClass}
*/ */
_manager: { _manager: {
type: Object, type: Object,
...@@ -110,9 +130,13 @@ ...@@ -110,9 +130,13 @@
'iron-resize': '_onIronResize' 'iron-resize': '_onIronResize'
}, },
observers: [
'__updateScrollObservers(isAttached, opened, scrollAction)'
],
/** /**
* The backdrop element. * The backdrop element.
* @type {Element} * @return {!Element}
*/ */
get backdropElement() { get backdropElement() {
return this._manager.backdropElement; return this._manager.backdropElement;
...@@ -120,7 +144,7 @@ ...@@ -120,7 +144,7 @@
/** /**
* Returns the node to give focus to. * Returns the node to give focus to.
* @type {Node} * @return {!Node}
*/ */
get _focusNode() { get _focusNode() {
return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this; return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
...@@ -133,7 +157,7 @@ ...@@ -133,7 +157,7 @@
* *
* If you know what is your content (specifically the first and last focusable children), * If you know what is your content (specifically the first and last focusable children),
* you can override this method to return only `[firstFocusable, lastFocusable];` * you can override this method to return only `[firstFocusable, lastFocusable];`
* @type {Array<Node>} * @return {!Array<!Node>}
* @protected * @protected
*/ */
get _focusableNodes() { get _focusableNodes() {
...@@ -148,10 +172,15 @@ ...@@ -148,10 +172,15 @@
this.__shouldRemoveTabIndex = false; this.__shouldRemoveTabIndex = false;
// Used for wrapping the focus on TAB / Shift+TAB. // Used for wrapping the focus on TAB / Shift+TAB.
this.__firstFocusableNode = this.__lastFocusableNode = null; this.__firstFocusableNode = this.__lastFocusableNode = null;
// Used by __onNextAnimationFrame to cancel any previous callback. // Used by to keep track of the RAF callbacks.
this.__raf = null; this.__rafs = {};
// Focused node before overlay gets opened. Can be restored on close. // Focused node before overlay gets opened. Can be restored on close.
this.__restoreFocusNode = null; this.__restoreFocusNode = null;
// Scroll info to be restored.
this.__scrollTop = this.__scrollLeft = null;
this.__onCaptureScroll = this.__onCaptureScroll.bind(this);
// Root nodes hosting the overlay, used to listen for scroll events on them.
this.__rootNodes = null;
this._ensureSetup(); this._ensureSetup();
}, },
...@@ -166,11 +195,25 @@ ...@@ -166,11 +195,25 @@
detached: function() { detached: function() {
Polymer.dom(this).unobserveNodes(this._observer); Polymer.dom(this).unobserveNodes(this._observer);
this._observer = null; this._observer = null;
if (this.__raf) { for (var cb in this.__rafs) {
window.cancelAnimationFrame(this.__raf); if (this.__rafs[cb] !== null) {
this.__raf = null; cancelAnimationFrame(this.__rafs[cb]);
}
} }
this.__rafs = {};
this._manager.removeOverlay(this); this._manager.removeOverlay(this);
// We got detached while animating, ensure we show/hide the overlay
// and fire iron-overlay-opened/closed event!
if (this.__isAnimating) {
if (this.opened) {
this._finishRenderOpened();
} else {
// Restore the focus if necessary.
this._applyFocus();
this._finishRenderClosed();
}
}
}, },
/** /**
...@@ -248,8 +291,8 @@ ...@@ -248,8 +291,8 @@
this.__isAnimating = true; this.__isAnimating = true;
// Use requestAnimationFrame for non-blocking rendering. // Deraf for non-blocking rendering.
this.__onNextAnimationFrame(this.__openedChanged); this.__deraf('__openedChanged', this.__openedChanged);
}, },
_canceledChanged: function() { _canceledChanged: function() {
...@@ -370,7 +413,16 @@ ...@@ -370,7 +413,16 @@
this._focusedChild = null; this._focusedChild = null;
// Restore focus. // Restore focus.
if (this.restoreFocusOnClose && this.__restoreFocusNode) { if (this.restoreFocusOnClose && this.__restoreFocusNode) {
this.__restoreFocusNode.focus(); // If the activeElement is `<body>` or inside the overlay,
// we are allowed to restore the focus. In all the other
// cases focus might have been moved elsewhere by another
// component or by an user interaction (e.g. click on a
// button outside the overlay).
var activeElement = this._manager.deepActiveElement;
if (activeElement === document.body ||
Polymer.dom(this).deepContains(activeElement)) {
this.__restoreFocusNode.focus();
}
} }
this.__restoreFocusNode = null; this.__restoreFocusNode = null;
// If many overlays get closed at the same time, one of them would still // If many overlays get closed at the same time, one of them would still
...@@ -479,7 +531,7 @@ ...@@ -479,7 +531,7 @@
*/ */
_onIronResize: function() { _onIronResize: function() {
if (this.opened && !this.__isAnimating) { if (this.opened && !this.__isAnimating) {
this.__onNextAnimationFrame(this.refit); this.__deraf('refit', this.refit);
} }
}, },
...@@ -532,23 +584,152 @@ ...@@ -532,23 +584,152 @@
}, },
/** /**
* Executes a callback on the next animation frame, overriding any previous * Debounces the execution of a callback to the next animation frame.
* callback awaiting for the next animation frame. e.g. * @param {!string} jobname
* `__onNextAnimationFrame(callback1) && __onNextAnimationFrame(callback2)`; * @param {!Function} callback Always bound to `this`
* `callback1` will never be invoked. * @private
* @param {!Function} callback Its `this` parameter is the overlay itself. */
__deraf: function(jobname, callback) {
var rafs = this.__rafs;
if (rafs[jobname] !== null) {
cancelAnimationFrame(rafs[jobname]);
}
rafs[jobname] = requestAnimationFrame(function nextAnimationFrame() {
rafs[jobname] = null;
callback.call(this);
}.bind(this));
},
/**
* @param {boolean} isAttached
* @param {boolean} opened
* @param {string=} scrollAction
* @private
*/
__updateScrollObservers: function(isAttached, opened, scrollAction) {
if (!isAttached || !opened || !this.__isValidScrollAction(scrollAction)) {
Polymer.IronScrollManager.removeScrollLock(this);
this.__removeScrollListeners();
} else {
if (scrollAction === 'lock') {
this.__saveScrollPosition();
Polymer.IronScrollManager.pushScrollLock(this);
}
this.__addScrollListeners();
}
},
/**
* @private
*/
__addScrollListeners: function() {
if (!this.__rootNodes) {
this.__rootNodes = [];
// Listen for scroll events in all shadowRoots hosting this overlay only
// when in native ShadowDOM.
if (Polymer.Settings.useShadow) {
var node = this;
while (node) {
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && node.host) {
this.__rootNodes.push(node);
}
node = node.host || node.assignedSlot || node.parentNode;
}
}
this.__rootNodes.push(document);
}
this.__rootNodes.forEach(function(el) {
el.addEventListener('scroll', this.__onCaptureScroll, {
capture: true,
passive: true,
});
}, this);
},
/**
* @private
*/
__removeScrollListeners: function() {
if (this.__rootNodes) {
this.__rootNodes.forEach(function(el) {
el.removeEventListener('scroll', this.__onCaptureScroll, {
capture: true,
passive: true,
});
}, this);
}
if (!this.isAttached) {
this.__rootNodes = null;
}
},
/**
* @param {string=} scrollAction
* @return {boolean}
* @private
*/
__isValidScrollAction: function(scrollAction) {
return scrollAction === 'lock' ||
scrollAction === 'refit' ||
scrollAction === 'cancel';
},
/**
* @private
*/
__onCaptureScroll: function(event) {
if (this.__isAnimating) {
return;
}
// Check if scroll outside the overlay.
if (Polymer.dom(event).path.indexOf(this) >= 0) {
return;
}
switch (this.scrollAction) {
case 'lock':
// NOTE: scrolling might happen if a scroll event is not cancellable, or if
// user pressed keys that cause scrolling (they're not prevented in order not to
// break a11y features like navigate with arrow keys).
this.__restoreScrollPosition();
break;
case 'refit':
this.__deraf('refit', this.refit);
break;
case 'cancel':
this.cancel(event);
break;
}
},
/**
* Memoizes the scroll position of the outside scrolling element.
* @private * @private
*/ */
__onNextAnimationFrame: function(callback) { __saveScrollPosition: function() {
if (this.__raf) { if (document.scrollingElement) {
window.cancelAnimationFrame(this.__raf); this.__scrollTop = document.scrollingElement.scrollTop;
} this.__scrollLeft = document.scrollingElement.scrollLeft;
var self = this; } else {
this.__raf = window.requestAnimationFrame(function nextAnimationFrame() { // Since we don't know if is the body or html, get max.
self.__raf = null; this.__scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
callback.call(self); this.__scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
}); }
} },
/**
* Resets the scroll position of the outside scrolling element.
* @private
*/
__restoreScrollPosition: function() {
if (document.scrollingElement) {
document.scrollingElement.scrollTop = this.__scrollTop;
document.scrollingElement.scrollLeft = this.__scrollLeft;
} else {
// Since we don't know if is the body or html, set both.
document.documentElement.scrollTop = document.body.scrollTop = this.__scrollTop;
document.documentElement.scrollLeft = document.body.scrollLeft = this.__scrollLeft;
}
},
}; };
......
...@@ -10,6 +10,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN ...@@ -10,6 +10,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<link rel="import" href="../iron-fit-behavior/iron-fit-behavior.html"> <link rel="import" href="../iron-fit-behavior/iron-fit-behavior.html">
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html"> <link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
<link rel="import" href="iron-overlay-manager.html"> <link rel="import" href="iron-overlay-manager.html">
<link rel="import" href="iron-scroll-manager.html">
<link rel="import" href="iron-focusables-helper.html"> <link rel="import" href="iron-focusables-helper.html">
</head><body><script src="iron-overlay-behavior-extracted.js"></script></body></html> </head><body><script src="iron-overlay-behavior-extracted.js"></script></body></html>
\ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
Polymer.IronOverlayManagerClass = function() { Polymer.IronOverlayManagerClass = function() {
/** /**
* Used to keep track of the opened overlays. * Used to keep track of the opened overlays.
* @private {Array<Element>} * @private {!Array<!Element>}
*/ */
this._overlays = []; this._overlays = [];
...@@ -24,8 +24,14 @@ ...@@ -24,8 +24,14 @@
this._backdropElement = null; this._backdropElement = null;
// Enable document-wide tap recognizer. // Enable document-wide tap recognizer.
Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this)); // NOTE: Use useCapture=true to avoid accidentally prevention of the closing
// of an overlay via event.stopPropagation(). The only way to prevent
// closing of an overlay should be through its APIs.
// NOTE: enable tap on <html> to workaround Polymer/polymer#4459
// Pass no-op function because MSEdge 15 doesn't handle null as 2nd argument
// https://github.com/Microsoft/ChakraCore/issues/3863
Polymer.Gestures.add(document.documentElement, 'tap', function() {});
document.addEventListener('tap', this._onCaptureClick.bind(this), true);
document.addEventListener('focus', this._onCaptureFocus.bind(this), true); document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true); document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
}; };
...@@ -36,7 +42,7 @@ ...@@ -36,7 +42,7 @@
/** /**
* The shared backdrop element. * The shared backdrop element.
* @type {!Element} backdropElement * @return {!Element} backdropElement
*/ */
get backdropElement() { get backdropElement() {
if (!this._backdropElement) { if (!this._backdropElement) {
...@@ -47,13 +53,17 @@ ...@@ -47,13 +53,17 @@
/** /**
* The deepest active element. * The deepest active element.
* @type {!Element} activeElement the active element * @return {!Element} activeElement the active element
*/ */
get deepActiveElement() { get deepActiveElement() {
var active = document.activeElement;
// document.activeElement can be null // document.activeElement can be null
// https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
// In case of null, default it to document.body. // In IE 11, it can also be an object when operating in iframes.
var active = document.activeElement || document.body; // In these cases, default it to document.body.
if (!active || active instanceof Element === false) {
active = document.body;
}
while (active.root && Polymer.dom(active.root).activeElement) { while (active.root && Polymer.dom(active.root).activeElement) {
active = Polymer.dom(active.root).activeElement; active = Polymer.dom(active.root).activeElement;
} }
...@@ -158,7 +168,7 @@ ...@@ -158,7 +168,7 @@
/** /**
* Returns the current overlay. * Returns the current overlay.
* @return {Element|undefined} * @return {!Element|undefined}
*/ */
currentOverlay: function() { currentOverlay: function() {
var i = this._overlays.length - 1; var i = this._overlays.length - 1;
...@@ -200,10 +210,14 @@ ...@@ -200,10 +210,14 @@
} }
this.backdropElement.style.zIndex = this._getZ(overlay) - 1; this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
this.backdropElement.opened = !!overlay; this.backdropElement.opened = !!overlay;
// Property observers are not fired until element is attached
// in Polymer 2.x, so we ensure element is attached if needed.
// https://github.com/Polymer/polymer/issues/4526
this.backdropElement.prepare();
}, },
/** /**
* @return {Array<Element>} * @return {!Array<!Element>}
*/ */
getBackdrops: function() { getBackdrops: function() {
var backdrops = []; var backdrops = [];
...@@ -224,12 +238,12 @@ ...@@ -224,12 +238,12 @@
}, },
/** /**
* Returns the first opened overlay that has a backdrop. * Returns the top opened overlay that has a backdrop.
* @return {Element|undefined} * @return {!Element|undefined}
* @private * @private
*/ */
_overlayWithBackdrop: function() { _overlayWithBackdrop: function() {
for (var i = 0; i < this._overlays.length; i++) { for (var i = this._overlays.length - 1; i >= 0; i--) {
if (this._overlays[i].withBackdrop) { if (this._overlays[i].withBackdrop) {
return this._overlays[i]; return this._overlays[i];
} }
...@@ -274,8 +288,8 @@ ...@@ -274,8 +288,8 @@
/** /**
* Returns the deepest overlay in the path. * Returns the deepest overlay in the path.
* @param {Array<Element>=} path * @param {!Array<!Element>=} path
* @return {Element|undefined} * @return {!Element|undefined}
* @suppress {missingProperties} * @suppress {missingProperties}
* @private * @private
*/ */
...@@ -294,10 +308,18 @@ ...@@ -294,10 +308,18 @@
* @private * @private
*/ */
_onCaptureClick: function(event) { _onCaptureClick: function(event) {
var overlay = /** @type {?} */ (this.currentOverlay()); var i = this._overlays.length - 1;
// Check if clicked outside of top overlay. if (i === -1) return;
if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) { var path = /** @type {!Array<!EventTarget>} */ (Polymer.dom(event).path);
var overlay;
// Check if clicked outside of overlay.
while ((overlay = /** @type {?} */ (this._overlays[i])) && this._overlayInPath(path) !== overlay) {
overlay._onCaptureClick(event); overlay._onCaptureClick(event);
if (overlay.allowClickThrough) {
i--;
} else {
break;
}
} }
}, },
......
(function() {
'use strict';
/**
* Used to calculate the scroll direction during touch events.
* @type {!Object}
*/
var lastTouchPosition = {
pageX: 0,
pageY: 0
};
/**
* Used to avoid computing event.path and filter scrollable nodes (better perf).
* @type {?EventTarget}
*/
var lastRootTarget = null;
/**
* @type {!Array<!Node>}
*/
var lastScrollableNodes = [];
/**
* @type {!Array<string>}
*/
var scrollEvents = [
// Modern `wheel` event for mouse wheel scrolling:
'wheel',
// Older, non-standard `mousewheel` event for some FF:
'mousewheel',
// IE:
'DOMMouseScroll',
// Touch enabled devices
'touchstart',
'touchmove'
];
/**
* The IronScrollManager is intended to provide a central source
* of authority and control over which elements in a document are currently
* allowed to scroll.
*
* @namespace
* @memberof Polymer
*/
Polymer.IronScrollManager = {
/**
* The current element that defines the DOM boundaries of the
* scroll lock. This is always the most recently locking element.
*
* @return {!Node|undefined}
*/
get currentLockingElement() {
return this._lockingElements[this._lockingElements.length - 1];
},
/**
* Returns true if the provided element is "scroll locked", which is to
* say that it cannot be scrolled via pointer or keyboard interactions.
*
* @memberof Polymer.IronScrollManager
* @param {!HTMLElement} element An HTML element instance which may or may
* not be scroll locked.
*/
elementIsScrollLocked: function(element) {
var currentLockingElement = this.currentLockingElement;
if (currentLockingElement === undefined)
return false;
var scrollLocked;
if (this._hasCachedLockedElement(element)) {
return true;
}
if (this._hasCachedUnlockedElement(element)) {
return false;
}
scrollLocked = !!currentLockingElement &&
currentLockingElement !== element &&
!this._composedTreeContains(currentLockingElement, element);
if (scrollLocked) {
this._lockedElementCache.push(element);
} else {
this._unlockedElementCache.push(element);
}
return scrollLocked;
},
/**
* Push an element onto the current scroll lock stack. The most recently
* pushed element and its children will be considered scrollable. All
* other elements will not be scrollable.
*
* Scroll locking is implemented as a stack so that cases such as
* dropdowns within dropdowns are handled well.
*
* @memberof Polymer.IronScrollManager
* @param {!HTMLElement} element The element that should lock scroll.
*/
pushScrollLock: function(element) {
// Prevent pushing the same element twice
if (this._lockingElements.indexOf(element) >= 0) {
return;
}
if (this._lockingElements.length === 0) {
this._lockScrollInteractions();
}
this._lockingElements.push(element);
this._lockedElementCache = [];
this._unlockedElementCache = [];
},
/**
* Remove an element from the scroll lock stack. The element being
* removed does not need to be the most recently pushed element. However,
* the scroll lock constraints only change when the most recently pushed
* element is removed.
*
* @memberof Polymer.IronScrollManager
* @param {!HTMLElement} element The element to remove from the scroll
* lock stack.
*/
removeScrollLock: function(element) {
var index = this._lockingElements.indexOf(element);
if (index === -1) {
return;
}
this._lockingElements.splice(index, 1);
this._lockedElementCache = [];
this._unlockedElementCache = [];
if (this._lockingElements.length === 0) {
this._unlockScrollInteractions();
}
},
_lockingElements: [],
_lockedElementCache: null,
_unlockedElementCache: null,
_hasCachedLockedElement: function(element) {
return this._lockedElementCache.indexOf(element) > -1;
},
_hasCachedUnlockedElement: function(element) {
return this._unlockedElementCache.indexOf(element) > -1;
},
_composedTreeContains: function(element, child) {
// NOTE(cdata): This method iterates over content elements and their
// corresponding distributed nodes to implement a contains-like method
// that pierces through the composed tree of the ShadowDOM. Results of
// this operation are cached (elsewhere) on a per-scroll-lock basis, to
// guard against potentially expensive lookups happening repeatedly as
// a user scrolls / touchmoves.
var contentElements;
var distributedNodes;
var contentIndex;
var nodeIndex;
if (element.contains(child)) {
return true;
}
contentElements = Polymer.dom(element).querySelectorAll('content,slot');
for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
// Polymer 2.x returns slot.assignedNodes which can contain text nodes.
if (distributedNodes[nodeIndex].nodeType !== Node.ELEMENT_NODE) continue;
if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
return true;
}
}
}
return false;
},
_scrollInteractionHandler: function(event) {
// Avoid canceling an event with cancelable=false, e.g. scrolling is in
// progress and cannot be interrupted.
if (event.cancelable && this._shouldPreventScrolling(event)) {
event.preventDefault();
}
// If event has targetTouches (touch event), update last touch position.
if (event.targetTouches) {
var touch = event.targetTouches[0];
lastTouchPosition.pageX = touch.pageX;
lastTouchPosition.pageY = touch.pageY;
}
},
_lockScrollInteractions: function() {
this._boundScrollHandler = this._boundScrollHandler ||
this._scrollInteractionHandler.bind(this);
for (var i = 0, l = scrollEvents.length; i < l; i++) {
// NOTE: browsers that don't support objects as third arg will
// interpret it as boolean, hence useCapture = true in this case.
document.addEventListener(scrollEvents[i], this._boundScrollHandler, {
capture: true,
passive: false
});
}
},
_unlockScrollInteractions: function() {
for (var i = 0, l = scrollEvents.length; i < l; i++) {
// NOTE: browsers that don't support objects as third arg will
// interpret it as boolean, hence useCapture = true in this case.
document.removeEventListener(scrollEvents[i], this._boundScrollHandler, {
capture: true,
passive: false
});
}
},
/**
* Returns true if the event causes scroll outside the current locking
* element, e.g. pointer/keyboard interactions, or scroll "leaking"
* outside the locking element when it is already at its scroll boundaries.
* @param {!Event} event
* @return {boolean}
* @private
*/
_shouldPreventScrolling: function(event) {
// Update if root target changed. For touch events, ensure we don't
// update during touchmove.
var target = Polymer.dom(event).rootTarget;
if (event.type !== 'touchmove' && lastRootTarget !== target) {
lastRootTarget = target;
lastScrollableNodes = this._getScrollableNodes(Polymer.dom(event).path);
}
// Prevent event if no scrollable nodes.
if (!lastScrollableNodes.length) {
return true;
}
// Don't prevent touchstart event inside the locking element when it has
// scrollable nodes.
if (event.type === 'touchstart') {
return false;
}
// Get deltaX/Y.
var info = this._getScrollInfo(event);
// Prevent if there is no child that can scroll.
return !this._getScrollingNode(lastScrollableNodes, info.deltaX, info.deltaY);
},
/**
* Returns an array of scrollable nodes up to the current locking element,
* which is included too if scrollable.
* @param {!Array<!Node>} nodes
* @return {!Array<!Node>} scrollables
* @private
*/
_getScrollableNodes: function(nodes) {
var scrollables = [];
var lockingIndex = nodes.indexOf(this.currentLockingElement);
// Loop from root target to locking element (included).
for (var i = 0; i <= lockingIndex; i++) {
// Skip non-Element nodes.
if (nodes[i].nodeType !== Node.ELEMENT_NODE) {
continue;
}
var node = /** @type {!Element} */ (nodes[i]);
// Check inline style before checking computed style.
var style = node.style;
if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
style = window.getComputedStyle(node);
}
if (style.overflow === 'scroll' || style.overflow === 'auto') {
scrollables.push(node);
}
}
return scrollables;
},
/**
* Returns the node that is scrolling. If there is no scrolling,
* returns undefined.
* @param {!Array<!Node>} nodes
* @param {number} deltaX Scroll delta on the x-axis
* @param {number} deltaY Scroll delta on the y-axis
* @return {!Node|undefined}
* @private
*/
_getScrollingNode: function(nodes, deltaX, deltaY) {
// No scroll.
if (!deltaX && !deltaY) {
return;
}
// Check only one axis according to where there is more scroll.
// Prefer vertical to horizontal.
var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
var canScroll = false;
if (verticalScroll) {
// delta < 0 is scroll up, delta > 0 is scroll down.
canScroll = deltaY < 0 ? node.scrollTop > 0 :
node.scrollTop < node.scrollHeight - node.clientHeight;
} else {
// delta < 0 is scroll left, delta > 0 is scroll right.
canScroll = deltaX < 0 ? node.scrollLeft > 0 :
node.scrollLeft < node.scrollWidth - node.clientWidth;
}
if (canScroll) {
return node;
}
}
},
/**
* Returns scroll `deltaX` and `deltaY`.
* @param {!Event} event The scroll event
* @return {{deltaX: number, deltaY: number}} Object containing the
* x-axis scroll delta (positive: scroll right, negative: scroll left,
* 0: no scroll), and the y-axis scroll delta (positive: scroll down,
* negative: scroll up, 0: no scroll).
* @private
*/
_getScrollInfo: function(event) {
var info = {
deltaX: event.deltaX,
deltaY: event.deltaY
};
// Already available.
if ('deltaX' in event) {
// do nothing, values are already good.
}
// Safari has scroll info in `wheelDeltaX/Y`.
else if ('wheelDeltaX' in event && 'wheelDeltaY' in event) {
info.deltaX = -event.wheelDeltaX;
info.deltaY = -event.wheelDeltaY;
}
// IE10 has only vertical scroll info in `wheelDelta`.
else if ('wheelDelta' in event) {
info.deltaX = 0;
info.deltaY = -event.wheelDelta;
}
// Firefox has scroll info in `detail` and `axis`.
else if ('axis' in event) {
info.deltaX = event.axis === 1 ? event.detail : 0;
info.deltaY = event.axis === 2 ? event.detail : 0;
}
// On mobile devices, calculate scroll direction.
else if (event.targetTouches) {
var touch = event.targetTouches[0];
// Touch moves from right to left => scrolling goes right.
info.deltaX = lastTouchPosition.pageX - touch.pageX;
// Touch moves from down to up => scrolling goes down.
info.deltaY = lastTouchPosition.pageY - touch.pageY;
}
return info;
}
};
})();
\ No newline at end of file
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--><html><head><link rel="import" href="../polymer/polymer.html">
</head><body><script src="iron-scroll-manager-extracted.js"></script></body></html>
\ No newline at end of file
...@@ -48,9 +48,9 @@ Tree link: https://github.com/PolymerElements/iron-collapse/tree/v2.1.0 ...@@ -48,9 +48,9 @@ Tree link: https://github.com/PolymerElements/iron-collapse/tree/v2.1.0
Name: iron-dropdown Name: iron-dropdown
Repository: https://github.com/PolymerElements/iron-dropdown.git Repository: https://github.com/PolymerElements/iron-dropdown.git
Tree: v1.5.2 Tree: v2.1.0
Revision: c5dbb9404ee56e00a0e893b95b1253be5181ae2b Revision: ec46c453782484d8fbee7b299a486a389699fdf2
Tree link: https://github.com/PolymerElements/iron-dropdown/tree/v1.5.2 Tree link: https://github.com/PolymerElements/iron-dropdown/tree/v2.1.0
Name: iron-fit-behavior Name: iron-fit-behavior
Repository: https://github.com/PolymerElements/iron-fit-behavior.git Repository: https://github.com/PolymerElements/iron-fit-behavior.git
...@@ -126,9 +126,9 @@ Tree link: https://github.com/PolymerElements/iron-meta/tree/v1.1.2 ...@@ -126,9 +126,9 @@ Tree link: https://github.com/PolymerElements/iron-meta/tree/v1.1.2
Name: iron-overlay-behavior Name: iron-overlay-behavior
Repository: https://github.com/PolymerElements/iron-overlay-behavior.git Repository: https://github.com/PolymerElements/iron-overlay-behavior.git
Tree: v1.10.2 Tree: v2.3.2
Revision: 27558b9ceeba7c670999818fc50eebe7e044ed5c Revision: 7431ea3da852adec26f5d8d58d6f4727c280a1f4
Tree link: https://github.com/PolymerElements/iron-overlay-behavior/tree/v1.10.2 Tree link: https://github.com/PolymerElements/iron-overlay-behavior/tree/v2.3.2
Name: iron-pages Name: iron-pages
Repository: https://github.com/PolymerElements/iron-pages.git Repository: https://github.com/PolymerElements/iron-pages.git
......
...@@ -14,9 +14,11 @@ index.html ...@@ -14,9 +14,11 @@ index.html
*.md *.md
metadata.html metadata.html
package.json package.json
package-lock.json
*/test/ */test/
*/tests/ */tests/
.travis.yml .travis.yml
*.d.ts
# app-layout specific # app-layout specific
*/patterns/ */patterns/
......
...@@ -276,6 +276,14 @@ ...@@ -276,6 +276,14 @@
file="../../../third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager.html" file="../../../third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager.html"
type="chrome_html" type="chrome_html"
compress="gzip" /> compress="gzip" />
<structure name="IDR_POLYMER_1_0_IRON_OVERLAY_BEHAVIOR_IRON_SCROLL_MANAGER_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-scroll-manager-extracted.js"
type="chrome_html"
compress="gzip" />
<structure name="IDR_POLYMER_1_0_IRON_OVERLAY_BEHAVIOR_IRON_SCROLL_MANAGER_HTML"
file="../../../third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-scroll-manager.html"
type="chrome_html"
compress="gzip" />
<structure name="IDR_POLYMER_1_0_IRON_PAGES_IRON_PAGES_EXTRACTED_JS" <structure name="IDR_POLYMER_1_0_IRON_PAGES_IRON_PAGES_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/iron-pages/iron-pages-extracted.js" file="../../../third_party/polymer/v1_0/components-chromium/iron-pages/iron-pages-extracted.js"
type="chrome_html" type="chrome_html"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment