summaryrefslogtreecommitdiff
path: root/lib/dijit/layout/ContentPane.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/layout/ContentPane.js')
-rw-r--r--lib/dijit/layout/ContentPane.js860
1 files changed, 581 insertions, 279 deletions
diff --git a/lib/dijit/layout/ContentPane.js b/lib/dijit/layout/ContentPane.js
index 56952800a..399ec1bc9 100644
--- a/lib/dijit/layout/ContentPane.js
+++ b/lib/dijit/layout/ContentPane.js
@@ -1,291 +1,593 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit.layout.ContentPane"]){
-dojo._hasResource["dijit.layout.ContentPane"]=true;
+if(!dojo._hasResource["dijit.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.ContentPane"] = true;
dojo.provide("dijit.layout.ContentPane");
dojo.require("dijit._Widget");
-dojo.require("dijit._Contained");
-dojo.require("dijit.layout._LayoutWidget");
-dojo.require("dojo.parser");
+dojo.require("dijit.layout._ContentPaneResizeMixin");
dojo.require("dojo.string");
dojo.require("dojo.html");
-dojo.requireLocalization("dijit","loading",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
-dojo.declare("dijit.layout.ContentPane",dijit._Widget,{href:"",extractContent:false,parseOnLoad:true,preventCache:false,preload:false,refreshOnShow:false,loadingMessage:"<span class='dijitContentPaneLoading'>${loadingState}</span>",errorMessage:"<span class='dijitContentPaneError'>${errorState}</span>",isLoaded:false,baseClass:"dijitContentPane",doLayout:true,ioArgs:{},isContainer:true,isLayoutContainer:true,onLoadDeferred:null,attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{title:[]}),postMixInProperties:function(){
-this.inherited(arguments);
-var _1=dojo.i18n.getLocalization("dijit","loading",this.lang);
-this.loadingMessage=dojo.string.substitute(this.loadingMessage,_1);
-this.errorMessage=dojo.string.substitute(this.errorMessage,_1);
-if(!this.href&&this.srcNodeRef&&this.srcNodeRef.innerHTML){
-this.isLoaded=true;
-}
-},buildRendering:function(){
-this.inherited(arguments);
-if(!this.containerNode){
-this.containerNode=this.domNode;
-}
-},postCreate:function(){
-this.domNode.title="";
-if(!dojo.attr(this.domNode,"role")){
-dijit.setWaiRole(this.domNode,"group");
-}
-dojo.addClass(this.domNode,this.baseClass);
-},startup:function(){
-if(this._started){
-return;
-}
-var _2=dijit._Contained.prototype.getParent.call(this);
-this._childOfLayoutWidget=_2&&_2.isLayoutContainer;
-this._needLayout=!this._childOfLayoutWidget;
-if(this.isLoaded){
-dojo.forEach(this.getChildren(),function(_3){
-_3.startup();
-});
-}
-if(this._isShown()||this.preload){
-this._onShow();
-}
-this.inherited(arguments);
-},_checkIfSingleChild:function(){
-var _4=dojo.query("> *",this.containerNode).filter(function(_5){
-return _5.tagName!=="SCRIPT";
-}),_6=_4.filter(function(_7){
-return dojo.hasAttr(_7,"dojoType")||dojo.hasAttr(_7,"widgetId");
-}),_8=dojo.filter(_6.map(dijit.byNode),function(_9){
-return _9&&_9.domNode&&_9.resize;
-});
-if(_4.length==_6.length&&_8.length==1){
-this._singleChild=_8[0];
-}else{
-delete this._singleChild;
-}
-dojo.toggleClass(this.containerNode,this.baseClass+"SingleChild",!!this._singleChild);
-},setHref:function(_a){
-dojo.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.","","2.0");
-return this.set("href",_a);
-},_setHrefAttr:function(_b){
-this.cancel();
-this.onLoadDeferred=new dojo.Deferred(dojo.hitch(this,"cancel"));
-this.href=_b;
-if(this._created&&(this.preload||this._isShown())){
-this._load();
-}else{
-this._hrefChanged=true;
-}
-return this.onLoadDeferred;
-},setContent:function(_c){
-dojo.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.","","2.0");
-this.set("content",_c);
-},_setContentAttr:function(_d){
-this.href="";
-this.cancel();
-this.onLoadDeferred=new dojo.Deferred(dojo.hitch(this,"cancel"));
-this._setContent(_d||"");
-this._isDownloaded=false;
-return this.onLoadDeferred;
-},_getContentAttr:function(){
-return this.containerNode.innerHTML;
-},cancel:function(){
-if(this._xhrDfd&&(this._xhrDfd.fired==-1)){
-this._xhrDfd.cancel();
-}
-delete this._xhrDfd;
-this.onLoadDeferred=null;
-},uninitialize:function(){
-if(this._beingDestroyed){
-this.cancel();
-}
-this.inherited(arguments);
-},destroyRecursive:function(_e){
-if(this._beingDestroyed){
-return;
-}
-this.inherited(arguments);
-},resize:function(_f,_10){
-if(!this._wasShown){
-this._onShow();
-}
-this._resizeCalled=true;
-if(_f){
-dojo.marginBox(this.domNode,_f);
-}
-var cn=this.containerNode;
-if(cn===this.domNode){
-var mb=_10||{};
-dojo.mixin(mb,_f||{});
-if(!("h" in mb)||!("w" in mb)){
-mb=dojo.mixin(dojo.marginBox(cn),mb);
-}
-this._contentBox=dijit.layout.marginBox2contentBox(cn,mb);
-}else{
-this._contentBox=dojo.contentBox(cn);
-}
-this._layoutChildren();
-},_isShown:function(){
-if(this._childOfLayoutWidget){
-if(this._resizeCalled&&"open" in this){
-return this.open;
-}
-return this._resizeCalled;
-}else{
-if("open" in this){
-return this.open;
-}else{
-var _11=this.domNode;
-return (_11.style.display!="none")&&(_11.style.visibility!="hidden")&&!dojo.hasClass(_11,"dijitHidden");
-}
-}
-},_onShow:function(){
-if(this.href){
-if(!this._xhrDfd&&(!this.isLoaded||this._hrefChanged||this.refreshOnShow)){
-this.refresh();
-}
-}else{
-if(!this._childOfLayoutWidget&&this._needLayout){
-this._layoutChildren();
-}
-}
-this.inherited(arguments);
-this._wasShown=true;
-},refresh:function(){
-this.cancel();
-this.onLoadDeferred=new dojo.Deferred(dojo.hitch(this,"cancel"));
-this._load();
-return this.onLoadDeferred;
-},_load:function(){
-this._setContent(this.onDownloadStart(),true);
-var _12=this;
-var _13={preventCache:(this.preventCache||this.refreshOnShow),url:this.href,handleAs:"text"};
-if(dojo.isObject(this.ioArgs)){
-dojo.mixin(_13,this.ioArgs);
-}
-var _14=(this._xhrDfd=(this.ioMethod||dojo.xhrGet)(_13));
-_14.addCallback(function(_15){
-try{
-_12._isDownloaded=true;
-_12._setContent(_15,false);
-_12.onDownloadEnd();
-}
-catch(err){
-_12._onError("Content",err);
-}
-delete _12._xhrDfd;
-return _15;
-});
-_14.addErrback(function(err){
-if(!_14.canceled){
-_12._onError("Download",err);
-}
-delete _12._xhrDfd;
-return err;
-});
-delete this._hrefChanged;
-},_onLoadHandler:function(_16){
-this.isLoaded=true;
-try{
-this.onLoadDeferred.callback(_16);
-this.onLoad(_16);
-}
-catch(e){
-console.error("Error "+this.widgetId+" running custom onLoad code: "+e.message);
-}
-},_onUnloadHandler:function(){
-this.isLoaded=false;
-try{
-this.onUnload();
-}
-catch(e){
-console.error("Error "+this.widgetId+" running custom onUnload code: "+e.message);
-}
-},destroyDescendants:function(){
-if(this.isLoaded){
-this._onUnloadHandler();
-}
-var _17=this._contentSetter;
-dojo.forEach(this.getChildren(),function(_18){
-if(_18.destroyRecursive){
-_18.destroyRecursive();
-}
-});
-if(_17){
-dojo.forEach(_17.parseResults,function(_19){
-if(_19.destroyRecursive&&_19.domNode&&_19.domNode.parentNode==dojo.body()){
-_19.destroyRecursive();
-}
-});
-delete _17.parseResults;
-}
-dojo.html._emptyNode(this.containerNode);
-delete this._singleChild;
-},_setContent:function(_1a,_1b){
-this.destroyDescendants();
-var _1c=this._contentSetter;
-if(!(_1c&&_1c instanceof dojo.html._ContentSetter)){
-_1c=this._contentSetter=new dojo.html._ContentSetter({node:this.containerNode,_onError:dojo.hitch(this,this._onError),onContentError:dojo.hitch(this,function(e){
-var _1d=this.onContentError(e);
-try{
-this.containerNode.innerHTML=_1d;
-}
-catch(e){
-console.error("Fatal "+this.id+" could not change content due to "+e.message,e);
-}
-})});
-}
-var _1e=dojo.mixin({cleanContent:this.cleanContent,extractContent:this.extractContent,parseContent:this.parseOnLoad,dir:this.dir,lang:this.lang},this._contentSetterParams||{});
-dojo.mixin(_1c,_1e);
-_1c.set((dojo.isObject(_1a)&&_1a.domNode)?_1a.domNode:_1a);
-delete this._contentSetterParams;
-if(!_1b){
-dojo.forEach(this.getChildren(),function(_1f){
-if(!this.parseOnLoad||_1f.getParent){
-_1f.startup();
-}
-},this);
-this._scheduleLayout();
-this._onLoadHandler(_1a);
-}
-},_onError:function(_20,err,_21){
-this.onLoadDeferred.errback(err);
-var _22=this["on"+_20+"Error"].call(this,err);
-if(_21){
-console.error(_21,err);
-}else{
-if(_22){
-this._setContent(_22,true);
-}
-}
-},_scheduleLayout:function(){
-if(this._isShown()){
-this._layoutChildren();
-}else{
-this._needLayout=true;
-}
-},_layoutChildren:function(){
-if(this.doLayout){
-this._checkIfSingleChild();
-}
-if(this._singleChild&&this._singleChild.resize){
-var cb=this._contentBox||dojo.contentBox(this.containerNode);
-this._singleChild.resize({w:cb.w,h:cb.h});
-}else{
-dojo.forEach(this.getChildren(),function(_23){
-if(_23.resize){
-_23.resize();
-}
+dojo.requireLocalization("dijit", "loading", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
+
+
+dojo.declare(
+ "dijit.layout.ContentPane", [dijit._Widget, dijit.layout._ContentPaneResizeMixin],
+{
+ // summary:
+ // A widget containing an HTML fragment, specified inline
+ // or by uri. Fragment may include widgets.
+ //
+ // description:
+ // This widget embeds a document fragment in the page, specified
+ // either by uri, javascript generated markup or DOM reference.
+ // Any widgets within this content are instantiated and managed,
+ // but laid out according to the HTML structure. Unlike IFRAME,
+ // ContentPane embeds a document fragment as would be found
+ // inside the BODY tag of a full HTML document. It should not
+ // contain the HTML, HEAD, or BODY tags.
+ // For more advanced functionality with scripts and
+ // stylesheets, see dojox.layout.ContentPane. This widget may be
+ // used stand alone or as a base class for other widgets.
+ // ContentPane is useful as a child of other layout containers
+ // such as BorderContainer or TabContainer, but note that those
+ // widgets can contain any widget as a child.
+ //
+ // example:
+ // Some quick samples:
+ // To change the innerHTML: cp.set('content', '<b>new content</b>')
+ //
+ // Or you can send it a NodeList: cp.set('content', dojo.query('div [class=selected]', userSelection))
+ //
+ // To do an ajax update: cp.set('href', url)
+
+ // href: String
+ // The href of the content that displays now.
+ // Set this at construction if you want to load data externally when the
+ // pane is shown. (Set preload=true to load it immediately.)
+ // Changing href after creation doesn't have any effect; Use set('href', ...);
+ href: "",
+
+/*=====
+ // content: String || DomNode || NodeList || dijit._Widget
+ // The innerHTML of the ContentPane.
+ // Note that the initialization parameter / argument to set("content", ...)
+ // can be a String, DomNode, Nodelist, or _Widget.
+ content: "",
+=====*/
+
+ // extractContent: Boolean
+ // Extract visible content from inside of <body> .... </body>.
+ // I.e., strip <html> and <head> (and it's contents) from the href
+ extractContent: false,
+
+ // parseOnLoad: Boolean
+ // Parse content and create the widgets, if any.
+ parseOnLoad: true,
+
+ // parserScope: String
+ // Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
+ // will search for data-dojo-type (or dojoType). For backwards compatibility
+ // reasons defaults to dojo._scopeName (which is "dojo" except when
+ // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
+ parserScope: dojo._scopeName,
+
+ // preventCache: Boolean
+ // Prevent caching of data from href's by appending a timestamp to the href.
+ preventCache: false,
+
+ // preload: Boolean
+ // Force load of data on initialization even if pane is hidden.
+ preload: false,
+
+ // refreshOnShow: Boolean
+ // Refresh (re-download) content when pane goes from hidden to shown
+ refreshOnShow: false,
+
+ // loadingMessage: String
+ // Message that shows while downloading
+ loadingMessage: "<span class='dijitContentPaneLoading'>${loadingState}</span>",
+
+ // errorMessage: String
+ // Message that shows if an error occurs
+ errorMessage: "<span class='dijitContentPaneError'>${errorState}</span>",
+
+ // isLoaded: [readonly] Boolean
+ // True if the ContentPane has data in it, either specified
+ // during initialization (via href or inline content), or set
+ // via set('content', ...) / set('href', ...)
+ //
+ // False if it doesn't have any content, or if ContentPane is
+ // still in the process of downloading href.
+ isLoaded: false,
+
+ baseClass: "dijitContentPane",
+
+ // ioArgs: Object
+ // Parameters to pass to xhrGet() request, for example:
+ // | <div dojoType="dijit.layout.ContentPane" href="./bar" ioArgs="{timeout: 500}">
+ ioArgs: {},
+
+ // onLoadDeferred: [readonly] dojo.Deferred
+ // This is the `dojo.Deferred` returned by set('href', ...) and refresh().
+ // Calling onLoadDeferred.addCallback() or addErrback() registers your
+ // callback to be called only once, when the prior set('href', ...) call or
+ // the initial href parameter to the constructor finishes loading.
+ //
+ // This is different than an onLoad() handler which gets called any time any href
+ // or content is loaded.
+ onLoadDeferred: null,
+
+ // Override _Widget's attributeMap because we don't want the title attribute (used to specify
+ // tab labels) to be copied to ContentPane.domNode... otherwise a tooltip shows up over the
+ // entire pane.
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ title: []
+ }),
+
+ // Flag to parser that I'll parse my contents, so it shouldn't.
+ stopParser: true,
+
+ // template: [private] Boolean
+ // Flag from the parser that this ContentPane is inside a template
+ // so the contents are pre-parsed.
+ // (TODO: this declaration can be commented out in 2.0)
+ template: false,
+
+ create: function(params, srcNodeRef){
+ // Convert a srcNodeRef argument into a content parameter, so that the original contents are
+ // processed in the same way as contents set via set("content", ...), calling the parser etc.
+ // Avoid modifying original params object since that breaks NodeList instantiation, see #11906.
+ if((!params || !params.template) && srcNodeRef && !("href" in params) && !("content" in params)){
+ var df = dojo.doc.createDocumentFragment();
+ srcNodeRef = dojo.byId(srcNodeRef)
+ while(srcNodeRef.firstChild){
+ df.appendChild(srcNodeRef.firstChild);
+ }
+ params = dojo.delegate(params, {content: df});
+ }
+ this.inherited(arguments, [params, srcNodeRef]);
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
+ this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
+ this.errorMessage = dojo.string.substitute(this.errorMessage, messages);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ // Since we have no template we need to set this.containerNode ourselves, to make getChildren() work.
+ // For subclasses of ContentPane that do have a template, does nothing.
+ if(!this.containerNode){
+ this.containerNode = this.domNode;
+ }
+
+ // remove the title attribute so it doesn't show up when hovering
+ // over a node (TODO: remove in 2.0, no longer needed after #11490)
+ this.domNode.title = "";
+
+ if(!dojo.attr(this.domNode,"role")){
+ dijit.setWaiRole(this.domNode, "group");
+ }
+ },
+
+ _startChildren: function(){
+ // summary:
+ // Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
+
+ // This starts all the widgets
+ this.inherited(arguments);
+
+ // And this catches stuff like dojo.dnd.Source
+ if(this._contentSetter){
+ dojo.forEach(this._contentSetter.parseResults, function(obj){
+ if(!obj._started && !obj._destroyed && dojo.isFunction(obj.startup)){
+ obj.startup();
+ obj._started = true;
+ }
+ }, this);
+ }
+ },
+
+ setHref: function(/*String|Uri*/ href){
+ // summary:
+ // Deprecated. Use set('href', ...) instead.
+ dojo.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.", "", "2.0");
+ return this.set("href", href);
+ },
+ _setHrefAttr: function(/*String|Uri*/ href){
+ // summary:
+ // Hook so set("href", ...) works.
+ // description:
+ // 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.
+ // href:
+ // url to the page you want to get, must be within the same domain as your mainpage
+
+ // Cancel any in-flight requests (a set('href', ...) will cancel any in-flight set('href', ...))
+ this.cancel();
+
+ this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+ this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
+
+ this._set("href", href);
+
+ // _setHrefAttr() is called during creation and by the user, after creation.
+ // Assuming preload == false, only in the second case do we actually load the URL;
+ // otherwise it's done in startup(), and only if this widget is shown.
+ if(this.preload || (this._created && this._isShown())){
+ this._load();
+ }else{
+ // Set flag to indicate that href needs to be loaded the next time the
+ // ContentPane is made visible
+ this._hrefChanged = true;
+ }
+
+ return this.onLoadDeferred; // dojo.Deferred
+ },
+
+ setContent: function(/*String|DomNode|Nodelist*/data){
+ // summary:
+ // Deprecated. Use set('content', ...) instead.
+ dojo.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.", "", "2.0");
+ this.set("content", data);
+ },
+ _setContentAttr: function(/*String|DomNode|Nodelist*/data){
+ // summary:
+ // Hook to make set("content", ...) work.
+ // Replaces old content with data content, include style classes from old content
+ // data:
+ // the new Content may be String, DomNode or NodeList
+ //
+ // if data is a NodeList (or an array of nodes) nodes are copied
+ // so you can import nodes from another document implicitly
+
+ // clear href so we can't run refresh and clear content
+ // refresh should only work if we downloaded the content
+ this._set("href", "");
+
+ // Cancel any in-flight requests (a set('content', ...) will cancel any in-flight set('href', ...))
+ this.cancel();
+
+ // Even though user is just setting content directly, still need to define an onLoadDeferred
+ // because the _onLoadHandler() handler is still getting called from setContent()
+ this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+ if(this._created){
+ // For back-compat reasons, call onLoad() for set('content', ...)
+ // calls but not for content specified in srcNodeRef (ie: <div dojoType=ContentPane>...</div>)
+ // or as initialization parameter (ie: new ContentPane({content: ...})
+ this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
+ }
+
+ this._setContent(data || "");
+
+ this._isDownloaded = false; // mark that content is from a set('content') not a set('href')
+
+ return this.onLoadDeferred; // dojo.Deferred
+ },
+ _getContentAttr: function(){
+ // summary:
+ // Hook to make get("content") work
+ return this.containerNode.innerHTML;
+ },
+
+ cancel: function(){
+ // summary:
+ // Cancels an in-flight download of content
+ if(this._xhrDfd && (this._xhrDfd.fired == -1)){
+ this._xhrDfd.cancel();
+ }
+ delete this._xhrDfd; // garbage collect
+
+ this.onLoadDeferred = null;
+ },
+
+ uninitialize: function(){
+ if(this._beingDestroyed){
+ this.cancel();
+ }
+ this.inherited(arguments);
+ },
+
+ destroyRecursive: function(/*Boolean*/ preserveDom){
+ // summary:
+ // Destroy the ContentPane and its contents
+
+ // if we have multiple controllers destroying us, bail after the first
+ if(this._beingDestroyed){
+ return;
+ }
+ this.inherited(arguments);
+ },
+
+ _onShow: function(){
+ // summary:
+ // Called when the ContentPane is made visible
+ // description:
+ // For a plain ContentPane, this is called on initialization, from startup().
+ // If the ContentPane is a hidden pane of a TabContainer etc., then it's
+ // called whenever the pane is made visible.
+ //
+ // Does necessary processing, including href download and layout/resize of
+ // child widget(s)
+
+ this.inherited(arguments);
+
+ if(this.href){
+ if(!this._xhrDfd && // if there's an href that isn't already being loaded
+ (!this.isLoaded || this._hrefChanged || this.refreshOnShow)
+ ){
+ return this.refresh(); // If child has an href, promise that fires when the load is complete
+ }
+ }
+ },
+
+ refresh: function(){
+ // summary:
+ // [Re]download contents of href and display
+ // description:
+ // 1. cancels any currently in-flight requests
+ // 2. posts "loading..." message
+ // 3. sends XHR to download new data
+
+ // Cancel possible prior in-flight request
+ this.cancel();
+
+ this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+ this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
+ this._load();
+ return this.onLoadDeferred; // If child has an href, promise that fires when refresh is complete
+ },
+
+ _load: function(){
+ // summary:
+ // Load/reload the href specified in this.href
+
+ // display loading message
+ this._setContent(this.onDownloadStart(), true);
+
+ var self = this;
+ var getArgs = {
+ preventCache: (this.preventCache || this.refreshOnShow),
+ url: this.href,
+ handleAs: "text"
+ };
+ if(dojo.isObject(this.ioArgs)){
+ dojo.mixin(getArgs, this.ioArgs);
+ }
+
+ var hand = (this._xhrDfd = (this.ioMethod || dojo.xhrGet)(getArgs));
+
+ hand.addCallback(function(html){
+ try{
+ self._isDownloaded = true;
+ self._setContent(html, false);
+ self.onDownloadEnd();
+ }catch(err){
+ self._onError('Content', err); // onContentError
+ }
+ delete self._xhrDfd;
+ return html;
+ });
+
+ hand.addErrback(function(err){
+ if(!hand.canceled){
+ // show error message in the pane
+ self._onError('Download', err); // onDownloadError
+ }
+ delete self._xhrDfd;
+ return err;
+ });
+
+ // Remove flag saying that a load is needed
+ delete this._hrefChanged;
+ },
+
+ _onLoadHandler: function(data){
+ // summary:
+ // This is called whenever new content is being loaded
+ this._set("isLoaded", true);
+ try{
+ this.onLoadDeferred.callback(data);
+ }catch(e){
+ console.error('Error '+this.widgetId+' running custom onLoad code: ' + e.message);
+ }
+ },
+
+ _onUnloadHandler: function(){
+ // summary:
+ // This is called whenever the content is being unloaded
+ this._set("isLoaded", false);
+ try{
+ this.onUnload();
+ }catch(e){
+ console.error('Error '+this.widgetId+' running custom onUnload code: ' + e.message);
+ }
+ },
+
+ destroyDescendants: function(){
+ // summary:
+ // Destroy all the widgets inside the ContentPane and empty containerNode
+
+ // Make sure we call onUnload (but only when the ContentPane has real content)
+ if(this.isLoaded){
+ this._onUnloadHandler();
+ }
+
+ // Even if this.isLoaded == false there might still be a "Loading..." message
+ // to erase, so continue...
+
+ // For historical reasons we need to delete all widgets under this.containerNode,
+ // even ones that the user has created manually.
+ var setter = this._contentSetter;
+ dojo.forEach(this.getChildren(), function(widget){
+ if(widget.destroyRecursive){
+ widget.destroyRecursive();
+ }
+ });
+ if(setter){
+ // Most of the widgets in setter.parseResults have already been destroyed, but
+ // things like Menu that have been moved to <body> haven't yet
+ dojo.forEach(setter.parseResults, function(widget){
+ if(widget.destroyRecursive && widget.domNode && widget.domNode.parentNode == dojo.body()){
+ widget.destroyRecursive();
+ }
+ });
+ delete setter.parseResults;
+ }
+
+ // And then clear away all the DOM nodes
+ dojo.html._emptyNode(this.containerNode);
+
+ // Delete any state information we have about current contents
+ delete this._singleChild;
+ },
+
+ _setContent: function(/*String|DocumentFragment*/ cont, /*Boolean*/ isFakeContent){
+ // summary:
+ // Insert the content into the container node
+
+ // first get rid of child widgets
+ this.destroyDescendants();
+
+ // dojo.html.set will take care of the rest of the details
+ // we provide an override for the error handling to ensure the widget gets the errors
+ // configure the setter instance with only the relevant widget instance properties
+ // NOTE: unless we hook into attr, or provide property setters for each property,
+ // we need to re-configure the ContentSetter with each use
+ var setter = this._contentSetter;
+ if(! (setter && setter instanceof dojo.html._ContentSetter)){
+ setter = this._contentSetter = new dojo.html._ContentSetter({
+ node: this.containerNode,
+ _onError: dojo.hitch(this, this._onError),
+ onContentError: dojo.hitch(this, function(e){
+ // fires if a domfault occurs when we are appending this.errorMessage
+ // like for instance if domNode is a UL and we try append a DIV
+ var errMess = this.onContentError(e);
+ try{
+ this.containerNode.innerHTML = errMess;
+ }catch(e){
+ console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
+ }
+ })/*,
+ _onError */
+ });
+ };
+
+ var setterParams = dojo.mixin({
+ cleanContent: this.cleanContent,
+ extractContent: this.extractContent,
+ parseContent: this.parseOnLoad,
+ parserScope: this.parserScope,
+ startup: false,
+ dir: this.dir,
+ lang: this.lang
+ }, this._contentSetterParams || {});
+
+ setter.set( (dojo.isObject(cont) && cont.domNode) ? cont.domNode : cont, setterParams );
+
+ // setter params must be pulled afresh from the ContentPane each time
+ delete this._contentSetterParams;
+
+ if(this.doLayout){
+ this._checkIfSingleChild();
+ }
+
+ if(!isFakeContent){
+ if(this._started){
+ // Startup each top level child widget (and they will start their children, recursively)
+ this._startChildren();
+
+ // Call resize() on each of my child layout widgets,
+ // or resize() on my single child layout widget...
+ // either now (if I'm currently visible) or when I become visible
+ this._scheduleLayout();
+ }
+
+ this._onLoadHandler(cont);
+ }
+ },
+
+ _onError: function(type, err, consoleText){
+ this.onLoadDeferred.errback(err);
+
+ // shows user the string that is returned by on[type]Error
+ // override on[type]Error and return your own string to customize
+ var errText = this['on' + type + 'Error'].call(this, err);
+ if(consoleText){
+ console.error(consoleText, err);
+ }else if(errText){// a empty string won't change current content
+ this._setContent(errText, true);
+ }
+ },
+
+ // EVENT's, should be overide-able
+ onLoad: function(data){
+ // summary:
+ // Event hook, is called after everything is loaded and widgetified
+ // tags:
+ // callback
+ },
+
+ onUnload: function(){
+ // summary:
+ // Event hook, is called before old content is cleared
+ // tags:
+ // callback
+ },
+
+ onDownloadStart: function(){
+ // summary:
+ // Called before download starts.
+ // description:
+ // The string returned by this function will be the html
+ // that tells the user we are loading something.
+ // Override with your own function if you want to change text.
+ // tags:
+ // extension
+ return this.loadingMessage;
+ },
+
+ onContentError: function(/*Error*/ error){
+ // summary:
+ // Called on DOM faults, require faults etc. in content.
+ //
+ // In order to display an error message in the pane, return
+ // the error message from this method, as an HTML string.
+ //
+ // By default (if this method is not overriden), it returns
+ // nothing, so the error message is just printed to the console.
+ // tags:
+ // extension
+ },
+
+ onDownloadError: function(/*Error*/ error){
+ // summary:
+ // Called when download error occurs.
+ //
+ // In order to display an error message in the pane, return
+ // the error message from this method, as an HTML string.
+ //
+ // Default behavior (if this method is not overriden) is to display
+ // the error message inside the pane.
+ // tags:
+ // extension
+ return this.errorMessage;
+ },
+
+ onDownloadEnd: function(){
+ // summary:
+ // Called when download is finished.
+ // tags:
+ // callback
+ }
});
-}
-delete this._needLayout;
-},onLoad:function(_24){
-},onUnload:function(){
-},onDownloadStart:function(){
-return this.loadingMessage;
-},onContentError:function(_25){
-},onDownloadError:function(_26){
-return this.errorMessage;
-},onDownloadEnd:function(){
-}});
+
}