| /* |
| Copyright (c) 2004-2005, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/community/licensing.shtml |
| */ |
| |
| /** |
| * @file bootstrap1.js |
| * |
| * bootstrap file that runs before hostenv_*.js file. |
| * |
| * @author Copyright 2004 Mark D. Anderson (mda@discerning.com) |
| * @author Licensed under the Academic Free License 2.1 http://www.opensource.org/licenses/afl-2.1.php |
| * |
| * $Id: bootstrap1.js 2836 2006-01-16 08:36:18Z alex $ |
| */ |
| |
| /** |
| * The global djConfig can be set prior to loading the library, to override |
| * certain settings. It does not exist under dojo.* so that it can be set |
| * before the dojo variable exists. Setting any of these variables *after* the |
| * library has loaded does nothing at all. The variables that can be set are |
| * as follows: |
| */ |
| |
| /** |
| * dj_global is an alias for the top-level global object in the host |
| * environment (the "window" object in a browser). |
| */ |
| var dj_global = this; //typeof window == 'undefined' ? this : window; |
| |
| function dj_undef(name, obj){ |
| if(!obj){ obj = dj_global; } |
| return (typeof obj[name] == "undefined"); |
| } |
| |
| if(dj_undef("djConfig")){ |
| var djConfig = {}; |
| } |
| |
| /** |
| * dojo is the root variable of (almost all) our public symbols. |
| */ |
| var dojo; |
| if(dj_undef("dojo")){ dojo = {}; } |
| |
| dojo.version = { |
| major: 0, minor: 2, patch: 2, flag: "", |
| revision: Number("$Rev: 2836 $".match(/[0-9]+/)[0]), |
| toString: function() { |
| with (dojo.version) { |
| return major + "." + minor + "." + patch + flag + " (" + revision + ")"; |
| } |
| } |
| }; |
| |
| /* |
| * evaluate a string like "A.B" without using eval. |
| */ |
| dojo.evalObjPath = function(objpath, create){ |
| // fast path for no periods |
| if(typeof objpath != "string"){ return dj_global; } |
| if(objpath.indexOf('.') == -1){ |
| if((dj_undef(objpath, dj_global))&&(create)){ |
| dj_global[objpath] = {}; |
| } |
| return dj_global[objpath]; |
| } |
| |
| var syms = objpath.split(/\./); |
| var obj = dj_global; |
| for(var i=0;i<syms.length;++i){ |
| if(!create){ |
| obj = obj[syms[i]]; |
| if((typeof obj == 'undefined')||(!obj)){ |
| return obj; |
| } |
| }else{ |
| if(dj_undef(syms[i], obj)){ |
| obj[syms[i]] = {}; |
| } |
| obj = obj[syms[i]]; |
| } |
| } |
| return obj; |
| }; |
| |
| |
| // **************************************************************** |
| // global public utils |
| // **************************************************************** |
| |
| /* |
| * utility to print an Error. |
| * TODO: overriding Error.prototype.toString won't accomplish this? |
| * ... since natively generated Error objects do not always reflect such things? |
| */ |
| dojo.errorToString = function(excep){ |
| return ((!dj_undef("message", excep)) ? excep.message : (dj_undef("description", excep) ? excep : excep.description )); |
| }; |
| |
| /** |
| * Throws an Error object given the string err. For now, will also do a println |
| * to the user first. |
| */ |
| dojo.raise = function(message, excep){ |
| if(excep){ |
| message = message + ": "+dojo.errorToString(excep); |
| } |
| var he = dojo.hostenv; |
| if((!dj_undef("hostenv", dojo))&&(!dj_undef("println", dojo.hostenv))){ |
| dojo.hostenv.println("FATAL: " + message); |
| } |
| throw Error(message); |
| }; |
| |
| dj_throw = dj_rethrow = function(m, e){ |
| dojo.deprecated("dj_throw and dj_rethrow deprecated, use dojo.raise instead"); |
| dojo.raise(m, e); |
| }; |
| |
| /** |
| * Produce a line of debug output. |
| * Does nothing unless djConfig.isDebug is true. |
| * varargs, joined with ''. |
| * Caller should not supply a trailing "\n". |
| */ |
| dojo.debug = function(){ |
| if (!djConfig.isDebug) { return; } |
| var args = arguments; |
| if(dj_undef("println", dojo.hostenv)){ |
| dojo.raise("dojo.debug not available (yet?)"); |
| } |
| var isJUM = dj_global["jum"] && !dj_global["jum"].isBrowser; |
| var s = [(isJUM ? "": "DEBUG: ")]; |
| for(var i=0;i<args.length;++i){ |
| if(!false && args[i] instanceof Error){ |
| var msg = "[" + args[i].name + ": " + dojo.errorToString(args[i]) + |
| (args[i].fileName ? ", file: " + args[i].fileName : "") + |
| (args[i].lineNumber ? ", line: " + args[i].lineNumber : "") + "]"; |
| } else { |
| try { |
| var msg = String(args[i]); |
| } catch(e) { |
| if(dojo.render.html.ie) { |
| var msg = "[ActiveXObject]"; |
| } else { |
| var msg = "[unknown]"; |
| } |
| } |
| } |
| s.push(msg); |
| } |
| if(isJUM){ // this seems to be the only way to get JUM to "play nice" |
| jum.debug(s.join(" ")); |
| }else{ |
| dojo.hostenv.println(s.join(" ")); |
| } |
| } |
| |
| /** |
| * this is really hacky for now - just |
| * display the properties of the object |
| **/ |
| |
| dojo.debugShallow = function(obj){ |
| if (!djConfig.isDebug) { return; } |
| dojo.debug('------------------------------------------------------------'); |
| dojo.debug('Object: '+obj); |
| for(i in obj){ |
| dojo.debug(i + ': ' + obj[i]); |
| } |
| dojo.debug('------------------------------------------------------------'); |
| } |
| |
| var dj_debug = dojo.debug; |
| |
| /** |
| * We put eval() in this separate function to keep down the size of the trapped |
| * evaluation context. |
| * |
| * Note that: |
| * - JSC eval() takes an optional second argument which can be 'unsafe'. |
| * - Mozilla/SpiderMonkey eval() takes an optional second argument which is the |
| * scope object for new symbols. |
| */ |
| function dj_eval(s){ return dj_global.eval ? dj_global.eval(s) : eval(s); } |
| |
| |
| /** |
| * Convenience for throwing an exception because some function is not |
| * implemented. |
| */ |
| dj_unimplemented = dojo.unimplemented = function(funcname, extra){ |
| // FIXME: need to move this away from dj_* |
| var mess = "'" + funcname + "' not implemented"; |
| if((!dj_undef(extra))&&(extra)){ mess += " " + extra; } |
| dojo.raise(mess); |
| } |
| |
| /** |
| * Convenience for informing of deprecated behaviour. |
| */ |
| dj_deprecated = dojo.deprecated = function(behaviour, extra, removal){ |
| var mess = "DEPRECATED: " + behaviour; |
| if(extra){ mess += " " + extra; } |
| if(removal){ mess += " -- will be removed in version: " + removal; } |
| dojo.debug(mess); |
| } |
| |
| /** |
| * Does inheritance |
| */ |
| dojo.inherits = function(subclass, superclass){ |
| if(typeof superclass != 'function'){ |
| dojo.raise("superclass: "+superclass+" borken"); |
| } |
| subclass.prototype = new superclass(); |
| subclass.prototype.constructor = subclass; |
| subclass.superclass = superclass.prototype; |
| // DEPRICATED: super is a reserved word, use 'superclass' |
| subclass['super'] = superclass.prototype; |
| } |
| |
| dj_inherits = function(subclass, superclass){ |
| dojo.deprecated("dj_inherits deprecated, use dojo.inherits instead"); |
| dojo.inherits(subclass, superclass); |
| } |
| |
| // an object that authors use determine what host we are running under |
| dojo.render = (function(){ |
| |
| function vscaffold(prefs, names){ |
| var tmp = { |
| capable: false, |
| support: { |
| builtin: false, |
| plugin: false |
| }, |
| prefixes: prefs |
| }; |
| for(var x in names){ |
| tmp[x] = false; |
| } |
| return tmp; |
| } |
| |
| return { |
| name: "", |
| ver: dojo.version, |
| os: { win: false, linux: false, osx: false }, |
| html: vscaffold(["html"], ["ie", "opera", "khtml", "safari", "moz"]), |
| svg: vscaffold(["svg"], ["corel", "adobe", "batik"]), |
| vml: vscaffold(["vml"], ["ie"]), |
| swf: vscaffold(["Swf", "Flash", "Mm"], ["mm"]), |
| swt: vscaffold(["Swt"], ["ibm"]) |
| }; |
| })(); |
| |
| // **************************************************************** |
| // dojo.hostenv methods that must be defined in hostenv_*.js |
| // **************************************************************** |
| |
| /** |
| * The interface definining the interaction with the EcmaScript host environment. |
| */ |
| |
| /* |
| * None of these methods should ever be called directly by library users. |
| * Instead public methods such as loadModule should be called instead. |
| */ |
| dojo.hostenv = (function(){ |
| |
| // default configuration options |
| var config = { |
| isDebug: false, |
| allowQueryConfig: false, |
| baseScriptUri: "", |
| baseRelativePath: "", |
| libraryScriptUri: "", |
| iePreventClobber: false, |
| ieClobberMinimal: true, |
| preventBackButtonFix: true, |
| searchIds: [], |
| parseWidgets: true |
| }; |
| |
| if (typeof djConfig == "undefined") { djConfig = config; } |
| else { |
| for (var option in config) { |
| if (typeof djConfig[option] == "undefined") { |
| djConfig[option] = config[option]; |
| } |
| } |
| } |
| |
| var djc = djConfig; |
| function _def(obj, name, def){ |
| return (dj_undef(name, obj) ? def : obj[name]); |
| } |
| |
| return { |
| name_: '(unset)', |
| version_: '(unset)', |
| pkgFileName: "__package__", |
| |
| // for recursion protection |
| loading_modules_: {}, |
| loaded_modules_: {}, |
| addedToLoadingCount: [], |
| removedFromLoadingCount: [], |
| inFlightCount: 0, |
| // FIXME: it should be possible to pull module prefixes in from djConfig |
| modulePrefixes_: { |
| dojo: {name: "dojo", value: "src"} |
| }, |
| |
| |
| setModulePrefix: function(module, prefix){ |
| this.modulePrefixes_[module] = {name: module, value: prefix}; |
| }, |
| |
| getModulePrefix: function(module){ |
| var mp = this.modulePrefixes_; |
| if((mp[module])&&(mp[module]["name"])){ |
| return mp[module].value; |
| } |
| return module; |
| }, |
| |
| getTextStack: [], |
| loadUriStack: [], |
| loadedUris: [], |
| // lookup cache for modules. |
| // NOTE: this is partially redundant a private variable in the jsdown |
| // implementation, but we don't want to couple the two. |
| // modules_ : {}, |
| post_load_: false, |
| modulesLoadedListeners: [], |
| /** |
| * Return the name of the hostenv. |
| */ |
| getName: function(){ return this.name_; }, |
| |
| /** |
| * Return the version of the hostenv. |
| */ |
| getVersion: function(){ return this.version_; }, |
| |
| /** |
| * Read the plain/text contents at the specified uri. If getText() is |
| * not implemented, then it is necessary to override loadUri() with an |
| * implementation that doesn't rely on it. |
| */ |
| getText: function(uri){ |
| dojo.unimplemented('getText', "uri=" + uri); |
| }, |
| |
| /** |
| * return the uri of the script that defined this function |
| * private method that must be implemented by the hostenv. |
| */ |
| getLibraryScriptUri: function(){ |
| // FIXME: need to implement!!! |
| dojo.unimplemented('getLibraryScriptUri',''); |
| } |
| }; |
| })(); |
| |
| /** |
| * Display a line of text to the user. |
| * The line argument should not contain a trailing "\n"; that is added by the |
| * implementation. |
| */ |
| //dojo.hostenv.println = function(line) {} |
| |
| // **************************************************************** |
| // dojo.hostenv methods not defined in hostenv_*.js |
| // **************************************************************** |
| |
| /** |
| * Return the base script uri that other scripts are found relative to. |
| * It is either the empty string, or a non-empty string ending in '/'. |
| */ |
| dojo.hostenv.getBaseScriptUri = function(){ |
| if(djConfig.baseScriptUri.length){ |
| return djConfig.baseScriptUri; |
| } |
| var uri = new String(djConfig.libraryScriptUri||djConfig.baseRelativePath); |
| if (!uri) { dojo.raise("Nothing returned by getLibraryScriptUri(): " + uri); } |
| |
| var lastslash = uri.lastIndexOf('/'); |
| djConfig.baseScriptUri = djConfig.baseRelativePath; |
| return djConfig.baseScriptUri; |
| } |
| |
| /** |
| * Set the base script uri. |
| */ |
| // In JScript .NET, see interface System._AppDomain implemented by |
| // System.AppDomain.CurrentDomain. Members include AppendPrivatePath, |
| // RelativeSearchPath, BaseDirectory. |
| dojo.hostenv.setBaseScriptUri = function(uri){ djConfig.baseScriptUri = uri } |
| |
| /** |
| * Loads and interprets the script located at relpath, which is relative to the |
| * script root directory. If the script is found but its interpretation causes |
| * a runtime exception, that exception is not caught by us, so the caller will |
| * see it. We return a true value if and only if the script is found. |
| * |
| * For now, we do not have an implementation of a true search path. We |
| * consider only the single base script uri, as returned by getBaseScriptUri(). |
| * |
| * @param relpath A relative path to a script (no leading '/', and typically |
| * ending in '.js'). |
| * @param module A module whose existance to check for after loading a path. |
| * Can be used to determine success or failure of the load. |
| */ |
| dojo.hostenv.loadPath = function(relpath, module /*optional*/, cb /*optional*/){ |
| if((relpath.charAt(0) == '/')||(relpath.match(/^\w+:/))){ |
| dojo.raise("relpath '" + relpath + "'; must be relative"); |
| } |
| var uri = this.getBaseScriptUri() + relpath; |
| if(djConfig.cacheBust && dojo.render.html.capable) { uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,""); } |
| try{ |
| return ((!module) ? this.loadUri(uri, cb) : this.loadUriAndCheck(uri, module, cb)); |
| }catch(e){ |
| dojo.debug(e); |
| return false; |
| } |
| } |
| |
| /** |
| * Reads the contents of the URI, and evaluates the contents. |
| * Returns true if it succeeded. Returns false if the URI reading failed. |
| * Throws if the evaluation throws. |
| * The result of the eval is not available to the caller. |
| */ |
| dojo.hostenv.loadUri = function(uri, cb){ |
| if(this.loadedUris[uri]){ |
| return; |
| } |
| var contents = this.getText(uri, null, true); |
| if(contents == null){ return 0; } |
| this.loadedUris[uri] = true; |
| var value = dj_eval(contents); |
| return 1; |
| } |
| |
| // FIXME: probably need to add logging to this method |
| dojo.hostenv.loadUriAndCheck = function(uri, module, cb){ |
| var ok = true; |
| try{ |
| ok = this.loadUri(uri, cb); |
| }catch(e){ |
| dojo.debug("failed loading ", uri, " with error: ", e); |
| } |
| return ((ok)&&(this.findModule(module, false))) ? true : false; |
| } |
| |
| dojo.loaded = function(){ } |
| |
| dojo.hostenv.loaded = function(){ |
| this.post_load_ = true; |
| var mll = this.modulesLoadedListeners; |
| for(var x=0; x<mll.length; x++){ |
| mll[x](); |
| } |
| dojo.loaded(); |
| } |
| |
| /* |
| Call styles: |
| dojo.addOnLoad(functionPointer) |
| dojo.addOnLoad(object, "functionName") |
| */ |
| dojo.addOnLoad = function(obj, fcnName) { |
| if(arguments.length == 1) { |
| dojo.hostenv.modulesLoadedListeners.push(obj); |
| } else if(arguments.length > 1) { |
| dojo.hostenv.modulesLoadedListeners.push(function() { |
| obj[fcnName](); |
| }); |
| } |
| }; |
| |
| dojo.hostenv.modulesLoaded = function(){ |
| if(this.post_load_){ return; } |
| if((this.loadUriStack.length==0)&&(this.getTextStack.length==0)){ |
| if(this.inFlightCount > 0){ |
| dojo.debug("files still in flight!"); |
| return; |
| } |
| if(typeof setTimeout == "object"){ |
| setTimeout("dojo.hostenv.loaded();", 0); |
| }else{ |
| dojo.hostenv.loaded(); |
| } |
| } |
| } |
| |
| dojo.hostenv.moduleLoaded = function(modulename){ |
| var modref = dojo.evalObjPath((modulename.split(".").slice(0, -1)).join('.')); |
| this.loaded_modules_[(new String(modulename)).toLowerCase()] = modref; |
| } |
| |
| /** |
| * loadModule("A.B") first checks to see if symbol A.B is defined. |
| * If it is, it is simply returned (nothing to do). |
| * |
| * If it is not defined, it will look for "A/B.js" in the script root directory, |
| * followed by "A.js". |
| * |
| * It throws if it cannot find a file to load, or if the symbol A.B is not |
| * defined after loading. |
| * |
| * It returns the object A.B. |
| * |
| * This does nothing about importing symbols into the current package. |
| * It is presumed that the caller will take care of that. For example, to import |
| * all symbols: |
| * |
| * with (dojo.hostenv.loadModule("A.B")) { |
| * ... |
| * } |
| * |
| * And to import just the leaf symbol: |
| * |
| * var B = dojo.hostenv.loadModule("A.B"); |
| * ... |
| * |
| * dj_load is an alias for dojo.hostenv.loadModule |
| */ |
| dojo.hostenv._global_omit_module_check = false; |
| dojo.hostenv.loadModule = function(modulename, exact_only, omit_module_check){ |
| if(!modulename){ return; } |
| omit_module_check = this._global_omit_module_check || omit_module_check; |
| var module = this.findModule(modulename, false); |
| if(module){ |
| return module; |
| } |
| |
| // protect against infinite recursion from mutual dependencies |
| if(dj_undef(modulename, this.loading_modules_)){ |
| this.addedToLoadingCount.push(modulename); |
| } |
| this.loading_modules_[modulename] = 1; |
| |
| // convert periods to slashes |
| var relpath = modulename.replace(/\./g, '/') + '.js'; |
| |
| var syms = modulename.split("."); |
| var nsyms = modulename.split("."); |
| for (var i = syms.length - 1; i > 0; i--) { |
| var parentModule = syms.slice(0, i).join("."); |
| var parentModulePath = this.getModulePrefix(parentModule); |
| if (parentModulePath != parentModule) { |
| syms.splice(0, i, parentModulePath); |
| break; |
| } |
| } |
| var last = syms[syms.length - 1]; |
| // figure out if we're looking for a full package, if so, we want to do |
| // things slightly diffrently |
| if(last=="*"){ |
| modulename = (nsyms.slice(0, -1)).join('.'); |
| |
| while(syms.length){ |
| syms.pop(); |
| syms.push(this.pkgFileName); |
| relpath = syms.join("/") + '.js'; |
| if(relpath.charAt(0)=="/"){ |
| relpath = relpath.slice(1); |
| } |
| ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null)); |
| if(ok){ break; } |
| syms.pop(); |
| } |
| }else{ |
| relpath = syms.join("/") + '.js'; |
| modulename = nsyms.join('.'); |
| var ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null)); |
| if((!ok)&&(!exact_only)){ |
| syms.pop(); |
| while(syms.length){ |
| relpath = syms.join('/') + '.js'; |
| ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null)); |
| if(ok){ break; } |
| syms.pop(); |
| relpath = syms.join('/') + '/'+this.pkgFileName+'.js'; |
| if(relpath.charAt(0)=="/"){ |
| relpath = relpath.slice(1); |
| } |
| ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null)); |
| if(ok){ break; } |
| } |
| } |
| |
| if((!ok)&&(!omit_module_check)){ |
| dojo.raise("Could not load '" + modulename + "'; last tried '" + relpath + "'"); |
| } |
| } |
| |
| // check that the symbol was defined |
| if(!omit_module_check){ |
| // pass in false so we can give better error |
| module = this.findModule(modulename, false); |
| if(!module){ |
| dojo.raise("symbol '" + modulename + "' is not defined after loading '" + relpath + "'"); |
| } |
| } |
| |
| return module; |
| } |
| |
| /** |
| * startPackage("A.B") follows the path, and at each level creates a new empty |
| * object or uses what already exists. It returns the result. |
| */ |
| dojo.hostenv.startPackage = function(packname){ |
| var syms = packname.split(/\./); |
| if(syms[syms.length-1]=="*"){ |
| syms.pop(); |
| } |
| return dojo.evalObjPath(syms.join("."), true); |
| } |
| |
| /** |
| * findModule("A.B") returns the object A.B if it exists, otherwise null. |
| * @param modulename A string like 'A.B'. |
| * @param must_exist Optional, defualt false. throw instead of returning null |
| * if the module does not currently exist. |
| */ |
| dojo.hostenv.findModule = function(modulename, must_exist) { |
| // check cache |
| /* |
| if(!dj_undef(modulename, this.modules_)){ |
| return this.modules_[modulename]; |
| } |
| */ |
| |
| var lmn = (new String(modulename)).toLowerCase(); |
| |
| if(this.loaded_modules_[lmn]){ |
| return this.loaded_modules_[lmn]; |
| } |
| |
| // see if symbol is defined anyway |
| var module = dojo.evalObjPath(modulename); |
| if((modulename)&&(typeof module != 'undefined')&&(module)){ |
| this.loaded_modules_[lmn] = module; |
| return module; |
| } |
| |
| if(must_exist){ |
| dojo.raise("no loaded module named '" + modulename + "'"); |
| } |
| return null; |
| } |