aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage/ui/native-control.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/montage/ui/native-control.js')
-rw-r--r--node_modules/montage/ui/native-control.js240
1 files changed, 240 insertions, 0 deletions
diff --git a/node_modules/montage/ui/native-control.js b/node_modules/montage/ui/native-control.js
new file mode 100644
index 00000000..d3c3a635
--- /dev/null
+++ b/node_modules/montage/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
7var Montage = require("montage").Montage,
8 Component = require("ui/component").Component;
9
10var isUndefined = function(obj) {
11 return (typeof obj === 'undefined');
12};
13
14var extend = function(destination, source) {
15 for (var property in source) {
16 destination[property] = source[property];
17 }
18 return destination;
19};
20
21var STRING_CLASS = '[object String]';
22var _toString = Object.prototype.toString;
23var isString = function(object) {
24 return _toString.call(object) === STRING_CLASS;
25};
26
27/**
28 * Base component for all native controls.
29 */
30exports.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') {
224 el.textContent = val;
225 } else {
226 //https://developer.mozilla.org/en/DOM/element.setAttribute