@polymer/polymer
Version:
The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to
1,109 lines (1,065 loc) • 32.1 kB
HTML
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../polymer.html">
<link rel="import" href="../../lib/mixins/strict-binding-parser.html">
<dom-module id="x-basic">
<template>
<div id="boundChild"
value="{{ value }}"
negvalue="{{!bool}}"
attrvalue$="{{attrvalue}}"
sanitize-value="{{sanitizeValue}}"
computedvalue="{{computedvalue}}"
computedvaluetwo="{{computedvaluetwo}}"
camel-case="{{value}}"
computed-inline="{{computeInline(value,add, divide)}}"
computed-inline2="{{computeInline(value, add,divide)}}"
computed-inline3="{{computeInline(value, add,
divide )}}"
computedattribute$="{{computeInline(value, add,divide)}}"
computedattribute2$="{{computeInline(
value, add, divide)}}"
neg-computed-inline="{{!computeInline(value,add,divide)}}"
computed-negative-number="{{computeNegativeNumber(-1)}}"
computed-negative-literal="{{computeNegativeNumber(-A)}}"
computed-wildcard="{{computeWildcard(a, b.*)}}"
style$="{{boundStyle}}"
data-id$="{{dataSetId}}"
custom-event-value="{{customEventValue::custom}}"
custom-event-object-value="{{customEventObject.value::change}}"
computed-from-mixed-literals='{{computeFromLiterals(3, "foo", bool)}}'
computed-from-pure-literals='{{computeFromLiterals( 3, "foo")}}'
computed-from-tricky-function='{{$computeTrickyFunctionFromLiterals( 3, "foo")}}'
computed-from-tricky-literals="{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}"
computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,'zot'" )}}'
computed-from-tricky-literals3='{{computeFromTrickyLiterals(3,
"tricky\,'zot'" )}}'
computed-from-no-args="{{computeFromNoArgs( )}}"
no-computed="{{foobared(noInlineComputed)}}"
compoundAttr1$="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literalComputed')}}"
compoundAttr2$="literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literalComputed')}} literal4"
compoundAttr3$="[yes/no]: {{cpnd1}}, {{computeCompound('world', 'username ', 'Hello {0} ')}}"
computed-from-behavior="{{computeFromBehavior(value)}}"
computed-dynamic-fn="{{dynamicFn('hello', 'username')}}"
>
Test
<!-- Malformed bindings to be ignored -->
{{really.long.identifier.in.malformed.binding.should.be.ignored]}
{{computeFromLiterals(3, 'really.long.literal.in.malformed.binding.should.be.ignored)]}
<!-- Should still parse -->
{{computeFromLiterals(3, 'foo', bool)}}
</div>
<x-prop id="boundProps"
prop1="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literalComputed')}}"
prop2="literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literalComputed')}} literal4"
></x-prop>
<span id="boundText">{{text}}</span>
<span id="sanitizeText">{{sanitizeText}}</span>
<span idtest id="{{boundId}}"></span>
<s id="computedContent">{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}</s>
<s id="computedContent2">{{computeFromTrickyLiterals("(",3)}}</s>
<input id="boundInput" value="{{text::input}}">
<textarea id="boundTextArea" value="{{text::input}}"></textarea>
<div id="compound1">{{cpnd1}}{{cpnd2}}{{cpnd3.prop}}{{computeCompound(cpnd4, cpnd5, 'literalComputed')}}</div>
<div id="compound2">
literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literalComputed')}} literal4
</div>
<span id="boundWithDash">{{objectWithDash.binding-with-dash}}</span>
<script id="scriptWithBinding">
/* eslint-disable no-unused-vars */
function foo() {
return "We have a {{binding}} here";
}
/* eslint-enable no-unused-vars */
</script>
<style id="styleWithBinding">
:host {
content: '[[binding]]'
}
</style>
<span id="boundWithSlash">[[objectWithSlash.binding/with/slash]]</span>
<span id="jsonContent">[["Jan", 31],["Feb", 28],["Mar", 31]]</span>
<span id="nonEnglishUnicode">{{objectWithNonEnglishUnicode.商品名}}</span>
<span id="booleanTrue">foo(field, true): {{computeWithBoolean(otherValue, true)}}</span>
<span id="booleanFalse">foo(field, false): {{computeWithBoolean(otherValue, false)}}</span>
</template>
<script>
let ComputingBehavior = {
properties: {
computeFromBehavior: Function
},
computeFromBehavior: function(value) {
return 'computed:' + value;
}
};
Polymer({
is: 'x-basic',
behaviors: [ComputingBehavior],
properties: {
value: {
type: Number,
observer: 'valueChanged',
value: 10
},
computedvalue: {
computed: 'computeValue(value)',
observer: 'computedvalueChanged'
},
computedvaluetwo: {
computed: 'computeValue(valuetwo)',
observer: 'computedvaluetwoChanged'
},
notifyingvalue: {
type: Number,
notify: true,
observer: 'notifyingvalueChanged'
},
notifyingvalueWithDefault: {
notify: true,
value: 99
},
computednotifyingvalue: {
type: Number,
notify: true,
// Naming here is to test that a private setter is not created for
// computed properties
computed: '_setComputednotifyingvalue(notifyingvalue)'
},
computedFromMultipleValues: {
type: Number,
notify: true,
computed: 'computeFromMultipleValues(sum1, sum2, divide)',
observer: 'computedFromMultipleValuesChanged'
},
camelNotifyingValue: {
type: Number,
notify: true
},
readonlyvalue: {
type: Number,
readOnly: true,
notify: true,
observer: 'readonlyvalueChanged'
},
notifierWithoutComputing: {
type: Number,
observer: 'notifierWithoutComputingChanged',
notify: true,
value: 0
},
add: {
value: 20
},
divide: {
value: 2
},
customEventValue: {
type: Number,
observer: 'customEventValueChanged'
},
customEventObject: {
type: Object,
value: function() { return {}; }
},
boundId: {
type: String,
value: 'span'
},
noObserver: {
observer: 'foobared'
},
noComputedProp: {
computed: 'foobared(noComputed)'
},
objectWithDash: {
type: Object
},
title: {
observer: 'titleChanged'
},
dynamicFn: {
type: Function
}
},
observers: [
'multipleDepChangeHandler(dep1, dep2, dep3)',
'customEventObjectValueChanged(customEventObject.value)',
'foobared(noComplexObserver.*)'
],
created: function() {
this.observerCounts = {
valueChanged: 0,
computedvalueChanged: 0,
computedvaluetwoChanged: 0,
notifyingvalueChanged: 0,
readonlyvalueChanged: 0,
computedFromMultipleValuesChanged: 0,
multipleDepChangeHandler: 0,
customEventValueChanged: 0,
customEventObjectValueChanged: 0,
notifierWithoutComputingChanged: 0
};
this.titleChanged = sinon.spy();
this._dynamicFnCalled = false;
},
ready: function() {
this.isReady = true;
},
clearObserverCounts: function() {
for (var i in this.observerCounts) {
this.observerCounts[i] = 0;
}
},
valueChanged: function(val, old) {
this.observerCounts.valueChanged++;
assert.equal(arguments.length, 2, 'observer argument length wrong');
assert.equal(val, this.value, 'observer value argument wrong');
assert.equal(old, this._value, 'observer old argument wrong');
this._value = val;
},
computeValue: function(val) {
return val + 1;
},
computedvalueChanged: function(val, old) {
this.observerCounts.computedvalueChanged++;
assert.equal(arguments.length, 2, 'observer argument length wrong');
assert.equal(val, this.computedvalue, 'observer value argument wrong');
assert.equal(old, this._computedvalue, 'observer old argument wrong');
this._computedvalue = val;
},
computedvaluetwoChanged: function(val, old) {
this.observerCounts.computedvaluetwoChanged++;
assert.equal(arguments.length, 2, 'observer argument length wrong');
assert.equal(val, this.computedvaluetwo, 'observer value argument wrong');
assert.equal(old, this._computedvaluetwo, 'observer old argument wrong');
this._computedvaluetwo = val;
},
notifyingvalueChanged: function(val, old) {
this.observerCounts.notifyingvalueChanged++;
assert.equal(arguments.length, 2, 'observer argument length wrong');
assert.equal(val, this.notifyingvalue, 'observer value argument wrong');
assert.equal(old, this._notifyingvalue, 'observer old argument wrong');
this._notifyingvalue = val;
},
readonlyvalueChanged: function(val, old) {
this.observerCounts.readonlyvalueChanged++;
assert.equal(arguments.length, 2, 'observer argument length wrong');
assert.equal(val, this.readonlyvalue, 'observer value argument wrong');
assert.equal(old, this._readonlyvalue, 'observer old argument wrong');
this._readonlyvalue = val;
},
notifierWithoutComputingChanged: function() {
this.observerCounts.notifierWithoutComputingChanged++;
},
_setComputednotifyingvalue: function(val) {
return val + 2;
},
computeFromMultipleValues: function(sum1, sum2, divide) {
assert.equal(arguments.length, 3, 'observer argument length wrong');
assert.equal(sum1, this.sum1, 'observer value argument wrong');
assert.equal(sum2, this.sum2, 'observer value argument wrong');
assert.equal(divide, this.divide, 'observer value argument wrong');
if (!isNaN(sum1) && !isNaN(sum2) && !isNaN(divide)) {
return (sum1 + sum2) / divide;
}
},
computedFromMultipleValuesChanged: function(val, old) {
this.observerCounts.computedFromMultipleValuesChanged++;
assert.equal(arguments.length, 2, 'observer argument length wrong');
assert.equal(val, this.computedFromMultipleValues, 'observer value argument wrong');
assert.equal(old, this._computedFromMultipleValues, 'observer old argument wrong');
this._computedFromMultipleValues = val;
},
multipleDepChangeHandler: function(dep1, dep2, dep3) {
this.observerCounts.multipleDepChangeHandler++;
assert.equal(arguments.length, 3, 'observer argument length wrong');
assert.equal(dep1, this.dep1, 'dependency 1 argument wrong');
assert.equal(dep2, this.dep2, 'dependency 2 argument wrong');
assert.equal(dep3, this.dep3, 'dependency 3 argument wrong');
},
computeInline: function(value, add, divide) {
assert.equal(arguments.length, 3, 'observer argument length wrong');
assert.equal(value, this.value, 'dependency 1 argument wrong');
assert.equal(add, this.add, 'dependency 2 argument wrong');
assert.equal(divide, this.divide, 'dependency 3 argument wrong');
return (value + add) / divide;
},
customEventValueChanged: function(val, old) {
this.observerCounts.customEventValueChanged++;
assert.equal(arguments.length, 2, 'observer argument length wrong');
assert.equal(val, this.customEventValue, 'observer value argument wrong');
assert.equal(old, this._customEventValue, 'observer old argument wrong');
this._customEventValue = val;
},
customEventObjectValueChanged: function(val) {
this.observerCounts.customEventObjectValueChanged++;
assert.equal(arguments.length, 1, 'observer argument length wrong');
assert.equal(val, this.customEventObject.value, 'observer value argument wrong');
// note, no `old` argument for path observers
},
computeFromLiterals: function(num, str) {
assert.equal(num, 3);
assert.equal(str, 'foo');
return num + str;
},
$computeTrickyFunctionFromLiterals: function(num, str) {
return this.computeFromLiterals(num, str);
},
computeFromTrickyLiterals: function(a, b) {
return a + b;
},
computeFromNoArgs: function() {
return 'no args!';
},
computeNegativeNumber: function (num) {
return num;
},
computeCompound: function(a, b, c) {
return '' + (c || '') + (b || '') + (a || '');
},
computeWildcard: function(a, bInfo) {
return a + (bInfo && bInfo.base ? bInfo.base.value : 0);
},
computeWithBoolean: function(value, bool) {
return bool ? value : value * 2;
},
fireCustomNotifyingEvent: function() {
this.customNotifyingValue = 'changed!';
this.dispatchEvent(new CustomEvent('custom-notifying-value-changed'),
{value: this.customNotifyingValue});
},
dynamicFn: function() {}
});
HTMLImports.whenReady(() => {
class XBasicWithStrictBindingParser extends Polymer.StrictBindingParser(customElements.get('x-basic')) {
static get is() { return 'x-basic-strict-binding-parser'; }
}
customElements.define(XBasicWithStrictBindingParser.is, XBasicWithStrictBindingParser);
});
</script>
</dom-module>
<dom-module id="x-compose">
<template>
<x-basic id="basic1"
value="{{boundvalue}}"
notifyingvalue="{{boundnotifyingvalue}}"
notifyingvalue-with-default="{{boundnotifyingvalueWithDefault}}"
camel-notifying-value="{{boundnotifyingvalue}}"
computedvalue="{{boundcomputedvalue}}"
computednotifyingvalue="{{boundcomputednotifyingvalue}}"
readonlyvalue="{{boundreadonlyvalue}}"
custom-notifying-value="{{boundCustomNotifyingValue}}"
>
</x-basic>
<x-basic id="basic2"
value="[[boundvalue]]"
notifyingvalue="[[boundnotifyingvalue]]"
computedvalue="[[boundcomputedvalue]]"
computednotifyingvalue="[[boundcomputednotifyingvalue]]">
</x-basic>
<x-basic id="basic3"
notifyingvalue="{{computedValue}}"
computedvalue="{{value}}">
</x-basic>
<x-basic id="basic4"
notifyingvalue="{{!negatedValue}}">
</x-basic>
</template>
<script>
Polymer({
is: 'x-compose',
observers: [
'boundvalueChanged(boundvalue)',
'boundnotifyingvalueChanged(boundnotifyingvalue)',
'boundcomputedvalueChanged(boundcomputedvalue)',
'boundcomputednotifyingvalueChanged(boundcomputednotifyingvalue)',
'boundreadonlyvalueChanged(boundreadonlyvalue)',
'boundCustomNotifyingValueChanged(boundCustomNotifyingValue)',
'boundnotifyingvalueWithDefaultChanged(boundnotifyingvalueWithDefault)'
],
properties: {
a: {
value: 10
},
b: {
value: 20
},
computedValue: {
computed: 'computeComputedValue(a, b)'
},
negatedValue: {
value: false
}
},
created: function() {
this.observerCounts = {
boundvalueChanged: 0,
boundnotifyingvalueChanged: 0,
boundcomputedvalueChanged: 0,
boundcomputednotifyingvalueChanged: 0,
boundreadonlyvalueChanged: 0,
boundCustomNotifyingValueChanged: 0,
boundnotifyingvalueWithDefault: 0
};
},
computeComputedValue: function(a, b) {
return a + b;
},
clearObserverCounts: function() {
for (var i in this.observerCounts) {
this.observerCounts[i] = 0;
}
},
assertClientsReady: function() {
assert.isTrue(this.$.basic1.isReady, 'basic1 not `ready` by observer time');
assert.isTrue(this.$.basic2.isReady, 'basic2 element not `ready` by observer time');
assert.isTrue(this.$.basic3.isReady, 'basic3 element not `ready` by observer time');
assert.isTrue(this.$.basic4.isReady, 'basic4 element not `ready` by observer time');
},
boundvalueChanged: function() {
this.assertClientsReady();
this.observerCounts.boundvalueChanged++;
},
boundnotifyingvalueChanged: function() {
this.assertClientsReady();
this.observerCounts.boundnotifyingvalueChanged++;
},
boundcomputedvalueChanged: function() {
this.assertClientsReady();
this.observerCounts.boundcomputedvalueChanged++;
},
boundcomputednotifyingvalueChanged: function() {
this.assertClientsReady();
this.observerCounts.boundcomputednotifyingvalueChanged++;
},
boundreadonlyvalueChanged: function() {
this.assertClientsReady();
this.observerCounts.boundreadonlyvalueChanged++;
},
boundCustomNotifyingValueChanged: function() {
this.assertClientsReady();
this.observerCounts.boundCustomNotifyingValueChanged++;
},
boundnotifyingvalueWithDefaultChanged: function() {
this.assertClientsReady();
this.observerCounts.boundnotifyingvalueWithDefault++;
}
});
</script>
</dom-module>
<dom-module id="x-handle-notify-event">
<template>
<slot name="drawer"></slot>
<div id="before"></div>
<x-basic id="basic1"
on-notifyingvalue-with-default-changed="handleNotify">
</x-basic>
<div id="later"></div>
</template>
<script>
Polymer({
is: 'x-handle-notify-event',
properties: {
prop: {
observer: 'propChanged'
}
},
created: function() {
this.readySpy = sinon.spy();
this.afterSettingProp = sinon.spy();
this.propChanged = sinon.spy();
this.handleNotify = sinon.spy(function() {
this.prop = 'prop';
this.afterSettingProp();
});
},
ready: function() {
this.readySpy();
}
});
</script>
</dom-module>
<script>
Polymer({
is: 'x-reflect',
properties: {
reflectedobject: {
type: Object,
reflectToAttribute: true
},
reflectedarray: {
type: Array,
reflectToAttribute: true
},
reflectedNumber: {
type: Number,
reflectToAttribute: true
},
reflectedstring: {
type: String,
reflectToAttribute: true
},
reflectedboolean: {
type: Boolean,
reflectToAttribute: true
},
reflecteddate: {
type: Date,
reflectToAttribute: true
}
}
});
</script>
<script>
Polymer({
is: 'x-prop',
properties: {
prop1: {
value: 'default',
observer: 'prop1Changed'
},
prop2: {
value: 'default',
observer: function(newProp, oldProp) { return this.prop2Changed(newProp, oldProp); }
}
},
created: function() {
this.prop1Changed = sinon.spy();
this.prop2Changed = sinon.spy();
}
});
</script>
<script>
Polymer({
is: 'x-notifies1',
properties: {
notifies: {
notify: true
}
},
ready: function() {
this.notifies = 'readyValue';
}
});
</script>
<dom-module id="x-notifies2">
<template>
<x-notifies1 id="notifies1" notifies="{{shouldChange}}"></x-notifies1>
</template>
</dom-module>
<script>
Polymer({
is: 'x-notifies2',
properties: {
notifies: {
notify: true
}
}
});
</script>
<dom-module id="x-notifies3">
<template>
<x-notifies2 id="notifies2" notifies="{{shouldNotChange}}"></x-notifies2>
</template>
</dom-module>
<script>
Polymer({
is: 'x-notifies3',
properties: {
shouldNotChange: {
observer: 'shouldNotChangeChanged'
}
},
shouldNotChangeChanged: function() { }
});
</script>
<dom-module id="x-entity-and-binding">
<template>
<p>©</p>
<p id="binding">{{myText}}</p>
</template>
</dom-module>
<script>
Polymer({
is: "x-entity-and-binding",
properties: {
myText: {
type: String,
value: 'binding'
}
}
});
</script>
<dom-module id="x-input-value">
<template>
<input id="input" value$="{{inputValue}}">
</template>
<script>
Polymer({
is: 'x-input-value'
});
</script>
</dom-module>
<dom-module id="x-bind-is-attached">
<template>
<div id="check">{{isAttached}}</div>
</template>
<script>
Polymer({
is: 'x-bind-is-attached',
properties: {
isAttached: {
observer: '_isAttachedChanged'
}
},
_isAttachedChanged: function() {}
});
</script>
</dom-module>
<dom-module id="x-order-of-effects-grand-parent">
<template>
<x-order-of-effects id="child" base="{{base}}"></x-order-of-effects>
</template>
</dom-module>
<dom-module id="x-order-of-effects">
<template>
<x-order-of-effects-child
prop1="[[base]]"
prop2="[[_computedAnnotation(base)]]"
></x-order-of-effects-child>
</template>
<script>
(function() {
var invocations = [];
Polymer({
is: 'x-order-of-effects-grand-parent',
initializeWhenCreated: true,
properties: {
base: {
observer: '_childPropertyChanged'
}
},
_childPropertyChanged: function() {
invocations.push('notify');
}
});
Polymer({
is: 'x-order-of-effects',
initializeWhenCreated: true,
properties: {
base: {
type: String,
observer: '_observer',
notify: true,
reflectToAttribute: true
},
computed: {
type: String,
computed: '_computed(base)'
}
},
observers: ['_complexObserver(base)'],
created: function() {
this.invocations = invocations;
},
attributeChanged(name) {
if (name == 'base') {
invocations.push('reflect');
}
},
_computed: function(base) {
invocations.push('compute');
return base;
},
_computedAnnotation: function(base) {
return base;
},
_observer: function() {
invocations.push('observe');
},
_complexObserver: function() {
invocations.push('observe');
}
});
Polymer({
is: 'x-order-of-effects-child',
properties: {
prop1: {
observer: '_prop1Changed'
},
prop2: {
observer: '_prop2Changed'
}
},
_prop1Changed: function() {
invocations.push('propagate');
},
_prop2Changed: function() {
invocations.push('propagate');
}
});
})();
</script>
</dom-module>
<dom-module id="x-bind-computed-property">
<template>
<div id="check">[[translateMessage('Hello World.')]]</div>
</template>
<script>
(function(){
var TranslateBehavior = {
properties: {
translateMessage: {
type: Function,
computed: '_computeTranslateFn(translator)'
}
}
};
Polymer({
is: 'x-bind-computed-property',
behaviors: [TranslateBehavior],
properties: {
translator: {
type: Function,
value: function() {
return function(message) {
return 'translated: ' + message;
};
}
}
},
_computeTranslateFn: function(translator) {
return function(message) {
return translator(message);
};
}
});
})();
</script>
</dom-module>
<dom-module id="x-bind-computed-property-late-translator">
<template>
<div id="check">[[translateMessage(message)]]</div>
</template>
<script>
Polymer({
is: 'x-bind-computed-property-late-translator',
properties: {
message: {
type: String,
value: 'Hello'
},
translateMessage: {
type: Function,
computed: '_computeTranslateFn(translator)'
},
translator: {
type: Function
}
},
_computeTranslateFn: function(translator) {
return function(message) {
return translator(message);
};
}
});
</script>
</dom-module>
<dom-module id="x-bind-bad-attribute-name">
<template>
<div -u-p-c-a-s-e$="[[UPCASE]]"></div>
</template>
<script>
Polymer({
is: 'x-bind-bad-attribute-name',
properties: {
UPCASE: {
type: String,
value: 'foo'
}
}
});
</script>
</dom-module>
<dom-module id="x-child-template-with-dynamic-fn">
<template>
<template is="dom-if" if="[[visible]]">
<p>[[translateMessage('text')]]</p>
</template>
</template>
<script>
Polymer({
is: 'x-child-template-with-dynamic-fn',
properties: {
translateMessage: {
type: Function,
value: function () {
return function(str) {
return str;
};
}
},
visible: {
type: Boolean,
value: true
}
}
});
</script>
</dom-module>
<dom-module id="x-propagate">
<script>
Polymer({
is: 'x-propagate',
properties: {
value: {
type: Number,
value: -1
}
},
observers: [
'_boundOne(value)',
'_boundTwo(value)'
],
_boundOne: function(value) {
if (value < 0) {
this.value = 1;
}
},
_boundTwo: function(value) {
if (value < 0) {
this.value = 2;
}
}
});
</script>
</dom-module>
<dom-module id="x-interop">
<template>
<x-polymer id="polymer" array="{{array}}" compound="**{{array}}**">{{array}}</x-polymer>
<x-raw id="raw" array="{{array}}" value="{{value}}" compound="**{{array}}**"></x-raw>
</template>
</dom-module>
<script>
class XRaw extends HTMLElement {
constructor() {
super();
this._value = null;
this.valueChangedCount = 0;
this.valueChanged = sinon.spy();
this.arrayChanged = sinon.spy();
this.compoundChanged = sinon.spy();
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
this.valueChanged(value);
this.notify();
}
get compound() {
return this._compound;
}
set compound(value) {
this._compound = value;
this.compoundChanged(value);
}
increment() {
this._value++;
this.notify();
}
notify() {
this.dispatchEvent(new CustomEvent('value-changed'));
}
set array(value) {
this.arrayChanged(value);
this.textContent = value;
}
}
customElements.define('x-raw', XRaw);
Polymer({
is: 'x-polymer',
created: function() {
this.arrayChanged = sinon.spy();
this.compoundChanged = sinon.spy();
},
observers: ['compoundChanged(compound)'],
set array(value) {
this._array = value;
this.arrayChanged(value);
},
get array() {
return this._array;
}
});
Polymer({
is: 'x-interop',
properties: {
value: {
value: 10
},
array: {
value: function() {
return [1,2,3];
}
}
}
});
Polymer({
is: 'x-template-proto',
_template: (function() {
let template = document.createElement('template');
template.innerHTML = '<div id="div" on-click="clicked">{{bound}}</div>';
return template;
})(),
properties: {
bound: {
value: 'yes'
}
},
clicked: sinon.spy()
});
let TemplateBehavior = {
_template: (function() {
let template = document.createElement('template');
template.innerHTML = '<div id="div" on-click="clicked">{{bound}}</div>';
return template;
})(),
properties: {
bound: {
value: 'yes'
}
},
clicked: sinon.spy()
};
Polymer({
is: 'x-template-behavior',
behaviors: [TemplateBehavior]
});
</script>
<dom-module id="x-immutable-a">
<template>
<x-immutable-b b="[[a.b]]" x="[[a.x]]" id="b"></x-immutable-b>
</template>
</dom-module>
<dom-module id="x-immutable-b">
<template>
<x-immutable-c c="[[b.c]]" x="[[b.x]]" id="c"></x-immutable-b>
</template>
</dom-module>
<script>
Polymer({
is: 'x-immutable-a',
observers: ['aChanged(a)', 'xChanged(x)'],
created() {
this.aChanged = sinon.spy();
this.xChanged = sinon.spy();
}
});
class XImmutableB extends Polymer.Element {
static get is() { return 'x-immutable-b'; }
static get observers() { return ['bChanged(b)', 'xChanged(x)']; }
constructor() {
super();
this.bChanged = sinon.spy();
this.xChanged = sinon.spy();
}
}
customElements.define('x-immutable-b', XImmutableB);
Polymer({
is: 'x-immutable-c',
observers: ['cChanged(c)', 'xChanged(x)'],
created() {
this.cChanged = sinon.spy();
this.xChanged = sinon.spy();
}
});
</script>
<dom-module id="x-mutable-a">
<template>
<x-mutable-b b="[[a.b]]" x="[[a.x]]" id="b"></x-mutable-b>
</template>
</dom-module>
<dom-module id="x-mutable-b">
<template>
<x-mutable-c c="[[b.c]]" x="[[b.x]]" id="c"></x-mutable-b>
</template>
</dom-module>
<script>
Polymer({
is: 'x-mutable-a',
behaviors: [Polymer.MutableDataBehavior],
observers: ['aChanged(a)', 'xChanged(x)'],
created() {
this.aChanged = sinon.spy();
this.xChanged = sinon.spy();
}
});
class XMutableB extends Polymer.MutableData(Polymer.Element) {
static get is() { return 'x-mutable-b'; }
static get observers() { return ['bChanged(b)', 'xChanged(x)']; }
constructor() {
super();
this.bChanged = sinon.spy();
this.xChanged = sinon.spy();
}
}
customElements.define('x-mutable-b', XMutableB);
Polymer({
is: 'x-mutable-c',
behaviors: [Polymer.MutableDataBehavior],
observers: ['cChanged(c)', 'xChanged(x)'],
created() {
this.cChanged = sinon.spy();
this.xChanged = sinon.spy();
}
});
</script>
<script>
class SuperObserverElement extends Polymer.Element {
static get is() { return 'super-observer-element'; }
static get properties() {
return {
prop: {
value: 'String',
observer() {
this.__observerCalled++;
}
}
};
}
}
SuperObserverElement.prototype.__observerCalled = 0;
customElements.define(SuperObserverElement.is, SuperObserverElement);
class SubObserverElement extends SuperObserverElement {
static get is() { return 'sub-observer-element'; }
}
customElements.define(SubObserverElement.is, SubObserverElement);
</script>
<dom-module id="svg-element">
<template>
<svg id="svg" viewBox="[[value]]"></svg>
</template>
<script>
class SVGElement extends Polymer.Element {
static get is() { return 'svg-element'; }
static get properties() {
return {
value: {
type: String,
value: '0 0 50 50'
}
};
}
}
customElements.define(SVGElement.is, SVGElement);
</script>
</dom-module>