]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dijit/layout/ContentPane.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dijit / layout / ContentPane.js
diff --git a/static/dojo-release-1.1.1/dijit/layout/ContentPane.js b/static/dojo-release-1.1.1/dijit/layout/ContentPane.js
new file mode 100644 (file)
index 0000000..c3a4ca4
--- /dev/null
@@ -0,0 +1,445 @@
+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.layout._LayoutWidget");
+
+dojo.require("dojo.parser");
+dojo.require("dojo.string");
+dojo.requireLocalization("dijit", "loading", null, "zh,pt,da,tr,ru,ROOT,de,sv,ja,he,fi,nb,el,ar,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu");
+
+dojo.declare(
+       "dijit.layout.ContentPane",
+       dijit._Widget,
+{
+       // summary:
+       //              A widget that acts as a Container for other widgets, and includes a ajax interface
+       // description:
+       //              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
+       //              generated markup or DOM content, instantiating widgets within that content.
+       //              Don't confuse it with an iframe, it only needs/wants 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.
+       // example:
+       //              Some quick samples:
+       //              To change the innerHTML use .setContent('<b>new content</b>')
+       //
+       //              Or you can send it a NodeList, .setContent(dojo.query('div [class=selected]', userSelection))
+       //              please note that the nodes in NodeList will copied, not moved
+       //
+       //              To do a ajax update use .setHref('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; see setHref();
+       href: "",
+
+       // extractContent: Boolean
+       //      Extract visible content from inside of <body> .... </body>
+       extractContent: false,
+
+       // parseOnLoad: Boolean
+       //      parse content and create the widgets, if any
+       parseOnLoad:    true,
+
+       // preventCache: Boolean
+       //              Cache content retreived externally
+       preventCache:   false,
+
+       // preload: Boolean
+       //      Force load of data 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: Boolean
+       //      Tells loading status see onLoad|onUnload for event hooks
+       isLoaded: false,
+
+       // class: String
+       //      Class name to apply to ContentPane dom nodes
+       // TODO: this should be called "baseClass" like in the other widgets
+       "class": "dijitContentPane",
+
+       // doLayout: String/Boolean
+       //      false - don't adjust size of children
+       //      true - looks for the first sizable child widget (ie, having resize() method) and sets it's size to
+       //                      however big the ContentPane is (TODO: implement)
+       //      auto - if there is a single sizable child widget (ie, having resize() method), set it's size to
+       //                      however big the ContentPane is
+       doLayout: "auto",
+
+       postCreate: function(){
+               // remove the title attribute so it doesn't show up when i hover
+               // over a node
+               this.domNode.title = "";
+
+               if(!this.containerNode){
+                       // make getDescendants() work
+                       this.containerNode = this.domNode;
+               }
+
+               if(this.preload){
+                       this._loadCheck();
+               }
+
+               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);
+               var curRole = dijit.getWaiRole(this.domNode);
+               if (!curRole){
+                       dijit.setWaiRole(this.domNode, "group");
+               }
+
+               // for programatically created ContentPane (with <span> tag), need to muck w/CSS
+               // or it's as though overflow:visible is set
+               dojo.addClass(this.domNode, this["class"]);
+       },
+
+       startup: function(){
+               if(this._started){ return; }
+               if(this.doLayout != "false" && this.doLayout !== false){
+                       this._checkIfSingleChild();
+                       if(this._singleChild){
+                               this._singleChild.startup();
+                       }
+               }
+               this._loadCheck();
+               this.inherited(arguments);
+       },
+
+       _checkIfSingleChild: function(){
+               // summary:
+               //      Test if we have exactly one widget as a child, and if so assume that we are a container for that widget,
+               //      and should propogate startup() and resize() calls to it.
+
+               // TODO: if there are two child widgets (a data store and a TabContainer, for example),
+               //      should still find the TabContainer
+               var childNodes = dojo.query(">", this.containerNode || this.domNode),
+                       childWidgets = childNodes.filter("[widgetId]");
+
+               if(childNodes.length == 1 && childWidgets.length == 1){
+                       this.isContainer = true;
+                       this._singleChild = dijit.byNode(childWidgets[0]);
+               }else{
+                       delete this.isContainer;
+                       delete this._singleChild;
+               }
+       },
+
+       refresh: function(){
+               // summary:
+               //      Force a refresh (re-download) of content, be sure to turn off cache
+
+               // we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
+               return this._prepareLoad(true);
+       },
+
+       setHref: function(/*String|Uri*/ href){
+               // 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
+               //      href:
+               //              url to the page you want to get, must be within the same domain as your mainpage
+               this.href = href;
+
+               // we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
+               return this._prepareLoad();
+       },
+
+       setContent: function(/*String|DomNode|Nodelist*/data){
+               // summary:
+               //              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 cant run refresh and clear content
+               // refresh should only work if we downloaded the content
+               if(!this._isDownloaded){
+                       this.href = "";
+                       this._onUnloadHandler();
+               }
+
+               this._setContent(data || "");
+
+               this._isDownloaded = false; // must be set after _setContent(..), pathadjust in dojox.layout.ContentPane
+
+               if(this.parseOnLoad){
+                       this._createSubWidgets();
+               }
+
+               if(this.doLayout != "false" && this.doLayout !== false){
+                       this._checkIfSingleChild();
+                       if(this._singleChild && this._singleChild.resize){
+                               this._singleChild.startup();
+                               this._singleChild.resize(this._contentBox || dojo.contentBox(this.containerNode || this.domNode));
+                       }
+               }
+
+               this._onLoadHandler();
+       },
+
+       cancel: function(){
+               // summary:
+               //              Cancels a inflight download of content
+               if(this._xhrDfd && (this._xhrDfd.fired == -1)){
+                       this._xhrDfd.cancel();
+               }
+               delete this._xhrDfd; // garbage collect
+       },
+
+       destroy: function(){
+               // if we have multiple controllers destroying us, bail after the first
+               if(this._beingDestroyed){
+                       return;
+               }
+               // make sure we call onUnload
+               this._onUnloadHandler();
+               this._beingDestroyed = true;
+               this.inherited("destroy",arguments);
+       },
+
+       resize: function(size){
+               dojo.marginBox(this.domNode, size);
+
+               // Compute content box size in case we [later] need to size child
+               // If either height or width wasn't specified by the user, then query node for it.
+               // But note that setting the margin box and then immediately querying dimensions may return
+               // inaccurate results, so try not to depend on it.
+               var node = this.containerNode || this.domNode,
+                       mb = dojo.mixin(dojo.marginBox(node), size||{});
+
+               this._contentBox = dijit.layout.marginBox2contentBox(node, mb);
+
+               // If we have a single widget child then size it to fit snugly within my borders
+               if(this._singleChild && this._singleChild.resize){
+                       this._singleChild.resize(this._contentBox);
+               }
+       },
+
+       _prepareLoad: function(forceLoad){
+               // sets up for a xhrLoad, load is deferred until widget onShow
+               // cancels a inflight download
+               this.cancel();
+               this.isLoaded = false;
+               this._loadCheck(forceLoad);
+       },
+
+       _isShown: function(){
+               // summary: returns true if the content is currently shown
+               if("open" in this){
+                       return this.open;               // for TitlePane, etc.
+               }else{
+                       var node = this.domNode;
+                       return (node.style.display != 'none')  && (node.style.visibility != 'hidden');
+               }
+       },
+
+       _loadCheck: function(/*Boolean*/ forceLoad){
+               // call this when you change onShow (onSelected) status when selected in parent container
+               // it's used as a trigger for href download when this.domNode.display != 'none'
+
+               // sequence:
+               // if no href -> bail
+               // forceLoad -> always load
+               // this.preload -> load when download not in progress, domNode display doesn't matter
+               // this.refreshOnShow -> load when download in progress bails, domNode display !='none' AND
+               //                                              this.open !== false (undefined is ok), isLoaded doesn't matter
+               // else -> load when download not in progress, if this.open !== false (undefined is ok) AND
+               //                                              domNode display != 'none', isLoaded must be false
+
+               var displayState = this._isShown();
+
+               if(this.href && 
+                       (forceLoad ||
+                               (this.preload && !this._xhrDfd) ||
+                               (this.refreshOnShow && displayState && !this._xhrDfd) ||
+                               (!this.isLoaded && displayState && !this._xhrDfd)
+                       )
+               ){
+                       this._downloadExternalContent();
+               }
+       },
+
+       _downloadExternalContent: function(){
+               this._onUnloadHandler();
+
+               // display loading message
+               this._setContent(
+                       this.onDownloadStart.call(this)
+               );
+
+               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.onDownloadEnd.call(self);
+                               self._isDownloaded = true;
+                               self.setContent.call(self, html); // onload event is called from here
+                       }catch(err){
+                               self._onError.call(self, 'Content', err); // onContentError
+                       }
+                       delete self._xhrDfd;
+                       return html;
+               });
+
+               hand.addErrback(function(err){
+                       if(!hand.cancelled){
+                               // show error message in the pane
+                               self._onError.call(self, 'Download', err); // onDownloadError
+                       }
+                       delete self._xhrDfd;
+                       return err;
+               });
+       },
+
+       _onLoadHandler: function(){
+               this.isLoaded = true;
+               try{
+                       this.onLoad.call(this);
+               }catch(e){
+                       console.error('Error '+this.widgetId+' running custom onLoad code');
+               }
+       },
+
+       _onUnloadHandler: function(){
+               this.isLoaded = false;
+               this.cancel();
+               try{
+                       this.onUnload.call(this);
+               }catch(e){
+                       console.error('Error '+this.widgetId+' running custom onUnload code');
+               }
+       },
+
+       _setContent: function(cont){
+               this.destroyDescendants();
+
+               try{
+                       var node = this.containerNode || this.domNode;
+                       while(node.firstChild){
+                               dojo._destroyElement(node.firstChild);
+                       }
+                       if(typeof cont == "string"){
+                               // dijit.ContentPane does only minimal fixes,
+                               // No pathAdjustments, script retrieval, style clean etc
+                               // some of these should be available in the dojox.layout.ContentPane
+                               if(this.extractContent){
+                                       match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+                                       if(match){ cont = match[1]; }
+                               }
+                               node.innerHTML = cont;
+                       }else{
+                               // domNode or NodeList
+                               if(cont.nodeType){ // domNode (htmlNode 1 or textNode 3)
+                                       node.appendChild(cont);
+                               }else{// nodelist or array such as dojo.Nodelist
+                                       dojo.forEach(cont, function(n){
+                                               node.appendChild(n.cloneNode(true));
+                                       });
+                               }
+                       }
+               }catch(e){
+                       // check 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{
+                               node.innerHTML = errMess;
+                       }catch(e){
+                               console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
+                       }
+               }
+       },
+
+       _onError: function(type, err, consoleText){
+               // shows user the string that is returned by on[type]Error
+               // overide 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.call(this, errText);
+               }
+       },
+
+       _createSubWidgets: function(){
+               // summary: scan my contents and create subwidgets
+               var rootNode = this.containerNode || this.domNode;
+               try{
+                       dojo.parser.parse(rootNode, true);
+               }catch(e){
+                       this._onError('Content', e, "Couldn't create widgets in "+this.id
+                               +(this.href ? " from "+this.href : ""));
+               }
+       },
+
+       // EVENT's, should be overide-able
+       onLoad: function(e){
+               // summary:
+               //              Event hook, is called after everything is loaded and widgetified
+       },
+
+       onUnload: function(e){
+               // summary:
+               //              Event hook, is called before old content is cleared
+       },
+
+       onDownloadStart: function(){
+               // summary:
+               //              called before download starts
+               //              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
+               return this.loadingMessage;
+       },
+
+       onContentError: function(/*Error*/ error){
+               // summary:
+               //              called on DOM faults, require fault etc in content
+               //              default is to display errormessage inside pane
+       },
+
+       onDownloadError: function(/*Error*/ error){
+               // summary:
+               //              Called when download error occurs, default is to display
+               //              errormessage inside pane. Overide function to change that.
+               //              The string returned by this function will be the html
+               //              that tells the user a error happend
+               return this.errorMessage;
+       },
+
+       onDownloadEnd: function(){
+               // summary:
+               //              called when download is finished
+       }
+});
+
+}