Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(613)

Unified Diff: pkg/web_components/lib/platform.concat.js

Issue 221653004: "Reverting 34633" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/web_components/lib/platform.concat.js
diff --git a/pkg/web_components/lib/platform.concat.js b/pkg/web_components/lib/platform.concat.js
index 9fa19b5c3d0c77a98d5e5a12c59c39c79628b508..6fa2b7b4f1830554045bbb76fead092f966584bc 100644
--- a/pkg/web_components/lib/platform.concat.js
+++ b/pkg/web_components/lib/platform.concat.js
@@ -52,6 +52,12 @@ if (typeof WeakMap === 'undefined') {
(function(global) {
'use strict';
+ var PROP_ADD_TYPE = 'add';
+ var PROP_UPDATE_TYPE = 'update';
+ var PROP_RECONFIGURE_TYPE = 'reconfigure';
+ var PROP_DELETE_TYPE = 'delete';
+ var ARRAY_SPLICE_TYPE = 'splice';
+
// Detect and do basic sanity checking on Object/Array.observe.
function detectObjectObserve() {
if (typeof Object.observe !== 'function' ||
@@ -66,29 +72,44 @@ if (typeof WeakMap === 'undefined') {
}
var test = {};
- var arr = [];
Object.observe(test, callback);
- Array.observe(arr, callback);
test.id = 1;
test.id = 2;
delete test.id;
- arr.push(1, 2);
- arr.length = 0;
-
Object.deliverChangeRecords(callback);
- if (records.length !== 5)
+ if (records.length !== 3)
return false;
- if (records[0].type != 'add' ||
- records[1].type != 'update' ||
- records[2].type != 'delete' ||
- records[3].type != 'splice' ||
- records[4].type != 'splice') {
+ // TODO(rafaelw): Remove this when new change record type names make it to
+ // chrome release.
+ if (records[0].type == 'new' &&
+ records[1].type == 'updated' &&
+ records[2].type == 'deleted') {
+ PROP_ADD_TYPE = 'new';
+ PROP_UPDATE_TYPE = 'updated';
+ PROP_RECONFIGURE_TYPE = 'reconfigured';
+ PROP_DELETE_TYPE = 'deleted';
+ } else if (records[0].type != 'add' ||
+ records[1].type != 'update' ||
+ records[2].type != 'delete') {
+ console.error('Unexpected change record names for Object.observe. ' +
+ 'Using dirty-checking instead');
return false;
}
-
Object.unobserve(test, callback);
- Array.unobserve(arr, callback);
+
+ test = [0];
+ Array.observe(test, callback);
+ test[1] = 1;
+ test.length = 0;
+ Object.deliverChangeRecords(callback);
+ if (records.length != 2)
+ return false;
+ if (records[0].type != ARRAY_SPLICE_TYPE ||
+ records[1].type != ARRAY_SPLICE_TYPE) {
+ return false;
+ }
+ Array.unobserve(test, callback);
return true;
}
@@ -247,7 +268,7 @@ if (typeof WeakMap === 'undefined') {
for (var i = 0; i < this.length; i++) {
if (i)
obj = obj[this[i - 1]];
- if (!isObject(obj))
+ if (!obj)
return;
observe(obj);
}
@@ -457,7 +478,7 @@ if (typeof WeakMap === 'undefined') {
var resetScheduled = false;
function observe(obj) {
- if (!obj)
+ if (!isObject(obj))
return;
var index = toRemove.indexOf(obj);
@@ -658,14 +679,7 @@ if (typeof WeakMap === 'undefined') {
var runningMicrotaskCheckpoint = false;
- var hasDebugForceFullDelivery = hasObserve && (function() {
- try {
- eval('%RunMicrotasks()');
- return true;
- } catch (ex) {
- return false;
- }
- })();
+ var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'function';
global.Platform = global.Platform || {};
@@ -674,7 +688,7 @@ if (typeof WeakMap === 'undefined') {
return;
if (hasDebugForceFullDelivery) {
- eval('%RunMicrotasks()');
+ Object.deliverAllChangeRecords();
return;
}
@@ -1104,11 +1118,10 @@ if (typeof WeakMap === 'undefined') {
}
}
- var expectedRecordTypes = {
- add: true,
- update: true,
- delete: true
- };
+ var expectedRecordTypes = {};
+ expectedRecordTypes[PROP_ADD_TYPE] = true;
+ expectedRecordTypes[PROP_UPDATE_TYPE] = true;
+ expectedRecordTypes[PROP_DELETE_TYPE] = true;
function notifyFunction(object, name) {
if (typeof Object.observe !== 'function')
@@ -1132,7 +1145,7 @@ if (typeof WeakMap === 'undefined') {
var value = observable.open(function(newValue, oldValue) {
value = newValue;
if (notify)
- notify('update', oldValue);
+ notify(PROP_UPDATE_TYPE, oldValue);
});
Object.defineProperty(target, name, {
@@ -1174,10 +1187,10 @@ if (typeof WeakMap === 'undefined') {
if (!(record.name in oldValues))
oldValues[record.name] = record.oldValue;
- if (record.type == 'update')
+ if (record.type == PROP_UPDATE_TYPE)
continue;
- if (record.type == 'add') {
+ if (record.type == PROP_ADD_TYPE) {
if (record.name in removed)
delete removed[record.name];
else
@@ -1574,12 +1587,12 @@ if (typeof WeakMap === 'undefined') {
for (var i = 0; i < changeRecords.length; i++) {
var record = changeRecords[i];
switch(record.type) {
- case 'splice':
+ case ARRAY_SPLICE_TYPE:
mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
break;
- case 'add':
- case 'update':
- case 'delete':
+ case PROP_ADD_TYPE:
+ case PROP_UPDATE_TYPE:
+ case PROP_DELETE_TYPE:
if (!isIndex(record.name))
continue;
var index = toNumber(record.name);
@@ -1628,6 +1641,16 @@ if (typeof WeakMap === 'undefined') {
global.CompoundObserver = CompoundObserver;
global.Path = Path;
global.ObserverTransform = ObserverTransform;
+
+ // TODO(rafaelw): Only needed for testing until new change record names
+ // make it to release.
+ global.Observer.changeRecordTypes = {
+ add: PROP_ADD_TYPE,
+ update: PROP_UPDATE_TYPE,
+ reconfigure: PROP_RECONFIGURE_TYPE,
+ 'delete': PROP_DELETE_TYPE,
+ splice: ARRAY_SPLICE_TYPE
+ };
})(typeof global !== 'undefined' && global && typeof module !== 'undefined' && module ? global : this || window);
// prepoulate window.Platform.flags for default controls
@@ -1643,8 +1666,7 @@ window.logFlags = window.logFlags || {};
o = o.split('=');
o[0] && (flags[o[0]] = o[1] || true);
});
- var entryPoint = document.currentScript ||
- document.querySelector('script[src*="platform.js"]');
+ var entryPoint = document.currentScript || document.querySelector('script[src*="platform.js"]');
if (entryPoint) {
var a = entryPoint.attributes;
for (var i = 0, n; i < a.length; i++) {
@@ -1662,19 +1684,13 @@ window.logFlags = window.logFlags || {};
// If any of these flags match 'native', then force native ShadowDOM; any
// other truthy value, or failure to detect native
// ShadowDOM, results in polyfill
- flags.shadow = flags.shadow || flags.shadowdom || flags.polyfill;
+ flags.shadow = (flags.shadow || flags.shadowdom || flags.polyfill);
if (flags.shadow === 'native') {
flags.shadow = false;
} else {
flags.shadow = flags.shadow || !HTMLElement.prototype.createShadowRoot;
}
- if (flags.shadow && document.querySelectorAll('script').length > 1) {
- console.warn('platform.js is not the first script on the page. ' +
- 'See http://www.polymer-project.org/docs/start/platform.html#setup ' +
- 'for details.');
- }
-
// CustomElements polyfill flag
if (flags.register) {
window.CustomElements = window.CustomElements || {flags: {}};
@@ -2554,9 +2570,6 @@ window.ShadowDOMPolyfill = {};
function setTreeScope(node, treeScope) {
if (node.treeScope_ !== treeScope) {
node.treeScope_ = treeScope;
- for (var sr = node.shadowRoot; sr; sr = sr.olderShadowRoot) {
- sr.treeScope_.parent = treeScope;
- }
for (var child = node.firstChild; child; child = child.nextSibling) {
setTreeScope(child, treeScope);
}
@@ -2753,17 +2766,8 @@ window.ShadowDOMPolyfill = {};
if (handledEventsTable.get(originalEvent))
return;
handledEventsTable.set(originalEvent, true);
- dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
- }
- function isLoadLikeEvent(event) {
- switch (event.type) {
- case 'beforeunload':
- case 'load':
- case 'unload':
- return true;
- }
- return false;
+ return dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
}
function dispatchEvent(event, originalWrapperTarget) {
@@ -2775,15 +2779,15 @@ window.ShadowDOMPolyfill = {};
scope.renderAllPending();
var eventPath = retarget(originalWrapperTarget);
- // For window "load" events the "load" event is dispatched at the window but
+ // For window load events the load event is dispatched at the window but
// the target is set to the document.
//
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end
//
// TODO(arv): Find a less hacky way to do this.
- if (eventPath.length === 2 &&
- eventPath[0].target instanceof wrappers.Document &&
- isLoadLikeEvent(event)) {
+ if (event.type === 'load' &&
+ eventPath.length === 2 &&
+ eventPath[0].target instanceof wrappers.Document) {
eventPath.shift();
}
@@ -2853,26 +2857,17 @@ window.ShadowDOMPolyfill = {};
if ('relatedTarget' in event) {
var originalEvent = unwrap(event);
- var unwrappedRelatedTarget = originalEvent.relatedTarget;
-
// X-Tag sets relatedTarget on a CustomEvent. If they do that there is no
// way to have relatedTarget return the adjusted target but worse is that
// the originalEvent might not have a relatedTarget so we hit an assert
// when we try to wrap it.
- if (unwrappedRelatedTarget) {
- // In IE we can get objects that are not EventTargets at this point.
- // Safari does not have an EventTarget interface so revert to checking
- // for addEventListener as an approximation.
- if (unwrappedRelatedTarget instanceof Object &&
- unwrappedRelatedTarget.addEventListener) {
- var relatedTarget = wrap(unwrappedRelatedTarget);
-
- var adjusted = adjustRelatedTarget(currentTarget, relatedTarget);
- if (adjusted === target)
- return true;
- } else {
- adjusted = null;
- }
+ if (originalEvent.relatedTarget) {
+ var relatedTarget = wrap(originalEvent.relatedTarget);
+
+ var adjusted = adjustRelatedTarget(currentTarget, relatedTarget);
+ if (adjusted === target)
+ return true;
+
relatedTargetTable.set(event, adjusted);
}
}
@@ -2959,14 +2954,10 @@ window.ShadowDOMPolyfill = {};
* @constructor
*/
function Event(type, options) {
- if (type instanceof OriginalEvent) {
- var impl = type;
- if (!OriginalBeforeUnloadEvent && impl.type === 'beforeunload')
- return new BeforeUnloadEvent(impl);
- this.impl = impl;
- } else {
+ if (type instanceof OriginalEvent)
+ this.impl = type;
+ else
return wrap(constructEvent(OriginalEvent, 'Event', type, options));
- }
}
Event.prototype = {
get target() {
@@ -3049,11 +3040,7 @@ window.ShadowDOMPolyfill = {};
var relatedTargetProto = {
get relatedTarget() {
- var relatedTarget = relatedTargetTable.get(this);
- // relatedTarget can be null.
- if (relatedTarget !== undefined)
- return relatedTarget;
- return wrap(unwrap(this).relatedTarget);
+ return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget);
}
};
@@ -3142,12 +3129,8 @@ window.ShadowDOMPolyfill = {};
configureEventConstructor('FocusEvent', {relatedTarget: null}, 'UIEvent');
}
- // Safari 7 does not yet have BeforeUnloadEvent.
- // https://bugs.webkit.org/show_bug.cgi?id=120849
- var OriginalBeforeUnloadEvent = window.BeforeUnloadEvent;
-
function BeforeUnloadEvent(impl) {
- Event.call(this, impl);
+ Event.call(this);
}
BeforeUnloadEvent.prototype = Object.create(Event.prototype);
mixin(BeforeUnloadEvent.prototype, {
@@ -3159,9 +3142,6 @@ window.ShadowDOMPolyfill = {};
}
});
- if (OriginalBeforeUnloadEvent)
- registerWrapper(OriginalBeforeUnloadEvent, BeforeUnloadEvent);
-
function isValidListener(fun) {
if (typeof fun === 'function')
return true;
@@ -3490,7 +3470,6 @@ window.ShadowDOMPolyfill = {};
var registerWrapper = scope.registerWrapper;
var setTreeScope = scope.setTreeScope;
var unwrap = scope.unwrap;
- var unwrapIfNeeded = scope.unwrapIfNeeded;
var wrap = scope.wrap;
var wrapIfNeeded = scope.wrapIfNeeded;
var wrappers = scope.wrappers;
@@ -4139,8 +4118,7 @@ window.ShadowDOMPolyfill = {};
compareDocumentPosition: function(otherNode) {
// This only wraps, it therefore only operates on the composed DOM and not
// the logical DOM.
- return originalCompareDocumentPosition.call(this.impl,
- unwrapIfNeeded(otherNode));
+ return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode));
},
normalize: function() {
@@ -4327,12 +4305,6 @@ window.ShadowDOMPolyfill = {};
}
wrapperList.length = i;
return wrapperList;
- },
-
- remove: function() {
- var p = this.parentNode;
- if (p)
- p.removeChild(this);
}
};
@@ -5275,14 +5247,8 @@ window.ShadowDOMPolyfill = {};
remove: function(indexOrNode) {
// Spec only allows index but implementations allow index or node.
// remove() is also allowed which is same as remove(undefined)
- if (indexOrNode === undefined) {
- HTMLElement.prototype.remove.call(this);
- return;
- }
-
if (typeof indexOrNode === 'object')
indexOrNode = unwrap(indexOrNode);
-
unwrap(this).remove(indexOrNode);
},
@@ -6802,15 +6768,7 @@ window.ShadowDOMPolyfill = {};
if (document.registerElement) {
var originalRegisterElement = document.registerElement;
Document.prototype.registerElement = function(tagName, object) {
- var prototype, extendsOption;
- if (object !== undefined) {
- prototype = object.prototype;
- extendsOption = object.extends;
- }
-
- if (!prototype)
- prototype = Object.create(HTMLElement.prototype);
-
+ var prototype = object.prototype;
// If we already used the object as a prototype for another custom
// element.
@@ -6871,13 +6829,13 @@ window.ShadowDOMPolyfill = {};
});
var p = {prototype: newPrototype};
- if (extendsOption)
- p.extends = extendsOption;
+ if (object.extends)
+ p.extends = object.extends;
function CustomElementConstructor(node) {
if (!node) {
- if (extendsOption) {
- return document.createElement(extendsOption, tagName);
+ if (object.extends) {
+ return document.createElement(object.extends, tagName);
} else {
return document.createElement(tagName);
}
@@ -7079,31 +7037,6 @@ window.ShadowDOMPolyfill = {};
})(window.ShadowDOMPolyfill);
-/**
- * Copyright 2014 The Polymer Authors. All rights reserved.
- * Use of this source code is goverened by a BSD-style
- * license that can be found in the LICENSE file.
- */
-
-(function(scope) {
- 'use strict';
-
- var unwrap = scope.unwrap;
-
- // DataTransfer (Clipboard in old Blink/WebKit) has a single method that
- // requires wrapping. Since it is only a method we do not need a real wrapper,
- // we can just override the method.
-
- var OriginalDataTransfer = window.DataTransfer || window.Clipboard;
- var OriginalDataTransferSetDragImage =
- OriginalDataTransfer.prototype.setDragImage;
-
- OriginalDataTransfer.prototype.setDragImage = function(image, x, y) {
- OriginalDataTransferSetDragImage.call(this, unwrap(image), x, y);
- };
-
-})(window.ShadowDOMPolyfill);
-
// Copyright 2013 The Polymer Authors. All rights reserved.
// Use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE file.
@@ -7274,7 +7207,7 @@ window.ShadowDOMPolyfill = {};
Shimmed features:
- * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
+ * :host, :ancestor: ShadowDOM allows styling of the shadowRoot's host
element using the :host rule. To shim this feature, the :host styles are
reformatted and prefixed with a given scope name and promoted to a
document level stylesheet.
@@ -7448,7 +7381,7 @@ var ShadowCSS = {
def.rootStyles = styles;
def.scopeStyles = def.rootStyles;
var extendee = this.registry[def.extendsName];
- if (extendee) {
+ if (extendee && (!root || root.querySelector('shadow'))) {
def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles);
}
return def;
@@ -7543,7 +7476,7 @@ var ShadowCSS = {
var unscoped = this.extractUnscopedRulesFromCssText(cssText);
cssText = this.insertPolyfillHostInCssText(cssText);
cssText = this.convertColonHost(cssText);
- cssText = this.convertColonHostContext(cssText);
+ cssText = this.convertColonAncestor(cssText);
cssText = this.convertCombinators(cssText);
if (scopeSelector) {
var self = this, cssText;
@@ -7592,7 +7525,7 @@ var ShadowCSS = {
this.colonHostPartReplacer);
},
/*
- * convert a rule like :host-context(.foo) > .bar { }
+ * convert a rule like :ancestor(.foo) > .bar { }
*
* to
*
@@ -7600,15 +7533,15 @@ var ShadowCSS = {
*
* and
*
- * :host-context(.foo:host) .bar { ... }
+ * :ancestor(.foo:host) .bar { ... }
*
* to
*
* scopeName.foo .bar { ... }
*/
- convertColonHostContext: function(cssText) {
- return this.convertColonRule(cssText, cssColonHostContextRe,
- this.colonHostContextPartReplacer);
+ convertColonAncestor: function(cssText) {
+ return this.convertColonRule(cssText, cssColonAncestorRe,
+ this.colonAncestorPartReplacer);
},
convertColonRule: function(cssText, regExp, partReplacer) {
// p1 = :host, p2 = contents of (), p3 rest of rule
@@ -7626,7 +7559,7 @@ var ShadowCSS = {
}
});
},
- colonHostContextPartReplacer: function(host, part, suffix) {
+ colonAncestorPartReplacer: function(host, part, suffix) {
if (part.match(polyfillHost)) {
return this.colonHostPartReplacer(host, part, suffix);
} else {
@@ -7640,10 +7573,7 @@ var ShadowCSS = {
* Convert ^ and ^^ combinators by replacing with space.
*/
convertCombinators: function(cssText) {
- for (var i=0; i < combinatorsRe.length; i++) {
- cssText = cssText.replace(combinatorsRe[i], ' ');
- }
- return cssText;
+ return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' ');
},
// change a selector like 'div' to 'name div'
scopeRules: function(cssRules, scopeSelector) {
@@ -7716,31 +7646,17 @@ var ShadowCSS = {
return scoped;
},
insertPolyfillHostInCssText: function(selector) {
- return selector.replace(colonHostContextRe, polyfillHostContext).replace(
- colonHostRe, polyfillHost);
+ return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
+ polyfillHost).replace(colonAncestorRe, polyfillAncestor);
},
propertiesFromRule: function(rule) {
- var cssText = rule.style.cssText;
// TODO(sorvell): Safari cssom incorrectly removes quotes from the content
// property. (https://bugs.webkit.org/show_bug.cgi?id=118045)
- // don't replace attr rules
- if (rule.style.content && !rule.style.content.match(/['"]+|attr/)) {
- cssText = cssText.replace(/content:[^;]*;/g, 'content: \'' +
+ if (rule.style.content && !rule.style.content.match(/['"]+/)) {
+ return rule.style.cssText.replace(/content:[^;]*;/g, 'content: \'' +
rule.style.content + '\';');
}
- // TODO(sorvell): we can workaround this issue here, but we need a list
- // of troublesome properties to fix https://github.com/Polymer/platform/issues/53
- //
- // inherit rules can be omitted from cssText
- // TODO(sorvell): remove when Blink bug is fixed:
- // https://code.google.com/p/chromium/issues/detail?id=358273
- var style = rule.style;
- for (var i in style) {
- if (style[i] === 'initial') {
- cssText += i + ': initial; ';
- }
- }
- return cssText;
+ return rule.style.cssText;
},
replaceTextInStyles: function(styles, action) {
if (styles && action) {
@@ -7776,28 +7692,21 @@ var selectorRe = /([^{]*)({[\s\S]*?})/gim,
cssPartRe = /::part\(([^)]*)\)/gim,
// note: :host pre-processed to -shadowcsshost.
polyfillHost = '-shadowcsshost',
- // note: :host-context pre-processed to -shadowcsshostcontext.
- polyfillHostContext = '-shadowcsscontext',
+ // note: :ancestor pre-processed to -shadowcssancestor.
+ polyfillAncestor = '-shadowcssancestor',
parenSuffix = ')(?:\\((' +
'(?:\\([^)(]*\\)|[^)(]*)+?' +
')\\))?([^,{]*)';
cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
- cssColonHostContextRe = new RegExp('(' + polyfillHostContext + parenSuffix, 'gim'),
+ cssColonAncestorRe = new RegExp('(' + polyfillAncestor + parenSuffix, 'gim'),
selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
+ hostRe = /@host/gim,
colonHostRe = /\:host/gim,
- colonHostContextRe = /\:host-context/gim,
+ colonAncestorRe = /\:ancestor/gim,
/* host name without combinator */
polyfillHostNoCombinator = polyfillHost + '-no-combinator',
polyfillHostRe = new RegExp(polyfillHost, 'gim'),
- polyfillHostContextRe = new RegExp(polyfillHostContext, 'gim'),
- combinatorsRe = [
- /\^\^/g,
- /\^/g,
- /\/shadow\//g,
- /\/shadow-deep\//g,
- /::shadow/g,
- /\/deep\//g
- ];
+ polyfillAncestorRe = new RegExp(polyfillAncestor, 'gim');
function stylesToCssText(styles, preserveComments) {
var cssText = '';
@@ -8009,18 +7918,30 @@ scope.ShadowCSS = ShadowCSS;
window.wrap = window.unwrap = function(n){
return n;
}
-
- addEventListener('DOMContentLoaded', function() {
- if (CustomElements.useNative === false) {
- var originalCreateShadowRoot = Element.prototype.createShadowRoot;
- Element.prototype.createShadowRoot = function() {
- var root = originalCreateShadowRoot.call(this);
- CustomElements.watchShadow(this);
- return root;
- };
+
+ var originalCreateShadowRoot = Element.prototype.webkitCreateShadowRoot;
+ Element.prototype.webkitCreateShadowRoot = function() {
+ var elderRoot = this.webkitShadowRoot;
+ var root = originalCreateShadowRoot.call(this);
+ root.olderShadowRoot = elderRoot;
+ root.host = this;
+ CustomElements.watchShadow(this);
+ return root;
+ }
+
+ Object.defineProperties(Element.prototype, {
+ shadowRoot: {
+ get: function() {
+ return this.webkitShadowRoot;
+ }
+ },
+ createShadowRoot: {
+ value: function() {
+ return this.webkitCreateShadowRoot();
+ }
}
});
-
+
window.templateContent = function(inTemplate) {
// if MDV exists, it may need to boostrap this template to reveal content
if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
@@ -9868,38 +9789,23 @@ window.HTMLImports = window.HTMLImports || {flags:{}};
},
fetch: function(url, elt) {
flags.load && console.log('fetch', url, elt);
- if (url.match(/^data:/)) {
- // Handle Data URI Scheme
- var pieces = url.split(',');
- var header = pieces[0];
- var body = pieces[1];
- if(header.indexOf(';base64') > -1) {
- body = atob(body);
- } else {
- body = decodeURIComponent(body);
- }
- setTimeout(function() {
- this.receive(url, elt, null, body);
- }.bind(this), 0);
+ var receiveXhr = function(err, resource) {
+ this.receive(url, elt, err, resource);
+ }.bind(this);
+ xhr.load(url, receiveXhr);
+ // TODO(sorvell): blocked on
+ // https://code.google.com/p/chromium/issues/detail?id=257221
+ // xhr'ing for a document makes scripts in imports runnable; otherwise
+ // they are not; however, it requires that we have doctype=html in
+ // the import which is unacceptable. This is only needed on Chrome
+ // to avoid the bug above.
+ /*
+ if (isDocumentLink(elt)) {
+ xhr.loadDocument(url, receiveXhr);
} else {
- var receiveXhr = function(err, resource) {
- this.receive(url, elt, err, resource);
- }.bind(this);
xhr.load(url, receiveXhr);
- // TODO(sorvell): blocked on)
- // https://code.google.com/p/chromium/issues/detail?id=257221
- // xhr'ing for a document makes scripts in imports runnable; otherwise
- // they are not; however, it requires that we have doctype=html in
- // the import which is unacceptable. This is only needed on Chrome
- // to avoid the bug above.
- /*
- if (isDocumentLink(elt)) {
- xhr.loadDocument(url, receiveXhr);
- } else {
- xhr.load(url, receiveXhr);
- }
- */
}
+ */
},
receive: function(url, elt, err, resource) {
this.cache[url] = resource;
@@ -11024,7 +10930,6 @@ if (useNative) {
scope.upgradeDocument = nop;
scope.upgradeDocumentTree = nop;
scope.takeRecords = nop;
- scope.reservedTagList = [];
} else {
@@ -11081,10 +10986,6 @@ if (useNative) {
// offer guidance)
throw new Error('document.registerElement: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
}
- // prevent registering reserved names
- if (isReservedTag(name)) {
- throw new Error('Failed to execute \'registerElement\' on \'Document\': Registration failed for type \'' + String(name) + '\'. The type name is invalid.');
- }
// elements may only be registered once
if (getRegisteredDefinition(name)) {
throw new Error('DuplicateDefinitionError: a type with name \'' + String(name) + '\' is already registered');
@@ -11128,19 +11029,6 @@ if (useNative) {
return definition.ctor;
}
- function isReservedTag(name) {
- for (var i = 0; i < reservedTagList.length; i++) {
- if (name === reservedTagList[i]) {
- return true;
- }
- }
- }
-
- var reservedTagList = [
- 'annotation-xml', 'color-profile', 'font-face', 'font-face-src',
- 'font-face-uri', 'font-face-format', 'font-face-name', 'missing-glyph'
- ];
-
function ancestry(extnds) {
var extendee = getRegisteredDefinition(extnds);
if (extendee) {
@@ -11437,7 +11325,6 @@ if (!Object.__proto__ && !useNative) {
// exports
scope.instanceof = isInstance;
-scope.reservedTagList = reservedTagList;
// bc
document.register = document.registerElement;
@@ -11871,7 +11758,7 @@ scope.styleResolver = styleResolver;
*/
(function() {
function shadowSelector(v) {
- return 'body /shadow-deep/ ' + selector(v);
+ return 'body ^^ ' + selector(v);
}
function selector(v) {
return '[touch-action="' + v + '"]';
@@ -11893,31 +11780,18 @@ scope.styleResolver = styleResolver;
}
];
var styles = '';
- // only install stylesheet if the browser has touch action support
- var head = document.head;
- var hasNativePE = window.PointerEvent || window.MSPointerEvent;
- // only add shadow selectors if shadowdom is supported
- var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoot;
-
- if (hasNativePE) {
- attrib2css.forEach(function(r) {
- if (String(r) === r) {
- styles += selector(r) + rule(r) + '\n';
- if (hasShadowRoot) {
- styles += shadowSelector(r) + rule(r) + '\n';
- }
- } else {
- styles += r.selectors.map(selector) + rule(r.rule) + '\n';
- if (hasShadowRoot) {
- styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n';
- }
- }
- });
-
- var el = document.createElement('style');
- el.textContent = styles;
- document.head.appendChild(el);
- }
+ attrib2css.forEach(function(r) {
+ if (String(r) === r) {
+ styles += selector(r) + rule(r) + '\n';
+ styles += shadowSelector(r) + rule(r) + '\n';
+ } else {
+ styles += r.selectors.map(selector) + rule(r.rule) + '\n';
+ styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n';
+ }
+ });
+ var el = document.createElement('style');
+ el.textContent = styles;
+ document.head.appendChild(el);
})();
/*
@@ -11941,6 +11815,16 @@ scope.styleResolver = styleResolver;
* @return {Event} A new PointerEvent of type `inType` and initialized with properties from `inDict`.
*/
(function(scope) {
+ // test for DOM Level 4 Events
+ var NEW_MOUSE_EVENT = false;
+ var HAS_BUTTONS = false;
+ try {
+ var ev = new MouseEvent('click', {buttons: 1});
+ NEW_MOUSE_EVENT = true;
+ HAS_BUTTONS = ev.buttons === 1;
+ ev = null;
+ } catch(e) {
+ }
var MOUSE_PROPS = [
'bubbles',
@@ -11957,8 +11841,6 @@ scope.styleResolver = styleResolver;
'metaKey',
'button',
'relatedTarget',
- 'pageX',
- 'pageY'
];
var MOUSE_DEFAULTS = [
@@ -11975,23 +11857,73 @@ scope.styleResolver = styleResolver;
false,
false,
0,
- null,
- 0,
- 0
+ null
];
function PointerEvent(inType, inDict) {
- inDict = inDict || Object.create(null);
+ inDict = inDict || {};
+ // According to the w3c spec,
+ // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button
+ // MouseEvent.button == 0 can mean either no mouse button depressed, or the
+ // left mouse button depressed.
+ //
+ // As of now, the only way to distinguish between the two states of
+ // MouseEvent.button is by using the deprecated MouseEvent.which property, as
+ // this maps mouse buttons to positive integers > 0, and uses 0 to mean that
+ // no mouse button is held.
+ //
+ // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,
+ // but initMouseEvent does not expose an argument with which to set
+ // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set
+ // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations
+ // of app developers.
+ //
+ // The only way to propagate the correct state of MouseEvent.which and
+ // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0
+ // is to call initMouseEvent with a buttonArg value of -1.
+ //
+ // This is fixed with DOM Level 4's use of buttons
+ var buttons = inDict.buttons;
+ // touch has two possible buttons state: 0 and 1, rely on being told the right one
+ if (!HAS_BUTTONS && !buttons && inType !== 'touch') {
+ switch (inDict.which) {
+ case 1: buttons = 1; break;
+ case 2: buttons = 4; break;
+ case 3: buttons = 2; break;
+ default: buttons = 0;
+ }
+ }
- var e = document.createEvent('Event');
- e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
+ var e;
+ if (NEW_MOUSE_EVENT) {
+ e = new MouseEvent(inType, inDict);
+ } else {
+ e = document.createEvent('MouseEvent');
+
+ // import values from the given dictionary
+ var props = {}, p;
+ for(var i = 0; i < MOUSE_PROPS.length; i++) {
+ p = MOUSE_PROPS[i];
+ props[p] = inDict[p] || MOUSE_DEFAULTS[i];
+ }
- // define inherited MouseEvent properties
- for(var i = 0, p; i < MOUSE_PROPS.length; i++) {
- p = MOUSE_PROPS[i];
- e[p] = inDict[p] || MOUSE_DEFAULTS[i];
+ // define the properties inherited from MouseEvent
+ e.initMouseEvent(
+ inType, props.bubbles, props.cancelable, props.view, props.detail,
+ props.screenX, props.screenY, props.clientX, props.clientY, props.ctrlKey,
+ props.altKey, props.shiftKey, props.metaKey, props.button, props.relatedTarget
+ );
+ }
+
+ // make the event pass instanceof checks
+ e.__proto__ = PointerEvent.prototype;
+
+ // define the buttons property according to DOM Level 3 spec
+ if (!HAS_BUTTONS) {
+ // IE 10 has buttons on MouseEvent.prototype as a getter w/o any setting
+ // mechanism
+ Object.defineProperty(e, 'buttons', {get: function(){ return buttons; }, enumerable: true});
}
- e.buttons = inDict.buttons || 0;
// Spec requires that pointers without pressure specified use 0.5 for down
// state and 0 for up state.
@@ -11999,26 +11931,27 @@ scope.styleResolver = styleResolver;
if (inDict.pressure) {
pressure = inDict.pressure;
} else {
- pressure = e.buttons ? 0.5 : 0;
+ pressure = buttons ? 0.5 : 0;
}
- // add x/y properties aliased to clientX/Y
- e.x = e.clientX;
- e.y = e.clientY;
-
// define the properties of the PointerEvent interface
- e.pointerId = inDict.pointerId || 0;
- e.width = inDict.width || 0;
- e.height = inDict.height || 0;
- e.pressure = pressure;
- e.tiltX = inDict.tiltX || 0;
- e.tiltY = inDict.tiltY || 0;
- e.pointerType = inDict.pointerType || '';
- e.hwTimestamp = inDict.hwTimestamp || 0;
- e.isPrimary = inDict.isPrimary || false;
+ Object.defineProperties(e, {
+ pointerId: { value: inDict.pointerId || 0, enumerable: true },
+ width: { value: inDict.width || 0, enumerable: true },
+ height: { value: inDict.height || 0, enumerable: true },
+ pressure: { value: pressure, enumerable: true },
+ tiltX: { value: inDict.tiltX || 0, enumerable: true },
+ tiltY: { value: inDict.tiltY || 0, enumerable: true },
+ pointerType: { value: inDict.pointerType || '', enumerable: true },
+ hwTimestamp: { value: inDict.hwTimestamp || 0, enumerable: true },
+ isPrimary: { value: inDict.isPrimary || false, enumerable: true }
+ });
return e;
}
+ // PointerEvent extends MouseEvent
+ PointerEvent.prototype = Object.create(MouseEvent.prototype);
+
// attach to window
if (!scope.PointerEvent) {
scope.PointerEvent = PointerEvent;
@@ -12129,9 +12062,7 @@ scope.styleResolver = styleResolver;
'type',
'target',
'currentTarget',
- 'which',
- 'pageX',
- 'pageY'
+ 'which'
];
var CLONE_DEFAULTS = [
@@ -12166,8 +12097,6 @@ scope.styleResolver = styleResolver;
'',
null,
null,
- 0,
- 0,
0
];
@@ -12186,12 +12115,13 @@ scope.styleResolver = styleResolver;
* - pointercancel: a pointer will no longer generate events
*/
var dispatcher = {
+ targets: new WeakMap(),
+ handledEvents: new WeakMap(),
pointermap: new scope.PointerMap(),
- eventMap: Object.create(null),
- captureInfo: Object.create(null),
+ eventMap: {},
// Scope objects for native events.
// This exists for ease of testing.
- eventSources: Object.create(null),
+ eventSources: {},
eventSourceList: [],
/**
* Add a new event source that will generate pointer events.
@@ -12281,7 +12211,7 @@ scope.styleResolver = styleResolver;
// This is used to prevent multiple dispatch of pointerevents from
// platform events. This can happen when two elements in different scopes
// are set up to create pointer events, which is relevant to Shadow DOM.
- if (inEvent._handledByPE) {
+ if (this.handledEvents.get(inEvent)) {
return;
}
var type = inEvent.type;
@@ -12289,7 +12219,7 @@ scope.styleResolver = styleResolver;
if (fn) {
fn(inEvent);
}
- inEvent._handledByPE = true;
+ this.handledEvents.set(inEvent, true);
},
// set up event listeners
listen: function(target, events) {
@@ -12320,14 +12250,14 @@ scope.styleResolver = styleResolver;
*/
makeEvent: function(inType, inEvent) {
// relatedTarget must be null if pointer is captured
- if (this.captureInfo[inEvent.pointerId]) {
+ if (this.captureInfo) {
inEvent.relatedTarget = null;
}
var e = new PointerEvent(inType, inEvent);
if (inEvent.preventDefault) {
e.preventDefault = inEvent.preventDefault;
}
- e._target = e._target || inEvent.target;
+ this.targets.set(e, this.targets.get(inEvent) || inEvent.target);
return e;
},
// make and dispatch an event in one call
@@ -12343,7 +12273,7 @@ scope.styleResolver = styleResolver;
* properties.
*/
cloneEvent: function(inEvent) {
- var eventCopy = Object.create(null), p;
+ var eventCopy = {}, p;
for (var i = 0; i < CLONE_PROPS.length; i++) {
p = CLONE_PROPS[i];
eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
@@ -12367,32 +12297,33 @@ scope.styleResolver = styleResolver;
getTarget: function(inEvent) {
// if pointer capture is set, route all events for the specified pointerId
// to the capture target
- return this.captureInfo[inEvent.pointerId] || inEvent._target;
+ if (this.captureInfo) {
+ if (this.captureInfo.id === inEvent.pointerId) {
+ return this.captureInfo.target;
+ }
+ }
+ return this.targets.get(inEvent);
},
setCapture: function(inPointerId, inTarget) {
- if (this.captureInfo[inPointerId]) {
- this.releaseCapture(inPointerId);
+ if (this.captureInfo) {
+ this.releaseCapture(this.captureInfo.id);
}
- this.captureInfo[inPointerId] = inTarget;
- var e = document.createEvent('Event');
- e.initEvent('gotpointercapture', true, false);
- e.pointerId = inPointerId;
+ this.captureInfo = {id: inPointerId, target: inTarget};
+ var e = new PointerEvent('gotpointercapture', { bubbles: true });
this.implicitRelease = this.releaseCapture.bind(this, inPointerId);
document.addEventListener('pointerup', this.implicitRelease);
document.addEventListener('pointercancel', this.implicitRelease);
- e._target = inTarget;
+ this.targets.set(e, inTarget);
this.asyncDispatchEvent(e);
},
releaseCapture: function(inPointerId) {
- var t = this.captureInfo[inPointerId];
- if (t) {
- var e = document.createEvent('Event');
- e.initEvent('lostpointercapture', true, false);
- e.pointerId = inPointerId;
- this.captureInfo[inPointerId] = undefined;
+ if (this.captureInfo && this.captureInfo.id === inPointerId) {
+ var e = new PointerEvent('lostpointercapture', { bubbles: true });
+ var t = this.captureInfo.target;
+ this.captureInfo = null;
document.removeEventListener('pointerup', this.implicitRelease);
document.removeEventListener('pointercancel', this.implicitRelease);
- e._target = t;
+ this.targets.set(e, t);
this.asyncDispatchEvent(e);
}
},
@@ -12409,7 +12340,7 @@ scope.styleResolver = styleResolver;
}
},
asyncDispatchEvent: function(inEvent) {
- requestAnimationFrame(this.dispatchEvent.bind(this, inEvent));
+ setTimeout(this.dispatchEvent.bind(this, inEvent), 0);
}
};
dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
@@ -12552,13 +12483,6 @@ scope.styleResolver = styleResolver;
// radius around touchend that swallows mouse events
var DEDUP_DIST = 25;
- var WHICH_TO_BUTTONS = [0, 1, 4, 2];
-
- var HAS_BUTTONS = false;
- try {
- HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1;
- } catch (e) {}
-
// handler block for native mouse events
var mouseEvents = {
POINTER_ID: 1,
@@ -12600,9 +12524,6 @@ scope.styleResolver = styleResolver;
e.pointerId = this.POINTER_ID;
e.isPrimary = true;
e.pointerType = this.POINTER_TYPE;
- if (!HAS_BUTTONS) {
- e.buttons = WHICH_TO_BUTTONS[e.which] || 0;
- }
return e;
},
mousedown: function(inEvent) {
@@ -12667,7 +12588,6 @@ scope.styleResolver = styleResolver;
(function(scope) {
var dispatcher = scope.dispatcher;
- var captureInfo = dispatcher.captureInfo;
var findTarget = scope.findTarget;
var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding);
var pointermap = dispatcher.pointermap;
@@ -12686,6 +12606,7 @@ scope.styleResolver = styleResolver;
// handler block for native touch events
var touchEvents = {
+ scrollType: new WeakMap(),
events: [
'touchstart',
'touchmove',
@@ -12710,21 +12631,21 @@ scope.styleResolver = styleResolver;
var a = el.getAttribute(ATTRIB);
var st = this.touchActionToScrollType(a);
if (st) {
- el._scrollType = st;
+ this.scrollType.set(el, st);
dispatcher.listen(el, this.events);
// set touch-action on shadows as well
allShadows(el).forEach(function(s) {
- s._scrollType = st;
+ this.scrollType.set(s, st);
dispatcher.listen(s, this.events);
}, this);
}
},
elementRemoved: function(el) {
- el._scrollType = undefined;
+ this.scrollType['delete'](el);
dispatcher.unlisten(el, this.events);
// remove touch-action from shadow
allShadows(el).forEach(function(s) {
- s._scrollType = undefined;
+ this.scrollType['delete'](s);
dispatcher.unlisten(s, this.events);
}, this);
},
@@ -12734,9 +12655,9 @@ scope.styleResolver = styleResolver;
var oldSt = this.touchActionToScrollType(oldValue);
// simply update scrollType if listeners are already established
if (st && oldSt) {
- el._scrollType = st;
+ this.scrollType.set(el, st);
allShadows(el).forEach(function(s) {
- s._scrollType = st;
+ this.scrollType.set(s, st);
}, this);
} else if (oldSt) {
this.elementRemoved(el);
@@ -12806,46 +12727,44 @@ scope.styleResolver = styleResolver;
return ret;
},
touchToPointer: function(inTouch) {
- var cte = this.currentTouchEvent;
var e = dispatcher.cloneEvent(inTouch);
// Spec specifies that pointerId 1 is reserved for Mouse.
// Touch identifiers can start at 0.
// Add 2 to the touch identifier for compatibility.
- var id = e.pointerId = inTouch.identifier + 2;
- e.target = captureInfo[id] || findTarget(e);
+ e.pointerId = inTouch.identifier + 2;
+ e.target = findTarget(e);
e.bubbles = true;
e.cancelable = true;
e.detail = this.clickCount;
e.button = 0;
- e.buttons = this.typeToButtons(cte.type);
+ e.buttons = this.typeToButtons(this.currentTouchEvent);
e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
e.isPrimary = this.isPrimaryTouch(inTouch);
e.pointerType = this.POINTER_TYPE;
- // forward touch preventDefaults
- var self = this;
- e.preventDefault = function() {
- self.scrolling = false;
- self.firstXY = null;
- cte.preventDefault();
- };
return e;
},
processTouches: function(inEvent, inFunction) {
var tl = inEvent.changedTouches;
- this.currentTouchEvent = inEvent;
- for (var i = 0, t; i < tl.length; i++) {
- t = tl[i];
- inFunction.call(this, this.touchToPointer(t));
- }
+ this.currentTouchEvent = inEvent.type;
+ var pointers = touchMap(tl, this.touchToPointer, this);
+ // forward touch preventDefaults
+ pointers.forEach(function(p) {
+ p.preventDefault = function() {
+ this.scrolling = false;
+ this.firstXY = null;
+ inEvent.preventDefault();
+ };
+ }, this);
+ pointers.forEach(inFunction, this);
},
// For single axis scrollers, determines whether the element should emit
// pointer events or behave as a scroller
shouldScroll: function(inEvent) {
if (this.firstXY) {
var ret;
- var scrollAxis = inEvent.currentTarget._scrollType;
+ var scrollAxis = this.scrollType.get(inEvent.currentTarget);
if (scrollAxis === 'none') {
// this element is a touch-action: none, should never scroll
ret = false;
@@ -12892,7 +12811,7 @@ scope.styleResolver = styleResolver;
// index in pointermap.
if (key !== 1 && !this.findTouch(tl, key - 2)) {
var p = value.out;
- d.push(p);
+ d.push(this.touchToPointer(p));
}
}, this);
d.forEach(this.cancelOut, this);
@@ -13108,7 +13027,8 @@ scope.styleResolver = styleResolver;
var dispatcher = scope.dispatcher;
// only activate if this platform does not have pointer events
- if (window.PointerEvent !== scope.PointerEvent) {
+ if (window.navigator.pointerEnabled === undefined) {
+ Object.defineProperty(window.navigator, 'pointerEnabled', {value: true, enumerable: true});
if (window.navigator.msPointerEnabled) {
var tp = window.navigator.msMaxTouchPoints;
@@ -13488,7 +13408,7 @@ PointerGestureEvent.prototype.preventTap = function() {
// must clone events to keep the (possibly shadowed) target correct for
// async dispatching
var e = this.cloneEvent(inEvent);
- requestAnimationFrame(this.runQueue.bind(this, inHandlerFns, e));
+ setTimeout(this.runQueue.bind(this, inHandlerFns, e), 0);
},
// Dispatch the queued events
runQueue: function(inHandlers, inEvent) {
@@ -13549,7 +13469,10 @@ PointerGestureEvent.prototype.preventTap = function() {
}
},
asyncDispatchEvent: function(inEvent, inTarget) {
- requestAnimationFrame(this.dispatchEvent.bind(this, inEvent, inTarget));
+ var fn = function() {
+ this.dispatchEvent(inEvent, inTarget);
+ }.bind(this);
+ setTimeout(fn, 0);
},
preventTap: function(inPointerId) {
var t = this.recognizers.tap;
@@ -14168,8 +14091,7 @@ PointerGestureEvent.prototype.preventTap = function() {
pointers.push(p);
});
var dist = 0;
- // start with at least two pointers
- var points = {a: pointers[0], b: pointers[1]};
+ var points = {};
var x, y, d;
for (var i = 0; i < pointers.length; i++) {
var a = pointers[i];
@@ -14347,12 +14269,19 @@ PointerGestureEvent.prototype.preventTap = function() {
}
})(window.PointerGestures);
-// Copyright (c) 2014 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
+// Copyright 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
(function(global) {
'use strict';
@@ -14367,24 +14296,42 @@ PointerGestureEvent.prototype.preventTap = function() {
return typeof node.getElementById === 'function' ? node : null;
}
+
Node.prototype.bind = function(name, observable) {
console.error('Unhandled binding to Node: ', this, name, observable);
};
- function updateBindings(node, name, binding) {
- var bindings = node.bindings_;
- if (!bindings)
- bindings = node.bindings_ = {};
+ function unbind(node, name) {
+ var bindings = node.bindings;
+ if (!bindings) {
+ node.bindings = {};
+ return;
+ }
- if (bindings[name])
- binding[name].close();
+ var binding = bindings[name];
+ if (!binding)
+ return;
- return bindings[name] = binding;
+ binding.close();
+ bindings[name] = undefined;
}
- function returnBinding(node, name, binding) {
- return binding;
- }
+ Node.prototype.unbind = function(name) {
+ unbind(this, name);
+ };
+
+ Node.prototype.unbindAll = function() {
+ if (!this.bindings)
+ return;
+ var names = Object.keys(this.bindings);
+ for (var i = 0; i < names.length; i++) {
+ var binding = this.bindings[names[i]];
+ if (binding)
+ binding.close();
+ }
+
+ this.bindings = {};
+ };
function sanitizeValue(value) {
return value == null ? '' : value;
@@ -14400,19 +14347,6 @@ PointerGestureEvent.prototype.preventTap = function() {
};
}
- var maybeUpdateBindings = returnBinding;
-
- Object.defineProperty(Platform, 'enableBindingsReflection', {
- get: function() {
- return maybeUpdateBindings === updateBindings;
- },
- set: function(enable) {
- maybeUpdateBindings = enable ? updateBindings : returnBinding;
- return enable;
- },
- configurable: true
- });
-
Text.prototype.bind = function(name, value, oneTime) {
if (name !== 'textContent')
return Node.prototype.bind.call(this, name, value, oneTime);
@@ -14420,9 +14354,9 @@ PointerGestureEvent.prototype.preventTap = function() {
if (oneTime)
return updateText(this, value);
- var observable = value;
- updateText(this, observable.open(textBinding(this)));
- return maybeUpdateBindings(this, name, observable);
+ unbind(this, 'textContent');
+ updateText(this, value.open(textBinding(this)));
+ return this.bindings.textContent = value;
}
function updateAttribute(el, name, conditional, value) {
@@ -14453,12 +14387,11 @@ PointerGestureEvent.prototype.preventTap = function() {
if (oneTime)
return updateAttribute(this, name, conditional, value);
-
- var observable = value;
+ unbind(this, name);
updateAttribute(this, name, conditional,
- observable.open(attributeBinding(this, name, conditional)));
+ value.open(attributeBinding(this, name, conditional)));
- return maybeUpdateBindings(this, name, observable);
+ return this.bindings[name] = value;
};
var checkboxEventType;
@@ -14527,13 +14460,15 @@ PointerGestureEvent.prototype.preventTap = function() {
}
input.addEventListener(eventType, eventHandler);
- return {
- close: function() {
- input.removeEventListener(eventType, eventHandler);
- observable.close();
- },
+ var capturedClose = observable.close;
+ observable.close = function() {
+ if (!capturedClose)
+ return;
+ input.removeEventListener(eventType, eventHandler);
- observable_: observable
+ observable.close = capturedClose;
+ observable.close();
+ capturedClose = undefined;
}
}
@@ -14577,10 +14512,10 @@ PointerGestureEvent.prototype.preventTap = function() {
if (input.tagName === 'INPUT' &&
input.type === 'radio') {
getAssociatedRadioButtons(input).forEach(function(radio) {
- var checkedBinding = radio.bindings_.checked;
+ var checkedBinding = radio.bindings.checked;
if (checkedBinding) {
// Set the value directly to avoid an infinite call stack.
- checkedBinding.observable_.setValue(false);
+ checkedBinding.setValue(false);
}
});
}
@@ -14590,6 +14525,7 @@ PointerGestureEvent.prototype.preventTap = function() {
if (name !== 'value' && name !== 'checked')
return HTMLElement.prototype.bind.call(this, name, value, oneTime);
+
this.removeAttribute(name);
var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue;
var postEventFn = name == 'checked' ? checkedPostEvent : noop;
@@ -14597,15 +14533,13 @@ PointerGestureEvent.prototype.preventTap = function() {
if (oneTime)
return updateInput(this, name, value, sanitizeFn);
-
- var observable = value;
- var binding = bindInputEvent(this, name, observable, postEventFn);
+ unbind(this, name);
+ bindInputEvent(this, name, value, postEventFn);
updateInput(this, name,
- observable.open(inputBinding(this, name, sanitizeFn)),
+ value.open(inputBinding(this, name, sanitizeFn)),
sanitizeFn);
- // Checkboxes may need to update bindings of other checkboxes.
- return updateBindings(this, name, binding);
+ return this.bindings[name] = value;
}
HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
@@ -14617,11 +14551,12 @@ PointerGestureEvent.prototype.preventTap = function() {
if (oneTime)
return updateInput(this, 'value', value);
- var observable = value;
- var binding = bindInputEvent(this, 'value', observable);
+ unbind(this, 'value');
+ bindInputEvent(this, 'value', value);
updateInput(this, 'value',
- observable.open(inputBinding(this, 'value', sanitizeValue)));
- return maybeUpdateBindings(this, name, binding);
+ value.open(inputBinding(this, 'value', sanitizeValue)));
+
+ return this.bindings.value = value;
}
function updateOption(option, value) {
@@ -14630,18 +14565,18 @@ PointerGestureEvent.prototype.preventTap = function() {
var selectBinding;
var oldValue;
if (parentNode instanceof HTMLSelectElement &&
- parentNode.bindings_ &&
- parentNode.bindings_.value) {
+ parentNode.bindings &&
+ parentNode.bindings.value) {
select = parentNode;
- selectBinding = select.bindings_.value;
+ selectBinding = select.bindings.value;
oldValue = select.value;
}
option.value = sanitizeValue(value);
if (select && select.value != oldValue) {
- selectBinding.observable_.setValue(select.value);
- selectBinding.observable_.discardChanges();
+ selectBinding.setValue(select.value);
+ selectBinding.discardChanges();
Platform.performMicrotaskCheckpoint();
}
}
@@ -14661,10 +14596,10 @@ PointerGestureEvent.prototype.preventTap = function() {
if (oneTime)
return updateOption(this, value);
- var observable = value;
- var binding = bindInputEvent(this, 'value', observable);
- updateOption(this, observable.open(optionBinding(this)));
- return maybeUpdateBindings(this, name, binding);
+ unbind(this, 'value');
+ bindInputEvent(this, 'value', value);
+ updateOption(this, value.open(optionBinding(this)));
+ return this.bindings.value = value;
}
HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
@@ -14679,22 +14614,27 @@ PointerGestureEvent.prototype.preventTap = function() {
if (oneTime)
return updateInput(this, name, value);
- var observable = value;
- var binding = bindInputEvent(this, name, observable);
+ unbind(this, name);
+ bindInputEvent(this, name, value);
updateInput(this, name,
- observable.open(inputBinding(this, name)));
-
- // Option update events may need to access select bindings.
- return updateBindings(this, name, binding);
+ value.open(inputBinding(this, name)));
+ return this.bindings[name] = value;
}
})(this);
-// Copyright (c) 2014 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
+// Copyright 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
(function(global) {
'use strict';
@@ -15159,13 +15099,8 @@ PointerGestureEvent.prototype.preventTap = function() {
if (oneTime)
return;
- if (!this.bindings_) {
- this.bindings_ = { ref: value };
- } else {
- this.bindings_.ref = value;
- }
-
- return value;
+ this.unbind('ref');
+ return this.bindings.ref = value;
},
processBindingDirectives_: function(directives) {
@@ -15176,6 +15111,7 @@ PointerGestureEvent.prototype.preventTap = function() {
if (this.iterator_) {
this.iterator_.close();
this.iterator_ = undefined;
+ this.bindings.iterator = undefined;
}
return;
@@ -15183,6 +15119,8 @@ PointerGestureEvent.prototype.preventTap = function() {
if (!this.iterator_) {
this.iterator_ = new TemplateIterator(this);
+ this.bindings = this.bindings || {};
+ this.bindings.iterator = this.iterator_;
}
this.iterator_.updateDependencies(directives, this.model_);
@@ -15195,16 +15133,14 @@ PointerGestureEvent.prototype.preventTap = function() {
return this.iterator_;
},
- createInstance: function(model, bindingDelegate, delegate_) {
+ createInstance: function(model, bindingDelegate, delegate_,
+ instanceBindings_) {
if (bindingDelegate)
delegate_ = this.newDelegate_(bindingDelegate);
if (!this.refContent_)
this.refContent_ = this.ref_.content;
var content = this.refContent_;
- if (content.firstChild === null)
- return emptyInstance;
-
var map = this.bindingMap_;
if (!map || map.content !== content) {
// TODO(rafaelw): Setup a MutationObserver on content to detect
@@ -15219,32 +15155,21 @@ PointerGestureEvent.prototype.preventTap = function() {
var instance = stagingDocument.createDocumentFragment();
instance.templateCreator_ = this;
instance.protoContent_ = content;
- instance.bindings_ = [];
- instance.terminator_ = null;
- var instanceRecord = instance.templateInstance_ = {
+
+ var instanceRecord = {
firstNode: null,
lastNode: null,
model: model
};
var i = 0;
- var collectTerminator = false;
for (var child = content.firstChild; child; child = child.nextSibling) {
- // The terminator of the instance is the clone of the last child of the
- // content. If the last child is an active template, it may produce
- // instances as a result of production, so simply collecting the last
- // child of the instance after it has finished producing may be wrong.
- if (child.nextSibling === null)
- collectTerminator = true;
-
var clone = cloneAndBindInstance(child, instance, stagingDocument,
map.children[i++],
model,
delegate_,
- instance.bindings_);
+ instanceBindings_);
clone.templateInstance_ = instanceRecord;
- if (collectTerminator)
- instance.terminator_ = clone;
}
instanceRecord.firstNode = instance.firstChild;
@@ -15279,8 +15204,7 @@ PointerGestureEvent.prototype.preventTap = function() {
clear: function() {
this.model_ = undefined;
this.delegate_ = undefined;
- if (this.bindings_ && this.bindings_.ref)
- this.bindings_.ref.close()
+ this.bindings_ = undefined;
this.refContent_ = undefined;
if (!this.iterator_)
return;
@@ -15385,14 +15309,9 @@ PointerGestureEvent.prototype.preventTap = function() {
var pathString = s.slice(startIndex + 2, endIndex).trim();
tokens.push(oneTime); // ONE_TIME?
onlyOneTime = onlyOneTime && oneTime;
+ tokens.push(Path.get(pathString)); // PATH
var delegateFn = prepareBindingFn &&
prepareBindingFn(pathString, name, node);
- // Don't try to parse the expression if there's a prepareBinding function
- if (delegateFn == null) {
- tokens.push(Path.get(pathString)); // PATH
- } else {
- tokens.push(null);
- }
tokens.push(delegateFn); // DELEGATE_FN
lastIndex = endIndex + 2;
}
@@ -15610,14 +15529,14 @@ PointerGestureEvent.prototype.preventTap = function() {
}
});
- var emptyInstance = document.createDocumentFragment();
- emptyInstance.bindings_ = [];
- emptyInstance.terminator_ = null;
-
function TemplateIterator(templateElement) {
this.closed = false;
this.templateElement_ = templateElement;
- this.instances = [];
+
+ // Flattened array of tuples:
+ // <instanceTerminatorNode, [bindingsSetupByInstance]>
+ this.terminators = [];
+
this.deps = undefined;
this.iteratedValue = [];
this.presentValue = undefined;
@@ -15712,53 +15631,63 @@ PointerGestureEvent.prototype.preventTap = function() {
this.iteratedValue));
},
- getLastInstanceNode: function(index) {
+ getTerminatorAt: function(index) {
if (index == -1)
return this.templateElement_;
- var instance = this.instances[index];
- var terminator = instance.terminator_;
- if (!terminator)
- return this.getLastInstanceNode(index - 1);
-
+ var terminator = this.terminators[index*2];
if (terminator.nodeType !== Node.ELEMENT_NODE ||
this.templateElement_ === terminator) {
return terminator;
}
- var subtemplateIterator = terminator.iterator_;
- if (!subtemplateIterator)
+ var subIterator = terminator.iterator_;
+ if (!subIterator)
return terminator;
- return subtemplateIterator.getLastTemplateNode();
+ return subIterator.getTerminatorAt(subIterator.terminators.length/2 - 1);
},
- getLastTemplateNode: function() {
- return this.getLastInstanceNode(this.instances.length - 1);
- },
+ // TODO(rafaelw): If we inserting sequences of instances we can probably
+ // avoid lots of calls to getTerminatorAt(), or cache its result.
+ insertInstanceAt: function(index, fragment, instanceNodes,
+ instanceBindings) {
+ var previousTerminator = this.getTerminatorAt(index - 1);
+ var terminator = previousTerminator;
+ if (fragment)
+ terminator = fragment.lastChild || terminator;
+ else if (instanceNodes)
+ terminator = instanceNodes[instanceNodes.length - 1] || terminator;
- insertInstanceAt: function(index, fragment) {
- var previousInstanceLast = this.getLastInstanceNode(index - 1);
+ this.terminators.splice(index*2, 0, terminator, instanceBindings);
var parent = this.templateElement_.parentNode;
- this.instances.splice(index, 0, fragment);
+ var insertBeforeNode = previousTerminator.nextSibling;
- parent.insertBefore(fragment, previousInstanceLast.nextSibling);
+ if (fragment) {
+ parent.insertBefore(fragment, insertBeforeNode);
+ } else if (instanceNodes) {
+ for (var i = 0; i < instanceNodes.length; i++)
+ parent.insertBefore(instanceNodes[i], insertBeforeNode);
+ }
},
extractInstanceAt: function(index) {
- var previousInstanceLast = this.getLastInstanceNode(index - 1);
- var lastNode = this.getLastInstanceNode(index);
- var parent = this.templateElement_.parentNode;
- var instance = this.instances.splice(index, 1)[0];
+ var instanceNodes = [];
+ var previousTerminator = this.getTerminatorAt(index - 1);
+ var terminator = this.getTerminatorAt(index);
+ instanceNodes.instanceBindings = this.terminators[index*2 + 1];
+ this.terminators.splice(index*2, 2);
- while (lastNode !== previousInstanceLast) {
- var node = previousInstanceLast.nextSibling;
- if (node == lastNode)
- lastNode = previousInstanceLast;
+ var parent = this.templateElement_.parentNode;
+ while (terminator !== previousTerminator) {
+ var node = previousTerminator.nextSibling;
+ if (node == terminator)
+ terminator = previousTerminator;
- instance.appendChild(parent.removeChild(node));
+ parent.removeChild(node);
+ instanceNodes.push(node);
}
- return instance;
+ return instanceNodes;
},
getDelegateFn: function(fn) {
@@ -15792,50 +15721,46 @@ PointerGestureEvent.prototype.preventTap = function() {
delegate.prepareInstancePositionChanged);
}
- // Instance Removals
var instanceCache = new Map;
var removeDelta = 0;
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- var removed = splice.removed;
- for (var j = 0; j < removed.length; j++) {
- var model = removed[j];
- var instance = this.extractInstanceAt(splice.index + removeDelta);
- if (instance !== emptyInstance) {
- instanceCache.set(model, instance);
- }
- }
+ splices.forEach(function(splice) {
+ splice.removed.forEach(function(model) {
+ var instanceNodes =
+ this.extractInstanceAt(splice.index + removeDelta);
+ instanceCache.set(model, instanceNodes);
+ }, this);
removeDelta -= splice.addedCount;
- }
+ }, this);
- // Instance Insertions
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
+ splices.forEach(function(splice) {
var addIndex = splice.index;
for (; addIndex < splice.index + splice.addedCount; addIndex++) {
var model = this.iteratedValue[addIndex];
- var instance = instanceCache.get(model);
- if (instance) {
+ var fragment = undefined;
+ var instanceNodes = instanceCache.get(model);
+ var instanceBindings;
+ if (instanceNodes) {
instanceCache.delete(model);
+ instanceBindings = instanceNodes.instanceBindings;
} else {
- if (this.instanceModelFn_) {
+ instanceBindings = [];
+ if (this.instanceModelFn_)
model = this.instanceModelFn_(model);
- }
- if (model === undefined) {
- instance = emptyInstance;
- } else {
- instance = template.createInstance(model, undefined, delegate);
+ if (model !== undefined) {
+ fragment = template.createInstance(model, undefined, delegate,
+ instanceBindings);
}
}
- this.insertInstanceAt(addIndex, instance);
+ this.insertInstanceAt(addIndex, fragment, instanceNodes,
+ instanceBindings);
}
- }
+ }, this);
- instanceCache.forEach(function(instance) {
- this.closeInstanceBindings(instance);
+ instanceCache.forEach(function(instanceNodes) {
+ this.closeInstanceBindings(instanceNodes.instanceBindings);
}, this);
if (this.instancePositionChangedFn_)
@@ -15843,11 +15768,17 @@ PointerGestureEvent.prototype.preventTap = function() {
},
reportInstanceMoved: function(index) {
- var instance = this.instances[index];
- if (instance === emptyInstance)
- return;
+ var previousTerminator = this.getTerminatorAt(index - 1);
+ var terminator = this.getTerminatorAt(index);
+ if (previousTerminator === terminator)
+ return; // instance has zero nodes.
- this.instancePositionChangedFn_(instance.templateInstance_, index);
+ // We must use the first node of the instance, because any subsequent
+ // nodes may have been generated by sub-templates.
+ // TODO(rafaelw): This is brittle WRT instance mutation -- e.g. if the
+ // first node was removed by script.
+ var templateInstance = previousTerminator.nextSibling.templateInstance;
+ this.instancePositionChangedFn_(templateInstance, index);
},
reportInstancesMoved: function(splices) {
@@ -15875,17 +15806,16 @@ PointerGestureEvent.prototype.preventTap = function() {
if (offset == 0)
return;
- var length = this.instances.length;
+ var length = this.terminators.length / 2;
while (index < length) {
this.reportInstanceMoved(index);
index++;
}
},
- closeInstanceBindings: function(instance) {
- var bindings = instance.bindings_;
- for (var i = 0; i < bindings.length; i++) {
- bindings[i].close();
+ closeInstanceBindings: function(instanceBindings) {
+ for (var i = 0; i < instanceBindings.length; i++) {
+ instanceBindings[i].close();
}
},
@@ -15901,11 +15831,11 @@ PointerGestureEvent.prototype.preventTap = function() {
if (this.closed)
return;
this.unobserve();
- for (var i = 0; i < this.instances.length; i++) {
- this.closeInstanceBindings(this.instances[i]);
+ for (var i = 1; i < this.terminators.length; i += 2) {
+ this.closeInstanceBindings(this.terminators[i]);
}
- this.instances.length = 0;
+ this.terminators.length = 0;
this.closeDeps();
this.templateElement_.iterator_ = undefined;
this.closed = true;
@@ -16954,12 +16884,19 @@ PointerGestureEvent.prototype.preventTap = function() {
};
})(this);
-// Copyright (c) 2014 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
+// Copyright 2013 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
(function (global) {
'use strict';
@@ -17386,18 +17323,10 @@ PointerGestureEvent.prototype.preventTap = function() {
return this.getValue(model, undefined, filterRegistry);
var observer = new CompoundObserver();
- // captures deps.
- var firstValue = this.getValue(model, observer, filterRegistry);
- var firstTime = true;
+ this.getValue(model, observer, filterRegistry); // captures deps.
var self = this;
function valueFn() {
- // deps cannot have changed on first value retrieval.
- if (firstTime) {
- firstTime = false;
- return firstValue;
- }
-
if (self.dynamicDeps)
observer.startReset();
@@ -17541,23 +17470,6 @@ PointerGestureEvent.prototype.preventTap = function() {
}
}
- function isLiteralExpression(pathString) {
- switch (pathString) {
- case '':
- return false;
-
- case 'false':
- case 'null':
- case 'true':
- return true;
- }
-
- if (!isNaN(Number(pathString)))
- return true;
-
- return false;
- };
-
function PolymerExpressions() {}
PolymerExpressions.prototype = {
@@ -17601,7 +17513,7 @@ PointerGestureEvent.prototype.preventTap = function() {
return prepareEventBinding(path, name, this);
}
- if (!isLiteralExpression(pathString) && path.valid) {
+ if (path.valid) {
if (path.length == 1) {
return function(model, node, oneTime) {
if (oneTime)
@@ -17609,8 +17521,9 @@ PointerGestureEvent.prototype.preventTap = function() {
var scope = findScope(model, path[0]);
return new PathObserver(scope, path);
- };
+ }
}
+
return; // bail out early if pathString is simple path.
}
@@ -17673,17 +17586,14 @@ function flush() {
};
// polling dirty checker
-// flush periodically if platform does not have object observe.
-if (!Observer.hasObjectObserve) {
- var FLUSH_POLL_INTERVAL = 125;
- window.addEventListener('WebComponentsReady', function() {
- flush();
+var FLUSH_POLL_INTERVAL = 125;
+window.addEventListener('WebComponentsReady', function() {
+ flush();
+ // flush periodically if platform does not have object observe.
+ if (!Observer.hasObjectObserve) {
scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL);
- });
-} else {
- // make flush a no-op when we have Object.observe
- flush = function() {};
-}
+ }
+});
if (window.CustomElements && !CustomElements.useNative) {
var originalImportNode = Document.prototype.importNode;
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698