-
Notifications
You must be signed in to change notification settings - Fork 1
/
Script.js
165 lines (137 loc) · 4.94 KB
/
Script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*** Script singleton, for loading scripts dynamically. ***/
(function(window) { // begin hidden from global scope
// return the "src" of the last script in the document
// this is generally the script that is executing right now
function $lastScript() {
var scripts = document.getElementsByTagName("script");
return scripts[scripts.length-1].src;
}
// load a single script by creating a SCRIPT element for it
function $loadOne(url) {
var script = document.createElement("script");
script.setAttribute("src", XHR.addCacheParam(url, XHR.cache));
Script.domParent.appendChild(script);
if (Script.debug) console.error("Adding script for ",url);
}
var Script = {
debug : hope.debug("Script"),
// parent where we will insert new script elements
domParent : document.querySelector("head"),
// map of scripts which have already been successfully loaded
loadedUrls : {},
// map of scripts which are currently loading
loadingUrls : {},
// Append a javascript @code block as a SCRIPT tag in the DOM immediately.
// @callback is a function to call immediately after script executes
// @errback is a function to call if the script fails (eg: syntax error)
// @errback will be called with the exception object.
execute : function(code, callback, errback, note) {
// create a informational callback if one wasn't defined
if (!errback) errback = function(e){
console.error("Error executing script:", e, "\n", code)
};
// and stick it in the global scope so we can call it on error
var errId = "SCRIPT_ERROR_" + SCRIPT_ERROR_ID++;
window[errId] = errback;
// wrap the code in a try/catch to call the errback
code = "try { "+ code +"} catch (e) { window."+errId+"(e) }";
// create the script element and attach it to the dom
var script = document.createElement("script");
if (note) script.setAttribute("note", note);
script.appendChild(document.createTextNode(code));
// append the script node to the document head
// NOTE: this will execute it immediately and synchronously in FF 3.5+ and Chrome
Script.domParent.appendChild(script);
// clear the callback
delete window[errId]
if (callback) callback();
},
// Asynchronously load one or more script files, and call the callback when completed.
load : function(urls, callback) {
// convert to an array, splitting on commas (which are not legal in URLs)
if (typeof urls === "string") urls = urls.split(/\s*,\s*/);
var unloaded = [];
if (urls) {
// figure out which scripts have not been loaded yet
var i = -1, url;
while (url = urls[++i]) {
// expand any named paths in the url
url = XHR.expand(url);
if (!Script.loadedUrls[url]) unloaded.push(url);
}
}
if (Script.debug) {
var script = XHR.collapse($lastScript()||"");
console.info("loading",script,
"\n requiring ",urls,
"\n unloaded ",unloaded
+ (unloaded.length ? "\n executing callback now" : "")
);
var loadMsg = function(didItWork){
console.info("load callback "+didItWork+" for ",urls)
};
}
var callbackFired = false;
// if nothing to load, we're done
if (unloaded.length === 0) {
callbackFired = true;
if (callback) callback();
return true;
}
function loadCallback() {
// bail if any of our requires are not loaded
var i = -1, url;
while (url = unloaded[++i]) {
if (!Script.loadedUrls[url]) {
if (Script.debug) loadMsg("not finished");
return;
}
}
if (Script.debug) loadMsg("finished");
// if we get here, we're all loaded, so execute the callback
if (!callbackFired && callback) callback();
callbackFired = true;
}
// load any that are not currently loading
var i = -1, url;
while (url = unloaded[++i]) {
if (!Script.loadingUrls[url]) {
$loadOne(url);
Script.loadingUrls[url] = [];
}
if (Script.debug) console.info("pushing callback for ",script," onto list for ",url);
if (callback) Script.loadingUrls[url].push(loadCallback);
}
return false;
},
// Require a bunch of scripts (NOT executed in order) and then do some callback.
// NOTE: this is syntatactic sugar for Script.load()
require : function (urls, callback) {
Script.load(urls, callback);
},
// Call this when a URL has been loaded.
//
//
// If any other scripts have require()d this script, this will execute them.
//
// If you load your file via Script.load or via static load before window.onload fires,
// this will be called automatically. (?)
loaded : function(url) {
if (Script.debug) console.warn("loaded ",url);
url = XHR.expand(url);
Script.loadedUrls[url] = true;
var callbacks = Script.loadingUrls[url];
if (callbacks) {
var i = -1, callback;
while (callback = callbacks[++i]) {
callback();
}
}
delete Script.loadingUrls[url];
},
toRef : function() { return "Script" }
}; // end Script
hope.setGlobal("Script", Script);
// hacky that this is here, but it's a bootstrap thing
Script.loaded("{{hope}}Script.js");
})(window);// end hidden from global scope