Merge branch 'master' into shady-linked

Conflicts:
	src/lib/dom-api.html
	src/mini/shady.html
This commit is contained in:
Steven Orvell 2015-12-11 11:32:25 -08:00
commit e3753dbaeb
18 changed files with 330 additions and 410 deletions

View File

@ -174,11 +174,11 @@ Polymer.CssParse = (function() {
customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim,
mixinProp: /(?:^|[\s;])?--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim,
mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim,
varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
keyframesRule: /^@[^\s]*keyframes/,
multipleSpaces: /\s+/g
},
},
VAR_START: '--',
MEDIA_START: '@media',
AT_START: '@'

View File

@ -29,7 +29,7 @@ Polymer.domInnerHTML = (function() {
case '>':
return '>';
case '"':
return '"'
return '"';
case '\u00A0':
return ' ';
}

View File

@ -6,7 +6,7 @@
var lcModules = {};
var findModule = function(id) {
return modules[id] || lcModules[id.toLowerCase()];
}
};
/**
* The `dom-module` element registers the dom it contains to the name given

View File

@ -193,7 +193,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// remote api
shadowize = function() {
var shadowize = function() {
var idx = Number(this.attributes.idx.value);
//alert(idx);
var node = drillable[idx];

View File

@ -12,7 +12,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
Polymer.StyleCache = function() {
this.cache = {};
}
};
Polymer.StyleCache.prototype = {

View File

@ -191,6 +191,18 @@ Then the `observe` property should be configured as follows:
*/
delay: Number,
/**
* Count of currently rendered items after `filter` (if any) has been applied.
* If "chunking mode" is enabled, `renderedItemCount` is updated each time a
* set of template instances is rendered.
*
*/
renderedItemCount: {
type: Number,
notify: true,
readOnly: true
},
/**
* Defines an initial count of template instances to render after setting
* the `items` array, before the next paint, and puts the `dom-repeat`
@ -439,6 +451,8 @@ 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
this._setRenderedItemCount(this._instances.length);
// Notify users
this.fire('dom-change');
// Check to see if we need to render more items

View File

@ -17,7 +17,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
(document._currentScript || document.currentScript).parentNode;
if (module.localName === 'dom-module') {
var id = module.id || module.getAttribute('name')
|| module.getAttribute('is')
|| module.getAttribute('is');
this.is = id;
}
}

View File

@ -27,7 +27,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* debouncedClickAction: function(e) {
* // will not call `processClick` more than once per 100ms
* this.debounce('click', function() {
* this.processClick;
* this.processClick();
* }, 100);
* }
*
@ -52,7 +52,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
*/
isDebouncerActive: function(jobName) {
var debouncer = this._debouncers[jobName];
return debouncer && debouncer.finish;
return !!(debouncer && debouncer.finish);
},
/**

View File

@ -106,6 +106,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
_addComplexObserverEffect: function(observer) {
var sig = this._parseMethod(observer);
if (!sig) {
throw new Error("Malformed observer expression '" + observer + "'");
}
for (var i=0, arg; (i<sig.args.length) && (arg=sig.args[i]); i++) {
this._addPropertyEffect(arg.model, 'complexObserver', {
method: sig.method,

View File

@ -454,7 +454,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
this.fire('up', Gestures.findOriginalTarget(e), e.changedTouches[0]);
},
fire: function(type, target, event) {
var self = this;
Gestures.fire(target, type, {
x: event.clientX,
y: event.clientY,

View File

@ -164,7 +164,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
/**
* Returns a list of nodes distributed to this element's `<content>`.
*
* If this element contans more than one `<content>` in its local DOM,
* If this element contains more than one `<content>` in its local DOM,
* an optional selector may be passed to choose the desired content.
*
* @method getContentChildNodes
@ -181,7 +181,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* Returns a list of element children distributed to this element's
* `<content>`.
*
* If this element contans more than one `<content>` in its
* If this element contains more than one `<content>` in its
* local DOM, an optional selector may be passed to choose the desired
* content. This method differs from `getContentChildNodes` in that only
* elements are returned.
@ -198,7 +198,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
});
},
/**
* Dispatches a custom event with an optional detail value.
*
@ -234,13 +234,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
__eventCache: {},
// NOTE: We optionally cache event objects for efficiency during high
// freq. opts. This option cannot be used for events which may have
// freq. opts. This option cannot be used for events which may have
// `stopPropagation` called on them. On Chrome and Safari (but not FF)
// if `stopPropagation` is called, the event cannot be reused. It does not
// if `stopPropagation` is called, the event cannot be reused. It does not
// dispatch again.
_getEvent: function(type, bubbles, cancelable, useCache) {
var event = useCache && this.__eventCache[type];
if (!event || ((event.bubbles != bubbles) ||
if (!event || ((event.bubbles != bubbles) ||
(event.cancelable != cancelable))) {
event = new Event(type, {
bubbles: Boolean(bubbles),
@ -358,12 +358,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* loaded.
* @param {Function} onerror Callback to notify when an import
* unsuccessfully loaded.
* @param {boolean} optAsync True if the import should be loaded `async`.
* Defaults to `false`.
* @return {HTMLLinkElement} The link element for the URL to be loaded.
*/
importHref: function(href, onload, onerror) {
importHref: function(href, onload, onerror, optAsync) {
var l = document.createElement('link');
l.rel = 'import';
l.href = href;
optAsync = Boolean(optAsync);
if (optAsync) {
l.setAttribute('async', '');
}
var self = this;
if (onload) {
l.onload = function(e) {

View File

@ -130,7 +130,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
style: style,
_scopeSelector: this._scopeSelector,
_styleProperties: this._styleProperties
}
};
scopeData.key.customStyle = {};
this.mixin(scopeData.key.customStyle, this.customStyle);
scope._styleCache.store(this.is, info, scopeData.key, this._styles);

View File

@ -119,6 +119,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
test('basic rendering, downward item binding', function() {
var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
assert.equal(configured.$.repeater.renderedItemCount, 3, 'rendered item count incorrect');
assert.equal(stamped[0].itemaProp, 'prop-1');
assert.equal(stamped[0].computeda, 'prop-1+itemForComputedA');
assert.equal(stamped[0].indexa, 0);
@ -286,6 +287,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
CustomElements.takeRecords();
var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
assert.equal(configured.$.repeater.renderedItemCount, 2, 'rendered item count incorrect');
assert.equal(stamped[0].itemaProp, 'prop-1');
assert.equal(stamped[0].indexa, 0);
assert.equal(stamped[13].itemaProp, 'prop-3');
@ -3313,6 +3315,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assert.equal(repeater3.keyForElement(stamped1[4]), coll3.getKey(items3[2]));
});
test('renderedItemCount', function() {
var repeater1 = primitive.$.repeater1;
primitive.items = [ 'a', 'b', 'c', 'd', 'e' ];
repeater1.render();
assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is incorrect');
repeater1.renderedItemCount = 0;
assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is writable');
repeater1.filter = function(item) {
return (item != 'a' && item != 'e');
}
repeater1.render();
assert.equal(repeater1.renderedItemCount, 3, 'renderedItemCount incorrect after filter');
// reset repeater
repeater1.filter = undefined;
repeater1.render();
});
test('__hideTemplateChildren__', function() {
// Initially all showing
var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');

View File

@ -20,7 +20,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<dynamic-element></dynamic-element>
<script>
suite('dynamic imports', function() {
test('use importHref to load and create an element', function(done) {
@ -36,6 +36,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
});
});
suite('async/sync loading', function() {
var url = 'dynamic-imports/dynamic-element.html';
test('importHref sync loads by default', function(done) {
Polymer.Base.importHref(url, function(e) {
assert.isFalse(e.target.hasAttribute('async'),
'sync load is default');
done();
});
});
test('importHref sync loading', function(done) {
Polymer.Base.importHref(url, function(e) {
assert.isTrue(e.target.hasAttribute('async'), 'async load');
done();
}, null, true);
});
});
});
</script>

View File

@ -12,12 +12,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<dom-module id="dynamic-element">
<template>
<span id="content">dynamic-element</span> :
<span id="content">dynamic-element</span> :
</template>
</dom-module>
<script>
Polymer({
is: 'dynamic-element',
ready: function() {
@ -42,4 +42,4 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
});
</script>
</script>

View File

@ -230,4 +230,4 @@
cChanged: function() {}
});
</script>
</dom-module>
</dom-module>

View File

@ -47,6 +47,80 @@ suite('basic path bindings', function() {
document.body.removeChild(el);
});
function setupNested() {
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
}
function setupComposedAndGetObject() {
el.nested = {
obj: {
value: 41
}
};
var obj = {
value: 42
};
el.expectedNestedSubpath = 'nested.obj';
el.expectedNestedValue = obj;
el.expectedNestedObjSubpath = 'nested.obj';
el.expectedNestedObjValue = obj;
el.$.compose.expectedObjSubpath = 'obj';
el.$.compose.expectedObjValue = obj;
el.$.forward.expectedObjSubpath = 'obj';
el.$.forward.expectedObjValue = obj;
el.$.forward.$.compose.expectedObjSubpath = 'obj';
el.$.forward.$.compose.expectedObjValue = obj;
el.clearObserverCounts();
return obj;
}
function verifyObserverOutput(expectedNestedObjChanged) {
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, expectedNestedObjChanged);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
}
function verifyNestedObserversOutput() {
verifyObserverOutput(0);
}
function verifyNonNestedObserversOutput() {
verifyObserverOutput(1);
}
test('downward data flow', function() {
// Setup
var nested = {
@ -67,462 +141,97 @@ suite('basic path bindings', function() {
// Do the thing
el.nested = nested;
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 1);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.obj, nested.obj);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.obj, nested.obj);
assert.equal(el.$.forward.$.compose.obj, nested.obj);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNonNestedObserversOutput();
});
test('notification from basic element property change', function() {
// Setup
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
setupNested();
// Do the thing
el.$.basic.notifyingValue = 42;
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 0);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNestedObserversOutput();
});
test('notification from composed element property change', function() {
// Setup
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
setupNested();
// Do the thing
el.$.compose.$.basic1.notifyingValue = 42;
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 0);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNestedObserversOutput();
});
test('notification from forward\'s composed element property change', function() {
// Setup
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
setupNested();
// Do the thing
el.$.forward.$.compose.$.basic1.notifyingValue = 42;
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 0);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNestedObserversOutput();
});
test('notification from set in top element', function() {
// Setup
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
setupNested();
// Do the thing
el.set('nested.obj.value', 42);
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 0);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNestedObserversOutput();
});
test('notification from set in composed element', function() {
// Setup
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
setupNested();
// Do the thing
el.$.compose.set('obj.value', 42);
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 0);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNestedObserversOutput();
});
test('notification from set in forward element', function() {
// Setup
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
setupNested();
// Do the thing
el.$.forward.set('obj.value', 42);
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 0);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNestedObserversOutput();
});
test('notification from set in forward\'s composed element', function() {
// Setup
var nested = {
obj: {
value: 41
}
};
el.nested = nested;
el.expectedNestedSubpath = 'nested.obj.value';
el.expectedNestedValue = 42;
el.expectedNestedObjSubpath = 'nested.obj.value';
el.expectedNestedObjValue = 42;
el.$.compose.expectedObjSubpath = 'obj.value';
el.$.compose.expectedObjValue = 42;
el.$.forward.expectedObjSubpath = 'obj.value';
el.$.forward.expectedObjValue = 42;
el.$.forward.$.compose.expectedObjSubpath = 'obj.value';
el.$.forward.$.compose.expectedObjValue = 42;
el.clearObserverCounts();
setupNested();
// Do the thing
el.$.forward.$.compose.set('obj.value', 42);
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 0);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNestedObserversOutput();
});
test('notification from object change in compose element', function() {
// Setup
el.nested = {
obj: {
value: 41
}
};
var obj = {
value: 42
};
el.expectedNestedSubpath = 'nested.obj';
el.expectedNestedValue = obj;
el.expectedNestedObjSubpath = 'nested.obj';
el.expectedNestedObjValue = obj;
el.$.compose.expectedObjSubpath = 'obj';
el.$.compose.expectedObjValue = obj;
el.$.forward.expectedObjSubpath = 'obj';
el.$.forward.expectedObjValue = obj;
el.$.forward.$.compose.expectedObjSubpath = 'obj';
el.$.forward.$.compose.expectedObjValue = obj;
el.clearObserverCounts();
var obj = setupComposedAndGetObject();
// Do the thing
el.$.compose.obj = obj;
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 1);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNonNestedObserversOutput();
});
test('notification from object change in forward element', function() {
// Setup
el.nested = {
obj: {
value: 41
}
};
var obj = {
value: 42
};
el.expectedNestedSubpath = 'nested.obj';
el.expectedNestedValue = obj;
el.expectedNestedObjSubpath = 'nested.obj';
el.expectedNestedObjValue = obj;
el.$.compose.expectedObjSubpath = 'obj';
el.$.compose.expectedObjValue = obj;
el.$.forward.expectedObjSubpath = 'obj';
el.$.forward.expectedObjValue = obj;
el.$.forward.$.compose.expectedObjSubpath = 'obj';
el.$.forward.$.compose.expectedObjValue = obj;
el.clearObserverCounts();
var obj = setupComposedAndGetObject();
// Do the thing
el.$.forward.obj = obj;
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 1);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNonNestedObserversOutput();
});
test('notification from object change in forward\'s compose element', function() {
// Setup
el.nested = {
obj: {
value: 41
}
};
var obj = {
value: 42
};
el.expectedNestedSubpath = 'nested.obj';
el.expectedNestedValue = obj;
el.expectedNestedObjSubpath = 'nested.obj';
el.expectedNestedObjValue = obj;
el.$.compose.expectedObjSubpath = 'obj';
el.$.compose.expectedObjValue = obj;
el.$.forward.expectedObjSubpath = 'obj';
el.$.forward.expectedObjValue = obj;
el.$.forward.$.compose.expectedObjSubpath = 'obj';
el.$.forward.$.compose.expectedObjValue = obj;
el.clearObserverCounts();
var obj = setupComposedAndGetObject();
// Do the thing
el.$.forward.$.compose.obj = obj;
// Verify
assert.equal(el.observerCounts.nestedSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjChanged, 1);
assert.equal(el.observerCounts.nestedObjSubpathChanged, 1);
assert.equal(el.observerCounts.nestedObjValueChanged, 1);
assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.compose.observerCounts.objValueChanged, 1);
assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1);
assert.equal(el.$.forward.observerCounts.objValueChanged, 1);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.basic.notifyingValue, 42);
assert.equal(el.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);
assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);
assert.equal(el.$.basic.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
verifyNonNestedObserversOutput();
});
test('negation', function() {
@ -1335,6 +1044,24 @@ suite('path API', function() {
});
suite('malformed observers', function() {
test('has nice message on failure', function() {
var thrown = false;
try {
Polymer({
is: 'x-broken',
observers: ['foo(missingParenthesis']
});
} catch (e) {
assert.equal(e.message, "Malformed observer expression 'foo(missingParenthesis'");
thrown = true;
}
assert.equal(thrown, true, "No exception thrown when parsing malformed observer");
});
});
</script>
</body>

View File

@ -57,6 +57,133 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
});
suite('debounce', function() {
test('debounce (no-wait)', function(done) {
var called = 0;
var cb = function() {
called++;
};
window.el1.debounce('foo', cb);
window.el1.debounce('foo', cb);
window.el1.debounce('foo', cb);
setTimeout(function() {
assert.equal(called, 1, 'debounce should be called exactly once');
done();
});
});
test('debounce (wait)', function(done) {
var called = 0;
var cb = function() {
called++;
};
window.el1.debounce('foo', cb);
window.el1.debounce('foo', cb, 50);
window.el1.debounce('foo', cb, 100);
setTimeout(function() {
assert.equal(called, 0, 'callback is not called yet');
}, 50);
setTimeout(function() {
assert.equal(called, 1, 'callback was called exactly once');
done();
}, 200);
});
test('debounce flushing', function(done) {
var called = 0;
var cb = function() {
called++;
};
window.el1.debounce('foo', cb);
window.el1.flushDebouncer('foo');
window.el1.debounce('foo', cb);
setTimeout(function() {
assert.equal(called, 2, 'debounce should be called twice');
done();
}, 100);
});
test('debounce state', function(done) {
window.el1.debounce('foo', function() {
assert.equal(window.el1.isDebouncerActive('foo'), false, 'debouncer is inactive after resolution');
done();
});
assert.equal(window.el1.isDebouncerActive('foo'), true, 'debouncer is active immediately after triggering');
});
test('debounce cancelling', function(done) {
var triggered = false;
window.el1.debounce('foo', function() {
triggered = true;
});
window.el1.cancelDebouncer('foo');
assert.equal(window.el1.isDebouncerActive('foo'), false, 'debouncer is inactive after cancelling');
setTimeout(function() {
assert.equal(triggered, false, 'debounce never fired');
done();
}, 100);
});
test('duplicate debouncer assignment (no-wait)', function(done) {
var a, b;
window.el1.debounce('foo', function() {
a = 'foo';
});
window.el1.debounce('foo', function() {
b = 'bar';
});
setTimeout(function() {
assert.equal(a, undefined, 'first debouncer was never fired');
assert.equal(b, 'bar', 'only the second debouncer callback was executed');
done();
});
});
test('duplicate debouncer assignment (wait)', function(done) {
var a, b, delay = 50;
window.el1.debounce('foo', function() {
a = 'foo';
}, delay);
window.el1.debounce('foo', function() {
b = 'bar';
}, delay);
setTimeout(function() {
assert.equal(a, undefined, 'first debouncer was never fired');
assert.equal(b, 'bar', 'only the second debouncer callback was executed');
done();
}, (delay+50));
});
});
</script>
</body>