Merge pull request #5452 from Polymer/shady-nopatch

Changes to make compatible with `noPatch` version of ShadyDOM [3.x]
This commit is contained in:
Kevin Schaaf
2019-02-06 17:04:54 -08:00
committed by GitHub
24 changed files with 1355 additions and 856 deletions

View File

@@ -13,6 +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';
/**
* @constructor
@@ -87,7 +88,7 @@ export class DomBind extends domBindBase {
}
__insertChildren() {
this.parentNode.insertBefore(this.root, this);
wrap(wrap(this).parentNode).insertBefore(this.root, this);
}
__removeChildren() {

View File

@@ -14,6 +14,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';
/**
* The `<dom-if>` element will stamp a light-dom `<template>` child when
@@ -120,9 +121,9 @@ export class DomIf extends PolymerElement {
*/
disconnectedCallback() {
super.disconnectedCallback();
if (!this.parentNode ||
(this.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE &&
!this.parentNode.host)) {
const parent = wrap(this).parentNode;
if (!parent || (parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE &&
!wrap(parent).host)) {
this.__teardownInstance();
}
}
@@ -174,15 +175,15 @@ export class DomIf extends PolymerElement {
}
__ensureInstance() {
let parentNode = this.parentNode;
let parentNode = wrap(this).parentNode;
// Guard against element being detached while render was queued
if (parentNode) {
if (!this.__ctor) {
let template = /** @type {HTMLTemplateElement} */(this.querySelector('template'));
let template = /** @type {HTMLTemplateElement} */(wrap(this).querySelector('template'));
if (!template) {
// Wait until childList changes and template should be there by then
let observer = new MutationObserver(() => {
if (this.querySelector('template')) {
if (wrap(this).querySelector('template')) {
observer.disconnect();
this.__render();
} else {
@@ -219,16 +220,16 @@ export class DomIf extends PolymerElement {
}
if (!this.__instance) {
this.__instance = new this.__ctor();
parentNode.insertBefore(this.__instance.root, this);
wrap(parentNode).insertBefore(this.__instance.root, this);
} else {
this.__syncHostProperties();
let c$ = this.__instance.children;
if (c$ && c$.length) {
// Detect case where dom-if was re-attached in new position
let lastChild = this.previousSibling;
let lastChild = wrap(this).previousSibling;
if (lastChild !== c$[c$.length-1]) {
for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) {
parentNode.insertBefore(n, this);
wrap(parentNode).insertBefore(n, this);
}
}
}
@@ -253,10 +254,11 @@ export class DomIf extends PolymerElement {
let c$ = this.__instance.children;
if (c$ && c$.length) {
// use first child parent, for case when dom-if may have been detached
let parent = c$[0].parentNode;
// Instance children may be disconnected from parents when dom-if
// detaches if a tree was innerHTML'ed
if (parent) {
let parent = wrap(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);
for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) {
parent.removeChild(n);
}

View File

@@ -15,6 +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';
/**
* @constructor
@@ -323,9 +324,9 @@ export class DomRepeat extends domRepeatBase {
// only perform attachment if the element was previously detached.
if (this.__isDetached) {
this.__isDetached = false;
let parent = this.parentNode;
let wrappedParent = wrap(wrap(this).parentNode);
for (let i=0; i<this.__instances.length; i++) {
this.__attachInstance(i, parent);
this.__attachInstance(i, wrappedParent);
}
}
}
@@ -583,15 +584,17 @@ export class DomRepeat extends domRepeatBase {
__detachInstance(idx) {
let inst = this.__instances[idx];
const wrappedRoot = wrap(inst.root);
for (let i=0; i<inst.children.length; i++) {
let el = inst.children[i];
inst.root.appendChild(el);
wrappedRoot.appendChild(el);
}
return inst;
}
__attachInstance(idx, parent) {
let inst = this.__instances[idx];
// Note, this is pre-wrapped as an optimization
parent.insertBefore(inst.root, this);
}
@@ -625,7 +628,7 @@ export class DomRepeat extends domRepeatBase {
}
let beforeRow = this.__instances[instIdx + 1];
let beforeNode = beforeRow ? beforeRow.children[0] : this;
this.parentNode.insertBefore(inst.root, beforeNode);
wrap(wrap(this).parentNode).insertBefore(inst.root, beforeNode);
this.__instances[instIdx] = inst;
return inst;
}

View File

@@ -180,7 +180,7 @@ function flattenBehaviors(behaviors, list, exclude) {
/**
* @param {!PolymerInit} info Polymer info object
* @param {function(new:HTMLElement)} Base base class to extend with info object
* @param {Object} behaviors behaviors to copy into the element
* @param {Object=} behaviors behaviors to copy into the element
* @return {function(new:HTMLElement)} Generated class
* @suppress {checkTypes}
* @private
@@ -197,7 +197,7 @@ function GenerateClassFromInfo(info, Base, behaviors) {
// explicitly not calling super._finalizeClass
static _finalizeClass() {
// if calling via a subclass that hasn't been generated, pass through to super
if (!this.hasOwnProperty(window.JSCompiler_renameProperty('generatedFrom', this))) {
if (!this.hasOwnProperty(JSCompiler_renameProperty('generatedFrom', this))) {
super._finalizeClass();
} else {
// interleave properties and observers per behavior and `info`

View File

@@ -151,12 +151,31 @@ Polymer.Class = (info, mixin) => Class(info,
// Apply LegacyDataMixin to Templatizer instances as well, and defer
// runtime switch to the root's host (_methodHost)
templatize.mixin =
dedupingMixin(superClass => class extends LegacyDataMixin(superClass) {
get _legacyUndefinedCheck() {
return this._methodHost && this._methodHost._legacyUndefinedCheck;
/**
* @mixinFunction
* @polymer
*/
const TemplatizeMixin =
dedupingMixin(superClass => {
/**
* @constructor
* @extends {HTMLElement}
*/
const legacyBase = LegacyDataMixin(superClass);
/**
* @private
*/
class TemplateLegacy extends legacyBase {
get _legacyUndefinedCheck() {
return this._methodHost && this._methodHost._legacyUndefinedCheck;
}
}
/** @type {!Polymer_PropertyEffects} */
TemplateLegacy.prototype._methodHost;
return TemplateLegacy;
});
templatize.mixin = TemplatizeMixin;
console.info('LegacyDataMixin will be applied to all legacy elements.\n' +
'Set `_legacyUndefinedCheck: true` on element class to enable.');

View File

@@ -8,7 +8,6 @@ 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 '@webcomponents/shadycss/entrypoints/apply-shim.js';
import { ElementMixin } from '../mixins/element-mixin.js';
import { GestureEventListeners } from '../mixins/gesture-event-listeners.js';
import { DirMixin } from '../mixins/dir-mixin.js';
@@ -20,6 +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';
let styleInterface = window.ShadyCSS;
@@ -419,7 +419,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
});
event.detail = detail;
let node = options.node || this;
node.dispatchEvent(event);
wrap(node).dispatchEvent(event);
return event;
}
@@ -506,6 +506,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @override
*/
$$(slctr) {
// Note, no need to `wrap` this because root is always patched
return this.root.querySelector(slctr);
}
@@ -516,7 +517,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @this {Element}
*/
get domHost() {
let root = this.getRootNode();
let root = wrap(this).getRootNode();
return (root instanceof DocumentFragment) ? /** @type {ShadowRoot} */ (root).host : root;
}
@@ -528,7 +529,9 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @override
*/
distributeContent() {
if (window.ShadyDOM && this.shadowRoot) {
const thisEl = /** @type {Element} */ (this);
const domApi = /** @type {PolymerDomApi} */(dom(thisEl));
if (window.ShadyDOM && domApi.shadowRoot) {
ShadyDOM.flush();
}
}
@@ -638,6 +641,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @override
*/
getContentChildNodes(slctr) {
// Note, no need to `wrap` this because root is always
let content = this.root.querySelector(slctr || 'slot');
return content ?
/** @type {PolymerDomApi} */ (dom(content)).getDistributedNodes() :
@@ -678,8 +682,8 @@ export const LegacyElementMixin = dedupingMixin((base) => {
*/
isLightDescendant(node) {
const thisNode = /** @type {Node} */ (this);
return thisNode !== node && thisNode.contains(node) &&
thisNode.getRootNode() === node.getRootNode();
return thisNode !== node && wrap(thisNode).contains(node) &&
wrap(thisNode).getRootNode() === wrap(node).getRootNode();
}
/**
@@ -690,7 +694,7 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @override
*/
isLocalDescendant(node) {
return this.root === node.getRootNode();
return this.root === wrap(node).getRootNode();
}
/**
@@ -875,18 +879,18 @@ export const LegacyElementMixin = dedupingMixin((base) => {
* @override
*/
toggleAttribute(name, bool) {
let node = /** @type {Element} */ this;
let node = /** @type {Element} */(this);
if (arguments.length === 3) {
node = /** @type {Element} */ arguments[2];
node = /** @type {Element} */(arguments[2]);
}
if (arguments.length == 1) {
bool = !node.hasAttribute(name);
}
if (bool) {
node.setAttribute(name, '');
wrap(node).setAttribute(name, '');
return true;
} else {
node.removeAttribute(name);
wrap(node).removeAttribute(name);
return false;
}
}

View File

@@ -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 '../utils/settings.js';
import { FlattenedNodesObserver } from '../utils/flattened-nodes-observer.js';
export { flush, enqueueDebouncer as addDebouncer } from '../utils/flush.js';
@@ -40,8 +40,9 @@ export const matchesSelector = function(node, selector) {
* Node API wrapper class returned from `Polymer.dom.(target)` when
* `target` is a `Node`.
* @implements {PolymerDomApi}
* @unrestricted
*/
export class DomApi {
class DomApiNative {
/**
* @param {Node} node Node for which to create a Polymer.dom helper object.
@@ -93,7 +94,7 @@ export class DomApi {
* @override
*/
deepContains(node) {
if (this.node.contains(node)) {
if (wrap(this.node).contains(node)) {
return true;
}
let n = node;
@@ -101,7 +102,7 @@ export class DomApi {
// walk from node to `this` or `document`
while (n && n !== doc && n !== this.node) {
// use logical parentnode, or native ShadowRoot host
n = n.parentNode || n.host;
n = wrap(n).parentNode || wrap(n).host;
}
return n === this.node;
}
@@ -116,7 +117,7 @@ export class DomApi {
* @override
*/
getOwnerRoot() {
return this.node.getRootNode();
return wrap(this.node).getRootNode();
}
/**
@@ -128,7 +129,7 @@ export class DomApi {
*/
getDistributedNodes() {
return (this.node.localName === 'slot') ?
this.node.assignedNodes({flatten: true}) :
wrap(this.node).assignedNodes({flatten: true}) :
[];
}
@@ -140,10 +141,10 @@ export class DomApi {
*/
getDestinationInsertionPoints() {
let ip$ = [];
let n = this.node.assignedSlot;
let n = wrap(this.node).assignedSlot;
while (n) {
ip$.push(n);
n = n.assignedSlot;
n = wrap(n).assignedSlot;
}
return ip$;
}
@@ -159,7 +160,7 @@ export class DomApi {
importNode(node, deep) {
let doc = this.node instanceof Document ? this.node :
this.node.ownerDocument;
return doc.importNode(node, deep);
return wrap(doc).importNode(node, deep);
}
/**
@@ -196,7 +197,7 @@ export class DomApi {
* For shadow roots, returns the currently focused element within this
* shadow root.
*
* @return {Node|undefined} Currently focused element
* return {Node|undefined} Currently focused element
* @override
*/
get activeElement() {
@@ -209,7 +210,7 @@ function forwardMethods(proto, methods) {
for (let i=0; i < methods.length; i++) {
let method = methods[i];
/* eslint-disable valid-jsdoc */
proto[method] = /** @this {DomApi} */ function() {
proto[method] = /** @this {DomApiNative} */ function() {
return this.node[method].apply(this.node, arguments);
};
/* eslint-enable */
@@ -221,7 +222,7 @@ function forwardReadOnlyProperties(proto, properties) {
let name = properties[i];
Object.defineProperty(proto, name, {
get: function() {
const domApi = /** @type {DomApi} */(this);
const domApi = /** @type {DomApiNative} */(this);
return domApi.node[name];
},
configurable: true
@@ -234,14 +235,14 @@ function forwardProperties(proto, properties) {
let name = properties[i];
Object.defineProperty(proto, name, {
/**
* @this {DomApi}
* @this {DomApiNative}
* @return {*} .
*/
get: function() {
return this.node[name];
},
/**
* @this {DomApi}
* @this {DomApiNative}
* @param {*} value .
*/
set: function(value) {
@@ -268,7 +269,7 @@ export class EventApi {
* @return {!EventTarget} The node this event was dispatched to
*/
get rootTarget() {
return this.event.composedPath()[0];
return this.path[0];
}
/**
@@ -294,105 +295,146 @@ export class EventApi {
* @param {boolean=} deep
* @return {!Node}
*/
DomApi.prototype.cloneNode;
DomApiNative.prototype.cloneNode;
/**
* @function
* @param {!Node} node
* @return {!Node}
*/
DomApi.prototype.appendChild;
DomApiNative.prototype.appendChild;
/**
* @function
* @param {!Node} newChild
* @param {Node} refChild
* @return {!Node}
*/
DomApi.prototype.insertBefore;
DomApiNative.prototype.insertBefore;
/**
* @function
* @param {!Node} node
* @return {!Node}
*/
DomApi.prototype.removeChild;
DomApiNative.prototype.removeChild;
/**
* @function
* @param {!Node} oldChild
* @param {!Node} newChild
* @return {!Node}
*/
DomApi.prototype.replaceChild;
DomApiNative.prototype.replaceChild;
/**
* @function
* @param {string} name
* @param {string} value
* @return {void}
*/
DomApi.prototype.setAttribute;
DomApiNative.prototype.setAttribute;
/**
* @function
* @param {string} name
* @return {void}
*/
DomApi.prototype.removeAttribute;
DomApiNative.prototype.removeAttribute;
/**
* @function
* @param {string} selector
* @return {?Element}
*/
DomApi.prototype.querySelector;
DomApiNative.prototype.querySelector;
/**
* @function
* @param {string} selector
* @return {!NodeList<!Element>}
*/
DomApi.prototype.querySelectorAll;
DomApiNative.prototype.querySelectorAll;
/** @type {?Node} */
DomApi.prototype.parentNode;
DomApiNative.prototype.parentNode;
/** @type {?Node} */
DomApi.prototype.firstChild;
DomApiNative.prototype.firstChild;
/** @type {?Node} */
DomApi.prototype.lastChild;
DomApiNative.prototype.lastChild;
/** @type {?Node} */
DomApi.prototype.nextSibling;
DomApiNative.prototype.nextSibling;
/** @type {?Node} */
DomApi.prototype.previousSibling;
DomApiNative.prototype.previousSibling;
/** @type {?HTMLElement} */
DomApi.prototype.firstElementChild;
DomApiNative.prototype.firstElementChild;
/** @type {?HTMLElement} */
DomApi.prototype.lastElementChild;
DomApiNative.prototype.lastElementChild;
/** @type {?HTMLElement} */
DomApi.prototype.nextElementSibling;
DomApiNative.prototype.nextElementSibling;
/** @type {?HTMLElement} */
DomApi.prototype.previousElementSibling;
DomApiNative.prototype.previousElementSibling;
/** @type {!Array<!Node>} */
DomApi.prototype.childNodes;
DomApiNative.prototype.childNodes;
/** @type {!Array<!HTMLElement>} */
DomApi.prototype.children;
DomApiNative.prototype.children;
/** @type {?DOMTokenList} */
DomApi.prototype.classList;
DomApiNative.prototype.classList;
/** @type {string} */
DomApi.prototype.textContent;
DomApiNative.prototype.textContent;
/** @type {string} */
DomApi.prototype.innerHTML;
DomApiNative.prototype.innerHTML;
forwardMethods(DomApi.prototype, [
'cloneNode', 'appendChild', 'insertBefore', 'removeChild',
'replaceChild', 'setAttribute', 'removeAttribute',
'querySelector', 'querySelectorAll'
]);
let DomApiImpl = DomApiNative;
forwardReadOnlyProperties(DomApi.prototype, [
'parentNode', 'firstChild', 'lastChild',
'nextSibling', 'previousSibling', 'firstElementChild',
'lastElementChild', 'nextElementSibling', 'previousElementSibling',
'childNodes', 'children', 'classList'
]);
if (window['ShadyDOM'] && window['ShadyDOM']['inUse'] && window['ShadyDOM']['noPatch'] && window['ShadyDOM']['Wrapper']) {
forwardProperties(DomApi.prototype, [
'textContent', 'innerHTML'
]);
/**
* @private
* @extends {HTMLElement}
*/
class Wrapper extends window['ShadyDOM']['Wrapper'] {}
// copy bespoke API onto wrapper
Object.getOwnPropertyNames(DomApiNative.prototype).forEach((prop) => {
if (prop != 'activeElement') {
Wrapper.prototype[prop] = DomApiNative.prototype[prop];
}
});
DomApiImpl = Wrapper;
Object.defineProperties(EventApi.prototype, {
localTarget: {
get() {
return this.event.currentTarget;
},
configurable: true
},
path: {
get() {
return window['ShadyDOM']['composedPath'](this.event);
},
configurable: true
}
});
} else {
forwardMethods(DomApiNative.prototype, [
'cloneNode', 'appendChild', 'insertBefore', 'removeChild',
'replaceChild', 'setAttribute', 'removeAttribute',
'querySelector', 'querySelectorAll'
]);
forwardReadOnlyProperties(DomApiNative.prototype, [
'parentNode', 'firstChild', 'lastChild',
'nextSibling', 'previousSibling', 'firstElementChild',
'lastElementChild', 'nextElementSibling', 'previousElementSibling',
'childNodes', 'children', 'classList'
]);
forwardProperties(DomApiNative.prototype, [
'textContent', 'innerHTML'
]);
}
export const DomApi = DomApiImpl;
/**
* Legacy DOM and Event manipulation API wrapper factory used to abstract
@@ -405,19 +447,25 @@ forwardProperties(DomApi.prototype, [
*
* @summary Legacy DOM and Event manipulation API wrapper factory used to
* abstract differences between native Shadow DOM and "Shady DOM."
* @param {(Node|Event)=} obj Node or event to operate on
* @return {!DomApi|!EventApi} Wrapper providing either node API or event API
* @param {(Node|Event|DomApiNative|EventApi)=} obj Node or event to operate on
* @return {!DomApiNative|!EventApi} Wrapper providing either node API or event API
*/
export const dom = function(obj) {
obj = obj || document;
if (!obj['__domApi']) {
let helper;
if (obj instanceof DomApiImpl) {
return /** @type {!DomApi} */(obj);
}
if (obj instanceof EventApi) {
return /** @type {!EventApi} */(obj);
}
let helper = obj['__domApi'];
if (!helper) {
if (obj instanceof Event) {
helper = new EventApi(obj);
} else {
helper = new DomApi(obj);
helper = new DomApiImpl(/** @type {Node} */(obj));
}
obj['__domApi'] = helper;
}
return obj['__domApi'];
return helper;
};

View File

@@ -1,13 +1,14 @@
/**
* @fileoverview
* @suppress {checkPrototypalTypes}
@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
*/
* @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
*/
import { PropertyAccessors } from './property-accessors.js';
import { dedupingMixin } from '../utils/mixin.js';

View File

@@ -1,13 +1,14 @@
/**
* @fileoverview
* @suppress {checkPrototypalTypes}
@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
*/
* @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
*/
import { ElementMixin } from './element-mixin.js';
import { dedupingMixin } from '../utils/mixin.js';

View File

@@ -1,22 +1,24 @@
/**
* @fileoverview
* @suppress {checkPrototypalTypes}
@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
*/
* @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
*/
import '../utils/boot.js';
import { rootPath, strictTemplatePolicy, allowTemplateFromDomModule, legacyOptimizations } from '../utils/settings.js';
import { rootPath, strictTemplatePolicy, allowTemplateFromDomModule, legacyOptimizations, syncInitialRender } from '../utils/settings.js';
import { dedupingMixin } from '../utils/mixin.js';
import { stylesFromTemplate, stylesFromModuleImports } from '../utils/style-gather.js';
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';
/**
* Current Polymer version in Semver notation.
@@ -324,7 +326,7 @@ export const ElementMixin = dedupingMixin(base => {
*/
class PolymerElement extends polymerElementBase {
/**
/**
* Current Polymer version in Semver notation.
* @type {string} Semver notation of the current version of Polymer.
*/
@@ -666,13 +668,17 @@ export const ElementMixin = dedupingMixin(base => {
* @return {ShadowRoot} node to which the dom has been attached.
*/
_attachDom(dom) {
if (this.attachShadow) {
const n = wrap(this);
if (n.attachShadow) {
if (dom) {
if (!this.shadowRoot) {
this.attachShadow({mode: 'open'});
if (!n.shadowRoot) {
n.attachShadow({mode: 'open'});
}
this.shadowRoot.appendChild(dom);
return this.shadowRoot;
n.shadowRoot.appendChild(dom);
if (syncInitialRender && window.ShadyDOM) {
ShadyDOM.flushInitial(n.shadowRoot);
}
return n.shadowRoot;
}
return null;
} else {
@@ -760,6 +766,7 @@ export const ElementMixin = dedupingMixin(base => {
* @param {Object=} effect Effect metadata object
* @return {void}
* @protected
* @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do
*/
static _addTemplatePropertyEffect(templateInfo, prop, effect) {
// Warn if properties are used in template without being declared.

View File

@@ -11,6 +11,7 @@ import '../utils/boot.js';
import { dedupingMixin } from '../utils/mixin.js';
import { microTask } from '../utils/async.js';
import { wrap } from '../utils/wrap.js';
/** @const {!AsyncInterface} */
const microtask = microTask;
@@ -496,6 +497,9 @@ export const PropertiesChanged = dedupingMixin(
if (str === undefined) {
node.removeAttribute(attribute);
} else {
if (attribute === 'class' || attribute === 'name' || attribute === 'slot') {
node = /** @type {?Element} */(wrap(node));
}
node.setAttribute(attribute, str);
}
}

View File

@@ -164,7 +164,7 @@ export const PropertyAccessors = dedupingMixin(superClass => {
* setter at instance time. This method is provided as an override
* point for customizing or providing more efficient initialization.
*
* @param {!Object} props Bag of property values that were overwritten
* @param {Object} props Bag of property values that were overwritten
* when creating property accessors.
* @return {void}
* @protected

View File

@@ -1,16 +1,17 @@
/**
* @fileoverview
* @suppress {checkPrototypalTypes}
@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
*/
* @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
*/
import '../utils/boot.js';
import { wrap } from '../utils/wrap.js';
import { dedupingMixin } from '../utils/mixin.js';
import { root, isAncestor, isDescendant, get, translate, isPath, set, normalize } from '../utils/path.js';
/* for notify, reflect */
@@ -300,7 +301,7 @@ function dispatchNotifyEvent(inst, eventName, value, path) {
if (path) {
detail.path = path;
}
/** @type {!HTMLElement} */(inst).dispatchEvent(new CustomEvent(eventName, { detail }));
wrap(/** @type {!HTMLElement} */(inst)).dispatchEvent(new CustomEvent(eventName, { detail }));
}
/**
@@ -1172,7 +1173,7 @@ export const PropertyEffects = dedupingMixin(superClass => {
* the prototype on the instance.
*
* @override
* @param {!Object} props Properties to initialize on the prototype
* @param {Object} props Properties to initialize on the prototype
* @return {void}
*/
_initializeProtoProperties(props) {

View File

@@ -11,6 +11,7 @@ import './boot.js';
import { calculateSplices } from './array-splice.js';
import { microTask } from './async.js';
import { wrap } from './wrap.js';
/**
* Returns true if `node` is a slot element
@@ -64,7 +65,7 @@ function isSlot(node) {
* "flattened nodes" on a given `node`.
* @implements {PolymerDomApi.ObserveHandle}
*/
export class FlattenedNodesObserver {
export let FlattenedNodesObserver = class {
/**
* Returns the list of flattened nodes for the given `node`.
@@ -80,15 +81,17 @@ export class FlattenedNodesObserver {
* @return {!Array<!Node>} The list of flattened nodes for the given `node`.
* @nocollapse See https://github.com/google/closure-compiler/issues/2763
*/
// eslint-disable-next-line
static getFlattenedNodes(node) {
const wrapped = wrap(node);
if (isSlot(node)) {
node = /** @type {!HTMLSlotElement} */(node); // eslint-disable-line no-self-assign
return node.assignedNodes({flatten: true});
return wrapped.assignedNodes({flatten: true});
} else {
return Array.from(node.childNodes).map((node) => {
return Array.from(wrapped.childNodes).map((node) => {
if (isSlot(node)) {
node = /** @type {!HTMLSlotElement} */(node); // eslint-disable-line no-self-assign
return node.assignedNodes({flatten: true});
return wrap(node).assignedNodes({flatten: true});
} else {
return [node];
}
@@ -101,6 +104,7 @@ export class FlattenedNodesObserver {
* @param {?function(this: Element, { target: !HTMLElement, addedNodes: !Array<!Element>, removedNodes: !Array<!Element> }):void} callback Function called when there are additions
* or removals from the target's list of flattened nodes.
*/
// eslint-disable-next-line
constructor(target, callback) {
/**
* @type {MutationObserver}
@@ -143,9 +147,9 @@ export class FlattenedNodesObserver {
connect() {
if (isSlot(this._target)) {
this._listenSlots([this._target]);
} else if (this._target.children) {
} else if (wrap(this._target).children) {
this._listenSlots(
/** @type {!NodeList<!Node>} */ (this._target.children));
/** @type {!NodeList<!Node>} */ (wrap(this._target).children));
if (window.ShadyDOM) {
this._shadyChildrenObserver =
ShadyDOM.observeChildren(this._target, (mutations) => {
@@ -174,9 +178,9 @@ export class FlattenedNodesObserver {
disconnect() {
if (isSlot(this._target)) {
this._unlistenSlots([this._target]);
} else if (this._target.children) {
} else if (wrap(this._target).children) {
this._unlistenSlots(
/** @type {!NodeList<!Node>} */ (this._target.children));
/** @type {!NodeList<!Node>} */ (wrap(this._target).children));
if (window.ShadyDOM && this._shadyChildrenObserver) {
ShadyDOM.unobserveChildren(this._shadyChildrenObserver);
this._shadyChildrenObserver = null;
@@ -307,4 +311,4 @@ export class FlattenedNodesObserver {
}
}
}
};

View File

@@ -26,6 +26,7 @@ import './boot.js';
import { timeOut, microTask } from './async.js';
import { Debouncer } from './debounce.js';
import { passiveTouchGestures } from './settings.js';
import { wrap } from './wrap.js';
// detect native touch action support
let HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
@@ -173,23 +174,21 @@ let mouseCanceller = function(mouseEvent) {
// disable "ghost clicks"
if (mouseEvent.type === 'click') {
let clickFromLabel = false;
let path = mouseEvent.composedPath && mouseEvent.composedPath();
if (path) {
for (let i = 0; i < path.length; i++) {
if (path[i].nodeType === Node.ELEMENT_NODE) {
if (path[i].localName === 'label') {
clickedLabels.push(path[i]);
} else if (canBeLabelled(path[i])) {
let ownerLabels = matchingLabels(path[i]);
// check if one of the clicked labels is labelling this element
for (let j = 0; j < ownerLabels.length; j++) {
clickFromLabel = clickFromLabel || clickedLabels.indexOf(ownerLabels[j]) > -1;
}
let path = getComposedPath(mouseEvent);
for (let i = 0; i < path.length; i++) {
if (path[i].nodeType === Node.ELEMENT_NODE) {
if (path[i].localName === 'label') {
clickedLabels.push(path[i]);
} else if (canBeLabelled(path[i])) {
let ownerLabels = matchingLabels(path[i]);
// check if one of the clicked labels is labelling this element
for (let j = 0; j < ownerLabels.length; j++) {
clickFromLabel = clickFromLabel || clickedLabels.indexOf(ownerLabels[j]) > -1;
}
}
if (path[i] === POINTERSTATE.mouse.target) {
return;
}
}
if (path[i] === POINTERSTATE.mouse.target) {
return;
}
}
// if one of the clicked labels was labelling the target element,
@@ -229,7 +228,7 @@ function ignoreMouse(e) {
POINTERSTATE.mouse.target = null;
POINTERSTATE.mouse.mouseIgnoreJob = null;
};
POINTERSTATE.mouse.target = e.composedPath()[0];
POINTERSTATE.mouse.target = getComposedPath(e)[0];
POINTERSTATE.mouse.mouseIgnoreJob = Debouncer.debounce(
POINTERSTATE.mouse.mouseIgnoreJob
, timeOut.after(MOUSE_TIMEOUT)
@@ -303,14 +302,12 @@ let POINTERSTATE = {
function firstTouchAction(ev) {
let ta = 'auto';
let path = ev.composedPath && ev.composedPath();
if (path) {
for (let i = 0, n; i < path.length; i++) {
n = path[i];
if (n[TOUCH_ACTION]) {
ta = n[TOUCH_ACTION];
break;
}
let path = getComposedPath(ev);
for (let i = 0, n; i < path.length; i++) {
n = path[i];
if (n[TOUCH_ACTION]) {
ta = n[TOUCH_ACTION];
break;
}
}
return ta;
@@ -334,6 +331,15 @@ function untrackDocument(stateObj) {
// Use passive event listeners, if supported, to not affect scrolling performance
document.addEventListener('touchend', ignoreMouse, SUPPORTS_PASSIVE ? {passive: true} : false);
/**
* Returns the composedPath for the given event.
* @param {Event} event to process
* @return {!Array<!EventTarget>} Path of the event
*/
const getComposedPath = window.ShadyDOM && window.ShadyDOM.noPatch ?
window.ShadyDOM.composedPath :
(event) => event.composedPath && event.composedPath() || [];
/** @type {!Object<string, !GestureRecognizer>} */
export const gestures = {};
@@ -380,14 +386,9 @@ export function deepTargetFind(x, y) {
* @return {EventTarget} Returns the event target.
*/
function _findOriginalTarget(ev) {
// shadowdom
if (ev.composedPath) {
const targets = /** @type {!Array<!EventTarget>} */(ev.composedPath());
// It shouldn't be, but sometimes targets is empty (window on Safari).
return targets.length > 0 ? targets[0] : ev.target;
}
// shadydom
return ev.target;
const path = getComposedPath(ev);
// It shouldn't be, but sometimes path is empty (window on Safari).
return path.length > 0 ? path[0] : ev.target;
}
/**
@@ -659,7 +660,7 @@ export function setTouchAction(node, value) {
function _fire(target, type, detail) {
let ev = new Event(type, { bubbles: true, cancelable: true, composed: true });
ev.detail = detail;
target.dispatchEvent(ev);
wrap(/** @type {!Node} */(target)).dispatchEvent(ev);
// forward `preventDefault` in a clean way
if (ev.defaultPrevented) {
let preventer = detail.preventer || detail.sourceEvent;

View File

@@ -140,3 +140,21 @@ export let legacyOptimizations = false;
export const setLegacyOptimizations = function(useLegacyOptimizations) {
legacyOptimizations = useLegacyOptimizations;
};
/**
* Setting to perform initial rendering synchronously when running under ShadyDOM.
* This matches the behavior of Polymer 1.
*/
export let syncInitialRender = false;
/**
* Sets `syncInitialRender` globally for all elements to enable synchronous
* initial rendering.
*
* @param {boolean} useSyncInitialRender enable or disable synchronous initial
* rendering globally.
* @return {void}
*/
export const setSyncInitialRender = function(useSyncInitialRender) {
syncInitialRender = useSyncInitialRender;
};

View File

@@ -29,7 +29,7 @@ export const registrations = [];
* @private
*/
function _regLog(prototype) {
console.log('[' + prototype.is + ']: registered');
console.log('[' + /** @type {?} */(prototype).is + ']: registered');
}
/**

View File

@@ -49,7 +49,8 @@ import './boot.js';
import { PropertyEffects } from '../mixins/property-effects.js';
import { MutableData } from '../mixins/mutable-data.js';
import { strictTemplatePolicy } from '../utils/settings.js';
import { strictTemplatePolicy } from './settings.js';
import { wrap } from './wrap.js';
// Base class for HTMLTemplateElement extension that has property effects
// machinery for propagating host properties to children. This is an ES5
@@ -116,6 +117,7 @@ class TemplateInstanceBase extends templateInstanceBase {
this.root = this._stampTemplate(this.__dataHost);
// Save list of stamped children
let children = this.children = [];
// Polymer 1.x did not use `Polymer.dom` here so not bothering.
for (let n = this.root.firstChild; n; n=n.nextSibling) {
children.push(n);
n.__templatizeInstance = this;
@@ -220,11 +222,11 @@ class TemplateInstanceBase extends templateInstanceBase {
} else if (n.localName === 'slot') {
if (hide) {
n.__polymerReplaced__ = document.createComment('hidden-slot');
n.parentNode.replaceChild(n.__polymerReplaced__, n);
wrap(wrap(n).parentNode).replaceChild(n.__polymerReplaced__, n);
} else {
const replace = n.__polymerReplaced__;
if (replace) {
replace.parentNode.replaceChild(n, replace);
wrap(wrap(replace).parentNode).replaceChild(n, replace);
}
}
}
@@ -338,7 +340,7 @@ function createTemplatizerClass(template, templateInfo, options) {
*/
let templatizerBase = options.mutableData ?
MutableTemplateInstanceBase : TemplateInstanceBase;
// Affordance for global mixins onto TemplatizeInstance
if (templatize.mixin) {
templatizerBase = templatize.mixin(templatizerBase);
@@ -599,7 +601,7 @@ export function modelForElement(template, node) {
} else {
// Still in a template scope, keep going up until
// a __templatizeInstance is found
node = node.parentNode;
node = wrap(node).parentNode;
}
}
return null;

23
lib/utils/wrap.js Normal file
View File

@@ -0,0 +1,23 @@
/**
@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
*/
/* eslint-disable valid-jsdoc */
/**
* Node wrapper to ensure ShadowDOM safe operation regardless of polyfill
* presence or mode. Note that with the introduction of `ShadyDOM.noPatch`,
* a node wrapper must be used to access ShadowDOM API.
* This is similar to using `Polymer.dom` but relies exclusively
* on the presence of the ShadyDOM polyfill rather than requiring the loading
* of legacy (Polymer.dom) API.
* @type {function(Node):Node}
*/
export const wrap = (window['ShadyDOM'] && window['ShadyDOM']['noPatch'] && window['ShadyDOM']['wrap']) ?
window['ShadyDOM']['wrap'] : (n) => n;

1307
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
"@polymer/gen-typescript-declarations": "^1.5.1",
"@polymer/iron-component-page": "^3.0.0-pre.12",
"@polymer/test-fixture": "^3.0.0-pre.12",
"@webcomponents/webcomponentsjs": "^2.2.6",
"@webcomponents/webcomponentsjs": "^2.2.7",
"babel-eslint": "^7.2.3",
"babel-preset-minify": "^0.2.0",
"del": "^3.0.0",

View File

@@ -37,6 +37,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
'unit/shady-events.html',
'unit/shady-content.html',
'unit/shady-dynamic.html',
'unit/shady-dynamic.html?syncInitialRender=true',
'unit/styling-scoped.html',
'unit/styling-cross-scope-var.html',
'unit/styling-cross-scope-apply.html',
@@ -70,6 +71,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
'unit/dom-bind.html',
'unit/array-selector.html',
'unit/polymer-dom.html',
'unit/polymer-dom-nopatch.html',
'unit/polymer-dom-observeNodes.html',
'unit/flattened-nodes-observer.html',
// TODO: substitute for equivalent es6 import tests

View File

@@ -0,0 +1,362 @@
<!doctype html>
<!--
@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>
<meta charset="utf-8">
<script>
ShadyDOM = {force: true, noPatch: true};
</script>
<script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
<script src="wct-browser-config.js"></script>
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
<script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>
<dom-module id="x-slot">
<template>
<div id="container"><slot id="slot"></slot></div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-slot'
});
</script>
</dom-module>
<dom-module id="x-container-slot">
<template>
<x-slot id="container"><div id="first">first</div><slot id="slot"></slot><div id="last">last</div></x-slot>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-container-slot'
});
</script>
</dom-module>
<dom-module id="x-event-scoped">
<template>
<div id="scoped"></div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-event-scoped',
fireComposed: function() {
return this.fire('composed', null, {node: this.$.scoped});
}
});
</script>
</dom-module>
<dom-module id="x-focusable-in-shadow">
<template>
<input id="focusable"></input>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-focusable-in-shadow'
});
</script>
</dom-module>
<test-fixture id="scoped">
<template>
<x-event-scoped></x-event-scoped>
</template>
</test-fixture>
<test-fixture id="slot">
<template>
<x-container-slot></x-container-slot>
</template>
</test-fixture>
<test-fixture id="focusableInShadow">
<template>
<x-focusable-in-shadow></x-focusable-in-shadow>
</template>
</test-fixture>
<script type="module">
import { dom } from '../../lib/legacy/polymer.dom.js';
import { useShadow, useNativeCustomElements, useNativeCSSProperties } from '../../lib/utils/settings.js';
suite('extended dom api', function() {
test('getEffectiveChildNodes', function() {
var el = fixture('slot');
var div = document.createElement('div');
dom(el).appendChild(div);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(dom(el).getEffectiveChildNodes(),
[div]);
assert.deepEqual(dom(el.$.container).getEffectiveChildNodes(),
[el.$.first, div, el.$.last]);
assert.deepEqual(dom(el.$.container.$.container).getEffectiveChildNodes(),
[el.$.first, div, el.$.last]);
});
test('queryDistributedElements', function() {
var el = fixture('slot');
var div = document.createElement('div');
dom(el).appendChild(div);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(dom(el).queryDistributedElements('foo'),
[]);
assert.deepEqual(dom(el).queryDistributedElements('div'),
[div]);
assert.deepEqual(dom(el.$.container).queryDistributedElements('#first'),
[el.$.first]);
assert.deepEqual(dom(el.$.container.$.container).queryDistributedElements('#last'),
[el.$.last]);
});
});
suite('distribution', function() {
test('getDistributedNodes', function() {
var el = fixture('slot');
var div = document.createElement('div');
dom(el).appendChild(div);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(dom(el.$.slot).getDistributedNodes(), [div]);
assert.deepEqual(dom(el.$.container.$.slot).getDistributedNodes(),
[el.$.first, div, el.$.last]);
});
test('getDestinationInsertionPoints', function() {
var el = fixture('slot');
var div = document.createElement('div');
dom(el).appendChild(div);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(dom(el.$.first).getDestinationInsertionPoints(),
[el.$.container.$.slot]);
assert.deepEqual(dom(div).getDestinationInsertionPoints(),
[el.$.slot, el.$.container.$.slot]);
});
});
suite('events', function() {
test('localTarget, rootTarget, path', function(done) {
// skip if noPatch is not available
if (!window.ShadyDOM.wrap) {
this.skip();
}
var el = fixture('scoped');
el.addEventListener('composed', function(e) {
assert.equal(dom(e).rootTarget, el.$.scoped);
assert.equal(dom(e).localTarget, el);
let nodes = [];
let p = el.$.scoped;
while (p) {
nodes.push(p);
p = dom(p).parentNode || ShadyDOM.wrap(p).host;
}
nodes.push(window);
const path = dom(e).path;
assert.deepEqual(path, nodes);
done();
});
ShadyDOM.flush();
el.fireComposed();
});
});
suite('activeElement getter', function() {
test('Retrieves `activeElement`', function() {
// skip if noPatch is not available
if (!window.ShadyDOM.wrap) {
this.skip();
}
var focusableInShadow = fixture('focusableInShadow');
ShadyDOM.wrap(focusableInShadow.$.focusable).focus();
var rootNode = ShadyDOM.wrap(focusableInShadow).getRootNode();
assert.equal(dom(rootNode).activeElement, focusableInShadow);
assert.equal(dom(dom(focusableInShadow).shadowRoot).activeElement, focusableInShadow.$.focusable);
});
});
suite('legacy api', function() {
test('getEffectiveChildNodes', function() {
var el = fixture('slot');
var div = document.createElement('div');
var t = document.createTextNode('yo');
dom(el).appendChild(div);
dom(el).appendChild(t);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(el.getEffectiveChildNodes(),
[div, t]);
assert.deepEqual(el.$.container.getEffectiveChildNodes(),
[el.$.first, div, t, el.$.last]);
});
test('getEffectiveChildren', function() {
var el = fixture('slot');
var div = document.createElement('div');
dom(el).appendChild(div);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(el.getEffectiveChildNodes(),
[div]);
assert.deepEqual(el.$.container.getEffectiveChildNodes(),
[el.$.first, div, el.$.last]);
});
test('getEffectiveTextContent', function() {
var el = fixture('slot');
var t1 = document.createTextNode('a');
var t2 = document.createTextNode('b');
dom(el).appendChild(t1);
dom(el).appendChild(t2);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(el.getEffectiveTextContent(), 'ab');
assert.deepEqual(el.$.container.getEffectiveTextContent(), 'firstablast');
});
test('getContentChildNodes', function() {
var el = fixture('slot');
var div1 = document.createElement('div');
var t = document.createTextNode('');
var div2 = document.createElement('div');
dom(el).appendChild(div1);
dom(el).appendChild(t);
dom(el).appendChild(div2);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(el.getContentChildNodes(),
[div1, t, div2]);
assert.deepEqual(el.getContentChildNodes('slot'),
[div1, t, div2]);
});
test('getContentChildren', function() {
var el = fixture('slot');
var div1 = document.createElement('div');
var t = document.createTextNode('');
var div2 = document.createElement('div');
dom(el).appendChild(div1);
dom(el).appendChild(t);
dom(el).appendChild(div2);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(el.getContentChildren(),
[div1, div2]);
assert.deepEqual(el.getContentChildren('slot'),
[div1, div2]);
});
test('queryDistributedElements', function() {
var el = fixture('slot');
var div = document.createElement('div');
dom(el).appendChild(div);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(el.queryDistributedElements('foo'),
[]);
assert.deepEqual(el.queryDistributedElements('div'),
[div]);
assert.deepEqual(el.$.container.queryDistributedElements('#first'),
[el.$.first]);
});
test('queryEffectiveChildren', function() {
var el = fixture('slot');
var div = document.createElement('div');
dom(el).appendChild(div);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.equal(el.queryEffectiveChildren('foo'),
null);
assert.deepEqual(el.queryEffectiveChildren('div'),
div);
assert.deepEqual(el.$.container.queryEffectiveChildren('#first'),
el.$.first);
});
test('queryAllEffectiveChildren', function() {
var el = fixture('slot');
var div1 = document.createElement('div');
var div2 = document.createElement('div');
dom(el).appendChild(div1);
dom(el).appendChild(div2);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.deepEqual(el.queryAllEffectiveChildren('foo'),
[]);
assert.deepEqual(el.queryAllEffectiveChildren('div'),
[div1, div2]);
assert.deepEqual(el.$.container.queryAllEffectiveChildren('div'),
[el.$.first, div1, div2, el.$.last]);
});
test('isLightDescendant', function() {
var el = fixture('slot');
var div1 = document.createElement('div');
dom(el).appendChild(div1);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.equal(el.isLightDescendant(div1), true);
assert.equal(el.isLightDescendant(el.$.container), false);
});
test('isLocalDescendant', function() {
var el = fixture('slot');
var div1 = document.createElement('div');
dom(el).appendChild(div1);
if (window.ShadyDOM) {
ShadyDOM.flush();
}
assert.equal(el.isLocalDescendant(div1), false);
assert.equal(el.isLocalDescendant(el.$.container), true);
});
test('domHost', function() {
var el = fixture('slot');
assert.equal(el.domHost, document);
assert.equal(el.$.container.domHost, el);
});
test('legacy settings', function() {
assert.equal(useShadow, !(window.ShadyDOM));
assert.equal(useNativeCustomElements, !(window.customElements.polyfillWrapFlushCallback));
assert.equal(useNativeCSSProperties, Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss));
});
});
</script>
</body>
</html>

View File

@@ -22,14 +22,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
<script src="wct-browser-config.js"></script>
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
<script type="module">
import {setSyncInitialRender} from '../../lib/utils/settings.js';
window.syncInitialRender = Boolean(window.location.search.match('syncInitialRender'));
setSyncInitialRender(window.syncInitialRender);
</script>
<script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>
<dom-module id="x-project">
<template>
x-project: [<slot></slot>]
</template>
<template strip-whitespace>x-project: [<slot></slot>]</template>
</dom-module>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
@@ -39,7 +42,7 @@ Polymer({
</script>
<dom-module id="x-reproject">
<template>
<template strip-whitespace>
<x-project>x-reproject: [<slot></slot>]</x-project>
</template>
</dom-module>
@@ -51,7 +54,7 @@ Polymer({
</script>
<dom-module id='x-rereproject'>
<template>
<template strip-whitespace>
<x-reproject>x-rereproject: [<slot></slot>]</x-reproject>
</template>
</dom-module>
@@ -67,7 +70,7 @@ Polymer({
</script>
<dom-module id="x-test">
<template>
<template strip-whitespace>
<x-rereproject><span id="projected">projected</span></x-rereproject>
</template>
</dom-module>
@@ -1328,6 +1331,22 @@ test('event.composedPath correctly calculated for elements with destination inse
document.body.removeChild(re);
});
test('initial distribution is synchronous when `syncInitialRender` is true', function() {
if (!window.syncInitialRender) {
this.skip();
}
const el = document.createElement('x-test');
document.body.appendChild(el);
let child = ShadyDOM.nativeTree.firstElementChild(el);
assert.equal(child.localName, 'x-rereproject');
child = ShadyDOM.nativeTree.firstElementChild(child);
assert.equal(child.localName, 'x-reproject');
child = ShadyDOM.nativeTree.firstElementChild(child);
assert.equal(child.localName, 'x-project');
assert.equal(ShadyDOM.nativeTree.textContent(child), 'x-project: [x-reproject: [x-rereproject: [projected]]]');
document.body.removeChild(el);
});
});
suite('Accessors', function() {