Skip to content

Commit 7954f93

Browse files
committed
Add Polymer.instanceof & isInstance. Fixes #2083.
1 parent fab2ed7 commit 7954f93

11 files changed

Lines changed: 68 additions & 30 deletions

File tree

‎polymer-micro.html‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
this._prepAttributes();
3232
// shared behaviors
3333
this._prepBehaviors();
34-
// inheritance
35-
this._prepExtends();
3634
// factory
3735
this._prepConstructor();
3836
},

‎polymer-mini.html‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828
this._prepAttributes();
2929
// shared behaviors
3030
this._prepBehaviors();
31-
// inheritance
32-
this._prepExtends();
33-
// factory
31+
// factory
3432
this._prepConstructor();
3533
// template
3634
this._prepTemplate();

‎polymer.html‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
this._prepIs();
3131
// attributes
3232
this._prepAttributes();
33-
// inheritance
34-
this._prepExtends();
3533
// factory
3634
this._prepConstructor();
3735
// template

‎src/lib/base.html‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

1212
Polymer.Base = {
1313

14+
// Used for `isInstance` type checking; cannot use `instanceof` because
15+
// there is no common Polymer.Base in the prototype chain between type
16+
// extensions and normal custom elements
17+
__isPolymerInstance__: true,
18+
1419
// pluggable features
1520
// `this` context is a prototype, not an instance
1621
_addFeature: function(feature) {
@@ -118,6 +123,18 @@
118123

119124
Polymer.Base = Polymer.Base.chainObject(Polymer.Base, HTMLElement.prototype);
120125

126+
if (window.CustomElements) {
127+
Polymer.instanceof = CustomElements.instanceof;
128+
} else {
129+
Polymer.instanceof = function(obj, ctor) {
130+
return obj instanceof ctor;
131+
};
132+
}
133+
134+
Polymer.isInstance = function(obj) {
135+
return Boolean(obj && obj.__isPolymerInstance__);
136+
};
137+
121138
// TODO(sjmiles): ad hoc telemetry
122139
Polymer.telemetry.instanceCount = 0;
123140

‎src/lib/dom-api.html‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@
177177
var fragContent = (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) &&
178178
!node.__noContent && Polymer.dom(node).querySelector(CONTENT);
179179
var wrappedContent = fragContent &&
180-
(Polymer.dom(fragContent).parentNode.nodeType !==
180+
(Polymer.dom(fragContent).parentNode.nodeType !==
181181
Node.DOCUMENT_FRAGMENT_NODE);
182182
var hasContent = fragContent || (node.localName === CONTENT);
183183
// There are 2 possible cases where a distribution may need to occur:
@@ -231,8 +231,8 @@
231231
return parent && parent.shadyRoot && hasInsertionPoint(parent.shadyRoot);
232232
},
233233

234-
// NOTE: if `ensureComposedRemoval` is true then the node should be
235-
// removed from its composed parent.
234+
// NOTE: if `ensureComposedRemoval` is true then the node should be
235+
// removed from its composed parent.
236236
_removeNodeFromHost: function(node, ensureComposedRemoval) {
237237
var hostNeedsDist;
238238
var root;
@@ -459,7 +459,7 @@
459459

460460
importNode: function(externalNode, deep) {
461461
// for convenience use this node's ownerDoc if the node isn't a document
462-
var doc = this.node instanceof HTMLDocument ? this.node :
462+
var doc = this.node instanceof Document ? this.node :
463463
this.node.ownerDocument;
464464
var n = nativeImportNode.call(doc, externalNode, false);
465465
if (deep) {
@@ -506,7 +506,7 @@
506506
this.domApi._distributeParent();
507507
},
508508
contains: function() {
509-
return this.node.classList.contains.apply(this.node.classList,
509+
return this.node.classList.contains.apply(this.node.classList,
510510
arguments);
511511
}
512512
}
@@ -682,7 +682,7 @@
682682
}
683683

684684
DomApi.prototype.importNode = function(externalNode, deep) {
685-
var doc = this.node instanceof HTMLDocument ? this.node :
685+
var doc = this.node instanceof Document ? this.node :
686686
this.node.ownerDocument;
687687
return doc.importNode(externalNode, deep);
688688
}
@@ -776,8 +776,8 @@
776776

777777
function getLightChildren(node) {
778778
var children = node._lightChildren;
779-
// TODO(sorvell): it's more correct to use _composedChildren instead of
780-
// childNodes here but any trivial failure to use Polymer.dom
779+
// TODO(sorvell): it's more correct to use _composedChildren instead of
780+
// childNodes here but any trivial failure to use Polymer.dom
781781
// will result in an error so we avoid using _composedChildren
782782
return children ? children : node.childNodes;
783783
}

‎src/lib/polymer-bootstrap.html‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@
3838
};
3939

4040
var desugar = function(prototype) {
41-
prototype = Polymer.Base.chainObject(prototype, Polymer.Base);
41+
// Note: need to chain user prorotype with the correct type-extended
42+
// version of Polymer.Base; this is especially important when you can't
43+
// prototype swizzle (e.g. IE10), since CustomElemets uses getPrototypeOf
44+
var base = Polymer.Base;
45+
if (prototype.extends) {
46+
base = Polymer.Base._getExtendedPrototype(prototype.extends);
47+
}
48+
prototype = Polymer.Base.chainObject(prototype, base);
4249
prototype.registerCallback();
4350
return prototype.constructor;
4451
};

‎src/lib/template/dom-bind.html‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
},
7373

7474
_registerFeatures: function() {
75-
this._prepExtends();
7675
this._prepConstructor();
7776
},
7877

‎src/micro/extends.html‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@
4747

4848
Polymer.Base._addFeature({
4949

50-
_prepExtends: function() {
51-
if (this.extends) {
52-
this.__proto__ = this._getExtendedPrototype(this.extends);
53-
}
54-
},
55-
5650
_getExtendedPrototype: function(tag) {
5751
return this._getExtendedNativePrototype(tag);
5852
},

‎src/standard/x-styling.html‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
_findStyleHost: function() {
5656
var e = this, root;
5757
while (root = Polymer.dom(e).getOwnerRoot()) {
58-
if (root.host && root.host._computeStyleProperties) {
58+
if (Polymer.isInstance(root.host)) {
5959
return root.host;
6060
}
6161
e = root.host;
@@ -174,8 +174,10 @@
174174
serializeValueToAttribute: function(value, attribute, node) {
175175
// override to ensure whenever classes are set, we need to shim them.
176176
node = node || this;
177-
if (attribute === 'class') {
177+
if (attribute === 'class' && !nativeShadow) {
178178
// host needed to scope styling.
179+
// Under Shady DOM, domHost is safe to use here because we know it
180+
// is a Polymer element
179181
var host = node === this ? (this.domHost || this.dataHost) : this;
180182
if (host) {
181183
value = host._scopeElementClass(node, value);
@@ -206,7 +208,7 @@
206208
* been made that affect the values of custom properties.
207209
*
208210
* @method updateStyles
209-
* @param {Object=} properties Properties object which is mixed into
211+
* @param {Object=} properties Properties object which is mixed into
210212
* the element's `customStyle` property. This argument provides a shortcut
211213
* for setting `customStyle` and then calling `updateStyles`.
212214
*/

‎test/unit/micro.html‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,22 @@
4242

4343
});
4444

45-
suite('constructor', function() {
45+
suite('type checking & constructor', function() {
46+
47+
test('Polymer.isInstance for non-instance', function() {
48+
var el = document.createElement('div');
49+
assert.isTrue(Polymer.instanceof(el, HTMLElement));
50+
assert.isTrue(Polymer.instanceof(el, HTMLDivElement));
51+
assert.isFalse(Polymer.isInstance(el));
52+
});
53+
54+
test('document.createElement', function() {
55+
var MyElement = Polymer({is: 'my-basic'});
56+
var el = document.createElement('my-basic');
57+
assert.isTrue(Polymer.instanceof(el, HTMLElement));
58+
assert.isTrue(Polymer.instanceof(el, MyElement));
59+
assert.isTrue(Polymer.isInstance(el));
60+
});
4661

4762
test('normal constructor', function() {
4863
var MyElement = Polymer({is: 'my-element'});
@@ -53,6 +68,9 @@
5368
assert.instanceOf(el, MyElement, 'Instance of MyElement');
5469
}
5570
assert.instanceOf(el, HTMLElement, 'Instance of HTMLElement');
71+
assert.isTrue(Polymer.instanceof(el, HTMLElement));
72+
assert.isTrue(Polymer.instanceof(el, MyElement));
73+
assert.isTrue(Polymer.isInstance(el));
5674
});
5775

5876
test('type-extension constructor', function() {
@@ -62,8 +80,12 @@
6280
if (Object.__proto__) {
6381
// instanceof Constructor only supported where proto swizzling is possible
6482
assert.instanceOf(el, MyInput, 'Instance of MyInput');
83+
assert.instanceOf(el, HTMLElement, 'Instance of HTMLInputElement');
6584
}
66-
assert.instanceOf(el, HTMLElement, 'Instance of HTMLInputElement');
85+
assert.isTrue(Polymer.instanceof(el, HTMLInputElement));
86+
assert.isTrue(Polymer.instanceof(el, HTMLElement));
87+
assert.isTrue(Polymer.instanceof(el, MyInput));
88+
assert.isTrue(Polymer.isInstance(el));
6789
});
6890

6991
test('custom constructor', function() {
@@ -81,6 +103,9 @@
81103
assert.instanceOf(el, HTMLElement, 'Instance of HTMLElement');
82104
}
83105
assert.equal(el.title, 'my title', 'Argument passed to constructor');
106+
assert.isTrue(Polymer.instanceof(el, HTMLElement));
107+
assert.isTrue(Polymer.instanceof(el, MyElement2));
108+
assert.isTrue(Polymer.isInstance(el));
84109
});
85110

86111
});

0 commit comments

Comments
 (0)