jasmine-stories 0.0.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.
@@ -0,0 +1,499 @@
1
+ /*
2
+ Script: Namespace.js
3
+ Namespace utility
4
+
5
+ Copyright:
6
+ Copyright (c) 2009 Maxime Bouroumeau-Fuseau
7
+
8
+ License:
9
+ MIT-style license.
10
+
11
+ Version:
12
+ 1.1
13
+ */
14
+
15
+ /*jslint evil : true */
16
+ /*global Namespace, XMLHttpRequest, ActiveXObject, window, document */
17
+
18
+ var Namespace = (function() {
19
+
20
+ var _listeners = {};
21
+ var _includedIdentifiers = [];
22
+
23
+ /**
24
+ * Returns an object in an array unless the object is an array
25
+ *
26
+ * @param mixed obj
27
+ * @return Array
28
+ */
29
+ var _toArray = function(obj) {
30
+ // checks if it's an array
31
+ if (typeof(obj) == 'object' && obj.sort) {
32
+ return obj;
33
+ }
34
+ return Array(obj);
35
+ };
36
+
37
+ /**
38
+ * Creates an XMLHttpRequest object
39
+ *
40
+ * @return XMLHttpRequest
41
+ */
42
+ var _createXmlHttpRequest = function() {
43
+ var xhr;
44
+ try { xhr = new XMLHttpRequest(); } catch(e) {
45
+ try { xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch(e2) {
46
+ try { xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch(e3) {
47
+ try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e4) {
48
+ try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } catch(e5) {
49
+ throw new Error( "This browser does not support XMLHttpRequest." );
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ return xhr;
56
+ };
57
+
58
+ /**
59
+ * Checks if an http request is successful based on its status code.
60
+ * Borrowed from dojo (http://www.dojotoolkit.org).
61
+ *
62
+ * @param Integer status Http status code
63
+ * @return Boolean
64
+ */
65
+ var _isHttpRequestSuccessful = function(status) {
66
+ return (status >= 200 && status < 300) || // Boolean
67
+ status == 304 || // allow any 2XX response code
68
+ status == 1223 || // get it out of the cache
69
+ (!status && (window.location.protocol == "file:" || window.location.protocol == "chrome:") ); // Internet Explorer mangled the status code
70
+ };
71
+
72
+ /**
73
+ * Creates a script tag with the specified data as content
74
+ *
75
+ * @param String data The content of the script
76
+ */
77
+ var _createScript = function(data) {
78
+ var script = document.createElement('script');
79
+ script.type = 'text/javascript';
80
+ script.text = data;
81
+
82
+ if (typeof window.execScript === "object") { // According to IE
83
+ window.execScript(data);
84
+ } else {
85
+ try { // Attempt body insertion
86
+ document.body.appendChild(script);
87
+ } catch (e) { // Fall back on eval
88
+ window['eval'](data);
89
+ }
90
+ }
91
+ };
92
+
93
+ /**
94
+ * Dispatches an event
95
+ *
96
+ * @param String eventName
97
+ * @param Object properties
98
+ */
99
+ var _dispatchEvent = function(eventName, properties) {
100
+ if (!_listeners[eventName]) { return; }
101
+ properties.event = eventName;
102
+ for (var i = 0; i < _listeners[eventName].length; i++) {
103
+ _listeners[eventName][i](properties);
104
+ }
105
+ };
106
+
107
+ /**
108
+ * Creates an Object following the specified namespace identifier.
109
+ *
110
+ * @public
111
+ * @param String identifier The namespace string
112
+ * @param Object klasses (OPTIONAL) An object which properties will be added to the namespace
113
+ * @return Object The most inner object
114
+ */
115
+ var _namespace = function(identifier) {
116
+ var klasses = arguments[1] || false;
117
+ var ns = window;
118
+
119
+ if (identifier !== '') {
120
+ var parts = identifier.split(Namespace.separator);
121
+ for (var i = 0; i < parts.length; i++) {
122
+ if (!ns[parts[i]]) {
123
+ ns[parts[i]] = {};
124
+ }
125
+ ns = ns[parts[i]];
126
+ }
127
+ }
128
+
129
+ if (klasses) {
130
+ for (var klass in klasses) {
131
+ if (klasses.hasOwnProperty(klass)) {
132
+ ns[klass] = klasses[klass];
133
+ }
134
+ }
135
+ }
136
+
137
+ _dispatchEvent('create', { 'identifier': identifier });
138
+ return ns;
139
+ };
140
+
141
+ /**
142
+ * Checks if the specified identifier is defined
143
+ *
144
+ * @public
145
+ * @param String identifier The namespace string
146
+ * @return Boolean
147
+ */
148
+ _namespace.exist = function(identifier) {
149
+ if (identifier === '') { return true; }
150
+
151
+ var parts = identifier.split(Namespace.separator);
152
+ var ns = window;
153
+ for (var i = 0; i < parts.length; i++) {
154
+ if (!ns[parts[i]]) {
155
+ return false;
156
+ }
157
+ ns = ns[parts[i]];
158
+ }
159
+
160
+ return true;
161
+ };
162
+
163
+ /**
164
+ * Maps an identifier to a uri. Is public so it can be overriden by custom scripts.
165
+ *
166
+ * @public
167
+ * @param String identifier The namespace identifier
168
+ * @return String The uri
169
+ */
170
+ _namespace.mapIdentifierToUri = function(identifier) {
171
+ var regexp = new RegExp('\\' + Namespace.separator, 'g');
172
+ return Namespace.baseUri + identifier.replace(regexp, '/') + '.js';
173
+ };
174
+
175
+ /**
176
+ * Loads a remote script atfer mapping the identifier to an uri
177
+ *
178
+ * @param String identifier The namespace identifier
179
+ * @param Function successCallback When set, the file will be loaded asynchronously. Will be called when the file is loaded
180
+ * @param Function errorCallback Callback to be called when an error occurs
181
+ * @return Boolean Success of failure when loading synchronously
182
+ */
183
+ var _loadScript = function(identifier) {
184
+ var successCallback = arguments[1];
185
+ var errorCallback = arguments[2];
186
+ var async = typeof successCallback === "function";
187
+ var uri = _namespace.mapIdentifierToUri(identifier);
188
+ var event = { 'identifier': identifier, 'uri': uri, 'async': async, 'callback': successCallback };
189
+
190
+ var xhr = _createXmlHttpRequest();
191
+ xhr.open("GET", uri, async);
192
+
193
+ if (async) {
194
+ xhr.onreadystatechange = function() {
195
+ if (xhr.readyState == 4) {
196
+ if (_isHttpRequestSuccessful(xhr.status || 0)) {
197
+ _createScript(xhr.responseText);
198
+ _dispatchEvent('include', event);
199
+ successCallback();
200
+ return;
201
+ }
202
+ event.status = xhr.status;
203
+ _dispatchEvent('includeError', event);
204
+ if (typeof errorCallback === "function") {
205
+ errorCallback();
206
+ }
207
+ }
208
+ };
209
+ }
210
+
211
+ xhr.send(null);
212
+
213
+ if (!async) {
214
+ if (_isHttpRequestSuccessful(xhr.status || 0)) {
215
+ _createScript(xhr.responseText);
216
+ _dispatchEvent('include', event);
217
+ return true;
218
+ }
219
+ event.status = xhr.status;
220
+ _dispatchEvent('includeError', event);
221
+ return false;
222
+ }
223
+ };
224
+
225
+ /**
226
+ * Includes a remote javascript file identified by the specified namespace string. The identifier
227
+ * must point to a class. Separators in the string will be converted to slashes and the .js extension will be appended.
228
+ *
229
+ * @public
230
+ * @param String identifier The namespace string
231
+ * @param Function callback (OPTIONAL) A function to call when the remote script has been included
232
+ */
233
+ _namespace.include = function(identifier) {
234
+ var successCallback = arguments[1] || false;
235
+ var errorCallback = arguments[2] || false;
236
+
237
+ // checks if the identifier is not already included
238
+ if (_includedIdentifiers[identifier]) {
239
+ if (typeof successCallback === "function") { successCallback(); }
240
+ return true;
241
+ }
242
+
243
+ if (successCallback) {
244
+ _loadScript(identifier, function() {
245
+ _includedIdentifiers[identifier] = true;
246
+ successCallback();
247
+ }, errorCallback);
248
+ } else {
249
+ if (_loadScript(identifier)) {
250
+ _includedIdentifiers[identifier] = true;
251
+ return true;
252
+ }
253
+ return false;
254
+ }
255
+ };
256
+
257
+ /**
258
+ * Imports properties from the specified namespace to the global space (ie. under window)
259
+ *
260
+ * The identifier string can contain the * wildcard character as its last segment (eg: com.test.*)
261
+ * which will import all properties from the namespace.
262
+ *
263
+ * If not, the targeted namespace will be imported (ie. if com.test is imported, the test object
264
+ * will now be global). If the targeted object is not found, it will be included using include().
265
+ *
266
+ * @public
267
+ * @param String identifier The namespace string
268
+ * @param Function callback (OPTIONAL) A function to call when the process is completed (including the include() if used)
269
+ * @param Boolean autoInclude (OPTIONAL) Whether to automatically auto include the targeted object is not found. Default is Namespace.autoInclude
270
+ */
271
+ _namespace.use = function(identifier) {
272
+ var identifiers = _toArray(identifier);
273
+ var callback = arguments[1] || false;
274
+ var autoInclude = arguments.length > 2 ? arguments[2] : Namespace.autoInclude;
275
+ var event = { 'identifier': identifier };
276
+ var parts, target, ns;
277
+
278
+ for (var i = 0; i < identifiers.length; i++) {
279
+ identifier = identifiers[i];
280
+
281
+ parts = identifier.split(Namespace.separator);
282
+ target = parts.pop();
283
+ ns = _namespace(parts.join(Namespace.separator));
284
+
285
+ if (target == '*') {
286
+ // imports all objects from the identifier, can't use include() in that case
287
+ for (var objectName in ns) {
288
+ if (ns.hasOwnProperty(objectName)) {
289
+ window[objectName] = ns[objectName];
290
+ }
291
+ }
292
+ } else {
293
+ // imports only one object
294
+ if (ns[target]) {
295
+ // the object exists, import it
296
+ window[target] = ns[target];
297
+ } else {
298
+ // the object does not exist
299
+ if (autoInclude) {
300
+ // try to auto include it
301
+ if (callback) {
302
+ _namespace.include(identifier, function() {
303
+ window[target] = ns[target];
304
+
305
+ if (i + 1 < identifiers.length) {
306
+ // we continue to unpack the rest from here
307
+ _namespace.unpack(identifiers.slice(i + 1), callback, autoInclude);
308
+ } else {
309
+ // no more identifiers to unpack
310
+ _dispatchEvent('use', event);
311
+ if (typeof callback === "function") {
312
+ callback();
313
+ }
314
+ }
315
+ });
316
+ return;
317
+ } else {
318
+ _namespace.include(identifier);
319
+ window[target] = ns[target];
320
+ }
321
+ }
322
+ }
323
+ }
324
+
325
+ }
326
+
327
+ // all identifiers have been unpacked
328
+ _dispatchEvent('use', event);
329
+ if (typeof callback === "function") { callback(); }
330
+ };
331
+
332
+ /**
333
+ * Binds the include() and unpack() method to a specified identifier
334
+ *
335
+ * @public
336
+ * @param String identifier The namespace identifier
337
+ * @return Object
338
+ */
339
+ _namespace.from = function(identifier) {
340
+ return {
341
+ /**
342
+ * Includes the identifier specified in from()
343
+ *
344
+ * @see Namespace.include()
345
+ */
346
+ include: function() {
347
+ var callback = arguments[0] || false;
348
+ _namespace.include(identifier, callback);
349
+ },
350
+ /**
351
+ * Includes the identifier specified in from() and unpack
352
+ * the specified indentifier in _identifier
353
+ *
354
+ * @see Namespace.use()
355
+ */
356
+ use: function(_identifier) {
357
+ var callback = arguments[1] || false;
358
+ if (_identifier.charAt(0) == '.') {
359
+ _identifier = identifier + _identifier;
360
+ }
361
+
362
+ if (callback) {
363
+ _namespace.include(identifier, function() {
364
+ _namespace.use(_identifier, callback, false);
365
+ });
366
+ } else {
367
+ _namespace.include(identifier);
368
+ _namespace.use(_identifier, callback, false);
369
+ }
370
+ }
371
+ };
372
+ };
373
+
374
+ /**
375
+ * Registers a namespace so it won't be included
376
+ *
377
+ * Idea and code submitted by Nathan Smith (http://github.com/smith)
378
+ *
379
+ * @param String|Array identifier
380
+ */
381
+ _namespace.provide = function(identifier) {
382
+ var identifiers = _toArray(identifier);
383
+
384
+ for (var i = 0; i < identifiers.length; i++) {
385
+ if (!(identifier in _includedIdentifiers)) {
386
+ _dispatchEvent('provide', { 'identifier': identifier });
387
+ _includedIdentifiers[identifier] = true;
388
+ }
389
+ }
390
+ };
391
+
392
+ /**
393
+ * Registers a function to be called when the specified event is dispatched
394
+ *
395
+ * @param String eventName
396
+ * @param Function callback
397
+ */
398
+ _namespace.addEventListener = function(eventName, callback) {
399
+ if (!_listeners[eventName]) { _listeners[eventName] = []; }
400
+ _listeners[eventName].push(callback);
401
+ };
402
+
403
+ /**
404
+ * Unregisters an event listener
405
+ *
406
+ * @param String eventName
407
+ * @param Function callback
408
+ */
409
+ _namespace.removeEventListener = function(eventName, callback) {
410
+ if (!_listeners[eventName]) { return; }
411
+ for (var i = 0; i < _listeners[eventName].length; i++) {
412
+ if (_listeners[eventName][i] == callback) {
413
+ delete _listeners[eventName][i];
414
+ return;
415
+ }
416
+ }
417
+ };
418
+
419
+ /**
420
+ * Adds methods to javascript native's object
421
+ * Inspired by http://thinkweb2.com/projects/prototype/namespacing-made-easy/
422
+ *
423
+ * @public
424
+ */
425
+ _namespace.registerNativeExtensions = function() {
426
+ /**
427
+ * @see Namespace()
428
+ */
429
+ String.prototype.namespace = function() {
430
+ var klasses = arguments[0] || {};
431
+ return _namespace(this.valueOf(), klasses);
432
+ };
433
+ /**
434
+ * @see Namespace.include()
435
+ */
436
+ String.prototype.include = function() {
437
+ var callback = arguments[0] || false;
438
+ return _namespace.include(this.valueOf(), callback);
439
+ };
440
+ /**
441
+ * @see Namespace.use()
442
+ */
443
+ String.prototype.use = function() {
444
+ var callback = arguments[0] || false;
445
+ return _namespace.use(this.valueOf(), callback);
446
+ };
447
+ /**
448
+ * @see Namespace.from()
449
+ */
450
+ String.prototype.from = function() {
451
+ return _namespace.from(this.valueOf());
452
+ };
453
+ /**
454
+ * @see Namespace.provide()
455
+ * Idea and code submitted by Nathan Smith (http://github.com/smith)
456
+ */
457
+ String.prototype.provide = function() {
458
+ return _namespace.provide(this.valueOf());
459
+ };
460
+ /**
461
+ * @see Namespace.use()
462
+ */
463
+ Array.prototype.use = function() {
464
+ var callback = arguments[0] || false;
465
+ return _namespace.use(this, callback);
466
+ };
467
+ /**
468
+ * @see Namespace.provide()
469
+ */
470
+ Array.prototype.provide = function() {
471
+ return _namespace.provide(this);
472
+ };
473
+ };
474
+
475
+ return _namespace;
476
+ })();
477
+
478
+ /**
479
+ * Namespace segment separator
480
+ *
481
+ * @var String
482
+ */
483
+ Namespace.separator = '.';
484
+
485
+ /**
486
+ * Base uri when using Namespace.include()
487
+ * Must end with a slash
488
+ *
489
+ * @var String
490
+ */
491
+ Namespace.baseUri = './';
492
+
493
+ /**
494
+ * Whether to automatically call Namespace.include() when Namespace.import()
495
+ * does not find the targeted object.
496
+ *
497
+ * @var Boolean
498
+ */
499
+ Namespace.autoInclude = true;