Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ShadyDOM on-demand patching #5585

Draft
wants to merge 23 commits into
base: legacy-undefined-noBatch
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/elements/dom-bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { PropertyEffects } from '../mixins/property-effects.js';
import { OptionalMutableData } from '../mixins/mutable-data.js';
import { GestureEventListeners } from '../mixins/gesture-event-listeners.js';
import { strictTemplatePolicy } from '../utils/settings.js';
import { wrap } from '../utils/wrap.js';
import { wrapIfNeeded } from '../utils/wrap.js';
import { hideElementsGlobally } from '../utils/hide-template-controls.js';

/**
Expand Down Expand Up @@ -96,7 +96,7 @@ export class DomBind extends domBindBase {
}

__insertChildren() {
wrap(wrap(this).parentNode).insertBefore(this.root, this);
wrapIfNeeded(wrapIfNeeded(this).parentNode).insertBefore(this.root, this);
}

__removeChildren() {
Expand Down
24 changes: 12 additions & 12 deletions lib/elements/dom-if.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Debouncer } from '../utils/debounce.js';
import { enqueueDebouncer, flush } from '../utils/flush.js';
import { microTask } from '../utils/async.js';
import { root } from '../utils/path.js';
import { wrap } from '../utils/wrap.js';
import { wrapIfNeeded } from '../utils/wrap.js';
import { hideElementsGlobally } from '../utils/hide-template-controls.js';
import { fastDomIf, strictTemplatePolicy, suppressTemplateNotifications } from '../utils/settings.js';
import { showHideChildren, templatize } from '../utils/templatize.js';
Expand Down Expand Up @@ -118,9 +118,9 @@ class DomIfBase extends PolymerElement {
*/
disconnectedCallback() {
super.disconnectedCallback();
const parent = wrap(this).parentNode;
const parent = wrapIfNeeded(this).parentNode;
if (!parent || (parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE &&
!wrap(parent).host)) {
!wrapIfNeeded(parent).host)) {
this.__teardownInstance();
}
}
Expand Down Expand Up @@ -158,11 +158,11 @@ class DomIfBase extends PolymerElement {
let template = thisAsTemplate._templateInfo ?
thisAsTemplate :
/** @type {!HTMLTemplateElement} */
(wrap(thisAsTemplate).querySelector('template'));
(thisAsTemplate.querySelector('template'));
if (!template) {
// Wait until childList changes and template should be there by then
let observer = new MutationObserver(() => {
if (wrap(this).querySelector('template')) {
if (this.querySelector('template')) {
observer.disconnect();
this.__render();
} else {
Expand Down Expand Up @@ -193,7 +193,7 @@ class DomIfBase extends PolymerElement {
* @return {boolean} True if the instance was created, false otherwise.
*/
__ensureInstance() {
let parentNode = wrap(this).parentNode;
let parentNode = wrapIfNeeded(this).parentNode;
if (!this.__hasInstance()) {
// Guard against element being detached while render was queued
if (!parentNode) {
Expand All @@ -209,10 +209,10 @@ class DomIfBase extends PolymerElement {
let children = this.__getInstanceNodes();
if (children && children.length) {
// Detect case where dom-if was re-attached in new position
let lastChild = wrap(this).previousSibling;
let lastChild = wrapIfNeeded(this).previousSibling;
if (lastChild !== children[children.length-1]) {
for (let i=0, n; (i<children.length) && (n=children[i]); i++) {
wrap(parentNode).insertBefore(n, this);
wrapIfNeeded(parentNode).insertBefore(n, this);
}
}
}
Expand Down Expand Up @@ -422,7 +422,7 @@ class DomIfFast extends DomIfBase {
// Stamp the template, and set its DocumentFragment to the "instance"
this.__instance = host._stampTemplate(
/** @type {!HTMLTemplateElement} */ (this.__template), templateInfo);
wrap(parentNode).insertBefore(this.__instance, this);
wrapIfNeeded(parentNode).insertBefore(this.__instance, this);
}

/**
Expand Down Expand Up @@ -558,7 +558,7 @@ class DomIfLegacy extends DomIfBase {
}
// Create and insert the instance
this.__instance = new this.__ctor();
wrap(parentNode).insertBefore(this.__instance.root, this);
wrapIfNeeded(parentNode).insertBefore(this.__instance.root, this);
}

/**
Expand All @@ -574,11 +574,11 @@ class DomIfLegacy extends DomIfBase {
let c$ = this.__instance.children;
if (c$ && c$.length) {
// use first child parent, for case when dom-if may have been detached
let parent = wrap(c$[0]).parentNode;
let parent = wrapIfNeeded(c$[0]).parentNode;
// Instance children may be disconnected from parents when dom-if
// detaches if a tree was innerHTML'ed
if (parent) {
parent = wrap(parent);
parent = wrapIfNeeded(parent);
for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) {
parent.removeChild(n);
}
Expand Down
7 changes: 4 additions & 3 deletions lib/elements/dom-repeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { enqueueDebouncer, flush } from '../utils/flush.js';
import { OptionalMutableData } from '../mixins/mutable-data.js';
import { matches, translate } from '../utils/path.js';
import { timeOut, microTask } from '../utils/async.js';
import { wrap } from '../utils/wrap.js';
import { wrap, wrapIfNeeded } from '../utils/wrap.js';
import { hideElementsGlobally } from '../utils/hide-template-controls.js';
import { suppressTemplateNotifications } from '../utils/settings.js';

Expand Down Expand Up @@ -339,7 +339,7 @@ export class DomRepeat extends domRepeatBase {
// only perform attachment if the element was previously detached.
if (this.__isDetached) {
this.__isDetached = false;
let wrappedParent = wrap(wrap(this).parentNode);
let wrappedParent = wrapIfNeeded(wrapIfNeeded(this).parentNode);
for (let i=0; i<this.__instances.length; i++) {
this.__attachInstance(i, wrappedParent);
}
Expand Down Expand Up @@ -607,6 +607,7 @@ export class DomRepeat extends domRepeatBase {

__detachInstance(idx) {
let inst = this.__instances[idx];
// Note, use slow `wrap` to ensure any removed DOM is properly undistributed.
const wrappedRoot = wrap(inst.root);
for (let i=0; i<inst.children.length; i++) {
let el = inst.children[i];
Expand Down Expand Up @@ -651,7 +652,7 @@ export class DomRepeat extends domRepeatBase {
}
let beforeRow = this.__instances[instIdx + 1];
let beforeNode = beforeRow ? beforeRow.children[0] : this;
wrap(wrap(this).parentNode).insertBefore(inst.root, beforeNode);
wrapIfNeeded(wrapIfNeeded(this).parentNode).insertBefore(inst.root, beforeNode);
this.__instances[instIdx] = inst;
return inst;
}
Expand Down
16 changes: 8 additions & 8 deletions lib/legacy/legacy-element-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { setTouchAction } from '../utils/gestures.js';
import { Debouncer } from '../utils/debounce.js';
import { timeOut, microTask } from '../utils/async.js';
import { get } from '../utils/path.js';
import { wrap } from '../utils/wrap.js';
import { wrapIfNeeded } from '../utils/wrap.js';
import { scopeSubtree } from '../utils/scope-subtree.js';

let styleInterface = window.ShadyCSS;
Expand Down Expand Up @@ -436,7 +436,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
});
event.detail = detail;
let node = options.node || this;
wrap(node).dispatchEvent(event);
wrapIfNeeded(node).dispatchEvent(event);
return event;
}

Expand Down Expand Up @@ -537,7 +537,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @override
*/
get domHost() {
let root = wrap(this).getRootNode();
let root = wrapIfNeeded(this).getRootNode();
return (root instanceof DocumentFragment) ? /** @type {ShadowRoot} */ (root).host : root;
}

Expand Down Expand Up @@ -702,8 +702,8 @@ export const LegacyElementMixin = dedupingMixin((base) => {
*/
isLightDescendant(node) {
const thisNode = /** @type {Node} */ (this);
return thisNode !== node && wrap(thisNode).contains(node) &&
wrap(thisNode).getRootNode() === wrap(node).getRootNode();
return thisNode !== node && wrapIfNeeded(thisNode).contains(node) &&
wrapIfNeeded(thisNode).getRootNode() === wrapIfNeeded(node).getRootNode();
}

/**
Expand All @@ -714,7 +714,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @override
*/
isLocalDescendant(node) {
return this.root === wrap(node).getRootNode();
return this.root === wrapIfNeeded(node).getRootNode();
}

/**
Expand Down Expand Up @@ -908,10 +908,10 @@ export const LegacyElementMixin = dedupingMixin((base) => {
bool = !node.hasAttribute(name);
}
if (bool) {
wrap(node).setAttribute(name, '');
wrapIfNeeded(node).setAttribute(name, '');
return true;
} else {
wrap(node).removeAttribute(name);
wrapIfNeeded(node).removeAttribute(name);
return false;
}
}
Expand Down
29 changes: 21 additions & 8 deletions lib/legacy/polymer-fn.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,22 @@ 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
*/
import { Class } from './class.js';
import { lazyDefine } from '../utils/settings.js';

import '../utils/boot.js';

const generateClass = (info) => {
// if input is a `class` (aka a function with a prototype), use the prototype
// remember that the `constructor` will never be called
let klass;
if (typeof info === 'function') {
klass = info;
} else {
klass = Polymer.Class(info);
}
return klass;
};

/**
* Legacy class factory and registration helper for defining Polymer
* elements.
Expand All @@ -31,16 +44,16 @@ import '../utils/boot.js';
* @suppress {duplicate, invalidCasts, checkTypes}
*/
const Polymer = function(info) {
// if input is a `class` (aka a function with a prototype), use the prototype
// remember that the `constructor` will never be called
let klass;
if (typeof info === 'function') {
klass = info;
// Note, when polyfillDefineLazy is used, the class is not returned from this function. Elements that require this should set `_needsCtor` to true to opt
// out of this optimization. In extended library code, only
// `iron-a11y-announcer` and/ `paper-menu-button` need this.
if (lazyDefine && customElements.polyfillDefineLazy && !info._needsCtor) {
customElements.polyfillDefineLazy(info.is, () => generateClass(info));
} else {
klass = Polymer.Class(info);
const klass = generateClass(info);
customElements.define(klass.is, /** @type {!HTMLElement} */(klass));
return klass;
}
customElements.define(klass.is, /** @type {!HTMLElement} */(klass));
return klass;
};

Polymer.Class = Class;
Expand Down
12 changes: 6 additions & 6 deletions lib/legacy/polymer.dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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
*/
import '../utils/boot.js';
import { wrap } from '../utils/wrap.js';
import { wrap, wrapIfNeeded } from '../utils/wrap.js';
import '../utils/settings.js';
import { FlattenedNodesObserver } from '../utils/flattened-nodes-observer.js';
export { flush, enqueueDebouncer as addDebouncer } from '../utils/flush.js';
Expand Down Expand Up @@ -97,15 +97,15 @@ class DomApiNative {
* @override
*/
deepContains(node) {
if (wrap(this.node).contains(node)) {
if (wrapIfNeeded(this.node).contains(node)) {
return true;
}
let n = node;
let doc = node.ownerDocument;
// walk from node to `this` or `document`
while (n && n !== doc && n !== this.node) {
// use logical parentnode, or native ShadowRoot host
n = wrap(n).parentNode || wrap(n).host;
n = wrapIfNeeded(n).parentNode || wrapIfNeeded(n).host;
}
return n === this.node;
}
Expand All @@ -132,7 +132,7 @@ class DomApiNative {
*/
getDistributedNodes() {
return (this.node.localName === 'slot') ?
wrap(this.node).assignedNodes({flatten: true}) :
wrapIfNeeded(this.node).assignedNodes({flatten: true}) :
[];
}

Expand All @@ -144,10 +144,10 @@ class DomApiNative {
*/
getDestinationInsertionPoints() {
let ip$ = [];
let n = wrap(this.node).assignedSlot;
let n = wrapIfNeeded(this.node).assignedSlot;
while (n) {
ip$.push(n);
n = wrap(n).assignedSlot;
n = wrapIfNeeded(n).assignedSlot;
}
return ip$;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/mixins/disable-upgrade-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/
import { ElementMixin } from './element-mixin.js';
import { dedupingMixin } from '../utils/mixin.js';
import { wrap } from '../utils/wrap.js';
import { wrapIfNeeded } from '../utils/wrap.js';

const DISABLED_ATTR = 'disable-upgrade';

Expand Down Expand Up @@ -131,7 +131,7 @@ export const DisableUpgradeMixin = dedupingMixin((base) => {
if (this.__isUpgradeDisabled && value == null) {
super._initializeProperties();
this.__isUpgradeDisabled = false;
if (wrap(this).isConnected) {
if (wrapIfNeeded(this).isConnected) {
super.connectedCallback();
}
}
Expand Down
12 changes: 10 additions & 2 deletions lib/mixins/element-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { pathFromUrl, resolveCss, resolveUrl } from '../utils/resolve-url.js';
import { DomModule } from '../elements/dom-module.js';
import { PropertyEffects } from './property-effects.js';
import { PropertiesMixin } from './properties-mixin.js';
import { wrap } from '../utils/wrap.js';
import { wrapIfNeeded } from '../utils/wrap.js';

/**
* Current Polymer version in Semver notation.
Expand Down Expand Up @@ -100,6 +100,14 @@ export const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];
* @return {function(new:T)} superClass with mixin applied.
*/
export const ElementMixin = dedupingMixin(base => {

// Optimizations for ShadyDOM's on-demand patching that pre-patches
// elements to work with ShadyDOM.
if (window.ShadyDOM && window.ShadyDOM.patchOnDemand) {
base = class extends base {};
ShadyDOM.patchElementProto(base.prototype);
}

/**
* @constructor
* @implements {Polymer_PropertyEffects}
Expand Down Expand Up @@ -699,7 +707,7 @@ export const ElementMixin = dedupingMixin(base => {
* @return {ShadowRoot} node to which the dom has been attached.
*/
_attachDom(dom) {
const n = wrap(this);
const n = wrapIfNeeded(this);
if (n.attachShadow) {
if (dom) {
if (!n.shadowRoot) {
Expand Down
1 change: 1 addition & 0 deletions lib/mixins/properties-changed.js
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ export const PropertiesChanged = dedupingMixin(
_valueToNodeAttribute(node, value, attribute) {
const str = this._serializeValue(value);
if (attribute === 'class' || attribute === 'name' || attribute === 'slot') {
// Note, must always wrap here since this may be an unpatched node.
node = /** @type {?Element} */(wrap(node));
}
if (str === undefined) {
Expand Down
Loading