@base-framework/base 2.6.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/base.min.js +1 -0
  2. package/es5/base.js +2968 -0
  3. package/es5/modules/ajax.js +663 -0
  4. package/es5/modules/animation.js +188 -0
  5. package/es5/modules/animations.js +1080 -0
  6. package/es5/modules/atom.js +65 -0
  7. package/es5/modules/component.js +1310 -0
  8. package/es5/modules/data-binder.js +1131 -0
  9. package/es5/modules/data.js +1808 -0
  10. package/es5/modules/date.js +525 -0
  11. package/es5/modules/form-validator.js +324 -0
  12. package/es5/modules/history.js +126 -0
  13. package/es5/modules/html-builder.js +461 -0
  14. package/es5/modules/layout.js +1679 -0
  15. package/es5/modules/mouse.js +124 -0
  16. package/es5/modules/nav-link.js +123 -0
  17. package/es5/modules/olderversions/animations-ease.js +1095 -0
  18. package/es5/modules/olderversions/animations-update.js +1048 -0
  19. package/es5/modules/olderversions/base-animations.js +636 -0
  20. package/es5/modules/olderversions/base-component-class.js +100 -0
  21. package/es5/modules/olderversions/base-data-binder-1.js +407 -0
  22. package/es5/modules/olderversions/base-data-binder-class.js +358 -0
  23. package/es5/modules/olderversions/base-layout-parser-class.js +172 -0
  24. package/es5/modules/olderversions/base-mode-1.js +777 -0
  25. package/es5/modules/olderversions/base-model-class.js +585 -0
  26. package/es5/modules/olderversions/data-binder/element-binding/base-data-binder-class.js +358 -0
  27. package/es5/modules/olderversions/data-binder/element-binding/base-model-class.js +585 -0
  28. package/es5/modules/olderversions/data-binder/model-binding/base-data-binder-class.js +353 -0
  29. package/es5/modules/olderversions/data-binder/model-binding/base-model-class.js +604 -0
  30. package/es5/modules/olderversions/data-binder-update-watcher.js +640 -0
  31. package/es5/modules/olderversions/data-tracker.js +187 -0
  32. package/es5/modules/olderversions/event-update.js +666 -0
  33. package/es5/modules/olderversions/nav-link.js +119 -0
  34. package/es5/modules/olderversions/router-with-templates-1.js +785 -0
  35. package/es5/modules/olderversions/router-with-templates.js +701 -0
  36. package/es5/modules/prototypes/ajax.js +657 -0
  37. package/es5/modules/prototypes/atom.js +65 -0
  38. package/es5/modules/prototypes/component.js +972 -0
  39. package/es5/modules/prototypes/data-binder.js +1089 -0
  40. package/es5/modules/prototypes/data.js +1290 -0
  41. package/es5/modules/prototypes/html-builder.js +414 -0
  42. package/es5/modules/prototypes/layout.js +879 -0
  43. package/es5/modules/router.js +1680 -0
  44. package/es5/modules/state.js +274 -0
  45. package/es6/.jshintrc +3 -0
  46. package/es6/base.js +41 -0
  47. package/es6/core.js +1 -0
  48. package/es6/data-tracker.js +351 -0
  49. package/es6/events.js +602 -0
  50. package/es6/legacy/es5/base.js +2968 -0
  51. package/es6/legacy/es5/modules/ajax.js +663 -0
  52. package/es6/legacy/es5/modules/animation.js +188 -0
  53. package/es6/legacy/es5/modules/animations.js +1080 -0
  54. package/es6/legacy/es5/modules/atom.js +65 -0
  55. package/es6/legacy/es5/modules/component.js +1310 -0
  56. package/es6/legacy/es5/modules/data-binder.js +1131 -0
  57. package/es6/legacy/es5/modules/data.js +1808 -0
  58. package/es6/legacy/es5/modules/date.js +525 -0
  59. package/es6/legacy/es5/modules/form-validator.js +324 -0
  60. package/es6/legacy/es5/modules/history.js +126 -0
  61. package/es6/legacy/es5/modules/html-builder.js +461 -0
  62. package/es6/legacy/es5/modules/layout.js +1679 -0
  63. package/es6/legacy/es5/modules/mouse.js +124 -0
  64. package/es6/legacy/es5/modules/nav-link.js +123 -0
  65. package/es6/legacy/es5/modules/olderversions/animations-ease.js +1095 -0
  66. package/es6/legacy/es5/modules/olderversions/animations-update.js +1048 -0
  67. package/es6/legacy/es5/modules/olderversions/base-animations.js +636 -0
  68. package/es6/legacy/es5/modules/olderversions/base-component-class.js +100 -0
  69. package/es6/legacy/es5/modules/olderversions/base-data-binder-1.js +407 -0
  70. package/es6/legacy/es5/modules/olderversions/base-data-binder-class.js +358 -0
  71. package/es6/legacy/es5/modules/olderversions/base-layout-parser-class.js +172 -0
  72. package/es6/legacy/es5/modules/olderversions/base-mode-1.js +777 -0
  73. package/es6/legacy/es5/modules/olderversions/base-model-class.js +585 -0
  74. package/es6/legacy/es5/modules/olderversions/data-binder/element-binding/base-data-binder-class.js +358 -0
  75. package/es6/legacy/es5/modules/olderversions/data-binder/element-binding/base-model-class.js +585 -0
  76. package/es6/legacy/es5/modules/olderversions/data-binder/model-binding/base-data-binder-class.js +353 -0
  77. package/es6/legacy/es5/modules/olderversions/data-binder/model-binding/base-model-class.js +604 -0
  78. package/es6/legacy/es5/modules/olderversions/data-binder-update-watcher.js +640 -0
  79. package/es6/legacy/es5/modules/olderversions/data-tracker.js +187 -0
  80. package/es6/legacy/es5/modules/olderversions/event-update.js +666 -0
  81. package/es6/legacy/es5/modules/olderversions/nav-link.js +119 -0
  82. package/es6/legacy/es5/modules/olderversions/router-with-templates-1.js +785 -0
  83. package/es6/legacy/es5/modules/olderversions/router-with-templates.js +701 -0
  84. package/es6/legacy/es5/modules/prototypes/ajax.js +657 -0
  85. package/es6/legacy/es5/modules/prototypes/atom.js +65 -0
  86. package/es6/legacy/es5/modules/prototypes/component.js +972 -0
  87. package/es6/legacy/es5/modules/prototypes/data-binder.js +1089 -0
  88. package/es6/legacy/es5/modules/prototypes/data.js +1290 -0
  89. package/es6/legacy/es5/modules/prototypes/html-builder.js +414 -0
  90. package/es6/legacy/es5/modules/prototypes/layout.js +879 -0
  91. package/es6/legacy/es5/modules/router.js +1680 -0
  92. package/es6/legacy/es5/modules/state.js +274 -0
  93. package/es6/main.js +1331 -0
  94. package/es6/modules/ajax/ajax.js +514 -0
  95. package/es6/modules/animation/animation.js +236 -0
  96. package/es6/modules/animations/animation-controller.js +231 -0
  97. package/es6/modules/animations/animation.js +64 -0
  98. package/es6/modules/animations/attr-movement.js +66 -0
  99. package/es6/modules/animations/css-movement.js +170 -0
  100. package/es6/modules/animations/movement.js +131 -0
  101. package/es6/modules/animations/value.js +187 -0
  102. package/es6/modules/atom/atom.js +54 -0
  103. package/es6/modules/component/component.js +230 -0
  104. package/es6/modules/component/event-helper.js +119 -0
  105. package/es6/modules/component/jot.js +144 -0
  106. package/es6/modules/component/state-helper.js +262 -0
  107. package/es6/modules/component/unit.js +551 -0
  108. package/es6/modules/data/attrs.js +40 -0
  109. package/es6/modules/data/basic-data.js +500 -0
  110. package/es6/modules/data/data-utils.js +29 -0
  111. package/es6/modules/data/data.js +3 -0
  112. package/es6/modules/data/deep-data.js +541 -0
  113. package/es6/modules/data/model-service.js +528 -0
  114. package/es6/modules/data/model.js +133 -0
  115. package/es6/modules/data/simple-data.js +33 -0
  116. package/es6/modules/data-binder/connection-tracker.js +113 -0
  117. package/es6/modules/data-binder/connection.js +16 -0
  118. package/es6/modules/data-binder/data-binder.js +352 -0
  119. package/es6/modules/data-binder/data-pub-sub.js +141 -0
  120. package/es6/modules/data-binder/data-source.js +56 -0
  121. package/es6/modules/data-binder/element-source.js +219 -0
  122. package/es6/modules/data-binder/one-way-connection.js +46 -0
  123. package/es6/modules/data-binder/one-way-source.js +43 -0
  124. package/es6/modules/data-binder/source.js +36 -0
  125. package/es6/modules/data-binder/two-way-connection.js +75 -0
  126. package/es6/modules/data-binder/two-way-source.js +41 -0
  127. package/es6/modules/date/date.js +544 -0
  128. package/es6/modules/history/history.js +89 -0
  129. package/es6/modules/html-builder/html-builder.js +434 -0
  130. package/es6/modules/import/import.js +390 -0
  131. package/es6/modules/layout/layout-builder.js +1269 -0
  132. package/es6/modules/layout/layout-parser.js +134 -0
  133. package/es6/modules/layout/watcher-helper.js +282 -0
  134. package/es6/modules/mouse/mouse.js +114 -0
  135. package/es6/modules/router/component-helper.js +163 -0
  136. package/es6/modules/router/history-controller.js +216 -0
  137. package/es6/modules/router/nav-link.js +124 -0
  138. package/es6/modules/router/route.js +401 -0
  139. package/es6/modules/router/router.js +789 -0
  140. package/es6/modules/router/utils.js +31 -0
  141. package/es6/modules/state/state-target.js +91 -0
  142. package/es6/modules/state/state.js +171 -0
  143. package/es6/package-lock.json +13 -0
  144. package/es6/package.json +28 -0
  145. package/es6/shared/objects.js +99 -0
  146. package/legacy/es5/base.js +2968 -0
  147. package/legacy/es5/modules/ajax.js +663 -0
  148. package/legacy/es5/modules/animation.js +188 -0
  149. package/legacy/es5/modules/animations.js +1080 -0
  150. package/legacy/es5/modules/atom.js +65 -0
  151. package/legacy/es5/modules/component.js +1310 -0
  152. package/legacy/es5/modules/data-binder.js +1131 -0
  153. package/legacy/es5/modules/data.js +1808 -0
  154. package/legacy/es5/modules/date.js +525 -0
  155. package/legacy/es5/modules/form-validator.js +324 -0
  156. package/legacy/es5/modules/history.js +126 -0
  157. package/legacy/es5/modules/html-builder.js +461 -0
  158. package/legacy/es5/modules/layout.js +1679 -0
  159. package/legacy/es5/modules/mouse.js +124 -0
  160. package/legacy/es5/modules/nav-link.js +123 -0
  161. package/legacy/es5/modules/olderversions/animations-ease.js +1095 -0
  162. package/legacy/es5/modules/olderversions/animations-update.js +1048 -0
  163. package/legacy/es5/modules/olderversions/base-animations.js +636 -0
  164. package/legacy/es5/modules/olderversions/base-component-class.js +100 -0
  165. package/legacy/es5/modules/olderversions/base-data-binder-1.js +407 -0
  166. package/legacy/es5/modules/olderversions/base-data-binder-class.js +358 -0
  167. package/legacy/es5/modules/olderversions/base-layout-parser-class.js +172 -0
  168. package/legacy/es5/modules/olderversions/base-mode-1.js +777 -0
  169. package/legacy/es5/modules/olderversions/base-model-class.js +585 -0
  170. package/legacy/es5/modules/olderversions/data-binder/element-binding/base-data-binder-class.js +358 -0
  171. package/legacy/es5/modules/olderversions/data-binder/element-binding/base-model-class.js +585 -0
  172. package/legacy/es5/modules/olderversions/data-binder/model-binding/base-data-binder-class.js +353 -0
  173. package/legacy/es5/modules/olderversions/data-binder/model-binding/base-model-class.js +604 -0
  174. package/legacy/es5/modules/olderversions/data-binder-update-watcher.js +640 -0
  175. package/legacy/es5/modules/olderversions/data-tracker.js +187 -0
  176. package/legacy/es5/modules/olderversions/event-update.js +666 -0
  177. package/legacy/es5/modules/olderversions/nav-link.js +119 -0
  178. package/legacy/es5/modules/olderversions/router-with-templates-1.js +785 -0
  179. package/legacy/es5/modules/olderversions/router-with-templates.js +701 -0
  180. package/legacy/es5/modules/prototypes/ajax.js +657 -0
  181. package/legacy/es5/modules/prototypes/atom.js +65 -0
  182. package/legacy/es5/modules/prototypes/component.js +972 -0
  183. package/legacy/es5/modules/prototypes/data-binder.js +1089 -0
  184. package/legacy/es5/modules/prototypes/data.js +1290 -0
  185. package/legacy/es5/modules/prototypes/html-builder.js +414 -0
  186. package/legacy/es5/modules/prototypes/layout.js +879 -0
  187. package/legacy/es5/modules/router.js +1680 -0
  188. package/legacy/es5/modules/state.js +274 -0
  189. package/package.json +8 -3
  190. package/update +16 -0
