0byt3m1n1
Path:
/
data
/
applications
/
aps
/
phprojekt
/
6.0.6-0
/
standard
/
htdocs
/
htdocs
/
dojo
/
dijit
/
layout
/
[
Home
]
File: ContentPane.js
/* Copyright (c) 2004-2010, 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"]){ //_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"); // for dijit.layout.marginBox2contentBox() dojo.require("dojo.parser"); 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, { // summary: // A widget that acts as a container for mixed HTML and widgets, and includes an Ajax interface // description: // A widget that can be used as a stand alone widget // or as a base class 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 .set('content', '<b>new content</b>') // // Or you can send it a NodeList, .set('content', dojo.query('div [class=selected]', userSelection)) // please note that the nodes in NodeList will copied, not moved // // To do a ajax update use .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 attr("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, // 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 attr('content', ...) / attr('href', ...) // // False if it doesn't have any content, or if ContentPane is // still in the process of downloading href. isLoaded: false, baseClass: "dijitContentPane", // doLayout: Boolean // - false - don't adjust size of children // - true - if there is a single visible child widget, set it's size to // however big the ContentPane is doLayout: true, // ioArgs: Object // Parameters to pass to xhrGet() request, for example: // | <div dojoType="dijit.layout.ContentPane" href="./bar" ioArgs="{timeout: 500}"> ioArgs: {}, // isContainer: [protected] Boolean // Indicates that this widget acts as a "parent" to the descendant widgets. // When the parent is started it will call startup() on the child widgets. // See also `isLayoutContainer`. isContainer: true, // isLayoutContainer: [protected] Boolean // Indicates that this widget will call resize() on it's child widgets // when they become visible. isLayoutContainer: true, // onLoadDeferred: [readonly] dojo.Deferred // This is the `dojo.Deferred` returned by attr('href', ...) and refresh(). // Calling onLoadDeferred.addCallback() or addErrback() registers your // callback to be called only once, when the prior attr('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 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: [] }), 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); // Detect if we were initialized with data if(!this.href && this.srcNodeRef && this.srcNodeRef.innerHTML){ this.isLoaded = true; } }, buildRendering: function(){ // Overrides Widget.buildRendering(). // Since we have no template we need to set this.containerNode ourselves. // For subclasses of ContentPane do have a template, does nothing. this.inherited(arguments); if(!this.containerNode){ // make getDescendants() work this.containerNode = this.domNode; } }, postCreate: function(){ // remove the title attribute so it doesn't show up when hovering // over a node this.domNode.title = ""; if(!dojo.attr(this.domNode,"role")){ dijit.setWaiRole(this.domNode, "group"); } dojo.addClass(this.domNode, this.baseClass); }, startup: function(){ // summary: // See `dijit.layout._LayoutWidget.startup` for description. // Although ContentPane doesn't extend _LayoutWidget, it does implement // the same API. if(this._started){ return; } var parent = dijit._Contained.prototype.getParent.call(this); this._childOfLayoutWidget = parent && parent.isLayoutContainer; // I need to call resize() on my child/children (when I become visible), unless // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then. this._needLayout = !this._childOfLayoutWidget; if(this.isLoaded){ dojo.forEach(this.getChildren(), function(child){ child.startup(); }); } if(this._isShown() || this.preload){ this._onShow(); } this.inherited(arguments); }, _checkIfSingleChild: function(){ // summary: // Test if we have exactly one visible 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. // Skips over things like data stores since they aren't visible. var childNodes = dojo.query("> *", this.containerNode).filter(function(node){ return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc.. }), childWidgetNodes = childNodes.filter(function(node){ return dojo.hasAttr(node, "dojoType") || dojo.hasAttr(node, "widgetId"); }), candidateWidgets = dojo.filter(childWidgetNodes.map(dijit.byNode), function(widget){ return widget && widget.domNode && widget.resize; }); if( // all child nodes are widgets childNodes.length == childWidgetNodes.length && // all but one are invisible (like dojo.data) candidateWidgets.length == 1 ){ this._singleChild = candidateWidgets[0]; }else{ delete this._singleChild; } // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449) dojo.toggleClass(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild); }, 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 attr("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 (an attr('href') will cancel any in-flight attr('href', ...)) this.cancel(); this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel")); this.href = href; // _setHrefAttr() is called during creation and by the user, after creation. // only in the second case do we actually load the URL; otherwise it's done in startup() if(this._created && (this.preload || 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 attr("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.href = ""; // Cancel any in-flight requests (an attr('content') will cancel any in-flight attr('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")); this._setContent(data || ""); this._isDownloaded = false; // mark that content is from a attr('content') not an attr('href') return this.onLoadDeferred; // dojo.Deferred }, _getContentAttr: function(){ // summary: // Hook to make attr("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); }, resize: function(changeSize, resultSize){ // summary: // See `dijit.layout._LayoutWidget.resize` for description. // Although ContentPane doesn't extend _LayoutWidget, it does implement // the same API. // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is // never called, so resize() is our trigger to do the initial href download. if(!this._wasShown){ this._onShow(); } this._resizeCalled = true; // Set margin box size, unless it wasn't specified, in which case use current size. if(changeSize){ dojo.marginBox(this.domNode, changeSize); } // Compute content box size of containerNode in case we [later] need to size our single child. var cn = this.containerNode; if(cn === this.domNode){ // If changeSize or resultSize was passed to this method and this.containerNode == // this.domNode then we can compute the content-box size without querying the node, // which is more reliable (similar to LayoutWidget.resize) (see for example #9449). var mb = resultSize || {}; dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize if(!("h" in mb) || !("w" in mb)){ mb = dojo.mixin(dojo.marginBox(cn), mb); // just use dojo.marginBox() to fill in missing values } this._contentBox = dijit.layout.marginBox2contentBox(cn, mb); }else{ this._contentBox = dojo.contentBox(cn); } // Make my children layout, or size my single child widget this._layoutChildren(); }, _isShown: function(){ // summary: // Returns true if the content is currently shown. // description: // If I am a child of a layout widget then it actually returns true if I've ever been visible, // not whether I'm currently visible, since that's much faster than tracing up the DOM/widget // tree every call, and at least solves the performance problem on page load by deferring loading // hidden ContentPanes until they are first shown if(this._childOfLayoutWidget){ // If we are TitlePane, etc - we return that only *IF* we've been resized if(this._resizeCalled && "open" in this){ return this.open; } return this._resizeCalled; }else if("open" in this){ return this.open; // for TitlePane, etc. }else{ // TODO: with _childOfLayoutWidget check maybe this branch no longer necessary? var node = this.domNode; return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !dojo.hasClass(node, "dijitHidden"); } }, _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) if(this.href){ if(!this._xhrDfd && // if there's an href that isn't already being loaded (!this.isLoaded || this._hrefChanged || this.refreshOnShow) ){ this.refresh(); } }else{ // If we are the child of a layout widget then the layout widget will call resize() on // us, and then we will size our child/children. Otherwise, we need to do it now. if(!this._childOfLayoutWidget && this._needLayout){ // If a layout has been scheduled for when we become visible, do it now this._layoutChildren(); } } this.inherited(arguments); // Need to keep track of whether ContentPane has been shown (which is different than // whether or not it's currently visible). this._wasShown = true; }, 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._load(); return this.onLoadDeferred; }, _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.isLoaded = true; try{ this.onLoadDeferred.callback(data); this.onLoad(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.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(cont, 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, dir: this.dir, lang: this.lang }, this._contentSetterParams || {}); dojo.mixin(setter, setterParams); setter.set( (dojo.isObject(cont) && cont.domNode) ? cont.domNode : cont ); // setter params must be pulled afresh from the ContentPane each time delete this._contentSetterParams; if(!isFakeContent){ // Startup each top level child widget (and they will start their children, recursively) dojo.forEach(this.getChildren(), function(child){ // The parser has already called startup on all widgets *without* a getParent() method if(!this.parseOnLoad || child.getParent){ child.startup(); } }, this); // 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 // 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(errText, true); } }, _scheduleLayout: function(){ // summary: // Call resize() on each of my child layout widgets, either now // (if I'm currently visible) or when I become visible if(this._isShown()){ this._layoutChildren(); }else{ this._needLayout = true; } }, _layoutChildren: function(){ // summary: // Since I am a Container widget, each of my children expects me to // call resize() or layout() on them. // description: // Should be called on initialization and also whenever we get new content // (from an href, or from attr('content', ...))... but deferred until // the ContentPane is visible if(this.doLayout){ this._checkIfSingleChild(); } if(this._singleChild && this._singleChild.resize){ var cb = this._contentBox || dojo.contentBox(this.containerNode); // note: if widget has padding this._contentBox will have l and t set, // but don't pass them to resize() or it will doubly-offset the child this._singleChild.resize({w: cb.w, h: cb.h}); }else{ // All my child widgets are independently sized (rather than matching my size), // but I still need to call resize() on each child to make it layout. dojo.forEach(this.getChildren(), function(widget){ if(widget.resize){ widget.resize(); } }); } delete this._needLayout; }, // 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 } }); }