-
Notifications
You must be signed in to change notification settings - Fork 1
/
LAB.js
147 lines (137 loc) · 4.68 KB
/
LAB.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
// LAB.js (LABjs :: Loading And Blocking JavaScript)
// v0.7 (c) Kyle Simpson
// MIT License
(function(global, doc, delay) {
var UNDEF = "undefined",
JSSTR = "string",
HEAD = "head",
BODY = "body",
_append_to = {
head: doc.getElementsByTagName(HEAD)[0],
body: doc.getElementsByTagName(BODY)[0]
},
all_scripts = {},
reFilename = /.*\/([^\?\#]+)(?:\?.*)?(?:\#.*)?$/,
toString = Object.prototype.toString;
function scriptFilename(src) {
return (src && src.length) ? src.match(reFilename)[1].toLowerCase() : '';
}
function scriptTagExists(filename) {
var scripts = doc.getElementsByTagName('script'), i = 0, script;
while (script = scripts[i++]) {
if (filename == scriptFilename(script.src)) {
return true;
}
}
return false;
}
function engine(queueExec,_which) {
queueExec = !!queueExec;
_which = (typeof _which === JSSTR) ? _which : HEAD;
var _ready = false,
_scripts_loading = false,
publicAPI,
_wait,
_scripts = {},
exec = [];
function handleScriptLoad(scriptentry) {
if ((this.readyState && this.readyState != 'complete' && this.readyState != 'loaded') || scriptentry.done) { return; }
this.onload = this.onreadystatechange = null; // prevent memory leak
scriptentry.done = true;
for (var i in _scripts) {
if ((_scripts[i] !== Object.prototype[i]) && !(_scripts[i].done)) return;
}
_ready = true;
if (_wait) _wait(); // safe since 'wait' will already contain old_func() call wrapped in try/catch
}
function loadScript(src, type, charset, allowDup) {
var src_filename = scriptFilename(src);
allowDup = !!allowDup;
if (!allowDup && (typeof all_scripts[src_filename] !== UNDEF || scriptTagExists(src_filename))) return;
if (typeof _scripts[src_filename] === UNDEF) _scripts[src_filename] = {done:false};
else _scripts[src_filename].done = false;
all_scripts[src_filename] = true;
_scripts_loading = true;
(function(__which){
var count = 1;
delay(function(){
var __append = _append_to[__which] || doc.getElementsByTagName(__which)[0];
if (!__append && (count++ < 10)) {
return delay(arguments.callee,25);
}
var scriptElem = doc.createElement('script');
scriptElem.setAttribute('type', type || 'text/javascript');
scriptElem.setAttribute('charset', charset || 'utf-8');
scriptElem.onload = scriptElem.onreadystatechange = function(){handleScriptLoad.call(scriptElem,_scripts[src_filename]);};
scriptElem.setAttribute('src', src);
__append.appendChild(scriptElem);
},0);
})(_which);
}
function executeOrQueue(execBody,retObj) {
if (queueExec) {
exec.push(execBody);
return retObj;
}
else return execBody();
}
publicAPI = {
script:function() {
var args = arguments;
return executeOrQueue(function(){
for (var i = 0, length = args.length, arg; i < length; i++) {
arg = args[i];
if (toString.call(arg) == '[object Array]') args.callee.apply(null, arg);
else if (typeof arg == 'object') loadScript(arg.src, arg.type, arg.charset, arg.allowDup);
else if (typeof arg == JSSTR) loadScript(arg);
}
return publicAPI;
},publicAPI);
},
block:function(func) {
if (typeof func !== "function") func = function(){};
var old_func = func, e = new engine(true,_which);
func = function(){try { old_func(); } catch(err) {} e.trigger(); }
return executeOrQueue(function(){
if (_scripts_loading && !_ready) _wait = func;
else delay(func, 0);
return e;
},e);
},
toHEAD:function(){
return executeOrQueue(function(){
_which=HEAD;
return publicAPI;
},publicAPI);
},
toBODY:function(){
return executeOrQueue(function(){
_which=BODY;
return publicAPI;
},publicAPI);
},
trigger:function(){
for (var i = 0; i < exec.length; i++) {
exec[i]();
}
}
};
return publicAPI;
};
global.$LAB = function() {
return {
script:function(){
return (new engine()).script.apply(null,arguments);
},
block:function(){
return (new engine()).block.apply(null,arguments);
},
toHEAD:function(){
return (new engine()).toHEAD();
},
toBODY:function(){
return (new engine()).toBODY();
}
};
}();
})(this, this.document, this.setTimeout);