| OLD | NEW |
| (Empty) |
| 1 | |
| 2 | |
| 3 Polymer.Templatizer = { | |
| 4 | |
| 5 templatize: function(template) { | |
| 6 this._templatized = template; | |
| 7 // TODO(sjmiles): supply _alternate_ content reference missing from root | |
| 8 // templates (not nested). `_content` exists to provide content sharing | |
| 9 // for nested templates. | |
| 10 if (!template._content) { | |
| 11 template._content = template.content; | |
| 12 } | |
| 13 // fast path if template's anonymous class has been memoized | |
| 14 if (template._content._ctor) { | |
| 15 this.ctor = template._content._ctor; | |
| 16 //console.log('Templatizer.templatize: using memoized archetype'); | |
| 17 // forward parent properties to archetype | |
| 18 this._prepParentProperties(this.ctor.prototype); | |
| 19 return; | |
| 20 } | |
| 21 // `archetype` is the prototype of the anonymous | |
| 22 // class created by the templatizer | |
| 23 var archetype = Object.create(Polymer.Base); | |
| 24 // normally Annotations.parseAnnotations(template) but | |
| 25 // archetypes do special caching | |
| 26 this.customPrepAnnotations(archetype, template); | |
| 27 | |
| 28 // setup accessors | |
| 29 archetype._prepEffects(); | |
| 30 archetype._prepBehaviors(); | |
| 31 archetype._prepBindings(); | |
| 32 | |
| 33 // forward parent properties to archetype | |
| 34 this._prepParentProperties(archetype); | |
| 35 | |
| 36 // boilerplate code | |
| 37 archetype._notifyPath = this._notifyPathImpl; | |
| 38 archetype._scopeElementClass = this._scopeElementClassImpl; | |
| 39 // boilerplate code | |
| 40 var _constructor = this._constructorImpl; | |
| 41 var ctor = function TemplateInstance(model, host) { | |
| 42 _constructor.call(this, model, host); | |
| 43 }; | |
| 44 // standard references | |
| 45 ctor.prototype = archetype; | |
| 46 archetype.constructor = ctor; | |
| 47 // TODO(sjmiles): constructor cache? | |
| 48 template._content._ctor = ctor; | |
| 49 // TODO(sjmiles): choose less general name | |
| 50 this.ctor = ctor; | |
| 51 }, | |
| 52 | |
| 53 _getRootDataHost: function() { | |
| 54 return (this.dataHost && this.dataHost._rootDataHost) || this.dataHost; | |
| 55 }, | |
| 56 | |
| 57 _getAllStampedChildren: function(children) { | |
| 58 children = children || []; | |
| 59 if (this._getStampedChildren) { | |
| 60 var c$ = this._getStampedChildren(); | |
| 61 for (var i=0, c; c = c$[i]; i++) { | |
| 62 children.push(c); | |
| 63 if (c._getAllStampedChildren) { | |
| 64 c._getAllStampedChildren(children); | |
| 65 } | |
| 66 } | |
| 67 } | |
| 68 return children; | |
| 69 }, | |
| 70 | |
| 71 customPrepAnnotations: function(archetype, template) { | |
| 72 if (template) { | |
| 73 archetype._template = template; | |
| 74 var c = template._content; | |
| 75 if (c) { | |
| 76 var rootDataHost = archetype._rootDataHost; | |
| 77 if (rootDataHost) { | |
| 78 Polymer.Annotations.prepElement = | |
| 79 rootDataHost._prepElement.bind(rootDataHost); | |
| 80 } | |
| 81 archetype._notes = c._notes || | |
| 82 Polymer.Annotations.parseAnnotations(template); | |
| 83 c._notes = archetype._notes; | |
| 84 Polymer.Annotations.prepElement = null; | |
| 85 archetype._parentProps = c._parentProps; | |
| 86 } | |
| 87 else { | |
| 88 console.warn('no _content'); | |
| 89 } | |
| 90 } | |
| 91 else { | |
| 92 console.warn('no _template'); | |
| 93 } | |
| 94 }, | |
| 95 | |
| 96 // Sets up accessors on the template to call abstract _forwardParentProp | |
| 97 // API that should be implemented by Templatizer users to get parent | |
| 98 // properties to their template instances. These accessors are memoized | |
| 99 // on the archetype and copied to instances. | |
| 100 _prepParentProperties: function(archetype) { | |
| 101 var parentProps = this._parentProps = archetype._parentProps; | |
| 102 if (this._forwardParentProp && parentProps) { | |
| 103 // Prototype setup (memoized on archetype) | |
| 104 var proto = archetype._parentPropProto; | |
| 105 if (!proto) { | |
| 106 proto = archetype._parentPropProto = Object.create(null); | |
| 107 if (this._templatized != this) { | |
| 108 // Assumption: if `this` isn't the template being templatized, | |
| 109 // assume that the template is not a Poylmer.Base, so prep it | |
| 110 // for binding | |
| 111 Polymer.Bind.prepareModel(proto); | |
| 112 } | |
| 113 // Create accessors for each parent prop that forward the property | |
| 114 // to template instances through abstract _forwardParentProp API | |
| 115 // that should be implemented by Templatizer users | |
| 116 for (var prop in parentProps) { | |
| 117 var parentProp = '_parent_' + prop; | |
| 118 var effects = [{ | |
| 119 kind: 'function', | |
| 120 effect: { function: this._createForwardPropEffector(prop) } | |
| 121 }]; | |
| 122 Polymer.Bind._createAccessors(proto, parentProp, effects); | |
| 123 } | |
| 124 } | |
| 125 // Instance setup | |
| 126 if (this._templatized != this) { | |
| 127 Polymer.Bind.prepareInstance(this._templatized); | |
| 128 this._templatized._forwardParentProp = | |
| 129 this._forwardParentProp.bind(this); | |
| 130 } | |
| 131 this._extendTemplate(this._templatized, proto); | |
| 132 } | |
| 133 }, | |
| 134 | |
| 135 _createForwardPropEffector: function(prop) { | |
| 136 return function(source, value) { | |
| 137 this._forwardParentProp(prop, value); | |
| 138 }; | |
| 139 }, | |
| 140 | |
| 141 // Similar to Polymer.Base.extend, but retains any previously set instance | |
| 142 // values (_propertySet back on instance once accessor is installed) | |
| 143 _extendTemplate: function(template, proto) { | |
| 144 Object.getOwnPropertyNames(proto).forEach(function(n) { | |
| 145 var val = template[n]; | |
| 146 var pd = Object.getOwnPropertyDescriptor(proto, n); | |
| 147 Object.defineProperty(template, n, pd); | |
| 148 if (val !== undefined) { | |
| 149 template._propertySet(n, val); | |
| 150 } | |
| 151 }); | |
| 152 }, | |
| 153 | |
| 154 _notifyPathImpl: function(path, value) { | |
| 155 var p = path.match(/([^.]*)\.(([^.]*).*)/); | |
| 156 // 'root.sub.path' | |
| 157 var root = p[1]; // 'root' | |
| 158 var sub = p[3]; // 'sub' | |
| 159 var subPath = p[2]; // 'sub.path' | |
| 160 // Notify host of parent.* path/property changes | |
| 161 var dataHost = this.dataHost; | |
| 162 if (root == 'parent') { | |
| 163 if (sub == subPath) { | |
| 164 dataHost.dataHost[sub] = value; | |
| 165 } else { | |
| 166 dataHost.notifyPath('_parent_' + subPath, value); | |
| 167 } | |
| 168 } | |
| 169 // Extension point for Templatizer sub-classes | |
| 170 if (dataHost._forwardInstancePath) { | |
| 171 dataHost._forwardInstancePath.call(dataHost, this, root, subPath, value)
; | |
| 172 } | |
| 173 }, | |
| 174 | |
| 175 // Overrides Base notify-path module | |
| 176 _pathEffector: function(path, value, fromAbove) { | |
| 177 if (this._forwardParentPath) { | |
| 178 if (path.indexOf('_parent_') === 0) { | |
| 179 this._forwardParentPath(path.substring(8), value); | |
| 180 } | |
| 181 } | |
| 182 Polymer.Base._pathEffector.apply(this, arguments); | |
| 183 }, | |
| 184 | |
| 185 _constructorImpl: function(model, host) { | |
| 186 var rootDataHost = host._getRootDataHost(); | |
| 187 if (rootDataHost) { | |
| 188 this.listen = rootDataHost.listen.bind(rootDataHost); | |
| 189 this._rootDataHost = rootDataHost; | |
| 190 } | |
| 191 this._setupConfigure(model); | |
| 192 this._pushHost(host); | |
| 193 this.root = this.instanceTemplate(this._template); | |
| 194 this.root.__styleScoped = true; | |
| 195 this._popHost(); | |
| 196 this._marshalAnnotatedNodes(); | |
| 197 this._marshalInstanceEffects(); | |
| 198 this._marshalAnnotatedListeners(); | |
| 199 this._tryReady(); | |
| 200 }, | |
| 201 | |
| 202 _scopeElementClassImpl: function(node, value) { | |
| 203 var host = this._rootDataHost; | |
| 204 if (host) { | |
| 205 return host._scopeElementClass(node, value); | |
| 206 } | |
| 207 }, | |
| 208 | |
| 209 stamp: function(model) { | |
| 210 model = model || {}; | |
| 211 if (this._parentProps) { | |
| 212 // TODO(kschaaf): Maybe this is okay | |
| 213 // model.parent = this.dataHost; | |
| 214 model.parent = model.parent || {}; | |
| 215 for (var prop in this._parentProps) { | |
| 216 model.parent[prop] = this['_parent_' + prop]; | |
| 217 } | |
| 218 } | |
| 219 return new this.ctor(model, this); | |
| 220 } | |
| 221 | |
| 222 // TODO(sorvell): note, using the template as host is ~5-10% faster if | |
| 223 // elements have no default values. | |
| 224 // _constructorImpl: function(model, host) { | |
| 225 // this._setupConfigure(model); | |
| 226 // host._beginHost(); | |
| 227 // this.root = this.instanceTemplate(this._template); | |
| 228 // host._popHost(); | |
| 229 // this._marshalTemplateContent(); | |
| 230 // this._marshalAnnotatedNodes(); | |
| 231 // this._marshalInstanceEffects(); | |
| 232 // this._marshalAnnotatedListeners(); | |
| 233 // this._ready(); | |
| 234 // }, | |
| 235 | |
| 236 // stamp: function(model) { | |
| 237 // return new this.ctor(model, this.dataHost); | |
| 238 // } | |
| 239 | |
| 240 | |
| 241 }; | |
| 242 | |
| OLD | NEW |