xooie 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,628 +0,0 @@
1
- /*
2
- * Copyright 2012 Comcast
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- /**
18
- * class Xooie.Widget
19
- *
20
- * The base xooie widget. This widget contains all common functionality for Xooie widgets but does not provide
21
- * specific functionality.
22
- **/
23
-
24
- define('xooie/widgets/base', ['jquery', 'xooie/xooie', 'xooie/helpers', 'xooie/shared', 'xooie/keyboard_navigation'], function($, $X, helpers, shared, keyboardNavigation) {
25
-
26
- var Widget;
27
-
28
- /**
29
- * Xooie.Widget@xooie-init(event)
30
- * - event (Event): A jQuery event object
31
- *
32
- * A jQuery special event triggered when the widget is successfully initialized. Triggers on the `root` element
33
- * of the widget. This event will fire if bound after the widget is instantiated.
34
- **/
35
-
36
- $.event.special['xooie-init'] = {
37
- add: function(handleObj) {
38
- var id = $(this).data('xooieInstance');
39
- if (typeof id !== 'undefined') {
40
- var event = $.Event('xooie-init');
41
- event.namespace = handleObj.namespace;
42
- event.data = handleObj.data;
43
-
44
- handleObj.handler.call(this, event);
45
- }
46
- }
47
- };
48
-
49
- /**
50
- * Xooie.Widget@xooie-refresh(event)
51
- * - event (Event): A jQuery event object
52
- *
53
- * A jQuery special event triggered when the widget is refreshed. Refresh events occur when the `root` element
54
- * is passed to [[$X]]. Triggers on the `root` element of the widget.
55
- **/
56
-
57
- /** internal
58
- * Xooie.Widget.roleDetails(name) -> Object
59
- *
60
- * TODO: Test and document.
61
- **/
62
- function roleDetails (name) {
63
- return {
64
- processor: '_process_role_' + name,
65
- renderer: '_render_role_' + name,
66
- getter: '_get_role_' + name,
67
- pluralName: name + 's',
68
- selector: '[data-x-role=' + name + ']'
69
- };
70
- }
71
-
72
- /** internal
73
- * Xooie.Widget.roleDispatcher(name, prototype)
74
- *
75
- * TODO: Test and document.
76
- **/
77
- function roleDispatcher(name, prototype) {
78
- var role = roleDetails(name);
79
-
80
- if (helpers.isUndefined(prototype[role.pluralName])) {
81
- prototype._definedRoles.push(name);
82
-
83
- prototype[role.pluralName] = function() {
84
- return this[role.getter]();
85
- };
86
- }
87
- }
88
-
89
- /** internal
90
- * Xooie.Widget.cacheInstance(instance) -> Integer
91
- * - instance (Widget): An instance of a Xooie widget to be cached
92
- *
93
- * Recursively checks for the next available index in [[$X._instanceCache]] using [[$X._instanceIndex]]
94
- * as a reference point. Returns the index.
95
- **/
96
- function cacheInstance (instance) {
97
- if (typeof instance !== 'undefined') {
98
- var index = $X._instanceIndex;
99
-
100
- $X._instanceIndex += 1;
101
-
102
- if (typeof $X._instanceCache[index] === 'undefined') {
103
- $X._instanceCache[index] = instance;
104
-
105
- return index;
106
- } else {
107
- return cacheInstance(instance);
108
- }
109
- }
110
- }
111
-
112
- /**
113
- * new Xooie.Widget(element[, addons])
114
- * - element (Element | String): A jQuery-selected element or string selector for the root element of this widget
115
- * - addons (Array): An optional collection of [[Xooie.Addon]] classes to be instantiated with this widget
116
- *
117
- * Instantiates a new Xooie widget, or returns an existing widget if it is already associated with the element passed.
118
- * Any addons passed into the constructor will be instantiated and added to the [[Xooie.Widget#addons]] collection.
119
- **/
120
- Widget = function(element, addons) {
121
- var self = this;
122
-
123
- element = $(element);
124
-
125
- //set the default options
126
- shared.setData(this, element.data());
127
-
128
- //do instance tracking
129
- if (element.data('xooieInstance')) {
130
- if (typeof $X._instanceCache[element.data('xooieInstance')] !== 'undefined'){
131
- element.trigger(this.get('refreshEvent'));
132
- return $X._instanceCache[element.data('xooieInstance')];
133
- } else {
134
- this.cleanup();
135
- }
136
- }
137
-
138
- element.on(this.get('initEvent') + ' ' + this.get('refreshEvent'), function(){
139
- self._applyRoles();
140
- });
141
-
142
- var id = cacheInstance(this);
143
-
144
- this.set('id', id);
145
-
146
- this.set('root', element);
147
-
148
- element.addClass(this.get('className'))
149
- .addClass(this.get('instanceClass'));
150
-
151
- var initCheck = function(){
152
- var i;
153
-
154
- if (!self._extendCount || self._extendCount <= 0) {
155
-
156
- if (typeof addons !== 'undefined') {
157
- for (i = 0; i < addons.length; i+=1) {
158
- new addons[i](self);
159
- }
160
- }
161
-
162
- element.attr('data-xooie-instance', id);
163
-
164
- element.trigger(self.get('initEvent'));
165
- self._extendCount = null;
166
- } else {
167
- setTimeout(initCheck, 0);
168
- }
169
- };
170
-
171
- if (this._extendCount > 0) {
172
- setTimeout(initCheck, 0);
173
- } else {
174
- initCheck();
175
- }
176
-
177
- // new keyboardNavigation();
178
- };
179
-
180
- /** internal
181
- * Xooie.Widget._renderMethods -> Object
182
- *
183
- * A dispatch table of all supported template render methods.
184
- *
185
- * ##### Supported Frameworks
186
- *
187
- * - **mustache**: [http://mustache.github.io/]
188
- * - **jsrender**: [https://github.com/BorisMoore/jsrender]
189
- * - **underscore**: [http://underscorejs.org/]
190
- **/
191
- Widget._renderMethods = {
192
- //TODO: make this a default template
193
- 'micro_template': function(template, view) {
194
- if (typeof template.micro_render !== 'undefined') {
195
- return $(template.micro_render(view));
196
- } else {
197
- return false;
198
- }
199
- },
200
-
201
- 'mustache': function(template, view) {
202
- if (typeof Mustache !== 'undefined' && typeof Mustache.render !== 'undefined') {
203
- return $(Mustache.render(template.html(), view));
204
- } else {
205
- return false;
206
- }
207
- },
208
-
209
- 'jsrender': function(template, view) {
210
- if (typeof template.render !== 'undefined') {
211
- return $(template.render(view));
212
- } else {
213
- return false;
214
- }
215
- },
216
-
217
- 'underscore': function(template, view) {
218
- if (typeof _ !== 'undefined' && typeof _.template !== 'undefined') {
219
- return $(_.template(template.html())(view).trim());
220
- } else {
221
- return false;
222
- }
223
- }
224
- };
225
-
226
- //CLASS METHODS
227
-
228
- /**
229
- * Xooie.Widget.defineWriteOnly(name)
230
- * - name (String): The name of the property to define as a write-only property
231
- *
232
- * See [[Xooie.shared.defineWriteOnly]].
233
- **/
234
- Widget.defineWriteOnly = function(name) {
235
- shared.defineWriteOnly(this, name);
236
- };
237
-
238
- /**
239
- * Xooie.Widget.defineReadOnly(name[, defaultValue])
240
- * - name (String): The name of the property to define as a read-only property.
241
- * - defaultValue (Object): An optional default value.
242
- *
243
- * See [[Xooie.shared.defineReadOnly]].
244
- **/
245
- Widget.defineReadOnly = function(name, defaultValue){
246
- shared.defineReadOnly(this, name, defaultValue);
247
- };
248
-
249
- /**
250
- * Xooie.Widget.define(name[, defaultValue])
251
- * - name (String): The name of the property to define.
252
- * - defaultValue: An optional default value.
253
- *
254
- * A method that defines a property as both readable and writable. In reality it calls both [[Xooie.Widget.defineReadOnly]]
255
- * and [[Xooie.Widget.defineWriteOnly]].
256
- **/
257
- Widget.define = function(name, defaultValue){
258
- this.defineReadOnly(name, defaultValue);
259
- this.defineWriteOnly(name);
260
- };
261
-
262
- /**
263
- * Xooie.Widget.defineRole(name)
264
- *
265
- * TODO: This needs tests and documentation
266
- **/
267
- Widget.defineRole = function(name) {
268
- var role = roleDetails(name);
269
-
270
- roleDispatcher(name, this.prototype);
271
-
272
- if (!helpers.isFunction(this.prototype[role.getter])) {
273
- this.prototype[role.getter] = function() {
274
- return this.root().find(role.selector);
275
- };
276
- }
277
- };
278
-
279
- /**
280
- * Xooie.Widget.extend(constr) -> Widget
281
- * - constr (Function): The constructor for the new [[Xooie.Widget]] class.
282
- *
283
- * See [[Xooie.shared.extend]].
284
- **/
285
- Widget.extend = function(constr){
286
- return shared.extend(constr, this);
287
- };
288
-
289
- /**
290
- * Xooie.Widget.createStyleRule(selector, properties) -> cssRule | undefined
291
- * - selector (String): The selector used to identify the rule.
292
- * - properties (Object): A hash of key/value pairs of css properties and values.
293
- *
294
- * Creates a new css rule in the Xooie stylesheet. If the rule exists, it will overwrite said rule.
295
- **/
296
- // TODO: update so that if the rule exists the properties are added to the rule
297
- Widget.createStyleRule = function(selector, properties) {
298
- if (typeof $X._stylesheet.addRule !== 'undefined') {
299
- return $X._stylesheet.addRule(selector, properties);
300
- }
301
- };
302
-
303
- /**
304
- * Xooie.Widget.getStyleRule(selector) -> cssRule | undefined
305
- * - selector (String): The selector used to identify the rule.
306
- *
307
- * Retrieves the css rule from the Xooie stylesheet using the provided `selector`. If the rule is not
308
- * present in [[$X._styleRules]] then the method will check in [[$X._stylesheet]].
309
- **/
310
- Widget.getStyleRule = function(selector) {
311
- if ($X._styleRules.hasOwnProperty(selector)) {
312
- return $X._styleRules[selector];
313
- } else {
314
- return $X._stylesheet.getRule(selector);
315
- }
316
- };
317
-
318
- /** internal
319
- * Xooie.Widget#_definedProps -> Array
320
- *
321
- * A collection of properties that have been defined for this class instance.
322
- **/
323
- Widget.prototype._definedProps = [];
324
-
325
- /** internal
326
- * Xooie.Widget#_definedRoles -> Array
327
- *
328
- * A collection of roles that have been defined for this class instance.
329
- **/
330
- Widget.prototype._definedRoles = [];
331
-
332
- /** internal, read-only
333
- * Xooie.Widget#_extendCount -> Integer | null
334
- *
335
- * Tracks the number of constructors that need to be called.
336
- **/
337
- Widget.prototype._extendCount = null;
338
-
339
- //PROPERTY DEFINITIONS
340
-
341
- /** internal
342
- * Xooie.Widget#_id -> Integer
343
- *
344
- * The id of this widget. This value is used to keep track of the instance.
345
- **/
346
- /**
347
- * Xooie.Widget#id([value]) -> Integer
348
- * - value: an optional value to be set.
349
- *
350
- * The method for setting or getting [[Xooie.Widget#_id]]. Returns the current value of
351
- * [[Xooie.Widget#_id]] if no value is passed or sets the value.
352
- **/
353
- Widget.define('id');
354
-
355
- /** internal
356
- * Xooie.Widget#_root -> Element
357
- *
358
- * The root DOM element associated with this widget. This is a jQuery-selected element.
359
- **/
360
- /**
361
- * Xooie.Widget#root([value]) -> Element
362
- * - value: an optional value to be set.
363
- *
364
- * The method for setting or getting [[Xooie.Widget#_root]]. Returns the current value of
365
- * [[Xooie.Widget#_root]] if no value is passed or sets the value.
366
- **/
367
- Widget.define('root');
368
-
369
- /** internal
370
- * Xooie.Widget#_namespace -> String
371
- *
372
- * The namespace of the widget. This value is used for determining the value of [[Xooie.Widget#className]],
373
- * [[Xooie.Widget#refreshEvent]], [[Xooie.Widget#initEvent]], and [[Xooie.Widget#instanceClass]].
374
- **/
375
- /**
376
- * Xooie.Widget#namespace([value]) -> String
377
- * - value: an optional value to be set.
378
- *
379
- * The method for setting or getting [[Xooie.Widget#_namespace]]. Returns the current value of
380
- * [[Xooie.Widget#_namespace]] if no value is passed or sets the value.
381
- **/
382
- Widget.define('namespace', '');
383
-
384
- /** internal
385
- * Xooie.Widget#_templateLanguage -> String
386
- *
387
- * Determines the template framework to use.
388
- * Default: `micro_template`.
389
- **/
390
- /**
391
- * Xooie.Widget#templateLanguage([value]) -> String
392
- * - value: an optional value to be set.
393
- *
394
- * The method for setting or getting [[Xooie.Widget#_templateLanguage]]. Returns the current value of
395
- * [[Xooie.Widget#_templateLanguage]] if no value is passed or sets the value.
396
- **/
397
- Widget.define('templateLanguage', 'micro_template');
398
-
399
- /** internal, read-only
400
- * Xooie.Widget#_addons -> Object
401
- *
402
- * A collection of addons instantiated addons associated with this widget.
403
- * Default: `{}`.
404
- **/
405
- /** read-only
406
- * Xooie.Widget#addons([value]) -> Object
407
- * - value: an optional value to be set.
408
- *
409
- * The method for setting or getting [[Xooie.Widget#_addons]]. Returns the current value of
410
- * [[Xooie.Widget#_addons]] if no value is passed or sets the value.
411
- **/
412
- Widget.defineReadOnly('addons');
413
-
414
- /** internal, read-only
415
- * Xooie.Widget#_refreshEvent -> String
416
- *
417
- * The name of the event that is triggered when the module is refreshed. Refresh events are triggered
418
- * when the root element of this widget is passed to [[$X]].
419
- * Default: `xooie-refresh`.
420
- **/
421
- /** read-only
422
- * Xooie.Widget#refreshEvent() -> String
423
- *
424
- * The method for getting [[Xooie.Widget#_refreshEvent]].
425
- **/
426
- Widget.defineReadOnly('refreshEvent', 'xooie-refresh');
427
-
428
- /** internal, read-only
429
- * Xooie.Widget#_initEvent -> String
430
- *
431
- * The name of the event that is triggered when the module is initialized. The initialization event
432
- * is not triggered until all addons have been instantiated.
433
- * Default: `xooie-init`.
434
- **/
435
- /** read-only
436
- * Xooie.Widget#initEvent() -> String
437
- *
438
- * The method for getting [[Xooie.Widget#_initEvent]].
439
- **/
440
- Widget.defineReadOnly('initEvent', 'xooie-init');
441
-
442
- /** internal, read-only
443
- * Xooie.Widget#_className -> String
444
- *
445
- * The string class name that is applied to the root element of this widget when it is instantiated.
446
- * Default: `is-instantiated`.
447
- **/
448
- /** read-only
449
- * Xooie.Widget#className() -> String
450
- *
451
- * The method for getting [[Xooie.Widget#_className]].
452
- **/
453
- Widget.defineReadOnly('className', 'is-instantiated');
454
-
455
- /** internal, read-only
456
- * Xooie.Widget#_instanceClass -> String
457
- *
458
- * A class that is generated and applied to the root element of the widget.
459
- * Default: `{{namespace}}-{{id}}`
460
- **/
461
- /** read-only
462
- * Xooie.Widget#instanceClass() -> String
463
- *
464
- * The method for getting [[Xooie.Widget#_instanceClass]].
465
- **/
466
- Widget.defineReadOnly('instanceClass');
467
-
468
-
469
- //PROTOTYPE DEFINITIONS
470
-
471
- /**
472
- * Xooie.Widget#get(name) -> object
473
- * - name (String): The name of the property to be retrieved.
474
- *
475
- * See [[Xooie.shared.get]].
476
- **/
477
- Widget.prototype.get = function(name) {
478
- return shared.get(this, name);
479
- };
480
-
481
- /**
482
- * Xooie.Widget#set(name, value)
483
- * - name (String): The name of the property to be set.
484
- * - value: The value of the property to be set.
485
- *
486
- * See [[Xooie.shared.set]].
487
- **/
488
- Widget.prototype.set = function(name, value) {
489
- return shared.set(this, name, value);
490
- };
491
-
492
- /**
493
- * Xooie.Widget#cleanup()
494
- *
495
- * Removes the `className` and `instanceClass` classes and `data-xooie-instance` attribute from the root element.
496
- * Calls [[Xooie.Addon.cleanup]] for each addon. This will permit the instance to be garbage collected.
497
- **/
498
- Widget.prototype.cleanup = function() {
499
- var name;
500
-
501
- for (name in this.addons()) {
502
- if (this.addons().hasOwnProperty(name)) {
503
- this.addons()[name].cleanup();
504
- }
505
- }
506
-
507
- this.root().removeClass(this.className());
508
- this.root().removeClass(this.instanceClass());
509
- this.root().attr('data-xooie-instance', false);
510
- };
511
-
512
- /**
513
- * Xooie.Widget#render(template, view) -> Element
514
- * - template (Element): A jQuery-selected script element that contains the template to be rendered.
515
- * - view (Object): The data to be passed to the template when it is rendered.
516
- *
517
- * Renders the template with the provided data by calling the method in [[Xooie.Widget.renderMethods]] based on the
518
- * template language specified. Returns `$('<span>Error rendering template</span>')` when an error occurs
519
- **/
520
- Widget.prototype.render = function(template, view) {
521
- var language = template.data('templateLanguage') || this.templateLanguage(),
522
- result = Widget._renderMethods[language](template, view);
523
-
524
- if (result === false) {
525
- return $('<span>Error rendering template</span>');
526
- } else {
527
- return result;
528
- }
529
- };
530
-
531
- /** internal
532
- * Xooie.Widget#_getRoleId(role, index) -> String
533
- * - role (String): The name of the role for which this id is being generated.
534
- * - index (Integer): The index at which the particular element exists in the read order.
535
- *
536
- * Generates an id string to be applied to an element of the specified role. The format of
537
- * this id string is `x-[[Xooie.Widget#id]]-{role}-{index}`.
538
- **/
539
- Widget.prototype._getRoleId = function(role, index) {
540
- return 'x-' + this.id() + '-' + role + '-' + index;
541
- };
542
-
543
- /** internal
544
- * Xooie.Widget#_applyRoles()
545
- *
546
- * TODO: Test and document.
547
- **/
548
- Widget.prototype._applyRoles = function() {
549
- var i, j, role, elements;
550
-
551
- for (i=0; i < this._definedRoles.length; i+=1) {
552
- role = roleDetails(this._definedRoles[i]);
553
- elements = this[role.getter]();
554
-
555
- if (elements.length === 0 && helpers.isFunction(this[role.renderer])) {
556
- elements = this[role.renderer]();
557
- }
558
-
559
- if (helpers.isUndefined(elements)) {
560
- return;
561
- }
562
-
563
- for (j=0; j < elements.length; j+=1) {
564
- $(elements[j]).attr('id', this._getRoleId(this._definedRoles[i], j));
565
- }
566
-
567
- if (helpers.isFunction(this[role.processor])) {
568
- this[role.processor](elements);
569
- }
570
- }
571
- };
572
-
573
- /** internal
574
- * Xooie.Widget#_process_addons(addons) -> Object
575
- * - addons (Object): The collection of instantiated addons for this widget
576
- *
577
- * Checks to see if the addons object has been defined. We can't define objects as
578
- * 'default' values for properties since the object will be the same for each instance.
579
- **/
580
- Widget.prototype._process_addons = function(addons){
581
- if (typeof addons === 'undefined'){
582
- addons = this._addons = {};
583
- }
584
-
585
- return addons;
586
- };
587
-
588
- /** internal
589
- * Xooie.Widget#_process_refreshEvent(refreshEvent) -> String
590
- * - refreshEvent (String): The unmodified refreshEvent string.
591
- *
592
- * Adds the [[Xooie.Widget#namespace]] to the `refreshEvent`
593
- **/
594
- Widget.prototype._process_refreshEvent = function(refreshEvent){
595
- return this.namespace() === '' ? refreshEvent : refreshEvent + '.' + this.namespace();
596
- };
597
-
598
- /** internal
599
- * Xooie.Widget#_process_initEvent(initEvent) -> String
600
- * - initEvent (String): The unmodified initEvent string.
601
- *
602
- * Adds the [[Xooie.Widget#namespace]] to the `initEvent`
603
- **/
604
- Widget.prototype._process_initEvent = function(initEvent){
605
- return this.namespace() === '' ? initEvent : initEvent + '.' + this.namespace();
606
- };
607
-
608
- /** internal
609
- * Xooie.Widget#_process_className(className) -> String
610
- * - className (String): The unmodified className string.
611
- *
612
- * Adds the [[Xooie.Widget#namespace]] to the `className`
613
- **/
614
- Widget.prototype._process_className = function(className) {
615
- return this.namespace() === '' ? className : className + '-' + this.namespace();
616
- };
617
-
618
- /** internal
619
- * Xooie.Widget#_process_instanceClass() -> String
620
- *
621
- * Creates an instanceClass string from the [[Xooie.Widget#namespace]] and [[Xooie.Widget#id]].
622
- **/
623
- Widget.prototype._process_instanceClass = function() {
624
- return this.namespace() === '' ? 'widget-' + this.id() : this.namespace() + '-' + this.id();
625
- };
626
-
627
- return Widget;
628
- });