diff options
Diffstat (limited to 'node_modules/montage-user/ui/native-control.js')
-rw-r--r-- | node_modules/montage-user/ui/native-control.js | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/node_modules/montage-user/ui/native-control.js b/node_modules/montage-user/ui/native-control.js new file mode 100644 index 00000000..d3c3a635 --- /dev/null +++ b/node_modules/montage-user/ui/native-control.js | |||
@@ -0,0 +1,240 @@ | |||
1 | /* <copyright> | ||
2 | This file contains proprietary software owned by Motorola Mobility, Inc.<br/> | ||
3 | No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> | ||
4 | (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. | ||
5 | </copyright> */ | ||
6 | |||
7 | var Montage = require("montage").Montage, | ||
8 | Component = require("ui/component").Component; | ||
9 | |||
10 | var isUndefined = function(obj) { | ||
11 | return (typeof obj === 'undefined'); | ||
12 | }; | ||
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 | |||
27 | /** | ||
28 | * Base component for all native controls. | ||
29 | */ | ||
30 | exports.NativeControl = Montage.create(Component, { | ||
31 | |||
32 | hasTemplate: { | ||
33 | value: false | ||
34 | }, | ||
35 | |||
36 | //http://www.w3.org/TR/html5/elements.html#global-attributes | ||
37 | _baseElementProperties: { | ||
38 | value: { | ||
39 | accesskey: null, | ||
40 | contenteditable: null, // true, false, inherit | ||
41 | contextmenu: null, | ||
42 | 'class': null, | ||
43 | dir: null, | ||
44 | draggable: {dataType: 'boolean'}, | ||
45 | dropzone: null, // copy/move/link | ||
46 | hidden: {dataType: 'boolean'}, | ||
47 | //id: null, | ||
48 | lang: null, | ||
49 | spellcheck: null, | ||
50 | style: null, | ||
51 | tabindex: null, | ||
52 | title: null | ||
53 | } | ||
54 | }, | ||
55 | |||
56 | /** Stores values that need to be set on the element. Cleared each draw | ||
57 | * cycle. | ||
58 | */ | ||
59 | _elementAttributeValues: { | ||
60 | value: {}, | ||
61 | distinct: true | ||
62 | }, | ||
63 | |||
64 | /** Stores the descriptors of the properties that can be set on this | ||
65 | * control | ||
66 | */ | ||
67 | _propertyDescriptors: { | ||
68 | value: {}, | ||
69 | distinct: true | ||
70 | }, | ||
71 | |||
72 | /** | ||
73 | * 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 | ||
75 | * automatically created and the value set to the value from the descriptor. | ||
76 | */ | ||
77 | defineAttribute: { | ||
78 | value: function(name, descriptor) { | ||
79 | descriptor = descriptor || {}; | ||
80 | |||
81 | var newDescriptor = { | ||
82 | configurable: isUndefined(descriptor.configurable) ? true: descriptor.configurable, | ||
83 | enumerable: isUndefined(descriptor.enumerable) ? true: descriptor.enumerable, | ||
84 | serializable: isUndefined(descriptor.serializable) ? true: descriptor.serializable, | ||
85 | set: (function(name) { | ||
86 | return function(value) { | ||
87 | var attrName = '_' + name; | ||
88 | |||
89 | var desc = this._propertyDescriptors[name]; | ||
90 | // if requested dataType is boolean (eg: checked, readonly etc) | ||
91 | // coerce the value to boolean | ||
92 | if(desc && "boolean" === desc.dataType) { | ||
93 | value = ( (value || value === "") ? true : false); | ||
94 | } | ||
95 | |||
96 | // If the set value is different to the current one, | ||
97 | // update it here, and set it to be updated on the | ||
98 | // element in the next draw cycle. | ||
99 | if(!isUndefined(value) && this[attrName] !== value) { | ||
100 | this[attrName] = value; | ||
101 | this._elementAttributeValues[name] = value; | ||
102 | this.needsDraw = true; | ||
103 | } | ||
104 | }; | ||
105 | }(name)), | ||
106 | get: (function(name) { | ||
107 | return function() { | ||
108 | return this['_' + name]; | ||
109 | }; | ||
110 | }(name)) | ||
111 | }; | ||
112 | |||
113 | // Define _ property | ||
114 | Montage.defineProperty(this, '_' + name, {value: null}); | ||
115 | // Define property getter and setter | ||
116 | Montage.defineProperty(this, name, newDescriptor); | ||
117 | } | ||
118 | }, | ||
119 | |||
120 | /** | ||
121 | * Add the specified properties as properties of this Component | ||
122 | */ | ||
123 | addAttributes: { | ||
124 | value: function(props) { | ||
125 | var i, desc, prop, obj; | ||
126 | var standardAttributes = {}; | ||
127 | standardAttributes = extend(standardAttributes, this._baseElementProperties); | ||
128 | standardAttributes = extend(standardAttributes, props); | ||
129 | |||
130 | this._propertyDescriptors = standardAttributes; | ||
131 | |||
132 | for(prop in standardAttributes) { | ||
133 | if(standardAttributes.hasOwnProperty(prop)) { | ||
134 | obj = standardAttributes[prop]; | ||
135 | // Make sure that the descriptor is of the correct form. | ||
136 | if(obj === null || isString(obj)) { | ||
137 | desc = {value: obj, dataType: "string"}; | ||
138 | standardAttributes[prop] = desc; | ||
139 | } else { | ||
140 | desc = obj; | ||
141 | } | ||
142 | |||
143 | // Only add the internal prop, and getter and setter if | ||
144 | // they don't already exist. | ||
145 | if(isUndefined(this[prop])) { | ||
146 | this.defineAttribute(prop, desc); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | }, | ||
152 | |||
153 | deserializedFromTemplate: { | ||
154 | value: function() { | ||
155 | // The element is now ready, so we can read the attributes that | ||
156 | // have been set on it. | ||
157 | var attrs = this.element.attributes || []; | ||
158 | var i=0, len = attrs.length, name, value, d, desc; | ||
159 | |||
160 | for(i=0; i< len; i++) { | ||
161 | name = attrs[i].name; | ||
162 | value = attrs[i].value; | ||
163 | |||
164 | if(isUndefined(this._elementAttributeValues[name])) { | ||
165 | this._elementAttributeValues[name] = value; | ||
166 | // since deserializedFromTemplate is called *after* the initial binding | ||
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; | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | |||
174 | // check if this element has textContent | ||
175 | var textContent = this.element.textContent; | ||
176 | // set textContent only if it is defined as part of element properties | ||
177 | if(('textContent' in this) && textContent && ("" !== textContent)) { | ||
178 | if(isUndefined(this._elementAttributeValues['textContent'])) { | ||
179 | 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) { | ||
183 | this['textContent'] = textContent; | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | // Set defaults for any properties that weren't serialised or set | ||
189 | // as attributes on the element. | ||
190 | for (d in this._propertyDescriptors) { | ||
191 | desc = this._propertyDescriptors[d]; | ||
192 | if (this["_"+d] === null && desc !== null && "value" in desc) { | ||
193 | this["_"+d] = this._propertyDescriptors[d].value; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | } | ||
198 | }, | ||
199 | |||
200 | |||
201 | draw: { | ||
202 | enumerable: false, | ||
203 | value: function() { | ||
204 | var el = this.element, desc; | ||
205 | |||
206 | for(var i in this._elementAttributeValues) { | ||
207 | if(this._elementAttributeValues.hasOwnProperty(i)) { | ||
208 | if(i === 'value') { | ||
209 | continue; | ||
210 | } | ||
211 | var val = this[i]; | ||
212 | desc = this._propertyDescriptors[i]; | ||
213 | if(desc && desc.dataType === 'boolean') { | ||
214 | if(val === true) { | ||
215 | el[i] = true; | ||
216 | el.setAttribute(i, i.toLowerCase()); | ||
217 | } else { | ||
218 | el[i] = false; | ||
219 | el.removeAttribute(i); | ||
220 | } | ||
221 | } else { | ||
222 | if(!isUndefined(val) && val !== null) { | ||
223 | if(i === 'textContent') { | ||