Skip to content

Commit 0565e22

Browse files
author
Scott Miles
committed
move bookkeeping code below main code in polymer-element, factor prototype generation out of polymer-element and into it's own 'api' module
1 parent ffae850 commit 0565e22

File tree

4 files changed

+162
-129
lines changed

4 files changed

+162
-129
lines changed

gruntfile.js

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module.exports = function(grunt) {
3838
"declaration/events.js",
3939
"declaration/properties.js",
4040
"declaration/attributes.js",
41+
"declaration/prototype.js",
4142
"declaration/polymer-element.js",
4243
"deprecated.js"
4344
].map(function(n) {

polymer.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var modules = [
3131
"declaration/events.js",
3232
"declaration/properties.js",
3333
"declaration/attributes.js",
34+
"declaration/prototype.js",
3435
"declaration/polymer-element.js",
3536
"deprecated.js"
3637
].map(function(n) {

src/declaration/polymer-element.js

+60-129
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,11 @@
77

88
// imports
99

10-
var extend = Polymer.extend;
10+
var extend = scope.extend;
1111
var apis = scope.api.declaration;
1212

1313
// imperative implementation: Polymer()
1414

15-
// maps tag names to prototypes
16-
var prototypesByName = {};
17-
18-
function getRegisteredPrototype(name) {
19-
return prototypesByName[name];
20-
}
21-
22-
// elements waiting for prototype, by name
23-
var waitPrototype = {};
24-
2515
// specify an 'own' prototype for tag `name`
2616
function element(name, prototype) {
2717
//console.log('registering [' + name + ']');
@@ -31,71 +21,9 @@
3121
notifyPrototype(name);
3222
}
3323

34-
function notifyPrototype(name) {
35-
if (waitPrototype[name]) {
36-
waitPrototype[name].registerWhenReady();
37-
delete waitPrototype[name];
38-
}
39-
}
40-
41-
// elements waiting for super, by name
42-
var waitSuper = {};
43-
44-
function notifySuper(name) {
45-
registered[name] = true;
46-
var waiting = waitSuper[name];
47-
if (waiting) {
48-
waiting.forEach(function(w) {
49-
w.registerWhenReady();
50-
});
51-
delete waitSuper[name];
52-
}
53-
}
54-
55-
// track document.register'ed tag names
56-
57-
var registered = {};
58-
59-
function isRegistered(name) {
60-
return registered[name];
61-
}
62-
63-
// returns a prototype that chains to <tag> or HTMLElement
64-
function generatePrototype(tag) {
65-
return Object.create(HTMLElement.getPrototypeForTag(tag));
66-
}
67-
68-
// On platforms that do not support __proto__ (IE10), the prototype chain
69-
// of a custom element is simulated via installation of __proto__.
70-
// Although custom elements manages this, we install it here so it's
71-
// available during desugaring.
72-
function ensurePrototypeTraversal(prototype) {
73-
if (!Object.__proto__) {
74-
var ancestor = Object.getPrototypeOf(prototype);
75-
prototype.__proto__ = ancestor;
76-
if (scope.isBase(ancestor)) {
77-
ancestor.__proto__ = Object.getPrototypeOf(ancestor);
78-
}
79-
}
80-
}
81-
82-
function whenImportsLoaded(doThis) {
83-
if (window.HTMLImports && !HTMLImports.readyTime) {
84-
addEventListener('HTMLImportsLoaded', doThis);
85-
} else {
86-
doThis();
87-
}
88-
}
89-
9024
// declarative implementation: <polymer-element>
9125

92-
var prototype = generatePrototype();
93-
94-
extend(prototype, {
95-
// TODO(sjmiles): temporary BC
96-
readyCallback: function() {
97-
this.createdCallback();
98-
},
26+
var prototype = extend(Object.create(HTMLElement.prototype), {
9927
createdCallback: function() {
10028
// fetch the element name
10129
this.name = this.getAttribute('name');
@@ -113,7 +41,6 @@
11341
var script = document.createElement('script');
11442
script.textContent = 'Polymer(\'' + name + '\');';
11543
this.appendChild(script);
116-
11744
}
11845
return;
11946
}
@@ -127,7 +54,7 @@
12754
return;
12855
}
12956
}
130-
// TODO(sjmiles): HTMLImports polyfill awareness
57+
// TODO(sjmiles): HTMLImports polyfill awareness:
13158
// elements in the main document are likely to parse
13259
// in advance of elements in imports because the
13360
// polyfill parser is simulated
@@ -152,7 +79,6 @@
15279
// Potentially remove when spec bug is addressed.
15380
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407
15481
this.addResolvePathApi();
155-
ensurePrototypeTraversal(this.prototype);
15682
// declarative features
15783
this.desugar();
15884
// under ShadowDOMPolyfill, transforms to approximate missing CSS features
@@ -183,57 +109,6 @@
183109
// cache the list of custom prototype names for faster reflection
184110
this.cacheProperties();
185111
},
186-
// prototype marshaling
187-
// build prototype combining extendee, Polymer base, and named api
188-
generateCustomPrototype: function (name, extnds) {
189-
// basal prototype
190-
var prototype = this.generateBasePrototype(extnds);
191-
// mixin registered custom api
192-
return this.addNamedApi(prototype, name);
193-
},
194-
// build prototype combining extendee, Polymer base, and named api
195-
generateBasePrototype: function(extnds) {
196-
// create a prototype based on tag-name extension
197-
var prototype = generatePrototype(extnds);
198-
// insert base api in inheritance chain (if needed)
199-
return this.ensureBaseApi(prototype);
200-
},
201-
// install Polymer instance api into prototype chain, as needed
202-
ensureBaseApi: function(prototype) {
203-
if (!prototype.PolymerBase) {
204-
Object.keys(scope.api.instance).forEach(function(n) {
205-
extend(prototype, scope.api.instance[n]);
206-
});
207-
prototype = Object.create(prototype);
208-
}
209-
// inherit publishing meta-data
210-
this.inheritAttributesObjects(prototype);
211-
// inherit event delegates
212-
this.inheritDelegates(prototype);
213-
// return buffed-up prototype
214-
return prototype;
215-
},
216-
// mix api registered to 'name' into 'prototype'
217-
addNamedApi: function(prototype, name) {
218-
// combine custom api into prototype
219-
return extend(prototype, getRegisteredPrototype(name));
220-
},
221-
// make a fresh object that inherits from a prototype object
222-
inheritObject: function(prototype, name) {
223-
// copy inherited properties onto a new object
224-
prototype[name] = extend({}, Object.getPrototypeOf(prototype)[name]);
225-
},
226-
// register 'prototype' to custom element 'name', store constructor
227-
registerPrototype: function(name) {
228-
// register the custom type
229-
this.ctor = document.register(name, {
230-
prototype: this.prototype
231-
});
232-
// constructor shenanigans
233-
this.prototype.constructor = this.ctor;
234-
// register the prototype with HTMLElement for name lookup
235-
HTMLElement.register(name, this.prototype);
236-
},
237112
// if a named constructor is requested in element, map a reference
238113
// to the constructor to the given symbol
239114
publishConstructor: function() {
@@ -244,6 +119,8 @@
244119
}
245120
});
246121

122+
// semi-pluggable APIs
123+
// TODO(sjmiles): should be fully pluggable
247124
Object.keys(apis).forEach(function(n) {
248125
extend(prototype, apis[n]);
249126
});
@@ -252,7 +129,61 @@
252129

253130
document.register('polymer-element', {prototype: prototype});
254131

255-
// namespace shenanigans so we can expose our scope on the registration function
132+
// utility and bookkeeping
133+
134+
// maps tag names to prototypes
135+
var prototypesByName = {};
136+
137+
function getRegisteredPrototype(name) {
138+
return prototypesByName[name];
139+
}
140+
141+
// elements waiting for prototype, by name
142+
var waitPrototype = {};
143+
144+
function notifyPrototype(name) {
145+
if (waitPrototype[name]) {
146+
waitPrototype[name].registerWhenReady();
147+
delete waitPrototype[name];
148+
}
149+
}
150+
151+
// elements waiting for super, by name
152+
var waitSuper = {};
153+
154+
function notifySuper(name) {
155+
registered[name] = true;
156+
var waiting = waitSuper[name];
157+
if (waiting) {
158+
waiting.forEach(function(w) {
159+
w.registerWhenReady();
160+
});
161+
delete waitSuper[name];
162+
}
163+
}
164+
165+
// track document.register'ed tag names
166+
167+
var registered = {};
168+
169+
function isRegistered(name) {
170+
return registered[name];
171+
}
172+
173+
function whenImportsLoaded(doThis) {
174+
if (window.HTMLImports && !HTMLImports.readyTime) {
175+
addEventListener('HTMLImportsLoaded', doThis);
176+
} else {
177+
doThis();
178+
}
179+
}
180+
181+
// exports
182+
183+
scope.getRegisteredPrototype = getRegisteredPrototype;
184+
185+
// namespace shenanigans so we can expose our scope on the registration
186+
// function
256187

257188
// TODO(sjmiles): find a way to do this that is less terrible
258189
// copy window.Polymer properties onto `element()`

src/declaration/prototype.js

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2013 The Polymer Authors. All rights reserved.
3+
* Use of this source code is governed by a BSD-style
4+
* license that can be found in the LICENSE file.
5+
*/
6+
(function(scope) {
7+
8+
// imports
9+
10+
var api = scope.api;
11+
var isBase = scope.isBase;
12+
var extend = scope.extend;
13+
14+
// returns a prototype that chains to <tag> or HTMLElement
15+
function generatePrototype(tag) {
16+
return Object.create(HTMLElement.getPrototypeForTag(tag));
17+
}
18+
19+
// On platforms that do not support __proto__ (IE10), the prototype chain
20+
// of a custom element is simulated via installation of __proto__.
21+
// Although custom elements manages this, we install it here so it's
22+
// available during desugaring.
23+
function ensurePrototypeTraversal(prototype) {
24+
if (!Object.__proto__) {
25+
var ancestor = Object.getPrototypeOf(prototype);
26+
prototype.__proto__ = ancestor;
27+
if (isBase(ancestor)) {
28+
ancestor.__proto__ = Object.getPrototypeOf(ancestor);
29+
}
30+
}
31+
}
32+
33+
// declarative implementation: <polymer-element>
34+
35+
var prototype = generatePrototype();
36+
37+
// prototype api
38+
39+
var prototype = {
40+
// prototype marshaling
41+
// build prototype combining extendee, Polymer base, and named api
42+
generateCustomPrototype: function (name, extnds) {
43+
// basal prototype
44+
var prototype = this.generateBasePrototype(extnds);
45+
// mixin registered custom api
46+
this.addNamedApi(prototype, name);
47+
// x-platform fixups
48+
ensurePrototypeTraversal(prototype);
49+
return prototype;
50+
},
51+
// build prototype combining extendee, Polymer base, and named api
52+
generateBasePrototype: function(extnds) {
53+
// create a prototype based on tag-name extension
54+
var prototype = generatePrototype(extnds);
55+
// insert base api in inheritance chain (if needed)
56+
return this.ensureBaseApi(prototype);
57+
},
58+
// install Polymer instance api into prototype chain, as needed
59+
ensureBaseApi: function(prototype) {
60+
if (!prototype.PolymerBase) {
61+
Object.keys(api.instance).forEach(function(n) {
62+
extend(prototype, api.instance[n]);
63+
});
64+
prototype = Object.create(prototype);
65+
}
66+
// inherit publishing meta-data
67+
this.inheritAttributesObjects(prototype);
68+
// inherit event delegates
69+
this.inheritDelegates(prototype);
70+
// return buffed-up prototype
71+
return prototype;
72+
},
73+
// mix api registered to 'name' into 'prototype'
74+
addNamedApi: function(prototype, name) {
75+
// combine custom api into prototype
76+
return extend(prototype, scope.getRegisteredPrototype(name));
77+
},
78+
// make a fresh object that inherits from a prototype object
79+
inheritObject: function(prototype, name) {
80+
// copy inherited properties onto a new object
81+
prototype[name] = extend({}, Object.getPrototypeOf(prototype)[name]);
82+
},
83+
// register 'prototype' to custom element 'name', store constructor
84+
registerPrototype: function(name) {
85+
// register the custom type
86+
this.ctor = document.register(name, {
87+
prototype: this.prototype
88+
});
89+
// constructor shenanigans
90+
this.prototype.constructor = this.ctor;
91+
// register the prototype with HTMLElement for name lookup
92+
HTMLElement.register(name, this.prototype);
93+
}
94+
};
95+
96+
// exports
97+
98+
api.declaration.prototype = prototype;
99+
100+
})(Polymer);

0 commit comments

Comments
 (0)