xooie 0.1.0 → 0.1.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.
@@ -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
- });