kojac 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +7 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +158 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +69 -0
  7. data/Rakefile +27 -0
  8. data/app/assets/javascripts/can_extensions.js +45 -0
  9. data/app/assets/javascripts/kojac.js +1230 -0
  10. data/app/assets/javascripts/kojac_canjs.js +191 -0
  11. data/app/assets/javascripts/kojac_ember.js +463 -0
  12. data/app/controllers/kojac_controller.rb +70 -0
  13. data/app/serializers/default_kojac_serializer.rb +10 -0
  14. data/diagram.odg +0 -0
  15. data/kojac.gemspec +36 -0
  16. data/lib/kojac/app_serialize.rb +29 -0
  17. data/lib/kojac/kojac_rails.rb +432 -0
  18. data/lib/kojac/ring_strong_parameters.rb +195 -0
  19. data/lib/kojac/version.rb +3 -0
  20. data/lib/kojac.rb +8 -0
  21. data/lib/tasks/kojac_tasks.rake +4 -0
  22. data/notes.txt +48 -0
  23. data/spec/.DS_Store +0 -0
  24. data/spec/can_cache_spec.js +87 -0
  25. data/spec/can_factory_spec.js +144 -0
  26. data/spec/can_model_spec.js +127 -0
  27. data/spec/demo/README.rdoc +261 -0
  28. data/spec/demo/Rakefile +7 -0
  29. data/spec/demo/app/assets/javascripts/application.js +15 -0
  30. data/spec/demo/app/assets/stylesheets/application.css +13 -0
  31. data/spec/demo/app/controllers/application_controller.rb +3 -0
  32. data/spec/demo/app/helpers/application_helper.rb +2 -0
  33. data/spec/demo/app/mailers/.gitkeep +0 -0
  34. data/spec/demo/app/models/.gitkeep +0 -0
  35. data/spec/demo/app/views/layouts/application.html.erb +14 -0
  36. data/spec/demo/config/application.rb +65 -0
  37. data/spec/demo/config/boot.rb +10 -0
  38. data/spec/demo/config/database.yml +25 -0
  39. data/spec/demo/config/environment.rb +5 -0
  40. data/spec/demo/config/environments/development.rb +37 -0
  41. data/spec/demo/config/environments/production.rb +67 -0
  42. data/spec/demo/config/environments/test.rb +37 -0
  43. data/spec/demo/config/initializers/backtrace_silencers.rb +7 -0
  44. data/spec/demo/config/initializers/inflections.rb +15 -0
  45. data/spec/demo/config/initializers/mime_types.rb +5 -0
  46. data/spec/demo/config/initializers/secret_token.rb +7 -0
  47. data/spec/demo/config/initializers/session_store.rb +8 -0
  48. data/spec/demo/config/initializers/wrap_parameters.rb +14 -0
  49. data/spec/demo/config/locales/en.yml +5 -0
  50. data/spec/demo/config/routes.rb +58 -0
  51. data/spec/demo/config.ru +4 -0
  52. data/spec/demo/lib/assets/.gitkeep +0 -0
  53. data/spec/demo/log/.gitkeep +0 -0
  54. data/spec/demo/public/404.html +26 -0
  55. data/spec/demo/public/422.html +26 -0
  56. data/spec/demo/public/500.html +25 -0
  57. data/spec/demo/public/favicon.ico +0 -0
  58. data/spec/demo/script/rails +6 -0
  59. data/spec/ember_factory_spec.js +157 -0
  60. data/spec/ember_model_spec.js +179 -0
  61. data/spec/external/.DS_Store +0 -0
  62. data/spec/external/ember/.DS_Store +0 -0
  63. data/spec/external/ember/ember-1.0.0-rc.6.js +30970 -0
  64. data/spec/external/ember/handlebars-1.0.0-rc.4.js +2239 -0
  65. data/spec/external/jasmine/MIT.LICENSE +20 -0
  66. data/spec/external/jasmine/jasmine-html.js +616 -0
  67. data/spec/external/jasmine/jasmine.css +81 -0
  68. data/spec/external/jasmine/jasmine.js +2529 -0
  69. data/spec/external/jasmine.async.js +51 -0
  70. data/spec/external/jquery/jquery-1.7.2.js +9404 -0
  71. data/spec/external/jquery/jquery-1.7.2.min.js +4 -0
  72. data/spec/external/jquery/jquery-1.9.1.js +9597 -0
  73. data/spec/external/json2.js +480 -0
  74. data/spec/external/steal/steal-121115.js +2747 -0
  75. data/spec/external/steal/steal-3.2.3.js +2098 -0
  76. data/spec/external/steal/steal-3.2.3.min.js +27 -0
  77. data/spec/external/steal/steal.js +2466 -0
  78. data/spec/external/steal/steal.min.js +32 -0
  79. data/spec/external/steal/stealconfig.js +19 -0
  80. data/spec/external/underscore.js +1223 -0
  81. data/spec/external/underscore_plus.js +261 -0
  82. data/spec/external.zip +0 -0
  83. data/spec/handler_stack_spec.js +143 -0
  84. data/spec/helpers/SpecHelper.js +10 -0
  85. data/spec/kojac_caching_spec.js +105 -0
  86. data/spec/kojac_mock_spec.js +230 -0
  87. data/spec/kojac_model_spec.js +126 -0
  88. data/spec/kojac_object_spec.js +171 -0
  89. data/spec/kojac_operations_spec.js +41 -0
  90. data/spec/mockjson/order_item.js +37 -0
  91. data/spec/mockjson/order_item__49.js +15 -0
  92. data/spec/mockjson/order_item__50.js +15 -0
  93. data/spec/mockjson/order_item__51.js +15 -0
  94. data/spec/mockjson/product.js +82 -0
  95. data/spec/mockjson/product__3.js +22 -0
  96. data/spec/model_ring_spec.rb +52 -0
  97. data/spec/operation_include_spec.js +77 -0
  98. data/spec/run.html +81 -0
  99. data/spec/spec.js +2 -0
  100. data/spec/support/jasmine.yml +86 -0
  101. metadata +380 -0
