Skip to content
This repository was archived by the owner on Mar 13, 2018. It is now read-only.

Commit 315f9a4

Browse files
author
Scott J. Miles
committed
throw exception if name argument to document.register contains no dash (+test)
1 parent f485280 commit 315f9a4

2 files changed

Lines changed: 77 additions & 54 deletions

File tree

src/CustomElements.js

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,23 @@ if (useNative) {
5656
*
5757
* When a registered element is created, a `readyCallback` method is called
5858
* in the scope of the element. The `readyCallback` method can be specified on
59-
* either `inOptions.prototype` or `inOptions.lifecycle` with the latter taking
59+
* either `options.prototype` or `options.lifecycle` with the latter taking
6060
* precedence.
6161
*
6262
* @method register
63-
* @param {String} inName The tag name to register. Must include a dash ('-'),
63+
* @param {String} name The tag name to register. Must include a dash ('-'),
6464
* for example 'x-component'.
65-
* @param {Object} inOptions
66-
* @param {String} [inOptions.extends]
65+
* @param {Object} options
66+
* @param {String} [options.extends]
6767
* (_off spec_) Tag name of an element to extend (or blank for a new
6868
* element). This parameter is not part of the specification, but instead
6969
* is a hint for the polyfill because the extendee is difficult to infer.
7070
* Remember that the input prototype must chain to the extended element's
7171
* prototype (or HTMLElement.prototype) regardless of the value of
7272
* `extends`.
73-
* @param {Object} inOptions.prototype The prototype to use for the new
73+
* @param {Object} options.prototype The prototype to use for the new
7474
* element. The prototype must inherit from HTMLElement.
75-
* @param {Object} [inOptions.lifecycle]
75+
* @param {Object} [options.lifecycle]
7676
* Callbacks that fire at important phases in the life of the custom
7777
* element.
7878
*
@@ -89,18 +89,23 @@ if (useNative) {
8989
* });
9090
* @return {Function} Constructor for the newly registered type.
9191
*/
92-
function register(inName, inOptions) {
93-
//console.warn('document.register("' + inName + '", ', inOptions, ')');
92+
function register(name, options) {
93+
//console.warn('document.register("' + name + '", ', options, ')');
9494
// construct a defintion out of options
95-
// TODO(sjmiles): probably should clone inOptions instead of mutating it
96-
var definition = inOptions || {};
97-
if (!inName) {
95+
// TODO(sjmiles): probably should clone options instead of mutating it
96+
var definition = options || {};
97+
if (!name) {
9898
// TODO(sjmiles): replace with more appropriate error (EricB can probably
9999
// offer guidance)
100-
throw new Error('Name argument must not be empty');
100+
throw new Error('document.register: first argument `name` must not be empty');
101+
}
102+
if (name.indexOf('-') < 0) {
103+
// TODO(sjmiles): replace with more appropriate error (EricB can probably
104+
// offer guidance)
105+
throw new Error('document.register: first argument `name` must contain a dash (\'-\'). Argument was \'' + String(name) + '\'.');
101106
}
102107
// record name
103-
definition.name = inName;
108+
definition.name = name;
104109
// must have a prototype, default to an extension of HTMLElement
105110
// TODO(sjmiles): probably should throw if no prototype, check spec
106111
if (!definition.prototype) {
@@ -123,7 +128,7 @@ if (useNative) {
123128
// overrides to implement attributeChanged callback
124129
overrideAttributeApi(definition.prototype);
125130
// 7.1.5: Register the DEFINITION with DOCUMENT
126-
registerDefinition(inName, definition);
131+
registerDefinition(name, definition);
127132
// 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
128133
// 7.1.8. Return the output of the previous step.
129134
definition.ctor = generateConstructor(definition);
@@ -138,98 +143,98 @@ if (useNative) {
138143
return definition.ctor;
139144
}
140145

141-
function ancestry(inExtends) {
142-
var extendee = registry[inExtends];
146+
function ancestry(extnds) {
147+
var extendee = registry[extnds];
143148
if (extendee) {
144149
return ancestry(extendee.extends).concat([extendee]);
145150
}
146151
return [];
147152
}
148153

149-
function resolveTagName(inDefinition) {
154+
function resolveTagName(definition) {
150155
// if we are explicitly extending something, that thing is our
151156
// baseTag, unless it represents a custom component
152-
var baseTag = inDefinition.extends;
157+
var baseTag = definition.extends;
153158
// if our ancestry includes custom components, we only have a
154159
// baseTag if one of them does
155-
for (var i=0, a; (a=inDefinition.ancestry[i]); i++) {
160+
for (var i=0, a; (a=definition.ancestry[i]); i++) {
156161
baseTag = a.is && a.tag;
157162
}
158163
// our tag is our baseTag, if it exists, and otherwise just our name
159-
inDefinition.tag = baseTag || inDefinition.name;
164+
definition.tag = baseTag || definition.name;
160165
if (baseTag) {
161166
// if there is a base tag, use secondary 'is' specifier
162-
inDefinition.is = inDefinition.name;
167+
definition.is = definition.name;
163168
}
164169
}
165170

166-
function resolvePrototypeChain(inDefinition) {
171+
function resolvePrototypeChain(definition) {
167172
// if we don't support __proto__ we need to locate the native level
168173
// prototype for precise mixing in
169174
if (!Object.__proto__) {
170175
// default prototype
171176
var native = HTMLElement.prototype;
172177
// work out prototype when using type-extension
173-
if (inDefinition.is) {
174-
var inst = document.createElement(inDefinition.tag);
178+
if (definition.is) {
179+
var inst = document.createElement(definition.tag);
175180
native = Object.getPrototypeOf(inst);
176181
}
177182
// ensure __proto__ reference is installed at each point on the prototype
178183
// chain.
179184
// NOTE: On platforms without __proto__, a mixin strategy is used instead
180185
// of prototype swizzling. In this case, this generated __proto__ provides
181186
// limited support for prototype traversal.
182-
var proto = inDefinition.prototype, ancestor;
187+
var proto = definition.prototype, ancestor;
183188
while (proto && (proto !== native)) {
184189
var ancestor = Object.getPrototypeOf(proto);
185190
proto.__proto__ = ancestor;
186191
proto = ancestor;
187192
}
188193
}
189194
// cache this in case of mixin
190-
inDefinition.native = native;
195+
definition.native = native;
191196
}
192197

193198
// SECTION 4
194199

195-
function instantiate(inDefinition) {
200+
function instantiate(definition) {
196201
// 4.a.1. Create a new object that implements PROTOTYPE
197202
// 4.a.2. Let ELEMENT by this new object
198203
//
199204
// the custom element instantiation algorithm must also ensure that the
200205
// output is a valid DOM element with the proper wrapper in place.
201206
//
202-
return upgrade(domCreateElement(inDefinition.tag), inDefinition);
207+
return upgrade(domCreateElement(definition.tag), definition);
203208
}
204209

205-
function upgrade(inElement, inDefinition) {
210+
function upgrade(element, definition) {
206211
// some definitions specify an 'is' attribute
207-
if (inDefinition.is) {
208-
inElement.setAttribute('is', inDefinition.is);
212+
if (definition.is) {
213+
element.setAttribute('is', definition.is);
209214
}
210-
// make 'element' implement inDefinition.prototype
211-
implement(inElement, inDefinition);
215+
// make 'element' implement definition.prototype
216+
implement(element, definition);
212217
// flag as upgraded
213-
inElement.__upgraded__ = true;
214-
// there should never be a shadow root on inElement at this point
218+
element.__upgraded__ = true;
219+
// there should never be a shadow root on element at this point
215220
// we require child nodes be upgraded before `created`
216-
scope.upgradeSubtree(inElement);
221+
scope.upgradeSubtree(element);
217222
// lifecycle management
218-
created(inElement);
223+
created(element);
219224
// OUTPUT
220-
return inElement;
225+
return element;
221226
}
222227

223-
function implement(inElement, inDefinition) {
228+
function implement(element, definition) {
224229
// prototype swizzling is best
225230
if (Object.__proto__) {
226-
inElement.__proto__ = inDefinition.prototype;
231+
element.__proto__ = definition.prototype;
227232
} else {
228233
// where above we can re-acquire inPrototype via
229234
// getPrototypeOf(Element), we cannot do so when
230235
// we use mixin, so we install a magic reference
231-
customMixin(inElement, inDefinition.prototype, inDefinition.native);
232-
inElement.__proto__ = inDefinition.prototype;
236+
customMixin(element, definition.prototype, definition.native);
237+
element.__proto__ = definition.prototype;
233238
}
234239
}
235240

@@ -257,10 +262,10 @@ if (useNative) {
257262
}
258263
}
259264

260-
function created(inElement) {
265+
function created(element) {
261266
// invoke createdCallback
262-
if (inElement.createdCallback) {
263-
inElement.createdCallback();
267+
if (element.createdCallback) {
268+
element.createdCallback();
264269
}
265270
}
266271

@@ -293,13 +298,13 @@ if (useNative) {
293298

294299
var registry = {};
295300

296-
function registerDefinition(inName, inDefinition) {
297-
registry[inName] = inDefinition;
301+
function registerDefinition(name, definition) {
302+
registry[name] = definition;
298303
}
299304

300-
function generateConstructor(inDefinition) {
305+
function generateConstructor(definition) {
301306
return function() {
302-
return instantiate(inDefinition);
307+
return instantiate(definition);
303308
};
304309
}
305310

@@ -313,11 +318,11 @@ if (useNative) {
313318
return domCreateElement(tag);
314319
}
315320

316-
function upgradeElement(inElement) {
317-
if (!inElement.__upgraded__ && (inElement.nodeType === Node.ELEMENT_NODE)) {
318-
var type = inElement.getAttribute('is') || inElement.localName;
321+
function upgradeElement(element) {
322+
if (!element.__upgraded__ && (element.nodeType === Node.ELEMENT_NODE)) {
323+
var type = element.getAttribute('is') || element.localName;
319324
var definition = registry[type];
320-
return definition && upgrade(inElement, definition);
325+
return definition && upgrade(element, definition);
321326
}
322327
}
323328

@@ -353,7 +358,7 @@ if (useNative) {
353358
* if it matches no registered custom tag name.
354359
*
355360
* @method ugprade
356-
* @param {Element} inElement The element to upgrade.
361+
* @param {Element} element The element to upgrade.
357362
* @return {Element} The upgraded element.
358363
*/
359364
scope.upgrade = upgradeElement;

test/js/customElements.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@
1717
document.body.removeChild(work);
1818
});
1919

20+
test('document.register requires name argument', function() {
21+
try {
22+
document.register();
23+
} catch(x) {
24+
return;
25+
}
26+
assert.ok(false, 'document.register failed to throw when given no arguments');
27+
});
28+
29+
test('document.register requires name argument to contain a dash', function() {
30+
try {
31+
document.register('xfoo', {prototype: Object.create(HTMLElement.prototype)});
32+
} catch(x) {
33+
return;
34+
}
35+
assert.ok(false, 'document.register failed to throw when given no arguments');
36+
});
37+
2038
test('document.register create via new', function() {
2139
// register x-foo
2240
var XFoo = document.register('x-foo', {prototype: Object.create(HTMLElement.prototype)});

0 commit comments

Comments
 (0)