update components
This commit is contained in:
parent
1f41a29864
commit
ba749de15d
18 changed files with 482 additions and 369 deletions
|
@ -15,197 +15,244 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
/**
|
||||
* @struct
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
Polymer.IronOverlayManagerClass = function() {
|
||||
/**
|
||||
* Used to keep track of the opened overlays.
|
||||
* @private {Array<Element>}
|
||||
*/
|
||||
this._overlays = [];
|
||||
// Used to keep track of the last focused node before an overlay gets opened.
|
||||
|
||||
/**
|
||||
* Used to keep track of the last focused node before an overlay gets opened.
|
||||
* @private {Array<Element>}
|
||||
*/
|
||||
this._lastFocusedNodes = [];
|
||||
|
||||
/**
|
||||
* iframes have a default z-index of 100, so this default should be at least
|
||||
* that.
|
||||
* iframes have a default z-index of 100,
|
||||
* so this default should be at least that.
|
||||
* @private {number}
|
||||
*/
|
||||
this._minimumZ = 101;
|
||||
|
||||
/**
|
||||
* Used to keep track of the opened overlays with backdrop.
|
||||
* @private {Array<Element>}
|
||||
*/
|
||||
this._backdrops = [];
|
||||
|
||||
/**
|
||||
* Memoized backdrop element.
|
||||
* @private {Element|null}
|
||||
*/
|
||||
this._backdropElement = null;
|
||||
Object.defineProperty(this, 'backdropElement', {
|
||||
get: function() {
|
||||
if (!this._backdropElement) {
|
||||
this._backdropElement = document.createElement('iron-overlay-backdrop');
|
||||
}
|
||||
return this._backdropElement;
|
||||
}.bind(this)
|
||||
});
|
||||
};
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype = {
|
||||
|
||||
constructor: Polymer.IronOverlayManagerClass,
|
||||
|
||||
/**
|
||||
* The shared backdrop element.
|
||||
* @type {Element} backdropElement
|
||||
*/
|
||||
get backdropElement() {
|
||||
if (!this._backdropElement) {
|
||||
this._backdropElement = document.createElement('iron-overlay-backdrop');
|
||||
}
|
||||
return this._backdropElement;
|
||||
},
|
||||
|
||||
/**
|
||||
* The deepest active element.
|
||||
* returns {?Node} element the active element
|
||||
* @type {Element|undefined} activeElement the active element
|
||||
*/
|
||||
this.deepActiveElement = null;
|
||||
Object.defineProperty(this, 'deepActiveElement', {
|
||||
get: function() {
|
||||
var active = document.activeElement;
|
||||
// document.activeElement can be null
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
|
||||
while (active && active.root && Polymer.dom(active.root).activeElement) {
|
||||
active = Polymer.dom(active.root).activeElement;
|
||||
get deepActiveElement() {
|
||||
var active = document.activeElement;
|
||||
// document.activeElement can be null
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
|
||||
while (active && active.root && Polymer.dom(active.root).activeElement) {
|
||||
active = Polymer.dom(active.root).activeElement;
|
||||
}
|
||||
return active;
|
||||
},
|
||||
|
||||
/**
|
||||
* If a node is contained in an overlay.
|
||||
* @param {Element=} node
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
_isChildOfOverlay: function(node) {
|
||||
while (node && node !== document.body) {
|
||||
// Use logical parentNode, or native ShadowRoot host.
|
||||
node = Polymer.dom(node).parentNode || node.host;
|
||||
// Check if it is an overlay.
|
||||
if (node && node.behaviors && node.behaviors.indexOf(Polymer.IronOverlayBehaviorImpl) !== -1) {
|
||||
return true;
|
||||
}
|
||||
return active;
|
||||
}.bind(this)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* If a node is contained in an overlay.
|
||||
* @private
|
||||
* @param {Node} node
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Polymer.IronOverlayManagerClass.prototype._isChildOfOverlay = function(node) {
|
||||
while (node && node !== document.body) {
|
||||
// Use logical parentNode, or native ShadowRoot host.
|
||||
node = Polymer.dom(node).parentNode || node.host;
|
||||
// Check if it is an overlay.
|
||||
if (node && node.behaviors && node.behaviors.indexOf(Polymer.IronOverlayBehaviorImpl) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
},
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype._applyOverlayZ = function(overlay, aboveZ) {
|
||||
this._setZ(overlay, aboveZ + 2);
|
||||
};
|
||||
/**
|
||||
* @param {Element} overlay
|
||||
* @param {number} aboveZ
|
||||
* @private
|
||||
*/
|
||||
_applyOverlayZ: function(overlay, aboveZ) {
|
||||
this._setZ(overlay, aboveZ + 2);
|
||||
},
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype._setZ = function(element, z) {
|
||||
element.style.zIndex = z;
|
||||
};
|
||||
/**
|
||||
* @param {Element} element
|
||||
* @param {number|string} z
|
||||
* @private
|
||||
*/
|
||||
_setZ: function(element, z) {
|
||||
element.style.zIndex = z;
|
||||
},
|
||||
|
||||
/**
|
||||
* track overlays for z-index and focus managemant
|
||||
*/
|
||||
Polymer.IronOverlayManagerClass.prototype.addOverlay = function(overlay) {
|
||||
var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
|
||||
this._overlays.push(overlay);
|
||||
var newZ = this.currentOverlayZ();
|
||||
if (newZ <= minimumZ) {
|
||||
this._applyOverlayZ(overlay, minimumZ);
|
||||
}
|
||||
var element = this.deepActiveElement;
|
||||
// If already in other overlay, don't reset focus there.
|
||||
if (this._isChildOfOverlay(element)) {
|
||||
element = null;
|
||||
}
|
||||
this._lastFocusedNodes.push(element);
|
||||
};
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype.removeOverlay = function(overlay) {
|
||||
var i = this._overlays.indexOf(overlay);
|
||||
if (i >= 0) {
|
||||
this._overlays.splice(i, 1);
|
||||
this._setZ(overlay, '');
|
||||
|
||||
var node = this._lastFocusedNodes[i];
|
||||
// Focus only if still contained in document.body
|
||||
if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deepContains(node)) {
|
||||
node.focus();
|
||||
/**
|
||||
* Tracks overlays for z-index and focus management.
|
||||
* @param {Element} overlay
|
||||
*/
|
||||
addOverlay: function(overlay) {
|
||||
var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
|
||||
this._overlays.push(overlay);
|
||||
var newZ = this.currentOverlayZ();
|
||||
if (newZ <= minimumZ) {
|
||||
this._applyOverlayZ(overlay, minimumZ);
|
||||
}
|
||||
this._lastFocusedNodes.splice(i, 1);
|
||||
}
|
||||
};
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype.currentOverlay = function() {
|
||||
var i = this._overlays.length - 1;
|
||||
while (this._overlays[i] && !this._overlays[i].opened) {
|
||||
--i;
|
||||
}
|
||||
return this._overlays[i];
|
||||
};
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype.currentOverlayZ = function() {
|
||||
return this._getOverlayZ(this.currentOverlay());
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures that the minimum z-index of new overlays is at least `minimumZ`.
|
||||
* This does not effect the z-index of any existing overlays.
|
||||
*
|
||||
* @param {number} minimumZ
|
||||
*/
|
||||
Polymer.IronOverlayManagerClass.prototype.ensureMinimumZ = function(minimumZ) {
|
||||
this._minimumZ = Math.max(this._minimumZ, minimumZ);
|
||||
};
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype.focusOverlay = function() {
|
||||
var current = this.currentOverlay();
|
||||
// We have to be careful to focus the next overlay _after_ any current
|
||||
// transitions are complete (due to the state being toggled prior to the
|
||||
// transition). Otherwise, we risk infinite recursion when a transitioning
|
||||
// (closed) overlay becomes the current overlay.
|
||||
//
|
||||
// NOTE: We make the assumption that any overlay that completes a transition
|
||||
// will call into focusOverlay to kick the process back off. Currently:
|
||||
// transitionend -> _applyFocus -> focusOverlay.
|
||||
if (current && !current.transitioning) {
|
||||
current._applyFocus();
|
||||
}
|
||||
};
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype.trackBackdrop = function(element) {
|
||||
// backdrops contains the overlays with a backdrop that are currently
|
||||
// visible
|
||||
var index = this._backdrops.indexOf(element);
|
||||
if (element.opened && element.withBackdrop) {
|
||||
// no duplicates
|
||||
if (index === -1) {
|
||||
this._backdrops.push(element);
|
||||
var element = this.deepActiveElement;
|
||||
// If already in other overlay, don't reset focus there.
|
||||
if (this._isChildOfOverlay(element)) {
|
||||
element = null;
|
||||
}
|
||||
} else if (index >= 0) {
|
||||
this._backdrops.splice(index, 1);
|
||||
}
|
||||
};
|
||||
this._lastFocusedNodes.push(element);
|
||||
},
|
||||
|
||||
Polymer.IronOverlayManagerClass.prototype.getBackdrops = function() {
|
||||
return this._backdrops;
|
||||
};
|
||||
/**
|
||||
* @param {Element} overlay
|
||||
*/
|
||||
removeOverlay: function(overlay) {
|
||||
var i = this._overlays.indexOf(overlay);
|
||||
if (i >= 0) {
|
||||
this._overlays.splice(i, 1);
|
||||
this._setZ(overlay, '');
|
||||
|
||||
/**
|
||||
* Returns the z-index for the backdrop.
|
||||
*/
|
||||
Polymer.IronOverlayManagerClass.prototype.backdropZ = function() {
|
||||
return this._getOverlayZ(this._overlayWithBackdrop()) - 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the first opened overlay that has a backdrop.
|
||||
*/
|
||||
Polymer.IronOverlayManagerClass.prototype._overlayWithBackdrop = function() {
|
||||
for (var i = 0; i < this._overlays.length; i++) {
|
||||
if (this._overlays[i].opened && this._overlays[i].withBackdrop) {
|
||||
return this._overlays[i];
|
||||
var node = this._lastFocusedNodes[i];
|
||||
// Focus only if still contained in document.body
|
||||
if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deepContains(node)) {
|
||||
node.focus();
|
||||
}
|
||||
this._lastFocusedNodes.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the minimum z-index for the overlay.
|
||||
*/
|
||||
Polymer.IronOverlayManagerClass.prototype._getOverlayZ = function(overlay) {
|
||||
var z = this._minimumZ;
|
||||
if (overlay) {
|
||||
var z1 = Number(window.getComputedStyle(overlay).zIndex);
|
||||
// Check if is a number
|
||||
// Number.isNaN not supported in IE 10+
|
||||
if (z1 === z1) {
|
||||
z = z1;
|
||||
/**
|
||||
* @return {Element|undefined} overlay The current overlay.
|
||||
*/
|
||||
currentOverlay: function() {
|
||||
var i = this._overlays.length - 1;
|
||||
while (this._overlays[i] && !this._overlays[i].opened) {
|
||||
--i;
|
||||
}
|
||||
return this._overlays[i];
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {number} zIndex the current overlay z-index.
|
||||
*/
|
||||
currentOverlayZ: function() {
|
||||
return this._getOverlayZ(this.currentOverlay());
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures that the minimum z-index of new overlays is at least `minimumZ`.
|
||||
* This does not effect the z-index of any existing overlays.
|
||||
* @param {number} minimumZ
|
||||
*/
|
||||
ensureMinimumZ: function(minimumZ) {
|
||||
this._minimumZ = Math.max(this._minimumZ, minimumZ);
|
||||
},
|
||||
|
||||
focusOverlay: function() {
|
||||
var current = /** @type {?} */ (this.currentOverlay());
|
||||
// We have to be careful to focus the next overlay _after_ any current
|
||||
// transitions are complete (due to the state being toggled prior to the
|
||||
// transition). Otherwise, we risk infinite recursion when a transitioning
|
||||
// (closed) overlay becomes the current overlay.
|
||||
//
|
||||
// NOTE: We make the assumption that any overlay that completes a transition
|
||||
// will call into focusOverlay to kick the process back off. Currently:
|
||||
// transitionend -> _applyFocus -> focusOverlay.
|
||||
if (current && !current.transitioning) {
|
||||
current._applyFocus();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Element} overlay The overlay that updated its withBackdrop.
|
||||
*/
|
||||
trackBackdrop: function(overlay) {
|
||||
var index = this._backdrops.indexOf(overlay);
|
||||
if (overlay.opened && overlay.withBackdrop) {
|
||||
// no duplicates
|
||||
if (index === -1) {
|
||||
this._backdrops.push(overlay);
|
||||
}
|
||||
} else if (index >= 0) {
|
||||
this._backdrops.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Array<Element>} backdrops
|
||||
*/
|
||||
getBackdrops: function() {
|
||||
return this._backdrops;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {number} index The z-index for the backdrop.
|
||||
*/
|
||||
backdropZ: function() {
|
||||
return this._getOverlayZ(this._overlayWithBackdrop()) - 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Element|undefined} overlay The first opened overlay that has a backdrop.
|
||||
* @private
|
||||
*/
|
||||
_overlayWithBackdrop: function() {
|
||||
for (var i = 0; i < this._overlays.length; i++) {
|
||||
if (this._overlays[i].opened && this._overlays[i].withBackdrop) {
|
||||
return this._overlays[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the minimum z-index for the overlay.
|
||||
* @param {Element=} overlay
|
||||
* @private
|
||||
*/
|
||||
_getOverlayZ: function(overlay) {
|
||||
var z = this._minimumZ;
|
||||
if (overlay) {
|
||||
var z1 = Number(window.getComputedStyle(overlay).zIndex);
|
||||
// Check if is a number
|
||||
// Number.isNaN not supported in IE 10+
|
||||
if (z1 === z1) {
|
||||
z = z1;
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
return z;
|
||||
};
|
||||
|
||||
Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
|
||||
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue