Provides a module, modules.js, with the following features:

A module is a JavaScript file. modules.js uses an XHR (HTTP request) to get the file's text, the eval function to run the script, and with blocks to manage the scope chain in the script.

These tools permit modules.js to load scripts only once and on demand, to completely avoid touching the global name space (no added members to the window object), to give every script its own private name space, and to insert names in a module's scope ("importing" using include).

modules.js also masks its own existence from other scripts by removing it's <script> tag from the <head> of the containing HTML document. The module loader then detects the earliest possible moment after the document's DOM has fully loaded, presumably before the document has been rendered, then loads a list of ampersand delimited modules from the query modules.js query string:

<script src="modules.js?includeMe.js"></script>

A single page can have more than one self-contained module loader, with its own cache of modules. Each module environment would be completely unaware of the others.

modules.js "launders" the scope chain so that every module has a safe and clean execution environment. The scope chain in each module includes, from bottom to top:

The context object, this, is the module inside a module script.

modules.js also bootstraps these modules:

modules.js L110
The modules system. You can acquire a reference to the module system using a require("modules.js") expression. modules.js is the only module that cannot be included in another module; you can only use require.
modules.js.beginTime L117
the Date that the module loader began building itself.
modules.js.endTime L122
the Date that the module loader finished building itself and began waiting for the DOM to load.
modules.js.readyTime L128
the Date that the module loader deemed that it was ready to begin requiring modules. This is the earliest time that the script can detect that the DOM has been fully loaded.
modules.js.Module L137
a function that returns a new, empty, module object.
modules.js.Module.moduleScope L145
a ModuleScope object that contains names that are available inside a module, like logging functions, module functions, and functions included in the module's scope but are not exported to other modules. Each module's include function writes names from other modules into moduleScope, not the module object itself.
modules.js.ModuleScope L159
a native JavaScript type for module scopes. All the names in a module scope are available to its module, but they are private in the sense that including a module in another module does not copy the former module's scope.
modules.js.ModuleScope.global L169
a reference to global scope. When using modules.js in a client, global is the window. This value exists to provide a consistent interface to the global object for scripts that can be executed in other environments such as Rhino, particularly XJS.
modules.js.ModuleScope.module L177
a synonym reference for module that contains this ModuleScope. module is a handy name for the current module object when this will not suffice, like in a method.
modules.js.ModuleScope.moduleUrl L184
the URL of the JavaScript file that produced the corresponding module.
modules.js.ModuleScope.modulesUrl L190
the fully qualified path URL leading up to modules.js in the HTML script tag hyper-reference.
modules.js.ModuleScope.moduleBind L196
moduleBind is a dual purpose function that defers member selection and binding to the module to call time. used to bind moduleScope functions to the module and by include to bind functions decorated with foreignModuleBind (like base.js's type, dir, and vars) to the module in which they're included rather than the module in which they're declared.

module scopes contain special bound copies of functions from the modules.js module and the environment.js module. Functions with these names are available in the module scope of every module and are aware of the module that they were called from. This permits them to perform behaviors like recording the URL of the module that called them or resolve URL arguments relative to the module that they are called in.

modules.js.ModuleScope.require L225
a version of require from modules.js that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.include L231
a version of include from modules.js that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.foreignModuleBind L237
a version of foreignModuleBind from modules.js that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.register L243
a version of register from modules.js that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.publish L249
a version of publish from modules.js that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.log L257
a version of log from environment.js (although defined in modules.js) that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.warn L263
a version of warn from environment.js (although defined in modules.js) that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.error L270
a version of error from environment.js (although defined in modules.js) that is lazily bound (lazy bind) to this ModuleScope.
modules.js.ModuleScope.info L276
a version of info from environment.js (although defined in modules.js) that is lazily bound (lazy bind) to this ModuleScope.
modules.js.logging L300
whether to log module load events.

modules.js.logModule L305

accepts:
  • a module URL String
  • an optional depth, noting how many occurences of require closures are on the JavaScript execution stack.

logs that a module at a given URL has been loaded. This function simply calls log, but can be overriden in other modules. This function does not check whether logging is turned on; that's checked by require.

modules.js.resolveObject L323

resolves a URL Object relative the calling module or modules.js. URLs beginning with . imply relation to the current module file.

URL Objects are produced by http.js#resolveObject and have values for all of the http.js#keys.

modules.js.resolve L352
resolves a URL relative the calling module or modules.js. URLs beginning with . imply relation to the current module file.
modules.js.relativeObject L361
returns an object containing named parts for a given URL as resolved as a module URL.
modules.js.relative L370
accepts a fully qualified URL and returns a URL string relative to a module implied by the context object.
modules.js.dub L379

decorates an object with attributes for their:

  • modules.js#moduleUrl,
  • modules.js#name, and
  • modules.js#fullName

denoting the module that it is from or bound to and the name it has in that scope.

accepts:
  • an object,
  • a module URL, and
  • the name of the object.
modules.js.require L405

returns a Module for a given moduleUrl:

var module = require(moduleUrl);

blocks until the module has been loaded or the module object has been retrieved from the cache of singleton module objects.

A moduleUrl is a String that describes the location of a JavaScript file relative to the modulesUrl, the path leading up to modules.js in the src attribute of its HTML script tag. If the moduleUrl begins with a dot (.), the moduleUrl is resolved relative to the URL of the current Module. Thus:

var http = require('http.js');

retrieves the http.js module that sits beside modules.js on the server. However, in browser/layout.js:

var html = require('./html.js');

retrieves the browser/html.js module.

supports optional continuation passing style:

require(moduleUrl, function (module) {
});

If a moduleUrl and a continuation are provided, require returns undefined and instead passes the Module to the continuation. If an exception is thrown during the execution of require, require will call the continuation with undefined as the first argument and the Error as a second argument.

Currently, require blocks until the continuation finishes executing. However, in future versions, the continuation passing style may be asynchronous.

modules.js.include L584

accepts a moduleUrl, returns a Module, and copies the items from the Module into the current ModuleScope except for the moduleScope item since this would mask the current module's scope:

var base = require('base.js');
include('base.js');
assert(base.Set == moduleScope.Set == Set);

include does not support continuation passing style.

include supports an alternate argument. If you provide include with an arbitrary object instead of a Module, it will copy the items of the object into the current ModuleScope instead. This object can be a Module:

include({
    'x': 10;
});
assert(x == 10);

include also marks any imported functions with their foreign module's URL and name using dub.

include doesn't work for modules.js. Use require instead. This is just a safety to prevent you from calling functions from modules.js that haven't been bound to the current module. If you were able to include items from modules.js in your ModuleScope, using include thereafter would fail since the version of include in modules.js is not bound to the current Module and cannot copy items into its ModuleScope.

modules.js.publish L662

copies items from an object onto the current Module. This is handy for exporting items from another module, since include does not do this implicitly as import would in Python.

accepts an Object or Module and returns undefined.

This function takes special care not to replace the calling module's moduleScope object.

modules.js.register L683

replaces a Module in the singleton module cache with a given object.

accepts:
  • a moduleUrl
  • a Module, a Function, or some other Object.
  • an optional boolean value indicating whether to force a reload of the module next time it's required or included.

If you provide a Module, the Module replaces the current module in the cache.

If you provide a Function, register treats the function as a constructor function for the a Module on the given URL. The function will be called with a Module object as the context object (this) when it's required. This particular feature is important for the module bundling step of the Chiron build process and permits multiple modules to be registered in a single file.

modules.js.foreignModuleBind L724

a decorator for functions that should receive the Module they're included in and called from as their context object (this)

For example, if in module a.js we declare a logModule exportable function with the foreignModuleBind decorator:

this.logModule = foreignModule(function () {
    log(this.moduleScope.moduleUrl);
});

And we include and call logModule in b.js:

include('a.js');
logModule();

logModule will receive the Module for b.js as this instead of the global context object (window) or the a.js Module. Thus, b.js would print to the console:

b.js
modules.js.modules L754
a mapping of URL's to singleton Module objects for each module that is being or has been loaded.
modules.js.registeredModules L760
an Object used as a dictionary of URL's to module constructor functions. register adds elements to this mapping, and require uses this mapping to construct modules from functions in preloaded module bundels.
modules.js.forceReload L769
an Object used as a set of URL's of modules that should be reloaded and evaluated next time they're required (or, by implication, included).
modules.js.evalGlobalWith L776

evaluates given text in global scope, such that evaluated scripts do not have an opportunity to accidentally access or manipulate anything but global variables, using evalGlobal, internally.

evalGlobalWith accepts some optional scope objects to evaluate the text within, so the user has the option of inserting variables for the script's use.

Usage:

evalGlobalWith(text)
    function () { eval(text) }.apply(this, arguments)

evalGlobalWith(text, scope)
    with (scope) {
    function () { eval(text) }.apply(this, arguments) }}

evalGlobalWith(text, innerScope, outerScope)
    with (outerScope) {
    with (innerScope) {
    function () { eval(text) }.apply(this, arguments) }}}

evalGlobalWith(text, innerScope, ..., outerScope)
modules.js.evalGlobal L838

a version of eval that guarantees that only global names are available inside the given script. evalGlobal blocks until the evaluation is complete and returns the last value evaluated. evalGlobal exists in response to the need to protect variables in the calling scope. eval permits the given program to access the caller's scope chain:

(function () {

    var a = 10;
    eval("a = 20");
    a == 20;

    var b = 10;
    evalGlobal("b = 20");
    b == 10;
    window.b == 20;

})();

The arguments object is a good way to pass and access variables inside of an evalGlobal program:

evalGlobal("arguments[1]", 10) == 10;

Environment

environment.js L878

environment.js.messages L882

environment.js.log L886

accepts:
  • a message and
  • an optional label.

The label, by convention, is one of "log"`, "info", "warn", or "error". Custom loggers treat labels like "module", "pass", or "fail". Attempts to write the message to window.console, progressively handling console implementations that provide a function for the given label, or defaulting to log depending on availability.

Also adds a [message, label, moduleUrl] array to the end of environment.messages. label is one of "log", "warn", "info", or "error" by convention. moduleUrl is the URL of the module from which log was called.

In Safari, log writes to the Javascript debug console, which is only available if you set the preference:

defaults write com.apple.Safari IncludeDebugMenu 1

In Firefox, you can get a debug console with Firebug, http://getfirebug.com.

You can override the behavior of log by assigning a different function to require('environment.js').log in any module.

Chiron can create a debug console for the purpose of unit testing or page debugging. To debug a web page, use modules.js to include debug.js on a page. To run a unit test, view run.html, lite.html, or edit.html with the moduleUrl of the unit test as a query string.

see:
  • error
  • warn
  • info
environment.js.warn L960

writes a warning message to window.console.warn or defers to log.

see:
  • log
  • error
  • info
environment.js.error L973

writes an error message to window.console.error or defers to log. Accepts a String or an Error.

see:
  • log
  • warn
  • info
environment.js.info L990

writes an informational message to window.console.info or defers to log depending on the console.

see:
  • log
  • error
  • warn

Application

environment.js.app L1015
one of "browser", "dashboard", "spiderMonkey", or "rhino".

environment.js.isBrowser L1027

environment.js.isDashboard L1029

environment.js.isRhino L1031

environment.js.isSpiderMonkey L1033

Browser

environment.js.browser L1040
one of "gecko", "safari", "konqueror", or "explorer", undefined.

environment.js.isOpera L1051

environment.js.isKonqueror L1053

environment.js.isWebKit L1055

environment.js.isSafari L1057

environment.js.isKhtml L1059

environment.js.isGecko L1065

environment.js.isFirefox L1072

environment.js.isIE L1074

environment.js.isIE5 L1076

environment.js.isIE5_5 L1078

environment.js.isIE6 L1080

environment.js.isIE7 L1082

System

isWindows L1090

isMac L1094

isUnix L1099

isUnix.url L1103

isUnix.locale L1106

isUnix.quirksMode L1111

Browser Base

browser.js L1125

browser.js.hasAttr L1139

browser.js.getAttr L1160

HTTP

''a.k.a., AJAX''

Uses regular expressions designed by Steven Levithan [1].

http.js L1174

http.js.keys L1178
members of a parsed URI object.
http.js.expressionKeys L1201
members of a parsed URI object that you get from evaluting the strict regular expression.

http.js.strictExpression L1223

http.js.urlParser L1254
returns a URI parser function given a regular expression that renders expressionKeys and returns an Object mapping all keys to values.
http.js.parseUrl L1302
a strict URI parser.
http.js.formatUrl L1307
accepts a parsed URI object and returns the corresponding string.
http.js.resolveObject L1360
returns an object representing a URL resolved from a relative location and a base location.
http.js.relativeObject L1426
returns an object representing a relative URL to a given target URL from a source URL.
http.js.resolve L1485
returns a URL resovled to a relative URL from a base URL.
http.js.relative L1492
returns a relative URL to a target from a source.
http.js.requestText L1499
returns the text at a given URL using an HTTP request. supports continuation passing form for asynchronous requests.
http.js.requestXml L1521
returns an XML DOM from a page on a given URL using an HTTP request. supports continuation passing form for asynchronous requests.
http.js.requestDocument L1540
returns an XML document element from a page on a given URL using an HTML request. supports continuation passing form for asynchronous requests.
http.js.synchronous L1559
a constant for specifying scnchronous, blocking, waiting HTTP requests.
http.js.asynchronous L1565
a constant for specifying asynchronous, non-blocking HTTP requests.
http.js.request L1571
sends an HTTP request to a given URL and returns the response. supports continuation passing form for asynchronous requests.
http.js.Request L1608
returns a wrapped HTTP Request object.

http.js.Request.toString L1632

http.js.Request.getResponse L1636

http.js.Request.pogress L1649
an event function that the Request calls when it receives a chunk of content.
http.js.Request.ready L1657
an event function that the Request calls when the Reponse is ready.
http.js.Request.ok L1665
an event function that the Request calls when a Response is ready and all went well.
http.js.Request.error L1673
an event function that the Request calls when a Reponse is completed but failed to retrieve the requested content.
http.js.Request.warn L1681
an event function that the Request calls when something is amiss with message.
http.js.Request.observe L1690
permits a user to observe ready, ok, error, and warn events with a handler function.

http.js.Request.setHeader L1706

http.js.Request.isOpen L1712

http.js.Request.isSent L1718

http.js.Request.getTimeout L1724

http.js.Request.setTimeout L1730

http.js.Request.open L1736

Accepts

  • method, an HTTP request method, for example, GET, POST, PROPFIND and others.
  • url, a web location string
  • synchronous, whether send will block until completed, for example, http.synchronous, http.asynchronous.
  • user, an optional HTTP user name.
  • password, an optional HTTP password.
http.js.Request.send L1763
Accepts an optional content argument for requests like POST method.

http.js.Request.abort L1788

http.js.Response L1859
returns a wrapped HTTP Response object.
http.js.Response.isReady L1878
whether the request is finished. This indicates whether you can call getStatus
http.js.Response.getStatus L1886
returns the HTTP response code. Local files return 0. Returns undefined if the underlying XML HTTP request throws an exception, getStatus returns undefined.
http.js.Response.isOk L1903

returns whether a request had a valid response. This usually is indicative of a 200 HTTP response code, but there are variations among browsers.

HTTP Status codes in the interval [200, 300] are all legal HTTP Ok responses.

In Firefox and Safari 3, local files acquired with an HTTP request have a status code of 0.

In Safari 2, local files acquired with an asynchronous HTTP request have a status of undefined.

In Safari, a response with no content causes a status of undefined.

Konqueror requires acceptance of 304, "using cache", according to dojo/src/hostenv_browser.js

http.js.Response.isError L1939

http.js.Response.getText L1945

http.js.Response.getXml L1951

http.js.Response.getDocument L1962

http.js.Response.getHeader L1968

http.js.Response.hasHeader L1974

http.js.Response.getHeaders L1980

http.js.Response.getLength L1988

http.js.createNativeRequest L1996
returns an XMLHttpRequest in most browsers.

As a final pass, modules.js accepts an optional, ampersand-delimited list of module URL's specified in the modules.js query string. When the module loader is ready and the DOM and CSS are fully loaded, it automatically uses require to load these modules. If you do not take advantage of this list, there is now way to use the module system since it leaves no toe-hold in global scope. The best practice is to at least require a module specific to your page, or use chiron.js to enable the use of namespaced inline scripts.

References

[1]http://stevenlevithan.com Steven Levithan. Provides regular expressions for both loose and strict URL parsing.