mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Test with ESLint enabled
Fix linter errors
This commit is contained in:
parent
c7554d9daa
commit
acdfc1e097
@ -15,6 +15,7 @@ before_script:
|
||||
- npm install -g bower
|
||||
- bower install
|
||||
script:
|
||||
- gulp lint
|
||||
- xvfb-run wct
|
||||
- "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
|
||||
env:
|
||||
|
@ -23,7 +23,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp",
|
||||
"test": "wct",
|
||||
"test": "gulp lint && wct",
|
||||
"test-build": "gulp switch && wct && gulp restore"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -1,389 +1,389 @@
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="../case-map.html">
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Scans a template to produce an annotation list that that associates
|
||||
* metadata culled from markup with tree locations
|
||||
* metadata and information to associate the metadata with nodes in an instance.
|
||||
*
|
||||
* Supported expressions include:
|
||||
*
|
||||
* Double-mustache annotations in text content. The annotation must be the only
|
||||
* content in the tag, compound expressions are not supported.
|
||||
*
|
||||
* <[tag]>{{annotation}}<[tag]>
|
||||
*
|
||||
* Double-escaped annotations in an attribute, either {{}} or [[]].
|
||||
*
|
||||
* <[tag] someAttribute="{{annotation}}" another="[[annotation]]"><[tag]>
|
||||
*
|
||||
* `on-` style event declarations.
|
||||
*
|
||||
* <[tag] on-<event-name>="annotation"><[tag]>
|
||||
*
|
||||
* Note that the `annotations` feature does not implement any behaviors
|
||||
* associated with these expressions, it only captures the data.
|
||||
*
|
||||
* Generated data-structure:
|
||||
*
|
||||
* [
|
||||
* {
|
||||
* id: '<id>',
|
||||
* events: [
|
||||
* {
|
||||
* name: '<name>'
|
||||
* value: '<annotation>'
|
||||
* }, ...
|
||||
* ],
|
||||
* bindings: [
|
||||
* {
|
||||
* kind: ['text'|'attribute'],
|
||||
* mode: ['{'|'['],
|
||||
* name: '<name>'
|
||||
* value: '<annotation>'
|
||||
* }, ...
|
||||
* ],
|
||||
* // TODO(sjmiles): this is annotation-parent, not node-parent
|
||||
* parent: <reference to parent annotation object>,
|
||||
* index: <integer index in parent's childNodes collection>
|
||||
* },
|
||||
* ...
|
||||
* ]
|
||||
*
|
||||
* @class Template feature
|
||||
*/
|
||||
|
||||
// null-array (shared empty array to avoid null-checks)
|
||||
Polymer.nar = [];
|
||||
|
||||
Polymer.Annotations = {
|
||||
|
||||
// preprocess-time
|
||||
|
||||
// construct and return a list of annotation records
|
||||
// by scanning `template`'s content
|
||||
//
|
||||
parseAnnotations: function(template) {
|
||||
var list = [];
|
||||
var content = template._content || template.content;
|
||||
this._parseNodeAnnotations(content, list,
|
||||
template.hasAttribute('strip-whitespace'));
|
||||
return list;
|
||||
},
|
||||
|
||||
// add annotations gleaned from subtree at `node` to `list`
|
||||
_parseNodeAnnotations: function(node, list, stripWhiteSpace) {
|
||||
return node.nodeType === Node.TEXT_NODE ?
|
||||
this._parseTextNodeAnnotation(node, list) :
|
||||
// TODO(sjmiles): are there other nodes we may encounter
|
||||
// that are not TEXT_NODE but also not ELEMENT?
|
||||
this._parseElementAnnotations(node, list, stripWhiteSpace);
|
||||
},
|
||||
|
||||
_bindingRegex: (function() {
|
||||
var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$-*]*' + ')';
|
||||
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
|
||||
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
|
||||
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
|
||||
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
|
||||
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
|
||||
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
|
||||
var ARGUMENT_LIST = '(?:' + '\\(\\s*' +
|
||||
'(?:' + ARGUMENTS + '?' + ')' +
|
||||
'\\)\\s*' + ')';
|
||||
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
|
||||
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
|
||||
var CLOSE_BRACKET = '(?:]]|}})';
|
||||
var NEGATE = '(?:(!)\\s*)?'; // Group 2
|
||||
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
|
||||
return new RegExp(EXPRESSION, "g");
|
||||
})(),
|
||||
|
||||
// TODO(kschaaf): We could modify this to allow an escape mechanism by
|
||||
// looking for the escape sequence in each of the matches and converting
|
||||
// the part back to a literal type, and then bailing if only literals
|
||||
// were found
|
||||
_parseBindings: function(text) {
|
||||
var re = this._bindingRegex;
|
||||
var parts = [];
|
||||
var lastIndex = 0;
|
||||
var m;
|
||||
// Example: "literal1{{prop}}literal2[[!compute(foo,bar)]]final"
|
||||
// Regex matches:
|
||||
// Iteration 1: Iteration 2:
|
||||
// m[1]: '{{' '[['
|
||||
// m[2]: '' '!'
|
||||
// m[3]: 'prop' 'compute(foo,bar)'
|
||||
while ((m = re.exec(text)) !== null) {
|
||||
// Add literal part
|
||||
if (m.index > lastIndex) {
|
||||
parts.push({literal: text.slice(lastIndex, m.index)});
|
||||
}
|
||||
// Add binding part
|
||||
// Mode (one-way or two)
|
||||
var mode = m[1][0];
|
||||
var negate = Boolean(m[2]);
|
||||
var value = m[3].trim();
|
||||
var customEvent, notifyEvent, colon;
|
||||
if (mode == '{' && (colon = value.indexOf('::')) > 0) {
|
||||
notifyEvent = value.substring(colon + 2);
|
||||
value = value.substring(0, colon);
|
||||
customEvent = true;
|
||||
}
|
||||
parts.push({
|
||||
compoundIndex: parts.length,
|
||||
value: value,
|
||||
mode: mode,
|
||||
negate: negate,
|
||||
event: notifyEvent,
|
||||
customEvent: customEvent
|
||||
});
|
||||
lastIndex = re.lastIndex;
|
||||
}
|
||||
// Add a final literal part
|
||||
if (lastIndex && lastIndex < text.length) {
|
||||
var literal = text.substring(lastIndex);
|
||||
if (literal) {
|
||||
parts.push({
|
||||
literal: literal
|
||||
});
|
||||
}
|
||||
}
|
||||
if (parts.length) {
|
||||
return parts;
|
||||
}
|
||||
},
|
||||
|
||||
_literalFromParts: function(parts) {
|
||||
var s = '';
|
||||
for (var i=0; i<parts.length; i++) {
|
||||
var literal = parts[i].literal;
|
||||
s += literal || '';
|
||||
}
|
||||
return s;
|
||||
},
|
||||
|
||||
// add annotations gleaned from TextNode `node` to `list`
|
||||
_parseTextNodeAnnotation: function(node, list) {
|
||||
var parts = this._parseBindings(node.textContent);
|
||||
if (parts) {
|
||||
// Initialize the textContent with any literal parts
|
||||
// NOTE: default to a space here so the textNode remains; some browsers
|
||||
// (IE) evacipate an empty textNode following cloneNode/importNode.
|
||||
node.textContent = this._literalFromParts(parts) || ' ';
|
||||
var annote = {
|
||||
bindings: [{
|
||||
kind: 'text',
|
||||
name: 'textContent',
|
||||
parts: parts,
|
||||
isCompound: parts.length !== 1
|
||||
}]
|
||||
};
|
||||
list.push(annote);
|
||||
return annote;
|
||||
}
|
||||
},
|
||||
|
||||
// add annotations gleaned from Element `node` to `list`
|
||||
_parseElementAnnotations: function(element, list, stripWhiteSpace) {
|
||||
var annote = {
|
||||
bindings: [],
|
||||
events: []
|
||||
};
|
||||
if (element.localName === 'content') {
|
||||
list._hasContent = true;
|
||||
}
|
||||
this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
|
||||
// TODO(sjmiles): is this for non-ELEMENT nodes? If so, we should
|
||||
// change the contract of this method, or filter these out above.
|
||||
if (element.attributes) {
|
||||
this._parseNodeAttributeAnnotations(element, annote, list);
|
||||
// TODO(sorvell): ad hoc callback for doing work on elements while
|
||||
// leveraging annotator's tree walk.
|
||||
// Consider adding an node callback registry and moving specific
|
||||
// processing out of this module.
|
||||
if (this.prepElement) {
|
||||
this.prepElement(element);
|
||||
}
|
||||
}
|
||||
if (annote.bindings.length || annote.events.length || annote.id) {
|
||||
list.push(annote);
|
||||
}
|
||||
return annote;
|
||||
},
|
||||
|
||||
// add annotations gleaned from children of `root` to `list`, `root`'s
|
||||
// `annote` is supplied as it is the annote.parent of added annotations
|
||||
_parseChildNodesAnnotations: function(root, annote, list, stripWhiteSpace) {
|
||||
if (root.firstChild) {
|
||||
var node = root.firstChild;
|
||||
var i = 0;
|
||||
while (node) {
|
||||
var next = node.nextSibling;
|
||||
if (node.localName === 'template' &&
|
||||
!node.hasAttribute('preserve-content')) {
|
||||
this._parseTemplate(node, i, list, annote);
|
||||
}
|
||||
// collapse adjacent textNodes: fixes an IE issue that can cause
|
||||
// text nodes to be inexplicably split =(
|
||||
// note that root.normalize() should work but does not so we do this
|
||||
// manually.
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
var n = next;
|
||||
while (n && (n.nodeType === Node.TEXT_NODE)) {
|
||||
node.textContent += n.textContent;
|
||||
next = n.nextSibling;
|
||||
root.removeChild(n);
|
||||
n = next;
|
||||
}
|
||||
// optionally strip whitespace
|
||||
if (stripWhiteSpace && !node.textContent.trim()) {
|
||||
root.removeChild(node);
|
||||
// decrement index since node is removed
|
||||
i--;
|
||||
}
|
||||
}
|
||||
// if this node didn't get evacipated, parse it.
|
||||
if (node.parentNode) {
|
||||
var childAnnotation = this._parseNodeAnnotations(node, list,
|
||||
stripWhiteSpace);
|
||||
if (childAnnotation) {
|
||||
childAnnotation.parent = annote;
|
||||
childAnnotation.index = i;
|
||||
}
|
||||
}
|
||||
node = next;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 1. Parse annotations from the template and memoize them on
|
||||
// content._notes (recurses into nested templates)
|
||||
// 2. Remove template.content and store it in annotation list, where it
|
||||
// will be the responsibility of the host to set it back to the template
|
||||
// (this is both an optimization to avoid re-stamping nested template
|
||||
// children and avoids a bug in Chrome where nested template children
|
||||
// upgrade)
|
||||
_parseTemplate: function(node, index, list, parent) {
|
||||
// TODO(sjmiles): simply altering the .content reference didn't
|
||||
// work (there was some confusion, might need verification)
|
||||
var content = document.createDocumentFragment();
|
||||
content._notes = this.parseAnnotations(node);
|
||||
content.appendChild(node.content);
|
||||
// TODO(sjmiles): using `nar` to avoid unnecessary allocation;
|
||||
// in general the handling of these arrays needs some cleanup
|
||||
// in this module
|
||||
list.push({
|
||||
bindings: Polymer.nar,
|
||||
events: Polymer.nar,
|
||||
templateContent: content,
|
||||
parent: parent,
|
||||
index: index
|
||||
});
|
||||
},
|
||||
|
||||
// add annotation data from attributes to the `annotation` for node `node`
|
||||
// TODO(sjmiles): the distinction between an `annotation` and
|
||||
// `annotation data` is not as clear as it could be
|
||||
_parseNodeAttributeAnnotations: function(node, annotation) {
|
||||
// Make copy of original attribute list, since the order may change
|
||||
// as attributes are added and removed
|
||||
var attrs = Array.prototype.slice.call(node.attributes);
|
||||
for (var i=attrs.length-1, a; (a=attrs[i]); i--) {
|
||||
var n = a.name;
|
||||
var v = a.value;
|
||||
var b;
|
||||
// events (on-*)
|
||||
if (n.slice(0, 3) === 'on-') {
|
||||
node.removeAttribute(n);
|
||||
annotation.events.push({
|
||||
name: n.slice(3),
|
||||
value: v
|
||||
});
|
||||
}
|
||||
// bindings (other attributes)
|
||||
else if (b = this._parseNodeAttributeAnnotation(node, n, v)) {
|
||||
annotation.bindings.push(b);
|
||||
}
|
||||
// static id
|
||||
else if (n === 'id') {
|
||||
annotation.id = v;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// construct annotation data from a generic attribute, or undefined
|
||||
_parseNodeAttributeAnnotation: function(node, name, value) {
|
||||
var parts = this._parseBindings(value);
|
||||
if (parts) {
|
||||
// Attribute or property
|
||||
var origName = name;
|
||||
var kind = 'property';
|
||||
if (name[name.length-1] == '$') {
|
||||
name = name.slice(0, -1);
|
||||
kind = 'attribute';
|
||||
}
|
||||
// Initialize attribute bindings with any literal parts
|
||||
var literal = this._literalFromParts(parts);
|
||||
if (literal && kind == 'attribute') {
|
||||
node.setAttribute(name, literal);
|
||||
}
|
||||
// Clear attribute before removing, since IE won't allow removing
|
||||
// `value` attribute if it previously had a value (can't
|
||||
// unconditionally set '' before removing since attributes with `$`
|
||||
// can't be set using setAttribute)
|
||||
if (node.localName === 'input' && origName === 'value') {
|
||||
node.setAttribute(origName, '');
|
||||
}
|
||||
// Remove annotation
|
||||
node.removeAttribute(origName);
|
||||
// Case hackery: attributes are lower-case, but bind targets
|
||||
// (properties) are case sensitive. Gambit is to map dash-case to
|
||||
// camel-case: `foo-bar` becomes `fooBar`.
|
||||
// Attribute bindings are excepted.
|
||||
if (kind === 'property') {
|
||||
name = Polymer.CaseMap.dashToCamelCase(name);
|
||||
}
|
||||
return {
|
||||
kind: kind,
|
||||
name: name,
|
||||
parts: parts,
|
||||
literal: literal,
|
||||
isCompound: parts.length !== 1
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// instance-time
|
||||
|
||||
findAnnotatedNode: function(root, annote) {
|
||||
// recursively ascend tree until we hit root
|
||||
var parent = annote.parent &&
|
||||
Polymer.Annotations.findAnnotatedNode(root, annote.parent);
|
||||
// unwind the stack, returning the indexed node at each level
|
||||
if (parent) {
|
||||
// note: marginally faster than indexing via childNodes
|
||||
// (http://jsperf.com/childnodes-lookup)
|
||||
for (var n=parent.firstChild, i=0; n; n=n.nextSibling) {
|
||||
if (annote.index === i++) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
</script>
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="../case-map.html">
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Scans a template to produce an annotation list that that associates
|
||||
* metadata culled from markup with tree locations
|
||||
* metadata and information to associate the metadata with nodes in an instance.
|
||||
*
|
||||
* Supported expressions include:
|
||||
*
|
||||
* Double-mustache annotations in text content. The annotation must be the only
|
||||
* content in the tag, compound expressions are not supported.
|
||||
*
|
||||
* <[tag]>{{annotation}}<[tag]>
|
||||
*
|
||||
* Double-escaped annotations in an attribute, either {{}} or [[]].
|
||||
*
|
||||
* <[tag] someAttribute="{{annotation}}" another="[[annotation]]"><[tag]>
|
||||
*
|
||||
* `on-` style event declarations.
|
||||
*
|
||||
* <[tag] on-<event-name>="annotation"><[tag]>
|
||||
*
|
||||
* Note that the `annotations` feature does not implement any behaviors
|
||||
* associated with these expressions, it only captures the data.
|
||||
*
|
||||
* Generated data-structure:
|
||||
*
|
||||
* [
|
||||
* {
|
||||
* id: '<id>',
|
||||
* events: [
|
||||
* {
|
||||
* name: '<name>'
|
||||
* value: '<annotation>'
|
||||
* }, ...
|
||||
* ],
|
||||
* bindings: [
|
||||
* {
|
||||
* kind: ['text'|'attribute'],
|
||||
* mode: ['{'|'['],
|
||||
* name: '<name>'
|
||||
* value: '<annotation>'
|
||||
* }, ...
|
||||
* ],
|
||||
* // TODO(sjmiles): this is annotation-parent, not node-parent
|
||||
* parent: <reference to parent annotation object>,
|
||||
* index: <integer index in parent's childNodes collection>
|
||||
* },
|
||||
* ...
|
||||
* ]
|
||||
*
|
||||
* @class Template feature
|
||||
*/
|
||||
|
||||
// null-array (shared empty array to avoid null-checks)
|
||||
Polymer.nar = [];
|
||||
|
||||
Polymer.Annotations = {
|
||||
|
||||
// preprocess-time
|
||||
|
||||
// construct and return a list of annotation records
|
||||
// by scanning `template`'s content
|
||||
//
|
||||
parseAnnotations: function(template) {
|
||||
var list = [];
|
||||
var content = template._content || template.content;
|
||||
this._parseNodeAnnotations(content, list,
|
||||
template.hasAttribute('strip-whitespace'));
|
||||
return list;
|
||||
},
|
||||
|
||||
// add annotations gleaned from subtree at `node` to `list`
|
||||
_parseNodeAnnotations: function(node, list, stripWhiteSpace) {
|
||||
return node.nodeType === Node.TEXT_NODE ?
|
||||
this._parseTextNodeAnnotation(node, list) :
|
||||
// TODO(sjmiles): are there other nodes we may encounter
|
||||
// that are not TEXT_NODE but also not ELEMENT?
|
||||
this._parseElementAnnotations(node, list, stripWhiteSpace);
|
||||
},
|
||||
|
||||
_bindingRegex: (function() {
|
||||
var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$-*]*' + ')';
|
||||
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
|
||||
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
|
||||
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
|
||||
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
|
||||
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
|
||||
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
|
||||
var ARGUMENT_LIST = '(?:' + '\\(\\s*' +
|
||||
'(?:' + ARGUMENTS + '?' + ')' +
|
||||
'\\)\\s*' + ')';
|
||||
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
|
||||
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
|
||||
var CLOSE_BRACKET = '(?:]]|}})';
|
||||
var NEGATE = '(?:(!)\\s*)?'; // Group 2
|
||||
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
|
||||
return new RegExp(EXPRESSION, "g");
|
||||
})(),
|
||||
|
||||
// TODO(kschaaf): We could modify this to allow an escape mechanism by
|
||||
// looking for the escape sequence in each of the matches and converting
|
||||
// the part back to a literal type, and then bailing if only literals
|
||||
// were found
|
||||
_parseBindings: function(text) {
|
||||
var re = this._bindingRegex;
|
||||
var parts = [];
|
||||
var lastIndex = 0;
|
||||
var m;
|
||||
// Example: "literal1{{prop}}literal2[[!compute(foo,bar)]]final"
|
||||
// Regex matches:
|
||||
// Iteration 1: Iteration 2:
|
||||
// m[1]: '{{' '[['
|
||||
// m[2]: '' '!'
|
||||
// m[3]: 'prop' 'compute(foo,bar)'
|
||||
while ((m = re.exec(text)) !== null) {
|
||||
// Add literal part
|
||||
if (m.index > lastIndex) {
|
||||
parts.push({literal: text.slice(lastIndex, m.index)});
|
||||
}
|
||||
// Add binding part
|
||||
// Mode (one-way or two)
|
||||
var mode = m[1][0];
|
||||
var negate = Boolean(m[2]);
|
||||
var value = m[3].trim();
|
||||
var customEvent, notifyEvent, colon;
|
||||
if (mode == '{' && (colon = value.indexOf('::')) > 0) {
|
||||
notifyEvent = value.substring(colon + 2);
|
||||
value = value.substring(0, colon);
|
||||
customEvent = true;
|
||||
}
|
||||
parts.push({
|
||||
compoundIndex: parts.length,
|
||||
value: value,
|
||||
mode: mode,
|
||||
negate: negate,
|
||||
event: notifyEvent,
|
||||
customEvent: customEvent
|
||||
});
|
||||
lastIndex = re.lastIndex;
|
||||
}
|
||||
// Add a final literal part
|
||||
if (lastIndex && lastIndex < text.length) {
|
||||
var literal = text.substring(lastIndex);
|
||||
if (literal) {
|
||||
parts.push({
|
||||
literal: literal
|
||||
});
|
||||
}
|
||||
}
|
||||
if (parts.length) {
|
||||
return parts;
|
||||
}
|
||||
},
|
||||
|
||||
_literalFromParts: function(parts) {
|
||||
var s = '';
|
||||
for (var i=0; i<parts.length; i++) {
|
||||
var literal = parts[i].literal;
|
||||
s += literal || '';
|
||||
}
|
||||
return s;
|
||||
},
|
||||
|
||||
// add annotations gleaned from TextNode `node` to `list`
|
||||
_parseTextNodeAnnotation: function(node, list) {
|
||||
var parts = this._parseBindings(node.textContent);
|
||||
if (parts) {
|
||||
// Initialize the textContent with any literal parts
|
||||
// NOTE: default to a space here so the textNode remains; some browsers
|
||||
// (IE) evacipate an empty textNode following cloneNode/importNode.
|
||||
node.textContent = this._literalFromParts(parts) || ' ';
|
||||
var annote = {
|
||||
bindings: [{
|
||||
kind: 'text',
|
||||
name: 'textContent',
|
||||
parts: parts,
|
||||
isCompound: parts.length !== 1
|
||||
}]
|
||||
};
|
||||
list.push(annote);
|
||||
return annote;
|
||||
}
|
||||
},
|
||||
|
||||
// add annotations gleaned from Element `node` to `list`
|
||||
_parseElementAnnotations: function(element, list, stripWhiteSpace) {
|
||||
var annote = {
|
||||
bindings: [],
|
||||
events: []
|
||||
};
|
||||
if (element.localName === 'content') {
|
||||
list._hasContent = true;
|
||||
}
|
||||
this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
|
||||
// TODO(sjmiles): is this for non-ELEMENT nodes? If so, we should
|
||||
// change the contract of this method, or filter these out above.
|
||||
if (element.attributes) {
|
||||
this._parseNodeAttributeAnnotations(element, annote, list);
|
||||
// TODO(sorvell): ad hoc callback for doing work on elements while
|
||||
// leveraging annotator's tree walk.
|
||||
// Consider adding an node callback registry and moving specific
|
||||
// processing out of this module.
|
||||
if (this.prepElement) {
|
||||
this.prepElement(element);
|
||||
}
|
||||
}
|
||||
if (annote.bindings.length || annote.events.length || annote.id) {
|
||||
list.push(annote);
|
||||
}
|
||||
return annote;
|
||||
},
|
||||
|
||||
// add annotations gleaned from children of `root` to `list`, `root`'s
|
||||
// `annote` is supplied as it is the annote.parent of added annotations
|
||||
_parseChildNodesAnnotations: function(root, annote, list, stripWhiteSpace) {
|
||||
if (root.firstChild) {
|
||||
var node = root.firstChild;
|
||||
var i = 0;
|
||||
while (node) {
|
||||
var next = node.nextSibling;
|
||||
if (node.localName === 'template' &&
|
||||
!node.hasAttribute('preserve-content')) {
|
||||
this._parseTemplate(node, i, list, annote);
|
||||
}
|
||||
// collapse adjacent textNodes: fixes an IE issue that can cause
|
||||
// text nodes to be inexplicably split =(
|
||||
// note that root.normalize() should work but does not so we do this
|
||||
// manually.
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
var n = next;
|
||||
while (n && (n.nodeType === Node.TEXT_NODE)) {
|
||||
node.textContent += n.textContent;
|
||||
next = n.nextSibling;
|
||||
root.removeChild(n);
|
||||
n = next;
|
||||
}
|
||||
// optionally strip whitespace
|
||||
if (stripWhiteSpace && !node.textContent.trim()) {
|
||||
root.removeChild(node);
|
||||
// decrement index since node is removed
|
||||
i--;
|
||||
}
|
||||
}
|
||||
// if this node didn't get evacipated, parse it.
|
||||
if (node.parentNode) {
|
||||
var childAnnotation = this._parseNodeAnnotations(node, list,
|
||||
stripWhiteSpace);
|
||||
if (childAnnotation) {
|
||||
childAnnotation.parent = annote;
|
||||
childAnnotation.index = i;
|
||||
}
|
||||
}
|
||||
node = next;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 1. Parse annotations from the template and memoize them on
|
||||
// content._notes (recurses into nested templates)
|
||||
// 2. Remove template.content and store it in annotation list, where it
|
||||
// will be the responsibility of the host to set it back to the template
|
||||
// (this is both an optimization to avoid re-stamping nested template
|
||||
// children and avoids a bug in Chrome where nested template children
|
||||
// upgrade)
|
||||
_parseTemplate: function(node, index, list, parent) {
|
||||
// TODO(sjmiles): simply altering the .content reference didn't
|
||||
// work (there was some confusion, might need verification)
|
||||
var content = document.createDocumentFragment();
|
||||
content._notes = this.parseAnnotations(node);
|
||||
content.appendChild(node.content);
|
||||
// TODO(sjmiles): using `nar` to avoid unnecessary allocation;
|
||||
// in general the handling of these arrays needs some cleanup
|
||||
// in this module
|
||||
list.push({
|
||||
bindings: Polymer.nar,
|
||||
events: Polymer.nar,
|
||||
templateContent: content,
|
||||
parent: parent,
|
||||
index: index
|
||||
});
|
||||
},
|
||||
|
||||
// add annotation data from attributes to the `annotation` for node `node`
|
||||
// TODO(sjmiles): the distinction between an `annotation` and
|
||||
// `annotation data` is not as clear as it could be
|
||||
_parseNodeAttributeAnnotations: function(node, annotation) {
|
||||
// Make copy of original attribute list, since the order may change
|
||||
// as attributes are added and removed
|
||||
var attrs = Array.prototype.slice.call(node.attributes);
|
||||
for (var i=attrs.length-1, a; (a=attrs[i]); i--) {
|
||||
var n = a.name;
|
||||
var v = a.value;
|
||||
var b;
|
||||
// events (on-*)
|
||||
if (n.slice(0, 3) === 'on-') {
|
||||
node.removeAttribute(n);
|
||||
annotation.events.push({
|
||||
name: n.slice(3),
|
||||
value: v
|
||||
});
|
||||
}
|
||||
// bindings (other attributes)
|
||||
else if ((b = this._parseNodeAttributeAnnotation(node, n, v))) {
|
||||
annotation.bindings.push(b);
|
||||
}
|
||||
// static id
|
||||
else if (n === 'id') {
|
||||
annotation.id = v;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// construct annotation data from a generic attribute, or undefined
|
||||
_parseNodeAttributeAnnotation: function(node, name, value) {
|
||||
var parts = this._parseBindings(value);
|
||||
if (parts) {
|
||||
// Attribute or property
|
||||
var origName = name;
|
||||
var kind = 'property';
|
||||
if (name[name.length-1] == '$') {
|
||||
name = name.slice(0, -1);
|
||||
kind = 'attribute';
|
||||
}
|
||||
// Initialize attribute bindings with any literal parts
|
||||
var literal = this._literalFromParts(parts);
|
||||
if (literal && kind == 'attribute') {
|
||||
node.setAttribute(name, literal);
|
||||
}
|
||||
// Clear attribute before removing, since IE won't allow removing
|
||||
// `value` attribute if it previously had a value (can't
|
||||
// unconditionally set '' before removing since attributes with `$`
|
||||
// can't be set using setAttribute)
|
||||
if (node.localName === 'input' && origName === 'value') {
|
||||
node.setAttribute(origName, '');
|
||||
}
|
||||
// Remove annotation
|
||||
node.removeAttribute(origName);
|
||||
// Case hackery: attributes are lower-case, but bind targets
|
||||
// (properties) are case sensitive. Gambit is to map dash-case to
|
||||
// camel-case: `foo-bar` becomes `fooBar`.
|
||||
// Attribute bindings are excepted.
|
||||
if (kind === 'property') {
|
||||
name = Polymer.CaseMap.dashToCamelCase(name);
|
||||
}
|
||||
return {
|
||||
kind: kind,
|
||||
name: name,
|
||||
parts: parts,
|
||||
literal: literal,
|
||||
isCompound: parts.length !== 1
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// instance-time
|
||||
|
||||
findAnnotatedNode: function(root, annote) {
|
||||
// recursively ascend tree until we hit root
|
||||
var parent = annote.parent &&
|
||||
Polymer.Annotations.findAnnotatedNode(root, annote.parent);
|
||||
// unwind the stack, returning the indexed node at each level
|
||||
if (parent) {
|
||||
// note: marginally faster than indexing via childNodes
|
||||
// (http://jsperf.com/childnodes-lookup)
|
||||
for (var n=parent.firstChild, i=0; n; n=n.nextSibling) {
|
||||
if (annote.index === i++) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
</script>
|
||||
|
@ -10,7 +10,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
<script>
|
||||
|
||||
Polymer.ArraySplice = (function() {
|
||||
|
||||
|
||||
function newSplice(index, removed, addedCount) {
|
||||
return {
|
||||
index: index,
|
||||
@ -56,8 +56,8 @@ Polymer.ArraySplice = (function() {
|
||||
for (var j = 0; j < columnCount; j++)
|
||||
distances[0][j] = j;
|
||||
|
||||
for (var i = 1; i < rowCount; i++) {
|
||||
for (var j = 1; j < columnCount; j++) {
|
||||
for (i = 1; i < rowCount; i++) {
|
||||
for (j = 1; j < columnCount; j++) {
|
||||
if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
|
||||
distances[i][j] = distances[i - 1][j - 1];
|
||||
else {
|
||||
@ -181,7 +181,7 @@ Polymer.ArraySplice = (function() {
|
||||
this.calcEditDistances(current, currentStart, currentEnd,
|
||||
old, oldStart, oldEnd));
|
||||
|
||||
var splice = undefined;
|
||||
splice = undefined;
|
||||
var splices = [];
|
||||
var index = currentStart;
|
||||
var oldIndex = oldStart;
|
||||
@ -259,4 +259,4 @@ Polymer.ArraySplice = (function() {
|
||||
return new ArraySplice();
|
||||
|
||||
})();
|
||||
</script>
|
||||
</script>
|
||||
|
@ -23,7 +23,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
_notifyChange: function(source, event, value) {
|
||||
value = value === undefined ? this[source] : value;
|
||||
event = event || Polymer.CaseMap.camelToDashCase(source) + '-changed';
|
||||
this.fire(event, {value: value},
|
||||
this.fire(event, {value: value},
|
||||
{bubbles: false, cancelable: false, _useCache: true});
|
||||
},
|
||||
|
||||
@ -221,8 +221,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
} else {
|
||||
// TODO(sorvell): even though we have a `value` argument, we *must*
|
||||
// lookup the current value of the property. Multiple listeners and
|
||||
// queued events during configuration can theoretically lead to
|
||||
// divergence of the passed value from the current value, but we
|
||||
// queued events during configuration can theoretically lead to
|
||||
// divergence of the passed value from the current value, but we
|
||||
// really need to track down a specific case where this happens.
|
||||
value = target[property];
|
||||
if (!isStructured) {
|
||||
@ -256,7 +256,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
//if (node._prepParentProperties || !node._propertyInfo || (p && p.notify)) {
|
||||
this._addNotifyListener(node, inst, info.event, info.changedFn);
|
||||
//}
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// TODO(sorvell): note, adding these synchronously may impact performance,
|
||||
|
@ -50,7 +50,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
removeKey: function(key) {
|
||||
if (key = this._parseKey(key)) {
|
||||
if ((key = this._parseKey(key))) {
|
||||
this._removeFromMap(this.store[key]);
|
||||
delete this.store[key];
|
||||
}
|
||||
@ -95,7 +95,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
setItem: function(key, item) {
|
||||
if (key = this._parseKey(key)) {
|
||||
if ((key = this._parseKey(key))) {
|
||||
var old = this.store[key];
|
||||
if (old) {
|
||||
this._removeFromMap(old);
|
||||
@ -110,7 +110,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
getItem: function(key) {
|
||||
if (key = this._parseKey(key)) {
|
||||
if ((key = this._parseKey(key))) {
|
||||
return this.store[key];
|
||||
}
|
||||
},
|
||||
@ -140,7 +140,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
key = this.getKey(s.removed[j]);
|
||||
keyMap[key] = keyMap[key] ? null : -1;
|
||||
}
|
||||
for (var j=0; j<s.addedCount; j++) {
|
||||
for (j=0; j<s.addedCount; j++) {
|
||||
var item = this.userArray[s.index + j];
|
||||
key = this.getKey(item);
|
||||
key = (key === undefined) ? this.add(item) : key;
|
||||
@ -154,7 +154,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// Convert added/removed key map to added/removed arrays
|
||||
var removed = [];
|
||||
var added = [];
|
||||
for (var key in keyMap) {
|
||||
for (key in keyMap) {
|
||||
if (keyMap[key] < 0) {
|
||||
this.removeKey(key);
|
||||
removed.push(key);
|
||||
|
@ -71,7 +71,6 @@ Note, all features of `custom-style` are available when defining styles as part
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
var nativeShadow = Polymer.Settings.useNativeShadow;
|
||||
var propertyUtils = Polymer.StyleProperties;
|
||||
var styleUtil = Polymer.StyleUtil;
|
||||
var cssParse = Polymer.CssParse;
|
||||
|
@ -1,268 +1,264 @@
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="settings.html">
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var DomApi = Polymer.DomApi.ctor;
|
||||
var Settings = Polymer.Settings;
|
||||
var hasDomApi = Polymer.DomApi.hasDomApi;
|
||||
|
||||
/**
|
||||
* DomApi.EffectiveNodesObserver tracks changes to an element's
|
||||
* effective child nodes, the same list returned from
|
||||
* `Polymer.dom(node).getEffectiveChildNodes()`.
|
||||
* It is not meant to be used directly; it is used by
|
||||
* `Polymer.dom(node).observeNodes(callback)` to observe changes.
|
||||
*/
|
||||
DomApi.EffectiveNodesObserver = function(domApi) {
|
||||
this.domApi = domApi;
|
||||
this.node = this.domApi.node;
|
||||
this._listeners = [];
|
||||
};
|
||||
|
||||
DomApi.EffectiveNodesObserver.prototype = {
|
||||
|
||||
addListener: function(callback) {
|
||||
if (!this._isSetup) {
|
||||
this._setup();
|
||||
this._isSetup = true;
|
||||
}
|
||||
var listener = {fn: callback, _nodes: []};
|
||||
this._listeners.push(listener);
|
||||
this._scheduleNotify();
|
||||
return listener;
|
||||
},
|
||||
|
||||
removeListener: function(handle) {
|
||||
var i = this._listeners.indexOf(handle);
|
||||
if (i >= 0) {
|
||||
this._listeners.splice(i, 1);
|
||||
handle._nodes = [];
|
||||
}
|
||||
if (!this._hasListeners()) {
|
||||
this._cleanup();
|
||||
this._isSetup = false;
|
||||
}
|
||||
},
|
||||
|
||||
_setup: function() {
|
||||
this._observeContentElements(this.domApi.childNodes);
|
||||
},
|
||||
|
||||
_cleanup: function() {
|
||||
this._unobserveContentElements(this.domApi.childNodes);
|
||||
},
|
||||
|
||||
_hasListeners: function() {
|
||||
return Boolean(this._listeners.length);
|
||||
},
|
||||
|
||||
_scheduleNotify: function() {
|
||||
if (this._debouncer) {
|
||||
this._debouncer.stop();
|
||||
}
|
||||
this._debouncer = Polymer.Debounce(this._debouncer,
|
||||
this._notify);
|
||||
this._debouncer.context = this;
|
||||
Polymer.dom.addDebouncer(this._debouncer);
|
||||
},
|
||||
|
||||
notify: function() {
|
||||
if (this._hasListeners()) {
|
||||
this._scheduleNotify();
|
||||
}
|
||||
},
|
||||
|
||||
_notify: function(mxns) {
|
||||
this._beforeCallListeners();
|
||||
this._callListeners();
|
||||
},
|
||||
|
||||
_beforeCallListeners: function() {
|
||||
this._updateContentElements();
|
||||
},
|
||||
|
||||
_updateContentElements: function() {
|
||||
this._observeContentElements(this.domApi.childNodes);
|
||||
},
|
||||
|
||||
_observeContentElements: function(elements) {
|
||||
for (var i=0, n; (i < elements.length) && (n=elements[i]); i++) {
|
||||
if (this._isContent(n)) {
|
||||
n.__observeNodesMap = n.__observeNodesMap || new WeakMap();
|
||||
if (!n.__observeNodesMap.has(this)) {
|
||||
n.__observeNodesMap.set(this, this._observeContent(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_observeContent: function(content) {
|
||||
var self = this;
|
||||
var h = Polymer.dom(content).observeNodes(function() {
|
||||
self._scheduleNotify();
|
||||
});
|
||||
h._avoidChangeCalculation = true;
|
||||
return h;
|
||||
},
|
||||
|
||||
_unobserveContentElements: function(elements) {
|
||||
for (var i=0, n, h; (i < elements.length) && (n=elements[i]); i++) {
|
||||
if (this._isContent(n)) {
|
||||
h = n.__observeNodesMap.get(this);
|
||||
if (h) {
|
||||
Polymer.dom(n).unobserveNodes(h);
|
||||
n.__observeNodesMap.delete(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_isContent: function(node) {
|
||||
return (node.localName === 'content');
|
||||
},
|
||||
|
||||
_callListeners: function() {
|
||||
var o$ = this._listeners;
|
||||
var nodes = this._getEffectiveNodes();
|
||||
for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) {
|
||||
var info = this._generateListenerInfo(o, nodes);
|
||||
if (info || o._alwaysNotify) {
|
||||
this._callListener(o, info);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getEffectiveNodes: function() {
|
||||
return this.domApi.getEffectiveChildNodes()
|
||||
},
|
||||
|
||||
_generateListenerInfo: function(listener, newNodes) {
|
||||
if (listener._avoidChangeCalculation) {
|
||||
return true;
|
||||
}
|
||||
var oldNodes = listener._nodes;
|
||||
var info = {
|
||||
target: this.node,
|
||||
addedNodes: [],
|
||||
removedNodes: []
|
||||
};
|
||||
var splices = Polymer.ArraySplice.calculateSplices(newNodes, oldNodes);
|
||||
// process removals
|
||||
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (var j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {
|
||||
info.removedNodes.push(n);
|
||||
}
|
||||
}
|
||||
// process adds
|
||||
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (var j=s.index; j < s.index + s.addedCount; j++) {
|
||||
info.addedNodes.push(newNodes[j]);
|
||||
}
|
||||
}
|
||||
// update cache
|
||||
listener._nodes = newNodes;
|
||||
if (info.addedNodes.length || info.removedNodes.length) {
|
||||
return info;
|
||||
}
|
||||
},
|
||||
|
||||
_callListener: function(listener, info) {
|
||||
return listener.fn.call(this.node, info);
|
||||
},
|
||||
|
||||
enableShadowAttributeTracking: function() {}
|
||||
|
||||
};
|
||||
|
||||
if (Settings.useShadow) {
|
||||
|
||||
var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
|
||||
var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
|
||||
|
||||
var beforeCallListeners = DomApi.EffectiveNodesObserver
|
||||
.prototype._beforeCallListeners;
|
||||
|
||||
Polymer.Base.extend(DomApi.EffectiveNodesObserver.prototype, {
|
||||
|
||||
_setup: function() {
|
||||
if (!this._observer) {
|
||||
var self = this;
|
||||
this._mutationHandler = function(mxns) {
|
||||
if (mxns && mxns.length) {
|
||||
self._scheduleNotify();
|
||||
}
|
||||
};
|
||||
this._observer = new MutationObserver(this._mutationHandler);
|
||||
this._boundFlush = function() {
|
||||
self._flush();
|
||||
}
|
||||
Polymer.dom.addStaticFlush(this._boundFlush);
|
||||
// NOTE: subtree true is way too aggressive, but it easily catches
|
||||
// attribute changes on children. These changes otherwise require
|
||||
// attribute observers on every child. Testing has shown this
|
||||
// approach to be more efficient.
|
||||
// TODO(sorvell): do we still need to include an option to defeat
|
||||
// attribute tracking?
|
||||
this._observer.observe(this.node, { childList: true });
|
||||
}
|
||||
baseSetup.call(this);
|
||||
},
|
||||
|
||||
_cleanup: function() {
|
||||
this._observer.disconnect();
|
||||
this._observer = null;
|
||||
this._mutationHandler = null;
|
||||
Polymer.dom.removeStaticFlush(this._boundFlush);
|
||||
baseCleanup.call(this);
|
||||
},
|
||||
|
||||
_flush: function() {
|
||||
if (this._observer) {
|
||||
this._mutationHandler(this._observer.takeRecords());
|
||||
}
|
||||
},
|
||||
|
||||
enableShadowAttributeTracking: function() {
|
||||
if (this._observer) {
|
||||
// provoke all listeners needed for <content> observation
|
||||
// to always call listeners when no-op changes occur (which may
|
||||
// affect lower distributions.
|
||||
this._makeContentListenersAlwaysNotify();
|
||||
this._observer.disconnect();
|
||||
this._observer.observe(this.node, {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
subtree: true
|
||||
});
|
||||
var root = this.domApi.getOwnerRoot();
|
||||
var host = root && root.host;
|
||||
if (host && Polymer.dom(host).observer) {
|
||||
Polymer.dom(host).observer.enableShadowAttributeTracking();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_makeContentListenersAlwaysNotify: function() {
|
||||
for (var i=0, h; i < this._listeners.length ; i++) {
|
||||
h = this._listeners[i];
|
||||
h._alwaysNotify = h._isContentListener;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="settings.html">
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var DomApi = Polymer.DomApi.ctor;
|
||||
var Settings = Polymer.Settings;
|
||||
|
||||
/**
|
||||
* DomApi.EffectiveNodesObserver tracks changes to an element's
|
||||
* effective child nodes, the same list returned from
|
||||
* `Polymer.dom(node).getEffectiveChildNodes()`.
|
||||
* It is not meant to be used directly; it is used by
|
||||
* `Polymer.dom(node).observeNodes(callback)` to observe changes.
|
||||
*/
|
||||
DomApi.EffectiveNodesObserver = function(domApi) {
|
||||
this.domApi = domApi;
|
||||
this.node = this.domApi.node;
|
||||
this._listeners = [];
|
||||
};
|
||||
|
||||
DomApi.EffectiveNodesObserver.prototype = {
|
||||
|
||||
addListener: function(callback) {
|
||||
if (!this._isSetup) {
|
||||
this._setup();
|
||||
this._isSetup = true;
|
||||
}
|
||||
var listener = {fn: callback, _nodes: []};
|
||||
this._listeners.push(listener);
|
||||
this._scheduleNotify();
|
||||
return listener;
|
||||
},
|
||||
|
||||
removeListener: function(handle) {
|
||||
var i = this._listeners.indexOf(handle);
|
||||
if (i >= 0) {
|
||||
this._listeners.splice(i, 1);
|
||||
handle._nodes = [];
|
||||
}
|
||||
if (!this._hasListeners()) {
|
||||
this._cleanup();
|
||||
this._isSetup = false;
|
||||
}
|
||||
},
|
||||
|
||||
_setup: function() {
|
||||
this._observeContentElements(this.domApi.childNodes);
|
||||
},
|
||||
|
||||
_cleanup: function() {
|
||||
this._unobserveContentElements(this.domApi.childNodes);
|
||||
},
|
||||
|
||||
_hasListeners: function() {
|
||||
return Boolean(this._listeners.length);
|
||||
},
|
||||
|
||||
_scheduleNotify: function() {
|
||||
if (this._debouncer) {
|
||||
this._debouncer.stop();
|
||||
}
|
||||
this._debouncer = Polymer.Debounce(this._debouncer,
|
||||
this._notify);
|
||||
this._debouncer.context = this;
|
||||
Polymer.dom.addDebouncer(this._debouncer);
|
||||
},
|
||||
|
||||
notify: function() {
|
||||
if (this._hasListeners()) {
|
||||
this._scheduleNotify();
|
||||
}
|
||||
},
|
||||
|
||||
_notify: function() {
|
||||
this._beforeCallListeners();
|
||||
this._callListeners();
|
||||
},
|
||||
|
||||
_beforeCallListeners: function() {
|
||||
this._updateContentElements();
|
||||
},
|
||||
|
||||
_updateContentElements: function() {
|
||||
this._observeContentElements(this.domApi.childNodes);
|
||||
},
|
||||
|
||||
_observeContentElements: function(elements) {
|
||||
for (var i=0, n; (i < elements.length) && (n=elements[i]); i++) {
|
||||
if (this._isContent(n)) {
|
||||
n.__observeNodesMap = n.__observeNodesMap || new WeakMap();
|
||||
if (!n.__observeNodesMap.has(this)) {
|
||||
n.__observeNodesMap.set(this, this._observeContent(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_observeContent: function(content) {
|
||||
var self = this;
|
||||
var h = Polymer.dom(content).observeNodes(function() {
|
||||
self._scheduleNotify();
|
||||
});
|
||||
h._avoidChangeCalculation = true;
|
||||
return h;
|
||||
},
|
||||
|
||||
_unobserveContentElements: function(elements) {
|
||||
for (var i=0, n, h; (i < elements.length) && (n=elements[i]); i++) {
|
||||
if (this._isContent(n)) {
|
||||
h = n.__observeNodesMap.get(this);
|
||||
if (h) {
|
||||
Polymer.dom(n).unobserveNodes(h);
|
||||
n.__observeNodesMap.delete(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_isContent: function(node) {
|
||||
return (node.localName === 'content');
|
||||
},
|
||||
|
||||
_callListeners: function() {
|
||||
var o$ = this._listeners;
|
||||
var nodes = this._getEffectiveNodes();
|
||||
for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) {
|
||||
var info = this._generateListenerInfo(o, nodes);
|
||||
if (info || o._alwaysNotify) {
|
||||
this._callListener(o, info);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getEffectiveNodes: function() {
|
||||
return this.domApi.getEffectiveChildNodes()
|
||||
},
|
||||
|
||||
_generateListenerInfo: function(listener, newNodes) {
|
||||
if (listener._avoidChangeCalculation) {
|
||||
return true;
|
||||
}
|
||||
var oldNodes = listener._nodes;
|
||||
var info = {
|
||||
target: this.node,
|
||||
addedNodes: [],
|
||||
removedNodes: []
|
||||
};
|
||||
var splices = Polymer.ArraySplice.calculateSplices(newNodes, oldNodes);
|
||||
// process removals
|
||||
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (var j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {
|
||||
info.removedNodes.push(n);
|
||||
}
|
||||
}
|
||||
// process adds
|
||||
for (i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (j=s.index; j < s.index + s.addedCount; j++) {
|
||||
info.addedNodes.push(newNodes[j]);
|
||||
}
|
||||
}
|
||||
// update cache
|
||||
listener._nodes = newNodes;
|
||||
if (info.addedNodes.length || info.removedNodes.length) {
|
||||
return info;
|
||||
}
|
||||
},
|
||||
|
||||
_callListener: function(listener, info) {
|
||||
return listener.fn.call(this.node, info);
|
||||
},
|
||||
|
||||
enableShadowAttributeTracking: function() {}
|
||||
|
||||
};
|
||||
|
||||
if (Settings.useShadow) {
|
||||
|
||||
var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
|
||||
var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
|
||||
|
||||
Polymer.Base.extend(DomApi.EffectiveNodesObserver.prototype, {
|
||||
|
||||
_setup: function() {
|
||||
if (!this._observer) {
|
||||
var self = this;
|
||||
this._mutationHandler = function(mxns) {
|
||||
if (mxns && mxns.length) {
|
||||
self._scheduleNotify();
|
||||
}
|
||||
};
|
||||
this._observer = new MutationObserver(this._mutationHandler);
|
||||
this._boundFlush = function() {
|
||||
self._flush();
|
||||
}
|
||||
Polymer.dom.addStaticFlush(this._boundFlush);
|
||||
// NOTE: subtree true is way too aggressive, but it easily catches
|
||||
// attribute changes on children. These changes otherwise require
|
||||
// attribute observers on every child. Testing has shown this
|
||||
// approach to be more efficient.
|
||||
// TODO(sorvell): do we still need to include an option to defeat
|
||||
// attribute tracking?
|
||||
this._observer.observe(this.node, { childList: true });
|
||||
}
|
||||
baseSetup.call(this);
|
||||
},
|
||||
|
||||
_cleanup: function() {
|
||||
this._observer.disconnect();
|
||||
this._observer = null;
|
||||
this._mutationHandler = null;
|
||||
Polymer.dom.removeStaticFlush(this._boundFlush);
|
||||
baseCleanup.call(this);
|
||||
},
|
||||
|
||||
_flush: function() {
|
||||
if (this._observer) {
|
||||
this._mutationHandler(this._observer.takeRecords());
|
||||
}
|
||||
},
|
||||
|
||||
enableShadowAttributeTracking: function() {
|
||||
if (this._observer) {
|
||||
// provoke all listeners needed for <content> observation
|
||||
// to always call listeners when no-op changes occur (which may
|
||||
// affect lower distributions.
|
||||
this._makeContentListenersAlwaysNotify();
|
||||
this._observer.disconnect();
|
||||
this._observer.observe(this.node, {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
subtree: true
|
||||
});
|
||||
var root = this.domApi.getOwnerRoot();
|
||||
var host = root && root.host;
|
||||
if (host && Polymer.dom(host).observer) {
|
||||
Polymer.dom(host).observer.enableShadowAttributeTracking();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_makeContentListenersAlwaysNotify: function() {
|
||||
for (var i=0, h; i < this._listeners.length ; i++) {
|
||||
h = this._listeners[i];
|
||||
h._alwaysNotify = h._isContentListener;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
@ -93,7 +93,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
if (root) {
|
||||
// note: we always need to see if an insertion point is added
|
||||
// since this saves logical tree info; however, invalidation state
|
||||
// needs
|
||||
// needs
|
||||
var ipAdded = this._maybeAddInsertionPoint(node, this.node);
|
||||
// invalidate insertion points IFF not already invalid!
|
||||
if (!root._invalidInsertionPoints) {
|
||||
@ -107,14 +107,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// if not distributing and not adding to host, do a fast path addition
|
||||
var handled = this._maybeDistribute(node) ||
|
||||
this.node.shadyRoot;
|
||||
// if shady is handling this node,
|
||||
// if shady is handling this node,
|
||||
// the actual dom may not be removed if the node or fragment contents
|
||||
// remain undistributed so we ensure removal here.
|
||||
// NOTE: we only remove from existing location iff shady dom is involved.
|
||||
// This is because a node fragment is passed to the native add method
|
||||
// which expects to see fragment children. Regular elements must also
|
||||
// use this check because not doing so causes separation of
|
||||
// attached/detached and breaks, for example,
|
||||
// use this check because not doing so causes separation of
|
||||
// attached/detached and breaks, for example,
|
||||
// dom-if's attached/detached checks.
|
||||
if (handled) {
|
||||
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
||||
@ -137,7 +137,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
*/
|
||||
removeChild: function(node) {
|
||||
if (TreeApi.Logical.getParentNode(node) !== this.node) {
|
||||
throw Error('The node to be removed is not a child of this node: ' +
|
||||
throw Error('The node to be removed is not a child of this node: ' +
|
||||
node);
|
||||
}
|
||||
if (!this._removeNode(node)) {
|
||||
@ -154,7 +154,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
return node;
|
||||
},
|
||||
|
||||
// Try to remove node: update logical info and perform distribution iff
|
||||
// Try to remove node: update logical info and perform distribution iff
|
||||
// needed. Return true if the removal has been handled.
|
||||
// note that it's possible for both the node's host and its parent
|
||||
// to require distribution... both cases are handled here.
|
||||
@ -214,7 +214,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
// memo-ize result for performance but only memo-ize a false-y
|
||||
// result if node is in the document. This avoids a problem where a root
|
||||
// can be cached while an element is inside a fragment.
|
||||
// can be cached while an element is inside a fragment.
|
||||
// If this happens and we cache the result, the value can become stale
|
||||
// because for perf we avoid processing the subtree of added fragments.
|
||||
if (root || document.documentElement.contains(node)) {
|
||||
@ -298,7 +298,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
_nodeNeedsDistribution: function(node) {
|
||||
return node && node.shadyRoot &&
|
||||
return node && node.shadyRoot &&
|
||||
DomApi.hasInsertionPoint(node.shadyRoot);
|
||||
},
|
||||
|
||||
@ -587,7 +587,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
return this.node.textContent;
|
||||
} else {
|
||||
var tc = [];
|
||||
for (var i = 0, cn = this.childNodes, c; c = cn[i]; i++) {
|
||||
for (var i = 0, cn = this.childNodes, c; (c = cn[i]); i++) {
|
||||
if (c.nodeType !== Node.COMMENT_NODE) {
|
||||
tc.push(c.textContent);
|
||||
}
|
||||
|
@ -1,131 +1,131 @@
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<script>
|
||||
|
||||
Polymer.domInnerHTML = (function() {
|
||||
|
||||
// Cribbed from ShadowDOM polyfill
|
||||
// https://github.com/webcomponents/webcomponentsjs/blob/master/src/ShadowDOM/wrappers/HTMLElement.js#L28
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// innerHTML and outerHTML
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
|
||||
var escapeAttrRegExp = /[&\u00A0"]/g;
|
||||
var escapeDataRegExp = /[&\u00A0<>]/g;
|
||||
|
||||
function escapeReplace(c) {
|
||||
switch (c) {
|
||||
case '&':
|
||||
return '&';
|
||||
case '<':
|
||||
return '<';
|
||||
case '>':
|
||||
return '>';
|
||||
case '"':
|
||||
return '"';
|
||||
case '\u00A0':
|
||||
return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
function escapeAttr(s) {
|
||||
return s.replace(escapeAttrRegExp, escapeReplace);
|
||||
}
|
||||
|
||||
function escapeData(s) {
|
||||
return s.replace(escapeDataRegExp, escapeReplace);
|
||||
}
|
||||
|
||||
function makeSet(arr) {
|
||||
var set = {};
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
set[arr[i]] = true;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#void-elements
|
||||
var voidElements = makeSet([
|
||||
'area',
|
||||
'base',
|
||||
'br',
|
||||
'col',
|
||||
'command',
|
||||
'embed',
|
||||
'hr',
|
||||
'img',
|
||||
'input',
|
||||
'keygen',
|
||||
'link',
|
||||
'meta',
|
||||
'param',
|
||||
'source',
|
||||
'track',
|
||||
'wbr'
|
||||
]);
|
||||
|
||||
var plaintextParents = makeSet([
|
||||
'style',
|
||||
'script',
|
||||
'xmp',
|
||||
'iframe',
|
||||
'noembed',
|
||||
'noframes',
|
||||
'plaintext',
|
||||
'noscript'
|
||||
]);
|
||||
|
||||
function getOuterHTML(node, parentNode, composed) {
|
||||
switch (node.nodeType) {
|
||||
case Node.ELEMENT_NODE:
|
||||
//var tagName = node.tagName.toLowerCase();
|
||||
var tagName = node.localName;
|
||||
var s = '<' + tagName;
|
||||
var attrs = node.attributes;
|
||||
for (var i = 0, attr; attr = attrs[i]; i++) {
|
||||
s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
|
||||
}
|
||||
s += '>';
|
||||
if (voidElements[tagName]) {
|
||||
return s;
|
||||
}
|
||||
return s + getInnerHTML(node, composed) + '</' + tagName + '>';
|
||||
case Node.TEXT_NODE:
|
||||
var data = node.data;
|
||||
if (parentNode && plaintextParents[parentNode.localName]) {
|
||||
return data;
|
||||
}
|
||||
return escapeData(data);
|
||||
case Node.COMMENT_NODE:
|
||||
return '<!--' + node.data + '-->';
|
||||
default:
|
||||
console.error(node);
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
function getInnerHTML(node, composed) {
|
||||
if (node instanceof HTMLTemplateElement)
|
||||
node = node.content;
|
||||
var s = '';
|
||||
var c$ = Polymer.dom(node).childNodes;
|
||||
for (var i=0, l=c$.length, child; (i<l) && (child=c$[i]); i++) {
|
||||
s += getOuterHTML(child, node, composed);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
return {
|
||||
getInnerHTML: getInnerHTML
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<script>
|
||||
|
||||
Polymer.domInnerHTML = (function() {
|
||||
|
||||
// Cribbed from ShadowDOM polyfill
|
||||
// https://github.com/webcomponents/webcomponentsjs/blob/master/src/ShadowDOM/wrappers/HTMLElement.js#L28
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// innerHTML and outerHTML
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
|
||||
var escapeAttrRegExp = /[&\u00A0"]/g;
|
||||
var escapeDataRegExp = /[&\u00A0<>]/g;
|
||||
|
||||
function escapeReplace(c) {
|
||||
switch (c) {
|
||||
case '&':
|
||||
return '&';
|
||||
case '<':
|
||||
return '<';
|
||||
case '>':
|
||||
return '>';
|
||||
case '"':
|
||||
return '"';
|
||||
case '\u00A0':
|
||||
return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
function escapeAttr(s) {
|
||||
return s.replace(escapeAttrRegExp, escapeReplace);
|
||||
}
|
||||
|
||||
function escapeData(s) {
|
||||
return s.replace(escapeDataRegExp, escapeReplace);
|
||||
}
|
||||
|
||||
function makeSet(arr) {
|
||||
var set = {};
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
set[arr[i]] = true;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#void-elements
|
||||
var voidElements = makeSet([
|
||||
'area',
|
||||
'base',
|
||||
'br',
|
||||
'col',
|
||||
'command',
|
||||
'embed',
|
||||
'hr',
|
||||
'img',
|
||||
'input',
|
||||
'keygen',
|
||||
'link',
|
||||
'meta',
|
||||
'param',
|
||||
'source',
|
||||
'track',
|
||||
'wbr'
|
||||
]);
|
||||
|
||||
var plaintextParents = makeSet([
|
||||
'style',
|
||||
'script',
|
||||
'xmp',
|
||||
'iframe',
|
||||
'noembed',
|
||||
'noframes',
|
||||
'plaintext',
|
||||
'noscript'
|
||||
]);
|
||||
|
||||
function getOuterHTML(node, parentNode, composed) {
|
||||
switch (node.nodeType) {
|
||||
case Node.ELEMENT_NODE:
|
||||
//var tagName = node.tagName.toLowerCase();
|
||||
var tagName = node.localName;
|
||||
var s = '<' + tagName;
|
||||
var attrs = node.attributes;
|
||||
for (var i = 0, attr; (attr = attrs[i]); i++) {
|
||||
s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
|
||||
}
|
||||
s += '>';
|
||||
if (voidElements[tagName]) {
|
||||
return s;
|
||||
}
|
||||
return s + getInnerHTML(node, composed) + '</' + tagName + '>';
|
||||
case Node.TEXT_NODE:
|
||||
var data = node.data;
|
||||
if (parentNode && plaintextParents[parentNode.localName]) {
|
||||
return data;
|
||||
}
|
||||
return escapeData(data);
|
||||
case Node.COMMENT_NODE:
|
||||
return '<!--' + node.data + '-->';
|
||||
default:
|
||||
console.error(node);
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
function getInnerHTML(node, composed) {
|
||||
if (node instanceof HTMLTemplateElement)
|
||||
node = node.content;
|
||||
var s = '';
|
||||
var c$ = Polymer.dom(node).childNodes;
|
||||
for (var i=0, l=c$.length, child; (i<l) && (child=c$[i]); i++) {
|
||||
s += getOuterHTML(child, node, composed);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
return {
|
||||
getInnerHTML: getInnerHTML
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
@ -45,7 +45,7 @@
|
||||
* @param {String} id The id at which to register the dom-module.
|
||||
*/
|
||||
register: function(id) {
|
||||
var id = id || this.id ||
|
||||
id = id || this.id ||
|
||||
this.getAttribute('name') || this.getAttribute('is');
|
||||
if (id) {
|
||||
this.id = id;
|
||||
@ -103,7 +103,7 @@
|
||||
var doc = script && script.ownerDocument || document;
|
||||
// find all dom-modules
|
||||
var modules = doc.querySelectorAll('dom-module');
|
||||
// minimize work by going backwards and stopping if we find an
|
||||
// minimize work by going backwards and stopping if we find an
|
||||
// upgraded module.
|
||||
for (var i= modules.length-1, m; (i >=0) && (m=modules[i]); i--) {
|
||||
if (m.__upgraded__) {
|
||||
|
@ -11,20 +11,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
<link rel="import" href="dom-innerHTML.html">
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
|
||||
'use strict';
|
||||
|
||||
// native add/remove
|
||||
var nativeInsertBefore = Element.prototype.insertBefore;
|
||||
var nativeAppendChild = Element.prototype.appendChild;
|
||||
var nativeRemoveChild = Element.prototype.removeChild;
|
||||
|
||||
|
||||
/**
|
||||
* TreeApi is a dom manipulation library used by Shady/Polymer.dom to
|
||||
* TreeApi is a dom manipulation library used by Shady/Polymer.dom to
|
||||
* manipulate composed and logical trees.
|
||||
*/
|
||||
var TreeApi = Polymer.TreeApi = {
|
||||
|
||||
Polymer.TreeApi = {
|
||||
|
||||
// sad but faster than slice...
|
||||
arrayCopyChildNodes: function(parent) {
|
||||
var copy=[], i=0;
|
||||
@ -62,7 +62,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
hasChildNodes: function(node) {
|
||||
return Boolean(node.__dom && node.__dom.childNodes !== undefined);
|
||||
},
|
||||
|
||||
|
||||
getChildNodes: function(node) {
|
||||
// note: we're distinguishing here between undefined and false-y:
|
||||
// hasChildNodes uses undefined check to see if this element has logical
|
||||
@ -77,7 +77,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
node.__dom.childNodes = [];
|
||||
for (var n=node.__dom.firstChild; n; n=n.__dom.nextSibling) {
|
||||
node.__dom.childNodes.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
return node.__dom.childNodes;
|
||||
},
|
||||
@ -89,32 +89,32 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// the mere existence of __dom is not enough to know if the requested
|
||||
// logical data is available and instead we do an explicit undefined check.
|
||||
getParentNode: function(node) {
|
||||
return node.__dom && node.__dom.parentNode !== undefined ?
|
||||
return node.__dom && node.__dom.parentNode !== undefined ?
|
||||
node.__dom.parentNode : node.parentNode;
|
||||
},
|
||||
|
||||
getFirstChild: function(node) {
|
||||
return node.__dom && node.__dom.firstChild !== undefined ?
|
||||
return node.__dom && node.__dom.firstChild !== undefined ?
|
||||
node.__dom.firstChild : node.firstChild;
|
||||
},
|
||||
|
||||
getLastChild: function(node) {
|
||||
return node.__dom && node.__dom.lastChild !== undefined ?
|
||||
return node.__dom && node.__dom.lastChild !== undefined ?
|
||||
node.__dom.lastChild : node.lastChild;
|
||||
},
|
||||
|
||||
getNextSibling: function(node) {
|
||||
return node.__dom && node.__dom.nextSibling !== undefined ?
|
||||
return node.__dom && node.__dom.nextSibling !== undefined ?
|
||||
node.__dom.nextSibling : node.nextSibling;
|
||||
},
|
||||
|
||||
getPreviousSibling: function(node) {
|
||||
return node.__dom && node.__dom.previousSibling !== undefined ?
|
||||
return node.__dom && node.__dom.previousSibling !== undefined ?
|
||||
node.__dom.previousSibling : node.previousSibling;
|
||||
},
|
||||
|
||||
getFirstElementChild: function(node) {
|
||||
return node.__dom && node.__dom.firstChild !== undefined ?
|
||||
return node.__dom && node.__dom.firstChild !== undefined ?
|
||||
this._getFirstElementChild(node) : node.firstElementChild;
|
||||
},
|
||||
|
||||
@ -207,9 +207,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
container.__dom = container.__dom || {};
|
||||
if (ref_node) {
|
||||
ref_node.__dom = ref_node.__dom || {};
|
||||
}
|
||||
}
|
||||
// update ref_node.previousSibling <-> node
|
||||
node.__dom.previousSibling = ref_node ? ref_node.__dom.previousSibling :
|
||||
node.__dom.previousSibling = ref_node ? ref_node.__dom.previousSibling :
|
||||
container.__dom.lastChild;
|
||||
if (node.__dom.previousSibling) {
|
||||
node.__dom.previousSibling.__dom.nextSibling = node;
|
||||
@ -255,7 +255,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// When an element is removed, logical data is no longer tracked.
|
||||
// Explicitly set `undefined` here to indicate this. This is disginguished
|
||||
// from `null` which is set if info is null.
|
||||
node.__dom.parentNode = node.__dom.previousSibling =
|
||||
node.__dom.parentNode = node.__dom.previousSibling =
|
||||
node.__dom.nextSibling = undefined;
|
||||
// remove caching of childNodes
|
||||
container.__dom.childNodes = null;
|
||||
@ -277,8 +277,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
// composed tracking needs to reset composed children here in case
|
||||
// they may have already been set (this shouldn't happen but can
|
||||
// if dependency ordering is incorrect and as a result upgrade order
|
||||
// they may have already been set (this shouldn't happen but can
|
||||
// if dependency ordering is incorrect and as a result upgrade order
|
||||
// is unexpected)
|
||||
clearChildNodes: function(node) {
|
||||
node.textContent = '';
|
||||
|
@ -13,11 +13,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
* Helper for determining when first render occurs.
|
||||
* Call `Polymer.RenderStatus.whenReady(callback)` to be notified when
|
||||
* first render occurs or immediately if it has already occured.
|
||||
* Note that since HTML Imports are designed to load before rendering,
|
||||
* Note that since HTML Imports are designed to load before rendering,
|
||||
* this call can also be used to guarantee that imports have loaded.
|
||||
* This behavior is normalized to function correctly with the HTMLImports
|
||||
* polyfill which does not otherwise maintain this rendering guarantee.
|
||||
* Querying style and layout data before first render is currently
|
||||
* Querying style and layout data before first render is currently
|
||||
* problematic on some browsers (Blink/Webkit) so this helper can be used
|
||||
* to prevent doing so until a safe time.
|
||||
*/
|
||||
@ -85,7 +85,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
for (var i=0, h; i < callbacks.length; i++) {
|
||||
h = callbacks[i];
|
||||
h[1].apply(h[0], h[2] || Polymer.nar);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -101,4 +101,4 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
Polymer.ImportStatus = Polymer.RenderStatus;
|
||||
Polymer.ImportStatus.whenLoaded = Polymer.ImportStatus.whenReady;
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
@ -1,91 +1,90 @@
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="style-util.html">
|
||||
<link rel="import" href="style-cache.html">
|
||||
<script>
|
||||
|
||||
Polymer.StyleDefaults = (function() {
|
||||
|
||||
var styleProperties = Polymer.StyleProperties;
|
||||
var styleUtil = Polymer.StyleUtil;
|
||||
var StyleCache = Polymer.StyleCache;
|
||||
|
||||
var api = {
|
||||
|
||||
_styles: [],
|
||||
_properties: null,
|
||||
customStyle: {},
|
||||
_styleCache: new StyleCache(),
|
||||
|
||||
addStyle: function(style) {
|
||||
this._styles.push(style);
|
||||
this._properties = null;
|
||||
},
|
||||
|
||||
// NOTE: this object can be used as a styling scope so it has an api
|
||||
// similar to that of an element wrt style properties
|
||||
get _styleProperties() {
|
||||
if (!this._properties) {
|
||||
// force rules to reparse since they may be out of date
|
||||
styleProperties.decorateStyles(this._styles);
|
||||
// NOTE: reset cache for own properties; it may have been set when
|
||||
// an element in an import applied styles (e.g. custom-style)
|
||||
this._styles._scopeStyleProperties = null;
|
||||
this._properties = styleProperties
|
||||
.scopePropertiesFromStyles(this._styles);
|
||||
// mixin customStyle
|
||||
styleProperties.mixinCustomStyle(this._properties, this.customStyle);
|
||||
styleProperties.reify(this._properties);
|
||||
}
|
||||
return this._properties;
|
||||
},
|
||||
|
||||
_needsStyleProperties: function() {},
|
||||
|
||||
_computeStyleProperties: function() {
|
||||
return this._styleProperties;
|
||||
},
|
||||
|
||||
/**
|
||||
* Re-evaluates and applies custom CSS properties to all elements in the
|
||||
* document based on dynamic changes, such as adding or removing classes.
|
||||
*
|
||||
* For performance reasons, Polymer's custom CSS property shim relies
|
||||
* on this explicit signal from the user to indicate when changes have
|
||||
* been made that affect the values of custom properties.
|
||||
*
|
||||
* @method updateStyles
|
||||
* @param {Object=} properties Properties object which is mixed into
|
||||
* the document root `customStyle` property. This argument provides a
|
||||
* shortcut for setting `customStyle` and then calling `updateStyles`.
|
||||
*/
|
||||
updateStyles: function(properties) {
|
||||
// force properties update.
|
||||
this._properties = null;
|
||||
if (properties) {
|
||||
Polymer.Base.mixin(this.customStyle, properties);
|
||||
}
|
||||
// invalidate the cache
|
||||
this._styleCache.clear();
|
||||
// update any custom-styles we are tracking
|
||||
for (var i=0, s; i < this._styles.length; i++) {
|
||||
s = this._styles[i];
|
||||
s = s.__importElement || s;
|
||||
s._apply();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// exports
|
||||
return api;
|
||||
|
||||
})();
|
||||
</script>
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="style-util.html">
|
||||
<link rel="import" href="style-cache.html">
|
||||
<script>
|
||||
|
||||
Polymer.StyleDefaults = (function() {
|
||||
|
||||
var styleProperties = Polymer.StyleProperties;
|
||||
var StyleCache = Polymer.StyleCache;
|
||||
|
||||
var api = {
|
||||
|
||||
_styles: [],
|
||||
_properties: null,
|
||||
customStyle: {},
|
||||
_styleCache: new StyleCache(),
|
||||
|
||||
addStyle: function(style) {
|
||||
this._styles.push(style);
|
||||
this._properties = null;
|
||||
},
|
||||
|
||||
// NOTE: this object can be used as a styling scope so it has an api
|
||||
// similar to that of an element wrt style properties
|
||||
get _styleProperties() {
|
||||
if (!this._properties) {
|
||||
// force rules to reparse since they may be out of date
|
||||
styleProperties.decorateStyles(this._styles);
|
||||
// NOTE: reset cache for own properties; it may have been set when
|
||||
// an element in an import applied styles (e.g. custom-style)
|
||||
this._styles._scopeStyleProperties = null;
|
||||
this._properties = styleProperties
|
||||
.scopePropertiesFromStyles(this._styles);
|
||||
// mixin customStyle
|
||||
styleProperties.mixinCustomStyle(this._properties, this.customStyle);
|
||||
styleProperties.reify(this._properties);
|
||||
}
|
||||
return this._properties;
|
||||
},
|
||||
|
||||
_needsStyleProperties: function() {},
|
||||
|
||||
_computeStyleProperties: function() {
|
||||
return this._styleProperties;
|
||||
},
|
||||
|
||||
/**
|
||||
* Re-evaluates and applies custom CSS properties to all elements in the
|
||||
* document based on dynamic changes, such as adding or removing classes.
|
||||
*
|
||||
* For performance reasons, Polymer's custom CSS property shim relies
|
||||
* on this explicit signal from the user to indicate when changes have
|
||||
* been made that affect the values of custom properties.
|
||||
*
|
||||
* @method updateStyles
|
||||
* @param {Object=} properties Properties object which is mixed into
|
||||
* the document root `customStyle` property. This argument provides a
|
||||
* shortcut for setting `customStyle` and then calling `updateStyles`.
|
||||
*/
|
||||
updateStyles: function(properties) {
|
||||
// force properties update.
|
||||
this._properties = null;
|
||||
if (properties) {
|
||||
Polymer.Base.mixin(this.customStyle, properties);
|
||||
}
|
||||
// invalidate the cache
|
||||
this._styleCache.clear();
|
||||
// update any custom-styles we are tracking
|
||||
for (var i=0, s; i < this._styles.length; i++) {
|
||||
s = this._styles[i];
|
||||
s = s.__importElement || s;
|
||||
s._apply();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// exports
|
||||
return api;
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
@ -1,101 +1,101 @@
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="style-util.html">
|
||||
|
||||
<script>
|
||||
|
||||
Polymer.StyleExtends = (function() {
|
||||
|
||||
var styleUtil = Polymer.StyleUtil;
|
||||
|
||||
return {
|
||||
|
||||
hasExtends: function(cssText) {
|
||||
return Boolean(cssText.match(this.rx.EXTEND));
|
||||
},
|
||||
|
||||
transform: function(style) {
|
||||
var rules = styleUtil.rulesForStyle(style);
|
||||
var self = this;
|
||||
styleUtil.forEachRule(rules, function(rule) {
|
||||
var map = self._mapRule(rule);
|
||||
if (rule.parent) {
|
||||
var m;
|
||||
while (m = self.rx.EXTEND.exec(rule.cssText)) {
|
||||
var extend = m[1];
|
||||
var extendor = self._findExtendor(extend, rule);
|
||||
if (extendor) {
|
||||
self._extendRule(rule, extendor);
|
||||
}
|
||||
}
|
||||
}
|
||||
rule.cssText = rule.cssText.replace(self.rx.EXTEND, '');
|
||||
});
|
||||
// strip unused % selectors
|
||||
return styleUtil.toCssText(rules, function(rule) {
|
||||
if (rule.selector.match(self.rx.STRIP)) {
|
||||
rule.cssText = '';
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
|
||||
_mapRule: function(rule) {
|
||||
if (rule.parent) {
|
||||
var map = rule.parent.map || (rule.parent.map = {});
|
||||
var parts = rule.selector.split(',');
|
||||
for (var i=0, p; i < parts.length; i++) {
|
||||
p = parts[i];
|
||||
map[p.trim()] = rule;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
},
|
||||
|
||||
_findExtendor: function(extend, rule) {
|
||||
return rule.parent && rule.parent.map && rule.parent.map[extend] ||
|
||||
this._findExtendor(extend, rule.parent);
|
||||
},
|
||||
|
||||
_extendRule: function(target, source) {
|
||||
if (target.parent !== source.parent) {
|
||||
this._cloneAndAddRuleToParent(source, target.parent);
|
||||
}
|
||||
target.extends = target.extends || [];
|
||||
target.extends.push(source);
|
||||
// TODO: this misses `%foo, .bar` as an unetended selector but
|
||||
// this seems rare and could possibly be unsupported.
|
||||
source.selector = source.selector.replace(this.rx.STRIP, '');
|
||||
source.selector = (source.selector && source.selector + ',\n') +
|
||||
target.selector;
|
||||
if (source.extends) {
|
||||
source.extends.forEach(function(e) {
|
||||
this._extendRule(target, e);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
_cloneAndAddRuleToParent: function(rule, parent) {
|
||||
rule = Object.create(rule);
|
||||
rule.parent = parent;
|
||||
if (rule.extends) {
|
||||
rule.extends = rule.extends.slice();
|
||||
}
|
||||
parent.rules.push(rule);
|
||||
},
|
||||
|
||||
rx: {
|
||||
EXTEND: /@extends\(([^)]*)\)\s*?;/gim,
|
||||
STRIP: /%[^,]*$/
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
</script>
|
||||
<!--
|
||||
@license
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="style-util.html">
|
||||
|
||||
<script>
|
||||
|
||||
Polymer.StyleExtends = (function() {
|
||||
|
||||
var styleUtil = Polymer.StyleUtil;
|
||||
|
||||
return {
|
||||
|
||||
hasExtends: function(cssText) {
|
||||
return Boolean(cssText.match(this.rx.EXTEND));
|
||||
},
|
||||
|
||||
transform: function(style) {
|
||||
var rules = styleUtil.rulesForStyle(style);
|
||||
var self = this;
|
||||
styleUtil.forEachRule(rules, function(rule) {
|
||||
self._mapRule(rule);
|
||||
if (rule.parent) {
|
||||
var m;
|
||||
while ((m = self.rx.EXTEND.exec(rule.cssText))) {
|
||||
var extend = m[1];
|
||||
var extendor = self._findExtendor(extend, rule);
|
||||
if (extendor) {
|
||||
self._extendRule(rule, extendor);
|
||||
}
|
||||
}
|
||||
}
|
||||
rule.cssText = rule.cssText.replace(self.rx.EXTEND, '');
|
||||
});
|
||||
// strip unused % selectors
|
||||
return styleUtil.toCssText(rules, function(rule) {
|
||||
if (rule.selector.match(self.rx.STRIP)) {
|
||||
rule.cssText = '';
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
|
||||
_mapRule: function(rule) {
|
||||
if (rule.parent) {
|
||||
var map = rule.parent.map || (rule.parent.map = {});
|
||||
var parts = rule.selector.split(',');
|
||||
for (var i=0, p; i < parts.length; i++) {
|
||||
p = parts[i];
|
||||
map[p.trim()] = rule;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
},
|
||||
|
||||
_findExtendor: function(extend, rule) {
|
||||
return rule.parent && rule.parent.map && rule.parent.map[extend] ||
|
||||
this._findExtendor(extend, rule.parent);
|
||||
},
|
||||
|
||||
_extendRule: function(target, source) {
|
||||
if (target.parent !== source.parent) {
|
||||
this._cloneAndAddRuleToParent(source, target.parent);
|
||||
}
|
||||
target.extends = target.extends || [];
|
||||
target.extends.push(source);
|
||||
// TODO: this misses `%foo, .bar` as an unetended selector but
|
||||
// this seems rare and could possibly be unsupported.
|
||||
source.selector = source.selector.replace(this.rx.STRIP, '');
|
||||
source.selector = (source.selector && source.selector + ',\n') +
|
||||
target.selector;
|
||||
if (source.extends) {
|
||||
source.extends.forEach(function(e) {
|
||||
this._extendRule(target, e);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
_cloneAndAddRuleToParent: function(rule, parent) {
|
||||
rule = Object.create(rule);
|
||||
rule.parent = parent;
|
||||
if (rule.extends) {
|
||||
rule.extends = rule.extends.slice();
|
||||
}
|
||||
parent.rules.push(rule);
|
||||
},
|
||||
|
||||
rx: {
|
||||
EXTEND: /@extends\(([^)]*)\)\s*?;/gim,
|
||||
STRIP: /%[^,]*$/
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
@ -71,7 +71,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
var m, rx = this.rx.VAR_ASSIGN;
|
||||
var cssText = rule.parsedCssText;
|
||||
var any;
|
||||
while (m = rx.exec(cssText)) {
|
||||
while ((m = rx.exec(cssText))) {
|
||||
// note: group 2 is var, 3 is mixin
|
||||
properties[m[1]] = (m[2] || m[3]).trim();
|
||||
any = true;
|
||||
@ -103,7 +103,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
collectPropertiesInCssText: function(cssText, props) {
|
||||
var m;
|
||||
while (m = this.rx.VAR_CAPTURE.exec(cssText)) {
|
||||
while ((m = this.rx.VAR_CAPTURE.exec(cssText))) {
|
||||
props[m[1]] = true;
|
||||
var def = m[2];
|
||||
if (def && def.match(this.rx.IS_VAR)) {
|
||||
@ -155,7 +155,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
valueForProperties: function(property, props) {
|
||||
var parts = property.split(';');
|
||||
for (var i=0, p, m; i<parts.length; i++) {
|
||||
if (p = parts[i]) {
|
||||
if ((p = parts[i])) {
|
||||
m = p.match(this.rx.MIXIN_MATCH);
|
||||
if (m) {
|
||||
p = this.valueForProperty(props[m[1]], props);
|
||||
|
@ -193,9 +193,9 @@ Then the `observe` property should be configured as follows:
|
||||
|
||||
/**
|
||||
* Count of currently rendered items after `filter` (if any) has been applied.
|
||||
* If "chunking mode" is enabled, `renderedItemCount` is updated each time a
|
||||
* If "chunking mode" is enabled, `renderedItemCount` is updated each time a
|
||||
* set of template instances is rendered.
|
||||
*
|
||||
*
|
||||
*/
|
||||
renderedItemCount: {
|
||||
type: Number,
|
||||
@ -409,7 +409,6 @@ Then the `observe` property should be configured as follows:
|
||||
},
|
||||
|
||||
_render: function() {
|
||||
var c = this.collection;
|
||||
// Choose rendering path: full vs. incremental using splices
|
||||
if (this._needFullRefresh) {
|
||||
// Full refresh when items, sort, or filter change, or when render() called
|
||||
@ -456,7 +455,7 @@ Then the `observe` property should be configured as follows:
|
||||
// `item` may not be sufficient if the pooled instance happens to be
|
||||
// the same item.
|
||||
this._pool.length = 0;
|
||||
// Set rendered item count
|
||||
// Set rendered item count
|
||||
this._setRenderedItemCount(this._instances.length);
|
||||
// Notify users
|
||||
this.fire('dom-change');
|
||||
@ -499,7 +498,7 @@ Then the `observe` property should be configured as follows:
|
||||
});
|
||||
}
|
||||
// Generate instances and assign items and keys
|
||||
for (var i=0; i<keys.length; i++) {
|
||||
for (i=0; i<keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var inst = this._instances[i];
|
||||
if (inst) {
|
||||
@ -529,23 +528,23 @@ Then the `observe` property should be configured as follows:
|
||||
// first, and added rows are insertion-sorted into place using user sort
|
||||
_applySplicesUserSort: function(splices) {
|
||||
var c = this.collection;
|
||||
var instances = this._instances;
|
||||
var keyMap = {};
|
||||
var key;
|
||||
// Dedupe added and removed keys to a final added/removed map
|
||||
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (var j=0; j<s.removed.length; j++) {
|
||||
var key = s.removed[j];
|
||||
key = s.removed[j];
|
||||
keyMap[key] = keyMap[key] ? null : -1;
|
||||
}
|
||||
for (var j=0; j<s.added.length; j++) {
|
||||
var key = s.added[j];
|
||||
for (j=0; j<s.added.length; j++) {
|
||||
key = s.added[j];
|
||||
keyMap[key] = keyMap[key] ? null : 1;
|
||||
}
|
||||
}
|
||||
// Convert added/removed key map to added/removed arrays
|
||||
var removedIdxs = [];
|
||||
var addedKeys = [];
|
||||
for (var key in keyMap) {
|
||||
for (key in keyMap) {
|
||||
if (keyMap[key] === -1) {
|
||||
removedIdxs.push(this._keyToInstIdx[key]);
|
||||
}
|
||||
@ -559,7 +558,7 @@ Then the `observe` property should be configured as follows:
|
||||
// so we don't invalidate instance index
|
||||
// use numeric sort, default .sort is alphabetic
|
||||
removedIdxs.sort(this._numericSort);
|
||||
for (var i=removedIdxs.length-1; i>=0 ; i--) {
|
||||
for (i=removedIdxs.length-1; i>=0 ; i--) {
|
||||
var idx = removedIdxs[i];
|
||||
// Removed idx may be undefined if item was previously filtered out
|
||||
if (idx !== undefined) {
|
||||
@ -583,7 +582,7 @@ Then the `observe` property should be configured as follows:
|
||||
});
|
||||
// Insertion-sort new instances into place (from pool or newly created)
|
||||
var start = 0;
|
||||
for (var i=0; i<addedKeys.length; i++) {
|
||||
for (i=0; i<addedKeys.length; i++) {
|
||||
start = this._insertRowUserSort(start, addedKeys[i]);
|
||||
}
|
||||
}
|
||||
@ -622,13 +621,12 @@ Then the `observe` property should be configured as follows:
|
||||
// rows are as placeholders, and placeholders are updated to
|
||||
// actual rows at the end to take full advantage of removed rows
|
||||
_applySplicesArrayOrder: function(splices) {
|
||||
var c = this.collection;
|
||||
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
// Detach & pool removed instances
|
||||
for (var j=0; j<s.removed.length; j++) {
|
||||
this._detachAndRemoveInstance(s.index);
|
||||
}
|
||||
for (var j=0; j<s.addedKeys.length; j++) {
|
||||
for (j=0; j<s.addedKeys.length; j++) {
|
||||
this._insertPlaceholder(s.index+j, s.addedKeys[j]);
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
|
||||
},
|
||||
|
||||
_flushTemplates: function(debouncerExpired) {
|
||||
_flushTemplates: function() {
|
||||
Polymer.dom.flush();
|
||||
},
|
||||
|
||||
@ -191,7 +191,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
archetype._addPropertyEffect(prop, 'function',
|
||||
this._createHostPropEffector(prop));
|
||||
}
|
||||
for (var prop in this._instanceProps) {
|
||||
for (prop in this._instanceProps) {
|
||||
archetype._addPropertyEffect(prop, 'function',
|
||||
this._createInstancePropEffector(prop));
|
||||
}
|
||||
@ -309,12 +309,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
// Extension points for Templatizer sub-classes
|
||||
/* eslint-disable no-unused-vars */
|
||||
_showHideChildren: function(hidden) { },
|
||||
_forwardInstancePath: function(inst, path, value) { },
|
||||
_forwardInstanceProp: function(inst, prop, value) { },
|
||||
// Defined-check rather than thunk used to avoid unnecessary work for these:
|
||||
// _forwardParentPath: function(path, value) { },
|
||||
// _forwardParentProp: function(prop, value) { },
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
_notifyPathUpImpl: function(path, value) {
|
||||
var dataHost = this.dataHost;
|
||||
@ -448,7 +450,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// An element with a _templateInstance marks the top boundary
|
||||
// of a scope; walk up until we find one, and then ensure that
|
||||
// its dataHost matches `this`, meaning this dom-repeat stamped it
|
||||
if (model = el._templateInstance) {
|
||||
if ((model = el._templateInstance)) {
|
||||
// Found an element stamped by another template; keep walking up
|
||||
// from its dataHost
|
||||
if (model.dataHost != this) {
|
||||
|
@ -108,7 +108,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
_setAttributeToProperty: function(model, attribute, property, info) {
|
||||
// Don't deserialize back to property if currently reflecting
|
||||
if (!this._serializing) {
|
||||
var property = property || Polymer.CaseMap.dashToCamelCase(attribute);
|
||||
property = (property || Polymer.CaseMap.dashToCamelCase(attribute));
|
||||
// fallback to property lookup
|
||||
// TODO(sorvell): check for _propertyInfo existence because of dom-bind
|
||||
info = info || (this._propertyInfo && this._propertyInfo[property]);
|
||||
@ -236,6 +236,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
* @return {string} String serialized from the provided property value.
|
||||
*/
|
||||
serialize: function(value) {
|
||||
/* eslint-disable no-fallthrough */
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
return value ? '' : undefined;
|
||||
@ -255,7 +256,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
return value != null ? value : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable no-fallthrough */
|
||||
});
|
||||
|
||||
</script>
|
||||
|
@ -116,7 +116,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
if (info) {
|
||||
return info;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return info || Polymer.nob;
|
||||
},
|
||||
@ -138,7 +138,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// union properties, behaviors.properties, and propertyEffects
|
||||
_prepPropertyInfo: function() {
|
||||
this._propertyInfo = {};
|
||||
for (var i=0, p; i < this.behaviors.length; i++) {
|
||||
for (var i=0; i < this.behaviors.length; i++) {
|
||||
this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
|
||||
}
|
||||
this._addPropertyInfo(this._propertyInfo, this.properties);
|
||||
@ -174,7 +174,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
@ -77,12 +77,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
this.shadyRoot._isShadyRoot = true;
|
||||
this.shadyRoot._dirtyRoots = [];
|
||||
// capture insertion point list
|
||||
var i$ = this.shadyRoot._insertionPoints = !this._notes ||
|
||||
var i$ = this.shadyRoot._insertionPoints = !this._notes ||
|
||||
this._notes._hasContent ?
|
||||
this.shadyRoot.querySelectorAll('content') : [];
|
||||
// save logical tree info
|
||||
// a. for shadyRoot
|
||||
// b. for insertion points (fallback)
|
||||
// a. for shadyRoot
|
||||
// b. for insertion points (fallback)
|
||||
// c. for parents of insertion points
|
||||
TreeApi.Logical.saveChildNodes(this.shadyRoot);
|
||||
for (var i=0, c; i < i$.length; i++) {
|
||||
@ -119,7 +119,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
*/
|
||||
distributeContent: function(updateInsertionPoints) {
|
||||
if (this.shadyRoot) {
|
||||
this.shadyRoot._invalidInsertionPoints =
|
||||
this.shadyRoot._invalidInsertionPoints =
|
||||
this.shadyRoot._invalidInsertionPoints || updateInsertionPoints;
|
||||
// Distribute the host that's the top of this element's distribution
|
||||
// tree. Distributing that host will *always* distibute this element.
|
||||
@ -164,7 +164,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// compose self
|
||||
if (this._useContent) {
|
||||
// note: it's important to mark this clean before distribution
|
||||
// so that attachment that provokes additional distribution (e.g.
|
||||
// so that attachment that provokes additional distribution (e.g.
|
||||
// adding something to your parentNode) works
|
||||
this.shadyRoot._distributionClean = true;
|
||||
if (DomApi.hasInsertionPoint(this.shadyRoot)) {
|
||||
@ -331,7 +331,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
for (var i=0, d=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (var j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {
|
||||
// check if the node is still where we expect it is before trying
|
||||
// to remove it; this can happen if Polymer.dom moves a node and
|
||||
// to remove it; this can happen if Polymer.dom moves a node and
|
||||
// then schedules its previous host for distribution resulting in
|
||||
// the node being removed here.
|
||||
if (TreeApi.Composed.getParentNode(n) === container) {
|
||||
@ -342,9 +342,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
d -= s.addedCount;
|
||||
}
|
||||
// process adds
|
||||
for (var i=0, s, next; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (var i=0, s, next; (i<splices.length) && (s=splices[i]); i++) { //eslint-disable-line no-redeclare
|
||||
next = composed[s.index];
|
||||
for (var j=s.index, n; j < s.index + s.addedCount; j++) {
|
||||
for (j=s.index, n; j < s.index + s.addedCount; j++) {
|
||||
n = children[j];
|
||||
TreeApi.Composed.insertBefore(container, n, next);
|
||||
// TODO(sorvell): is this splice strictly needed?
|
||||
|
@ -227,7 +227,7 @@ TODO(sjmiles): this module should produce either syntactic metadata
|
||||
},
|
||||
|
||||
// push configuration references at configure time
|
||||
_configureAnnotationReferences: function(config) {
|
||||
_configureAnnotationReferences: function() {
|
||||
var notes = this._notes;
|
||||
var nodes = this._nodes;
|
||||
for (var i=0; i<notes.length; i++) {
|
||||
|
@ -255,7 +255,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
}
|
||||
// enforce gesture recognizer order
|
||||
for (var i = 0, r; i < recognizers.length; i++) {
|
||||
for (i = 0, r; i < recognizers.length; i++) {
|
||||
r = recognizers[i];
|
||||
if (gs[r.name] && !handled[r.name]) {
|
||||
handled[r.name] = true;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -144,7 +144,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
getEffectiveTextContent: function() {
|
||||
var cn = this.getEffectiveChildNodes();
|
||||
var tc = [];
|
||||
for (var i=0, c; c = cn[i]; i++) {
|
||||
for (var i=0, c; (c = cn[i]); i++) {
|
||||
if (c.nodeType !== Node.COMMENT_NODE) {
|
||||
tc.push(Polymer.dom(c).textContent);
|
||||
}
|
||||
@ -215,7 +215,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
fire: function(type, detail, options) {
|
||||
options = options || Polymer.nob;
|
||||
var node = options.node || this;
|
||||
var detail = (detail === null || detail === undefined) ? {} : detail;
|
||||
detail = (detail === null || detail === undefined) ? {} : detail;
|
||||
var bubbles = options.bubbles === undefined ? true : options.bubbles;
|
||||
var cancelable = Boolean(options.cancelable);
|
||||
var useCache = options._useCache;
|
||||
|
@ -19,7 +19,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
var propertyUtils = Polymer.StyleProperties;
|
||||
var styleTransformer = Polymer.StyleTransformer;
|
||||
var styleUtil = Polymer.StyleUtil;
|
||||
var styleDefaults = Polymer.StyleDefaults;
|
||||
|
||||
var nativeShadow = Polymer.Settings.useNativeShadow;
|
||||
@ -77,7 +76,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
_findStyleHost: function() {
|
||||
var e = this, root;
|
||||
while (root = Polymer.dom(e).getOwnerRoot()) {
|
||||
while ((root = Polymer.dom(e).getOwnerRoot())) {
|
||||
if (Polymer.isInstance(root.host)) {
|
||||
return root.host;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user