├── LICENSE
├── README.md
├── app.build.js
├── examples-build
├── as-globals.html
├── as-modules-only.html
├── as-modules.html
├── build-example.html
├── build.txt
├── js
│ ├── build-example.js
│ ├── cheese.js
│ ├── config.js
│ ├── lib
│ │ ├── candy.js
│ │ ├── donut.js
│ │ ├── frosting.js
│ │ ├── nachos.js
│ │ ├── r.js
│ │ ├── require.js
│ │ ├── rolls.js
│ │ ├── sugar.js
│ │ ├── text.js
│ │ └── wheat.js
│ └── pizza.js
└── use-path-option.html
├── examples
├── as-globals.html
├── as-modules-only.html
├── as-modules.html
├── build-example.html
├── js
│ ├── build-example.js
│ ├── cheese.js
│ ├── config.js
│ ├── lib
│ │ ├── candy.js
│ │ ├── donut.js
│ │ ├── frosting.js
│ │ ├── ketchup.js
│ │ ├── nachos.js
│ │ ├── r.js
│ │ ├── require.js
│ │ ├── rolls.js
│ │ ├── sugar.js
│ │ ├── tasty.hamburger.js
│ │ ├── text.js
│ │ └── wheat.js
│ └── pizza.js
└── use-path-option.html
├── spec
├── browser
│ └── wrapjs-test.js
├── buster.js
└── module
│ ├── amd-test.js
│ ├── amd-test2.js
│ └── amd-test3.js
└── wrap.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 | -----------
3 |
4 | Copyright (c) 2012 Dave Geddes
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DEPRECATED
2 | ## This plugin's wildest dreams came true and its functionality was added to RequireJS 2.0
Please upgrade your RequireJS and use its new [shim config](http://requirejs.org/docs/api.html#config-shim) instead of wrap.js
3 |
4 |
5 | # wrap.js
6 | version 0.2.2
7 | A RequireJS plugin for wrapping regular scripts as AMD modules.
8 | This is useful for cases where regular scripts have dependencies, like jQuery plugins and Backbone.
9 | Depends on the [text plugin](http://requirejs.org/docs/api.html#text)
10 |
11 | ## Usage
12 | In your require.config use the wrapJS object to specify which scripts you want to wrap.
13 | Use the `deps` attribute to specify all the script's dependencies.
14 | Use the `attach` attribute to specify the global name of the library (think $, _, Backbone, etc)
15 | Use the `path` attribute to specify the location of the script to wrap. Alternatively use require's regular path config.
16 | The following example wraps backbone, declaring underscore and jQuery as dependencies:
17 |
18 |
19 | ```js
20 | require.config({
21 | wrapJS: {
22 | "backbone": {
23 | deps: ["underscore", "jquery"], //an array of the script's dependencies
24 | attach: "Backbone"
25 | }
26 | });
27 |
28 | ```
29 |
30 | Now use the wrap plugin to load the backbone (and its dependencies) like so:
31 |
32 | ```js
33 | require('wrap!backbone', function(Backbone){
34 | console.log(Backbone); //now returns Backbone, just as if Backbone were an AMD module
35 | }
36 | ```
37 |
38 | NOTE: As of RequireJS 1.0.5 you can reuse your app's main.js config as part of your build config, by using the new mainConfigFile setting: `mainConfigFile:'path/to/main.js'` So you only have to specify the wrapJS stuff once. Here's a sample [app.build.js](https://github.com/geddesign/wrapjs/blob/master/app.build.js).
39 |
40 | ## How It Works
41 |
42 | During development, wrap.js basically does a nested `require()` for you, so that the script's dependencies are sure to load first. Then when you run the r.js build, an actual AMD module is generated based on your config. So say you were trying to wrap Backbone.js, and the Backbone.js script looks like this:
43 |
44 | ```js
45 | (function(){
46 | //stuff
47 | }).call(this);
48 | ```
49 |
50 | Now after the r.js build backbone looks like this:
51 |
52 | ```js
53 | define('wrap!backbone', ['jquery', 'underscore'], function(){
54 | (function(){
55 | //backbone stuff
56 | }).call(this);
57 | return (function () {
58 | var attach = Backbone;
59 | return (typeof attach === 'function') ? attach.apply(this) : attach;
60 | }());
61 | });
62 | ```
63 |
64 | NOTE: the generated AMD module contains an immediate function that resolves to and returns Backbone in the example above. Pure JS magic.
65 |
66 | So there you have it. The wrap.js plugin turns any old script into an AMD module with just a little config.
67 |
68 | ## More Examples
69 | I've included several examples in the `examples` directory.
70 |
71 | ### Use as Globals
72 | By default the wrapped scripts are still available as globals. See [as-globals.html](https://github.com/geddesign/wrapjs/blob/master/examples/as-globals.html).
73 |
74 | ### Use as Modules
75 | The wrapped scripts are also returned to your callback just like AMD modules. See [as-modules.html](https://github.com/geddesign/wrapjs/blob/master/examples/as-modules.html).
76 |
77 | ### Remove Globals
78 | If you want to have the wrapped scripts no longer available as globals, you can remove the global—and do any other custom things—in a function you pass to the `attach` property. See [as-modules-only.html](https://github.com/geddesign/wrapjs/blob/master/examples/as-modules-only.html).
79 |
80 | ### Using the path option
81 | Using the `path` attribute can help keep your config small. See [use-path-option.html](https://github.com/geddesign/wrapjs/blob/master/examples/use-path-option.html)
82 |
83 | ### Post-build example
84 | To see an example of a generated module, see the build-example.js [before](https://github.com/geddesign/wrapjs/blob/master/examples/js/build-example.js) and [after](https://github.com/geddesign/wrapjs/blob/master/examples-build/js/build-example.js).
85 |
--------------------------------------------------------------------------------
/app.build.js:
--------------------------------------------------------------------------------
1 | ({
2 | appDir:"examples/",
3 | baseUrl: "js/",
4 | dir:"examples-build/",
5 | optimize: 'none', //for sake of example don't compress
6 | mainConfigFile:'examples/js/config.js',
7 | modules:[
8 | { name:"build-example",
9 | //exluding config for the sake of testing.
10 | exclude: ['text', 'wrap', 'config']
11 | }
12 | ],
13 | findNestedDependencies:true
14 | })
--------------------------------------------------------------------------------
/examples-build/as-globals.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | keep as globals
5 |
6 |
27 |
28 |
--------------------------------------------------------------------------------
/examples-build/as-modules-only.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | turn into modules with no more globals
5 |
6 |
35 |
36 |
--------------------------------------------------------------------------------
/examples-build/as-modules.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | turn scripts into modules
5 |
6 |
31 |
32 |
--------------------------------------------------------------------------------
/examples-build/build-example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | load the build-time generated modules
5 |
6 |
7 |
--------------------------------------------------------------------------------
/examples-build/build.txt:
--------------------------------------------------------------------------------
1 |
2 | js/build-example.js
3 | ----------------
4 | wrap!frosting
5 | wrap!donut
6 | js/lib/frosting.js
7 | js/build-example.js
8 |
--------------------------------------------------------------------------------
/examples-build/js/build-example.js:
--------------------------------------------------------------------------------
1 |
2 | /* script wrapped by the wrap! plugin */
3 | define("wrap!frosting", [], function(){
4 | frosting = {
5 | name:"frosting"
6 | };
7 | return (function () {
8 | var attach = frosting;
9 | return (typeof attach === 'function') ? attach.apply(this) : attach;
10 | }());
11 | });
12 |
13 | /* script wrapped by the wrap! plugin */
14 | define("wrap!donut", ["wrap!frosting"], function(){
15 | donut = {
16 | name: "donut",
17 | ingredients: [frosting] //depends on the global sugar.js being available
18 | };
19 | return (function () {
20 | var attach = function (){var donut=this.donut;delete this.donut;return donut};
21 | return (typeof attach === 'function') ? attach.apply(this) : attach;
22 | }());
23 | });
24 |
25 | //NOTE: I commented this out for the sake of loading this file during the tests.
26 |
27 | // //see config.js for the wrapJS config being used here
28 | // require(['require', 'config'], function(require){
29 | // // requiring donut will now make sure frosting is loaded first
30 | // require(['wrap!donut'], function (donut) {
31 | // console.log("donut: ", donut);
32 | // // notice that the scripts are available as parameters to this callback, as if it were an AMD module
33 | // console.log('mmm', donut.name);
34 | // console.log('mmm', donut.ingredients[0].name);
35 |
36 | // // also notice the donut variable is no longer available as a global
37 | // console.log('look no more global: ', window.donut);
38 | // });
39 | // });
40 | // define("build-example", function(){});
41 |
--------------------------------------------------------------------------------
/examples-build/js/cheese.js:
--------------------------------------------------------------------------------
1 | cheese = {
2 | name:"cheese"
3 | };
--------------------------------------------------------------------------------
/examples-build/js/config.js:
--------------------------------------------------------------------------------
1 | //wrap the scripts that have dependencies, specify what to return for the AMD module, and remove the script's global
2 | require.config({
3 | paths:{ 'wrap':'../../wrap', 'text':'lib/text'},
4 | wrapJS:{
5 | 'donut':{
6 | deps:['wrap!frosting'],
7 | attach:function () {
8 | var donut = this.donut; // this === window (global)
9 | delete this.donut; //kill the global
10 | return donut; //tell the module what to return
11 | },
12 | path: 'lib/donut'
13 | }
14 | ,'frosting': {
15 | attach: 'frosting',
16 | path: 'lib/frosting'
17 | }
18 | }
19 | });
--------------------------------------------------------------------------------
/examples-build/js/lib/candy.js:
--------------------------------------------------------------------------------
1 | candy = {
2 | name: "candy",
3 | ingredients: [sugar] //depends on the global sugar.js being available
4 | };
--------------------------------------------------------------------------------
/examples-build/js/lib/donut.js:
--------------------------------------------------------------------------------
1 | donut = {
2 | name: "donut",
3 | ingredients: [frosting] //depends on the global sugar.js being available
4 | };
--------------------------------------------------------------------------------
/examples-build/js/lib/frosting.js:
--------------------------------------------------------------------------------
1 | frosting = {
2 | name:"frosting"
3 | };
--------------------------------------------------------------------------------
/examples-build/js/lib/nachos.js:
--------------------------------------------------------------------------------
1 | var nachos = {
2 | name: 'nachos',
3 | ingredients: [cheese] //depends on the global cheese.js being available
4 | };
--------------------------------------------------------------------------------
/examples-build/js/lib/require.js:
--------------------------------------------------------------------------------
1 | /** vim: et:ts=4:sw=4:sts=4
2 | * @license RequireJS 1.0.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
3 | * Available via the MIT or new BSD license.
4 | * see: http://github.com/jrburke/requirejs for details
5 | */
6 | /*jslint strict: false, plusplus: false, sub: true */
7 | /*global window, navigator, document, importScripts, jQuery, setTimeout, opera */
8 | var requirejs, require, define;
9 | (function () {
10 | //Change this version number for each release.
11 | var version = "1.0.7",
12 | commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
13 | cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g,
14 | currDirRegExp = /^\.\//,
15 | jsSuffixRegExp = /\.js$/,
16 | ostring = Object.prototype.toString,
17 | ap = Array.prototype,
18 | aps = ap.slice,
19 | apsp = ap.splice,
20 | isBrowser = !!(typeof window !== "undefined" && navigator && document),
21 | isWebWorker = !isBrowser && typeof importScripts !== "undefined",
22 | //PS3 indicates loaded and complete, but need to wait for complete
23 | //specifically. Sequence is "loading", "loaded", execution,
24 | // then "complete". The UA check is unfortunate, but not sure how
25 | //to feature test w/o causing perf issues.
26 | readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
27 | /^complete$/ : /^(complete|loaded)$/,
28 | defContextName = "_",
29 | //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
30 | isOpera = typeof opera !== "undefined" && opera.toString() === "[object Opera]",
31 | empty = {},
32 | contexts = {},
33 | globalDefQueue = [],
34 | interactiveScript = null,
35 | checkLoadedDepth = 0,
36 | useInteractive = false,
37 | reservedDependencies = {
38 | require: true,
39 | module: true,
40 | exports: true
41 | },
42 | req, cfg = {}, currentlyAddingScript, s, head, baseElement, scripts, script,
43 | src, subPath, mainScript, dataMain, globalI, ctx, jQueryCheck, checkLoadedTimeoutId;
44 |
45 | function isFunction(it) {
46 | return ostring.call(it) === "[object Function]";
47 | }
48 |
49 | function isArray(it) {
50 | return ostring.call(it) === "[object Array]";
51 | }
52 |
53 | /**
54 | * Simple function to mix in properties from source into target,
55 | * but only if target does not already have a property of the same name.
56 | * This is not robust in IE for transferring methods that match
57 | * Object.prototype names, but the uses of mixin here seem unlikely to
58 | * trigger a problem related to that.
59 | */
60 | function mixin(target, source, force) {
61 | for (var prop in source) {
62 | if (!(prop in empty) && (!(prop in target) || force)) {
63 | target[prop] = source[prop];
64 | }
65 | }
66 | return req;
67 | }
68 |
69 | /**
70 | * Constructs an error with a pointer to an URL with more information.
71 | * @param {String} id the error ID that maps to an ID on a web page.
72 | * @param {String} message human readable error.
73 | * @param {Error} [err] the original error, if there is one.
74 | *
75 | * @returns {Error}
76 | */
77 | function makeError(id, msg, err) {
78 | var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
79 | if (err) {
80 | e.originalError = err;
81 | }
82 | return e;
83 | }
84 |
85 | /**
86 | * Used to set up package paths from a packagePaths or packages config object.
87 | * @param {Object} pkgs the object to store the new package config
88 | * @param {Array} currentPackages an array of packages to configure
89 | * @param {String} [dir] a prefix dir to use.
90 | */
91 | function configurePackageDir(pkgs, currentPackages, dir) {
92 | var i, location, pkgObj;
93 |
94 | for (i = 0; (pkgObj = currentPackages[i]); i++) {
95 | pkgObj = typeof pkgObj === "string" ? { name: pkgObj } : pkgObj;
96 | location = pkgObj.location;
97 |
98 | //Add dir to the path, but avoid paths that start with a slash
99 | //or have a colon (indicates a protocol)
100 | if (dir && (!location || (location.indexOf("/") !== 0 && location.indexOf(":") === -1))) {
101 | location = dir + "/" + (location || pkgObj.name);
102 | }
103 |
104 | //Create a brand new object on pkgs, since currentPackages can
105 | //be passed in again, and config.pkgs is the internal transformed
106 | //state for all package configs.
107 | pkgs[pkgObj.name] = {
108 | name: pkgObj.name,
109 | location: location || pkgObj.name,
110 | //Remove leading dot in main, so main paths are normalized,
111 | //and remove any trailing .js, since different package
112 | //envs have different conventions: some use a module name,
113 | //some use a file name.
114 | main: (pkgObj.main || "main")
115 | .replace(currDirRegExp, '')
116 | .replace(jsSuffixRegExp, '')
117 | };
118 | }
119 | }
120 |
121 | /**
122 | * jQuery 1.4.3-1.5.x use a readyWait/ready() pairing to hold DOM
123 | * ready callbacks, but jQuery 1.6 supports a holdReady() API instead.
124 | * At some point remove the readyWait/ready() support and just stick
125 | * with using holdReady.
126 | */
127 | function jQueryHoldReady($, shouldHold) {
128 | if ($.holdReady) {
129 | $.holdReady(shouldHold);
130 | } else if (shouldHold) {
131 | $.readyWait += 1;
132 | } else {
133 | $.ready(true);
134 | }
135 | }
136 |
137 | if (typeof define !== "undefined") {
138 | //If a define is already in play via another AMD loader,
139 | //do not overwrite.
140 | // return;
141 | }
142 |
143 | if (typeof requirejs !== "undefined") {
144 | if (isFunction(requirejs)) {
145 | //Do not overwrite and existing requirejs instance.
146 | return;
147 | } else {
148 | cfg = requirejs;
149 | requirejs = undefined;
150 | }
151 | }
152 |
153 | //Allow for a require config object
154 | if (typeof require !== "undefined" && !isFunction(require)) {
155 | //assume it is a config object.
156 | cfg = require;
157 | require = undefined;
158 | }
159 |
160 | /**
161 | * Creates a new context for use in require and define calls.
162 | * Handle most of the heavy lifting. Do not want to use an object
163 | * with prototype here to avoid using "this" in require, in case it
164 | * needs to be used in more super secure envs that do not want this.
165 | * Also there should not be that many contexts in the page. Usually just
166 | * one for the default context, but could be extra for multiversion cases
167 | * or if a package needs a special context for a dependency that conflicts
168 | * with the standard context.
169 | */
170 | function newContext(contextName) {
171 | var context, resume,
172 | config = {
173 | waitSeconds: 7,
174 | baseUrl: "./",
175 | paths: {},
176 | pkgs: {},
177 | catchError: {}
178 | },
179 | defQueue = [],
180 | specified = {
181 | "require": true,
182 | "exports": true,
183 | "module": true
184 | },
185 | urlMap = {},
186 | defined = {},
187 | loaded = {},
188 | waiting = {},
189 | waitAry = [],
190 | urlFetched = {},
191 | managerCounter = 0,
192 | managerCallbacks = {},
193 | plugins = {},
194 | //Used to indicate which modules in a build scenario
195 | //need to be full executed.
196 | needFullExec = {},
197 | fullExec = {},
198 | resumeDepth = 0;
199 |
200 | /**
201 | * Trims the . and .. from an array of path segments.
202 | * It will keep a leading path segment if a .. will become
203 | * the first path segment, to help with module name lookups,
204 | * which act like paths, but can be remapped. But the end result,
205 | * all paths that use this function should look normalized.
206 | * NOTE: this method MODIFIES the input array.
207 | * @param {Array} ary the array of path segments.
208 | */
209 | function trimDots(ary) {
210 | var i, part;
211 | for (i = 0; (part = ary[i]); i++) {
212 | if (part === ".") {
213 | ary.splice(i, 1);
214 | i -= 1;
215 | } else if (part === "..") {
216 | if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
217 | //End of the line. Keep at least one non-dot
218 | //path segment at the front so it can be mapped
219 | //correctly to disk. Otherwise, there is likely
220 | //no path mapping for a path starting with '..'.
221 | //This can still fail, but catches the most reasonable
222 | //uses of ..
223 | break;
224 | } else if (i > 0) {
225 | ary.splice(i - 1, 2);
226 | i -= 2;
227 | }
228 | }
229 | }
230 | }
231 |
232 | /**
233 | * Given a relative module name, like ./something, normalize it to
234 | * a real name that can be mapped to a path.
235 | * @param {String} name the relative name
236 | * @param {String} baseName a real name that the name arg is relative
237 | * to.
238 | * @returns {String} normalized name
239 | */
240 | function normalize(name, baseName) {
241 | var pkgName, pkgConfig;
242 |
243 | //Adjust any relative paths.
244 | if (name && name.charAt(0) === ".") {
245 | //If have a base name, try to normalize against it,
246 | //otherwise, assume it is a top-level require that will
247 | //be relative to baseUrl in the end.
248 | if (baseName) {
249 | if (config.pkgs[baseName]) {
250 | //If the baseName is a package name, then just treat it as one
251 | //name to concat the name with.
252 | baseName = [baseName];
253 | } else {
254 | //Convert baseName to array, and lop off the last part,
255 | //so that . matches that "directory" and not name of the baseName's
256 | //module. For instance, baseName of "one/two/three", maps to
257 | //"one/two/three.js", but we want the directory, "one/two" for
258 | //this normalization.
259 | baseName = baseName.split("/");
260 | baseName = baseName.slice(0, baseName.length - 1);
261 | }
262 |
263 | name = baseName.concat(name.split("/"));
264 | trimDots(name);
265 |
266 | //Some use of packages may use a . path to reference the
267 | //"main" module name, so normalize for that.
268 | pkgConfig = config.pkgs[(pkgName = name[0])];
269 | name = name.join("/");
270 | if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
271 | name = pkgName;
272 | }
273 | } else if (name.indexOf("./") === 0) {
274 | // No baseName, so this is ID is resolved relative
275 | // to baseUrl, pull off the leading dot.
276 | name = name.substring(2);
277 | }
278 | }
279 | return name;
280 | }
281 |
282 | /**
283 | * Creates a module mapping that includes plugin prefix, module
284 | * name, and path. If parentModuleMap is provided it will
285 | * also normalize the name via require.normalize()
286 | *
287 | * @param {String} name the module name
288 | * @param {String} [parentModuleMap] parent module map
289 | * for the module name, used to resolve relative names.
290 | *
291 | * @returns {Object}
292 | */
293 | function makeModuleMap(name, parentModuleMap) {
294 | var index = name ? name.indexOf("!") : -1,
295 | prefix = null,
296 | parentName = parentModuleMap ? parentModuleMap.name : null,
297 | originalName = name,
298 | normalizedName, url, pluginModule;
299 |
300 | if (index !== -1) {
301 | prefix = name.substring(0, index);
302 | name = name.substring(index + 1, name.length);
303 | }
304 |
305 | if (prefix) {
306 | prefix = normalize(prefix, parentName);
307 | }
308 |
309 | //Account for relative paths if there is a base name.
310 | if (name) {
311 | if (prefix) {
312 | pluginModule = defined[prefix];
313 | if (pluginModule && pluginModule.normalize) {
314 | //Plugin is loaded, use its normalize method.
315 | normalizedName = pluginModule.normalize(name, function (name) {
316 | return normalize(name, parentName);
317 | });
318 | } else {
319 | normalizedName = normalize(name, parentName);
320 | }
321 | } else {
322 | //A regular module.
323 | normalizedName = normalize(name, parentName);
324 |
325 | url = urlMap[normalizedName];
326 | if (!url) {
327 | //Calculate url for the module, if it has a name.
328 | //Use name here since nameToUrl also calls normalize,
329 | //and for relative names that are outside the baseUrl
330 | //this causes havoc. Was thinking of just removing
331 | //parentModuleMap to avoid extra normalization, but
332 | //normalize() still does a dot removal because of
333 | //issue #142, so just pass in name here and redo
334 | //the normalization. Paths outside baseUrl are just
335 | //messy to support.
336 | url = context.nameToUrl(name, null, parentModuleMap);
337 |
338 | //Store the URL mapping for later.
339 | urlMap[normalizedName] = url;
340 | }
341 | }
342 | }
343 |
344 | return {
345 | prefix: prefix,
346 | name: normalizedName,
347 | parentMap: parentModuleMap,
348 | url: url,
349 | originalName: originalName,
350 | fullName: prefix ? prefix + "!" + (normalizedName || '') : normalizedName
351 | };
352 | }
353 |
354 | /**
355 | * Determine if priority loading is done. If so clear the priorityWait
356 | */
357 | function isPriorityDone() {
358 | var priorityDone = true,
359 | priorityWait = config.priorityWait,
360 | priorityName, i;
361 | if (priorityWait) {
362 | for (i = 0; (priorityName = priorityWait[i]); i++) {
363 | if (!loaded[priorityName]) {
364 | priorityDone = false;
365 | break;
366 | }
367 | }
368 | if (priorityDone) {
369 | delete config.priorityWait;
370 | }
371 | }
372 | return priorityDone;
373 | }
374 |
375 | function makeContextModuleFunc(func, relModuleMap, enableBuildCallback) {
376 | return function () {
377 | //A version of a require function that passes a moduleName
378 | //value for items that may need to
379 | //look up paths relative to the moduleName
380 | var args = aps.call(arguments, 0), lastArg;
381 | if (enableBuildCallback &&
382 | isFunction((lastArg = args[args.length - 1]))) {
383 | lastArg.__requireJsBuild = true;
384 | }
385 | args.push(relModuleMap);
386 | return func.apply(null, args);
387 | };
388 | }
389 |
390 | /**
391 | * Helper function that creates a require function object to give to
392 | * modules that ask for it as a dependency. It needs to be specific
393 | * per module because of the implication of path mappings that may
394 | * need to be relative to the module name.
395 | */
396 | function makeRequire(relModuleMap, enableBuildCallback, altRequire) {
397 | var modRequire = makeContextModuleFunc(altRequire || context.require, relModuleMap, enableBuildCallback);
398 |
399 | mixin(modRequire, {
400 | nameToUrl: makeContextModuleFunc(context.nameToUrl, relModuleMap),
401 | toUrl: makeContextModuleFunc(context.toUrl, relModuleMap),
402 | defined: makeContextModuleFunc(context.requireDefined, relModuleMap),
403 | specified: makeContextModuleFunc(context.requireSpecified, relModuleMap),
404 | isBrowser: req.isBrowser
405 | });
406 | return modRequire;
407 | }
408 |
409 | /*
410 | * Queues a dependency for checking after the loader is out of a
411 | * "paused" state, for example while a script file is being loaded
412 | * in the browser, where it may have many modules defined in it.
413 | */
414 | function queueDependency(manager) {
415 | context.paused.push(manager);
416 | }
417 |
418 | function execManager(manager) {
419 | var i, ret, err, errFile, errModuleTree,
420 | cb = manager.callback,
421 | map = manager.map,
422 | fullName = map.fullName,
423 | args = manager.deps,
424 | listeners = manager.listeners,
425 | cjsModule;
426 |
427 | //Call the callback to define the module, if necessary.
428 | if (cb && isFunction(cb)) {
429 | if (config.catchError.define) {
430 | try {
431 | ret = req.execCb(fullName, manager.callback, args, defined[fullName]);
432 | } catch (e) {
433 | err = e;
434 | }
435 | } else {
436 | ret = req.execCb(fullName, manager.callback, args, defined[fullName]);
437 | }
438 |
439 | if (fullName) {
440 | //If setting exports via "module" is in play,
441 | //favor that over return value and exports. After that,
442 | //favor a non-undefined return value over exports use.
443 | cjsModule = manager.cjsModule;
444 | if (cjsModule &&
445 | cjsModule.exports !== undefined &&
446 | //Make sure it is not already the exports value
447 | cjsModule.exports !== defined[fullName]) {
448 | ret = defined[fullName] = manager.cjsModule.exports;
449 | } else if (ret === undefined && manager.usingExports) {
450 | //exports already set the defined value.
451 | ret = defined[fullName];
452 | } else {
453 | //Use the return value from the function.
454 | defined[fullName] = ret;
455 | //If this module needed full execution in a build
456 | //environment, mark that now.
457 | if (needFullExec[fullName]) {
458 | fullExec[fullName] = true;
459 | }
460 | }
461 | }
462 | } else if (fullName) {
463 | //May just be an object definition for the module. Only
464 | //worry about defining if have a module name.
465 | ret = defined[fullName] = cb;
466 |
467 | //If this module needed full execution in a build
468 | //environment, mark that now.
469 | if (needFullExec[fullName]) {
470 | fullExec[fullName] = true;
471 | }
472 | }
473 |
474 | //Clean up waiting. Do this before error calls, and before
475 | //calling back listeners, so that bookkeeping is correct
476 | //in the event of an error and error is reported in correct order,
477 | //since the listeners will likely have errors if the
478 | //onError function does not throw.
479 | if (waiting[manager.id]) {
480 | delete waiting[manager.id];
481 | manager.isDone = true;
482 | context.waitCount -= 1;
483 | if (context.waitCount === 0) {
484 | //Clear the wait array used for cycles.
485 | waitAry = [];
486 | }
487 | }
488 |
489 | //Do not need to track manager callback now that it is defined.
490 | delete managerCallbacks[fullName];
491 |
492 | //Allow instrumentation like the optimizer to know the order
493 | //of modules executed and their dependencies.
494 | if (req.onResourceLoad && !manager.placeholder) {
495 | req.onResourceLoad(context, map, manager.depArray);
496 | }
497 |
498 | if (err) {
499 | errFile = (fullName ? makeModuleMap(fullName).url : '') ||
500 | err.fileName || err.sourceURL;
501 | errModuleTree = err.moduleTree;
502 | err = makeError('defineerror', 'Error evaluating ' +
503 | 'module "' + fullName + '" at location "' +
504 | errFile + '":\n' +
505 | err + '\nfileName:' + errFile +
506 | '\nlineNumber: ' + (err.lineNumber || err.line), err);
507 | err.moduleName = fullName;
508 | err.moduleTree = errModuleTree;
509 | return req.onError(err);
510 | }
511 |
512 | //Let listeners know of this manager's value.
513 | for (i = 0; (cb = listeners[i]); i++) {
514 | cb(ret);
515 | }
516 |
517 | return undefined;
518 | }
519 |
520 | /**
521 | * Helper that creates a callack function that is called when a dependency
522 | * is ready, and sets the i-th dependency for the manager as the
523 | * value passed to the callback generated by this function.
524 | */
525 | function makeArgCallback(manager, i) {
526 | return function (value) {
527 | //Only do the work if it has not been done
528 | //already for a dependency. Cycle breaking
529 | //logic in forceExec could mean this function
530 | //is called more than once for a given dependency.
531 | if (!manager.depDone[i]) {
532 | manager.depDone[i] = true;
533 | manager.deps[i] = value;
534 | manager.depCount -= 1;
535 | if (!manager.depCount) {
536 | //All done, execute!
537 | execManager(manager);
538 | }
539 | }
540 | };
541 | }
542 |
543 | function callPlugin(pluginName, depManager) {
544 | var map = depManager.map,
545 | fullName = map.fullName,
546 | name = map.name,
547 | plugin = plugins[pluginName] ||
548 | (plugins[pluginName] = defined[pluginName]),
549 | load;
550 |
551 | //No need to continue if the manager is already
552 | //in the process of loading.
553 | if (depManager.loading) {
554 | return;
555 | }
556 | depManager.loading = true;
557 |
558 | load = function (ret) {
559 | depManager.callback = function () {
560 | return ret;
561 | };
562 | execManager(depManager);
563 |
564 | loaded[depManager.id] = true;
565 |
566 | //The loading of this plugin
567 | //might have placed other things
568 | //in the paused queue. In particular,
569 | //a loader plugin that depends on
570 | //a different plugin loaded resource.
571 | resume();
572 | };
573 |
574 | //Allow plugins to load other code without having to know the
575 | //context or how to "complete" the load.
576 | load.fromText = function (moduleName, text) {
577 | /*jslint evil: true */
578 | var hasInteractive = useInteractive;
579 |
580 | //Indicate a the module is in process of loading.
581 | loaded[moduleName] = false;
582 | context.scriptCount += 1;
583 |
584 | //Indicate this is not a "real" module, so do not track it
585 | //for builds, it does not map to a real file.
586 | context.fake[moduleName] = true;
587 |
588 | //Turn off interactive script matching for IE for any define
589 | //calls in the text, then turn it back on at the end.
590 | if (hasInteractive) {
591 | useInteractive = false;
592 | }
593 |
594 | req.exec(text);
595 |
596 | if (hasInteractive) {
597 | useInteractive = true;
598 | }
599 |
600 | //Support anonymous modules.
601 | context.completeLoad(moduleName);
602 | };
603 |
604 | //No need to continue if the plugin value has already been
605 | //defined by a build.
606 | if (fullName in defined) {
607 | load(defined[fullName]);
608 | } else {
609 | //Use parentName here since the plugin's name is not reliable,
610 | //could be some weird string with no path that actually wants to
611 | //reference the parentName's path.
612 | plugin.load(name, makeRequire(map.parentMap, true, function (deps, cb) {
613 | var moduleDeps = [],
614 | i, dep, depMap;
615 | //Convert deps to full names and hold on to them
616 | //for reference later, when figuring out if they
617 | //are blocked by a circular dependency.
618 | for (i = 0; (dep = deps[i]); i++) {
619 | depMap = makeModuleMap(dep, map.parentMap);
620 | deps[i] = depMap.fullName;
621 | if (!depMap.prefix) {
622 | moduleDeps.push(deps[i]);
623 | }
624 | }
625 | depManager.moduleDeps = (depManager.moduleDeps || []).concat(moduleDeps);
626 | return context.require(deps, cb);
627 | }), load, config);
628 | }
629 | }
630 |
631 | /**
632 | * Adds the manager to the waiting queue. Only fully
633 | * resolved items should be in the waiting queue.
634 | */
635 | function addWait(manager) {
636 | if (!waiting[manager.id]) {
637 | waiting[manager.id] = manager;
638 | waitAry.push(manager);
639 | context.waitCount += 1;
640 | }
641 | }
642 |
643 | /**
644 | * Function added to every manager object. Created out here
645 | * to avoid new function creation for each manager instance.
646 | */
647 | function managerAdd(cb) {
648 | this.listeners.push(cb);
649 | }
650 |
651 | function getManager(map, shouldQueue) {
652 | var fullName = map.fullName,
653 | prefix = map.prefix,
654 | plugin = prefix ? plugins[prefix] ||
655 | (plugins[prefix] = defined[prefix]) : null,
656 | manager, created, pluginManager, prefixMap;
657 |
658 | if (fullName) {
659 | manager = managerCallbacks[fullName];
660 | }
661 |
662 | if (!manager) {
663 | created = true;
664 | manager = {
665 | //ID is just the full name, but if it is a plugin resource
666 | //for a plugin that has not been loaded,
667 | //then add an ID counter to it.
668 | id: (prefix && !plugin ?
669 | (managerCounter++) + '__p@:' : '') +
670 | (fullName || '__r@' + (managerCounter++)),
671 | map: map,
672 | depCount: 0,
673 | depDone: [],
674 | depCallbacks: [],
675 | deps: [],
676 | listeners: [],
677 | add: managerAdd
678 | };
679 |
680 | specified[manager.id] = true;
681 |
682 | //Only track the manager/reuse it if this is a non-plugin
683 | //resource. Also only track plugin resources once
684 | //the plugin has been loaded, and so the fullName is the
685 | //true normalized value.
686 | if (fullName && (!prefix || plugins[prefix])) {
687 | managerCallbacks[fullName] = manager;
688 | }
689 | }
690 |
691 | //If there is a plugin needed, but it is not loaded,
692 | //first load the plugin, then continue on.
693 | if (prefix && !plugin) {
694 | prefixMap = makeModuleMap(prefix);
695 |
696 | //Clear out defined and urlFetched if the plugin was previously
697 | //loaded/defined, but not as full module (as in a build
698 | //situation). However, only do this work if the plugin is in
699 | //defined but does not have a module export value.
700 | if (prefix in defined && !defined[prefix]) {
701 | delete defined[prefix];
702 | delete urlFetched[prefixMap.url];
703 | }
704 |
705 | pluginManager = getManager(prefixMap, true);
706 | pluginManager.add(function (plugin) {
707 | //Create a new manager for the normalized
708 | //resource ID and have it call this manager when
709 | //done.
710 | var newMap = makeModuleMap(map.originalName, map.parentMap),
711 | normalizedManager = getManager(newMap, true);
712 |
713 | //Indicate this manager is a placeholder for the real,
714 | //normalized thing. Important for when trying to map
715 | //modules and dependencies, for instance, in a build.
716 | manager.placeholder = true;
717 |
718 | normalizedManager.add(function (resource) {
719 | manager.callback = function () {
720 | return resource;
721 | };
722 | execManager(manager);
723 | });
724 | });
725 | } else if (created && shouldQueue) {
726 | //Indicate the resource is not loaded yet if it is to be
727 | //queued.
728 | loaded[manager.id] = false;
729 | queueDependency(manager);
730 | addWait(manager);
731 | }
732 |
733 | return manager;
734 | }
735 |
736 | function main(inName, depArray, callback, relModuleMap) {
737 | var moduleMap = makeModuleMap(inName, relModuleMap),
738 | name = moduleMap.name,
739 | fullName = moduleMap.fullName,
740 | manager = getManager(moduleMap),
741 | id = manager.id,
742 | deps = manager.deps,
743 | i, depArg, depName, depPrefix, cjsMod;
744 |
745 | if (fullName) {
746 | //If module already defined for context, or already loaded,
747 | //then leave. Also leave if jQuery is registering but it does
748 | //not match the desired version number in the config.
749 | if (fullName in defined || loaded[id] === true ||
750 | (fullName === "jquery" && config.jQuery &&
751 | config.jQuery !== callback().fn.jquery)) {
752 | return;
753 | }
754 |
755 | //Set specified/loaded here for modules that are also loaded
756 | //as part of a layer, where onScriptLoad is not fired
757 | //for those cases. Do this after the inline define and
758 | //dependency tracing is done.
759 | specified[id] = true;
760 | loaded[id] = true;
761 |
762 | //If module is jQuery set up delaying its dom ready listeners.
763 | if (fullName === "jquery" && callback) {
764 | jQueryCheck(callback());
765 | }
766 | }
767 |
768 | //Attach real depArray and callback to the manager. Do this
769 | //only if the module has not been defined already, so do this after
770 | //the fullName checks above. IE can call main() more than once
771 | //for a module.
772 | manager.depArray = depArray;
773 | manager.callback = callback;
774 |
775 | //Add the dependencies to the deps field, and register for callbacks
776 | //on the dependencies.
777 | for (i = 0; i < depArray.length; i++) {
778 | depArg = depArray[i];
779 | //There could be cases like in IE, where a trailing comma will
780 | //introduce a null dependency, so only treat a real dependency
781 | //value as a dependency.
782 | if (depArg) {
783 | //Split the dependency name into plugin and name parts
784 | depArg = makeModuleMap(depArg, (name ? moduleMap : relModuleMap));
785 | depName = depArg.fullName;
786 | depPrefix = depArg.prefix;
787 |
788 | //Fix the name in depArray to be just the name, since
789 | //that is how it will be called back later.
790 | depArray[i] = depName;
791 |
792 | //Fast path CommonJS standard dependencies.
793 | if (depName === "require") {
794 | deps[i] = makeRequire(moduleMap);
795 | } else if (depName === "exports") {
796 | //CommonJS module spec 1.1
797 | deps[i] = defined[fullName] = {};
798 | manager.usingExports = true;
799 | } else if (depName === "module") {
800 | //CommonJS module spec 1.1
801 | manager.cjsModule = cjsMod = deps[i] = {
802 | id: name,
803 | uri: name ? context.nameToUrl(name, null, relModuleMap) : undefined,
804 | exports: defined[fullName]
805 | };
806 | } else if (depName in defined && !(depName in waiting) &&
807 | (!(fullName in needFullExec) ||
808 | (fullName in needFullExec && fullExec[depName]))) {
809 | //Module already defined, and not in a build situation
810 | //where the module is a something that needs full
811 | //execution and this dependency has not been fully
812 | //executed. See r.js's requirePatch.js for more info
813 | //on fullExec.
814 | deps[i] = defined[depName];
815 | } else {
816 | //Mark this dependency as needing full exec if
817 | //the current module needs full exec.
818 | if (fullName in needFullExec) {
819 | needFullExec[depName] = true;
820 | //Reset state so fully executed code will get
821 | //picked up correctly.
822 | delete defined[depName];
823 | urlFetched[depArg.url] = false;
824 | }
825 |
826 | //Either a resource that is not loaded yet, or a plugin
827 | //resource for either a plugin that has not
828 | //loaded yet.
829 | manager.depCount += 1;
830 | manager.depCallbacks[i] = makeArgCallback(manager, i);
831 | getManager(depArg, true).add(manager.depCallbacks[i]);
832 | }
833 | }
834 | }
835 |
836 | //Do not bother tracking the manager if it is all done.
837 | if (!manager.depCount) {
838 | //All done, execute!
839 | execManager(manager);
840 | } else {
841 | addWait(manager);
842 | }
843 | }
844 |
845 | /**
846 | * Convenience method to call main for a define call that was put on
847 | * hold in the defQueue.
848 | */
849 | function callDefMain(args) {
850 | main.apply(null, args);
851 | }
852 |
853 | /**
854 | * jQuery 1.4.3+ supports ways to hold off calling
855 | * calling jQuery ready callbacks until all scripts are loaded. Be sure
856 | * to track it if the capability exists.. Also, since jQuery 1.4.3 does
857 | * not register as a module, need to do some global inference checking.
858 | * Even if it does register as a module, not guaranteed to be the precise
859 | * name of the global. If a jQuery is tracked for this context, then go
860 | * ahead and register it as a module too, if not already in process.
861 | */
862 | jQueryCheck = function (jqCandidate) {
863 | if (!context.jQuery) {
864 | var $ = jqCandidate || (typeof jQuery !== "undefined" ? jQuery : null);
865 |
866 | if ($) {
867 | //If a specific version of jQuery is wanted, make sure to only
868 | //use this jQuery if it matches.
869 | if (config.jQuery && $.fn.jquery !== config.jQuery) {
870 | return;
871 | }
872 |
873 | if ("holdReady" in $ || "readyWait" in $) {
874 | context.jQuery = $;
875 |
876 | //Manually create a "jquery" module entry if not one already
877 | //or in process. Note this could trigger an attempt at
878 | //a second jQuery registration, but does no harm since
879 | //the first one wins, and it is the same value anyway.
880 | callDefMain(["jquery", [], function () {
881 | return jQuery;
882 | }]);
883 |
884 | //Ask jQuery to hold DOM ready callbacks.
885 | if (context.scriptCount) {
886 | jQueryHoldReady($, true);
887 | context.jQueryIncremented = true;
888 | }
889 | }
890 | }
891 | }
892 | };
893 |
894 | function findCycle(manager, traced) {
895 | var fullName = manager.map.fullName,
896 | depArray = manager.depArray,
897 | fullyLoaded = true,
898 | i, depName, depManager, result;
899 |
900 | if (manager.isDone || !fullName || !loaded[fullName]) {
901 | return result;
902 | }
903 |
904 | //Found the cycle.
905 | if (traced[fullName]) {
906 | return manager;
907 | }
908 |
909 | traced[fullName] = true;
910 |
911 | //Trace through the dependencies.
912 | if (depArray) {
913 | for (i = 0; i < depArray.length; i++) {
914 | //Some array members may be null, like if a trailing comma
915 | //IE, so do the explicit [i] access and check if it has a value.
916 | depName = depArray[i];
917 | if (!loaded[depName] && !reservedDependencies[depName]) {
918 | fullyLoaded = false;
919 | break;
920 | }
921 | depManager = waiting[depName];
922 | if (depManager && !depManager.isDone && loaded[depName]) {
923 | result = findCycle(depManager, traced);
924 | if (result) {
925 | break;
926 | }
927 | }
928 | }
929 | if (!fullyLoaded) {
930 | //Discard the cycle that was found, since it cannot
931 | //be forced yet. Also clear this module from traced.
932 | result = undefined;
933 | delete traced[fullName];
934 | }
935 | }
936 |
937 | return result;
938 | }
939 |
940 | function forceExec(manager, traced) {
941 | var fullName = manager.map.fullName,
942 | depArray = manager.depArray,
943 | i, depName, depManager, prefix, prefixManager, value;
944 |
945 |
946 | if (manager.isDone || !fullName || !loaded[fullName]) {
947 | return undefined;
948 | }
949 |
950 | if (fullName) {
951 | if (traced[fullName]) {
952 | return defined[fullName];
953 | }
954 |
955 | traced[fullName] = true;
956 | }
957 |
958 | //Trace through the dependencies.
959 | if (depArray) {
960 | for (i = 0; i < depArray.length; i++) {
961 | //Some array members may be null, like if a trailing comma
962 | //IE, so do the explicit [i] access and check if it has a value.
963 | depName = depArray[i];
964 | if (depName) {
965 | //First, make sure if it is a plugin resource that the
966 | //plugin is not blocked.
967 | prefix = makeModuleMap(depName).prefix;
968 | if (prefix && (prefixManager = waiting[prefix])) {
969 | forceExec(prefixManager, traced);
970 | }
971 | depManager = waiting[depName];
972 | if (depManager && !depManager.isDone && loaded[depName]) {
973 | value = forceExec(depManager, traced);
974 | manager.depCallbacks[i](value);
975 | }
976 | }
977 | }
978 | }
979 |
980 | return defined[fullName];
981 | }
982 |
983 | /**
984 | * Checks if all modules for a context are loaded, and if so, evaluates the
985 | * new ones in right dependency order.
986 | *
987 | * @private
988 | */
989 | function checkLoaded() {
990 | var waitInterval = config.waitSeconds * 1000,
991 | //It is possible to disable the wait interval by using waitSeconds of 0.
992 | expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
993 | noLoads = "", hasLoadedProp = false, stillLoading = false,
994 | cycleDeps = [],
995 | i, prop, err, manager, cycleManager, moduleDeps;
996 |
997 | //If there are items still in the paused queue processing wait.
998 | //This is particularly important in the sync case where each paused
999 | //item is processed right away but there may be more waiting.
1000 | if (context.pausedCount > 0) {
1001 | return undefined;
1002 | }
1003 |
1004 | //Determine if priority loading is done. If so clear the priority. If
1005 | //not, then do not check
1006 | if (config.priorityWait) {
1007 | if (isPriorityDone()) {
1008 | //Call resume, since it could have
1009 | //some waiting dependencies to trace.
1010 | resume();
1011 | } else {
1012 | return undefined;
1013 | }
1014 | }
1015 |
1016 | //See if anything is still in flight.
1017 | for (prop in loaded) {
1018 | if (!(prop in empty)) {
1019 | hasLoadedProp = true;
1020 | if (!loaded[prop]) {
1021 | if (expired) {
1022 | noLoads += prop + " ";
1023 | } else {
1024 | stillLoading = true;
1025 | if (prop.indexOf('!') === -1) {
1026 | //No reason to keep looking for unfinished
1027 | //loading. If the only stillLoading is a
1028 | //plugin resource though, keep going,
1029 | //because it may be that a plugin resource
1030 | //is waiting on a non-plugin cycle.
1031 | cycleDeps = [];
1032 | break;
1033 | } else {
1034 | moduleDeps = managerCallbacks[prop] && managerCallbacks[prop].moduleDeps;
1035 | if (moduleDeps) {
1036 | cycleDeps.push.apply(cycleDeps, moduleDeps);
1037 | }
1038 | }
1039 | }
1040 | }
1041 | }
1042 | }
1043 |
1044 | //Check for exit conditions.
1045 | if (!hasLoadedProp && !context.waitCount) {
1046 | //If the loaded object had no items, then the rest of
1047 | //the work below does not need to be done.
1048 | return undefined;
1049 | }
1050 | if (expired && noLoads) {
1051 | //If wait time expired, throw error of unloaded modules.
1052 | err = makeError("timeout", "Load timeout for modules: " + noLoads);
1053 | err.requireType = "timeout";
1054 | err.requireModules = noLoads;
1055 | err.contextName = context.contextName;
1056 | return req.onError(err);
1057 | }
1058 |
1059 | //If still loading but a plugin is waiting on a regular module cycle
1060 | //break the cycle.
1061 | if (stillLoading && cycleDeps.length) {
1062 | for (i = 0; (manager = waiting[cycleDeps[i]]); i++) {
1063 | if ((cycleManager = findCycle(manager, {}))) {
1064 | forceExec(cycleManager, {});
1065 | break;
1066 | }
1067 | }
1068 |
1069 | }
1070 |
1071 | //If still waiting on loads, and the waiting load is something
1072 | //other than a plugin resource, or there are still outstanding
1073 | //scripts, then just try back later.
1074 | if (!expired && (stillLoading || context.scriptCount)) {
1075 | //Something is still waiting to load. Wait for it, but only
1076 | //if a timeout is not already in effect.
1077 | if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
1078 | checkLoadedTimeoutId = setTimeout(function () {
1079 | checkLoadedTimeoutId = 0;
1080 | checkLoaded();
1081 | }, 50);
1082 | }
1083 | return undefined;
1084 | }
1085 |
1086 | //If still have items in the waiting cue, but all modules have
1087 | //been loaded, then it means there are some circular dependencies
1088 | //that need to be broken.
1089 | //However, as a waiting thing is fired, then it can add items to
1090 | //the waiting cue, and those items should not be fired yet, so
1091 | //make sure to redo the checkLoaded call after breaking a single
1092 | //cycle, if nothing else loaded then this logic will pick it up
1093 | //again.
1094 | if (context.waitCount) {
1095 | //Cycle through the waitAry, and call items in sequence.
1096 | for (i = 0; (manager = waitAry[i]); i++) {
1097 | forceExec(manager, {});
1098 | }
1099 |
1100 | //If anything got placed in the paused queue, run it down.
1101 | if (context.paused.length) {
1102 | resume();
1103 | }
1104 |
1105 | //Only allow this recursion to a certain depth. Only
1106 | //triggered by errors in calling a module in which its
1107 | //modules waiting on it cannot finish loading, or some circular
1108 | //dependencies that then may add more dependencies.
1109 | //The value of 5 is a bit arbitrary. Hopefully just one extra
1110 | //pass, or two for the case of circular dependencies generating
1111 | //more work that gets resolved in the sync node case.
1112 | if (checkLoadedDepth < 5) {
1113 | checkLoadedDepth += 1;
1114 | checkLoaded();
1115 | }
1116 | }
1117 |
1118 | checkLoadedDepth = 0;
1119 |
1120 | //Check for DOM ready, and nothing is waiting across contexts.
1121 | req.checkReadyState();
1122 |
1123 | return undefined;
1124 | }
1125 |
1126 | /**
1127 | * Resumes tracing of dependencies and then checks if everything is loaded.
1128 | */
1129 | resume = function () {
1130 | var manager, map, url, i, p, args, fullName;
1131 |
1132 | //Any defined modules in the global queue, intake them now.
1133 | context.takeGlobalQueue();
1134 |
1135 | resumeDepth += 1;
1136 |
1137 | if (context.scriptCount <= 0) {
1138 | //Synchronous envs will push the number below zero with the
1139 | //decrement above, be sure to set it back to zero for good measure.
1140 | //require() calls that also do not end up loading scripts could
1141 | //push the number negative too.
1142 | context.scriptCount = 0;
1143 | }
1144 |
1145 | //Make sure any remaining defQueue items get properly processed.
1146 | while (defQueue.length) {
1147 | args = defQueue.shift();
1148 | if (args[0] === null) {
1149 | return req.onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
1150 | } else {
1151 | callDefMain(args);
1152 | }
1153 | }
1154 |
1155 | //Skip the resume of paused dependencies
1156 | //if current context is in priority wait.
1157 | if (!config.priorityWait || isPriorityDone()) {
1158 | while (context.paused.length) {
1159 | p = context.paused;
1160 | context.pausedCount += p.length;
1161 | //Reset paused list
1162 | context.paused = [];
1163 |
1164 | for (i = 0; (manager = p[i]); i++) {
1165 | map = manager.map;
1166 | url = map.url;
1167 | fullName = map.fullName;
1168 |
1169 | //If the manager is for a plugin managed resource,
1170 | //ask the plugin to load it now.
1171 | if (map.prefix) {
1172 | callPlugin(map.prefix, manager);
1173 | } else {
1174 | //Regular dependency.
1175 | if (!urlFetched[url] && !loaded[fullName]) {
1176 | req.load(context, fullName, url);
1177 |
1178 | //Mark the URL as fetched, but only if it is
1179 | //not an empty: URL, used by the optimizer.
1180 | //In that case we need to be sure to call
1181 | //load() for each module that is mapped to
1182 | //empty: so that dependencies are satisfied
1183 | //correctly.
1184 | if (url.indexOf('empty:') !== 0) {
1185 | urlFetched[url] = true;
1186 | }
1187 | }
1188 | }
1189 | }
1190 |
1191 | //Move the start time for timeout forward.
1192 | context.startTime = (new Date()).getTime();
1193 | context.pausedCount -= p.length;
1194 | }
1195 | }
1196 |
1197 | //Only check if loaded when resume depth is 1. It is likely that
1198 | //it is only greater than 1 in sync environments where a factory
1199 | //function also then calls the callback-style require. In those
1200 | //cases, the checkLoaded should not occur until the resume
1201 | //depth is back at the top level.
1202 | if (resumeDepth === 1) {
1203 | checkLoaded();
1204 | }
1205 |
1206 | resumeDepth -= 1;
1207 |
1208 | return undefined;
1209 | };
1210 |
1211 | //Define the context object. Many of these fields are on here
1212 | //just to make debugging easier.
1213 | context = {
1214 | contextName: contextName,
1215 | config: config,
1216 | defQueue: defQueue,
1217 | waiting: waiting,
1218 | waitCount: 0,
1219 | specified: specified,
1220 | loaded: loaded,
1221 | urlMap: urlMap,
1222 | urlFetched: urlFetched,
1223 | scriptCount: 0,
1224 | defined: defined,
1225 | paused: [],
1226 | pausedCount: 0,
1227 | plugins: plugins,
1228 | needFullExec: needFullExec,
1229 | fake: {},
1230 | fullExec: fullExec,
1231 | managerCallbacks: managerCallbacks,
1232 | makeModuleMap: makeModuleMap,
1233 | normalize: normalize,
1234 | /**
1235 | * Set a configuration for the context.
1236 | * @param {Object} cfg config object to integrate.
1237 | */
1238 | configure: function (cfg) {
1239 | var paths, prop, packages, pkgs, packagePaths, requireWait;
1240 |
1241 | //Make sure the baseUrl ends in a slash.
1242 | if (cfg.baseUrl) {
1243 | if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== "/") {
1244 | cfg.baseUrl += "/";
1245 | }
1246 | }
1247 |
1248 | //Save off the paths and packages since they require special processing,
1249 | //they are additive.
1250 | paths = config.paths;
1251 | packages = config.packages;
1252 | pkgs = config.pkgs;
1253 |
1254 | //Mix in the config values, favoring the new values over
1255 | //existing ones in context.config.
1256 | mixin(config, cfg, true);
1257 |
1258 | //Adjust paths if necessary.
1259 | if (cfg.paths) {
1260 | for (prop in cfg.paths) {
1261 | if (!(prop in empty)) {
1262 | paths[prop] = cfg.paths[prop];
1263 | }
1264 | }
1265 | config.paths = paths;
1266 | }
1267 |
1268 | packagePaths = cfg.packagePaths;
1269 | if (packagePaths || cfg.packages) {
1270 | //Convert packagePaths into a packages config.
1271 | if (packagePaths) {
1272 | for (prop in packagePaths) {
1273 | if (!(prop in empty)) {
1274 | configurePackageDir(pkgs, packagePaths[prop], prop);
1275 | }
1276 | }
1277 | }
1278 |
1279 | //Adjust packages if necessary.
1280 | if (cfg.packages) {
1281 | configurePackageDir(pkgs, cfg.packages);
1282 | }
1283 |
1284 | //Done with modifications, assing packages back to context config
1285 | config.pkgs = pkgs;
1286 | }
1287 |
1288 | //If priority loading is in effect, trigger the loads now
1289 | if (cfg.priority) {
1290 | //Hold on to requireWait value, and reset it after done
1291 | requireWait = context.requireWait;
1292 |
1293 | //Allow tracing some require calls to allow the fetching
1294 | //of the priority config.
1295 | context.requireWait = false;
1296 | //But first, call resume to register any defined modules that may
1297 | //be in a data-main built file before the priority config
1298 | //call.
1299 | resume();
1300 |
1301 | context.require(cfg.priority);
1302 |
1303 | //Trigger a resume right away, for the case when
1304 | //the script with the priority load is done as part
1305 | //of a data-main call. In that case the normal resume
1306 | //call will not happen because the scriptCount will be
1307 | //at 1, since the script for data-main is being processed.
1308 | resume();
1309 |
1310 | //Restore previous state.
1311 | context.requireWait = requireWait;
1312 | config.priorityWait = cfg.priority;
1313 | }
1314 |
1315 | //If a deps array or a config callback is specified, then call
1316 | //require with those args. This is useful when require is defined as a
1317 | //config object before require.js is loaded.
1318 | if (cfg.deps || cfg.callback) {
1319 | context.require(cfg.deps || [], cfg.callback);
1320 | }
1321 | },
1322 |
1323 | requireDefined: function (moduleName, relModuleMap) {
1324 | return makeModuleMap(moduleName, relModuleMap).fullName in defined;
1325 | },
1326 |
1327 | requireSpecified: function (moduleName, relModuleMap) {
1328 | return makeModuleMap(moduleName, relModuleMap).fullName in specified;
1329 | },
1330 |
1331 | require: function (deps, callback, relModuleMap) {
1332 | var moduleName, fullName, moduleMap;
1333 | if (typeof deps === "string") {
1334 | if (isFunction(callback)) {
1335 | //Invalid call
1336 | return req.onError(makeError("requireargs", "Invalid require call"));
1337 | }
1338 |
1339 | //Synchronous access to one module. If require.get is
1340 | //available (as in the Node adapter), prefer that.
1341 | //In this case deps is the moduleName and callback is
1342 | //the relModuleMap
1343 | if (req.get) {
1344 | return req.get(context, deps, callback);
1345 | }
1346 |
1347 | //Just return the module wanted. In this scenario, the
1348 | //second arg (if passed) is just the relModuleMap.
1349 | moduleName = deps;
1350 | relModuleMap = callback;
1351 |
1352 | //Normalize module name, if it contains . or ..
1353 | moduleMap = makeModuleMap(moduleName, relModuleMap);
1354 | fullName = moduleMap.fullName;
1355 |
1356 | if (!(fullName in defined)) {
1357 | return req.onError(makeError("notloaded", "Module name '" +
1358 | moduleMap.fullName +
1359 | "' has not been loaded yet for context: " +
1360 | contextName));
1361 | }
1362 | return defined[fullName];
1363 | }
1364 |
1365 | //Call main but only if there are dependencies or
1366 | //a callback to call.
1367 | if (deps && deps.length || callback) {
1368 | main(null, deps, callback, relModuleMap);
1369 | }
1370 |
1371 | //If the require call does not trigger anything new to load,
1372 | //then resume the dependency processing.
1373 | if (!context.requireWait) {
1374 | while (!context.scriptCount && context.paused.length) {
1375 | resume();
1376 | }
1377 | }
1378 | return context.require;
1379 | },
1380 |
1381 | /**
1382 | * Internal method to transfer globalQueue items to this context's
1383 | * defQueue.
1384 | */
1385 | takeGlobalQueue: function () {
1386 | //Push all the globalDefQueue items into the context's defQueue
1387 | if (globalDefQueue.length) {
1388 | //Array splice in the values since the context code has a
1389 | //local var ref to defQueue, so cannot just reassign the one
1390 | //on context.
1391 | apsp.apply(context.defQueue,
1392 | [context.defQueue.length - 1, 0].concat(globalDefQueue));
1393 | globalDefQueue = [];
1394 | }
1395 | },
1396 |
1397 | /**
1398 | * Internal method used by environment adapters to complete a load event.
1399 | * A load event could be a script load or just a load pass from a synchronous
1400 | * load call.
1401 | * @param {String} moduleName the name of the module to potentially complete.
1402 | */
1403 | completeLoad: function (moduleName) {
1404 | var args;
1405 |
1406 | context.takeGlobalQueue();
1407 |
1408 | while (defQueue.length) {
1409 | args = defQueue.shift();
1410 |
1411 | if (args[0] === null) {
1412 | args[0] = moduleName;
1413 | break;
1414 | } else if (args[0] === moduleName) {
1415 | //Found matching define call for this script!
1416 | break;
1417 | } else {
1418 | //Some other named define call, most likely the result
1419 | //of a build layer that included many define calls.
1420 | callDefMain(args);
1421 | args = null;
1422 | }
1423 | }
1424 | if (args) {
1425 | callDefMain(args);
1426 | } else {
1427 | //A script that does not call define(), so just simulate
1428 | //the call for it. Special exception for jQuery dynamic load.
1429 | callDefMain([moduleName, [],
1430 | moduleName === "jquery" && typeof jQuery !== "undefined" ?
1431 | function () {
1432 | return jQuery;
1433 | } : null]);
1434 | }
1435 |
1436 | //Doing this scriptCount decrement branching because sync envs
1437 | //need to decrement after resume, otherwise it looks like
1438 | //loading is complete after the first dependency is fetched.
1439 | //For browsers, it works fine to decrement after, but it means
1440 | //the checkLoaded setTimeout 50 ms cost is taken. To avoid
1441 | //that cost, decrement beforehand.
1442 | if (req.isAsync) {
1443 | context.scriptCount -= 1;
1444 | }
1445 | resume();
1446 | if (!req.isAsync) {
1447 | context.scriptCount -= 1;
1448 | }
1449 | },
1450 |
1451 | /**
1452 | * Converts a module name + .extension into an URL path.
1453 | * *Requires* the use of a module name. It does not support using
1454 | * plain URLs like nameToUrl.
1455 | */
1456 | toUrl: function (moduleNamePlusExt, relModuleMap) {
1457 | var index = moduleNamePlusExt.lastIndexOf("."),
1458 | ext = null;
1459 |
1460 | if (index !== -1) {
1461 | ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
1462 | moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
1463 | }
1464 |
1465 | return context.nameToUrl(moduleNamePlusExt, ext, relModuleMap);
1466 | },
1467 |
1468 | /**
1469 | * Converts a module name to a file path. Supports cases where
1470 | * moduleName may actually be just an URL.
1471 | */
1472 | nameToUrl: function (moduleName, ext, relModuleMap) {
1473 | var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
1474 | config = context.config;
1475 |
1476 | //Normalize module name if have a base relative module name to work from.
1477 | moduleName = normalize(moduleName, relModuleMap && relModuleMap.fullName);
1478 |
1479 | //If a colon is in the URL, it indicates a protocol is used and it is just
1480 | //an URL to a file, or if it starts with a slash or ends with .js, it is just a plain file.
1481 | //The slash is important for protocol-less URLs as well as full paths.
1482 | if (req.jsExtRegExp.test(moduleName)) {
1483 | //Just a plain path, not module name lookup, so just return it.
1484 | //Add extension if it is included. This is a bit wonky, only non-.js things pass
1485 | //an extension, this method probably needs to be reworked.
1486 | url = moduleName + (ext ? ext : "");
1487 | } else {
1488 | //A module that needs to be converted to a path.
1489 | paths = config.paths;
1490 | pkgs = config.pkgs;
1491 |
1492 | syms = moduleName.split("/");
1493 | //For each module name segment, see if there is a path
1494 | //registered for it. Start with most specific name
1495 | //and work up from it.
1496 | for (i = syms.length; i > 0; i--) {
1497 | parentModule = syms.slice(0, i).join("/");
1498 | if (paths[parentModule]) {
1499 | syms.splice(0, i, paths[parentModule]);
1500 | break;
1501 | } else if ((pkg = pkgs[parentModule])) {
1502 | //If module name is just the package name, then looking
1503 | //for the main module.
1504 | if (moduleName === pkg.name) {
1505 | pkgPath = pkg.location + '/' + pkg.main;
1506 | } else {
1507 | pkgPath = pkg.location;
1508 | }
1509 | syms.splice(0, i, pkgPath);
1510 | break;
1511 | }
1512 | }
1513 |
1514 | //Join the path parts together, then figure out if baseUrl is needed.
1515 | url = syms.join("/") + (ext || ".js");
1516 | url = (url.charAt(0) === '/' || url.match(/^\w+:/) ? "" : config.baseUrl) + url;
1517 | }
1518 |
1519 | return config.urlArgs ? url +
1520 | ((url.indexOf('?') === -1 ? '?' : '&') +
1521 | config.urlArgs) : url;
1522 | }
1523 | };
1524 |
1525 | //Make these visible on the context so can be called at the very
1526 | //end of the file to bootstrap
1527 | context.jQueryCheck = jQueryCheck;
1528 | context.resume = resume;
1529 |
1530 | return context;
1531 | }
1532 |
1533 | /**
1534 | * Main entry point.
1535 | *
1536 | * If the only argument to require is a string, then the module that
1537 | * is represented by that string is fetched for the appropriate context.
1538 | *
1539 | * If the first argument is an array, then it will be treated as an array
1540 | * of dependency string names to fetch. An optional function callback can
1541 | * be specified to execute when all of those dependencies are available.
1542 | *
1543 | * Make a local req variable to help Caja compliance (it assumes things
1544 | * on a require that are not standardized), and to give a short
1545 | * name for minification/local scope use.
1546 | */
1547 | req = requirejs = function (deps, callback) {
1548 |
1549 | //Find the right context, use default
1550 | var contextName = defContextName,
1551 | context, config;
1552 |
1553 | // Determine if have config object in the call.
1554 | if (!isArray(deps) && typeof deps !== "string") {
1555 | // deps is a config object
1556 | config = deps;
1557 | if (isArray(callback)) {
1558 | // Adjust args if there are dependencies
1559 | deps = callback;
1560 | callback = arguments[2];
1561 | } else {
1562 | deps = [];
1563 | }
1564 | }
1565 |
1566 | if (config && config.context) {
1567 | contextName = config.context;
1568 | }
1569 |
1570 | context = contexts[contextName] ||
1571 | (contexts[contextName] = newContext(contextName));
1572 |
1573 | if (config) {
1574 | context.configure(config);
1575 | }
1576 |
1577 | return context.require(deps, callback);
1578 | };
1579 |
1580 | /**
1581 | * Support require.config() to make it easier to cooperate with other
1582 | * AMD loaders on globally agreed names.
1583 | */
1584 | req.config = function (config) {
1585 | return req(config);
1586 | };
1587 |
1588 | /**
1589 | * Export require as a global, but only if it does not already exist.
1590 | */
1591 | if (!require) {
1592 | require = req;
1593 | }
1594 |
1595 | /**
1596 | * Global require.toUrl(), to match global require, mostly useful
1597 | * for debugging/work in the global space.
1598 | */
1599 | req.toUrl = function (moduleNamePlusExt) {
1600 | return contexts[defContextName].toUrl(moduleNamePlusExt);
1601 | };
1602 |
1603 | req.version = version;
1604 |
1605 | //Used to filter out dependencies that are already paths.
1606 | req.jsExtRegExp = /^\/|:|\?|\.js$/;
1607 | s = req.s = {
1608 | contexts: contexts,
1609 | //Stores a list of URLs that should not get async script tag treatment.
1610 | skipAsync: {}
1611 | };
1612 |
1613 | req.isAsync = req.isBrowser = isBrowser;
1614 | if (isBrowser) {
1615 | head = s.head = document.getElementsByTagName("head")[0];
1616 | //If BASE tag is in play, using appendChild is a problem for IE6.
1617 | //When that browser dies, this can be removed. Details in this jQuery bug:
1618 | //http://dev.jquery.com/ticket/2709
1619 | baseElement = document.getElementsByTagName("base")[0];
1620 | if (baseElement) {
1621 | head = s.head = baseElement.parentNode;
1622 | }
1623 | }
1624 |
1625 | /**
1626 | * Any errors that require explicitly generates will be passed to this
1627 | * function. Intercept/override it if you want custom error handling.
1628 | * @param {Error} err the error object.
1629 | */
1630 | req.onError = function (err) {
1631 | throw err;
1632 | };
1633 |
1634 | /**
1635 | * Does the request to load a module for the browser case.
1636 | * Make this a separate function to allow other environments
1637 | * to override it.
1638 | *
1639 | * @param {Object} context the require context to find state.
1640 | * @param {String} moduleName the name of the module.
1641 | * @param {Object} url the URL to the module.
1642 | */
1643 | req.load = function (context, moduleName, url) {
1644 | req.resourcesReady(false);
1645 |
1646 | context.scriptCount += 1;
1647 | req.attach(url, context, moduleName);
1648 |
1649 | //If tracking a jQuery, then make sure its ready callbacks
1650 | //are put on hold to prevent its ready callbacks from
1651 | //triggering too soon.
1652 | if (context.jQuery && !context.jQueryIncremented) {
1653 | jQueryHoldReady(context.jQuery, true);
1654 | context.jQueryIncremented = true;
1655 | }
1656 | };
1657 |
1658 | function getInteractiveScript() {
1659 | var scripts, i, script;
1660 | if (interactiveScript && interactiveScript.readyState === 'interactive') {
1661 | return interactiveScript;
1662 | }
1663 |
1664 | scripts = document.getElementsByTagName('script');
1665 | for (i = scripts.length - 1; i > -1 && (script = scripts[i]); i--) {
1666 | if (script.readyState === 'interactive') {
1667 | return (interactiveScript = script);
1668 | }
1669 | }
1670 |
1671 | return null;
1672 | }
1673 |
1674 | /**
1675 | * The function that handles definitions of modules. Differs from
1676 | * require() in that a string for the module should be the first argument,
1677 | * and the function to execute after dependencies are loaded should
1678 | * return a value to define the module corresponding to the first argument's
1679 | * name.
1680 | */
1681 | define = function (name, deps, callback) {
1682 | var node, context;
1683 |
1684 | //Allow for anonymous functions
1685 | if (typeof name !== 'string') {
1686 | //Adjust args appropriately
1687 | callback = deps;
1688 | deps = name;
1689 | name = null;
1690 | }
1691 |
1692 | //This module may not have dependencies
1693 | if (!isArray(deps)) {
1694 | callback = deps;
1695 | deps = [];
1696 | }
1697 |
1698 | //If no name, and callback is a function, then figure out if it a
1699 | //CommonJS thing with dependencies.
1700 | if (!deps.length && isFunction(callback)) {
1701 | //Remove comments from the callback string,
1702 | //look for require calls, and pull them into the dependencies,
1703 | //but only if there are function args.
1704 | if (callback.length) {
1705 | callback
1706 | .toString()
1707 | .replace(commentRegExp, "")
1708 | .replace(cjsRequireRegExp, function (match, dep) {
1709 | deps.push(dep);
1710 | });
1711 |
1712 | //May be a CommonJS thing even without require calls, but still
1713 | //could use exports, and module. Avoid doing exports and module
1714 | //work though if it just needs require.
1715 | //REQUIRES the function to expect the CommonJS variables in the
1716 | //order listed below.
1717 | deps = (callback.length === 1 ? ["require"] : ["require", "exports", "module"]).concat(deps);
1718 | }
1719 | }
1720 |
1721 | //If in IE 6-8 and hit an anonymous define() call, do the interactive
1722 | //work.
1723 | if (useInteractive) {
1724 | node = currentlyAddingScript || getInteractiveScript();
1725 | if (node) {
1726 | if (!name) {
1727 | name = node.getAttribute("data-requiremodule");
1728 | }
1729 | context = contexts[node.getAttribute("data-requirecontext")];
1730 | }
1731 | }
1732 |
1733 | //Always save off evaluating the def call until the script onload handler.
1734 | //This allows multiple modules to be in a file without prematurely
1735 | //tracing dependencies, and allows for anonymous module support,
1736 | //where the module name is not known until the script onload event
1737 | //occurs. If no context, use the global queue, and get it processed
1738 | //in the onscript load callback.
1739 | (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
1740 |
1741 | return undefined;
1742 | };
1743 |
1744 | define.amd = {
1745 | multiversion: true,
1746 | plugins: true,
1747 | jQuery: true
1748 | };
1749 |
1750 | /**
1751 | * Executes the text. Normally just uses eval, but can be modified
1752 | * to use a more environment specific call.
1753 | * @param {String} text the text to execute/evaluate.
1754 | */
1755 | req.exec = function (text) {
1756 | return eval(text);
1757 | };
1758 |
1759 | /**
1760 | * Executes a module callack function. Broken out as a separate function
1761 | * solely to allow the build system to sequence the files in the built
1762 | * layer in the right sequence.
1763 | *
1764 | * @private
1765 | */
1766 | req.execCb = function (name, callback, args, exports) {
1767 | return callback.apply(exports, args);
1768 | };
1769 |
1770 |
1771 | /**
1772 | * Adds a node to the DOM. Public function since used by the order plugin.
1773 | * This method should not normally be called by outside code.
1774 | */
1775 | req.addScriptToDom = function (node) {
1776 | //For some cache cases in IE 6-8, the script executes before the end
1777 | //of the appendChild execution, so to tie an anonymous define
1778 | //call to the module name (which is stored on the node), hold on
1779 | //to a reference to this node, but clear after the DOM insertion.
1780 | currentlyAddingScript = node;
1781 | if (baseElement) {
1782 | head.insertBefore(node, baseElement);
1783 | } else {
1784 | head.appendChild(node);
1785 | }
1786 | currentlyAddingScript = null;
1787 | };
1788 |
1789 | /**
1790 | * callback for script loads, used to check status of loading.
1791 | *
1792 | * @param {Event} evt the event from the browser for the script
1793 | * that was loaded.
1794 | *
1795 | * @private
1796 | */
1797 | req.onScriptLoad = function (evt) {
1798 | //Using currentTarget instead of target for Firefox 2.0's sake. Not
1799 | //all old browsers will be supported, but this one was easy enough
1800 | //to support and still makes sense.
1801 | var node = evt.currentTarget || evt.srcElement, contextName, moduleName,
1802 | context;
1803 |
1804 | if (evt.type === "load" || (node && readyRegExp.test(node.readyState))) {
1805 | //Reset interactive script so a script node is not held onto for
1806 | //to long.
1807 | interactiveScript = null;
1808 |
1809 | //Pull out the name of the module and the context.
1810 | contextName = node.getAttribute("data-requirecontext");
1811 | moduleName = node.getAttribute("data-requiremodule");
1812 | context = contexts[contextName];
1813 |
1814 | contexts[contextName].completeLoad(moduleName);
1815 |
1816 | //Clean up script binding. Favor detachEvent because of IE9
1817 | //issue, see attachEvent/addEventListener comment elsewhere
1818 | //in this file.
1819 | if (node.detachEvent && !isOpera) {
1820 | //Probably IE. If not it will throw an error, which will be
1821 | //useful to know.
1822 | node.detachEvent("onreadystatechange", req.onScriptLoad);
1823 | } else {
1824 | node.removeEventListener("load", req.onScriptLoad, false);
1825 | }
1826 | }
1827 | };
1828 |
1829 | /**
1830 | * Attaches the script represented by the URL to the current
1831 | * environment. Right now only supports browser loading,
1832 | * but can be redefined in other environments to do the right thing.
1833 | * @param {String} url the url of the script to attach.
1834 | * @param {Object} context the context that wants the script.
1835 | * @param {moduleName} the name of the module that is associated with the script.
1836 | * @param {Function} [callback] optional callback, defaults to require.onScriptLoad
1837 | * @param {String} [type] optional type, defaults to text/javascript
1838 | * @param {Function} [fetchOnlyFunction] optional function to indicate the script node
1839 | * should be set up to fetch the script but do not attach it to the DOM
1840 | * so that it can later be attached to execute it. This is a way for the
1841 | * order plugin to support ordered loading in IE. Once the script is fetched,
1842 | * but not executed, the fetchOnlyFunction will be called.
1843 | */
1844 | req.attach = function (url, context, moduleName, callback, type, fetchOnlyFunction) {
1845 | var node;
1846 | if (isBrowser) {
1847 | //In the browser so use a script tag
1848 | callback = callback || req.onScriptLoad;
1849 | node = context && context.config && context.config.xhtml ?
1850 | document.createElementNS("http://www.w3.org/1999/xhtml", "html:script") :
1851 | document.createElement("script");
1852 | node.type = type || (context && context.config.scriptType) ||
1853 | "text/javascript";
1854 | node.charset = "utf-8";
1855 | //Use async so Gecko does not block on executing the script if something
1856 | //like a long-polling comet tag is being run first. Gecko likes
1857 | //to evaluate scripts in DOM order, even for dynamic scripts.
1858 | //It will fetch them async, but only evaluate the contents in DOM
1859 | //order, so a long-polling script tag can delay execution of scripts
1860 | //after it. But telling Gecko we expect async gets us the behavior
1861 | //we want -- execute it whenever it is finished downloading. Only
1862 | //Helps Firefox 3.6+
1863 | //Allow some URLs to not be fetched async. Mostly helps the order!
1864 | //plugin
1865 | node.async = !s.skipAsync[url];
1866 |
1867 | if (context) {
1868 | node.setAttribute("data-requirecontext", context.contextName);
1869 | }
1870 | node.setAttribute("data-requiremodule", moduleName);
1871 |
1872 | //Set up load listener. Test attachEvent first because IE9 has
1873 | //a subtle issue in its addEventListener and script onload firings
1874 | //that do not match the behavior of all other browsers with
1875 | //addEventListener support, which fire the onload event for a
1876 | //script right after the script execution. See:
1877 | //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
1878 | //UNFORTUNATELY Opera implements attachEvent but does not follow the script
1879 | //script execution mode.
1880 | if (node.attachEvent && !isOpera) {
1881 | //Probably IE. IE (at least 6-8) do not fire
1882 | //script onload right after executing the script, so
1883 | //we cannot tie the anonymous define call to a name.
1884 | //However, IE reports the script as being in "interactive"
1885 | //readyState at the time of the define call.
1886 | useInteractive = true;
1887 |
1888 |
1889 | if (fetchOnlyFunction) {
1890 | //Need to use old school onreadystate here since
1891 | //when the event fires and the node is not attached
1892 | //to the DOM, the evt.srcElement is null, so use
1893 | //a closure to remember the node.
1894 | node.onreadystatechange = function (evt) {
1895 | //Script loaded but not executed.
1896 | //Clear loaded handler, set the real one that
1897 | //waits for script execution.
1898 | if (node.readyState === 'loaded') {
1899 | node.onreadystatechange = null;
1900 | node.attachEvent("onreadystatechange", callback);
1901 | fetchOnlyFunction(node);
1902 | }
1903 | };
1904 | } else {
1905 | node.attachEvent("onreadystatechange", callback);
1906 | }
1907 | } else {
1908 | node.addEventListener("load", callback, false);
1909 | }
1910 | node.src = url;
1911 |
1912 | //Fetch only means waiting to attach to DOM after loaded.
1913 | if (!fetchOnlyFunction) {
1914 | req.addScriptToDom(node);
1915 | }
1916 |
1917 | return node;
1918 | } else if (isWebWorker) {
1919 | //In a web worker, use importScripts. This is not a very
1920 | //efficient use of importScripts, importScripts will block until
1921 | //its script is downloaded and evaluated. However, if web workers
1922 | //are in play, the expectation that a build has been done so that
1923 | //only one script needs to be loaded anyway. This may need to be
1924 | //reevaluated if other use cases become common.
1925 | importScripts(url);
1926 |
1927 | //Account for anonymous modules
1928 | context.completeLoad(moduleName);
1929 | }
1930 | return null;
1931 | };
1932 |
1933 | //Look for a data-main script attribute, which could also adjust the baseUrl.
1934 | if (isBrowser) {
1935 | //Figure out baseUrl. Get it from the script tag with require.js in it.
1936 | scripts = document.getElementsByTagName("script");
1937 |
1938 | for (globalI = scripts.length - 1; globalI > -1 && (script = scripts[globalI]); globalI--) {
1939 | //Set the "head" where we can append children by
1940 | //using the script's parent.
1941 | if (!head) {
1942 | head = script.parentNode;
1943 | }
1944 |
1945 | //Look for a data-main attribute to set main script for the page
1946 | //to load. If it is there, the path to data main becomes the
1947 | //baseUrl, if it is not already set.
1948 | if ((dataMain = script.getAttribute('data-main'))) {
1949 | if (!cfg.baseUrl) {
1950 | //Pull off the directory of data-main for use as the
1951 | //baseUrl.
1952 | src = dataMain.split('/');
1953 | mainScript = src.pop();
1954 | subPath = src.length ? src.join('/') + '/' : './';
1955 |
1956 | //Set final config.
1957 | cfg.baseUrl = subPath;
1958 | //Strip off any trailing .js since dataMain is now
1959 | //like a module name.
1960 | dataMain = mainScript.replace(jsSuffixRegExp, '');
1961 | }
1962 |
1963 | //Put the data-main script in the files to load.
1964 | cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
1965 |
1966 | break;
1967 | }
1968 | }
1969 | }
1970 |
1971 | //See if there is nothing waiting across contexts, and if not, trigger
1972 | //resourcesReady.
1973 | req.checkReadyState = function () {
1974 | var contexts = s.contexts, prop;
1975 | for (prop in contexts) {
1976 | if (!(prop in empty)) {
1977 | if (contexts[prop].waitCount) {
1978 | return;
1979 | }
1980 | }
1981 | }
1982 | req.resourcesReady(true);
1983 | };
1984 |
1985 | /**
1986 | * Internal function that is triggered whenever all scripts/resources
1987 | * have been loaded by the loader. Can be overridden by other, for
1988 | * instance the domReady plugin, which wants to know when all resources
1989 | * are loaded.
1990 | */
1991 | req.resourcesReady = function (isReady) {
1992 | var contexts, context, prop;
1993 |
1994 | //First, set the public variable indicating that resources are loading.
1995 | req.resourcesDone = isReady;
1996 |
1997 | if (req.resourcesDone) {
1998 | //If jQuery with DOM ready delayed, release it now.
1999 | contexts = s.contexts;
2000 | for (prop in contexts) {
2001 | if (!(prop in empty)) {
2002 | context = contexts[prop];
2003 | if (context.jQueryIncremented) {
2004 | jQueryHoldReady(context.jQuery, false);
2005 | context.jQueryIncremented = false;
2006 | }
2007 | }
2008 | }
2009 | }
2010 | };
2011 |
2012 | //FF < 3.6 readyState fix. Needed so that domReady plugin
2013 | //works well in that environment, since require.js is normally
2014 | //loaded via an HTML script tag so it will be there before window load,
2015 | //where the domReady plugin is more likely to be loaded after window load.
2016 | req.pageLoaded = function () {
2017 | if (document.readyState !== "complete") {
2018 | document.readyState = "complete";
2019 | }
2020 | };
2021 | if (isBrowser) {
2022 | if (document.addEventListener) {
2023 | if (!document.readyState) {
2024 | document.readyState = "loading";
2025 | window.addEventListener("load", req.pageLoaded, false);
2026 | }
2027 | }
2028 | }
2029 |
2030 | //Set up default context. If require was a configuration object, use that as base config.
2031 | req(cfg);
2032 |
2033 | //If modules are built into require.js, then need to make sure dependencies are
2034 | //traced. Use a setTimeout in the browser world, to allow all the modules to register
2035 | //themselves. In a non-browser env, assume that modules are not built into require.js,
2036 | //which seems odd to do on the server.
2037 | if (req.isAsync && typeof setTimeout !== "undefined") {
2038 | ctx = s.contexts[(cfg.context || defContextName)];
2039 | //Indicate that the script that includes require() is still loading,
2040 | //so that require()'d dependencies are not traced until the end of the
2041 | //file is parsed (approximated via the setTimeout call).
2042 | ctx.requireWait = true;
2043 | setTimeout(function () {
2044 | ctx.requireWait = false;
2045 |
2046 | if (!ctx.scriptCount) {
2047 | ctx.resume();
2048 | }
2049 | req.checkReadyState();
2050 | }, 0);
2051 | }
2052 | }());
2053 |
--------------------------------------------------------------------------------
/examples-build/js/lib/rolls.js:
--------------------------------------------------------------------------------
1 | rolls = {
2 | name: "rolls",
3 | ingredients: [wheat] //depends on the global wheat.js being available
4 | };
--------------------------------------------------------------------------------
/examples-build/js/lib/sugar.js:
--------------------------------------------------------------------------------
1 | sugar = {
2 | name:"sugar"
3 | };
--------------------------------------------------------------------------------
/examples-build/js/lib/text.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license RequireJS text 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3 | * Available via the MIT or new BSD license.
4 | * see: http://github.com/jrburke/requirejs for details
5 | */
6 | /*jslint regexp: false, nomen: false, plusplus: false, strict: false */
7 | /*global require: false, XMLHttpRequest: false, ActiveXObject: false,
8 | define: false, window: false, process: false, Packages: false,
9 | java: false, location: false */
10 | (function () {
11 | var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
12 | xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
13 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im,
14 | hasLocation = typeof location !== 'undefined' && location.href,
15 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
16 | defaultHostName = hasLocation && location.hostname,
17 | defaultPort = hasLocation && (location.port || undefined),
18 | buildMap = [];
19 |
20 | define(function () {
21 | var text, get, fs;
22 |
23 | if (typeof window !== "undefined" && window.navigator && window.document) {
24 | get = function (url, callback) {
25 | var xhr = text.createXhr();
26 | xhr.open('GET', url, true);
27 | xhr.onreadystatechange = function (evt) {
28 | //Do not explicitly handle errors, those should be
29 | //visible via console output in the browser.
30 | if (xhr.readyState === 4) {
31 | callback(xhr.responseText);
32 | }
33 | };
34 | xhr.send(null);
35 | };
36 | } else if (typeof process !== "undefined" &&
37 | process.versions &&
38 | !!process.versions.node) {
39 | //Using special require.nodeRequire, something added by r.js.
40 | fs = require.nodeRequire('fs');
41 |
42 | get = function (url, callback) {
43 | callback(fs.readFileSync(url, 'utf8'));
44 | };
45 | } else if (typeof Packages !== 'undefined') {
46 | //Why Java, why is this so awkward?
47 | get = function (url, callback) {
48 | var encoding = "utf-8",
49 | file = new java.io.File(url),
50 | lineSeparator = java.lang.System.getProperty("line.separator"),
51 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
52 | stringBuffer, line,
53 | content = '';
54 | try {
55 | stringBuffer = new java.lang.StringBuffer();
56 | line = input.readLine();
57 |
58 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
59 | // http://www.unicode.org/faq/utf_bom.html
60 |
61 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
62 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
63 | if (line && line.length() && line.charAt(0) === 0xfeff) {
64 | // Eat the BOM, since we've already found the encoding on this file,
65 | // and we plan to concatenating this buffer with others; the BOM should
66 | // only appear at the top of a file.
67 | line = line.substring(1);
68 | }
69 |
70 | stringBuffer.append(line);
71 |
72 | while ((line = input.readLine()) !== null) {
73 | stringBuffer.append(lineSeparator);
74 | stringBuffer.append(line);
75 | }
76 | //Make sure we return a JavaScript string and not a Java string.
77 | content = String(stringBuffer.toString()); //String
78 | } finally {
79 | input.close();
80 | }
81 | callback(content);
82 | };
83 | }
84 |
85 | text = {
86 | version: '1.0.2',
87 |
88 | strip: function (content) {
89 | //Strips declarations so that external SVG and XML
90 | //documents can be added to a document without worry. Also, if the string
91 | //is an HTML document, only the part inside the body tag is returned.
92 | if (content) {
93 | content = content.replace(xmlRegExp, "");
94 | var matches = content.match(bodyRegExp);
95 | if (matches) {
96 | content = matches[1];
97 | }
98 | } else {
99 | content = "";
100 | }
101 | return content;
102 | },
103 |
104 | jsEscape: function (content) {
105 | return content.replace(/(['\\])/g, '\\$1')
106 | .replace(/[\f]/g, "\\f")
107 | .replace(/[\b]/g, "\\b")
108 | .replace(/[\n]/g, "\\n")
109 | .replace(/[\t]/g, "\\t")
110 | .replace(/[\r]/g, "\\r");
111 | },
112 |
113 | createXhr: function () {
114 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first.
115 | var xhr, i, progId;
116 | if (typeof XMLHttpRequest !== "undefined") {
117 | return new XMLHttpRequest();
118 | } else {
119 | for (i = 0; i < 3; i++) {
120 | progId = progIds[i];
121 | try {
122 | xhr = new ActiveXObject(progId);
123 | } catch (e) {}
124 |
125 | if (xhr) {
126 | progIds = [progId]; // so faster next time
127 | break;
128 | }
129 | }
130 | }
131 |
132 | if (!xhr) {
133 | throw new Error("createXhr(): XMLHttpRequest not available");
134 | }
135 |
136 | return xhr;
137 | },
138 |
139 | get: get,
140 |
141 | /**
142 | * Parses a resource name into its component parts. Resource names
143 | * look like: module/name.ext!strip, where the !strip part is
144 | * optional.
145 | * @param {String} name the resource name
146 | * @returns {Object} with properties "moduleName", "ext" and "strip"
147 | * where strip is a boolean.
148 | */
149 | parseName: function (name) {
150 | var strip = false, index = name.indexOf("."),
151 | modName = name.substring(0, index),
152 | ext = name.substring(index + 1, name.length);
153 |
154 | index = ext.indexOf("!");
155 | if (index !== -1) {
156 | //Pull off the strip arg.
157 | strip = ext.substring(index + 1, ext.length);
158 | strip = strip === "strip";
159 | ext = ext.substring(0, index);
160 | }
161 |
162 | return {
163 | moduleName: modName,
164 | ext: ext,
165 | strip: strip
166 | };
167 | },
168 |
169 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
170 |
171 | /**
172 | * Is an URL on another domain. Only works for browser use, returns
173 | * false in non-browser environments. Only used to know if an
174 | * optimized .js version of a text resource should be loaded
175 | * instead.
176 | * @param {String} url
177 | * @returns Boolean
178 | */
179 | useXhr: function (url, protocol, hostname, port) {
180 | var match = text.xdRegExp.exec(url),
181 | uProtocol, uHostName, uPort;
182 | if (!match) {
183 | return true;
184 | }
185 | uProtocol = match[2];
186 | uHostName = match[3];
187 |
188 | uHostName = uHostName.split(':');
189 | uPort = uHostName[1];
190 | uHostName = uHostName[0];
191 |
192 | return (!uProtocol || uProtocol === protocol) &&
193 | (!uHostName || uHostName === hostname) &&
194 | ((!uPort && !uHostName) || uPort === port);
195 | },
196 |
197 | finishLoad: function (name, strip, content, onLoad, config) {
198 | content = strip ? text.strip(content) : content;
199 | if (config.isBuild) {
200 | buildMap[name] = content;
201 | }
202 | onLoad(content);
203 | },
204 |
205 | load: function (name, req, onLoad, config) {
206 | //Name has format: some.module.filext!strip
207 | //The strip part is optional.
208 | //if strip is present, then that means only get the string contents
209 | //inside a body tag in an HTML string. For XML/SVG content it means
210 | //removing the declarations so the content can be inserted
211 | //into the current doc without problems.
212 |
213 | // Do not bother with the work if a build and text will
214 | // not be inlined.
215 | if (config.isBuild && !config.inlineText) {
216 | onLoad();
217 | return;
218 | }
219 |
220 | var parsed = text.parseName(name),
221 | nonStripName = parsed.moduleName + '.' + parsed.ext,
222 | url = req.toUrl(nonStripName),
223 | useXhr = (config && config.text && config.text.useXhr) ||
224 | text.useXhr;
225 |
226 |
227 | //Load the text. Use XHR if possible and in a browser.
228 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
229 | text.get(url, function (content) {
230 | text.finishLoad(name, parsed.strip, content, onLoad, config);
231 | });
232 | } else {
233 | //Need to fetch the resource across domains. Assume
234 | //the resource has been optimized into a JS module. Fetch
235 | //by the module name + extension, but do not include the
236 | //!strip part to avoid file system issues.
237 | req([nonStripName], function (content) {
238 | text.finishLoad(parsed.moduleName + '.' + parsed.ext,
239 | parsed.strip, content, onLoad, config);
240 | });
241 | }
242 | },
243 |
244 | write: function (pluginName, moduleName, write, config) {
245 | if (moduleName in buildMap) {
246 | var content = text.jsEscape(buildMap[moduleName]);
247 | write.asModule(pluginName + "!" + moduleName,
248 | "define(function () { return '" +
249 | content +
250 | "';});\n");
251 | }
252 | },
253 |
254 | writeFile: function (pluginName, moduleName, req, write, config) {
255 | var parsed = text.parseName(moduleName),
256 | nonStripName = parsed.moduleName + '.' + parsed.ext,
257 | //Use a '.js' file name so that it indicates it is a
258 | //script that can be loaded across domains.
259 | fileName = req.toUrl(parsed.moduleName + '.' +
260 | parsed.ext) + '.js';
261 |
262 | //Leverage own load() method to load plugin value, but only
263 | //write out values that do not have the strip argument,
264 | //to avoid any potential issues with ! in file names.
265 | text.load(nonStripName, req, function (value) {
266 | //Use own write() method to construct full module value.
267 | //But need to create shell that translates writeFile's
268 | //write() to the right interface.
269 | var textWrite = function (contents) {
270 | return write(fileName, contents);
271 | };
272 | textWrite.asModule = function (moduleName, contents) {
273 | return write.asModule(moduleName, fileName, contents);
274 | };
275 |
276 | text.write(pluginName, nonStripName, textWrite, config);
277 | }, config);
278 | }
279 | };
280 |
281 | return text;
282 | });
283 | }());
284 |
--------------------------------------------------------------------------------
/examples-build/js/lib/wheat.js:
--------------------------------------------------------------------------------
1 | wheat = {
2 | name:"wheat"
3 | };
--------------------------------------------------------------------------------
/examples-build/js/pizza.js:
--------------------------------------------------------------------------------
1 | pizza = {
2 | name: "pizza",
3 | ingredients: [cheese] //depends on the global cheese.js being available
4 | };
--------------------------------------------------------------------------------
/examples-build/use-path-option.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | use the path option
5 |
6 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/as-globals.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | keep as globals
5 |
6 |
27 |
28 |
--------------------------------------------------------------------------------
/examples/as-modules-only.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | turn into modules with no more globals
5 |
6 |
35 |
36 |
--------------------------------------------------------------------------------
/examples/as-modules.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | turn scripts into modules
5 |
6 |
31 |
32 |
--------------------------------------------------------------------------------
/examples/build-example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | load the build-time generated modules
5 |
6 |
7 |
--------------------------------------------------------------------------------
/examples/js/build-example.js:
--------------------------------------------------------------------------------
1 | //see config.js for the wrapJS config being used here
2 | require(['require', 'config'], function(require){
3 | // requiring donut will now make sure frosting is loaded first
4 | require(['wrap!donut'], function (donut) {
5 | console.log("donut: ", donut);
6 | // notice that the scripts are available as parameters to this callback, as if it were an AMD module
7 | console.log('mmm', donut.name);
8 | console.log('mmm', donut.ingredients[0].name);
9 |
10 | // also notice the donut variable is no longer available as a global
11 | console.log('look no more global: ', window.donut);
12 | });
13 | });
--------------------------------------------------------------------------------
/examples/js/cheese.js:
--------------------------------------------------------------------------------
1 | cheese = {
2 | name:"cheese"
3 | };
--------------------------------------------------------------------------------
/examples/js/config.js:
--------------------------------------------------------------------------------
1 | //wrap the scripts that have dependencies, specify what to return for the AMD module, and remove the script's global
2 | require.config({
3 | paths:{ 'wrap':'../../wrap', 'text':'lib/text'},
4 | wrapJS:{
5 | 'donut':{
6 | deps:['wrap!frosting'],
7 | attach:function () {
8 | var donut = this.donut; // this === window (global)
9 | delete this.donut; //kill the global
10 | return donut; //tell the module what to return
11 | },
12 | path: 'lib/donut'
13 | }
14 | ,'frosting': {
15 | attach: 'frosting',
16 | path: 'lib/frosting'
17 | }
18 | }
19 | });
--------------------------------------------------------------------------------
/examples/js/lib/candy.js:
--------------------------------------------------------------------------------
1 | candy = {
2 | name: "candy",
3 | ingredients: [sugar] //depends on the global sugar.js being available
4 | };
--------------------------------------------------------------------------------
/examples/js/lib/donut.js:
--------------------------------------------------------------------------------
1 | donut = {
2 | name: "donut",
3 | ingredients: [frosting] //depends on the global sugar.js being available
4 | };
--------------------------------------------------------------------------------
/examples/js/lib/frosting.js:
--------------------------------------------------------------------------------
1 | frosting = {
2 | name:"frosting"
3 | };
--------------------------------------------------------------------------------
/examples/js/lib/ketchup.js:
--------------------------------------------------------------------------------
1 | ketchup = {
2 | name:"ketchup"
3 | };
--------------------------------------------------------------------------------
/examples/js/lib/nachos.js:
--------------------------------------------------------------------------------
1 | var nachos = {
2 | name: 'nachos',
3 | ingredients: [cheese] //depends on the global cheese.js being available
4 | };
--------------------------------------------------------------------------------
/examples/js/lib/rolls.js:
--------------------------------------------------------------------------------
1 | rolls = {
2 | name: "rolls",
3 | ingredients: [wheat] //depends on the global wheat.js being available
4 | };
--------------------------------------------------------------------------------
/examples/js/lib/sugar.js:
--------------------------------------------------------------------------------
1 | sugar = {
2 | name:"sugar"
3 | };
--------------------------------------------------------------------------------
/examples/js/lib/tasty.hamburger.js:
--------------------------------------------------------------------------------
1 | hamburger = {
2 | name: "hamburger",
3 | ingredients: [ketchup] //depends on the global ketchup.js being available
4 | };
--------------------------------------------------------------------------------
/examples/js/lib/text.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license RequireJS text 1.0.7 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3 | * Available via the MIT or new BSD license.
4 | * see: http://github.com/jrburke/requirejs for details
5 | */
6 | /*jslint regexp: false, nomen: false, plusplus: false, strict: false */
7 | /*global require: false, XMLHttpRequest: false, ActiveXObject: false,
8 | define: false, window: false, process: false, Packages: false,
9 | java: false, location: false */
10 |
11 | (function () {
12 | var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
13 | xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
14 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im,
15 | hasLocation = typeof location !== 'undefined' && location.href,
16 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
17 | defaultHostName = hasLocation && location.hostname,
18 | defaultPort = hasLocation && (location.port || undefined),
19 | buildMap = [];
20 |
21 | define(function () {
22 | var text, get, fs;
23 |
24 | if (typeof window !== "undefined" && window.navigator && window.document) {
25 | get = function (url, callback) {
26 | var xhr = text.createXhr();
27 | xhr.open('GET', url, true);
28 | xhr.onreadystatechange = function (evt) {
29 | //Do not explicitly handle errors, those should be
30 | //visible via console output in the browser.
31 | if (xhr.readyState === 4) {
32 | callback(xhr.responseText);
33 | }
34 | };
35 | xhr.send(null);
36 | };
37 | } else if (typeof process !== "undefined" &&
38 | process.versions &&
39 | !!process.versions.node) {
40 | //Using special require.nodeRequire, something added by r.js.
41 | fs = require.nodeRequire('fs');
42 |
43 | get = function (url, callback) {
44 | var file = fs.readFileSync(url, 'utf8');
45 | //Remove BOM (Byte Mark Order) from utf8 files if it is there.
46 | if (file.indexOf('\uFEFF') === 0) {
47 | file = file.substring(1);
48 | }
49 | callback(file);
50 | };
51 | } else if (typeof Packages !== 'undefined') {
52 | //Why Java, why is this so awkward?
53 | get = function (url, callback) {
54 | var encoding = "utf-8",
55 | file = new java.io.File(url),
56 | lineSeparator = java.lang.System.getProperty("line.separator"),
57 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
58 | stringBuffer, line,
59 | content = '';
60 | try {
61 | stringBuffer = new java.lang.StringBuffer();
62 | line = input.readLine();
63 |
64 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
65 | // http://www.unicode.org/faq/utf_bom.html
66 |
67 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
68 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
69 | if (line && line.length() && line.charAt(0) === 0xfeff) {
70 | // Eat the BOM, since we've already found the encoding on this file,
71 | // and we plan to concatenating this buffer with others; the BOM should
72 | // only appear at the top of a file.
73 | line = line.substring(1);
74 | }
75 |
76 | stringBuffer.append(line);
77 |
78 | while ((line = input.readLine()) !== null) {
79 | stringBuffer.append(lineSeparator);
80 | stringBuffer.append(line);
81 | }
82 | //Make sure we return a JavaScript string and not a Java string.
83 | content = String(stringBuffer.toString()); //String
84 | } finally {
85 | input.close();
86 | }
87 | callback(content);
88 | };
89 | }
90 |
91 | text = {
92 | version: '1.0.7',
93 |
94 | strip: function (content) {
95 | //Strips declarations so that external SVG and XML
96 | //documents can be added to a document without worry. Also, if the string
97 | //is an HTML document, only the part inside the body tag is returned.
98 | if (content) {
99 | content = content.replace(xmlRegExp, "");
100 | var matches = content.match(bodyRegExp);
101 | if (matches) {
102 | content = matches[1];
103 | }
104 | } else {
105 | content = "";
106 | }
107 | return content;
108 | },
109 |
110 | jsEscape: function (content) {
111 | return content.replace(/(['\\])/g, '\\$1')
112 | .replace(/[\f]/g, "\\f")
113 | .replace(/[\b]/g, "\\b")
114 | .replace(/[\n]/g, "\\n")
115 | .replace(/[\t]/g, "\\t")
116 | .replace(/[\r]/g, "\\r");
117 | },
118 |
119 | createXhr: function () {
120 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first.
121 | var xhr, i, progId;
122 | if (typeof XMLHttpRequest !== "undefined") {
123 | return new XMLHttpRequest();
124 | } else {
125 | for (i = 0; i < 3; i++) {
126 | progId = progIds[i];
127 | try {
128 | xhr = new ActiveXObject(progId);
129 | } catch (e) {}
130 |
131 | if (xhr) {
132 | progIds = [progId]; // so faster next time
133 | break;
134 | }
135 | }
136 | }
137 |
138 | if (!xhr) {
139 | throw new Error("createXhr(): XMLHttpRequest not available");
140 | }
141 |
142 | return xhr;
143 | },
144 |
145 | get: get,
146 |
147 | /**
148 | * Parses a resource name into its component parts. Resource names
149 | * look like: module/name.ext!strip, where the !strip part is
150 | * optional.
151 | * @param {String} name the resource name
152 | * @returns {Object} with properties "moduleName", "ext" and "strip"
153 | * where strip is a boolean.
154 | */
155 | parseName: function (name) {
156 | var strip = false, index = name.indexOf("."),
157 | modName = name.substring(0, index),
158 | ext = name.substring(index + 1, name.length);
159 |
160 | index = ext.indexOf("!");
161 | if (index !== -1) {
162 | //Pull off the strip arg.
163 | strip = ext.substring(index + 1, ext.length);
164 | strip = strip === "strip";
165 | ext = ext.substring(0, index);
166 | }
167 |
168 | return {
169 | moduleName: modName,
170 | ext: ext,
171 | strip: strip
172 | };
173 | },
174 |
175 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
176 |
177 | /**
178 | * Is an URL on another domain. Only works for browser use, returns
179 | * false in non-browser environments. Only used to know if an
180 | * optimized .js version of a text resource should be loaded
181 | * instead.
182 | * @param {String} url
183 | * @returns Boolean
184 | */
185 | useXhr: function (url, protocol, hostname, port) {
186 | var match = text.xdRegExp.exec(url),
187 | uProtocol, uHostName, uPort;
188 | if (!match) {
189 | return true;
190 | }
191 | uProtocol = match[2];
192 | uHostName = match[3];
193 |
194 | uHostName = uHostName.split(':');
195 | uPort = uHostName[1];
196 | uHostName = uHostName[0];
197 |
198 | return (!uProtocol || uProtocol === protocol) &&
199 | (!uHostName || uHostName === hostname) &&
200 | ((!uPort && !uHostName) || uPort === port);
201 | },
202 |
203 | finishLoad: function (name, strip, content, onLoad, config) {
204 | content = strip ? text.strip(content) : content;
205 | if (config.isBuild) {
206 | buildMap[name] = content;
207 | }
208 | onLoad(content);
209 | },
210 |
211 | load: function (name, req, onLoad, config) {
212 | //Name has format: some.module.filext!strip
213 | //The strip part is optional.
214 | //if strip is present, then that means only get the string contents
215 | //inside a body tag in an HTML string. For XML/SVG content it means
216 | //removing the declarations so the content can be inserted
217 | //into the current doc without problems.
218 |
219 | // Do not bother with the work if a build and text will
220 | // not be inlined.
221 | if (config.isBuild && !config.inlineText) {
222 | onLoad();
223 | return;
224 | }
225 |
226 | var parsed = text.parseName(name),
227 | nonStripName = parsed.moduleName + '.' + parsed.ext,
228 | url = req.toUrl(nonStripName),
229 | useXhr = (config && config.text && config.text.useXhr) ||
230 | text.useXhr;
231 |
232 | //Load the text. Use XHR if possible and in a browser.
233 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
234 | text.get(url, function (content) {
235 | text.finishLoad(name, parsed.strip, content, onLoad, config);
236 | });
237 | } else {
238 | //Need to fetch the resource across domains. Assume
239 | //the resource has been optimized into a JS module. Fetch
240 | //by the module name + extension, but do not include the
241 | //!strip part to avoid file system issues.
242 | req([nonStripName], function (content) {
243 | text.finishLoad(parsed.moduleName + '.' + parsed.ext,
244 | parsed.strip, content, onLoad, config);
245 | });
246 | }
247 | },
248 |
249 | write: function (pluginName, moduleName, write, config) {
250 | if (moduleName in buildMap) {
251 | var content = text.jsEscape(buildMap[moduleName]);
252 | write.asModule(pluginName + "!" + moduleName,
253 | "define(function () { return '" +
254 | content +
255 | "';});\n");
256 | }
257 | },
258 |
259 | writeFile: function (pluginName, moduleName, req, write, config) {
260 | var parsed = text.parseName(moduleName),
261 | nonStripName = parsed.moduleName + '.' + parsed.ext,
262 | //Use a '.js' file name so that it indicates it is a
263 | //script that can be loaded across domains.
264 | fileName = req.toUrl(parsed.moduleName + '.' +
265 | parsed.ext) + '.js';
266 |
267 | //Leverage own load() method to load plugin value, but only
268 | //write out values that do not have the strip argument,
269 | //to avoid any potential issues with ! in file names.
270 | text.load(nonStripName, req, function (value) {
271 | //Use own write() method to construct full module value.
272 | //But need to create shell that translates writeFile's
273 | //write() to the right interface.
274 | var textWrite = function (contents) {
275 | return write(fileName, contents);
276 | };
277 | textWrite.asModule = function (moduleName, contents) {
278 | return write.asModule(moduleName, fileName, contents);
279 | };
280 |
281 | text.write(pluginName, nonStripName, textWrite, config);
282 | }, config);
283 | }
284 | };
285 |
286 | return text;
287 | });
288 | }());
289 |
--------------------------------------------------------------------------------
/examples/js/lib/wheat.js:
--------------------------------------------------------------------------------
1 | wheat = {
2 | name:"wheat"
3 | };
--------------------------------------------------------------------------------
/examples/js/pizza.js:
--------------------------------------------------------------------------------
1 | pizza = {
2 | name: "pizza",
3 | ingredients: [cheese] //depends on the global cheese.js being available
4 | };
--------------------------------------------------------------------------------
/examples/use-path-option.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | use the path option
5 |
6 |
32 |
33 |
--------------------------------------------------------------------------------
/spec/browser/wrapjs-test.js:
--------------------------------------------------------------------------------
1 | buster.spec.expose();
2 | require.config({
3 | baseUrl: 'examples/js/',
4 | paths: { 'wrap': '../../wrap', 'text': 'lib/text', 'candy': 'lib/candy' },
5 | wrapJS: {
6 | 'pizza': {
7 | deps: ['cheese'],
8 | attach: 'pizza'
9 | },
10 | 'candy': {
11 | deps: ['lib/sugar'],
12 | attach: function(){
13 | var candy = this.candy; // this === window (global)
14 | delete this.candy; //kill the global
15 | return candy; //tell the module what to return
16 | }
17 | },
18 | 'rolls': {
19 | deps: ['lib/wheat'],
20 | attach: 'rolls',
21 | path: 'lib/rolls'
22 | },
23 | 'lib/tasty.hamburger': {
24 | deps: ['lib/ketchup'],
25 | attach: "hamburger"
26 | }
27 | }
28 | });
29 |
30 | describe("simple attach", function (run) {
31 | require(['wrap!pizza'], function (pza) {
32 | run(function(){
33 | it("should be available as a global", function () {
34 | expect(window.pizza.name).toEqual('pizza');
35 | expect(window.pizza.ingredients[0].name).toEqual('cheese');
36 | });
37 |
38 | it('should be available as a module', function(){
39 | expect(pza.name).toEqual('pizza');
40 | expect(pza.ingredients[0].name).toEqual('cheese');
41 | });
42 | });
43 | });
44 | });
45 |
46 | describe('removing the global variable', function(run){
47 | require(['wrap!candy'], function (candy) {
48 | run(function(){
49 | it('should be available as a module', function(){
50 | expect(candy.name).toEqual('candy');
51 | expect(candy.ingredients[0].name).toEqual('sugar');
52 | });
53 |
54 | it('but not as a global', function(){
55 | expect(window.candy).not().toBeDefined();
56 | });
57 | });
58 | });
59 | });
60 |
61 | describe('using the path option', function(run){
62 | require(['wrap!rolls'], function (rolls) {
63 | run(function(){
64 | it('should find the right lib based on the path', function(){
65 | expect(rolls.name).toEqual('rolls');
66 | expect(rolls.ingredients[0].name).toEqual('wheat');
67 | });
68 | });
69 | });
70 | });
71 |
72 | describe('paths containing a dot', function(run){
73 | require(['wrap!lib/tasty.hamburger'], function (hamburger) {
74 | run(function(){
75 | it('should find the right lib based on the path', function(){
76 | expect(hamburger.name).toEqual('hamburger');
77 | expect(hamburger.ingredients[0].name).toEqual('ketchup');
78 | });
79 | });
80 | });
81 | });
82 |
83 | describe('post-build', function(run){
84 | require(['../../examples-build/js/build-example'], function(){
85 | run(function(){
86 | it('should wrap the script in an AMD module', function(){
87 | var wrappedDonut = require('wrap!donut');
88 | expect(wrappedDonut).toBeDefined();
89 | expect(wrappedDonut.name).toEqual('donut');
90 | });
91 |
92 | it('should not have loaded a duplicate script separately as a global', function(){
93 | expect(window.donut).not().toBeDefined();
94 | });
95 |
96 | it('frosting dependency should still be global', function(){
97 | expect(window.frosting).toBeDefined();
98 | expect(window.frosting.name).toEqual('frosting');
99 | });
100 | });
101 | });
102 | });
--------------------------------------------------------------------------------
/spec/buster.js:
--------------------------------------------------------------------------------
1 | var config = module.exports;
2 |
3 | config["Browser Tests"] = {
4 | environment:"browser",
5 | rootPath:"../",
6 | libs:["examples/js/lib/require.js"],
7 | tests:[
8 | "spec/browser/*.js"
9 | ],
10 | resources:['examples/js/*.js', 'examples/js/lib/*.js', 'examples-build/js/*.js', 'wrap.js']
11 | };
--------------------------------------------------------------------------------
/spec/module/amd-test.js:
--------------------------------------------------------------------------------
1 |
2 | //IDEAL, but doesn't currently work because buster ends before it can finish
3 | require(['lib/test!http://raw.github.com/gist/3eb65c2883af6b6f2b8d/41b6fbfaf24b8106268dd3c770ad22a976afcf3e/mymodule'], function (module) {
4 | describe("AMD", function (done) {
5 | it("should work", function () {
6 | console.log('YAY');
7 | expect(module.name).toEqual("A Module");
8 | expect(true).toEqual(false);
9 | done();
10 | });
11 | });
12 | });
13 |
14 | //works most of the time, but only because it happens before buster thinks things are done
15 | require(['lib/test!lib/mymodule'], function(module){
16 | buster.spec.expose(); //todo where to put this?
17 | describe("AMD", function () {
18 | it("should work", function () {
19 | expect(module.name).toEqual("A Module");
20 | expect(module.dependsOn).toEqual("a dependency");
21 | expect(true).toEqual(true);
22 | });
23 | });
24 | });
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/spec/module/amd-test2.js:
--------------------------------------------------------------------------------
1 | require(['lib/mymodule'], function(module){
2 | buster.spec.expose(); //todo where to put this?
3 | describe("Another AMD", function () {
4 | window.it("should work", function () {
5 | expect(module.name).toEqual("A Module");
6 | expect(true).toEqual(true);
7 | });
8 | });
9 | });
10 |
11 |
12 |
--------------------------------------------------------------------------------
/spec/module/amd-test3.js:
--------------------------------------------------------------------------------
1 | buster.spec.expose();
2 | describe('another way to test AMD', function(){
3 | require(['lib/mymodule'], function(run){
4 | run(function(){
5 | console.log('loaded the thingy to test: ', module);
6 | it('should work', function () {
7 | expect(true).toEqual(true);
8 | });
9 | });
10 | });
11 | });
--------------------------------------------------------------------------------
/wrap.js:
--------------------------------------------------------------------------------
1 | /* wrap.js RequireJS plugin
2 | * Copyright 2012, Dave Geddes (@geddesign)
3 | * wrap.js may be freely distributed under the MIT license.
4 | * version 0.2.2
5 | * docs: http://github.com/geddesign/wrapjs
6 | */
7 |
8 | define(['text'], function (text) {
9 | return {
10 | buildMap:{},
11 | load:function (name, req, load, config) {
12 | var _this = this,
13 | module = config.wrapJS && config.wrapJS[name],
14 | //use the `path` attribute if specified
15 | path = config.wrapJS[name].path || name;
16 |
17 | // if no module to load return early.
18 | if (!module) return load();
19 |
20 | // load the wrapped script's dependencies
21 | req(module.deps || [], function () {
22 | //for the build, get the contents with the text plugin and store the contents of the script for the write() function
23 | if (config.isBuild) {
24 | text.get(req.toUrl(path), function (scriptContent) {
25 | _this.buildMap[name] = {
26 | content:scriptContent,
27 | deps:module.deps || [],
28 | attach:config.wrapJS[name].attach
29 | };
30 | return load();
31 | });
32 | }
33 | else {
34 | // load the script now that dependencies are loaded.
35 | req([path], function () {
36 | // Attach property
37 | return load(getAttach(config.wrapJS[name].attach));
38 | });
39 | }
40 | });
41 | },
42 |
43 | /* write the output during the build, effectively turning the script into an AMD module */
44 | write:function (pluginName, name, write) {
45 | var module = this.buildMap[name],
46 | deps = module.deps.map(toQuotes).join(', '),
47 | generatedName = pluginName + '!' + name,
48 | output = createModule(generatedName, deps, module.content, getReturnVal(module.attach));
49 | write(output);
50 | }
51 | };
52 |
53 | /* Generate AMD module to wrap the script */
54 | function createModule(name, deps, content, ret){
55 | return '/* script wrapped by the wrap! plugin */\n'+
56 | 'define("' + name + '", ['+ deps + '], function(){ \n' +
57 | content + '\n' +
58 | 'return ' + ret + ';\n' +
59 | '});\n';
60 | }
61 |
62 | /*
63 | Determines what to have the wrapping module return. Will either be a global variable
64 | or an immediate function that will execute when the module is loaded,
65 | enabling the removal of global variables once wrapped.
66 | */
67 | function getReturnVal(attach){
68 | if(typeof attach !== 'function') return attach;
69 | return "(function () {\n" +
70 | "var attach = "+attach+"; \n" +
71 | "return (typeof attach === 'function') ? attach.apply(this) : attach; \n" +
72 | "}())"
73 | }
74 |
75 | /* surround a value with quotes */
76 | function toQuotes(val) {
77 | return "\"" + val + "\"";
78 | }
79 |
80 | /* return the correct attached object */
81 | function getAttach(attach){
82 | return (typeof attach === 'function') ? attach.apply(this, arguments) : this[attach];
83 | }
84 | });
--------------------------------------------------------------------------------