dojo.provide("dojo.widget.ContentPane"); dojo.require("dojo.widget.*"); dojo.require("dojo.io.*"); dojo.require("dojo.widget.HtmlWidget"); dojo.require("dojo.string"); dojo.require("dojo.string.extras"); dojo.require("dojo.html.style"); dojo.widget.defineWidget( "dojo.widget.ContentPane", dojo.widget.HtmlWidget, function(){ // summary: // A widget that can be used as a standalone widget // or as a baseclass for other widgets // Handles replacement of document fragment using either external uri or javascript/java // generated markup or DomNode content, instanciating widgets within content and runs scripts. // Dont confuse it with an iframe, it only needs document fragments. // It's useful as a child of LayoutContainer, SplitContainer, or TabContainer. // But note that those classes can contain any widget as a child. // scriptScope: Function // reference holder to the inline scripts container, if scriptSeparation is true // bindArgs: String[] // Send in extra args to the dojo.io.bind call // per widgetImpl variables this._styleNodes = []; this._onLoadStack = []; this._onUnloadStack = []; this._callOnUnload = false; this._ioBindObj; // Note: // dont change this value externally this.scriptScope; // undefined for now // loading option // example: // bindArgs="preventCache:false;" overrides cacheContent this.bindArgs = {}; }, { isContainer: true, // loading options // adjustPaths: Boolean // adjust relative paths in markup to fit this page adjustPaths: true, // href: String // The href of the content that displays now // Set this at construction if you want to load externally, // changing href after creation doesnt have any effect, see setUrl href: "", // extractContent Boolean: Extract visible content from inside of
.... extractContent: true, // parseContent Boolean: Construct all widgets that is in content parseContent: true, // cacheContent Boolean: Cache content retreived externally cacheContent: true, // preload: Boolean // Force load of data even if pane is hidden. // Note: // In order to delay download you need to initially hide the node it constructs from preload: false, // refreshOnShow: Boolean // Refresh (re-download) content when pane goes from hidden to shown refreshOnShow: false, // handler: String||Function // Generate pane content from a java function // The name of the java proxy function handler: "", // executeScripts: Boolean // Run scripts within content, extractContent has NO effect on this. // Note: // if true scripts in content will be evaled after content is innerHTML'ed executeScripts: false, // scriptSeparation: Boolean // Run scripts in a separate scope, unique for each ContentPane scriptSeparation: true, // loadingMessage: String // Message that shows while downloading loadingMessage: "Loading...", // isLoaded: Boolean // Tells loading status isLoaded: false, postCreate: function(args, frag, parentComp){ if (this.handler!==""){ this.setHandler(this.handler); } if(this.isShowing() || this.preload){ this.loadContents(); } }, show: function(){ // if refreshOnShow is true, reload the contents every time; otherwise, load only the first time if(this.refreshOnShow){ this.refresh(); }else{ this.loadContents(); } dojo.widget.ContentPane.superclass.show.call(this); }, refresh: function(){ // summary: // Force a refresh (re-download) of content, be sure to turn of cache this.isLoaded=false; this.loadContents(); }, loadContents: function() { // summary: // Download if isLoaded is false, else ignore if ( this.isLoaded ){ return; } if ( dojo.lang.isFunction(this.handler)) { this._runHandler(); } else if ( this.href != "" ) { this._downloadExternalContent(this.href, this.cacheContent && !this.refreshOnShow); } }, setUrl: function(/*String||dojo.uri.Uri*/ url) { // summary: // Reset the (external defined) content of this pane and replace with new url // Note: // It delays the download until widget is shown if preload is false this.href = url; this.isLoaded = false; if ( this.preload || this.isShowing() ){ this.loadContents(); } }, abort: function(){ // summary // Aborts a inflight download of content var bind = this._ioBindObj; if(!bind || !bind.abort){ return; } bind.abort(); delete this._ioBindObj; }, _downloadExternalContent: function(url, useCache) { this.abort(); this._handleDefaults(this.loadingMessage, "onDownloadStart"); var self = this; this._ioBindObj = dojo.io.bind( this._cacheSetting({ url: url, mimetype: "text/html", handler: function(type, data, xhr){ delete self._ioBindObj; // makes sure abort doesnt clear cache if(type=="load"){ self.onDownloadEnd.call(self, url, data); }else{ // XHR isnt a normal JS object, IE doesnt have prototype on XHR so we cant extend it or shallowCopy it var e = { responseText: xhr.responseText, status: xhr.status, statusText: xhr.statusText, responseHeaders: xhr.getAllResponseHeaders(), text: "Error loading '" + url + "' (" + xhr.status + " "+ xhr.statusText + ")" }; self._handleDefaults.call(self, e, "onDownloadError"); self.onLoad(); } } }, useCache) ); }, _cacheSetting: function(bindObj, useCache){ for(var x in this.bindArgs){ if(dojo.lang.isUndefined(bindObj[x])){ bindObj[x] = this.bindArgs[x]; } } if(dojo.lang.isUndefined(bindObj.useCache)){ bindObj.useCache = useCache; } if(dojo.lang.isUndefined(bindObj.preventCache)){ bindObj.preventCache = !useCache; } if(dojo.lang.isUndefined(bindObj.mimetype)){ bindObj.mimetype = "text/html"; } return bindObj; }, onLoad: function(e){ // summary: // Event hook, is called after everything is loaded and widgetified this._runStack("_onLoadStack"); this.isLoaded=true; }, onUnLoad: function(e){ // summary: // Deprecated, use onUnload (lowercased load) dojo.deprecated(this.widgetType+".onUnLoad, use .onUnload (lowercased load)", 0.5); }, onUnload: function(e){ // summary: // Event hook, is called before old content is cleared this._runStack("_onUnloadStack"); delete this.scriptScope; // FIXME: remove for 0.5 along with onUnLoad if(this.onUnLoad !== dojo.widget.ContentPane.prototype.onUnLoad){ this.onUnLoad.apply(this, arguments); } }, _runStack: function(stName){ var st = this[stName]; var err = ""; var scope = this.scriptScope || window; for(var i = 0;i < st.length; i++){ try{ st[i].call(scope); }catch(e){ err += "\n"+st[i]+" failed: "+e.description; } } this[stName] = []; if(err.length){ var name = (stName== "_onLoadStack") ? "addOnLoad" : "addOnUnLoad"; this._handleDefaults(name+" failure\n "+err, "onExecError", "debug"); } }, addOnLoad: function(obj, func){ // summary // Stores function refs and calls them one by one in the order they came in // when load event occurs. // obj: Function||Object? // holder object // func: Function // function that will be called this._pushOnStack(this._onLoadStack, obj, func); }, addOnUnload: function(obj, func){ // summary // Stores function refs and calls them one by one in the order they came in // when unload event occurs. // obj: Function||Object // holder object // func: Function // function that will be called this._pushOnStack(this._onUnloadStack, obj, func); }, addOnUnLoad: function(){ // summary: // Deprecated use addOnUnload (lower cased load) dojo.deprecated(this.widgetType + ".addOnUnLoad, use addOnUnload instead. (lowercased Load)", 0.5); this.addOnUnload.apply(this, arguments); }, _pushOnStack: function(stack, obj, func){ if(typeof func == 'undefined') { stack.push(obj); }else{ stack.push(function(){ obj[func](); }); } }, destroy: function(){ // make sure we call onUnload this.onUnload(); dojo.widget.ContentPane.superclass.destroy.call(this); }, onExecError: function(/*Object*/e){ // summary: // called when content script eval error or Java error occurs, preventDefault-able // default is to debug not alert as in 0.3.1 }, onContentError: function(/*Object*/e){ // summary: // called on DOM faults, require fault etc in content, preventDefault-able // default is to display errormessage inside pane }, onDownloadError: function(/*Object*/e){ // summary: // called when download error occurs, preventDefault-able // default is to display errormessage inside pane }, onDownloadStart: function(/*Object*/e){ // summary: // called before download starts, preventDefault-able // default is to display loadingMessage inside pane // by changing e.text in your event handler you can change loading message }, // onDownloadEnd: function(url, data){ // summary: // called when download is finished // // url String: url that downloaded data // data String: the markup that was downloaded data = this.splitAndFixPaths(data, url); this.setContent(data); }, // useful if user wants to prevent default behaviour ie: _setContent("Error...") _handleDefaults: function(e, handler, messType){ if(!handler){ handler = "onContentError"; } if(dojo.lang.isString(e)){ e = {text: e}; } if(!e.text){ e.text = e.toString(); } e.toString = function(){ return this.text; }; if(typeof e.returnValue != "boolean"){ e.returnValue = true; } if(typeof e.preventDefault != "function"){ e.preventDefault = function(){ this.returnValue = false; }; } // call our handler this[handler](e); if(e.returnValue){ switch(messType){ case true: // fallthrough, old compat case "alert": alert(e.toString()); break; case "debug": dojo.debug(e.toString()); break; default: // makes sure scripts can clean up after themselves, before we setContent if(this._callOnUnload){ this.onUnload(); } // makes sure we dont try to call onUnLoad again on this event, // ie onUnLoad before 'Loading...' but not before clearing 'Loading...' this._callOnUnload = false; // we might end up in a endless recursion here if domNode cant append content if(arguments.callee._loopStop){ dojo.debug(e.toString()); }else{ arguments.callee._loopStop = true; this._setContent(e.toString()); } } } arguments.callee._loopStop = false; }, // pathfixes, require calls, css stuff and neccesary content clean splitAndFixPaths: function(s, url){ // summary: // adjusts all relative paths in (hopefully) all cases, images, remote scripts, links etc. // splits up content in different pieces, scripts, title, style, link and whats left becomes .xml // s String: The markup in string // url (String||dojo.uri.Uri?) url that pulled in markup var titles = [], scripts = [],tmp = [];// init vars var match = [], requires = [], attr = [], styles = []; var str = '', path = '', fix = '', tagFix = '', tag = '', origPath = ''; if(!url) { url = "./"; } // point to this page if not set if(s){ // make sure we dont run regexes on empty content /**************