-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enable 'publishing' system for attributes, add tests, fresh builds
- Loading branch information
Scott J. Miles
committed
Apr 15, 2013
1 parent
6e66b2b
commit ececd01
Showing
10 changed files
with
271 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,92 +1,119 @@ | ||
/* | ||
* Copyright 2013 The Toolkitchen Authors. All rights reserved. | ||
* Use of this source code is governed by a BSD-style | ||
* license that can be found in the LICENSE file. | ||
*/ | ||
|
||
(function() { | ||
|
||
// imports | ||
|
||
var bindPattern = Toolkit.bindPattern; | ||
|
||
var publishAttributes = function(inAttributes, inDefinition) { | ||
if (inAttributes) { | ||
/* | ||
var pd = conventions.PUBLISH_DIRECTIVE; | ||
// need a publish block to extend | ||
var pub = inDefinition[pd] = inDefinition[pd] || {}; | ||
// use the value of the attributes-attribute | ||
var a$ = inAttributes.value; | ||
// attributes='a b c' or attributes='a,b,c' | ||
var names = a$.split(a$.indexOf(',') >= 0 ? ',' : ' '); | ||
// record each name for publishing | ||
names.forEach(function(p) { | ||
pub[p.trim()] = null; | ||
}); | ||
*/ | ||
} | ||
}; | ||
|
||
function takeAttributes() { | ||
// for each attribute | ||
forEach(this.attributes, function(a) { | ||
// try to match this attribute to a property (attributess are | ||
// all lower-case, so this is case-insensitive search) | ||
var name = propertyForAttribute.call(this, a.name); | ||
if (name) { | ||
// filter out 'mustached' values, these are to be | ||
// replaced with bound-data and are not yet values | ||
// themselves | ||
if (a.value.search(bindPattern) >= 0) { | ||
return; | ||
} | ||
// get original value | ||
var defaultValue = this[name]; | ||
// deserialize Boolean or Number values from attribute | ||
var value = deserializeValue(a.value, defaultValue); | ||
//console.log('takeAttributes: ', a.name, a.value); | ||
// only act if the value has changed | ||
if (value !== defaultValue) { | ||
// install new value (has side-effects) | ||
this[name] = value; | ||
} | ||
} | ||
}, this); | ||
}; | ||
|
||
// find the public property identified by inAttributeName | ||
function propertyForAttribute(inAttributeName) { | ||
// specifically search the __proto__ (as opposed to getPrototypeOf) | ||
// __proto__ is simulated on platforms which don't support it naturally | ||
// TODO(sjmiles): I'm reluctant to search the entire namespace | ||
// but this set is too small. Perhaps in 'full public' mode, one | ||
// must declare 'attributable properties'. | ||
var properties = Object.keys(this.__proto__); | ||
//var properties = Object.keys(Object.getPrototypeOf(this)); | ||
for (var i=0, n; (n=properties[i]); i++) { | ||
if (n.toLowerCase() == inAttributeName) { | ||
return n; | ||
} | ||
} | ||
}; | ||
|
||
function deserializeValue(inValue, inDefaultValue) { | ||
var inferredType = typeof inDefaultValue; | ||
switch (inValue) { | ||
case '': | ||
case 'true': | ||
return inferredType == 'boolean' ? true : inValue; | ||
case 'false': | ||
return inferredType == 'boolean' ? false : inValue; | ||
} | ||
return isNaN(inValue) ? inValue : parseFloat(inValue); | ||
} | ||
|
||
// exports | ||
|
||
Toolkit.takeAttributes = takeAttributes; | ||
Toolkit.propertyForAttribute = propertyForAttribute; | ||
Toolkit.publishAttributes = publishAttributes; | ||
|
||
/* | ||
* Copyright 2013 The Toolkitchen Authors. All rights reserved. | ||
* Use of this source code is governed by a BSD-style | ||
* license that can be found in the LICENSE file. | ||
*/ | ||
|
||
(function() { | ||
|
||
// imports | ||
|
||
var bindPattern = Toolkit.bindPattern; | ||
|
||
// constants | ||
|
||
var published$ = '__published'; | ||
var attributes$ = 'attributes'; | ||
var attrProps$ = 'publish'; | ||
//var attrProps$ = 'attributeDefaults'; | ||
|
||
var publishAttributes = function(inElement, inPrototype) { | ||
var published = {}; | ||
// merge attribute names from 'attributes' attribute | ||
var attributes = inElement.getAttribute(attributes$); | ||
if (attributes) { | ||
// attributes='a b c' or attributes='a,b,c' | ||
var names = attributes.split(attributes.indexOf(',') >= 0 ? ',' : ' '); | ||
// record each name for publishing | ||
names.forEach(function(p) { | ||
published[p.trim()] = null; | ||
}); | ||
} | ||
// combine with 'publish' object from prototype' | ||
published = mixin(published, inPrototype[attrProps$]); | ||
// install actual properties on the prototype | ||
Object.keys(published).forEach(function(p) { | ||
inPrototype[p] = published[p]; | ||
}); | ||
// combine with inherited published properties | ||
inPrototype[published$] = mixin( | ||
{}, | ||
inElement.options.prototype[published$], | ||
published); | ||
}; | ||
|
||
function takeAttributes() { | ||
// for each attribute | ||
forEach(this.attributes, function(a) { | ||
// try to match this attribute to a property (attributess are | ||
// all lower-case, so this is case-insensitive search) | ||
var name = propertyForAttribute.call(this, a.name); | ||
if (name) { | ||
// filter out 'mustached' values, these are to be | ||
// replaced with bound-data and are not yet values | ||
// themselves | ||
if (a.value.search(bindPattern) >= 0) { | ||
return; | ||
} | ||
// get original value | ||
var defaultValue = this[name]; | ||
// deserialize Boolean or Number values from attribute | ||
var value = deserializeValue(a.value, defaultValue); | ||
//console.log('takeAttributes: ', a.name, a.value); | ||
// only act if the value has changed | ||
if (value !== defaultValue) { | ||
// install new value (has side-effects) | ||
this[name] = value; | ||
} | ||
} | ||
}, this); | ||
}; | ||
|
||
var lowerCase = String.prototype.toLowerCase.call.bind( | ||
String.prototype.toLowerCase); | ||
|
||
// return the published property matching name, or undefined | ||
function propertyForAttribute(name) { | ||
// matchable properties must be published | ||
var properties = Object.keys(this[published$]); | ||
// search for a matchable property | ||
return properties[properties.map(lowerCase).indexOf(name)]; | ||
}; | ||
|
||
/* | ||
// find the public property identified by inAttributeName | ||
function propertyForAttribute(inAttributeName) { | ||
// specifically search the __proto__ (as opposed to getPrototypeOf) | ||
// __proto__ is simulated on platforms which don't support it naturally | ||
// TODO(sjmiles): I'm reluctant to search the entire namespace | ||
// but this set is too small. Perhaps in 'full public' mode, one | ||
// must declare 'attributable properties'. | ||
var properties = Object.keys(this.__proto__); | ||
//var properties = Object.keys(Object.getPrototypeOf(this)); | ||
for (var i=0, n; (n=properties[i]); i++) { | ||
if (n.toLowerCase() == inAttributeName) { | ||
return n; | ||
} | ||
} | ||
}; | ||
*/ | ||
|
||
function deserializeValue(inValue, inDefaultValue) { | ||
var inferredType = typeof inDefaultValue; | ||
switch (inValue) { | ||
case '': | ||
case 'true': | ||
return inferredType == 'boolean' ? true : inValue; | ||
case 'false': | ||
return inferredType == 'boolean' ? false : inValue; | ||
} | ||
return isNaN(inValue) ? inValue : parseFloat(inValue); | ||
} | ||
|
||
// exports | ||
|
||
Toolkit.takeAttributes = takeAttributes; | ||
Toolkit.publishAttributes = publishAttributes; | ||
Toolkit.propertyForAttribute = propertyForAttribute; | ||
|
||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>publish attributes</title> | ||
<script src="../../platform/platform.js"></script> | ||
<script src="../../toolkit.js"></script> | ||
<script src="../../tools/test/htmltest.js"></script> | ||
<script src="../../node_modules/chai/chai.js"></script> | ||
</head> | ||
<body> | ||
|
||
<element name="x-foo" attributes="Foo baz" constructor="XFoo"> | ||
<script> | ||
Toolkit.register(this); | ||
</script> | ||
</element> | ||
|
||
<element name="x-bar" extends="x-foo" attributes="Bar" constructor="XBar"> | ||
<script> | ||
Toolkit.register(this); | ||
</script> | ||
</element> | ||
|
||
<element name="x-zot" extends="x-bar" constructor="XZot"> | ||
<script> | ||
Toolkit.register(this, { | ||
publish: { | ||
zot: 3 | ||
} | ||
}); | ||
</script> | ||
</element> | ||
|
||
<element name="x-squid" extends="x-zot" attributes="squid" constructor="XSquid"> | ||
<script> | ||
Toolkit.register(this, { | ||
publish: { | ||
baz: 13, | ||
zot: 5, | ||
squid: 7 | ||
} | ||
}); | ||
</script> | ||
</element> | ||
|
||
<script> | ||
var assert = chai.assert; | ||
document.addEventListener('WebComponentsReady', function() { | ||
// | ||
assert.deepEqual( | ||
XFoo.prototype.__published, | ||
{Foo: null, baz: null}); | ||
assert.deepEqual( | ||
XBar.prototype.__published, | ||
{Foo: null, baz: null, Bar: null}); | ||
assert.deepEqual( | ||
XZot.prototype.__published, | ||
{Foo: null, baz: null, Bar: null, zot: 3}); | ||
assert.deepEqual( | ||
XSquid.prototype.__published, | ||
{Foo: null, baz: 13, Bar: null, zot: 5, squid: 7}); | ||
// | ||
assert.equal( | ||
Toolkit.propertyForAttribute.call(XFoo.prototype, 'foo'), | ||
'Foo'); | ||
XFoo.prototype.baz = true; | ||
assert.isUndefined( | ||
Toolkit.propertyForAttribute.call(XFoo.prototype, 'splat')); | ||
// | ||
done(); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
Oops, something went wrong.
This overwrites the instance attributes when used with ShadowDOM polyfill. Can we remove?