-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathteleport.js
338 lines (299 loc) · 10.8 KB
/
teleport.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/* vim:set ts=2 sw=2 sts=2 expandtab */
/*jshint asi: true undef: true es5: true node: true devel: true browser: true
forin: true, eqnull: true latedef: false supernew: true */
/*global define: true */
// CommonJS AMD 1.1 loader.
var teleport = new function Teleport(global, undefined) {
'use strict';
var exports = this,
mainId,
descriptors = {},
modules = {},
anonymousModules = [],
isArray,
_toString = Object.prototype.toString,
// Constants
MAIN_ATTR = 'data-main',
SCRIPT_ELEMENT = 'script',
UNDEFINED = 'undefined',
SCRIPT_TYPE = 'text/javascript',
BASE = getBase(),
// IE (at least 6-8) do not dispatches `'load'` events on script elements
// after execution, but `readyState` property value of such script elements
// is `'interactive'`, which we default to in case `addEventListener` is
// not defined.
interactiveMode = !('addEventListener' in document),
isBrowser = UNDEFINED !== typeof window && window.window === window,
hasNewJS = isBrowser && 0 <= navigator.userAgent.indexOf('Firefox'),
isWorker = !isBrowser && UNDEFINED !== typeof importScripts,
COMMENTS_MATCH = /(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|((^|\n)[^\'\"\n]*\/\/[^\n]*)/g,
REQUIRE_MATCH = /(^|[^\w\_])require\s*\(('|")([\w\W]*?)('|")\)/g
if (hasNewJS) SCRIPT_TYPE = 'application/javascript;version=1.8'
function getBase() {
var base = (document.baseURI || document.URL).split('?')[0].split('#')[0]
if (0 < base.substr(base.lastIndexOf('/')).indexOf('.'))
base = base.substr(0, base.lastIndexOf('/') + 1)
return base
}
function isString(value) {
return 'string' === typeof value
}
isArray = Array.isArray || function isArray(value) {
return '[object Array]' === _toString.call(value)
}
function getInteractiveScript() {
var scripts = document.getElementsByTagName('script'),
l = scripts.length,
interactiveScript, script
while ((script = scripts[--l])) {
if ('interactive' === script.readyState)
return (interactiveScript = script)
}
}
function isModuleIdRelative(id) {
return '.' === id.charAt(0)
}
function getExtension(id) {
var basename = id.split('/').pop(), index = basename.lastIndexOf('.')
return 0 < index ? basename.substr(index) : ''
}
/**
* Resolves relative module ID to an absolute id.
* @param {String} id
* relative id to be resolved
* @param {String} baseId
* absolute id of a requirer module
* @return {String}
* absolute id
*/
function resolveId(id, baseId) {
var parts, part, root, base, extension
// If given `id` is not relative or `baseId` is not provided we can't resolve.
if (!baseId || !isModuleIdRelative(id)) return id
extension = getExtension(baseId)
parts = id.split('/')
root = parts[0]
base = baseId.split('/')
if (base.length > 1) base.pop()
while ((part = parts.shift())) {
if (part === '..' && base.length) base.pop()
else if (part !== '.') base.push(part)
}
return base.join('/') + extension
}
function resolveURL(id) {
id = resolveId(id, BASE)
id = 0 < id.indexOf('://') ? id : 'support/' + id + '.js'
return id + '?module&transport'
}
function createModule(id) {
return (modules[id] = { id: id, exports: {} })
}
function getModule(id) {
return id in modules ? modules[id] : createModule(id)
}
function createDescriptor(id) {
return (descriptors[id] = {
ready: false,
loading: false,
defined: false,
factory: null,
id: id,
url: resolveURL(id),
dependencies: null,
dependents: null
})
}
function getDescriptor(id) {
return id in descriptors ? descriptors[id] : createDescriptor(id)
}
function declareDependency(dependent, dependency) {
var dependents = dependency.dependents || (dependency.dependents = {})
return (dependents[dependent.id] = dependent)
}
/**
* Function takes `id` and `source` of module and returns array of absolute
* id's of modules that are required by a given module. (function does naive
* parsing of source to find all the `require` statements and resolves all the
* relative id's in it to a given `id`).
* @param {String} id
* Absolute id of a module.
* @param {String()} source
* Source of a module.
* @returns {String[]}
*/
function getDependencies(id, source) {
var dependency, dependencies = []
// strip out comments to ignore commented `require` calls.
source = String(source).replace(COMMENTS_MATCH, '')
while ((dependency = REQUIRE_MATCH.exec(source))) {
dependency = dependency[3]
dependencies.push(resolveId(dependency, id))
}
return dependencies
}
function fetch(descriptor) {
var module = document.createElement(SCRIPT_ELEMENT)
module.setAttribute('type', SCRIPT_TYPE)
module.setAttribute('data-loader', 'teleport')
module.setAttribute('data-id', descriptor.id)
module.setAttribute('src', descriptor.url)
module.setAttribute('charset', 'utf-8')
module.setAttribute('async', true)
if (module.addEventListener)
module.addEventListener('load', onModuleLoad, false)
document.getElementsByTagName('head')[0].appendChild(module)
}
// Loads module and all it's dependencies. Once module with all the
// dependencies is loaded callback is called.
function load(descriptor) {
if (!descriptor.loading) {
descriptor.loading = true
fetch(descriptor)
}
}
function onModuleLoad(event) {
var deferred, element, id
element = event.currentTarget || event.srcElement
element.removeEventListener('load', onModuleLoad, false)
id = element.getAttribute('data-id')
// Define deferred module only if it has not been defined yet. In some
// cases modules with explicit id's can be used in mix with anonymous
// modules and we should only handle anonymous ones.
if (!getDescriptor(id).defined) {
;(deferred = anonymousModules.pop()).unshift(id)
define.apply(null, deferred)
}
}
function onReady(descriptor) {
descriptor.ready = true
updateDependents(descriptor)
if (descriptor.execute) Require()(descriptor.id)
}
function moduleStateChange(descriptor) {
if (!descriptor.ready &&
descriptor.defined &&
0 === updateDependencyStates(descriptor, descriptor.dependencies)
) onReady(descriptor)
}
function onDefine(descriptor) {
// If descriptor was not ready yet.
descriptor.defined = true
moduleStateChange(descriptor)
}
function updateDependencyStates(descriptor, dependencies) {
var dependency, i, ii, pending = 0
if (dependencies) {
for (i = 0, ii = dependencies.length; i < ii; i++) {
// Getting module descriptor for each dependency.
dependency = getDescriptor(dependencies[i])
if (!dependency.ready) {
pending ++
// Adding `descriptor` to a list of dependent modules on `dependency`.
declareDependency(descriptor, dependency)
// Start loading if not in progress already.
if (!dependency.loading) load(dependency)
}
}
}
// Return list of pending dependencies.
return pending
}
// Notifies all the dependents that dependency is ready.
function updateDependents(descriptor) {
var dependency, name, dependents = descriptor.dependents;
delete descriptor.dependents
if (dependents) {
// Go through each dependent and check.
for (name in dependents) moduleStateChange(dependents[name])
}
}
function getMainId() {
var i, ii, main, elements = document.getElementsByTagName(SCRIPT_ELEMENT)
for (i = 0, ii = elements.length; i < ii; i++)
if ((main = elements[i].getAttribute(MAIN_ATTR))) return main
}
/**
* Implementation of CommonJS
* [Modules/Transport/D](http://wiki.commonjs.org/wiki/Modules/Transport/D)
* @param {Object} descriptors
* Hash of module top level module id's and relevant factories.
*
* @param {String[]} dependencies
* Top-level module identifiers corresponding to the shallow dependencies
* of the given module factory
* @param {Object} extra
* **Non-standard** helper utilities (improving debugging)
*/
function define(id, dependencies, factory) {
var descriptor
// If first argument is string then it's a module with provided `id` and
// we register module immediately
if (isString(id)) {
// Creating module descriptor for this id.
descriptor = getDescriptor(id)
// If second argument is not an array then module dependencies have not
// been provided and we need to figure them out by source analyses.
if (!isArray(dependencies)) {
factory = dependencies
dependencies = getDependencies(id, factory)
}
descriptor.dependencies = dependencies
descriptor.factory = factory
// Registering this module.
onDefine(descriptor)
// If `id` is an array then it's an anonymous module with known
// dependencies.
} else {
// Shifting arguments as we know id is missing.
factory = dependencies
dependencies = id
// If it's an interactive mode we are able to detect module ID by finding
// an interactive scripts `data-id` attribute. In this case we do so and
// call `define` with an id.
if (interactiveMode) {
id = getInteractiveScript().getAttribute('data-id')
define(id, dependencies, factory)
// If it's not an interactive mode we defer module definition until
// associated script's `load` event in order to detect module id.
} else anonymousModules.push([ dependencies, factory ])
}
}
exports.define = define
// `require` generator fun modules.
function Require(requirerID) {
function require(id) {
var module, descriptor
// resolving relative id to an absolute id.
id = resolveId(id, requirerID)
// using module if it was already created, otherwise creating one
// and registering into global module registry.
module = getModule(id)
if (!module.filename) {
descriptor = getDescriptor(id)
module.filename = descriptor.url
descriptor.factory.call(NaN, Require(id), module.exports, module)
}
return module.exports
}
require.main = Require.main
return require
}
function main(id) {
// setting main in order to reuse it later
Require.main = getModule(id)
return require(id)
}
exports.main = main
function require(id) {
var module = getModule(id), descriptor = getDescriptor(id)
descriptor.execute = true
load(descriptor)
return module.exports
}
require.main = main
exports.require = require
if (!('require' in global)) global.require = require
if (!('define' in global)) global.define = define
if ((mainId = getMainId())) require.main(mainId)
}(this)