diff options
Diffstat (limited to 'node_modules/montage/ui/native-control.js')
-rw-r--r-- | node_modules/montage/ui/native-control.js | 175 |
1 files changed, 94 insertions, 81 deletions
diff --git a/node_modules/montage/ui/native-control.js b/node_modules/montage/ui/native-control.js index d3c3a635..d308ad89 100644 --- a/node_modules/montage/ui/native-control.js +++ b/node_modules/montage/ui/native-control.js | |||
@@ -11,48 +11,31 @@ var isUndefined = function(obj) { | |||
11 | return (typeof obj === 'undefined'); | 11 | return (typeof obj === 'undefined'); |
12 | }; | 12 | }; |
13 | 13 | ||
14 | var extend = function(destination, source) { | ||
15 | for (var property in source) { | ||
16 | destination[property] = source[property]; | ||
17 | } | ||
18 | return destination; | ||
19 | }; | ||
20 | |||
21 | var STRING_CLASS = '[object String]'; | ||
22 | var _toString = Object.prototype.toString; | ||
23 | var isString = function(object) { | ||
24 | return _toString.call(object) === STRING_CLASS; | ||
25 | }; | ||
26 | 14 | ||
27 | /** | 15 | /** |
28 | * Base component for all native controls. | 16 | * Base component for all native controls. |
29 | */ | 17 | */ |
30 | exports.NativeControl = Montage.create(Component, { | 18 | var NativeControl = exports.NativeControl = Montage.create(Component, { |
31 | 19 | ||
32 | hasTemplate: { | 20 | hasTemplate: { |
33 | value: false | 21 | value: false |
34 | }, | 22 | }, |
35 | 23 | ||
36 | //http://www.w3.org/TR/html5/elements.html#global-attributes | 24 | element: { |
37 | _baseElementProperties: { | 25 | serializable: true, |
38 | value: { | 26 | enumerable: true, |
39 | accesskey: null, | 27 | get: function() { |
40 | contenteditable: null, // true, false, inherit | 28 | return this._element; |
41 | contextmenu: null, | 29 | }, |
42 | 'class': null, | 30 | set: function(value) { |
43 | dir: null, | 31 | //var component = Object.getPrototypeOf(NativeControl); |
44 | draggable: {dataType: 'boolean'}, | 32 | // call super set |
45 | dropzone: null, // copy/move/link | 33 | Object.getPropertyDescriptor(Component, "element").set.call(this, value); |
46 | hidden: {dataType: 'boolean'}, | 34 | this.didSetElement(); |
47 | //id: null, | ||
48 | lang: null, | ||
49 | spellcheck: null, | ||
50 | style: null, | ||
51 | tabindex: null, | ||
52 | title: null | ||
53 | } | 35 | } |
54 | }, | 36 | }, |
55 | 37 | ||
38 | |||
56 | /** Stores values that need to be set on the element. Cleared each draw | 39 | /** Stores values that need to be set on the element. Cleared each draw |
57 | * cycle. | 40 | * cycle. |
58 | */ | 41 | */ |
@@ -64,11 +47,30 @@ exports.NativeControl = Montage.create(Component, { | |||
64 | /** Stores the descriptors of the properties that can be set on this | 47 | /** Stores the descriptors of the properties that can be set on this |
65 | * control | 48 | * control |
66 | */ | 49 | */ |
67 | _propertyDescriptors: { | 50 | |
51 | _elementAttributeDescriptors: { | ||
68 | value: {}, | 52 | value: {}, |
69 | distinct: true | 53 | distinct: true |
70 | }, | 54 | }, |
71 | 55 | ||
56 | |||
57 | _getElementAttributeDescriptor: { | ||
58 | value: function(attributeName) { | ||
59 | var attributeDescriptor, instance = this; | ||
60 | // walk up the prototype chain from the instance to NativeControl's prototype | ||
61 | while(instance && !isUndefined(instance._elementAttributeDescriptors)) { | ||
62 | attributeDescriptor = instance._elementAttributeDescriptors[attributeName]; | ||
63 | if(attributeDescriptor) { | ||
64 | break; | ||
65 | } else { | ||
66 | instance = Object.getPrototypeOf(instance); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | return attributeDescriptor; | ||
71 | } | ||
72 | }, | ||
73 | |||
72 | /** | 74 | /** |
73 | * Add a property to this Component. A default getter/setter is provided and a | 75 | * Add a property to this Component. A default getter/setter is provided and a |
74 | * "_" property is created by default. Eg: if the property is "title", "_title" is | 76 | * "_" property is created by default. Eg: if the property is "title", "_title" is |
@@ -86,7 +88,8 @@ exports.NativeControl = Montage.create(Component, { | |||
86 | return function(value) { | 88 | return function(value) { |
87 | var attrName = '_' + name; | 89 | var attrName = '_' + name; |
88 | 90 | ||
89 | var desc = this._propertyDescriptors[name]; | 91 | var desc = this._getElementAttributeDescriptor(name, this); |
92 | |||
90 | // if requested dataType is boolean (eg: checked, readonly etc) | 93 | // if requested dataType is boolean (eg: checked, readonly etc) |
91 | // coerce the value to boolean | 94 | // coerce the value to boolean |
92 | if(desc && "boolean" === desc.dataType) { | 95 | if(desc && "boolean" === desc.dataType) { |
@@ -121,64 +124,56 @@ exports.NativeControl = Montage.create(Component, { | |||
121 | * Add the specified properties as properties of this Component | 124 | * Add the specified properties as properties of this Component |
122 | */ | 125 | */ |
123 | addAttributes: { | 126 | addAttributes: { |
124 | value: function(props) { | 127 | value: function(properties) { |
125 | var i, desc, prop, obj; | 128 | var i, descriptor, property, object; |
126 | var standardAttributes = {}; | 129 | this._elementAttributeDescriptors = properties; |
127 | standardAttributes = extend(standardAttributes, this._baseElementProperties); | ||
128 | standardAttributes = extend(standardAttributes, props); | ||
129 | |||
130 | this._propertyDescriptors = standardAttributes; | ||
131 | 130 | ||
132 | for(prop in standardAttributes) { | 131 | for(property in properties) { |
133 | if(standardAttributes.hasOwnProperty(prop)) { | 132 | if(properties.hasOwnProperty(property)) { |
134 | obj = standardAttributes[prop]; | 133 | object = properties[property]; |
135 | // Make sure that the descriptor is of the correct form. | 134 | // Make sure that the descriptor is of the correct form. |
136 | if(obj === null || isString(obj)) { | 135 | if(object === null || String.isString(object)) { |
137 | desc = {value: obj, dataType: "string"}; | 136 | descriptor = {value: object, dataType: "string"}; |
138 | standardAttributes[prop] = desc; | 137 | properties[property] = descriptor; |
139 | } else { | 138 | } else { |
140 | desc = obj; | 139 | descriptor = object; |
141 | } | 140 | } |
142 | 141 | ||
143 | // Only add the internal prop, and getter and setter if | 142 | // Only add the internal property, and getter and setter if |
144 | // they don't already exist. | 143 | // they don't already exist. |
145 | if(isUndefined(this[prop])) { | 144 | if(isUndefined(this[property])) { |
146 | this.defineAttribute(prop, desc); | 145 | this.defineAttribute(property, descriptor); |
147 | } | 146 | } |
148 | } | 147 | } |
149 | } | 148 | } |
150 | } | 149 | } |
151 | }, | 150 | }, |
152 | 151 | ||
153 | deserializedFromTemplate: { | 152 | didSetElement: { |
154 | value: function() { | 153 | value: function() { |
155 | // The element is now ready, so we can read the attributes that | 154 | // The element is now ready, so we can read the attributes that |
156 | // have been set on it. | 155 | // have been set on it. |
157 | var attrs = this.element.attributes || []; | 156 | var attributes = this.element.attributes || []; |
158 | var i=0, len = attrs.length, name, value, d, desc; | 157 | var i=0, length = attributes.length, name, value, attributeName, descriptor, textContent; |
159 | 158 | ||
160 | for(i=0; i< len; i++) { | 159 | for(i=0; i< length; i++) { |
161 | name = attrs[i].name; | 160 | name = attributes[i].name; |
162 | value = attrs[i].value; | 161 | value = attributes[i].value; |
163 | 162 | ||
164 | if(isUndefined(this._elementAttributeValues[name])) { | 163 | if(isUndefined(this._elementAttributeValues[name])) { |
165 | this._elementAttributeValues[name] = value; | 164 | this._elementAttributeValues[name] = value; |
166 | // since deserializedFromTemplate is called *after* the initial binding | 165 | if(isUndefined(this[name]) || this[name] == null) { |
167 | // is done, override the values only if a value does not already exist | ||
168 | if(isUndefined(this[name]) || this[name] === null) { | ||
169 | this[name] = value; | 166 | this[name] = value; |
170 | } | 167 | } |
171 | } | 168 | } |
172 | } | 169 | } |
173 | 170 | ||
174 | // check if this element has textContent | 171 | // check if this element has textContent |
175 | var textContent = this.element.textContent; | 172 | textContent = this.element.textContent; |
176 | // set textContent only if it is defined as part of element properties | 173 | // set textContent only if it is defined as part of element properties |
177 | if(('textContent' in this) && textContent && ("" !== textContent)) { | 174 | if(('textContent' in this) && textContent && ("" !== textContent)) { |
178 | if(isUndefined(this._elementAttributeValues['textContent'])) { | 175 | if(isUndefined(this._elementAttributeValues['textContent'])) { |
179 | this._elementAttributeValues['textContent'] = textContent; | 176 | this._elementAttributeValues['textContent'] = textContent; |
180 | // since deserializedFromTemplate is called *after* the initial binding | ||
181 | // is done, override the values only if a value does not already exist | ||
182 | if(isUndefined(this['textContent']) || this['textContent'] === null) { | 177 | if(isUndefined(this['textContent']) || this['textContent'] === null) { |
183 | this['textContent'] = textContent; | 178 | this['textContent'] = textContent; |
184 | } | 179 | } |
@@ -187,10 +182,10 @@ exports.NativeControl = Montage.create(Component, { | |||
187 | 182 | ||
188 | // Set defaults for any properties that weren't serialised or set | 183 | // Set defaults for any properties that weren't serialised or set |
189 | // as attributes on the element. | 184 | // as attributes on the element. |
190 | for (d in this._propertyDescriptors) { | 185 | for (attributeName in this._elementAttr |