Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8/8 master -> stable #231

Merged
merged 19 commits into from
Aug 8, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* license that can be found in the LICENSE file.
*/
module.exports = function(grunt) {
var banner = [grunt.file.read('LICENSE'), '// @version ' + grunt.file.readJSON('package.json').version, ''].join(grunt.util.linefeed);
Platform = [
'../platform/platform.min.js'
];
Expand Down Expand Up @@ -81,7 +82,7 @@ module.exports = function(grunt) {
},
uglify: {
options: {
banner: grunt.file.read('LICENSE'),
banner: banner,
nonull: true
},
Polymer: {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Polymer",
"version": "0.0.1",
"version": "0.0.20130808",
"devDependencies": {
"mocha": "*",
"chai": "*",
Expand Down
186 changes: 148 additions & 38 deletions src/declaration/polymer-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,69 @@
(function(scope) {

// imports

var extend = Polymer.extend;
var apis = scope.api.declaration;

var deferred = {};

// imperative implementation: Polymer()

// maps tag names to prototypes
var registry = {};
var prototypesByName = {};

function getRegisteredPrototype(name) {
return prototypesByName[name];
}

// elements waiting for prototype, by name
var waitPrototype = {};

// register an 'own' prototype for tag `name`
// specify an 'own' prototype for tag `name`
function element(name, prototype) {
registry[name] = prototype || {};
if (deferred[name]) {
deferred[name].define();
//console.log('registering [' + name + ']');
// cache the prototype
prototypesByName[name] = prototype || {};
// notify the registrar waiting for 'name', if any
notifyPrototype(name);
}

function notifyPrototype(name) {
if (waitPrototype[name]) {
waitPrototype[name].registerWhenReady();
delete waitPrototype[name];
}
}


// elements waiting for super, by name
var waitSuper = {};

function notifySuper(name) {
registered[name] = true;
var waiting = waitSuper[name];
if (waiting) {
waiting.forEach(function(w) {
w.registerWhenReady();
});
delete waitSuper[name];
}
}

// track document.register'ed tag names

var registered = {};

function isRegistered(name) {
return registered[name];
}

// returns a prototype that chains to <tag> or HTMLElement
function generatePrototype(tag) {
return Object.create(HTMLElement.getPrototypeForTag(tag));
}

// On platforms that do not support __proto__ (IE10), the prototype chain
// of a custom element is simulated via installation of __proto__.
// Although custom elements manages this, we install it here so it's
// available during desuaring.
// available during desugaring.
function ensurePrototypeTraversal(prototype) {
if (!Object.__proto__) {
var ancestor = Object.getPrototypeOf(prototype);
Expand All @@ -44,35 +79,108 @@
}
}

// declarative implementation: <polymer-element>

function whenImportsLoaded(doThis) {
if (window.HTMLImports && !HTMLImports.readyTime) {
addEventListener('HTMLImportsLoaded', doThis);
} else {
doThis();
}
}

// declarative implementation: <polymer-element>

var prototype = generatePrototype();

extend(prototype, {
// TODO(sjmiles): temporary BC
readyCallback: function() {
this._createdCallback();
this.createdCallback();
},
createdCallback: function() {
this._createdCallback();
// fetch the element name
this.name = this.getAttribute('name');
// install element definition, if ready
this.registerWhenReady();
},
// custom element processing
_createdCallback: function() {
// fetch our element name
var name = this.getAttribute('name');
if (registry[name]) {
this.define();
registerWhenReady: function() {
var name = this.name;
// if we have no prototype
if (!getRegisteredPrototype(name)) {
// then wait for a prototype
waitPrototype[name] = this;
// TODO(sjmiles): 'noscript' gambit is mutually exclusive
// with 'async' gambit below
//
// if explicitly marked as 'noscript'
if (this.hasAttribute('noscript')) {
// go async to allow children to parse
setTimeout(function() {
// register with the default prototype
element(name, null);
}, 0);
}
// TODO(sjmiles): 'async' gambit is deemed too dangerous
// because it changes the timing of noscript elements
// in import from 'timeout 0' to 'HTMLImportsReady'
/*
// if we are not explicitly async...
if (!this.hasAttribute('async')) {
// then we expect the script to be registered
// by end of microtask(-ish) and can otherwise
// consider this element to have no script
//
// TODO(sjmiles):
// we have to wait for end-of-microtask because
// native CE upgrades polymer-element (any custom
// element, really) *before* it's children are
// parsed, and it's common for the script to
// exist as a child of the polymer-element
//
// additionally, there is a massive asynchrony
// between parsing HTML in imports and executing
// script that foils the end of microtask gambit
// Waiting on HTMLImportsLoaded signal solves
// both timing problems for imports loaded
// at startup under the import polyfill
whenImportsLoaded(function() {
if (!getRegisteredPrototype(name)) {
console.warn('giving up waiting for script for [' + name + ']');
element(name, null);
}
});
}
*/
return;
}
// fetch our extendee name
var extendee = this.getAttribute('extends');
// if extending a custom element...
if (extendee && extendee.indexOf('-') >= 0) {
// wait for the extendee to be registered first
if (!isRegistered(extendee)) {
(waitSuper[extendee] = (waitSuper[extendee] || [])).push(this);
return;
}
}
// TODO(sjmiles): HTMLImports polyfill awareness
// elements in the main document are likely to parse
// in advance of elements in imports because the
// polyfill parser is simulated
// therefore, wait for imports loaded before
// finalizing elements in the main document
if (document.contains(this)) {
whenImportsLoaded(function() {
this.register(name, extendee);
}.bind(this));
} else {
deferred[name] = this;
this.register(name, extendee);
}
},
define: function() {
// fetch our element name
var name = this.getAttribute('name');
// fetch our extendee name
var extnds = this.getAttribute('extends');
register: function(name, extendee) {
//console.log('register', name, extendee);
// build prototype combining extendee, Polymer base, and named api
this.prototype = this.generateCustomPrototype(name, extnds);
// questionable backref
this.prototype = this.generateCustomPrototype(name, extendee);
// backref
this.prototype.element = this;
// TODO(sorvell): install a helper method this.resolvePath to aid in
// setting resource paths. e.g.
Expand All @@ -85,12 +193,14 @@
this.desugar();
// under ShadowDOMPolyfill, transforms to approximate missing CSS features
if (window.ShadowDOMPolyfill) {
Platform.ShadowCSS.shimStyling(this.templateContent(), name, extnds);
Platform.ShadowCSS.shimStyling(this.templateContent(), name, extendee);
}
// register our custom element
this.register(name);
// reference constructor in a global named by 'constructor' attribute
this.registerPrototype(name);
// reference constructor in a global named by 'constructor' attribute
this.publishConstructor();
// subclasses may now register themselves
notifySuper(name);
},
// implement various declarative features
desugar: function(prototype) {
Expand Down Expand Up @@ -142,15 +252,15 @@
// mix api registered to 'name' into 'prototype'
addNamedApi: function(prototype, name) {
// combine custom api into prototype
return extend(prototype, registry[name]);
return extend(prototype, getRegisteredPrototype(name));
},
// make a fresh object that inherits from a prototype object
inheritObject: function(prototype, name) {
// copy inherited properties onto a new object
prototype[name] = extend({}, Object.getPrototypeOf(prototype)[name]);
},
// register 'prototype' to custom element 'name', store constructor
register: function(name) {
registerPrototype: function(name) {
// register the custom type
this.ctor = document.register(name, {
prototype: this.prototype
Expand All @@ -177,12 +287,12 @@
// register polymer-element with document

document.register('polymer-element', {prototype: prototype});
// namespace shenanigans

// namespace shenanigans so we can expose our scope on the registration function

// TODO(sjmiles): find a way to do this that is less terrible
// copy window.Polymer properties onto `element()`
extend(element, window.Polymer);
extend(element, scope);
// make window.Polymer reference `element()`
window.Polymer = element;

Expand Down
2 changes: 1 addition & 1 deletion src/instance/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
if (!event.cancelBubble) {
event.on = EVENT_PREFIX + event.type;
log.events && console.group("[%s]: listenLocal [%s]", host.localName, event.on);
if (!event.path || window.ShadowDOMPolyfill) {
if (!event.path) {
_listenLocalNoEventPath(host, event);
} else {
_listenLocal(host, event);
Expand Down
6 changes: 3 additions & 3 deletions src/instance/mdv.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
instanceTemplate: function(template) {
return template.createInstance(this, mdv_syntax);
},
createBinding: function(name, model, path) {
//console.log(arguments);
bind: function(name, model, path) {
var property = this.propertyForAttribute(name);
if (property) {
this.unbind(name);
// use n-way Polymer binding
var observer = this.bindProperty(property, model, path);
// stick path on observer so it's available via this.bindings
observer.path = path;
return observer;
return this.bindings[name] = observer;
} else {
return this.super(arguments);
}
Expand Down
4 changes: 2 additions & 2 deletions test/html/attr-mustache.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<script>
Polymer('x-target', {
// force an mdv binding
createBinding: function() {
return Element.prototype.createBinding.apply(this, arguments);
bind: function() {
return Element.prototype.bind.apply(this, arguments);
},
inserted: function() {
this.testSrcForMustache();
Expand Down
2 changes: 1 addition & 1 deletion test/html/callbacks.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<title>event path</title>
<script src="../../polymer.js"></script>
<script src="../../tools/test/htmltest.js"></script>
<script src="../../node_modules/chai/chai.js"></script>
<script src="../../tools/test/chai/chai.js"></script>
</head>
<body>

Expand Down
Loading