kojac 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +7 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +158 -0
- data/MIT-LICENSE +20 -0
- data/README.md +69 -0
- data/Rakefile +27 -0
- data/app/assets/javascripts/can_extensions.js +45 -0
- data/app/assets/javascripts/kojac.js +1230 -0
- data/app/assets/javascripts/kojac_canjs.js +191 -0
- data/app/assets/javascripts/kojac_ember.js +463 -0
- data/app/controllers/kojac_controller.rb +70 -0
- data/app/serializers/default_kojac_serializer.rb +10 -0
- data/diagram.odg +0 -0
- data/kojac.gemspec +36 -0
- data/lib/kojac/app_serialize.rb +29 -0
- data/lib/kojac/kojac_rails.rb +432 -0
- data/lib/kojac/ring_strong_parameters.rb +195 -0
- data/lib/kojac/version.rb +3 -0
- data/lib/kojac.rb +8 -0
- data/lib/tasks/kojac_tasks.rake +4 -0
- data/notes.txt +48 -0
- data/spec/.DS_Store +0 -0
- data/spec/can_cache_spec.js +87 -0
- data/spec/can_factory_spec.js +144 -0
- data/spec/can_model_spec.js +127 -0
- data/spec/demo/README.rdoc +261 -0
- data/spec/demo/Rakefile +7 -0
- data/spec/demo/app/assets/javascripts/application.js +15 -0
- data/spec/demo/app/assets/stylesheets/application.css +13 -0
- data/spec/demo/app/controllers/application_controller.rb +3 -0
- data/spec/demo/app/helpers/application_helper.rb +2 -0
- data/spec/demo/app/mailers/.gitkeep +0 -0
- data/spec/demo/app/models/.gitkeep +0 -0
- data/spec/demo/app/views/layouts/application.html.erb +14 -0
- data/spec/demo/config/application.rb +65 -0
- data/spec/demo/config/boot.rb +10 -0
- data/spec/demo/config/database.yml +25 -0
- data/spec/demo/config/environment.rb +5 -0
- data/spec/demo/config/environments/development.rb +37 -0
- data/spec/demo/config/environments/production.rb +67 -0
- data/spec/demo/config/environments/test.rb +37 -0
- data/spec/demo/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/demo/config/initializers/inflections.rb +15 -0
- data/spec/demo/config/initializers/mime_types.rb +5 -0
- data/spec/demo/config/initializers/secret_token.rb +7 -0
- data/spec/demo/config/initializers/session_store.rb +8 -0
- data/spec/demo/config/initializers/wrap_parameters.rb +14 -0
- data/spec/demo/config/locales/en.yml +5 -0
- data/spec/demo/config/routes.rb +58 -0
- data/spec/demo/config.ru +4 -0
- data/spec/demo/lib/assets/.gitkeep +0 -0
- data/spec/demo/log/.gitkeep +0 -0
- data/spec/demo/public/404.html +26 -0
- data/spec/demo/public/422.html +26 -0
- data/spec/demo/public/500.html +25 -0
- data/spec/demo/public/favicon.ico +0 -0
- data/spec/demo/script/rails +6 -0
- data/spec/ember_factory_spec.js +157 -0
- data/spec/ember_model_spec.js +179 -0
- data/spec/external/.DS_Store +0 -0
- data/spec/external/ember/.DS_Store +0 -0
- data/spec/external/ember/ember-1.0.0-rc.6.js +30970 -0
- data/spec/external/ember/handlebars-1.0.0-rc.4.js +2239 -0
- data/spec/external/jasmine/MIT.LICENSE +20 -0
- data/spec/external/jasmine/jasmine-html.js +616 -0
- data/spec/external/jasmine/jasmine.css +81 -0
- data/spec/external/jasmine/jasmine.js +2529 -0
- data/spec/external/jasmine.async.js +51 -0
- data/spec/external/jquery/jquery-1.7.2.js +9404 -0
- data/spec/external/jquery/jquery-1.7.2.min.js +4 -0
- data/spec/external/jquery/jquery-1.9.1.js +9597 -0
- data/spec/external/json2.js +480 -0
- data/spec/external/steal/steal-121115.js +2747 -0
- data/spec/external/steal/steal-3.2.3.js +2098 -0
- data/spec/external/steal/steal-3.2.3.min.js +27 -0
- data/spec/external/steal/steal.js +2466 -0
- data/spec/external/steal/steal.min.js +32 -0
- data/spec/external/steal/stealconfig.js +19 -0
- data/spec/external/underscore.js +1223 -0
- data/spec/external/underscore_plus.js +261 -0
- data/spec/external.zip +0 -0
- data/spec/handler_stack_spec.js +143 -0
- data/spec/helpers/SpecHelper.js +10 -0
- data/spec/kojac_caching_spec.js +105 -0
- data/spec/kojac_mock_spec.js +230 -0
- data/spec/kojac_model_spec.js +126 -0
- data/spec/kojac_object_spec.js +171 -0
- data/spec/kojac_operations_spec.js +41 -0
- data/spec/mockjson/order_item.js +37 -0
- data/spec/mockjson/order_item__49.js +15 -0
- data/spec/mockjson/order_item__50.js +15 -0
- data/spec/mockjson/order_item__51.js +15 -0
- data/spec/mockjson/product.js +82 -0
- data/spec/mockjson/product__3.js +22 -0
- data/spec/model_ring_spec.rb +52 -0
- data/spec/operation_include_spec.js +77 -0
- data/spec/run.html +81 -0
- data/spec/spec.js +2 -0
- data/spec/support/jasmine.yml +86 -0
- 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
|
+
* <script src='steal/steal.js'></script>
|
|
2069
|
+
* <script>
|
|
2070
|
+
* steal('can/control', function(){
|
|
2071
|
+
* setTimeout(function(){
|
|
2072
|
+
* steal('can/model')
|
|
2073
|
+
* },200)
|
|
2074
|
+
* })
|
|
2075
|
+
* </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
|
+
})();
|