may affect its height.
if(pos == "top" || pos == "bottom"){
sizeSetting.w = dim.w;
size(child, sizeSetting);
dim.h -= child.h;
if(pos == "top"){
dim.t += child.h;
}else{
elmStyle.top = dim.t + dim.h + "px";
}
}else if(pos == "left" || pos == "right"){
sizeSetting.h = dim.h;
size(child, sizeSetting);
dim.w -= child.w;
if(pos == "left"){
dim.l += child.w;
}else{
elmStyle.left = dim.l + dim.w + "px";
}
}else if(pos == "client" || pos == "center"){
size(child, dim);
}
});
}
};
lang.setObject("dijit.layout.utils", utils); // remove for 2.0
return utils;
});
},
'dijit/layout/ContentPane':function(){
define([
"dojo/_base/kernel", // kernel.deprecated
"dojo/_base/lang", // lang.mixin lang.delegate lang.hitch lang.isFunction lang.isObject
"../_Widget",
"../_Container",
"./_ContentPaneResizeMixin",
"dojo/string", // string.substitute
"dojo/html", // html._ContentSetter
"dojo/_base/array", // array.forEach
"dojo/_base/declare", // declare
"dojo/_base/Deferred", // Deferred
"dojo/dom", // dom.byId
"dojo/dom-attr", // domAttr.attr
"dojo/dom-construct", // empty()
"dojo/_base/xhr", // xhr.get
"dojo/i18n", // i18n.getLocalization
"dojo/when",
"dojo/i18n!../nls/loading"
], function(kernel, lang, _Widget, _Container, _ContentPaneResizeMixin, string, html, array, declare,
Deferred, dom, domAttr, domConstruct, xhr, i18n, when){
// module:
// dijit/layout/ContentPane
return declare("dijit.layout.ContentPane", [_Widget, _Container, _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', '
')`
// 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 ` .... `.
// I.e., strip `` and `` (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: kernel._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: "
",
// errorMessage: String
// Message that shows if an error occurs
errorMessage: "
",
// 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",
/*======
// ioMethod: dojo/_base/xhr.get|dojo._base/xhr.post
// Function that should grab the content specified via href.
ioMethod: dojo.xhrGet,
======*/
// ioArgs: Object
// Parameters to pass to xhrGet() request, for example:
// |
ioArgs: {},
// onLoadDeferred: [readonly] dojo.Deferred
// This is the `dojo.Deferred` returned by set('href', ...) and refresh().
// Calling onLoadDeferred.then() 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,
// Cancel _WidgetBase's _setTitleAttr 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.
_setTitleAttr: null,
// 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,
markupFactory: function(params, node, ctor){
var self = new ctor(params, node);
// If a parse has started but is waiting for modules to load, then return a Promise for when the parser
// finishes. Don't return a promise though for the case when content hasn't started loading because the
// ContentPane is hidden and it has an href (ex: hidden pane of a TabContainer). In that case we consider
// that initialization has already finished.
return !self.href && self._contentSetter && self._contentSetter.parseDeferred && !self._contentSetter.parseDeferred.isFulfilled() ?
self._contentSetter.parseDeferred.then(function(){
return self;
}) : self;
},
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)){
srcNodeRef = dom.byId(srcNodeRef);
var df = srcNodeRef.ownerDocument.createDocumentFragment();
while(srcNodeRef.firstChild){
df.appendChild(srcNodeRef.firstChild);
}
params = lang.delegate(params, {content: df});
}
this.inherited(arguments, [params, srcNodeRef]);
},
postMixInProperties: function(){
this.inherited(arguments);
var messages = i18n.getLocalization("dijit", "loading", this.lang);
this.loadingMessage = string.substitute(this.loadingMessage, messages);
this.errorMessage = 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.removeAttribute("title");
},
startup: 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){
array.forEach(this._contentSetter.parseResults, function(obj){
if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){
obj.startup();
obj._started = true;
}
}, this);
}
},
_startChildren: function(){
// summary:
// Called when content is loaded. Calls startup on each child widget. Similar to ContentPane.startup()
// itself, but avoids marking the ContentPane itself as "restarted" (see #15581).
// This starts all the widgets
array.forEach(this.getChildren(), function(obj){
if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){
obj.startup();
obj._started = true;
}
});
// And this catches stuff like dojo/dnd/Source
if(this._contentSetter){
array.forEach(this._contentSetter.parseResults, function(obj){
if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){
obj.startup();
obj._started = true;
}
}, this);
}
},
setHref: function(/*String|Uri*/ href){
// summary:
// Deprecated. Use set('href', ...) instead.
kernel.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 Deferred(lang.hitch(this, "cancel"));
this.onLoadDeferred.then(lang.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; // Deferred
},
setContent: function(/*String|DomNode|Nodelist*/data){
// summary:
// Deprecated. Use set('content', ...) instead.
kernel.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 Deferred(lang.hitch(this, "cancel"));
if(this._created){
// For back-compat reasons, call onLoad() for set('content', ...)
// calls but not for content specified in srcNodeRef (ie:
...
)
// or as initialization parameter (ie: new ContentPane({content: ...})
this.onLoadDeferred.then(lang.hitch(this, "onLoad"));
}
this._setContent(data || "");
this._isDownloaded = false; // mark that content is from a set('content') not a set('href')
return this.onLoadDeferred; // 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;
},
destroy: function(){
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 Deferred(lang.hitch(this, "cancel"));
this.onLoadDeferred.then(lang.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(lang.isObject(this.ioArgs)){
lang.mixin(getArgs, this.ioArgs);
}
var hand = (this._xhrDfd = (this.ioMethod || xhr.get)(getArgs)),
returnedHtml;
hand.then(
function(html){
returnedHtml = html;
try{
self._isDownloaded = true;
return self._setContent(html, false);
}catch(err){
self._onError('Content', err); // onContentError
}
},
function(err){
if(!hand.canceled){
// show error message in the pane
self._onError('Download', err); // onDownloadError
}
delete self._xhrDfd;
return err;
}
).then(function(){
self.onDownloadEnd();
delete self._xhrDfd;
return returnedHtml;
});
// 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.resolve(data);
}catch(e){
console.error('Error ' + (this.widgetId || this.id) + ' 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(/*Boolean*/ preserveDom){
// 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;
array.forEach(this.getChildren(), function(widget){
if(widget.destroyRecursive){
// All widgets will hit this branch
widget.destroyRecursive(preserveDom);
}else if(widget.destroy){
// Things like dojo/dnd/Source have destroy(), not destroyRecursive()
widget.destroy(preserveDom);
}
widget._destroyed = true;
});
if(setter){
// Most of the widgets in setter.parseResults have already been destroyed, but
// things like Menu that have been moved to haven't yet
array.forEach(setter.parseResults, function(widget){
if(!widget._destroyed){
if(widget.destroyRecursive){
// All widgets will hit this branch
widget.destroyRecursive(preserveDom);
}else if(widget.destroy){
// Things like dojo/dnd/Source have destroy(), not destroyRecursive()
widget.destroy(preserveDom);
}
widget._destroyed = true;
}
});
delete setter.parseResults;
}
// And then clear away all the DOM nodes
if(!preserveDom){
domConstruct.empty(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
// returns:
// Returns a Deferred promise that is resolved when the content is parsed.
cont = this.preprocessContent(cont);
// first get rid of child widgets
this.destroyDescendants();
// 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 html._ContentSetter)){
setter = this._contentSetter = new html._ContentSetter({
node: this.containerNode,
_onError: lang.hitch(this, this._onError),
onContentError: lang.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 = lang.mixin({
cleanContent: this.cleanContent,
extractContent: this.extractContent,
parseContent: !cont.domNode && this.parseOnLoad,
parserScope: this.parserScope,
startup: false,
dir: this.dir,
lang: this.lang,
textDir: this.textDir
}, this._contentSetterParams || {});
var p = setter.set((lang.isObject(cont) && cont.domNode) ? cont.domNode : cont, setterParams);
// dojox/layout/html/_base::_ContentSetter.set() returns a Promise that indicates when everything is completed.
// dojo/html::_ContentSetter.set() currently returns the DOMNode, but that will be changed for 2.0.
// So, if set() returns a promise then use it, otherwise fallback to waiting on setter.parseDeferred
var self = this;
return when(p && p.then ? p : setter.parseDeferred, function(){
// setter params must be pulled afresh from the ContentPane each time
delete self._contentSetterParams;
if(!isFakeContent){
if(self._started){
// Startup each top level child widget (and they will start their children, recursively)
self._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
self._scheduleLayout();
}
self._onLoadHandler(cont);
}
});
},
preprocessContent: function(/*String|DocumentFragment*/ content){
// summary:
// Hook, called after content has loaded, before being processed.
// description:
// A subclass should preprocess the content and return the preprocessed content.
// See https://bugs.dojotoolkit.org/ticket/9622
// returns:
// Returns preprocessed content, either a String or DocumentFragment
return content;
},
_onError: function(type, err, consoleText){
this.onLoadDeferred.reject(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
}
});
});
},
'dijit/layout/_ContentPaneResizeMixin':function(){
define([
"dojo/_base/array", // array.filter array.forEach
"dojo/_base/declare", // declare
"dojo/dom-class", // domClass.contains domClass.toggle
"dojo/dom-geometry", // domGeometry.contentBox domGeometry.marginBox
"dojo/dom-style",
"dojo/_base/lang", // lang.mixin
"dojo/query", // query
"../registry", // registry.byId
"../Viewport",
"./utils" // marginBox2contextBox
], function(array, declare, domClass, domGeometry, domStyle, lang, query,
registry, Viewport, layoutUtils){
// module:
// dijit/layout/_ContentPaneResizeMixin
return declare("dijit.layout._ContentPaneResizeMixin", null, {
// summary:
// Resize() functionality of ContentPane. If there's a single layout widget
// child then it will call resize() with the same dimensions as the ContentPane.
// Otherwise just calls resize on each child.
//
// Also implements basic startup() functionality, where starting the parent
// will start the children
// 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,
// isLayoutContainer: [protected] Boolean
// Indicates that this widget will call resize() on it's child widgets
// when they become visible.
isLayoutContainer: true,
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 = this.getParent();
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;
this.inherited(arguments);
if(this._isShown()){
this._onShow();
}
if(!this._childOfLayoutWidget){
// Since my parent isn't a layout container, and my style *may be* width=height=100%
// or something similar (either set directly or via a CSS class),
// monitor when viewport size changes so that I can re-layout.
// This is more for subclasses of ContentPane than ContentPane itself, although it
// could be useful for a ContentPane if it has a single child widget inheriting ContentPane's size.
this.own(Viewport.on("resize", lang.hitch(this, "resize")));
}
},
_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 propagate startup() and resize() calls to it.
// Skips over things like data stores since they aren't visible.
if(!this.doLayout){ return; }
var candidateWidgets = [],
otherVisibleNodes = false;
query("> *", this.containerNode).some(function(node){
var widget = registry.byNode(node);
if(widget && widget.resize){
candidateWidgets.push(widget);
}else if(!/script|link|style/i.test(node.nodeName) && node.offsetHeight){
otherVisibleNodes = true;
}
});
this._singleChild = candidateWidgets.length == 1 && !otherVisibleNodes ?
candidateWidgets[0] : null;
// So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
},
resize: function(changeSize, resultSize){
// summary:
// See `dijit/layout/_LayoutWidget.resize()` for description.
// Although ContentPane doesn't extend _LayoutWidget, it does implement
// the same API.
this._resizeCalled = true;
this._scheduleLayout(changeSize, resultSize);
},
_scheduleLayout: function(changeSize, resultSize){
// summary:
// Resize myself, and 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._layout(changeSize, resultSize);
}else{
this._needLayout = true;
this._changeSize = changeSize;
this._resultSize = resultSize;
}
},
_layout: function(changeSize, resultSize){
// summary:
// Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
// Also, since I am an isLayoutContainer widget, each of my children expects me to
// call resize() or layout() on it.
//
// Should be called on initialization and also whenever we get new content
// (from an href, or from set('content', ...))... but deferred until
// the ContentPane is visible
delete this._needLayout;
// For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
// never called directly, so resize() is our trigger to do the initial href download (see [20099]).
// However, don't load href for closed TitlePanes.
if(!this._wasShown && this.open !== false){
this._onShow();
}
// Set margin box size, unless it wasn't specified, in which case use current size.
if(changeSize){
domGeometry.setMarginBox(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 || {};
lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
if(!("h" in mb) || !("w" in mb)){
mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values
}
this._contentBox = layoutUtils.marginBox2contentBox(cn, mb);
}else{
this._contentBox = domGeometry.getContentBox(cn);
}
this._layoutChildren();
},
_layoutChildren: function(){
// Call _checkIfSingleChild() again in case app has manually mucked w/the content
// of the ContentPane (rather than changing it through the set("content", ...) API.
this._checkIfSingleChild();
if(this._singleChild && this._singleChild.resize){
var cb = this._contentBox || domGeometry.getContentBox(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.
var children = this.getChildren(),
widget,
i = 0;
while(widget = children[i++]){
if(widget.resize){
widget.resize();
}
}
}
},
_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{
var node = this.domNode, parent = this.domNode.parentNode;
return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") &&
parent && parent.style && (parent.style.display != 'none');
}
},
_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 layout/resize of child widget(s)
// Need to keep track of whether ContentPane has been shown (which is different than
// whether or not it's currently visible).
this._wasShown = true;
if(this._needLayout){
// If a layout has been scheduled for when we become visible, do it now
this._layout(this._changeSize, this._resultSize);
}
this.inherited(arguments);
}
});
});
},
'dojo/html':function(){
define(["./_base/kernel", "./_base/lang", "./_base/array", "./_base/declare", "./dom", "./dom-construct", "./parser"],
function(kernel, lang, darray, declare, dom, domConstruct, parser){
// module:
// dojo/html
// the parser might be needed..
// idCounter is incremented with each instantiation to allow assignment of a unique id for tracking, logging purposes
var idCounter = 0;
var html = {
// summary:
// TODOC
_secureForInnerHtml: function(/*String*/ cont){
// summary:
// removes !DOCTYPE and title elements from the html string.
//
// khtml is picky about dom faults, you can't attach a style or `
` node as child of body
// must go into head, so we need to cut out those tags
// cont:
// An html string for insertion into the dom
//
return cont.replace(/(?:\s*]+>|]*>[\s\S]*?<\/title>)/ig, ""); // String
},
// Deprecated, should use dojo/dom-constuct.empty() directly, remove in 2.0.
_emptyNode: domConstruct.empty,
_setNodeContent: function(/*DomNode*/ node, /*String|DomNode|NodeList*/ cont){
// summary:
// inserts the given content into the given node
// node:
// the parent element
// content:
// the content to be set on the parent element.
// This can be an html string, a node reference or a NodeList, dojo/NodeList, Array or other enumerable list of nodes
// always empty
domConstruct.empty(node);
if(cont){
if(typeof cont == "number"){
cont = cont.toString();
}
if(typeof cont == "string"){
cont = domConstruct.toDom(cont, node.ownerDocument);
}
if(!cont.nodeType && lang.isArrayLike(cont)){
// handle as enumerable, but it may shrink as we enumerate it
for(var startlen=cont.length, i=0; i, wrapper before injection
cleanContent: false,
// extractContent: Boolean
// Should the content be treated as a full html document,
// and the real content stripped of ` ` wrapper before injection
extractContent: false,
// parseContent: Boolean
// Should the node by passed to the parser after the new content is set
parseContent: false,
// 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: kernel._scopeName,
// startup: Boolean
// Start the child widgets after parsing them. Only obeyed if parseContent is true.
startup: true,
// lifecycle methods
constructor: function(/*Object*/ params, /*String|DomNode*/ node){
// summary:
// Provides a configurable, extensible object to wrap the setting on content on a node
// call the set() method to actually set the content..
// the original params are mixed directly into the instance "this"
lang.mixin(this, params || {});
// give precedence to params.node vs. the node argument
// and ensure its a node, not an id string
node = this.node = dom.byId( this.node || node );
if(!this.id){
this.id = [
"Setter",
(node) ? node.id || node.tagName : "",
idCounter++
].join("_");
}
},
set: function(/* String|DomNode|NodeList? */ cont, /*Object?*/ params){
// summary:
// front-end to the set-content sequence
// cont:
// An html string, node or enumerable list of nodes for insertion into the dom
// If not provided, the object's content property will be used
if(undefined !== cont){
this.content = cont;
}
if(typeof cont == 'number'){
cont = cont.toString();
}
// in the re-use scenario, set needs to be able to mixin new configuration
if(params){
this._mixin(params);
}
this.onBegin();
this.setContent();
var ret = this.onEnd();
if(ret && ret.then){
// Make dojox/html/_ContentSetter.set() return a Promise that resolves when load and parse complete.
return ret;
}else{
// Vanilla dojo/html._ContentSetter.set() returns a DOMNode for back compat. For 2.0, switch it to
// return a Deferred like above.
return this.node;
}
},
setContent: function(){
// summary:
// sets the content on the node
var node = this.node;
if(!node){
// can't proceed
throw new Error(this.declaredClass + ": setContent given no node");
}
try{
node = html._setNodeContent(node, this.content);
}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
// FIXME: need to allow the user to provide a content error message string
var errMess = this.onContentError(e);
try{
node.innerHTML = errMess;
}catch(e){
console.error('Fatal ' + this.declaredClass + '.setContent could not change content due to '+e.message, e);
}
}
// always put back the node for the next method
this.node = node; // DomNode
},
empty: function(){
// summary:
// cleanly empty out existing content
// If there is a parse in progress, cancel it.
if(this.parseDeferred){
if(!this.parseDeferred.isResolved()){
this.parseDeferred.cancel();
}
delete this.parseDeferred;
}
// destroy any widgets from a previous run
// NOTE: if you don't want this you'll need to empty
// the parseResults array property yourself to avoid bad things happening
if(this.parseResults && this.parseResults.length){
darray.forEach(this.parseResults, function(w){
if(w.destroy){
w.destroy();
}
});
delete this.parseResults;
}
// this is fast, but if you know its already empty or safe, you could
// override empty to skip this step
domConstruct.empty(this.node);
},
onBegin: function(){
// summary:
// Called after instantiation, but before set();
// It allows modification of any of the object properties -
// including the node and content provided - before the set operation actually takes place
// This default implementation checks for cleanContent and extractContent flags to
// optionally pre-process html string content
var cont = this.content;
if(lang.isString(cont)){
if(this.cleanContent){
cont = html._secureForInnerHtml(cont);
}
if(this.extractContent){
var match = cont.match(/]*>\s*([\s\S]+)\s*<\/body>/im);
if(match){ cont = match[1]; }
}
}
// clean out the node and any cruft associated with it - like widgets
this.empty();
this.content = cont;
return this.node; // DomNode
},
onEnd: function(){
// summary:
// Called after set(), when the new content has been pushed into the node
// It provides an opportunity for post-processing before handing back the node to the caller
// This default implementation checks a parseContent flag to optionally run the dojo parser over the new content
if(this.parseContent){
// populates this.parseResults and this.parseDeferred if you need those..
this._parse();
}
return this.node; // DomNode
// TODO: for 2.0 return a Promise indicating that the parse completed.
},
tearDown: function(){
// summary:
// manually reset the Setter instance if its being re-used for example for another set()
// description:
// tearDown() is not called automatically.
// In normal use, the Setter instance properties are simply allowed to fall out of scope
// but the tearDown method can be called to explicitly reset this instance.
delete this.parseResults;
delete this.parseDeferred;
delete this.node;
delete this.content;
},
onContentError: function(err){
return "Error occurred setting content: " + err;
},
onExecError: function(err){
return "Error occurred executing scripts: " + err;
},
_mixin: function(params){
// mix properties/methods into the instance
// TODO: the intention with tearDown is to put the Setter's state
// back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
// so we could do something here to move the original properties aside for later restoration
var empty = {}, key;
for(key in params){
if(key in empty){ continue; }
// TODO: here's our opportunity to mask the properties we don't consider configurable/overridable
// .. but history shows we'll almost always guess wrong
this[key] = params[key];
}
},
_parse: function(){
// summary:
// runs the dojo parser over the node contents, storing any results in this.parseResults
// and the parse promise in this.parseDeferred
// Any errors resulting from parsing are passed to _onError for handling
var rootNode = this.node;
try{
// store the results (widgets, whatever) for potential retrieval
var inherited = {};
darray.forEach(["dir", "lang", "textDir"], function(name){
if(this[name]){
inherited[name] = this[name];
}
}, this);
var self = this;
this.parseDeferred = parser.parse({
rootNode: rootNode,
noStart: !this.startup,
inherited: inherited,
scope: this.parserScope
}).then(function(results){
return self.parseResults = results;
}, function(e){
self._onError('Content', e, "Error parsing in _ContentSetter#" + self.id);
});
}catch(e){
this._onError('Content', e, "Error parsing in _ContentSetter#" + this.id);
}
},
_onError: function(type, err, consoleText){
// summary:
// shows user the string that is returned by on[type]Error
// override/implement 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
html._setNodeContent(this.node, errText, true);
}
}
}), // end declare()
set: function(/*DomNode*/ node, /*String|DomNode|NodeList*/ cont, /*Object?*/ params){
// summary:
// inserts (replaces) the given content into the given node. dojo/dom-construct.place(cont, node, "only")
// may be a better choice for simple HTML insertion.
// description:
// Unless you need to use the params capabilities of this method, you should use
// dojo/dom-construct.place(cont, node, "only"). dojo/dom-construct..place() has more robust support for injecting
// an HTML string into the DOM, but it only handles inserting an HTML string as DOM
// elements, or inserting a DOM node. dojo/dom-construct..place does not handle NodeList insertions
// dojo/dom-construct.place(cont, node, "only"). dojo/dom-construct.place() has more robust support for injecting
// an HTML string into the DOM, but it only handles inserting an HTML string as DOM
// elements, or inserting a DOM node. dojo/dom-construct.place does not handle NodeList insertions
// or the other capabilities as defined by the params object for this method.
// node:
// the parent element that will receive the content
// cont:
// the content to be set on the parent element.
// This can be an html string, a node reference or a NodeList, dojo/NodeList, Array or other enumerable list of nodes
// params:
// Optional flags/properties to configure the content-setting. See dojo/html/_ContentSetter
// example:
// A safe string/node/nodelist content replacement/injection with hooks for extension
// Example Usage:
// | html.set(node, "some string");
// | html.set(node, contentNode, {options});
// | html.set(node, myNode.childNodes, {options});
if(undefined == cont){
console.warn("dojo.html.set: no cont argument provided, using empty string");
cont = "";
}
if (typeof cont == 'number'){
cont = cont.toString();
}
if(!params){
// simple and fast
return html._setNodeContent(node, cont, true);
}else{
// more options but slower
// note the arguments are reversed in order, to match the convention for instantiation via the parser
var op = new html._ContentSetter(lang.mixin(
params,
{ content: cont, node: node }
));
return op.set();
}
}
};
lang.setObject("dojo.html", html);
return html;
});
},
'dojo/parser':function(){
define([
"require", "./_base/kernel", "./_base/lang", "./_base/array", "./_base/config", "./dom", "./_base/window",
"./_base/url", "./aspect", "./promise/all", "./date/stamp", "./Deferred", "./has", "./json5", "./query", "./on",
"./ready"
], function(require, dojo, dlang, darray, config, dom, dwindow, _Url, aspect, all, dates, Deferred, has, json5, query,
don, ready){
// module:
// dojo/parser
new Date("X"); // workaround for #11279, new Date("") == NaN
var myEval;
if(has('csp-restrictions')) {
// JSON5 data attributes can be parsed without using eval; JS expressions will throw an error
myEval = json5.parse;
}
else {
myEval = function(text){
// data-dojo-props etc. is not restricted to JSON, it can be any javascript
/* jshint -W061 */
return eval("(" + text + ")");
};
}
// Widgets like BorderContainer add properties to _Widget via dojo.extend().
// If BorderContainer is loaded after _Widget's parameter list has been cached,
// we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
var extendCnt = 0;
aspect.after(dlang, "extend", function(){
extendCnt++;
}, true);
function getNameMap(ctor){
// summary:
// Returns map from lowercase name to attribute name in class, ex: {onclick: "onClick"}
var map = ctor._nameCaseMap, proto = ctor.prototype;
// Create the map if it's undefined.
// Refresh the map if a superclass was possibly extended with new methods since the map was created.
if(!map || map._extendCnt < extendCnt){
map = ctor._nameCaseMap = {};
for(var name in proto){
if(name.charAt(0) === "_"){
continue;
} // skip internal properties
map[name.toLowerCase()] = name;
}
map._extendCnt = extendCnt;
}
return map;
}
function getCtor(/*String[]*/ types, /*Function?*/ contextRequire){
// summary:
// Retrieves a constructor. If the types array contains more than one class/MID then the
// subsequent classes will be mixed into the first class and a unique constructor will be
// returned for that array.
if(!contextRequire){
contextRequire = require;
}
// Map from widget name or list of widget names(ex: "dijit/form/Button,acme/MyMixin") to a constructor.
// Keep separate map for each requireContext to avoid false matches (ex: "./Foo" can mean different things
// depending on context.)
var ctorMap = contextRequire._dojoParserCtorMap || (contextRequire._dojoParserCtorMap = {});
var ts = types.join();
if(!ctorMap[ts]){
var mixins = [];
for(var i = 0, l = types.length; i < l; i++){
var t = types[i];
// TODO: Consider swapping getObject and require in the future
mixins[mixins.length] = (ctorMap[t] = ctorMap[t] || (dlang.getObject(t) || (~t.indexOf('/') &&
contextRequire(t))));
}
var ctor = mixins.shift();
ctorMap[ts] = mixins.length ? (ctor.createSubclass ? ctor.createSubclass(mixins) : ctor.extend.apply(ctor, mixins)) : ctor;
}
return ctorMap[ts];
}
var parser = {
// summary:
// The Dom/Widget parsing package
_clearCache: function(){
// summary:
// Clear cached data. Used mainly for benchmarking.
extendCnt++;
_ctorMap = {};
},
_functionFromScript: function(script, attrData){
// summary:
// Convert a ``
// into a function
// script: DOMNode
// The `` node,
// calls require() to load the specified modules and (asynchronously) assign them to the specified global
// variables, and returns a Promise for when that operation completes.
//
// In the example above, it is effectively doing a require(["acme/bar", ...], function(a){ bar = a; }).
var hash = myEval("{" + script.innerHTML + "}"), // can't use dojo/json::parse() because maybe no quotes
vars = [],
mids = [],
d = new Deferred();
var contextRequire = (options && options.contextRequire) || require;
for(var name in hash){
vars.push(name);
mids.push(hash[name]);
}
contextRequire(mids, function(){
for(var i = 0; i < vars.length; i++){
dlang.setObject(vars[i], arguments[i]);
}
d.resolve(arguments);
});
return d.promise;
},
_scanAmd: function(root, options){
// summary:
// Scans the DOM for any declarative requires and returns their values.
// description:
// Looks for `` node, calls require() to load the
// specified modules and (asynchronously) assign them to the specified global variables,
// and returns a Promise for when those operations complete.
// root: DomNode
// The node to base the scan from.
// options: Object?
// a kwArgs options object, see parse() for details
// Promise that resolves when all the