Skip to content

Commit

Permalink
Merge branch 'master' into shadydom-upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven Orvell committed Apr 10, 2019
2 parents 1aeaa80 + b7c73bd commit 707a376
Show file tree
Hide file tree
Showing 17 changed files with 489 additions and 72 deletions.
1 change: 0 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Beyond GitHub, we try to have a variety of different lines of communication open

* [Blog](https://blog.polymer-project.org/)
* [Twitter](https://twitter.com/polymer)
* [Google+ Community](https://plus.sandbox.google.com/u/0/communities/115626364525706131031?cfem=1)
* [Mailing list](https://groups.google.com/forum/#!forum/polymer-dev)
* [Slack channel](https://bit.ly/polymerslack)

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ Beyond GitHub, we try to have a variety of different lines of communication avai

* [Blog](https://blog.polymer-project.org/)
* [Twitter](https://twitter.com/polymer)
* [Google+ community](https://plus.google.com/communities/115626364525706131031)
* [Mailing list](https://groups.google.com/forum/#!forum/polymer-dev)
* [Slack channel](https://bit.ly/polymerslack)

Expand Down
28 changes: 17 additions & 11 deletions lib/elements/array-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => {

__updateSelection(multi, itemsInfo) {
let path = itemsInfo.path;
if (path == 'items') {
if (path == JSCompiler_renameProperty('items', this)) {
// Case 1 - items array changed, so diff against previous array and
// deselect any removed items and adjust selected indices
let newItems = itemsInfo.base || [];
Expand All @@ -122,14 +122,14 @@ let ArraySelectorMixin = dedupingMixin(superClass => {
}
this.__lastItems = newItems;
this.__lastMulti = multi;
} else if (itemsInfo.path == 'items.splices') {
} else if (itemsInfo.path == `${JSCompiler_renameProperty('items', this)}.splices`) {
// Case 2 - got specific splice information describing the array mutation:
// deselect any removed items and adjust selected indices
this.__applySplices(itemsInfo.value.indexSplices);
} else {
// Case 3 - an array element was changed, so deselect the previous
// item for that index if it was previously selected
let part = path.slice('items.'.length);
let part = path.slice(`${JSCompiler_renameProperty('items', this)}.`.length);
let idx = parseInt(part, 10);
if ((part.indexOf('.') < 0) && part == idx) {
this.__deselectChangedIdx(idx);
Expand Down Expand Up @@ -167,7 +167,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => {
selected.forEach((idx, item) => {
if (idx < 0) {
if (this.multi) {
this.splice('selected', sidx, 1);
this.splice(JSCompiler_renameProperty('selected', this), sidx, 1);
} else {
this.selected = this.selectedItem = null;
}
Expand All @@ -184,13 +184,19 @@ let ArraySelectorMixin = dedupingMixin(superClass => {
let sidx = 0;
this.__selectedMap.forEach(idx => {
if (idx >= 0) {
this.linkPaths('items.' + idx, 'selected.' + sidx++);
this.linkPaths(
`${JSCompiler_renameProperty('items', this)}.${idx}`,
`${JSCompiler_renameProperty('selected', this)}.${sidx++}`);
}
});
} else {
this.__selectedMap.forEach(idx => {
this.linkPaths('selected', 'items.' + idx);
this.linkPaths('selectedItem', 'items.' + idx);
this.linkPaths(
JSCompiler_renameProperty('selected', this),
`${JSCompiler_renameProperty('items', this)}.${idx}`);
this.linkPaths(
JSCompiler_renameProperty('selectedItem', this),
`${JSCompiler_renameProperty('items', this)}.${idx}`);
});
}
}
Expand Down Expand Up @@ -248,9 +254,9 @@ let ArraySelectorMixin = dedupingMixin(superClass => {
}

__selectedIndexForItemIndex(idx) {
let selected = this.__dataLinkedPaths['items.' + idx];
let selected = this.__dataLinkedPaths[`${JSCompiler_renameProperty('items', this)}.${idx}`];
if (selected) {
return parseInt(selected.slice('selected.'.length), 10);
return parseInt(selected.slice(`${JSCompiler_renameProperty('selected', this)}.`.length), 10);
}
}

Expand All @@ -271,7 +277,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => {
}
this.__updateLinks();
if (this.multi) {
this.splice('selected', sidx, 1);
this.splice(JSCompiler_renameProperty('selected', this), sidx, 1);
} else {
this.selected = this.selectedItem = null;
}
Expand Down Expand Up @@ -318,7 +324,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => {
this.__selectedMap.set(item, idx);
this.__updateLinks();
if (this.multi) {
this.push('selected', item);
this.push(JSCompiler_renameProperty('selected', this), item);
} else {
this.selected = this.selectedItem = item;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/elements/dom-repeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ export class DomRepeat extends domRepeatBase {
if (prop == this.as) {
this.items[idx] = value;
}
let path = translate(this.as, 'items.' + idx, prop);
let path = translate(this.as, `${JSCompiler_renameProperty('items', this)}.${idx}`, prop);
this.notifyPath(path, value);
}
}
Expand Down
24 changes: 22 additions & 2 deletions lib/legacy/class.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,26 @@ function flattenBehaviors(behaviors, list, exclude) {
return list;
}

/**
* Copies property descriptors from source to target, overwriting all fields
* of any previous descriptor for a property *except* for `value`, which is
* merged in from the target if it does not exist on the source.
*
* @param {*} target Target properties object
* @param {*} source Source properties object
*/
function mergeProperties(target, source) {
for (const p in source) {
const targetInfo = target[p];
const sourceInfo = source[p];
if (!('value' in sourceInfo) && targetInfo && ('value' in targetInfo)) {
target[p] = Object.assign({value: targetInfo.value}, sourceInfo);
} else {
target[p] = sourceInfo;
}
}
}

/* Note about construction and extension of legacy classes.
[Changed in Q4 2018 to optimize performance.]
Expand Down Expand Up @@ -227,10 +247,10 @@ function GenerateClassFromInfo(info, Base, behaviors) {
const properties = {};
if (behaviorList) {
for (let i=0; i < behaviorList.length; i++) {
Object.assign(properties, behaviorList[i].properties);
mergeProperties(properties, behaviorList[i].properties);
}
}
Object.assign(properties, info.properties);
mergeProperties(properties, info.properties);
return properties;
}

Expand Down
11 changes: 11 additions & 0 deletions lib/legacy/polymer.dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,12 @@ if (window['ShadyDOM'] && window['ShadyDOM']['inUse'] && window['ShadyDOM']['noP
}
});

// Note, `classList` is here only for legacy compatibility since it does not
// trigger distribution in v1 Shadow DOM.
forwardReadOnlyProperties(Wrapper.prototype, [
'classList'
]);

DomApiImpl = Wrapper;

Object.defineProperties(EventApi.prototype, {
Expand All @@ -416,12 +422,17 @@ if (window['ShadyDOM'] && window['ShadyDOM']['inUse'] && window['ShadyDOM']['noP

} else {

// Methods that can provoke distribution or must return the logical, not
// composed tree.
forwardMethods(DomApiNative.prototype, [
'cloneNode', 'appendChild', 'insertBefore', 'removeChild',
'replaceChild', 'setAttribute', 'removeAttribute',
'querySelector', 'querySelectorAll'
]);

// Properties that should return the logical, not composed tree. Note, `classList`
// is here only for legacy compatibility since it does not trigger distribution
// in v1 Shadow DOM.
forwardReadOnlyProperties(DomApiNative.prototype, [
'parentNode', 'firstChild', 'lastChild',
'nextSibling', 'previousSibling', 'firstElementChild',
Expand Down
2 changes: 1 addition & 1 deletion lib/mixins/element-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { wrap } from '../utils/wrap.js';
* Current Polymer version in Semver notation.
* @type {string} Semver notation of the current version of Polymer.
*/
export const version = '3.0.5';
export const version = '3.2.0';

const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];

Expand Down
20 changes: 6 additions & 14 deletions lib/mixins/template-stamp.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import '../utils/boot.js';

import { dedupingMixin } from '../utils/mixin.js';

const walker = document.createTreeWalker(document, NodeFilter.SHOW_ALL,
null, false);

// 1.x backwards-compatible auto-wrapper for template type extensions
// This is a clear layering violation and gives favored-nation status to
// dom-if and dom-repeat templates. This is a conceit we're choosing to keep
Expand Down Expand Up @@ -48,8 +45,7 @@ function findTemplateNode(root, nodeInfo) {
if (parent) {
// note: marginally faster than indexing via childNodes
// (http://jsperf.com/childnodes-lookup)
walker.currentNode = parent;
for (let n=walker.firstChild(), i=0; n; n=walker.nextSibling()) {
for (let n=parent.firstChild, i=0; n; n=n.nextSibling) {
if (nodeInfo.parentIndex === i++) {
return n;
}
Expand Down Expand Up @@ -238,8 +234,7 @@ export const TemplateStamp = dedupingMixin(
// For ShadyDom optimization, indicating there is an insertion point
templateInfo.hasInsertionPoint = true;
}
walker.currentNode = element;
if (walker.firstChild()) {
if (element.firstChild) {
noted = this._parseTemplateChildNodes(element, templateInfo, nodeInfo) || noted;
}
if (element.hasAttributes && element.hasAttributes()) {
Expand All @@ -265,8 +260,7 @@ export const TemplateStamp = dedupingMixin(
if (root.localName === 'script' || root.localName === 'style') {
return;
}
walker.currentNode = root;
for (let node=walker.firstChild(), parentIndex=0, next; node; node=next) {
for (let node=root.firstChild, parentIndex=0, next; node; node=next) {
// Wrap templates
if (node.localName == 'template') {
node = wrapTemplateExtension(node);
Expand All @@ -275,13 +269,12 @@ export const TemplateStamp = dedupingMixin(
// text nodes to be inexplicably split =(
// note that root.normalize() should work but does not so we do this
// manually.
walker.currentNode = node;
next = walker.nextSibling();
next = node.nextSibling;
if (node.nodeType === Node.TEXT_NODE) {
let /** Node */ n = next;
while (n && (n.nodeType === Node.TEXT_NODE)) {
node.textContent += n.textContent;
next = walker.nextSibling();
next = n.nextSibling;
root.removeChild(n);
n = next;
}
Expand All @@ -296,8 +289,7 @@ export const TemplateStamp = dedupingMixin(
childInfo.infoIndex = templateInfo.nodeInfoList.push(/** @type {!NodeInfo} */(childInfo)) - 1;
}
// Increment if not removed
walker.currentNode = node;
if (walker.parentNode()) {
if (node.parentNode) {
parentIndex++;
}
}
Expand Down
53 changes: 52 additions & 1 deletion lib/utils/debounce.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class Debouncer {
this._callback = callback;
this._timer = this._asyncModule.run(() => {
this._timer = null;
debouncerQueue.delete(this);
this._callback();
});
}
Expand All @@ -44,6 +45,21 @@ export class Debouncer {
* @return {void}
*/
cancel() {
if (this.isActive()) {
this._cancelAsync();
// Canceling a debouncer removes its spot from the flush queue,
// so if a debouncer is manually canceled and re-debounced, it
// will reset its flush order (this is a very minor difference from 1.x)
// Re-debouncing via the `debounce` API retains the 1.x FIFO flush order
debouncerQueue.delete(this);
}
}
/**
* Cancels a debouncer's async callback.
*
* @return {void}
*/
_cancelAsync() {
if (this.isActive()) {
this._asyncModule.cancel(/** @type {number} */(this._timer));
this._timer = null;
Expand Down Expand Up @@ -104,11 +120,46 @@ export class Debouncer {
*/
static debounce(debouncer, asyncModule, callback) {
if (debouncer instanceof Debouncer) {
debouncer.cancel();
// Cancel the async callback, but leave in debouncerQueue if it was
// enqueued, to maintain 1.x flush order
debouncer._cancelAsync();
} else {
debouncer = new Debouncer();
}
debouncer.setConfig(asyncModule, callback);
return debouncer;
}
}

let debouncerQueue = new Set();

/**
* Adds a `Debouncer` to a list of globally flushable tasks.
*
* @param {!Debouncer} debouncer Debouncer to enqueue
* @return {void}
*/
export const enqueueDebouncer = function(debouncer) {
debouncerQueue.add(debouncer);
};

/**
* Flushes any enqueued debouncers
*
* @return {boolean} Returns whether any debouncers were flushed
*/
export const flushDebouncers = function() {
const didFlush = Boolean(debouncerQueue.size);
// If new debouncers are added while flushing, Set.forEach will ensure
// newly added ones are also flushed
debouncerQueue.forEach(debouncer => {
try {
debouncer.flush();
} catch(e) {
setTimeout(() => {
throw e;
});
}
});
return didFlush;
};
28 changes: 2 additions & 26 deletions lib/utils/flush.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,8 @@ import './boot.js';
/* eslint-disable no-unused-vars */
import { Debouncer } from '../utils/debounce.js'; // used in type annotations
/* eslint-enable no-unused-vars */

let debouncerQueue = [];

/**
* Adds a `Debouncer` to a list of globally flushable tasks.
*
* @param {!Debouncer} debouncer Debouncer to enqueue
* @return {void}
*/
export const enqueueDebouncer = function(debouncer) {
debouncerQueue.push(debouncer);
};

function flushDebouncers() {
const didFlush = Boolean(debouncerQueue.length);
while (debouncerQueue.length) {
try {
debouncerQueue.shift().flush();
} catch(e) {
setTimeout(() => {
throw e;
});
}
}
return didFlush;
}
import { flushDebouncers } from '../utils/debounce.js'; // used in type annotations
export { enqueueDebouncer } from '../utils/debounce.js'; // used in type annotations

/**
* Forces several classes of asynchronously queued tasks to flush:
Expand Down
9 changes: 5 additions & 4 deletions lib/utils/gestures.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,10 @@ let mouseCanceller = function(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]);
clickedLabels.push(/** @type {!HTMLLabelElement} */ (path[i]));
} else if (canBeLabelled(/** @type {!HTMLElement} */ (path[i]))) {
let ownerLabels =
matchingLabels(/** @type {!HTMLElement} */ (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;
Expand Down Expand Up @@ -386,7 +387,7 @@ export function deepTargetFind(x, y) {
* @return {EventTarget} Returns the event target.
*/
function _findOriginalTarget(ev) {
const path = getComposedPath(ev);
const path = getComposedPath(/** @type {?Event} */ (ev));
// It shouldn't be, but sometimes path is empty (window on Safari).
return path.length > 0 ? path[0] : ev.target;
}
Expand Down
Loading

0 comments on commit 707a376

Please sign in to comment.