@@ -0,0 +1,1679 @@
1
+ /* base framework module */
2
+ /*
3
+ this will create a layout builder object
4
+ and shortcut functions.
5
+ */
6
+ (function(global)
7
+ {
8
+ "use strict";
9
+
10
+ /**
11
+ * LayoutParser
12
+ *
13
+ * This will parse JSON layouts.
14
+ * @class
15
+ */
16
+ var LayoutParser = base.Class.extend(
17
+ {
18
+ /**
19
+ * @member {array} _reserved
20
+ * @protected
21
+ */
22
+ _reserved: [
23
+ 'tag',
24
+ 'bind',
25
+ 'onCreated',
26
+ 'route',
27
+ 'switch',
28
+ 'useParent',
29
+ 'useState',
30
+ 'useData',
31
+ 'addState',
32
+ 'map',
33
+ 'for',
34
+ 'html',
35
+ 'onSet',
36
+ 'onState',
37
+ 'watch',
38
+ 'context',
39
+ 'useContext',
40
+ 'addContext',
41
+ 'role',
42
+ 'aria',
43
+ 'cache'
44
+ ],
45
+
46
+ /**
47
+ * This will get the tag name of an element.
48
+ *
49
+ * @param {object} obj
50
+ * @return {string}
51
+ */
52
+ getElementTag: function(obj)
53
+ {
54
+ var type = 'div';
55
+
56
+ var node = obj.tag || obj.t;
57
+ if (typeof node !== 'undefined')
58
+ {
59
+ type = obj.tag = node;
60
+ }
61
+
62
+ return type;
63
+ },
64
+
65
+ /**
66
+ * This will setup the element children.
67
+ *
68
+ * @param {object} obj
69
+ */
70
+ setupChildren: function(obj)
71
+ {
72
+ if(obj.nest)
73
+ {
74
+ obj.children = obj.nest;
75
+ obj.nest = null;
76
+ }
77
+ },
78
+
79
+ /**
80
+ * This will parse a layout element.
81
+ *
82
+ * @param {object} obj
83
+ * @return {object}
84
+ */
85
+ parseElement: function(obj)
86
+ {
87
+ var attr = {},
88
+ children = [];
89
+
90
+ var tag = this.getElementTag(obj);
91
+ if(tag === 'button')
92
+ {
93
+ attr.type = attr.type || 'button';
94
+ }
95
+
96
+ this.setupChildren(obj);
97
+ var reserved = this._reserved;
98
+
99
+ for (var key in obj)
100
+ {
101
+ if (obj.hasOwnProperty(key))
102
+ {
103
+ var value = obj[key];
104
+ if(value === undefined || value === null)
105
+ {
106
+ continue;
107
+ }
108
+
109
+ if (base.inArray(reserved, key) !== -1)
110
+ {
111
+ continue;
112
+ }
113
+
114
+ /* we need to filter the children from the attr
115
+ settings. the children need to keep their order. */
116
+ if (typeof value !== 'object')
117
+ {
118
+ attr[key] = value;
119
+ }
120
+ else
121
+ {
122
+ if (key === 'children')
123
+ {
124
+ //Array.prototype.push.apply(children, value);
125
+ children = children.concat(value);
126
+ }
127
+ else
128
+ {
129
+ children.push(value);
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ return {
136
+ tag: tag,
137
+ attr: attr,
138
+ children: children
139
+ };
140
+ }
141
+ });
142
+
143
+ var WATCHER_PATTERN = /(\[\[(.*?)\]\])/g;
144
+
145
+ /**
146
+ * WatcherHelper
147
+ *
148
+ * This helper creates watcher callBacks, parses watcher strings
149
+ * and sets up watchers.
150
+ */
151
+ var WatcherHelper =
152
+ {
153
+ /**
154
+ * This will get the property names to be watched.
155
+ *
156
+ * @protected
157
+ * @param {string} string
158
+ * @return {(array|null)}
159
+ */
160
+ _getWatcherProps: function(string)
161
+ {
162
+ var pattern = /\[\[(.*?)\]\]/g;
163
+ var matches = string.match(pattern);
164
+ if(matches)
165
+ {
166
+ pattern = /(\[\[|\]\])/g;
167
+ for(var i = 0, length = matches.length; i < length; i++)
168
+ {
169
+ matches[i] = matches[i].replace(pattern, '');
170
+ }
171
+ }
172
+ return matches;
173
+ },
174
+
175
+ /**
176
+ * This will update an element attribute.
177
+ *
178
+ * @protected
179
+ * @param {object} ele
180
+ * @param {string} attr
181
+ * @param {string} value
182
+ */
183
+ updateAttr: function(ele, attr, value)
184
+ {
185
+ if(attr === 'text' || attr === 'textContent')
186
+ {
187
+ ele.textContent = value;
188
+ }
189
+ else if(attr === 'innerHTML')
190
+ {
191
+ ele.innerHTML = value;
192
+ }
193
+ else
194
+ {
195
+ if(attr.substring(4, 1) === '-')
196
+ {
197
+ base.setAttr(ele, attr, value);
198
+ }
199
+ else
200
+ {
201
+ ele[attr] = value;
202
+ }
203
+ }
204
+ },
205
+
206
+ /**
207
+ * This will get a watcher callBack.
208
+ *
209
+ * @protected
210
+ * @param {object} ele
211
+ * @param {(object|array)} data
212
+ * @param {string} string
213
+ * @param {string} attr
214
+ * @param {boolean} isArray
215
+ * @return {function}
216
+ */
217
+ _getWatcherCallBack: function(ele, data, string, attr, isArray)
218
+ {
219
+ var self = this;
220
+ return function()
221
+ {
222
+ var count = 0,
223
+ value = string.replace(WATCHER_PATTERN, function()
224
+ {
225
+ var watcherData = (isArray)? data[count] : data;
226
+ count++;
227
+ var result = watcherData.get(arguments[2]);
228
+ return (typeof result !== 'undefined'? result : '');
229
+ });
230
+ self.updateAttr(ele, attr, value);
231
+ };
232
+ },
233
+
234
+ /**
235
+ * This will get the parent data.
236
+ *
237
+ * @param {object} parent
238
+ * @returns {object|null}
239
+ */
240
+ getParentData: function(parent)
241
+ {
242
+ if(parent.data)
243
+ {
244
+ return parent.data;
245
+ }
246
+
247
+ if(parent.context && parent.context.data)
248
+ {
249
+ return parent.context.data;
250
+ }
251
+
252
+ if(parent.state)
253
+ {
254
+ return parent.state;
255
+ }
256
+
257
+ return null;
258
+ },
259
+
260
+ /**
261
+ * This will get a watcher value.
262
+ *
263
+ * @private
264
+ * @param {(string|object)} settings
265
+ * @param {object} parent
266
+ * @return {array}
267
+ */
268
+ getValue: function(settings, parent)
269
+ {
270
+ if(typeof settings === 'string')
271
+ {
272
+ settings =
273
+ {
274
+ value: settings
275
+ };
276
+ }
277
+
278
+ var value = settings.value;
279
+ if(base.isArray(value) === false)
280
+ {
281
+ /**
282
+ * This will setup an array watcher based on a string.
283
+ */
284
+ value = [value, this.getParentData(parent)];
285
+ }
286
+ else
287
+ {
288
+ /**
289
+ * This will check to add the default data.
290
+ */
291
+ if(value.length < 2)
292
+ {
293
+ value.push(this.getParentData(parent));
294
+ }
295
+ }
296
+ return value;
297
+ },
298
+
299
+ /**
300
+ * This will get the prop values.
301
+ *
302
+ * @param {object} data
303
+ * @param {string} string
304
+ * @param {bool} isArray
305
+ * @return {array}
306
+ */
307
+ getPropValues: function(data, props, isArray)
308
+ {
309
+ var values = [];
310
+
311
+ for(var i = 0, length = props.length; i < length; i++)
312
+ {
313
+ var watcherData = (isArray)? data[i] : data;
314
+ var value = watcherData.get(props[i]);
315
+ value = (typeof value !== 'undefined'? value : '');
316
+ values.push(value);
317
+ }
318
+
319
+ return values;
320
+ },
321
+
322
+ /**
323
+ * This will get the watcher callBack.
324
+ *
325
+ * @param {object} settings
326
+ * @param {object} ele
327
+ * @param {object} data
328
+ * @param {string} string
329
+ * @param {bool} isDataArray
330
+ * @return {function}
331
+ */
332
+ getCallBack: function(settings, ele, data, string, isDataArray)
333
+ {
334
+ var callBack,
335
+ overrideCallBack = settings.callBack;
336
+ if(typeof overrideCallBack === 'function')
337
+ {
338
+ var self = this;
339
+ var props = string.match(WATCHER_PATTERN);
340
+ var isMultiProp = (props && props.length > 1);
341
+ callBack = function(value, committer)
342
+ {
343
+ value = (isMultiProp !== true)? value : self.getPropValues(data, props, isDataArray);
344
+ overrideCallBack(ele, value, committer);
345
+ };
346
+ }
347
+ else
348
+ {
349
+ var attr = settings.attr || 'textContent';
350
+ callBack = this._getWatcherCallBack(ele, data, string, attr, isDataArray);
351
+ }
352
+ return callBack;
353
+ },
354
+
355
+ /**
356
+ * This will add a data watcher.
357
+ *
358
+ * @private
359
+ * @param {object} ele
360
+ * @param {(string|object)} settings
361
+ * @param {object} parent
362
+ */
363
+ addDataWatcher: function(ele, settings, parent)
364
+ {
365
+ var value = this.getValue(settings, parent),
366
+ data = value[1];
367
+ if(!data)
368
+ {
369
+ return false;
370
+ }
371
+
372
+ var string = value[0],
373
+ isDataArray = base.isArray(data);
374
+
375
+ var callBack = this.getCallBack(settings, ele, data, string, isDataArray);
376
+ var props = this._getWatcherProps(string);
377
+ for(var i = 0, length = props.length; i < length; i++)
378
+ {
379
+ var watcherData = (isDataArray)? data[i] : data;
380
+ this.addWatcher(ele, watcherData, props[i], callBack);
381
+ }
382
+ },
383
+
384
+ /**
385
+ * This will setup a data watcher.
386
+ *
387
+ * @param {object} ele
388
+ * @param {(string|object)} settings
389
+ * @param {object} parent
390
+ */
391
+ setup: function(ele, settings, parent)
392
+ {
393
+ if(!settings)
394
+ {
395
+ return false;
396
+ }
397
+
398
+ if(Array.isArray(settings))
399
+ {
400
+ settings = {
401
+ attr: settings[2],
402
+ value: [settings[0], settings[1]]
403
+ };
404
+ }
405
+
406
+ this.addDataWatcher(ele, settings, parent);
407
+ },
408
+
409
+ /**
410
+ * This will add a watcher.
411
+ *
412
+ * @private
413
+ * @param {object} ele
414
+ * @param {object} data
415
+ * @param {string} prop
416
+ * @param {function} callBack
417
+ */
418
+ addWatcher: function(ele, data, prop, callBack)
419
+ {
420
+ base.DataBinder.watch(ele, data, prop, callBack);
421
+ }
422
+ };
423
+
424
+ /**
425
+ * This will create a watch element.
426
+ *
427
+ * @param {object} data
428
+ * @param {string} prop
429
+ * @returns {function}
430
+ */
431
+ global.Watch = function(data, prop)
432
+ {
433
+ return function(callBack)
434
+ {
435
+ return {
436
+ onSet: [data, prop, function(ele, value)
437
+ {
438
+ return callBack(value);
439
+ }]
440
+ };
441
+ };
442
+ };
443
+
444
+ base.DataTracker.addType('context', function(data)
445
+ {
446
+ if(!data)
447
+ {
448
+ return false;
449
+ }
450
+
451
+ data.parent.removeContextBranch(data.branch);
452
+ });
453
+
454
+ var parser = new LayoutParser();
455
+
456
+ /**
457
+ * LayoutBuilder
458
+ *
459
+ * This will build JSON layouts.
460
+ *
461
+ * @class
462
+ * @augments base.htmlBuilder
463
+ */
464
+ var LayoutBuilder = base.htmlBuilder.extend(
465
+ {
466
+ /**
467
+ * This will create a new element.
468
+ *
469
+ * @override
470
+ * @param {string} nodeName The node name.
471
+ * @param {object} attrObject The node attributes.
472
+ * @param {object} container The node container.
473
+ * @param {object} parent
474
+ * @return {object} The new element.
475
+ */
476
+ create: function(nodeName, attrObject, container, parent)
477
+ {
478
+ var obj = document.createElement(nodeName);
479
+ this._addElementAttrs(obj, attrObject, parent);
480
+ this.append(container, obj);
481
+ return obj;
482
+ },
483
+
484
+ /**
485
+ * This will add the element attributes.
486
+ *
487
+ * @protected
488
+ * @param {object} obj
489
+ * @param {object} attrObject
490
+ * @param {object} parent
491
+ */
492
+ _addElementAttrs: function(obj, attrObject, parent)
493
+ {
494
+ /* we want to check if we have attrributes to add */
495
+ if(!attrObject || typeof attrObject !== 'object')
496
+ {
497
+ return false;
498
+ }
499
+
500
+ /* we need to add the type if set to stop ie
501
+ from removing the value if set after the value is
502
+ added */
503
+ var type = attrObject.type;
504
+ if(typeof type !== 'undefined')
505
+ {
506
+ base.setAttr(obj, 'type', type);
507
+ }
508
+
509
+ /* we want to add each attr to the obj */
510
+ for(var prop in attrObject)
511
+ {
512
+ /* we have already added the type so we need to
513
+ skip if the prop is type */
514
+ if(attrObject.hasOwnProperty(prop) === false || prop === 'type')
515
+ {
516
+ continue;
517
+ }
518
+
519
+ var attrPropValue = attrObject[prop];
520
+
521
+ /* we want to check to add the attr settings
522
+ by property name */
523
+ if(prop === 'innerHTML')
524
+ {
525
+ obj.innerHTML = attrPropValue;
526
+ }
527
+ else if(prop.indexOf('-') !== -1)
528
+ {
529
+ // this will handle data and aria attributes
530
+ base.setAttr(obj, prop, attrPropValue);
531
+ }
532
+ else
533
+ {
534
+ this.addAttr(obj, prop, attrPropValue, parent);
535
+ }
536
+ }
537
+ },
538
+
539
+ /**
540
+ * This will add an element attribute.
541
+ *
542
+ * @param {object} obj
543
+ * @param {object} attr
544
+ * @param {string} value
545
+ */
546
+ addAttr: function(obj, attr, value, parent)
547
+ {
548
+ if(value === '' || !attr)
549
+ {
550
+ return false;
551
+ }
552
+
553
+ /* we want to check to add a value or an event listener */
554
+ var type = typeof value;
555
+ if(type === 'function')
556
+ {
557
+ /* this will add the event using the base events
558
+ so the event is tracked */
559
+ attr = removeEventPrefix(attr);
560
+ base.addListener(attr, obj, function(e)
561
+ {
562
+ value.call(this, e, parent);
563
+ });
564
+ }
565
+ else
566
+ {
567
+ var attrName = normalizeAttr(attr);
568
+ obj[attrName] = value;
569
+ }
570
+ },
571
+
572
+ /**
573
+ * This will render a function/Unit/Component.
574
+ *
575
+ * @param {object|function} layout
576
+ * @param {object} container
577
+ * @param {object} [parent]
578
+ * @returns {object} The layout Unit or Component
579
+ */
580
+ render: function(layout, container, parent)
581
+ {
582
+ if(!layout)
583
+ {
584
+ return;
585
+ }
586
+
587
+ switch(typeof layout)
588
+ {
589
+ case 'object':
590
+ if(layout.isUnit === true)
591
+ {
592
+ this.createComponent(layout, container, parent);
593
+ return layout;
594
+ }
595
+ default:
596
+ var component = Jot(layout);
597
+ var jot = new component();
598
+ this.createComponent(jot, container, parent);
599
+ return jot;
600
+ }
601
+ },
602
+
603
+ /**
604
+ * This will build a JSON layout.
605
+ *
606
+ * @param {object} obj The JSON layout.
607
+ * @param {object} [container] The parent receiving the layout.
608
+ * @param {object} [parent] The component adding the layout.
609
+ * @return {object} The doc Frag element.
610
+ */
611
+ build: function(obj, container, parent)
612
+ {
613
+ var fragment = this.createDocFragment();
614
+
615
+ if (base.isArray(obj))
616
+ {
617
+ var item;
618
+ for (var i = 0, length = obj.length; i < length; i++)
619
+ {
620
+ item = obj[i];
621
+ this.buildElement(item, fragment, parent);
622
+ }
623
+ }
624
+ else
625
+ {
626
+ this.buildElement(obj, fragment, parent);
627
+ }
628
+
629
+ if(container && typeof container === 'object')
630
+ {
631
+ container.appendChild(fragment);
632
+ }
633
+ return fragment;
634
+ },
635
+
636
+ /**
637
+ * This will build an element or component.
638
+ *
639
+ * @param {object} obj
640
+ * @param {object} container
641
+ * @param {object} [parent] The component adding the layout.
642
+ */
643
+ buildElement: function(obj, container, parent)
644
+ {
645
+ if(!obj)
646
+ {
647
+ return;
648
+ }
649
+
650
+ if(obj.component || obj.isUnit === true)
651
+ {
652
+ this.createComponent(obj, container, parent);
653
+ }
654
+ else
655
+ {
656
+ this.createElement(obj, container, parent);
657
+ }
658
+ },
659
+
660
+ /**
661
+ * This will append a child element to a parent.
662
+ *
663
+ * @override
664
+ * @param {object} parent
665
+ * @param {object} child
666
+ */
667
+ append: function(parent, child)
668
+ {
669
+ parent.appendChild(child);
670
+ },
671
+
672
+ /**
673
+ * This will create an element.
674
+ *
675
+ * @protected
676
+ * @param {object} obj
677
+ * @param {object} container
678
+ * @param {object} [parent] The component adding the layout.
679
+ */
680
+ createElement: function(obj, container, parent)
681
+ {
682
+ var settings = parser.parseElement(obj);
683
+ var ele = this.createNode(settings, container, parent);
684
+
685
+ var propName = obj.cache;
686
+ if(parent && propName)
687
+ {
688
+ parent[propName] = ele;
689
+ }
690
+
691
+ /* we want to recursively add the children to
692
+ the new element */
693
+ var children = settings.children;
694
+ if (children.length > 0)
695
+ {
696
+ var child;
697
+ for (var i = 0, length = children.length; i < length; i++)
698
+ {
699
+ child = children[i];
700
+ if(child === null)
701
+ {
702
+ continue;
703
+ }
704
+
705
+ this.buildElement(child, ele, parent);
706
+ }
707
+ }
708
+
709
+ this.addElementDirectives(ele, obj, parent);
710
+ },
711
+
712
+ /**
713
+ * This will add the element directives.
714
+ *
715
+ * @param {object} ele
716
+ * @param {object} obj
717
+ * @param {object} [parent]
718
+ */
719
+ addElementDirectives: function(ele, obj, parent)
720
+ {
721
+ if(typeof obj.onCreated === 'function')
722
+ {
723
+ obj.onCreated(ele, parent);
724
+ }
725
+
726
+ /* this will check to bind the element to
727
+ the prop of a data */
728
+ var bind = obj.bind;
729
+ if(bind)
730
+ {
731
+ this.bindElement(ele, bind, parent);
732
+ }
733
+
734
+ if(obj.route)
735
+ {
736
+ this.addRoute(ele, obj.route, parent);
737
+ }
738
+
739
+ if(obj.switch)
740
+ {
741
+ this.addSwitch(ele, obj.switch, parent);
742
+ }
743
+
744
+ if(obj.html)
745
+ {
746
+ this.addHtml(ele, obj.html);
747
+ }
748
+
749
+ if(obj.useContext)
750
+ {
751
+ this.useContext(ele, obj.useContext, parent);
752
+ }
753
+
754
+ if(obj.addContext)
755
+ {
756
+ this.addContext(ele, obj.addContext, parent);
757
+ }
758
+
759
+ if(obj.context)
760
+ {
761
+ this.context(ele, obj.context, parent);
762
+ }
763
+
764
+ if(obj.role)
765
+ {
766
+ this.addRole(ele, obj.role, parent);
767
+ }
768
+
769
+ if(obj.aria)
770
+ {
771
+ this.addAria(ele, obj.aria, parent);
772
+ }
773
+
774
+ if(parent)
775
+ {
776
+ var onState = obj.onState;
777
+ if(onState && onState.length)
778
+ {
779
+ this.onState(ele, onState, parent);
780
+ }
781
+
782
+ var onSet = obj.onSet;
783
+ if(onSet && onSet.length)
784
+ {
785
+ this.onSet(ele, onSet, parent);
786
+ }
787
+
788
+ var map = obj.map;
789
+ if(map && map.length)
790
+ {
791
+ this.map(ele, map, parent);
792
+ }
793
+
794
+ var forBind = obj.for;
795
+ if(forBind && forBind.length)
796
+ {
797
+ this.for(ele, forBind, parent);
798
+ }
799
+
800
+ var useParent = obj.useParent;
801
+ if(useParent)
802
+ {
803
+ this.useParent(ele, useParent, parent);
804
+ }
805
+
806
+ var useData = obj.useData;
807
+ if(useData)
808
+ {
809
+ this.useData(ele, useData, parent);
810
+ }
811
+
812
+ var useState = obj.useState;
813
+ if(useState)
814
+ {
815
+ this.useState(ele, useState, parent);
816
+ }
817
+
818
+ var addState = obj.addState;
819
+ if(addState)
820
+ {
821
+ this.addState(ele, addState, parent);
822
+ }
823
+ }
824
+
825
+ if(obj.watch)
826
+ {
827
+ this.watch(ele, obj.watch, parent);
828
+ }
829
+ },
830
+
831
+ /**
832
+ * This will get the data source from the parent component.
833
+ *
834
+ * @protected
835
+ * @param {object} parent
836
+ * @return {(object|boolean)}
837
+ */
838
+ _getDataSource: function(parent)
839
+ {
840
+ if(!parent)
841
+ {
842
+ return false;
843
+ }
844
+
845
+ if(parent.data)
846
+ {
847
+ return parent.data;
848
+ }
849
+
850
+ if(parent.context && parent.context.data)
851
+ {
852
+ return parent.context.data;
853
+ }
854
+
855
+ if(parent.state)
856
+ {
857
+ return parent.state;
858
+ }
859
+
860
+ return false;
861
+ },
862
+
863
+ /**
864
+ * This will bind an element to data.
865
+ *
866
+ * @protected
867
+ * @param {object} ele
868
+ * @param {(string|array)} bind
869
+ * @param {*} parent
870
+ */
871
+ bindElement: function(ele, bind, parent)
872
+ {
873
+ var data, prop, filter;
874
+
875
+ if(typeof bind === 'string')
876
+ {
877
+ data = this._getDataSource(parent);
878
+ if(!data)
879
+ {
880
+ return false;
881
+ }
882
+
883
+ prop = bind;
884
+ }
885
+ else
886
+ {
887
+ if(typeof bind[0] !== 'object')
888
+ {
889
+ var dataSource = this._getDataSource(parent);
890
+ if(!dataSource)
891
+ {
892
+ return false;
893
+ }
894
+ else
895
+ {
896
+ bind.unshift(dataSource);
897
+ }
898
+ }
899
+
900
+ data = bind[0];
901
+ prop = bind[1];
902
+ filter = bind[2];
903
+ }
904
+
905
+ base.DataBinder.bind(ele, data, prop, filter);
906
+ },
907
+
908
+ /**
909
+ * This will add a route.
910
+ *
911
+ * @protected
912
+ * @param {object} ele
913
+ * @param {(object|array)} route
914
+ * @param {object} parent
915
+ */
916
+ addRoute: function(ele, route, parent)
917
+ {
918
+ if(!route)
919
+ {
920
+ return false;
921
+ }
922
+
923
+ if(base.isArray(route))
924
+ {
925
+ for(var i = 0, length = route.length; i < length; i++)
926
+ {
927
+ this.setupRoute(ele, route[i], parent);
928
+ }
929
+ }
930
+ else
931
+ {
932
+ this.setupRoute(ele, route, parent);
933
+ }
934
+ },
935
+
936
+ /**
937
+ * This will setup a route.
938
+ *
939
+ * @protected
940
+ * @param {object} ele
941
+ * @param {object} route
942
+ * @param {object} parent
943
+ */
944
+ setupRoute: function(ele, route, parent)
945
+ {
946
+ // this will check to resume route
947
+ // if(this.checkResume(route))
948
+ // {
949
+ // this.resumeRoute(ele, route.component.route);
950
+ // return;
951
+ // }
952
+
953
+ route.container = ele;
954
+ route.parent = parent;
955
+ var newRoute = base.router.add(route);
956
+
957
+ this.trackRoute(ele, newRoute);
958
+ },
959
+
960
+ /**
961
+ * This will check to resume route.
962
+ *
963
+ * @param {object} route
964
+ */
965
+ checkResume: function(route)
966
+ {
967
+ return (route && route.component && route.component.route);
968
+ },
969
+
970
+ /**
971
+ * This will resume a route.
972
+ *
973
+ * @param {object} ele
974
+ * @param {object} route
975
+ */
976
+ resumeRoute: function(ele, route)
977
+ {
978
+ base.router.resume(route, ele);
979
+
980
+ this.trackRoute(ele, route);
981
+ },
982
+
983
+ /**
984
+ * This will track a route.
985
+ *
986
+ * @param {object} ele
987
+ * @param {object} route
988
+ */
989
+ trackRoute: function(ele, route)
990
+ {
991
+ base.DataTracker.add(ele, 'routes',
992
+ {
993
+ route: route
994
+ });
995
+ },
996
+
997
+ /**
998
+ * This will add a switch.
999
+ *
1000
+ * @protected
1001
+ * @param {object} ele
1002
+ * @param {array} group
1003
+ * @param {object} parent
1004
+ */
1005
+ addSwitch: function(ele, group, parent)
1006
+ {
1007
+ var route = group[0];
1008
+ // this will check to resume switch
1009
+ // if(this.checkResume(route))
1010
+ // {
1011
+ // this.resumeSwitch(ele, group);
1012
+ // return;
1013
+ // }
1014
+
1015
+ for(var i = 0, length = group.length; i < length; i++)
1016
+ {
1017
+ route = group[i];
1018
+ route.container = ele;
1019
+ route.parent = parent;
1020
+ }
1021
+
1022
+ var id = base.router.addSwitch(group);
1023
+ this.trackSwitch(ele, id);
1024
+ },
1025
+
1026
+ resumeSwitch: function(ele, group)
1027
+ {
1028
+ var id = base.router.resumeSwitch(group, ele);
1029
+ this.trackSwitch(ele, id);
1030
+ },
1031
+
1032
+ /**
1033
+ * This will track a switch.
1034
+ *
1035
+ * @param {object} ele
1036
+ * @param {int} id
1037
+ */
1038
+ trackSwitch: function(ele, id)
1039
+ {
1040
+ base.DataTracker.add(ele, 'switch',
1041
+ {
1042
+ id: id
1043
+ });
1044
+ },
1045
+
1046
+ /**
1047
+ * This will add aria attributes.
1048
+ *
1049
+ * @protected
1050
+ * @param {object} ele
1051
+ * @param {array} role
1052
+ * @param {object} parent
1053
+ */
1054
+ addRole: function(ele, role, parent)
1055
+ {
1056
+ if(!role)
1057
+ {
1058
+ return;
1059
+ }
1060
+
1061
+ if(role)
1062
+ {
1063
+ base.setAttr(ele, 'role', role);
1064
+ }
1065
+ },
1066
+
1067
+ /**
1068
+ * This will add aria attributes.
1069
+ *
1070
+ * @protected
1071
+ * @param {object} ele
1072
+ * @param {array} attributes
1073
+ * @param {object} parent
1074
+ */
1075
+ addAria: function(ele, attributes, parent)
1076
+ {
1077
+ if(!attributes)
1078
+ {
1079
+ return;
1080
+ }
1081
+
1082
+ var role = attributes.role;
1083
+ if(role)
1084
+ {
1085
+ base.setAttr(ele, 'role', role);
1086
+ attributes.role = null;
1087
+ }
1088
+
1089
+ /**
1090
+ * This will setup the onSet callBack.
1091
+ *
1092
+ * @param {string} attr
1093
+ * @return {function}
1094
+ */
1095
+ var onSetCallBack = function(attr)
1096
+ {
1097
+ return function(ele, val)
1098
+ {
1099
+ var text = (val)? "true" : "false";
1100
+ base.setAttr(ele, attr, text);
1101
+ };
1102
+ };
1103
+
1104
+ for(var prop in attributes)
1105
+ {
1106
+ if(attributes.hasOwnProperty(prop) === false || attributes[prop] === null)
1107
+ {
1108
+ continue;
1109
+ }
1110
+
1111
+ var value = attributes[prop];
1112
+ var attr = 'aria-' + prop;
1113
+
1114
+ /* this will setup an onSet to change the attr value
1115
+ when the data chnages. */
1116
+ if(Array.isArray(value))
1117
+ {
1118
+ value.push(onSetCallBack(attr));
1119
+ this.onSet(ele, value, parent);
1120
+ }
1121
+ else
1122
+ {
1123
+ base.setAttr(ele, attr, value);
1124
+ }
1125
+ }
1126
+ },
1127
+
1128
+ /**
1129
+ * This will get the parent context.
1130
+ *
1131
+ * @param {object|null} parent
1132
+ * @returns {object|null}
1133
+ */
1134
+ getParentContext: function(parent)
1135
+ {
1136
+ return (!parent)? null : parent.getContext();
1137
+ },
1138
+
1139
+ /**
1140
+ * This will set the context attributes.
1141
+ *
1142
+ * @protected
1143
+ * @param {object} ele
1144
+ * @param {function} context
1145
+ * @param {object} [parent]
1146
+ */
1147
+ context: function(ele, context, parent)
1148
+ {
1149
+ if(typeof context !== 'function')
1150
+ {
1151
+ return;
1152
+ }
1153
+
1154
+ var parentContext = this.getParentContext(parent);
1155
+ var attributes = context(parentContext);
1156
+ if(!attributes)
1157
+ {
1158
+ return;
1159
+ }
1160
+
1161
+ this._addElementAttrs(ele, attributes, parent);
1162
+ this.addElementDirectives(ele, attributes, parent);
1163
+ },
1164
+
1165
+ /**
1166
+ * This will use the parent context.
1167
+ *
1168
+ * @param {object} ele
1169
+ * @param {function} callBack
1170
+ * @param {object} [parent]
1171
+ * @returns {void}
1172
+ */
1173
+ useContext: function(ele, callBack, parent)
1174
+ {
1175
+ if(typeof callBack !== 'function')
1176
+ {
1177
+ return;
1178
+ }
1179
+
1180
+ var parentContext = this.getParentContext(parent);
1181
+ callBack(parentContext);
1182
+ },
1183
+
1184
+ /**
1185
+ * This will add context the parent context.
1186
+ *
1187
+ * @param {object} ele
1188
+ * @param {array} callBack
1189
+ * @param {object} [parent]
1190
+ * @returns {void}
1191
+ */
1192
+ addContext: function(ele, callBack, parent)
1193
+ {
1194
+ if(typeof callBack !== 'function' || !parent)
1195
+ {
1196
+ return;
1197
+ }
1198
+
1199
+ var parentContext = this.getParentContext(parent);
1200
+ var childContext = callBack(parentContext);
1201
+ if(!childContext)
1202
+ {
1203
+ return;
1204
+ }
1205
+
1206
+ parent.addContextBranch(childContext[0], childContext[1]);
1207
+ },
1208
+
1209
+ /**
1210
+ * This will track the child context on the element.
1211
+ *
1212
+ * @param {object} ele
1213
+ * @param {string} branchName
1214
+ * @param {object} parent
1215
+ */
1216
+ trackContext: function(ele, branchName, parent)
1217
+ {
1218
+ base.DataTracker.add(ele, 'context',
1219
+ {
1220
+ branch: branchName,
1221
+ parent: parent
1222
+ });
1223
+ },
1224
+
1225
+ /**
1226
+ * This will add a watcher.
1227
+ *
1228
+ * @protected
1229
+ * @param {object} ele
1230
+ * @param {(array|object)} watcher
1231
+ * @param {object} [parent]
1232
+ */
1233
+ watch: function(ele, watcher, parent)
1234
+ {
1235
+ if(!watcher)
1236
+ {
1237
+ return false;
1238
+ }
1239
+
1240
+ if(base.isArray(watcher) && typeof watcher[0] !== 'string')
1241
+ {
1242
+ for(var i = 0, length = watcher.length; i < length; i++)
1243
+ {
1244
+ WatcherHelper.setup(ele, watcher[i], parent);
1245
+ }
1246
+ }
1247
+ else
1248
+ {
1249
+ WatcherHelper.setup(ele, watcher, parent);
1250
+ }
1251
+ },
1252
+
1253
+ /**
1254
+ * This will pass the parent state to the callBack.
1255
+ *
1256
+ * @param {object} ele
1257
+ * @param {function} callBack
1258
+ * @param {object} parent
1259
+ */
1260
+ useParent: function(ele, callBack, parent)
1261
+ {
1262
+ if(!callBack || !parent)
1263
+ {
1264
+ return false;
1265
+ }
1266
+
1267
+ callBack(parent, ele);
1268
+ },
1269
+
1270
+ /**
1271
+ * This will pass the parent state to the callBack.
1272
+ *
1273
+ * @param {object} ele
1274
+ * @param {function} callBack
1275
+ * @param {object} parent
1276
+ */
1277
+ useData: function(ele, callBack, parent)
1278
+ {
1279
+ if(!callBack || !parent)
1280
+ {
1281
+ return false;
1282
+ }
1283
+
1284
+ callBack(parent.data, ele);
1285
+ },
1286
+
1287
+ /**
1288
+ * This will pass the parent state to the callBack.
1289
+ *
1290
+ * @param {object} ele
1291
+ * @param {function} callBack
1292
+ * @param {object} parent
1293
+ */
1294
+ useState: function(ele, callBack, parent)
1295
+ {
1296
+ if(!callBack || !parent)
1297
+ {
1298
+ return false;
1299
+ }
1300
+
1301
+ callBack(parent.state, ele);
1302
+ },
1303
+
1304
+ /**
1305
+ * This will pass the parent state to the callBack.
1306
+ *
1307
+ * @param {object} ele
1308
+ * @param {function} callBack
1309
+ * @param {object} parent
1310
+ */
1311
+ addState: function(ele, callBack, parent)
1312
+ {
1313
+ if(!callBack || !parent)
1314
+ {
1315
+ return false;
1316
+ }
1317
+
1318
+ if(parent.stateHelper)
1319
+ {
1320
+ var state = parent.state;
1321
+ var states = callBack(state);
1322
+ parent.stateHelper.addStates(states);
1323
+ }
1324
+ },
1325
+
1326
+ /**
1327
+ * This will map children to the element.
1328
+ *
1329
+ * @param {object} ele
1330
+ * @param {array} settings
1331
+ * @param {object} parent
1332
+ */
1333
+ map: function(ele, settings, parent)
1334
+ {
1335
+ var items = settings[0];
1336
+ if(!items || items.length < 1)
1337
+ {
1338
+ return;
1339
+ }
1340
+
1341
+ var item = settings[1];
1342
+ var children = [];
1343
+ for(var i = 0, length = items.length; i < length; i++)
1344
+ {
1345
+ var row = items[i];
1346
+ if(!row)
1347
+ {
1348
+ continue;
1349
+ }
1350
+
1351
+ var layout = item(row, i);
1352
+ if(layout === null)
1353
+ {
1354
+ continue;
1355
+ }
1356
+
1357
+ children.push(layout);
1358
+ }
1359
+
1360
+ return this.build(children, ele, parent);
1361
+ },
1362
+
1363
+ /**
1364
+ * This will watch a data attr and update the
1365
+ * children to the element when the attr value is updated.
1366
+ *
1367
+ * @param {object} ele
1368
+ * @param {array} settings
1369
+ * @param {object} parent
1370
+ */
1371
+ for: function(ele, settings, parent)
1372
+ {
1373
+ var data, prop, item, scope;
1374
+
1375
+ if(settings.length < 3)
1376
+ {
1377
+ var parentData = this.getParentSetData(parent);
1378
+ if(!parentData)
1379
+ {
1380
+ return;
1381
+ }
1382
+
1383
+ data = parentData;
1384
+ prop = settings[0];
1385
+ item = settings[1];
1386
+ scope = settings[2];
1387
+ }
1388
+ else
1389
+ {
1390
+ data = settings[0];
1391
+ prop = settings[1];
1392
+ item = settings[2];
1393
+ scope = settings[3];
1394
+ }
1395
+
1396
+ var scopeData = (scope !== false);
1397
+ var self = this;
1398
+ base.DataBinder.watch(ele, data, prop, function(items)
1399
+ {
1400
+ self.removeAll(ele);
1401
+ if(!items || items.length < 1)
1402
+ {
1403
+ return;
1404
+ }
1405
+
1406
+ var children = [];
1407
+ for(var i = 0, length = items.length; i < length; i++)
1408
+ {
1409
+ var scoped = (scopeData)? data.scope(prop + '[' + i + ']') : null;
1410
+ var layout = item(items[i], i, scoped);
1411
+ if(layout === null)
1412
+ {
1413
+ continue;
1414
+ }
1415
+
1416
+ children.push(layout);
1417
+ }
1418
+
1419
+ return self.build(children, ele, parent);
1420
+ });
1421
+ },
1422
+
1423
+ /**
1424
+ * This will add an onState watcher.
1425
+ *
1426
+ * @param {object} ele
1427
+ * @param {array} onState
1428
+ * @param {object} parent
1429
+ */
1430
+ onState: function(ele, onState, parent)
1431
+ {
1432
+ this.onUpdate(ele, parent.state, onState, parent);
1433
+ },
1434
+
1435
+ /**
1436
+ * This will get the parent set data.
1437
+ *
1438
+ * @param {object} parent
1439
+ * @returns {object|null}
1440
+ */
1441
+ getParentSetData: function(parent)
1442
+ {
1443
+ if(parent.data)
1444
+ {
1445
+ return parent.data;
1446
+ }
1447
+
1448
+ if(parent.context && parent.context.data)
1449
+ {
1450
+ return parent.context.data;
1451
+ }
1452
+
1453
+ return null;
1454
+ },
1455
+
1456
+ /**
1457
+ * This will add an onSet watcher.
1458
+ *
1459
+ * @param {object} ele
1460
+ * @param {array} onSet
1461
+ * @param {object} parent
1462
+ */
1463
+ onSet: function(ele, onSet, parent)
1464
+ {
1465
+ var data = this.getParentSetData(parent);
1466
+ this.onUpdate(ele, data, onSet, parent);
1467
+ },
1468
+
1469
+ /**
1470
+ * This will setup a data watcher.
1471
+ *
1472
+ * @param {object} ele
1473
+ * @param {object} data
1474
+ * @param {string} prop
1475
+ * @param {(function|object)} callBack
1476
+ * @param {string} parent
1477
+ */
1478
+ onUpdate: function(ele, data, settings, parent)
1479
+ {
1480
+ var prop,
1481
+ self = this,
1482
+ callBack, update;
1483
+
1484
+ if(base.isArray(settings[0]))
1485
+ {
1486
+ for(var i = 0, maxLength = settings.length; i < maxLength; i++)
1487
+ {
1488
+ var itemSettings = settings[i];
1489
+ if(!itemSettings)
1490
+ {
1491
+ continue;
1492
+ }
1493
+
1494
+ this.onUpdate(ele, data, itemSettings, parent);
1495
+ }
1496
+ return;
1497
+ }
1498
+
1499
+ if(settings.length < 3)
1500
+ {
1501
+ prop = settings[0];
1502
+ callBack = settings[1];
1503
+ }
1504
+ else
1505
+ {
1506
+ data = settings[0];
1507
+ prop = settings[1];
1508
+ callBack = settings[2];
1509
+ }
1510
+
1511
+ if(!data || !prop)
1512
+ {
1513
+ return false;
1514
+ }
1515
+
1516
+ switch(typeof callBack)
1517
+ {
1518
+ case 'object':
1519
+ update = function(value)
1520
+ {
1521
+ self.addClass(ele, callBack, value);
1522
+ };
1523
+ break;
1524
+ case 'function':
1525
+ update = function(value)
1526
+ {
1527
+ self.updateElement(ele, callBack, prop, value, parent);
1528
+ };
1529
+ break;
1530
+ }
1531
+
1532
+ base.DataBinder.watch(ele, data, prop, update);
1533
+ },
1534
+
1535
+ /**
1536
+ * This will setup a data watcher.
1537
+ *
1538
+ * @private
1539
+ * @param {object} ele
1540
+ * @param {function} callBack
1541
+ * @param {string} value
1542
+ * @param {string} parent
1543
+ */
1544
+ updateElement: function(ele, callBack, prop, value, parent)
1545
+ {
1546
+ var result = callBack(ele, value, parent);
1547
+ switch(typeof result)
1548
+ {
1549
+ case 'object':
1550
+ if(parent && result && result.isUnit === true && parent.persist === true && parent.state)
1551
+ {
1552
+ var key = prop + ':' + value,
1553
+ state = parent.state,
1554
+ previousResult = state.get(key);
1555
+ if(typeof previousResult !== 'undefined')
1556
+ {
1557
+ result = previousResult;
1558
+ }
1559
+
1560
+ state.set(key, result);
1561
+ }
1562
+ this.rebuild(ele, result, parent);
1563
+ break;
1564
+ case 'string':
1565
+ this.addHtml(ele, result);
1566
+ break;
1567
+ }
1568
+ },
1569
+
1570
+ /**
1571
+ * This will add or remove a class from an element.
1572
+ *
1573
+ * @param {object} ele
1574
+ * @param {object} stateStyles
1575
+ * @param {*} newValue
1576
+ */
1577
+ addClass: function(ele, stateStyles, newValue)
1578
+ {
1579
+ for(var prop in stateStyles)
1580
+ {
1581
+ if(!stateStyles.hasOwnProperty(prop) || !prop)
1582
+ {
1583
+ continue;
1584
+ }
1585
+
1586
+ if(stateStyles[prop] === newValue)
1587
+ {
1588
+ base.addClass(ele, prop);
1589
+ }
1590
+ else
1591
+ {
1592
+ base.removeClass(ele, prop);
1593
+ }
1594
+ }
1595
+ },
1596
+
1597
+ /**
1598
+ * This will reset an element innerHTML and rebuild.
1599
+ *
1600
+ * @private
1601
+ * @param {object} ele
1602
+ * @param {object} layout
1603
+ * @param {object} parent
1604
+ */
1605
+ rebuild: function(ele, layout, parent)
1606
+ {
1607
+ this.removeAll(ele);
1608
+ this.build(layout, ele, parent);
1609
+ },
1610
+
1611
+ /**
1612
+ * This will create a component.
1613
+ *
1614
+ * @protected
1615
+ * @param {object} obj
1616
+ * @param {object} container
1617
+ * @param {object} parent
1618
+ */
1619
+ createComponent: function(obj, container, parent)
1620
+ {
1621
+ // this will allow both cached components or native components
1622
+ var component = obj.component || obj;
1623
+ component.parent = parent;
1624
+
1625
+ if(parent && parent.persist === true && component.persist !== false)
1626
+ {
1627
+ component.persist = true;
1628
+ }
1629
+
1630
+ if(component.cacheable && parent)
1631
+ {
1632
+ parent[component.cacheable] = component;
1633
+ }
1634
+
1635
+ component.setup(container);
1636
+
1637
+ if(obj.component && typeof obj.onCreated === 'function')
1638
+ {
1639
+ obj.onCreated(component);
1640
+ }
1641
+ },
1642
+
1643
+ /**
1644
+ * This will create a node.
1645
+ *
1646
+ * @param {object} settings
1647
+ * @param {object} container
1648
+ * @param {object} parent
1649
+ * @return {object}
1650
+ */
1651
+ createNode: function(settings, container, parent)
1652
+ {
1653
+ var tag = settings.tag;
1654
+ if(tag !== 'text')
1655
+ {
1656
+ return this.create(tag, settings.attr, container, parent);
1657
+ }
1658
+
1659
+ var attr = settings.attr;
1660
+ var text = attr.textContent || attr.text;
1661
+ return this.createTextNode(text, container);
1662
+ }
1663
+ });
1664
+
1665
+ var builder = base.extend.builder = new LayoutBuilder();
1666
+
1667
+ /**
1668
+ * This will build a JSON layout.
1669
+ *
1670
+ * @param {object} obj
1671
+ * @param {object} [container]
1672
+ * @param {object} [parent]
1673
+ * @return {object}
1674
+ */
1675
+ base.extend.buildLayout = function(obj, container, parent)
1676
+ {
1677
+ builder.build(obj, container, parent);
1678
+ };
1679
+ })(this);