@@ -0,0 +1,2747 @@
1
+ // steal is a resource loader for JavaScript. It is broken into the following parts:
2
+ //
3
+ // - Helpers - basic utility methods used internally
4
+ // - AOP - aspect oriented code helpers
5
+ // - Deferred - a minimal deferred implementation
6
+ // - Uri - methods for dealing with urls
7
+ // - Api - steal's API
8
+ // - Module - an object that represents a resource that is loaded and run and has dependencies.
9
+ // - Type - a type systems used to load and run different types of resources
10
+ // - Packages - used to define packages
11
+ // - Extensions - makes steal pre-load a type based on an extension (ex: .coffee)
12
+ // - Mapping - configures steal to load resources in a different location
13
+ // - Startup - startup code
14
+ // - jQuery - code to make jQuery's readWait work
15
+ // - Error Handling - detect scripts failing to load
16
+ // - Has option - used to specify that one resources contains multiple other resources
17
+ // - Window Load - API for knowing when the window has loaded and all scripts have loaded
18
+ // - Interactive - Code for IE
19
+ // - Options -
20
+ (function (undefined) {
21
+
22
+ var requestFactory = function () {
23
+ return h.win.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
24
+ };
25
+
26
+ // ## Helpers ##
27
+ // The following are a list of helper methods used internally to steal
28
+ var h = {
29
+ // check that we have a document,
30
+ win: (function () {
31
+ return this
32
+ }).call(null),
33
+ // a jQuery-like $.each
34
+ each: function (o, cb) {
35
+ var i, len;
36
+
37
+ // weak array detection, but we only use this internally so don't
38
+ // pass it weird stuff
39
+ if (typeof o.length == 'number') {
40
+ for (i = 0, len = o.length; i < len; i++) {
41
+ cb.call(o[i], i, o[i], o)
42
+ }
43
+ } else {
44
+ for (i in o) {
45
+ if (o.hasOwnProperty(i)) {
46
+ cb.call(o[i], i, o[i], o)
47
+ }
48
+
49
+ }
50
+ }
51
+ return o;
52
+ },
53
+ // adds the item to the array only if it doesn't currently exist
54
+ uniquePush: function (arr, item) {
55
+ if (h.inArray(arr, item) === -1) {
56
+ return arr.push(item)
57
+ }
58
+ },
59
+ // if o is a string
60
+ isString: function (o) {
61
+ return typeof o == "string";
62
+ },
63
+ // if o is a function
64
+ isFn: function (o) {
65
+ return typeof o == "function";
66
+ },
67
+ // dummy function
68
+ noop: function () {},
69
+ endsInSlashRegex: /\/$/,
70
+ // creates an element
71
+ createElement: function (nodeName) {
72
+ return h.doc.createElement(nodeName)
73
+ },
74
+ // creates a script tag
75
+ scriptTag: function () {
76
+ var start = h.createElement("script");
77
+ start.type = "text/javascript";
78
+ return start;
79
+ },
80
+ // minify-able verstion of getElementsByTagName
81
+ getElementsByTagName: function (tag) {
82
+ return h.doc.getElementsByTagName(tag);
83
+ },
84
+ // A function that returns the head element
85
+ // creates and caches the lookup for faster
86
+ // performance.
87
+ head: function () {
88
+ var hd = h.getElementsByTagName("head")[0];
89
+ if (!hd) {
90
+ hd = h.createElement("head");
91
+ h.docEl.insertBefore(hd, h.docEl.firstChild);
92
+ }
93
+ // replace head so it runs fast next time.
94
+ h.head = function () {
95
+ return hd;
96
+ }
97
+ return hd;
98
+ },
99
+ // extends one object with another
100
+ extend: function (d, s) {
101
+ // only extend if we have something to extend
102
+ s && h.each(s, function (k) {
103
+ if (s.hasOwnProperty(k)) {
104
+ d[k] = s[k];
105
+ }
106
+ });
107
+ return d;
108
+ },
109
+ // makes an array of things, or a mapping of things
110
+ map: function (args, cb) {
111
+ var arr = [];
112
+ h.each(args, function (i, str) {
113
+ arr.push(cb ? (h.isString(cb) ? str[cb] : cb.call(str, str)) : str)
114
+ });
115
+ return arr;
116
+ },
117
+ // ## AOP ##
118
+ // Aspect oriented programming helper methods are used to
119
+ // weave in functionality into steal's API.
120
+ // calls `before` before `f` is called.
121
+ // steal.complete = before(steal.complete, f)
122
+ // `changeArgs=true` makes before return the same args
123
+ before: function (f, before, changeArgs) {
124
+ return changeArgs ?
125
+ function before_changeArgs() {
126
+ return f.apply(this, before.apply(this, arguments));
127
+ } : function before_args() {
128
+ before.apply(this, arguments);
129
+ return f.apply(this, arguments);
130
+ }
131
+ },
132
+ // returns a function that calls `after`
133
+ // after `f`
134
+ after: function (f, after, changeRet) {
135
+ return changeRet ?
136
+ function after_CRet() {
137
+ return after.apply(this, [f.apply(this, arguments)].concat(h.map(arguments)));
138
+ } : function after_Ret() {
139
+ var ret = f.apply(this, arguments);
140
+ after.apply(this, arguments);
141
+ return ret;
142
+ }
143
+ },
144
+ /**
145
+ * Performs an XHR request
146
+ * @param {Object} options
147
+ * @param {Function} success
148
+ * @param {Function} error
149
+ */
150
+ request: function (options, success, error) {
151
+ var request = new requestFactory(),
152
+ contentType = (options.contentType || "application/x-www-form-urlencoded; charset=utf-8"),
153
+ clean = function () {
154
+ request = check = clean = null;
155
+ },
156
+ check = function () {
157
+ var status;
158
+ if (request && request.readyState === 4) {
159
+ status = request.status;
160
+ if (status === 500 || status === 404 || status === 2 || request.status < 0 || (!status && request.responseText === "")) {
161
+ error && error(request.status);
162
+ } else {
163
+ success(request.responseText);
164
+ }
165
+ clean();
166
+ }
167
+ };
168
+ request.open("GET", options.src + '', !(options.async === false));
169
+ request.setRequestHeader("Content-type", contentType);
170
+ if (request.overrideMimeType) {
171
+ request.overrideMimeType(contentType);
172
+ }
173
+
174
+ request.onreadystatechange = check;
175
+ try {
176
+ request.send(null);
177
+ }
178
+ catch (e) {
179
+ if (clean) {
180
+ console.error(e);
181
+ error && error();
182
+ clean();
183
+ }
184
+ }
185
+ },
186
+ matchesId: function (loc, id) {
187
+ if (loc === "*") {
188
+ return true;
189
+ } else if (id.indexOf(loc) === 0) {
190
+ return true;
191
+ }
192
+ },
193
+ // are we in production
194
+ stealCheck: /steal\.(production\.)?js.*/,
195
+ // get script that loaded steal
196
+ getStealScriptSrc: function () {
197
+ if (!h.doc) {
198
+ return;
199
+ }
200
+ var scripts = h.getElementsByTagName("script"),
201
+ script;
202
+
203
+ // find the steal script and setup initial paths.
204
+ h.each(scripts, function (i, s) {
205
+ if (h.stealCheck.test(s.src)) {
206
+ script = s;
207
+ }
208
+ });
209
+ return script;
210
+ },
211
+ inArray: function (arr, val) {
212
+ for (var i = 0; i < arr.length; i++) {
213
+ if (arr[i] === val) {
214
+ return i;
215
+ }
216
+ }
217
+ return -1;
218
+ },
219
+ addEvent: function (elem, type, fn) {
220
+ if (elem.addEventListener) {
221
+ elem.addEventListener(type, fn, false);
222
+ } else if (elem.attachEvent) {
223
+ elem.attachEvent("on" + type, fn);
224
+ } else {
225
+ fn();
226
+ }
227
+ },
228
+ useIEShim: false
229
+ }
230
+
231
+ h.doc = h.win.document;
232
+ h.docEl = h.doc && h.doc.documentElement;
233
+
234
+ h.support = {
235
+ // does onerror work in script tags?
236
+ error: h.doc && (function () {
237
+ var script = h.scriptTag();
238
+ script.onerror = h.noop;
239
+ return h.isFn(script.onerror) || "onerror" in script;
240
+ })(),
241
+ // If scripts support interactive ready state.
242
+ // This is tested later.
243
+ interactive: false,
244
+ // use attachEvent for event listening (IE)
245
+ attachEvent: h.doc && h.scriptTag().attachEvent
246
+ }
247
+
248
+ // steal's deferred library. It is used through steal
249
+ // to support jQuery like API for file loading.
250
+ var Deferred = function (func) {
251
+ if (!(this instanceof Deferred)) return new Deferred();
252
+ // arrays for `done` and `fail` callbacks
253
+ this.doneFuncs = [];
254
+ this.failFuncs = [];
255
+
256
+ this.resultArgs = null;
257
+ this.status = "";
258
+
259
+ // check for option function: call it with this as context and as first
260
+ // parameter, as specified in jQuery api
261
+ func && func.call(this, this);
262
+ }
263
+
264
+ Deferred.when = function () {
265
+ var args = h.map(arguments);
266
+ if (args.length < 2) {
267
+ var obj = args[0];
268
+ if (obj && (h.isFn(obj.isResolved) && h.isFn(obj.isRejected))) {
269
+ return obj;
270
+ } else {
271
+ return Deferred().resolve(obj);
272
+ }
273
+ } else {
274
+
275
+ var df = Deferred(),
276
+ done = 0,
277
+ // resolve params: params of each resolve, we need to track down
278
+ // them to be able to pass them in the correct order if the master
279
+ // needs to be resolved
280
+ rp = [];
281
+
282
+ h.each(args, function (j, arg) {
283
+ arg.done(function () {
284
+ rp[j] = (arguments.length < 2) ? arguments[0] : arguments;
285
+ if (++done == args.length) {
286
+ df.resolve.apply(df, rp);
287
+ }
288
+ }).fail(function () {
289
+ df.reject(arguments);
290
+ });
291
+ });
292
+
293
+ return df;
294
+
295
+ }
296
+ }
297
+ // call resolve functions
298
+ var resolveFunc = function (type, status) {
299
+ return function (context) {
300
+ var args = this.resultArgs = (arguments.length > 1) ? arguments[1] : [];
301
+ return this.exec(context, this[type], args, status);
302
+ }
303
+ },
304
+
305
+ doneFunc = function (type, status) {
306
+ return function () {
307
+ var self = this;
308
+ h.each(arguments, function (i, v, args) {
309
+ if (!v) return;
310
+ if (v.constructor === Array) {
311
+ args.callee.apply(self, v)
312
+ } else {
313
+ // immediately call the function if the deferred has been resolved
314
+ if (self.status === status) v.apply(this, self.resultArgs || []);
315
+
316
+ self[type].push(v);
317
+ }
318
+ });
319
+ return this;
320
+ }
321
+ };
322
+
323
+ h.extend(Deferred.prototype, {
324
+ resolveWith: resolveFunc("doneFuncs", "rs"),
325
+ rejectWith: resolveFunc("failFuncs", "rj"),
326
+ done: doneFunc("doneFuncs", "rs"),
327
+ fail: doneFunc("failFuncs", "rj"),
328
+ always: function () {
329
+ var args = h.map(arguments);
330
+ if (args.length && args[0]) this.done(args[0]).fail(args[0]);
331
+
332
+ return this;
333
+ },
334
+ then: function () {
335
+ var args = h.map(arguments);
336
+ // fail function(s)
337
+ if (args.length > 1 && args[1]) this.fail(args[1]);
338
+
339
+ // done function(s)
340
+ if (args.length && args[0]) this.done(args[0]);
341
+
342
+ return this;
343
+ },
344
+ isResolved: function () {
345
+ return this.status === "rs";
346
+ },
347
+ isRejected: function () {
348
+ return this.status === "rj";
349
+ },
350
+ reject: function () {
351
+ return this.rejectWith(this, arguments);
352
+ },
353
+ resolve: function () {
354
+ return this.resolveWith(this, arguments);
355
+ },
356
+ exec: function (context, dst, args, st) {
357
+ if (this.status !== "") return this;
358
+
359
+ this.status = st;
360
+
361
+ h.each(dst, function (i, d) {
362
+ d.apply(context, args);
363
+ });
364
+
365
+ return this;
366
+ }
367
+ });
368
+ // ## HELPER METHODS FOR DEFERREDS
369
+ // Used to call a method on an object or resolve a
370
+ // deferred on it when a group of deferreds is resolved.
371
+ //
372
+ // whenEach(resources,"complete",resource,"execute")
373
+ var whenEach = function (arr, func, obj, func2) {
374
+
375
+ var deferreds = h.map(arr, func)
376
+ return Deferred.when.apply(Deferred, deferreds).then(function () {
377
+ if (h.isFn(obj[func2])) {
378
+ obj[func2]()
379
+ } else {
380
+ obj[func2].resolve();
381
+ }
382
+
383
+ });
384
+ };
385
+
386
+ // ## URI ##
387
+ /**
388
+ * @class steal.URI
389
+ * A URL / URI helper for getting information from a URL.
390
+ *
391
+ * var uri = URI( "http://stealjs.com/index.html" )
392
+ * uri.path //-> "/index.html"
393
+ */
394
+
395
+ var URI = function (url) {
396
+ if (this.constructor !== URI) {
397
+ return new URI(url);
398
+ }
399
+ h.extend(this, URI.parse("" + url));
400
+ };
401
+ // the current url (relative to root, which is relative from page)
402
+ // normalize joins from this
403
+ //
404
+ h.extend(URI, {
405
+ // parses a URI into it's basic parts
406
+ parse: function (string) {
407
+ var uriParts = string.split("?"),
408
+ uri = uriParts.shift(),
409
+ queryParts = uriParts.join("").split("#"),
410
+ protoParts = uri.split("://"),
411
+ parts = {
412
+ query: queryParts.shift(),
413
+ fragment: queryParts.join("#")
414
+ },
415
+ pathParts;
416
+
417
+ if (protoParts[1]) {
418
+ parts.protocol = protoParts.shift();
419
+ pathParts = protoParts[0].split("/");
420
+ parts.host = pathParts.shift();
421
+ parts.path = "/" + pathParts.join("/");
422
+ } else {
423
+ parts.path = protoParts[0];
424
+ }
425
+ return parts;
426
+ }
427
+ });
428
+
429
+ /**
430
+ * @attribute page
431
+ * The location of the page as a URI.
432
+ *
433
+ * st.URI.page.protocol //-> "http"
434
+ */
435
+ URI.page = URI(h.win.location && location.href);
436
+ /**
437
+ * @attribute cur
438
+ *
439
+ * The current working directory / path. Anything
440
+ * loaded relative will be loaded relative to this.
441
+ */
442
+ URI.cur = URI();
443
+
444
+ /**
445
+ * @prototype
446
+ */
447
+ h.extend(URI.prototype, {
448
+ dir: function () {
449
+ var parts = this.path.split("/");
450
+ parts.pop();
451
+ return URI(this.domain() + parts.join("/"))
452
+ },
453
+ filename: function () {
454
+ return this.path.split("/").pop();
455
+ },
456
+ ext: function () {
457
+ var filename = this.filename();
458
+ return (filename.indexOf(".") > -1) ? filename.split(".").pop() : "";
459
+ },
460
+ domain: function () {
461
+ return this.protocol ? this.protocol + "://" + this.host : "";
462
+ },
463
+ isCrossDomain: function (uri) {
464
+ uri = URI(uri || h.win.location.href);
465
+ var domain = this.domain(),
466
+ uriDomain = uri.domain()
467
+ return (domain && uriDomain && domain != uriDomain) || this.protocol === "file" || (domain && !uriDomain);
468
+ },
469
+ isRelativeToDomain: function () {
470
+ return !this.path.indexOf("/");
471
+ },
472
+ hash: function () {
473
+ return this.fragment ? "#" + this.fragment : ""
474
+ },
475
+ search: function () {
476
+ return this.query ? "?" + this.query : ""
477
+ },
478
+ // like join, but returns a string
479
+ add: function (uri) {
480
+ return this.join(uri) + '';
481
+ },
482
+ join: function (uri, min) {
483
+ uri = URI(uri);
484
+ if (uri.isCrossDomain(this)) {
485
+ return uri;
486
+ }
487
+ if (uri.isRelativeToDomain()) {
488
+ return URI(this.domain() + uri)
489
+ }
490
+ // at this point we either
491
+ // - have the same domain
492
+ // - this has a domain but uri does not
493
+ // - both don't have domains
494
+ var left = this.path ? this.path.split("/") : [],
495
+ right = uri.path.split("/"),
496
+ part = right[0];
497
+ //if we are joining from a folder like cookbook/, remove the last empty part
498
+ if (this.path.match(/\/$/)) {
499
+ left.pop();
500
+ }
501
+ while (part == ".." && left.length) {
502
+ // if we've emptied out, folders, just break
503
+ // leaving any additional ../s
504
+ if (!left.pop()) {
505
+ break;
506
+ }
507
+ right.shift();
508
+
509
+ part = right[0];
510
+ }
511
+ return h.extend(URI(this.domain() + left.concat(right).join("/")), {
512
+ query: uri.query
513
+ });
514
+ },
515
+ /**
516
+ * For a given path, a given working directory, and file location, update the
517
+ * path so it points to a location relative to steal's root.
518
+ *
519
+ * We want everything relative to steal's root so the same app can work in
520
+ * multiple pages.
521
+ *
522
+ * ./files/a.js = steals a.js
523
+ * ./files/a = a/a.js
524
+ * files/a = //files/a/a.js
525
+ * files/a.js = loads //files/a.js
526
+ */
527
+ normalize: function (cur) {
528
+ cur = cur ? cur.dir() : URI.cur.dir();
529
+ var path = this.path,
530
+ res = URI(path);
531
+ //if path is rooted from steal's root (DEPRECATED)
532
+ if (!path.indexOf("//")) {
533
+ res = URI(path.substr(2));
534
+ } else if (!path.indexOf("./")) { // should be relative
535
+ res = cur.join(path.substr(2));
536
+ }
537
+ // only if we start with ./ or have a /foo should we join from cur
538
+ else if (this.isRelative()) {
539
+ res = cur.join(this.domain() + path)
540
+ }
541
+ res.query = this.query;
542
+ return res;
543
+ },
544
+ isRelative: function () {
545
+ return /^[\.|\/]/.test(this.path)
546
+ },
547
+ // a min path from 2 urls that share the same domain
548
+ pathTo: function (uri) {
549
+ uri = URI(uri);
550
+ var uriParts = uri.path.split("/"),
551
+ thisParts = this.path.split("/"),
552
+ result = [];
553
+ while (uriParts.length && thisParts.length && uriParts[0] == thisParts[0]) {
554
+ uriParts.shift();
555
+ thisParts.shift();
556
+ }
557
+ h.each(thisParts, function () {
558
+ result.push("../")
559
+ })
560
+ return URI(result.join("") + uriParts.join("/"));
561
+ },
562
+ mapJoin: function (url) {
563
+ return this.join(URI(url).insertMapping());
564
+ },
565
+ // helper to go from jquery to jquery/jquery.js
566
+ addJS: function () {
567
+ var ext = this.ext();
568
+ if (!ext) {
569
+ // if first character of path is a . or /, just load this file
570
+ if (!this.isRelative()) {
571
+ this.path += "/" + this.filename();
572
+ }
573
+ this.path += ".js"
574
+ }
575
+ return this;
576
+ }
577
+ });
578
+ // This can't be added to the prototype using extend because
579
+ // then for some reason IE < 9 won't recognize it.
580
+ URI.prototype.toString = function () {
581
+ return this.domain() + this.path + this.search() + this.hash();
582
+ };
583
+ // =============================== MAPPING ===============================
584
+ URI.prototype.insertMapping = function () {
585
+ // go through mappings
586
+ var orig = "" + this,
587
+ key, value;
588
+ for (key in steal.mappings) {
589
+ value = steal.mappings[key]
590
+ if (value.test.test(orig)) {
591
+ return orig.replace(key, value.path);
592
+ }
593
+ }
594
+ return URI(orig);
595
+ };
596
+
597
+ // --- END URI
598
+ /**
599
+ * `new ConfigManager(config)` creates configuration profile for the steal context.
600
+ * It keeps all config parameters in the instance which allows steal to clone it's
601
+ * context.
602
+ *
603
+ * config.stealConfig is tipically set up in __stealconfig.js__. The available options are:
604
+ *
605
+ * - map - map an id to another id
606
+ * - paths - maps an id to a file
607
+ * - root - the path to the "root" folder
608
+ * - env - `"development"` or `"production"`
609
+ * - types - processor rules for various types
610
+ * - ext - behavior rules for extensions
611
+ * - urlArgs - extra queryString arguments
612
+ * - startFile - the file to load
613
+ *
614
+ * ## map
615
+ *
616
+ * Maps an id to another id with a certain scope of other ids. This can be
617
+ * used to use different modules within the same id or map ids to another id.
618
+ * Example:
619
+ *
620
+ * st.config({
621
+ * map: {
622
+ * "*": {
623
+ * "jquery/jquery.js": "jquery"
624
+ * },
625
+ * "compontent1":{
626
+ * "underscore" : "underscore1.2"
627
+ * },
628
+ * "component2":{
629
+ * "underscore" : "underscore1.1"
630
+ * }
631
+ * }
632
+ * })
633
+ *
634
+ * ## paths
635
+ *
636
+ * Maps an id or matching ids to a url. Each mapping is specified
637
+ * by an id or part of the id to match and what that
638
+ * part should be replaced with.
639
+ *
640
+ * st.config({
641
+ * paths: {
642
+ * // maps everything in a jquery folder like: `jquery/controller`
643
+ * // to http://cdn.com/jquery/controller/controller.com
644
+ * "jquery/" : "http://cdn.com/jquery/"
645
+ *
646
+ * // if path does not end with /, it matches only that id
647
+ * "jquery" : "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"
648
+ * }
649
+ * })
650
+ *
651
+ * ## root
652
+ * ## env
653
+ *
654
+ * If production, does not load "ignored" scripts and loads production script. If development gives more warnings / errors.
655
+ *
656
+ * ## types
657
+ *
658
+ * The types option can specify how a type is loaded.
659
+ *
660
+ * ## ext
661
+ *
662
+ * The ext option specifies the default behavior if file is loaded with the
663
+ * specified extension. For a given extension, a file that configures the type can be given or
664
+ * an existing type. For example, for ejs:
665
+ *
666
+ * st.config({ext: {"ejs": "can/view/ejs/ejs.js"}})
667
+ *
668
+ * This tells steal to make sure `can/view/ejs/ejs.js` is executed before any file with
669
+ * ".ejs" is executed.
670
+ *
671
+ *
672
+ **/
673
+
674
+
675
+
676
+ var ConfigManager = function (options) {
677
+ this.stealConfig = {};
678
+ this.callbacks = [];
679
+ this.attr(ConfigManager.defaults);
680
+ this.attr(options)
681
+ }
682
+
683
+ h.extend(ConfigManager.prototype, {
684
+ // get or set config.stealConfig attributes
685
+ attr: function (config) {
686
+ if (!config) { // called as a getter, so just return
687
+ return this.stealConfig;
688
+ }
689
+ if (arguments.length === 1 && typeof config === "string") { // called as a getter, so just return
690
+ return this.stealConfig && this.stealConfig[config];
691
+ }
692
+ this.stealConfig = this.stealConfig || {};
693
+ for (var prop in config) {
694
+ var value = config[prop];
695
+ // if it's a special function
696
+ this[prop] ?
697
+ // run it
698
+ this[prop](value) :
699
+ // otherwise set or extend
700
+ (typeof value == "object" && this.stealConfig[prop] ?
701
+ // extend
702
+ h.extend(this.stealConfig[prop], value) :
703
+ // set
704
+ this.stealConfig[prop] = value);
705
+
706
+ }
707
+
708
+ for (var i = 0; i < this.callbacks.length; i++) {
709
+ this.callbacks[i](this.stealConfig)
710
+ }
711
+
712
+ return this;
713
+ },
714
+
715
+ // add callbacks which are called after config is changed
716
+ on: function (cb) {
717
+ this.callbacks.push(cb)
718
+ },
719
+
720
+ // get the current start file
721
+ startFile: function (startFile) {
722
+ // make sure startFile and production look right
723
+ this.stealConfig.startFile = "" + URI(startFile).addJS()
724
+ if (!this.stealConfig.production) {
725
+ this.stealConfig.production = URI(this.stealConfig.startFile).dir() + "/production.js";
726
+ }
727
+ },
728
+
729
+ /**
730
+ *
731
+ * Read or define the path relative URI's should be referenced from.
732
+ *
733
+ * window.location //-> "http://foo.com/site/index.html"
734
+ * st.URI.root("http://foo.com/app/files/")
735
+ * st.root.toString() //-> "../../app/files/"
736
+ */
737
+ root: function (relativeURI) {
738
+ if (relativeURI !== undefined) {
739
+ var root = URI(relativeURI);
740
+
741
+ // the current folder-location of the page http://foo.com/bar/card
742
+ var cleaned = URI.page,
743
+ // the absolute location or root
744
+ loc = cleaned.join(relativeURI);
745
+
746
+ // cur now points to the 'root' location, but from the page
747
+ URI.cur = loc.pathTo(cleaned)
748
+ this.stealConfig.root = root;
749
+ return this;
750
+ }
751
+ this.stealConfig.root = root || URI("");
752
+ },
753
+ //var stealConfig = configs[configContext];
754
+ cloneContext: function () {
755
+ return new ConfigManager(h.extend({}, this.stealConfig));
756
+ }
757
+ })
758
+ // ConfigManager's defaults
759
+ ConfigManager.defaults = {
760
+ types: {},
761
+ ext: {},
762
+ env: "development",
763
+ loadProduction: true,
764
+ logLevel: 0,
765
+ root: "",
766
+ amd: false
767
+ };
768
+
769
+ // ### TYPES ##
770
+ /**
771
+ * Registers a type. You define the type of the file, the basic type it
772
+ * converts to, and a conversion function where you convert the original file
773
+ * to JS or CSS. This is modeled after the
774
+ * [http://api.jquery.com/extending-ajax/#Converters AJAX converters] in jQuery.
775
+ *
776
+ * Types are designed to make it simple to switch between steal's development
777
+ * and production modes. In development mode, the types are converted
778
+ * in the browser to allow devs to see changes as they work. When the app is
779
+ * built, these converter functions are run by the build process,
780
+ * and the processed text is inserted into the production script, optimized for
781
+ * performance.
782
+ *
783
+ * Here's an example converting files of type .foo to JavaScript. Foo is a
784
+ * fake language that saves global variables defined like. A .foo file might
785
+ * look like this:
786
+ *
787
+ * REQUIRED FOO
788
+ *
789
+ * To define this type, you'd call steal.type like this:
790
+ *
791
+ * steal.type("foo js", function(options, original, success, error){
792
+ * var parts = options.text.split(" ")
793
+ * options.text = parts[0]+"='"+parts[1]+"'";
794
+ * success();
795
+ * });
796
+ *
797
+ * The method we provide is called with the text of .foo files in options.text.
798
+ * We parse the file, create JavaScript and put it in options.text. Couldn't
799
+ * be simpler.
800
+ *
801
+ * Here's an example,
802
+ * converting [http://jashkenas.github.com/coffee-script/ coffeescript]
803
+ * to JavaScript:
804
+ *
805
+ * steal.type("coffee js", function(options, original, success, error){
806
+ * options.text = CoffeeScript.compile(options.text);
807
+ * success();
808
+ * });
809
+ *
810
+ * In this example, any time steal encounters a file with extension .coffee,
811
+ * it will call the given converter method. CoffeeScript.compile takes the
812
+ * text of the file, converts it from coffeescript to javascript, and saves
813
+ * the JavaScript text in options.text.
814
+ *
815
+ * Similarly, languages on top of CSS, like [http://lesscss.org/ LESS], can
816
+ * be converted to CSS:
817
+ *
818
+ * steal.type("less css", function(options, original, success, error){
819
+ * new (less.Parser)({
820
+ * optimization: less.optimization,
821
+ * paths: []
822
+ * }).parse(options.text, function (e, root) {
823
+ * options.text = root.toCSS();
824
+ * success();
825
+ * });
826
+ * });
827
+ *
828
+ * This simple type system could be used to convert any file type to be used
829
+ * in your JavaScript app. For example, [http://fdik.org/yml/ yml] could be
830
+ * used for configuration. jQueryMX uses steal.type to support JS templates,
831
+ * such as EJS, TMPL, and others.
832
+ *
833
+ * @param {String} type A string that defines the new type being defined and
834
+ * the type being converted to, separated by a space, like "coffee js".
835
+ *
836
+ * There can be more than two steps used in conversion, such as "ejs view js".
837
+ * This will define a method that converts .ejs files to .view files. There
838
+ * should be another converter for "view js" that makes this final conversion
839
+ * to JS.
840
+ *
841
+ * @param {Function} cb( options, original, success, error ) a callback
842
+ * function that converts the new file type to a basic type. This method
843
+ * needs to do two things: 1) save the text of the converted file in
844
+ * options.text and 2) call success() when the conversion is done (it can work
845
+ * asynchronously).
846
+ *
847
+ * - __options__ - the steal options for this file, including path information
848
+ * - __original__ - the original argument passed to steal, which might be a
849
+ * path or a function
850
+ * - __success__ - a method to call when the file is converted and processed
851
+ * successfully
852
+ * - __error__ - a method called if the conversion fails or the file doesn't
853
+ * exist
854
+ */
855
+ ConfigManager.prototype.types = function (types) {
856
+ var configTypes = this.stealConfig.types || (this.stealConfig.types = {});
857
+ h.each(types, function (type, cb) {
858
+ var typs = type.split(" ");
859
+ configTypes[typs.shift()] = {
860
+ require: cb,
861
+ convert: typs
862
+ };
863
+ });
864
+ };
865
+ ConfigManager.prototype.require = function (options, success, error) {
866
+ // add the src option
867
+ // but it is not added to functions
868
+ if (options.idToUri) {
869
+ var old = options.src;
870
+ options.src = this.addSuffix(options.idToUri(options.id));
871
+ }
872
+
873
+ // get the type
874
+ var type = this.attr().types[options.type],
875
+ converters;
876
+
877
+ // if this has converters, make it get the text first, then pass it to the type
878
+ if (type.convert.length) {
879
+ converters = type.convert.slice(0);
880
+ converters.unshift("text", options.type)
881
+ } else {
882
+ converters = [options.type]
883
+ }
884
+ require(options, converters, success, error, this)
885
+ }
886
+ ConfigManager.prototype.addSuffix = function (str) {
887
+ var suffix = this.attr('suffix')
888
+ if (suffix) {
889
+ str = (str + '').indexOf('?') > -1 ? str + "&" + suffix : str + "?" + suffix;
890
+ }
891
+ return str;
892
+ }
893
+
894
+ // Require function. It will be called recursevly until all
895
+ // converters are ran. After that `success` callback is ran.
896
+ // For instance if we're loading the .less file it will first
897
+ // run the `text` converter, then `less` converter and finally
898
+ // the `fn` converter.
899
+
900
+
901
+ function require(options, converters, success, error, config) {
902
+ var t = converters[0]
903
+ var type = config.attr('types')[converters.shift()];
904
+
905
+ type.require(options, function require_continue_check() {
906
+ // if we have more types to convert
907
+ if (converters.length) {
908
+ require(options, converters, success, error, config)
909
+ } else { // otherwise this is the final
910
+ success.apply(this, arguments);
911
+ }
912
+ }, error, config)
913
+ };
914
+
915
+
916
+
917
+
918
+ // =============================== TYPES ===============================
919
+ // a clean up script that prevents memory leaks and removes the
920
+ // script
921
+ var cleanUp = function (elem) {
922
+ elem.onreadystatechange = elem.onload = elem.onerror = null;
923
+
924
+ setTimeout(function () {
925
+ h.head().removeChild(elem);
926
+ }, 1);
927
+ },
928
+ // the last inserted script, needed for IE
929
+ lastInserted,
930
+ // if the state is done
931
+ stateCheck = /^loade|c|u/;
932
+
933
+
934
+ var cssCount = 0,
935
+ createSheet = h.doc && h.doc.createStyleSheet,
936
+ lastSheet, lastSheetOptions;
937
+
938
+ // Apply all the basic types
939
+ ConfigManager.defaults.types = {
940
+ "js": function (options, success, error) {
941
+ // create a script tag
942
+ var script = h.scriptTag(),
943
+ callback = function () {
944
+ if (!script.readyState || stateCheck.test(script.readyState)) {
945
+ cleanUp(script);
946
+ success();
947
+ }
948
+ },
949
+ errorTimeout;
950
+ // if we have text, just set and insert text
951
+ if (options.text) {
952
+ // insert
953
+ script.text = options.text;
954
+
955
+ } else {
956
+ var src = options.src; //st.idToUri( options.id );
957
+ // If we're in IE older than IE9 we need to use
958
+ // onreadystatechange to determine when javascript file
959
+ // is loaded. Unfortunately this makes it impossible to
960
+ // call teh error callback, because it will return
961
+ // loaded or completed for the script even if it
962
+ // encountered the 404 error
963
+ if (h.useIEShim) {
964
+ script.onreadystatechange = function () {
965
+ if (stateCheck.test(script.readyState)) {
966
+ success();
967
+ }
968
+ }
969
+ } else {
970
+ script.onload = callback;
971
+ // error handling doesn't work on firefox on the filesystem
972
+ if (h.support.error && error && src.protocol !== "file") {
973
+ script.onerror = error;
974
+ }
975
+ }
976
+
977
+ // listen to loaded
978
+ script.src = "" + src;
979
+ //script.src = options.src = addSuffix(options.src);
980
+ //script.async = false;
981
+ script.onSuccess = success;
982
+ }
983
+
984
+ // insert the script
985
+ lastInserted = script;
986
+ h.head().insertBefore(script, h.head().firstChild);
987
+
988
+ // if text, just call success right away, and clean up
989
+ if (options.text) {
990
+ callback();
991
+ }
992
+ },
993
+ "fn": function (options, success) {
994
+ var ret;
995
+ if (!options.skipCallbacks) {
996
+ ret = options.fn();
997
+ }
998
+ success(ret);
999
+ },
1000
+ // request text
1001
+ "text": function (options, success, error) {
1002
+ h.request(options, function (text) {
1003
+ options.text = text;
1004
+ success(text);
1005
+ }, error)
1006
+ },
1007
+ // loads css files and works around IE's 31 sheet limit
1008
+ "css": function (options, success, error) {
1009
+ if (options.text) { // less
1010
+ var css = h.createElement("style");
1011
+ css.type = "text/css";
1012
+ if (css.styleSheet) { // IE
1013
+ css.styleSheet.cssText = options.text;
1014
+ } else {
1015
+ (function (node) {
1016
+ if (css.childNodes.length) {
1017
+ if (css.firstChild.nodeValue !== node.nodeValue) {
1018
+ css.replaceChild(node, css.firstChild);
1019
+ }
1020
+ } else {
1021
+ css.appendChild(node);
1022
+ }
1023
+ })(h.doc.createTextNode(options.text));
1024
+ }
1025
+ h.head().appendChild(css);
1026
+ } else {
1027
+ if (createSheet) {
1028
+ // IE has a 31 sheet and 31 import per sheet limit
1029
+ if (!cssCount++) {
1030
+ lastSheet = h.doc.createStyleSheet(options.src);
1031
+ lastSheetOptions = options;
1032
+ } else {
1033
+ var relative = "" + URI(URI(lastSheetOptions.src).dir()).pathTo(options.src);
1034
+ lastSheet.addImport(relative);
1035
+ if (cssCount == 30) {
1036
+ cssCount = 0;
1037
+ }
1038
+ }
1039
+ success();
1040
+ return;
1041
+ }
1042
+
1043
+ options = options || {};
1044
+ var link = h.createElement("link");
1045
+ link.rel = options.rel || "stylesheet";
1046
+ link.href = options.src;
1047
+ link.type = "text/css";
1048
+ h.head().appendChild(link);
1049
+ }
1050
+
1051
+ success();
1052
+ }
1053
+ };
1054
+
1055
+
1056
+ var moduleManager = function (steal, stealModules, interactives, config) {
1057
+
1058
+ // ============ MODULE ================
1059
+ // a map of modules by moduleID
1060
+ var modules = {},
1061
+ id = 0;
1062
+ // this is for methods on a 'steal instance'. A file can be in one of a few states:
1063
+ // created - the steal instance is created, but we haven't started loading it yet
1064
+ // this happens when thens are used
1065
+ // loading - (loading=true) By calling load, this will tell steal to load a file
1066
+ // loaded - (isLoaded=true) The file has been run, but its dependency files have been completed
1067
+ // complete - all of this files dependencies have loaded and completed.
1068
+ // A Module is almost anything. It is different from a module
1069
+ // as it doesn't represent some unit of functionality, rather
1070
+ // it represents a unit that can have other units "within" it
1071
+ // as dependencies. A module can:
1072
+ //
1073
+ // - load - load the module to the client so it is available, but don't run it yet
1074
+ // - run - run the code for the module
1075
+ // - executed - the code has been run for the module, but all
1076
+ // dependencies for that module might not have finished
1077
+ // - completed - all modules within the module have completed
1078
+ //
1079
+ // __options__
1080
+ // `options` can be a string, function, or object.
1081
+ //
1082
+ // __properties__
1083
+ //
1084
+ // - options - has a number of properties
1085
+ // - src - a URI to this module that can be loaded from the current page
1086
+ // - rootSrc - a URI to this module relative to the current root URI.
1087
+ // - type - the type of module: "fn", "js", "css", etc
1088
+ // - needs - other modules that must be loaded prior to this module
1089
+ // - fn - a callback function to run when executed
1090
+ // - unique - false if this module should be loaded each time
1091
+ // - waits - this module should wait until all prior scripts have completed before running
1092
+ // - loaded - a deferred indicating if this module has been loaded to the client
1093
+ // - run - a deferred indicating if the the code for this module run
1094
+ // - completed - a deferred indicating if all of this modules dependencies have
1095
+ // completed
1096
+ // - dependencies - an array of dependencies
1097
+ var Module = function (options) {
1098
+ // an array for dependencies, this is the steal calls this module makes
1099
+ this.dependencies = [];
1100
+
1101
+ // an array of implicit dependencies this steal needs
1102
+ this.needsDependencies = [];
1103
+
1104
+ // id for debugging
1105
+ this.id = (++id);
1106
+ // the original options
1107
+ this.orig = options;
1108
+ // the parent steal's id
1109
+ this.curId = steal.cur && steal.cur.options.id;
1110
+
1111
+ this.setOptions(options);
1112
+ // create the deferreds used to manage state
1113
+ this.loaded = Deferred();
1114
+ this.run = Deferred();
1115
+ this.completed = Deferred();
1116
+ };
1117
+
1118
+ Module.pending = [];
1119
+ // `Module.make` is used to either create
1120
+ // a new module, or return an existing
1121
+ // module that matches the options.
1122
+ Module.make = function (options) {
1123
+ // create the temporary reasource
1124
+ var module = new Module(options),
1125
+ // use `rootSrc` as the definitive ID
1126
+ id = module.options.id;
1127
+
1128
+ // assuming this module should not be created again.
1129
+ if (module.unique && id) {
1130
+
1131
+ // Check if we already have a module for this rootSrc
1132
+ // Also check with a .js ending because we defer 'type'
1133
+ // determination until later
1134
+ if (!modules[id] && !modules[id + ".js"]) {
1135
+ // If we haven't loaded, cache the module
1136
+ modules[id] = module;
1137
+ } else {
1138
+
1139
+ // Otherwise get the cached module
1140
+ existingModule = modules[id];
1141
+ // If options were passed, copy new properties over.
1142
+ // Don't copy src, etc because those have already
1143
+ // been changed to be the right values;
1144
+ if (!h.isString(options)) {
1145
+ // extend everything other than id
1146
+ for (var prop in options) {
1147
+ if (prop !== "id") {
1148
+ existingModule.options[prop] = options[prop];
1149
+ }
1150
+ }
1151
+ }
1152
+ return existingModule;
1153
+ }
1154
+ }
1155
+
1156
+ return module;
1157
+ };
1158
+
1159
+ // updates the paths of things ...
1160
+ // use stealModules b/c they are more fuzzy
1161
+ // a module's id stays the same, but a path might change
1162
+ //
1163
+ h.extend(Module.prototype, {
1164
+ setOptions: function (options) {
1165
+ var prevOptions = this.options;
1166
+ // if we have no options, we are the global Module that
1167
+ // contains all other modules.
1168
+ if (!options) { //global init cur ...
1169
+ this.options = {};
1170
+ this.waits = false;
1171
+ }
1172
+ //handle callback functions
1173
+ else if (h.isFn(options)) {
1174
+ var uri = URI.cur,
1175
+ self = this,
1176
+ cur = steal.cur;
1177
+ this.options = {
1178
+ fn: function () {
1179
+
1180
+ // Set the URI if there are steals
1181
+ // within the callback.
1182
+ URI.cur = uri;
1183
+
1184
+ // we should get the current "module"
1185
+ // check it's listed dependencies and see
1186
+ // if they have a value
1187
+ var args = [],
1188
+ found = false,
1189
+ dep, value;
1190
+ // iterate backwards through dependencies
1191
+ for (var i = cur.dependencies.length; i >= 0; i--) {
1192
+ dep = cur.dependencies[i];
1193
+
1194
+ if (found) {
1195
+ if (dep === null) {
1196
+ // //alert("YES")
1197
+ break;
1198
+ }
1199
+ // We need to access the stored stealModules in this order
1200
+ // - calculated id
1201
+ // - original name
1202
+ // - dependency return value otherwise
1203
+ value = stealModules[dep.options.id] || stealModules[dep.orig] || dep.value;
1204
+ args.unshift(value);
1205
+
1206
+ // what does this do?
1207
+ }
1208
+
1209
+ if (dep === self) {
1210
+ found = true;
1211
+ }
1212
+ }
1213
+
1214
+
1215
+
1216
+ var ret = options.apply(cur, args);
1217
+
1218
+ // if this returns a value, we should register it as a module ...
1219
+ if (ret) {
1220
+ // register this module ....
1221
+ cur.value = ret;
1222
+ }
1223
+ return ret;
1224
+ },
1225
+ id: uri,
1226
+ type: "fn"
1227
+ }
1228
+ // this has nothing to do with 'loading' options
1229
+ this.waits = true;
1230
+ this.unique = false;
1231
+ } else {
1232
+ // save the original options
1233
+ this.options = steal.makeOptions(h.extend({}, options), this.curId);
1234
+
1235
+ this.waits = this.options.waits || false;
1236
+ this.unique = true;
1237
+ }
1238
+ // if there are other options we haven't already set, reuse the old ones
1239
+ for (opt in prevOptions) {
1240
+ if (!this.options[opt]) {
1241
+ this.options[opt] = prevOptions[opt];
1242
+ }
1243
+ }
1244
+ if (this.options.id) {
1245
+ this.options.abort = false;
1246
+ }
1247
+ },
1248
+
1249
+ // Calling complete indicates that all dependencies have
1250
+ // been completed for this module
1251
+ complete: function () {
1252
+ this.completed.resolve();
1253
+ },
1254
+ // After the script has been loaded and run
1255
+ // - checks what has been stolen (in pending)
1256
+ // - wires up pendings steal's deferreds to eventually complete this
1257
+ // - this is where all of steal's complexity is
1258
+ executed: function (script) {
1259
+ var myqueue, stel, src = this.options.src,
1260
+ rootSrc = this.options.rootSrc;
1261
+ // Set this as the current file so any relative urls
1262
+ // will load from it.
1263
+ // rootSrc needs to be the translated path
1264
+ // we need id vs rootSrc ...
1265
+ if (this.options.id) {
1266
+ URI.cur = URI(this.options.id);
1267
+ }
1268
+ if (this.exports) {
1269
+ this.exports()
1270
+ }
1271
+ // set this as the current module
1272
+ steal.cur = this;
1273
+
1274
+ // mark yourself as 'loaded'.
1275
+ this.run.resolve();
1276
+
1277
+ // If we are IE, get the queue from interactives.
1278
+ // It in interactives because you can't use onload to know
1279
+ // which script is executing.
1280
+ if (h.support.interactive && src) { /*myqueue = interactives[src];*/
1281
+ if (interactives[src]) {
1282
+ myqueue = [];
1283
+ if (interactives.length) {
1284
+ for (var i = 0; i < interactives.length; i++) {
1285
+ if (interactives[i] !== this.orig) {
1286
+ myqueue.push(interactives[i])
1287
+ }
1288
+ }
1289
+ } else {
1290
+ if (interactives[src] !== this.orig) {
1291
+ myqueue = interactives[src];
1292
+ delete interactives[src];
1293
+ }
1294
+ }
1295
+
1296
+ }
1297
+ }
1298
+ // In other browsers, the queue of items to load is
1299
+ // what is in pending
1300
+ if (!myqueue) {
1301
+ myqueue = Module.pending.slice(0);
1302
+ Module.pending = [];
1303
+ }
1304
+
1305
+ // if we have nothing, mark us as complete
1306
+ if (!myqueue.length) {
1307
+ this.complete();
1308
+ return;
1309
+ }
1310
+ this.addDependencies(myqueue)
1311
+ this.loadDependencies();
1312
+
1313
+ },
1314
+ // add depenedencies to the module
1315
+ addDependencies: function (myqueue) {
1316
+ var self = this,
1317
+ isProduction = steal.config().env == "production";
1318
+ this.queue = [];
1319
+ h.each(myqueue, function (i, item) {
1320
+ if (item === null) {
1321
+ self.queue.push(null);
1322
+ return;
1323
+ }
1324
+
1325
+ if ((isProduction && item.ignore) || (!isProduction && !steal.isRhino && item.prodonly)) {
1326
+ return;
1327
+ }
1328
+
1329
+ // make a steal object
1330
+ var stel = Module.make(item);
1331
+ if (steal.packHash[stel.options.id] && stel.options.type !== 'fn') { // if we are production, and this is a package, mark as loading, but steal package?
1332
+ steal.has("" + stel.options.id);
1333
+ stel = steal.make(steal.packHash["" + stel.options.id]);
1334
+ }
1335
+ // has to happen before 'needs' for when reversed...
1336
+ self.queue.push(stel);
1337
+ });
1338
+ },
1339
+ // loads module's dependencies
1340
+ loadDependencies: function () {
1341
+
1342
+ //print("-setting up "+this.options.id)
1343
+ // now we have to figure out how to wire up our pending steals
1344
+ var self = this,
1345
+ // the current
1346
+
1347
+ // iterate through the collection and add all the 'needs'
1348
+ // before fetching...
1349
+ //print("-instances "+this.options.id)
1350
+ // The set of modules before the previous "wait" module
1351
+ priorSet = [],
1352
+ // The current set of modules after and including the
1353
+ // previous "wait" module
1354
+ set = [],
1355
+ // The first set of modules that we will execute
1356
+ // right away. This should be the first set of dependencies
1357
+ // that we can load in parallel. If something has
1358
+ // a need, the need should be in this set
1359
+ firstSet = [],
1360
+ // Should we be adding modules to the
1361
+ // firstSet
1362
+ setFirstSet = true;
1363
+
1364
+ // Goes through each module and maintains
1365
+ // a list of the set of modules
1366
+ // that must be complete before the current
1367
+ // module (`priorSet`).
1368
+ h.each(this.queue, function (i, module) {
1369
+ // add it as a dependency, circular are not allowed
1370
+ self.dependencies.push(module);
1371
+
1372
+ // if there's a wait and it's not the first thing
1373
+ if ((module === null || module.waits) && set.length) {
1374
+ // add the current set to `priorSet`
1375
+ priorSet = priorSet.concat(set);
1376
+ // empty the current set
1377
+ set = [];
1378
+ // we have our firs set of items
1379
+ setFirstSet = false;
1380
+ if (module === null) {
1381
+ return;
1382
+ }
1383
+
1384
+ }
1385
+ if (module === null) return;
1386
+
1387
+ // lets us know this module is currently wired to load
1388
+ module.isSetupToExecute = true;
1389
+ // when the priorSet is completed, execute this module
1390
+ // and when it's needs are done
1391
+ var waitsOn = priorSet.slice(0);
1392
+ // if there are needs, this can not be part of the "firstSet"
1393
+ h.each(module.options.needs || [], function (i, raw) {
1394
+
1395
+ var need = Module.make({
1396
+ id: raw,
1397
+ idToUri: self.options.idToUri
1398
+ });
1399
+ // add the need to the module's dependencies
1400
+ h.uniquePush(module.needsDependencies, need);
1401
+ waitsOn.push(need);
1402
+ // add needs to first set to execute
1403
+ firstSet.push(need)
1404
+ });
1405
+ waitsOn.length && whenEach(waitsOn, "completed", module, "execute");
1406
+
1407
+ // what is this used for?
1408
+ // module.waitedOn = module.waitedOn ? module.waitedOn.concat(priorSet) : priorSet.slice(0);
1409
+ // add this steal to the current set
1410
+ set.push(module);
1411
+ // if we are still on the first set, and this has no needs
1412
+ if (setFirstSet && (module.options.needs || []).length == 0) {
1413
+ // add this to the first set of things
1414
+ firstSet.push(module)
1415
+ }
1416
+ // start loading the module if possible
1417
+ module.load();
1418
+ });
1419
+
1420
+ // when every thing is complete, mark us as completed
1421
+ priorSet = priorSet.concat(set);
1422
+ whenEach(priorSet, "completed", self, "completed");
1423
+
1424
+ // execute the first set of dependencies
1425
+ h.each(firstSet, function (i, f) {
1426
+ f.execute();
1427
+ });
1428
+ },
1429
+ /**
1430
+ * Loads this steal
1431
+ */
1432
+ load: function (returnScript) {
1433
+ // if we are already loading / loaded
1434
+ if (this.loading || this.loaded.isResolved()) {
1435
+ return;
1436
+ }
1437
+
1438
+ this.loading = true;
1439
+ this.loaded.resolve();
1440
+ },
1441
+ execute: function () {
1442
+ var self = this;
1443
+ // if a late need dependency was addded
1444
+ if (this.lateNeedDependency && !this.lateNeedDependency.completed.isResolved()) {
1445
+ // call execute again when it's finished
1446
+ this.lateNeedDependency.completed.then(function () {
1447
+ self.execute()
1448
+ })
1449
+ return;
1450
+ }
1451
+
1452
+ // check types
1453
+ var raw = this.options,
1454
+ types = config.attr('types');
1455
+
1456
+ // if it's a string, get it's extension and check if
1457
+ // it is a registered type, if it is ... set the type
1458
+ if (!raw.type) {
1459
+ var ext = URI(raw.id).ext();
1460
+ if (!ext && !types[ext]) {
1461
+ ext = "js";
1462
+ }
1463
+ raw.type = ext;
1464
+ }
1465
+ if (!types[raw.type] && steal.config().env == 'development') {
1466
+ throw "steal.js - type " + raw.type + " has not been loaded.";
1467
+ } else if (!types[raw.type] && steal.config().env == 'production') {
1468
+ // if we haven't defined EJS yet and we're in production, its ok, just ignore it
1469
+ return;
1470
+ }
1471
+ var converters = types[raw.type].convert;
1472
+ raw.buildType = converters.length ? converters[converters.length - 1] : raw.type;
1473
+
1474
+ if (!self.loaded.isResolved()) {
1475
+ self.loaded.resolve();
1476
+ }
1477
+ if (!self.executing) {
1478
+ self.executing = true;
1479
+
1480
+ config.require(self.options, function (value) {
1481
+ self.executed(value);
1482
+ }, function (error, src) {
1483
+ var abortFlag = self.options.abort,
1484
+ errorCb = self.options.error;
1485
+
1486
+ // if an error callback was provided, fire it
1487
+ if (errorCb) {
1488
+ errorCb.call(self.options);
1489
+ }
1490
+
1491
+ h.win.clearTimeout && h.win.clearTimeout(self.completeTimeout)
1492
+
1493
+ // if abort: false, register the script as loaded, and don't throw
1494
+ if (abortFlag === false) {
1495
+ self.executed();
1496
+ return;
1497
+ }
1498
+ throw "steal.js : " + self.options.src + " not completed"
1499
+ });
1500
+ }
1501
+ },
1502
+ updateOptions: function () {
1503
+ var buildType = this.options.buildType;
1504
+ var orginalOptions = this.options;
1505
+ this.setOptions(this.orig);
1506
+ var newOptions = this.options;
1507
+ this.options = orginalOptions;
1508
+ for (opt in newOptions) {
1509
+ this.options[opt] = newOptions[opt];
1510
+ }
1511
+ this.options.buildType = buildType;
1512
+ },
1513
+ rewriteIdAndUpdateOptions: function (id) {
1514
+ // if module is not a function it means it's `src` is changeable
1515
+ if (this.options.type != "fn") {
1516
+ // finds module's needs
1517
+ // TODO this is terrible
1518
+ var needs = (this.options.needs || []).slice(0),
1519
+ buildType = this.options.buildType;
1520
+ this.updateOptions();
1521
+ var newId = this.options.id;
1522
+ // this mapping is to move a config'd key
1523
+ if (id !== newId) {
1524
+ modules[newId] = this;
1525
+ // TODO: remove the old one ....
1526
+ }
1527
+ this.options.buildType = buildType;
1528
+
1529
+ // if a module is set to load
1530
+ // check if there are new needs
1531
+ if (this.isSetupToExecute) {
1532
+ this.addLateDependencies(needs);
1533
+ }
1534
+ }
1535
+ },
1536
+ addLateDependencies: function (needs) {
1537
+ var self = this;
1538
+ // find all `needs` and set up "late dependencies"
1539
+ // this allows us to steal files that need to load
1540
+ // special converters without loading these converters
1541
+ // explicitely:
1542
+ //
1543
+ // steal('view.ejs', function(ejsFn){...})
1544
+ //
1545
+ // This will load files needed to convert .ejs files
1546
+ // without explicite steal
1547
+ h.each(this.options.needs || [], function (i, need) {
1548
+ if (h.inArray(needs, need) == -1) {
1549
+ var n = steal.make(need);
1550
+ n.execute()
1551
+ self.needsDependencies.push(n);
1552
+ self.lateNeedDependency = n;
1553
+ }
1554
+ })
1555
+ }
1556
+ });
1557
+
1558
+ // =============================== ERROR HANDLING ===============================
1559
+ h.extend(Module.prototype, {
1560
+ load: h.after(Module.prototype.load, function (stel) {
1561
+ var self = this;
1562
+ if (h.doc && !self.completed && !self.completeTimeout && !steal.isRhino && (self.options.src.protocol == "file" || !h.support.error)) {
1563
+ self.completeTimeout = setTimeout(function () {
1564
+ throw "steal.js : " + self.options.src + " not completed"
1565
+ }, 5000);
1566
+ }
1567
+ }),
1568
+ complete: h.after(Module.prototype.complete, function () {
1569
+ this.completeTimeout && clearTimeout(this.completeTimeout)
1570
+ }),
1571
+
1572
+ // if we're about to mark a file as executed, mark its "has" array files as
1573
+ // executed also
1574
+ executed: h.before(Module.prototype.executed, function () {
1575
+ if (this.options.has) {
1576
+ this.loadHas();
1577
+ }
1578
+ }),
1579
+
1580
+ /**
1581
+ * @hide
1582
+ * Goes through the array of files listed in this.options.has, marks them all as loaded.
1583
+ * This is used for files like production.css, which, once they load, need to mark the files they
1584
+ * contain as loaded.
1585
+ */
1586
+ loadHas: function () {
1587
+ var stel, i, current = URI.cur;
1588
+
1589
+ if (this.options.buildType == 'js') {
1590
+ return;
1591
+ }
1592
+
1593
+ // mark everything in has loaded
1594
+ h.each(this.options.has, function (i, has) {
1595
+ // don't want the current file to change, since we're just marking files as loaded
1596
+ URI.cur = URI(current);
1597
+ steal.executed(has);
1598
+ });
1599
+
1600
+ }
1601
+ });
1602
+
1603
+
1604
+ // =========== HAS ARRAY STUFF ============
1605
+ // Logic that deals with files that have collections of other files within
1606
+ // them. This is usually a production.css file,
1607
+ // which when it loads, needs to mark several CSS and LESS files it represents
1608
+ // as being "loaded". This is done by the production.js file having
1609
+ // steal({src: "production.css", has: ["file1.css", "file2.css"]
1610
+ //
1611
+ // after a steal is created, if its been loaded
1612
+ // already and has a "has", mark those files as loaded
1613
+ Module.make = h.after(Module.make, function (stel) {
1614
+ // if we have things
1615
+ if (stel.options.has) {
1616
+ // if we have loaded this already (and we are adding has's)
1617
+ if (stel.run.isResolved()) {
1618
+ stel.loadHas();
1619
+ } else {
1620
+ // have to mark has as loading and executing (so we don't try to get them)
1621
+ steal.has.apply(steal, stel.options.has)
1622
+ }
1623
+ }
1624
+ return stel;
1625
+ }, true);
1626
+ Module.modules = modules;
1627
+ return Module;
1628
+ }
1629
+
1630
+ function stealManager(kickoff, config, setStealOnWindow) {
1631
+
1632
+ // a startup function that will be called when steal is ready
1633
+ var interactiveScript,
1634
+ // key is script name, value is array of pending items
1635
+ interactives = {},
1636
+ // empty startup function
1637
+ startup = function () {};
1638
+
1639
+ var st = function () {
1640
+
1641
+ // convert arguments into an array
1642
+ var args = h.map(arguments, function (options) {
1643
+ if (options) {
1644
+ var opts = h.isString(options) ? {
1645
+ id: options
1646
+ } : options;
1647
+
1648
+ if (!opts.idToUri) {
1649
+ opts.idToUri = st.idToUri
1650
+ }
1651
+ return opts;
1652
+ } else {
1653
+ return options;
1654
+ }
1655
+ });
1656
+ if (args.length) {
1657
+ Module.pending.push.apply(Module.pending, args);
1658
+ // steal.after is called everytime steal is called
1659
+ // it kicks off loading these files
1660
+ st.after(args);
1661
+ // return steal for chaining
1662
+ }
1663
+
1664
+ return st;
1665
+ };
1666
+ if (setStealOnWindow) {
1667
+ h.win.steal = st;
1668
+ }
1669
+ // clone steal context
1670
+ st.clone = function () {
1671
+ return stealManager(false, config.cloneContext())
1672
+ }
1673
+
1674
+ st.config = function () {
1675
+ st.config.called = true;
1676
+ return config.attr.apply(config, arguments)
1677
+ };
1678
+ st.require = function () {
1679
+ return config.require.apply(config, arguments);
1680
+ }
1681
+ st.config.called = false;
1682
+ st._id = Math.floor(1000 * Math.random());
1683
+
1684
+ /**
1685
+ * @function st.getScriptOptions
1686
+ *
1687
+ * `steal.getScriptOptions` is used to determine various
1688
+ * options passed to the steal.js file:
1689
+ *
1690
+ * - should we load the production version of the
1691
+ * (if you use steal.production.js instead of steal.js)
1692
+ * - parts of the query string to determine `startFile`
1693
+ * - location of the `root url`
1694
+ */
1695
+
1696
+ st.getScriptOptions = function (script) {
1697
+
1698
+ var options = {},
1699
+ parts, src, query, startFile, env;
1700
+
1701
+ script = script || h.getStealScriptSrc();
1702
+
1703
+ if (script) {
1704
+
1705
+ // Split on question mark to get query
1706
+ parts = script.src.split("?");
1707
+ src = parts.shift();
1708
+ // // for IE7, where the script.src is always relative
1709
+ // if(!/\/\//.test(src)){
1710
+ // var dir = URI.page.dir();
1711
+ // src = URI(dir.join(src))+"";
1712
+ // }
1713
+ query = parts.join("?");
1714
+
1715
+ // Split on comma to get startFile and env
1716
+ parts = query.split(",");
1717
+
1718
+ if (src.indexOf("steal.production") > -1) {
1719
+ options.env = "production";
1720
+ }
1721
+
1722
+ // Grab startFile
1723
+ startFile = parts[0];
1724
+
1725
+ if (startFile) {
1726
+ if (startFile.indexOf(".js") == -1) {
1727
+ startFile += "/" + startFile.split("/").pop() + ".js";
1728
+ }
1729
+ options.startFile = startFile;
1730
+ }
1731
+
1732
+ // Grab env
1733
+ env = parts[1];
1734
+
1735
+ if (env) {
1736
+ options.env = env;
1737
+ }
1738
+
1739
+ // Split on / to get rootUrl
1740
+ parts = src.split("/")
1741
+ parts.pop();
1742
+ if (parts[parts.length - 1] == "steal") {
1743
+ parts.pop();
1744
+ }
1745
+ var root = parts.join("/");
1746
+ options.root = root
1747
+
1748
+ }
1749
+
1750
+ return options;
1751
+ };
1752
+
1753
+ /**
1754
+ * @function st.id
1755
+ *
1756
+ * Given a resource id passed to `steal( resourceID, currentWorkingId )`, this function converts it to the
1757
+ * final, unique id. This function can be overwritten
1758
+ * to change how unique ids are defined, for example, to be more AMD-like.
1759
+ *
1760
+ * The following are the default rules.
1761
+ *
1762
+ * Given an ID:
1763
+ *
1764
+ * 1. Check the id has an extension like _.js_ or _.customext_. If it doesn't:
1765
+ * 1. Check if the id is relative, meaning it starts with _../_ or _./_. If it is not, add
1766
+ * "/" plus everything after the last "/". So `foo/bar` becomes `foo/bar/bar`
1767
+ * 2. Add .js to the id.
1768
+ * 2. Check if the id is relative, meaning it starts with _../_ or _./_. If it is relative,
1769
+ * set the id to the id joined from the currentWorkingId.
1770
+ * 3. Check the
1771
+ *
1772
+ *
1773
+ * `st.id()`
1774
+ */
1775
+ // returns the "rootSrc" id, something that looks like requireJS
1776
+ // for a given id/path, what is the "REAL" id that should be used
1777
+ // this is where substituation can happen
1778
+ st.id = function (id, currentWorkingId, type) {
1779
+ // id should be like
1780
+ var uri = URI(id);
1781
+ uri = uri.addJS().normalize(currentWorkingId ? new URI(currentWorkingId) : null)
1782
+ // check foo/bar
1783
+ if (!type) {
1784
+ type = "js"
1785
+ }
1786
+ if (type == "js") {
1787
+ // if it ends with .js remove it ...
1788
+ // if it ends
1789
+ }
1790
+ // check map config
1791
+ var map = config.attr().map || {};
1792
+ // always run past
1793
+ h.each(map, function (loc, maps) {
1794
+ // is the current working id matching loc
1795
+ if (h.matchesId(loc, currentWorkingId)) {
1796
+ // run maps
1797
+ h.each(maps, function (part, replaceWith) {
1798
+ if (("" + uri).indexOf(part) == 0) {
1799
+ uri = URI(("" + uri).replace(part, replaceWith))
1800
+ }
1801
+ })
1802
+ }
1803
+ })
1804
+
1805
+ return uri;
1806
+ }
1807
+
1808
+ st.amdToId = function (id, currentWorkingId, type) {
1809
+ var uri = URI(id);
1810
+ uri = uri.normalize(currentWorkingId ? new URI(currentWorkingId) : null)
1811
+ // check foo/bar
1812
+ if (!type) {
1813
+ type = "js"
1814
+ }
1815
+ if (type == "js") {
1816
+ // if it ends with .js remove it ...
1817
+ // if it ends
1818
+ }
1819
+ // check map config
1820
+ var map = config.attr().map || {};
1821
+ // always run past
1822
+ h.each(map, function (loc, maps) {
1823
+ // is the current working id matching loc
1824
+ if (h.matchesId(loc, currentWorkingId)) {
1825
+ // run maps
1826
+ h.each(maps, function (part, replaceWith) {
1827
+ if (("" + uri).indexOf(part) == 0) {
1828
+ uri = URI(("" + uri).replace(part, replaceWith))
1829
+ }
1830
+ })
1831
+ }
1832
+ })
1833
+ return uri;
1834
+ }
1835
+
1836
+ // for a given ID, where should I find this resource
1837
+ /**
1838
+ * @function st.idToUri
1839
+ *
1840
+ * `steal.idToUri( id, noJoin )` takes an id and returns a URI that
1841
+ * is the location of the file. It uses the paths option of [config].
1842
+ * Passing true for `noJoin` does not join from the root URI.
1843
+ */
1844
+ st.idToUri = function (id, noJoin) {
1845
+ // this is normalize
1846
+ var paths = config.attr().paths || {},
1847
+ path;
1848
+ // always run past
1849
+ h.each(paths, function (part, replaceWith) {
1850
+ path = "" + id;
1851
+ // if path ends in / only check first part of id
1852
+ if ((h.endsInSlashRegex.test(part) && path.indexOf(part) == 0) ||
1853
+ // or check if its a full match only
1854
+ path === part) {
1855
+ id = URI(path.replace(part, replaceWith));
1856
+ }
1857
+ })
1858
+
1859
+ return noJoin ? id : config.attr().root.join(id)
1860
+ }
1861
+
1862
+ // for a given AMD id this will return an URI object
1863
+ /**
1864
+ * @function st.amdIdToUri
1865
+ *
1866
+ * `steal.amdIdToUri( id, noJoin )` takes and AMD id and returns a URI that
1867
+ * is the location of the file. It uses the paths options of [config].
1868
+ * Passing true for `noJoin` does not join from that URI.
1869
+ */
1870
+ st.amdIdToUri = function (id, noJoin) {
1871
+ // this is normalize
1872
+ var paths = config.attr().paths || {},
1873
+ path;
1874
+ // always run past
1875
+ h.each(paths, function (part, replaceWith) {
1876
+ path = "" + id;
1877
+ // if path ends in / only check first part of id
1878
+ if ((h.endsInSlashRegex.test(part) && path.indexOf(part) == 0) ||
1879
+ // or check if its a full match only
1880
+ path === part) {
1881
+ id = URI(path.replace(part, replaceWith));
1882
+ }
1883
+ })
1884
+ if (/(^|\/)[^\/\.]+$/.test(id)) {
1885
+ id = URI(id + ".js")
1886
+ }
1887
+ return id //noJoin ? id : config().root.join(id)
1888
+ }
1889
+
1890
+ // ## AMD ##
1891
+ var modules = {
1892
+
1893
+ };
1894
+
1895
+
1896
+ // AMD is not available for now. If you want to use AMD features with
1897
+ // steal you can by setting the `amd` param to true:
1898
+ //
1899
+ // steal({
1900
+ // amd: true
1901
+ // })
1902
+ //
1903
+ // This will expose `define` and `require` functions which can be used
1904
+ // to load AMD modules
1905
+ if (config.attr('amd') === true) {
1906
+
1907
+ // convert resources to modules ...
1908
+ // a function is a module definition piece
1909
+ // you steal(moduleId1, moduleId2, function(module1, module2){});
1910
+ /**
1911
+ * @function window.define
1912
+ *
1913
+ * AMD compatible `define` function. It is available only if steal's
1914
+ * `amd` param is set to true:
1915
+ *
1916
+ * <script type="text/javascript">
1917
+ * steal = {
1918
+ * amd : true
1919
+ * }
1920
+ * <script />
1921
+ * <script type="text/javascript" src="steal/steal.js"></script>
1922
+ *
1923
+ */
1924
+ h.win.define = function (moduleId, dependencies, method) {
1925
+ if (typeof moduleId == 'function') {
1926
+ modules[URI.cur + ""] = moduleId();
1927
+ } else if (!method && dependencies) {
1928
+ if (typeof dependencies == "function") {
1929
+ modules[moduleId] = dependencies();
1930
+ } else {
1931
+ modules[moduleId] = dependencies;
1932
+ }
1933
+
1934
+ } else if (dependencies && method && !dependencies.length) {
1935
+ modules[moduleId] = method();
1936
+ } else {
1937
+ st.apply(null, h.map(dependencies, function (dependency) {
1938
+ dependency = typeof dependency === "string" ? {
1939
+ id: dependency
1940
+ } : dependency;
1941
+ dependency.toId = st.amdToId;
1942
+
1943
+ dependency.idToUri = st.amdIdToUri;
1944
+ return dependency;
1945
+ }).concat(method))
1946
+ }
1947
+
1948
+ }
1949
+ /**
1950
+ * @function window.require
1951
+ *
1952
+ * AMD compatible require function. It is available only if steal's
1953
+ * `amd` param is set to true:
1954
+ *
1955
+ * <script type="text/javascript">
1956
+ * steal = {
1957
+ * amd : true
1958
+ * }
1959
+ * <script />
1960
+ * <script type="text/javascript" src="steal/steal.js"></script>
1961
+ *
1962
+ */
1963
+ h.win.require = function (dependencies, method) {
1964
+ var depends = h.map(dependencies, function (dependency) {
1965
+ dependency = typeof dependency === "string" ? {
1966
+ id: dependency
1967
+ } : dependency;
1968
+ dependency.toId = st.amdToId;
1969
+
1970
+ dependency.idToUri = st.amdIdToUri;
1971
+ return dependency;
1972
+ }).concat([method]);
1973
+ st.apply(null, depends)
1974
+ }
1975
+ h.win.define.amd = {
1976
+ jQuery: true
1977
+ }
1978
+
1979
+ // expose steal as AMD module
1980
+ define("steal", [], function () {
1981
+ return st;
1982
+ });
1983
+
1984
+ define("require", function () {
1985
+ return require;
1986
+ })
1987
+
1988
+ }
1989
+
1990
+ /**
1991
+ * @add steal
1992
+ */
1993
+ // =============================== STATIC API ===============================
1994
+ var events = {},
1995
+ page;
1996
+
1997
+ h.extend(st, {
1998
+ each: h.each,
1999
+ extend: h.extend,
2000
+ Deferred: Deferred,
2001
+ // Currently used a few places
2002
+ isRhino: h.win.load && h.win.readUrl && h.win.readFile,
2003
+ /**
2004
+ * @hide
2005
+ * Makes options
2006
+ * @param {Object} options
2007
+ */
2008
+ makeOptions: function (options, curId) {
2009
+ // convert it to a uri
2010
+ if (!options.id) {
2011
+ throw {
2012
+ message: "no id",
2013
+ options: options
2014
+ }
2015
+ }
2016
+ options.id = options.toId ? options.toId(options.id, curId) : st.id(options.id, curId);
2017
+ // set the ext
2018
+ options.ext = options.id.ext();
2019
+ options.src = options.idToUri ? options.idToUri(options.id) + "" : steal.idToUri(options.id) + "";
2020
+ // Check if it's a configured needs
2021
+ var configedExt = config.attr().ext[options.ext];
2022
+ // if we have something, but it's not a type
2023
+ if (configedExt && !config.attr().types[configedExt]) {
2024
+ if (!options.needs) {
2025
+ options.needs = [];
2026
+ }
2027
+
2028
+ options.needs.push(configedExt);
2029
+ }
2030
+
2031
+ return options;
2032
+ },
2033
+ /**
2034
+ * Calls steal, but waits until all previous steals
2035
+ * have completed loading until loading the
2036
+ * files passed to the arguments:
2037
+ *
2038
+ * steal('jquery', 'can/util').then('file/that/depends/on_jquery.js')
2039
+ *
2040
+ * In this case first `jquery` and `can/util` will be loaded in parallel,
2041
+ * and after both are loaded `file/that/depends/on_jquery.js` will be loaded
2042
+ */
2043
+ then: function () {
2044
+ var args = h.map(arguments);
2045
+ args.unshift(null)
2046
+ return st.apply(h.win, args);
2047
+ },
2048
+ /**
2049
+ * `steal.bind( event, handler(eventData...) )` listens to
2050
+ * events on steal. Typically these are used by various build processes
2051
+ * to know when steal starts and finish loading resources and their
2052
+ * dependencies. Listen to an event like:
2053
+ *
2054
+ * steal.bind('end', function(rootModule){
2055
+ * rootModule.dependencies // the first stolen resources.
2056
+ * })
2057
+ *
2058
+ * Steal supports the following events:
2059
+ *
2060
+ * - __start__ - steal has started loading a group of resources and their dependencies.
2061
+ * - __end__ - steal has finished loading a group of resources and their dependencies.
2062
+ * - __done__ - steal has finished loading the first set of resources and their dependencies.
2063
+ * - __ready__ - after both steal's "done" event and the `window`'s onload event have fired.
2064
+ *
2065
+ * For example, the following html:
2066
+ *
2067
+ * @codestart html
2068
+ * &lt;script src='steal/steal.js'>&lt;/script>
2069
+ * &lt;script>
2070
+ * steal('can/control', function(){
2071
+ * setTimeout(function(){
2072
+ * steal('can/model')
2073
+ * },200)
2074
+ * })
2075
+ * &lt;/script>
2076
+ * @codeend
2077
+ *
2078
+ * Would fire:
2079
+ *
2080
+ * - __start__ - immediately after `steal('can/control')` is called
2081
+ * - __end__ - after 'can/control', all of it's dependencies, and the callback function have executed and completed.
2082
+ * - __done__ - fired after the first 'end' event.
2083
+ * - __ready__ - fired after window.onload and the 'done' event
2084
+ * - __start__ - immediately after `steal('can/model')` is called
2085
+ * - __end__ - fired after 'can/model' and all of it's dependencies have fired.
2086
+ *
2087
+ *
2088
+ *
2089
+ * @param {String} event
2090
+ * @param {Function} listener
2091
+ */
2092
+ bind: function (event, listener) {
2093
+ if (!events[event]) {
2094
+ events[event] = []
2095
+ }
2096
+ var special = st.events[event]
2097
+ if (special && special.add) {
2098
+ listener = special.add(listener);
2099
+ }
2100
+ listener && events[event].push(listener);
2101
+ return st;
2102
+ },
2103
+ /**
2104
+ * `steal.one(eventName, handler(eventArgs...) )` works just like
2105
+ * [steal.bind] but immediately unbinds after `handler` is called.
2106
+ */
2107
+ one: function (event, listener) {
2108
+ return st.bind(event, function () {
2109
+ listener.apply(this, arguments);
2110
+ st.unbind(event, arguments.callee);
2111
+ });
2112
+ },
2113
+ events: {},
2114
+ /**
2115
+ * `steal.unbind( eventName, handler )` removes an event listener on steal.
2116
+ * @param {String} event
2117
+ * @param {Function} listener
2118
+ */
2119
+ unbind: function (event, listener) {
2120
+ var evs = events[event] || [],
2121
+ i = 0;
2122
+ while (i < evs.length) {
2123
+ if (listener === evs[i]) {
2124
+ evs.splice(i, 1);
2125
+ } else {
2126
+ i++;
2127
+ }
2128
+ }
2129
+ },
2130
+ trigger: function (event, arg) {
2131
+ var arr = events[event] || [];
2132
+ // array items might be removed during each iteration (with unbind),
2133
+ // so we iterate over a copy
2134
+ h.each(h.map(arr), function (i, f) {
2135
+ f(arg);
2136
+ })
2137
+ },
2138
+ /**
2139
+ * @hide
2140
+ * Creates resources and marks them as loading so steal doesn't try
2141
+ * to load them.
2142
+ *
2143
+ * steal.has("foo/bar.js","zed/car.js");
2144
+ *
2145
+ * This is used when a file has other resources in it.
2146
+ */
2147
+ has: function () {
2148
+ // we don't use IE's interactive script functionality while
2149
+ // production scripts are loading
2150
+ h.support.interactive = false;
2151
+ h.each(arguments, function (i, arg) {
2152
+ var stel = Module.make({
2153
+ id: arg,
2154
+ idToUri: st.idToUri
2155
+ });
2156
+ stel.loading = stel.executing = true;
2157
+ });
2158
+ },
2159
+ make: function (id) {
2160
+ var opts = (typeof id === "string" ? {
2161
+ id: id
2162
+ } : id);
2163
+ if (!opts.idToUri) {
2164
+ opts.idToUri = st.idToUri;
2165
+ }
2166
+ return Module.make(opts);
2167
+ },
2168
+ // a dummy function to add things to after the stel is created, but before executed is called
2169
+ preexecuted: function () {},
2170
+ /**
2171
+ * @hide
2172
+ * Signals that a resource's JS code has been run. This is used
2173
+ * when a file has other resources in it.
2174
+ *
2175
+ * steal.has("foo/bar.js");
2176
+ *
2177
+ * //start code for foo/bar.js
2178
+ * steal("zed/car.js", function(){ ... });
2179
+ * steal.executed("foo/bar.js");
2180
+ *
2181
+ * When a resource is executed, its dependent resources are loaded and eventually
2182
+ * executed.
2183
+ */
2184
+ // called when a script has loaded via production
2185
+ executed: function (name) {
2186
+ // create the steal, mark it as loading, then as loaded
2187
+ var resource = Module.make({
2188
+ id: name,
2189
+ idToUri: st.idToUri
2190
+ });
2191
+ resource.loading = resource.executing = true;
2192
+ //convert(stel, "complete");
2193
+ st.preexecuted(resource);
2194
+ resource.executed()
2195
+ return st;
2196
+ },
2197
+ type: function (type, cb) {
2198
+ var typs = type.split(" ");
2199
+ if (!cb) {
2200
+ return config.attr('types')[typs.shift()].require
2201
+ }
2202
+
2203
+ var types = config.attr('types')
2204
+
2205
+ types[typs.shift()] = {
2206
+ require: cb,
2207
+ convert: typs
2208
+ };
2209
+
2210
+ config.attr('types', types)
2211
+ },
2212
+ request: h.request
2213
+ });
2214
+ // Determine if we're running in IE older than IE9. This
2215
+ // will affect loading strategy for JavaScripts.
2216
+ h.useIEShim = (function () {
2217
+ if (st.isRhino) {
2218
+ return false;
2219
+ }
2220
+
2221
+ var d = document.createElement('div');
2222
+ d.innerHTML = "<!--[if lt IE 9]>ie<![endif]-->";
2223
+ return !!(h.scriptTag().readyState && d.innerText === "ie");
2224
+ })()
2225
+
2226
+ // ============================== Packages ===============================
2227
+ /**
2228
+ * @function packages
2229
+ * `steal.packages( packageIds... )` defines modules for deferred downloading.
2230
+ *
2231
+ * This is used by the build system to build collections of modules that will be downloaded
2232
+ * after initial page load.
2233
+ *
2234
+ * For example, an application that wants to progressively load the contents and
2235
+ * dependencies of _login/login.js_, _filemanager/filemanager.js_, and _contacts/contacts.js_,
2236
+ * while immediately loading the current users's data might look like:
2237
+ *
2238
+ * steal.packages('login','filemanager','contacts')
2239
+ * steal('models/user', function(User){
2240
+ *
2241
+ * // get the current User
2242
+ * User.findOne({id: "current"},
2243
+ *
2244
+ * // success - they logged in
2245
+ * function(user){
2246
+ * if(window.location.hash == "#filemanager"){
2247
+ * steal('filemanager')
2248
+ * }
2249
+ * },
2250
+ * // error - they are logged out
2251
+ * function(){
2252
+ * steal('login', function(){
2253
+ * new Login(document.body);
2254
+ * // preload filemanager
2255
+ *
2256
+ * })
2257
+ * })
2258
+ * })
2259
+ *
2260
+ *
2261
+ * steal.packages('tasks','dashboard','fileman');
2262
+ *
2263
+ */
2264
+ st.packs = [];
2265
+ st.packHash = {};
2266
+ st.packages = function (map) {
2267
+
2268
+ if (!arguments.length) {
2269
+ return st.packs;
2270
+ } else {
2271
+ if (typeof map == 'string') {
2272
+ st.packs.push.apply(st.packs, arguments);
2273
+ } else {
2274
+ st.packHash = map;
2275
+ }
2276
+
2277
+ return this;
2278
+ }
2279
+ };
2280
+
2281
+
2282
+ var Module = moduleManager(st, modules, interactives, config);
2283
+ resources = Module.modules;
2284
+
2285
+ /**
2286
+ * Implements shim support for steal
2287
+ *
2288
+ * This function sets up shims for steal. It follows RequireJS' syntax:
2289
+ *
2290
+ * steal.config({
2291
+ * shim : {
2292
+ * jquery: {
2293
+ * exports: "jQuery"
2294
+ * }
2295
+ * }
2296
+ * })
2297
+ *
2298
+ * You can also set function to explicitely return value from the module:
2299
+ *
2300
+ * steal.config({
2301
+ * shim : {
2302
+ * jquery: {
2303
+ * exports: function(){
2304
+ * return window.jQuery;
2305
+ * }
2306
+ * }
2307
+ * }
2308
+ * })
2309
+ *
2310
+ * This enables steal to pass you a value from library that is not wrapped
2311
+ * with steal() call.
2312
+ *
2313
+ * steal('jquery', function(j){
2314
+ * // j is set to jQuery
2315
+ * })
2316
+ */
2317
+ st.setupShims = function (shims) {
2318
+ // Go through all shims
2319
+ for (var id in shims) {
2320
+ // Make resource from shim's id. Since steal takes care
2321
+ // of always returning same resource for same id
2322
+ // when someone steals resource created in this function
2323
+ // they will get same object back
2324
+ var resource = Module.make({
2325
+ id: id
2326
+ });
2327
+ if (typeof shims[id] === "object") {
2328
+ // set up dependencies of the module
2329
+ var needs = shims[id].deps || []
2330
+ var exports = shims[id].exports;
2331
+ var init = shims[id].init
2332
+ } else {
2333
+ needs = shims[id];
2334
+ }(function (_resource, _needs) {
2335
+ _resource.options.needs = _needs;
2336
+ })(resource, needs);
2337
+ // create resource's exports function. We check for existance
2338
+ // of this function in `Module.prototype.executed` and if it exitst
2339
+ // it is called, which sets `value` of the module
2340
+ resource.exports = (function (_resource, _needs, _exports, _init) {
2341
+ return function () {
2342
+ var args = [];
2343
+ h.each(_needs, function (i, id) {
2344
+ args.push(Module.make(id).value);
2345
+ });
2346
+ if (_init) {
2347
+ // if module has exports function, call it
2348
+ _resource.value = _init.apply(null, args);
2349
+ } else {
2350
+ // otherwise it's a string so we just return
2351
+ // object from the window e.g window['jQuery']
2352
+ _resource.value = h.win[_exports];
2353
+ }
2354
+ }
2355
+ })(resource, needs, exports, init)
2356
+ }
2357
+ }
2358
+
2359
+ // =============================== STARTUP ===============================
2360
+ var rootSteal = false;
2361
+
2362
+ // essentially ... we need to know when we are on our first steal
2363
+ // then we need to know when the collection of those steals ends ...
2364
+ // and, it helps if we use a 'collection' steal because of it's natural
2365
+ // use for going through the pending queue
2366
+ //
2367
+ h.extend(st, {
2368
+ // modifies src
2369
+ /*makeOptions : after(steal.makeOptions,function(raw){
2370
+ raw.src = URI.root().join(raw.rootSrc = URI( raw.rootSrc ).insertMapping());
2371
+ }),*/
2372
+
2373
+ //root mappings to other locations
2374
+ mappings: {},
2375
+
2376
+ /**
2377
+ * Maps a 'rooted' folder to another location. For instance you could use it
2378
+ * to map from the `foo/bar` location to the `http://foo.cdn/bar`:
2379
+ *
2380
+ * steal.map('foo/bar', 'http://foo.cdn/bar');
2381
+ *
2382
+ * @param {String|Object} from the location you want to map from. For example:
2383
+ * 'foo/bar'
2384
+ * @param {String} [to] where you want to map this folder too. Ex: 'http://foo.cdn/bar'
2385
+ * @return {steal}
2386
+ */
2387
+ map: function (from, to) {
2388
+ if (h.isString(from)) {
2389
+ st.mappings[from] = {
2390
+ test: new RegExp("^(\/?" + from + ")([/.]|$)"),
2391
+ path: to
2392
+ };
2393
+ h.each(modules, function (id, module) {
2394
+ if (module.options.type != "fn") {
2395
+ // TODO terrible
2396
+ var buildType = module.options.buildType;
2397
+ module.updateOptions();
2398
+ module.options.buildType = buildType;
2399
+ }
2400
+ })
2401
+ } else { // its an object
2402
+ h.each(from, st.map);
2403
+ }
2404
+ return this;
2405
+ },
2406
+ // called after steals are added to the pending queue
2407
+ after: function () {
2408
+ // if we don't have a current 'top' steal
2409
+ // we create one and set it up
2410
+ // to start loading its dependencies (the current pending steals)
2411
+ if (!rootSteal) {
2412
+ rootSteal = new Module();
2413
+ // keep a reference in case it disappears
2414
+ var cur = rootSteal,
2415
+ // runs when a steal is starting
2416
+ go = function () {
2417
+ // indicates that a collection of steals has started
2418
+ st.trigger("start", cur);
2419
+ cur.completed.then(function () {
2420
+
2421
+ rootSteal = null;
2422
+ st.trigger("end", cur);
2423
+
2424
+
2425
+ });
2426
+
2427
+ cur.executed();
2428
+ };
2429
+ // If we are in the browser, wait a
2430
+ // brief timeout before executing the rootModule.
2431
+ // This allows embeded script tags with steal to be part of
2432
+ // the initial set
2433
+ if (h.win.setTimeout) {
2434
+ // we want to insert a "wait" after the current pending
2435
+ st.pushPending();
2436
+ setTimeout(function () {
2437
+ st.popPending();
2438
+ go();
2439
+ }, 0)
2440
+ } else {
2441
+ // if we are in rhino, start loading dependencies right away
2442
+ go()
2443
+ }
2444
+ }
2445
+ },
2446
+ _before: h.before,
2447
+ _after: h.after
2448
+ });
2449
+
2450
+ (function () {
2451
+ var myPending;
2452
+ st.pushPending = function () {
2453
+ myPending = Module.pending.slice(0);
2454
+ Module.pending = [];
2455
+ h.each(myPending, function (i, arg) {
2456
+ Module.make(arg);
2457
+ })
2458
+ }
2459
+ st.popPending = function () {
2460
+ Module.pending = Module.pending.length ? myPending.concat(null, Module.pending) : myPending;
2461
+ }
2462
+ })();
2463
+
2464
+ // =============================== jQuery ===============================
2465
+ (function () {
2466
+ var jQueryIncremented = false,
2467
+ jQ, ready = false;
2468
+
2469
+ // check if jQuery loaded after every script load ...
2470
+ Module.prototype.executed = h.before(Module.prototype.executed, function () {
2471
+
2472
+ var $ = h.win.jQuery;
2473
+ if ($ && "readyWait" in $) {
2474
+
2475
+ //Increment jQuery readyWait if ncecessary.
2476
+ if (!jQueryIncremented) {
2477
+ jQ = $;
2478
+ $.readyWait += 1;
2479
+ jQueryIncremented = true;
2480
+ }
2481
+ }
2482
+ });
2483
+
2484
+ // once the current batch is done, fire ready if it hasn't already been done
2485
+ st.bind("end", function () {
2486
+ if (jQueryIncremented && !ready) {
2487
+ jQ.ready(true);
2488
+ ready = true;
2489
+ }
2490
+ })
2491
+
2492
+ })();
2493
+
2494
+ // =========== DEBUG =========
2495
+ // var name = function(stel){
2496
+ // if(stel.options && stel.options.type == "fn"){
2497
+ // return stel.orig.name? stel.orig.name : stel.options.id+":fn";//(""+stel.orig).substr(0,10)
2498
+ // }
2499
+ // return stel.options ? stel.options.id + "": "CONTAINER"
2500
+ // }
2501
+ //
2502
+ // Module.prototype.load = before( Module.prototype.load, function(){
2503
+ // console.log(" load", name(this), this.loading, steal._id, this.id)
2504
+ // })
2505
+ //
2506
+ // Module.prototype.executed = before(Module.prototype.executed, function(){
2507
+ // var namer= name(this)
2508
+ // console.log(" executed", namer, steal._id, this.id)
2509
+ // })
2510
+ //
2511
+ // Module.prototype.complete = before(Module.prototype.complete, function(){
2512
+ // console.log(" complete", name(this), steal._id, this.id)
2513
+ // })
2514
+ // ============= WINDOW LOAD ========
2515
+ var loaded = {
2516
+ load: Deferred(),
2517
+ end: Deferred()
2518
+ },
2519
+ firstEnd = false;
2520
+
2521
+ h.addEvent(h.win, "load", function () {
2522
+ loaded.load.resolve();
2523
+ });
2524
+
2525
+ st.one("end", function (collection) {
2526
+ loaded.end.resolve(collection);
2527
+ firstEnd = collection;
2528
+ st.trigger("done", firstEnd)
2529
+ })
2530
+ st.firstComplete = loaded.end;
2531
+
2532
+ Deferred.when(loaded.load, loaded.end).then(function () {
2533
+ st.trigger("ready")
2534
+ st.isReady = true;
2535
+ });
2536
+
2537
+ st.events.done = {
2538
+ add: function (cb) {
2539
+ if (firstEnd) {
2540
+ cb(firstEnd);
2541
+ return false;
2542
+ } else {
2543
+ return cb;
2544
+ }
2545
+ }
2546
+ };
2547
+
2548
+ startup = h.after(startup, function () {
2549
+ // get options from
2550
+ var urlOptions = st.getScriptOptions();
2551
+ // A: GET OPTIONS
2552
+ // 1. get script options
2553
+ //h.extend(options, ); TODO: remove
2554
+ // 2. options from a steal object that existed before this steal
2555
+ // the steal object is copied right away
2556
+ // h.extend(options, opts);
2557
+ // 3. if url looks like steal[xyz]=bar, add those to the options
2558
+ // does this need to be supported anywhere?
2559
+ // NO - Justin
2560
+ var search = h.win.location && decodeURIComponent(h.win.location.search);
2561
+ search && search.replace(/steal\[([^\]]+)\]=([^&]+)/g, function (whoe, prop, val) {
2562
+ urlOptions[prop] = ~val.indexOf(",") ? val.split(",") : val;
2563
+ });
2564
+ // B: DO THINGS WITH OPTIONS
2565
+ // CALCULATE CURRENT LOCATION OF THINGS ...
2566
+ config.attr(urlOptions);
2567
+ var options = config.attr();
2568
+
2569
+ // mark things that have already been loaded
2570
+ h.each(options.executed || [], function (i, stel) {
2571
+ st.executed(stel)
2572
+ })
2573
+ // immediate steals we do
2574
+ var steals = [];
2575
+
2576
+ // add start files first
2577
+ if (options.startFiles) {
2578
+ /// this can be a string or an array
2579
+ steals.push.apply(steals, h.isString(options.startFiles) ? [options.startFiles] : options.startFiles)
2580
+ options.startFiles = steals.slice(0)
2581
+ }
2582
+
2583
+ // either instrument is in this page (if we're the window opened from
2584
+ // steal.browser), or its opener has it
2585
+ // try-catching this so we dont have to build up to the iframe
2586
+ // instrumentation check
2587
+ try {
2588
+ // win.top.steal.instrument is for qunit
2589
+ // win.top.opener.steal.instrument is for funcunit
2590
+ if (!options.browser && ((h.win.top && h.win.top.st.instrument) || (h.win.top && h.win.top.opener && h.win.top.opener.steal && h.win.top.opener.st.instrument))) {
2591
+
2592
+ // force startFiles to load before instrument
2593
+ steals.push(h.noop, {
2594
+ id: "steal/instrument",
2595
+ waits: true
2596
+ });
2597
+ }
2598
+ } catch (e) {
2599
+ // This would throw permission denied if
2600
+ // the child window was from a different domain
2601
+ }
2602
+
2603
+ // we only load things with force = true
2604
+ if (config.attr().env == "production" && config.attr().loadProduction && config.attr().production) {
2605
+ st({
2606
+ id: config.attr().production,
2607
+ force: true
2608
+ });
2609
+ } else {
2610
+ steals.unshift({
2611
+ id: "stealconfig.js",
2612
+ abort: false
2613
+ });
2614
+
2615
+ if (options.loadDev !== false) {
2616
+ steals.unshift({
2617
+ id: "steal/dev/dev.js",
2618
+ ignore: true
2619
+ });
2620
+ }
2621
+
2622
+ if (options.startFile) {
2623
+ steals.push(null, options.startFile)
2624
+ }
2625
+ }
2626
+ if (steals.length) {
2627
+ st.apply(h.win, steals);
2628
+ }
2629
+ });
2630
+
2631
+ // =========== INTERACTIVE STUFF ===========
2632
+ // Logic that deals with making steal work with IE. IE executes scripts out of order, so in order to tell which scripts are
2633
+ // dependencies of another, steal needs to check which is the currently "interactive" script.
2634
+ var getInteractiveScript = function () {
2635
+ var scripts = h.getElementsByTagName("script"),
2636
+ i = scripts.length;
2637
+ while (i--) {
2638
+ // if script's readyState is interactive it is the one we want
2639
+ if (scripts[i].readyState === "interactive") {
2640
+ return scripts[i];
2641
+ }
2642
+ }
2643
+ },
2644
+ getCachedInteractiveScript = function () {
2645
+ if (interactiveScript && interactiveScript.readyState === 'interactive') {
2646
+ return interactiveScript;
2647
+ }
2648
+
2649
+ if (interactiveScript = getInteractiveScript()) {
2650
+ return interactiveScript;
2651
+ }
2652
+
2653
+ // check last inserted
2654
+ if (lastInserted && lastInserted.readyState == 'interactive') {
2655
+ return lastInserted;
2656
+ }
2657
+
2658
+ return null;
2659
+ };
2660
+
2661
+
2662
+ h.support.interactive = h.doc && !! getInteractiveScript();
2663
+ if (h.support.interactive) {
2664
+ // after steal is called, check which script is "interactive" (for IE)
2665
+ st.after = h.after(st.after, function () {
2666
+ // check if disabled by st.loading()
2667
+ if (!h.support.interactive) {
2668
+ return;
2669
+ }
2670
+
2671
+ var interactive = getCachedInteractiveScript();
2672
+ // if no interactive script, this is a steal coming from inside a steal, let complete handle it
2673
+ if (!interactive || !interactive.src || /steal\.(production|production\.[a-zA-Z0-9\-\.\_]*)*js/.test(interactive.src)) {
2674
+ return;
2675
+ }
2676
+ // get the source of the script
2677
+ var src = interactive.src;
2678
+ // create an array to hold all steal calls for this script
2679
+ if (!interactives[src]) {
2680
+ interactives[src] = []
2681
+ }
2682
+
2683
+ // add to the list of steals for this script tag
2684
+ if (src) {
2685
+ interactives[src].push.apply(interactives[src], Module.pending);
2686
+ Module.pending = [];
2687
+ }
2688
+ })
2689
+
2690
+ // This is used for packaged scripts. As the packaged script executes, we grab the
2691
+ // dependencies that have come so far and assign them to the loaded script
2692
+ st.preexecuted = h.before(st.preexecuted, function (stel) {
2693
+ // check if disabled by st.loading()
2694
+ if (!h.support.interactive) {
2695
+ return;
2696
+ }
2697
+
2698
+ // get the src name
2699
+ var src = stel.options.src,
2700
+ // and the src of the current interactive script
2701
+ interactiveSrc = getCachedInteractiveScript().src;
2702
+
2703
+ interactives[src] = interactives[interactiveSrc];
2704
+ interactives[interactiveSrc] = null;
2705
+
2706
+ })
2707
+ }
2708
+
2709
+ // Use config.on to listen on changes in config. We primarily use this
2710
+ // to update resources' paths when stealconfig.js is loaded.
2711
+ config.on(function (configData) {
2712
+ h.each(resources, function (id, resource) {
2713
+ resource.rewriteIdAndUpdateOptions(id);
2714
+ });
2715
+ // set up shims after ids are updated
2716
+ if (configData.shim) {
2717
+ st.setupShims(configData.shim)
2718
+ }
2719
+ })
2720
+
2721
+ st.File = st.URI = URI;
2722
+
2723
+ // if this is a first steal context in the page
2724
+ // we need to set up the `steal` module so we would
2725
+ // know steal was loaded.
2726
+ if (kickoff) {
2727
+ var stealModule = new Module({
2728
+ id: "steal"
2729
+ })
2730
+ stealModule.value = st;
2731
+ stealModule.loaded.resolve();
2732
+ stealModule.run.resolve();
2733
+ stealModule.executing = true;
2734
+ stealModule.completed.resolve();
2735
+ resources[stealModule.options.id] = stealModule;
2736
+ }
2737
+
2738
+ startup();
2739
+ st.resources = resources;
2740
+ st.Module = Module;
2741
+
2742
+ return st;
2743
+ }
2744
+ // create initial steal instance
2745
+ stealManager(true, new ConfigManager(typeof h.win.steal == "object" ? h.win.steal : {}), true)
2746
+
2747
+ })();