1 // TODO: this file needs to be converted to the v1.7 loader
3 // a host environment specifically built for Mozilla extensions, but derived
4 // from the browser host environment
5 if(typeof window != 'undefined'){
7 dojo._name = "browser";
11 // http://developer.mozilla.org/en/mozIJSSubScriptLoader
14 // attempt to figure out the path to dojo if it isn't set in the config
16 // this is a scope protection closure. We set browser versions and grab
17 // the URL we were loaded from here.
19 // FIXME: need to probably use a different reference to "document" to get the hosting XUL environment
21 dojo.baseUrl = dojo.config.baseUrl;
23 // fill in the rendering support information in dojo.render.*
25 var dua = n.userAgent;
26 var dav = n.appVersion;
27 var tv = parseFloat(dav);
29 dojo.isMozilla = dojo.isMoz = tv;
31 dojo.isFF = parseFloat(dua.split("Firefox/")[1]) || undefined;
35 dojo.isQuirks = document.compatMode == "BackCompat";
38 // TODO: is the HTML LANG attribute relevant?
39 dojo.locale = dojo.config.locale || n.language.toLowerCase();
41 dojo._xhrObj = function(){
42 return new XMLHttpRequest();
45 // monkey-patch _loadUri to handle file://, chrome://, and resource:// url's
46 var oldLoadUri = dojo._loadUri;
47 dojo._loadUri = function(uri, cb){
48 var handleLocal = ["file:", "chrome:", "resource:"].some(function(prefix){
49 return String(uri).indexOf(prefix) == 0;
53 // http://developer.mozilla.org/en/mozIJSSubScriptLoader
54 var l = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
55 .getService(Components.interfaces.mozIJSSubScriptLoader);
56 var value = l.loadSubScript(uri, dojo.global);
60 // otherwise, call the pre-existing version
61 return oldLoadUri.apply(dojo, arguments);
66 dojo._isDocumentOk = function(http){
67 var stat = http.status || 0;
68 return (stat >= 200 && stat < 300) || // Boolean
69 stat == 304 || // allow any 2XX response code
70 stat == 1223 || // get it out of the cache
71 (!stat && (location.protocol == "file:" || location.protocol == "chrome:") );
75 // var owloc = window.location+"";
76 // var base = document.getElementsByTagName("base");
77 // var hasBase = (base && base.length > 0);
80 dojo._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
82 // Read the contents of the specified uri and return those contents.
84 // A relative or absolute uri. If absolute, it still must be in
85 // the same "domain" as we are.
87 // Default false. If fail_ok and loading fails, return null
88 // instead of throwing.
90 // The response text. null is returned when there is a
91 // failure and failure is okay (an exception otherwise)
93 // alert("_getText: " + uri);
95 // NOTE: must be declared before scope switches ie. this._xhrObj()
96 var http = dojo._xhrObj();
98 if(!hasBase && dojo._Url){
99 uri = (new dojo._Url(uri)).toString();
101 if(dojo.config.cacheBust){
102 //Make sure we have a string before string methods are used on uri
104 uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(dojo.config.cacheBust).replace(/\W+/g, "");
106 var handleLocal = ["file:", "chrome:", "resource:"].some(function(prefix){
107 return String(uri).indexOf(prefix) == 0;
111 // http://forums.mozillazine.org/viewtopic.php?p=921150#921150
112 var ioService = Components.classes["@mozilla.org/network/io-service;1"]
113 .getService(Components.interfaces.nsIIOService);
114 var scriptableStream = Components
115 .classes["@mozilla.org/scriptableinputstream;1"]
116 .getService(Components.interfaces.nsIScriptableInputStream);
118 var channel = ioService.newChannel(uri, null, null);
119 var input = channel.open();
120 scriptableStream.init(input);
121 var str = scriptableStream.read(input.available());
122 scriptableStream.close();
126 http.open('GET', uri, false);
130 if(!dojo._isDocumentOk(http)){
131 var err = Error("Unable to load " + uri + " status:" + http.status);
132 err.status = http.status;
133 err.responseText = http.responseText;
140 // rethrow the exception
143 return http.responseText; // String
147 dojo._windowUnloaders = [];
150 dojo.windowUnloaded = function(){
152 // signal fired by impending window destruction. You may use
153 // dojo.addOnWIndowUnload() or dojo.connect() to this method to perform
154 // page/application cleanup methods. See dojo.addOnWindowUnload for more info.
155 var mll = dojo._windowUnloaders;
162 dojo.addOnWindowUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
164 // registers a function to be triggered when window.onunload fires.
165 // Be careful trying to modify the DOM or access JavaScript properties
166 // during this phase of page unloading: they may not always be available.
167 // Consider dojo.addOnUnload() if you need to modify the DOM or do heavy
170 // | dojo.addOnWindowUnload(functionPointer)
171 // | dojo.addOnWindowUnload(object, "functionName")
172 // | dojo.addOnWindowUnload(object, function(){ /* ... */});
174 dojo._onto(dojo._windowUnloaders, obj, functionName);
180 dojo._defaultContext = [ window, document ];
182 dojo.pushContext = function(/*Object|String?*/g, /*MDocumentElement?*/d){
184 // causes subsequent calls to Dojo methods to assume the
185 // passed object and, optionally, document as the default
186 // scopes to use. A 2-element array of the previous global and
187 // document are returned.
189 // dojo.pushContext treats contexts as a stack. The
190 // auto-detected contexts which are initially provided using
191 // dojo.setContext() require authors to keep state in order to
192 // "return" to a previous context, whereas the
193 // dojo.pushContext and dojo.popContext methods provide a more
194 // natural way to augment blocks of code to ensure that they
195 // execute in a different window or frame without issue. If
196 // called without any arguments, the default context (the
197 // context when Dojo is first loaded) is instead pushed into
198 // the stack. If only a single string is passed, a node in the
199 // intitial context's document is looked up and its
200 // contextWindow and contextDocument properties are used as
201 // the context to push. This means that iframes can be given
202 // an ID and code can be executed in the scope of the iframe's
203 // document in subsequent calls easily.
205 // The global context. If a string, the id of the frame to
206 // search for a context and document.
208 // The document element to execute subsequent code with.
209 var old = [dojo.global, dojo.doc];
213 n = dojo._defaultContext;
216 if(!d && dojo.isString(g)){
217 var t = document.getElementById(g);
218 if(t.contentDocument){
219 n = [t.contentWindow, t.contentDocument];
224 dojo.setContext.apply(dojo, n);
228 dojo.popContext = function(){
230 // If the context stack contains elements, ensure that
231 // subsequent code executes in the *previous* context to the
232 // current context. The current context set ([global,
233 // document]) is returned.
235 if(!contexts.length){
238 dojo.setContext.apply(dojo, contexts.pop());
243 // don't really like the current arguments and order to
244 // _inContext, so don't make it public until it's right!
245 dojo._inContext = function(g, d, f){
246 var a = dojo._toArray(arguments);
251 dojo.pushContext(g, d);
259 dojo._initFired = false;
260 // BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
261 dojo._loadInit = function(e){
262 dojo._initFired = true;
263 // allow multiple calls, only first one will take effect
264 // A bug in khtml calls events callbacks for document for event which isnt supported
265 // for example a created contextmenu event calls DOMContentLoaded, workaround
266 var type = (e && e.type) ? e.type.toLowerCase() : "load";
267 if(arguments.callee.initialized || (type != "domcontentloaded" && type != "load")){ return; }
268 arguments.callee.initialized = true;
269 if(dojo._inFlightCount == 0){
270 dojo._modulesLoaded();
277 var _handleNodeEvent = function(evtName, fp){
279 // non-destructively adds the specified function to the node's
281 // evtName: should be in the form "onclick" for "onclick" handlers.
282 // Make sure you pass in the "on" part.
283 var oldHandler = _w[evtName] || function(){};
284 _w[evtName] = function(){
285 fp.apply(_w, arguments);
286 oldHandler.apply(_w, arguments);
290 // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
291 _handleNodeEvent("onbeforeunload", function(){ dojo.unloaded(); });
292 _handleNodeEvent("onunload", function(){ dojo.windowUnloaded(); });
298 // this event fires a lot, namely for all plugin XUL overlays and for
299 // all iframes (in addition to window navigations). We only want
300 // Dojo's to fire once..but we might care if pages navigate. We'll
301 // probably need an extension-specific API
302 if(!dojo.config.afterOnLoad){
303 window.addEventListener("DOMContentLoaded", function(e){
305 // console.log("DOM content loaded", e);
309 } //if (typeof window != 'undefined')
311 //Register any module paths set up in djConfig. Need to do this
312 //in the hostenvs since hostenv_browser can read djConfig from a
313 //script tag's attribute.
315 var mp = dojo.config["modulePaths"];
317 for(var param in mp){
318 dojo.registerModulePath(param, mp[param]);
323 //Load debug code if necessary.
324 if(dojo.config.isDebug){
325 // logging stub for extension logging
326 console.log = function(m){
327 var s = Components.classes["@mozilla.org/consoleservice;1"].getService(
328 Components.interfaces.nsIConsoleService
330 s.logStringMessage(m);
332 console.debug = function(){
333 console.log(dojo._toArray(arguments).join(" "));
335 // FIXME: what about the rest of the console.* methods? And is there any way to reach into firebug and log into it directly?