summaryrefslogtreecommitdiff
path: root/lib/dijit/layout
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2011-11-08 20:40:44 +0400
committerAndrew Dolgov <[email protected]>2011-11-08 20:40:44 +0400
commit81bea17aefb26859f825b9293c7c99192874806e (patch)
treefb244408ca271affa2899adb634788802c9a89d8 /lib/dijit/layout
parent870a70e109ac9e80a88047044530de53d0404ec7 (diff)
upgrade Dojo to 1.6.1
Diffstat (limited to 'lib/dijit/layout')
-rw-r--r--lib/dijit/layout/AccordionContainer.js686
-rw-r--r--lib/dijit/layout/AccordionPane.js28
-rw-r--r--lib/dijit/layout/BorderContainer.js830
-rw-r--r--lib/dijit/layout/ContentPane.js860
-rw-r--r--lib/dijit/layout/LayoutContainer.js96
-rw-r--r--lib/dijit/layout/LinkPane.js51
-rw-r--r--lib/dijit/layout/ScrollingTabController.js662
-rw-r--r--lib/dijit/layout/SplitContainer.js913
-rw-r--r--lib/dijit/layout/StackContainer.js460
-rw-r--r--lib/dijit/layout/StackController.js484
-rw-r--r--lib/dijit/layout/TabContainer.js77
-rw-r--r--lib/dijit/layout/TabController.js216
-rw-r--r--lib/dijit/layout/_ContentPaneResizeMixin.js260
-rw-r--r--lib/dijit/layout/_LayoutWidget.js411
-rw-r--r--lib/dijit/layout/_TabContainerBase.js193
15 files changed, 4322 insertions, 1905 deletions
diff --git a/lib/dijit/layout/AccordionContainer.js b/lib/dijit/layout/AccordionContainer.js
index 5bad370f5..6177583ba 100644
--- a/lib/dijit/layout/AccordionContainer.js
+++ b/lib/dijit/layout/AccordionContainer.js
@@ -1,220 +1,498 @@
/*
- 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.AccordionContainer"]){
-dojo._hasResource["dijit.layout.AccordionContainer"]=true;
+if(!dojo._hasResource["dijit.layout.AccordionContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.AccordionContainer"] = true;
dojo.provide("dijit.layout.AccordionContainer");
-dojo.require("dojo.fx");
dojo.require("dijit._Container");
dojo.require("dijit._Templated");
dojo.require("dijit._CssStateMixin");
dojo.require("dijit.layout.StackContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit.layout.AccordionPane");
-dojo.declare("dijit.layout.AccordionContainer",dijit.layout.StackContainer,{duration:dijit.defaultDuration,buttonWidget:"dijit.layout._AccordionButton",_verticalSpace:0,baseClass:"dijitAccordionContainer",postCreate:function(){
-this.domNode.style.overflow="hidden";
-this.inherited(arguments);
-dijit.setWaiRole(this.domNode,"tablist");
-},startup:function(){
-if(this._started){
-return;
-}
-this.inherited(arguments);
-if(this.selectedChildWidget){
-var _1=this.selectedChildWidget.containerNode.style;
-_1.display="";
-_1.overflow="auto";
-this.selectedChildWidget._wrapperWidget.set("selected",true);
-}
-},_getTargetHeight:function(_2){
-var cs=dojo.getComputedStyle(_2);
-return Math.max(this._verticalSpace-dojo._getPadBorderExtents(_2,cs).h-dojo._getMarginExtents(_2,cs).h,0);
-},layout:function(){
-var _3=this.selectedChildWidget;
-if(!_3){
-return;
-}
-var _4=_3._wrapperWidget.domNode,_5=dojo._getMarginExtents(_4),_6=dojo._getPadBorderExtents(_4),_7=this._contentBox;
-var _8=0;
-dojo.forEach(this.getChildren(),function(_9){
-if(_9!=_3){
-_8+=dojo.marginBox(_9._wrapperWidget.domNode).h;
-}
-});
-this._verticalSpace=_7.h-_8-_5.h-_6.h-_3._buttonWidget.getTitleHeight();
-this._containerContentBox={h:this._verticalSpace,w:this._contentBox.w-_5.w-_6.w};
-if(_3){
-_3.resize(this._containerContentBox);
-}
-},_setupChild:function(_a){
-_a._wrapperWidget=new dijit.layout._AccordionInnerContainer({contentWidget:_a,buttonWidget:this.buttonWidget,id:_a.id+"_wrapper",dir:_a.dir,lang:_a.lang,parent:this});
-this.inherited(arguments);
-},addChild:function(_b,_c){
-if(this._started){
-dojo.place(_b.domNode,this.containerNode,_c);
-if(!_b._started){
-_b.startup();
-}
-this._setupChild(_b);
-dojo.publish(this.id+"-addChild",[_b,_c]);
-this.layout();
-if(!this.selectedChildWidget){
-this.selectChild(_b);
-}
-}else{
-this.inherited(arguments);
-}
-},removeChild:function(_d){
-_d._wrapperWidget.destroy();
-delete _d._wrapperWidget;
-dojo.removeClass(_d.domNode,"dijitHidden");
-this.inherited(arguments);
-},getChildren:function(){
-return dojo.map(this.inherited(arguments),function(_e){
-return _e.declaredClass=="dijit.layout._AccordionInnerContainer"?_e.contentWidget:_e;
-},this);
-},destroy:function(){
-dojo.forEach(this.getChildren(),function(_f){
-_f._wrapperWidget.destroy();
+
+
+//dojo.require("dijit.layout.AccordionPane "); // for back compat, remove for 2.0
+
+// Design notes:
+//
+// An AccordionContainer is a StackContainer, but each child (typically ContentPane)
+// is wrapped in a _AccordionInnerContainer. This is hidden from the caller.
+//
+// The resulting markup will look like:
+//
+// <div class=dijitAccordionContainer>
+// <div class=dijitAccordionInnerContainer> (one pane)
+// <div class=dijitAccordionTitle> (title bar) ... </div>
+// <div class=dijtAccordionChildWrapper> (content pane) </div>
+// </div>
+// </div>
+//
+// Normally the dijtAccordionChildWrapper is hidden for all but one child (the shown
+// child), so the space for the content pane is all the title bars + the one dijtAccordionChildWrapper,
+// which on claro has a 1px border plus a 2px bottom margin.
+//
+// During animation there are two dijtAccordionChildWrapper's shown, so we need
+// to compensate for that.
+
+dojo.declare(
+ "dijit.layout.AccordionContainer",
+ dijit.layout.StackContainer,
+ {
+ // summary:
+ // Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
+ // and switching between panes is visualized by sliding the other panes up/down.
+ // example:
+ // | <div dojoType="dijit.layout.AccordionContainer">
+ // | <div dojoType="dijit.layout.ContentPane" title="pane 1">
+ // | </div>
+ // | <div dojoType="dijit.layout.ContentPane" title="pane 2">
+ // | <p>This is some text</p>
+ // | </div>
+ // | </div>
+
+ // duration: Integer
+ // Amount of time (in ms) it takes to slide panes
+ duration: dijit.defaultDuration,
+
+ // buttonWidget: [const] String
+ // The name of the widget used to display the title of each pane
+ buttonWidget: "dijit.layout._AccordionButton",
+
+/*=====
+ // _verticalSpace: Number
+ // Pixels of space available for the open pane
+ // (my content box size minus the cumulative size of all the title bars)
+ _verticalSpace: 0,
+=====*/
+ baseClass: "dijitAccordionContainer",
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ this.domNode.style.overflow = "hidden"; // TODO: put this in dijit.css
+ dijit.setWaiRole(this.domNode, "tablist"); // TODO: put this in template
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ this.inherited(arguments);
+ if(this.selectedChildWidget){
+ var style = this.selectedChildWidget.containerNode.style;
+ style.display = "";
+ style.overflow = "auto";
+ this.selectedChildWidget._wrapperWidget.set("selected", true);
+ }
+ },
+
+ layout: function(){
+ // Implement _LayoutWidget.layout() virtual method.
+ // Set the height of the open pane based on what room remains.
+
+ var openPane = this.selectedChildWidget;
+
+ if(!openPane){ return;}
+
+ // space taken up by title, plus wrapper div (with border/margin) for open pane
+ var wrapperDomNode = openPane._wrapperWidget.domNode,
+ wrapperDomNodeMargin = dojo._getMarginExtents(wrapperDomNode),
+ wrapperDomNodePadBorder = dojo._getPadBorderExtents(wrapperDomNode),
+ wrapperContainerNode = openPane._wrapperWidget.containerNode,
+ wrapperContainerNodeMargin = dojo._getMarginExtents(wrapperContainerNode),
+ wrapperContainerNodePadBorder = dojo._getPadBorderExtents(wrapperContainerNode),
+ mySize = this._contentBox;
+
+ // get cumulative height of all the unselected title bars
+ var totalCollapsedHeight = 0;
+ dojo.forEach(this.getChildren(), function(child){
+ if(child != openPane){
+ totalCollapsedHeight += dojo._getMarginSize(child._wrapperWidget.domNode).h;
+ }
+ });
+ this._verticalSpace = mySize.h - totalCollapsedHeight - wrapperDomNodeMargin.h
+ - wrapperDomNodePadBorder.h - wrapperContainerNodeMargin.h - wrapperContainerNodePadBorder.h
+ - openPane._buttonWidget.getTitleHeight();
+
+ // Memo size to make displayed child
+ this._containerContentBox = {
+ h: this._verticalSpace,
+ w: this._contentBox.w - wrapperDomNodeMargin.w - wrapperDomNodePadBorder.w
+ - wrapperContainerNodeMargin.w - wrapperContainerNodePadBorder.w
+ };
+
+ if(openPane){
+ openPane.resize(this._containerContentBox);
+ }
+ },
+
+ _setupChild: function(child){
+ // Overrides _LayoutWidget._setupChild().
+ // Put wrapper widget around the child widget, showing title
+
+ child._wrapperWidget = new dijit.layout._AccordionInnerContainer({
+ contentWidget: child,
+ buttonWidget: this.buttonWidget,
+ id: child.id + "_wrapper",
+ dir: child.dir,
+ lang: child.lang,
+ parent: this
+ });
+
+ this.inherited(arguments);
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ if(this._started){
+ // Adding a child to a started Accordion is complicated because children have
+ // wrapper widgets. Default code path (calling this.inherited()) would add
+ // the new child inside another child's wrapper.
+
+ // First add in child as a direct child of this AccordionContainer
+ dojo.place(child.domNode, this.containerNode, insertIndex);
+
+ if(!child._started){
+ child.startup();
+ }
+
+ // Then stick the wrapper widget around the child widget
+ this._setupChild(child);
+
+ // Code below copied from StackContainer
+ dojo.publish(this.id+"-addChild", [child, insertIndex]);
+ this.layout();
+ if(!this.selectedChildWidget){
+ this.selectChild(child);
+ }
+ }else{
+ // We haven't been started yet so just add in the child widget directly,
+ // and the wrapper will be created on startup()
+ this.inherited(arguments);
+ }
+ },
+
+ removeChild: function(child){
+ // Overrides _LayoutWidget.removeChild().
+
+ // Destroy wrapper widget first, before StackContainer.getChildren() call.
+ // Replace wrapper widget with true child widget (ContentPane etc.).
+ // This step only happens if the AccordionContainer has been started; otherwise there's no wrapper.
+ if(child._wrapperWidget){
+ dojo.place(child.domNode, child._wrapperWidget.domNode, "after");
+ child._wrapperWidget.destroy();
+ delete child._wrapperWidget;
+ }
+
+ dojo.removeClass(child.domNode, "dijitHidden");
+
+ this.inherited(arguments);
+ },
+
+ getChildren: function(){
+ // Overrides _Container.getChildren() to return content panes rather than internal AccordionInnerContainer panes
+ return dojo.map(this.inherited(arguments), function(child){
+ return child.declaredClass == "dijit.layout._AccordionInnerContainer" ? child.contentWidget : child;
+ }, this);
+ },
+
+ destroy: function(){
+ if(this._animation){
+ this._animation.stop();
+ }
+ dojo.forEach(this.getChildren(), function(child){
+ // If AccordionContainer has been started, then each child has a wrapper widget which
+ // also needs to be destroyed.
+ if(child._wrapperWidget){
+ child._wrapperWidget.destroy();
+ }else{
+ child.destroyRecursive();
+ }
+ });
+ this.inherited(arguments);
+ },
+
+ _showChild: function(child){
+ // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
+ child._wrapperWidget.containerNode.style.display="block";
+ return this.inherited(arguments);
+ },
+
+ _hideChild: function(child){
+ // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
+ child._wrapperWidget.containerNode.style.display="none";
+ this.inherited(arguments);
+ },
+
+ _transition: function(/*dijit._Widget?*/ newWidget, /*dijit._Widget?*/ oldWidget, /*Boolean*/ animate){
+ // Overrides StackContainer._transition() to provide sliding of title bars etc.
+
+ if(dojo.isIE < 8){
+ // workaround animation bugs by not animating; not worth supporting animation for IE6 & 7
+ animate = false;
+ }
+
+ if(this._animation){
+ // there's an in-progress animation. speedily end it so we can do the newly requested one
+ this._animation.stop(true);
+ delete this._animation;
+ }
+
+ var self = this;
+
+ if(newWidget){
+ newWidget._wrapperWidget.set("selected", true);
+
+ var d = this._showChild(newWidget); // prepare widget to be slid in
+
+ // Size the new widget, in case this is the first time it's being shown,
+ // or I have been resized since the last time it was shown.
+ // Note that page must be visible for resizing to work.
+ if(this.doLayout && newWidget.resize){
+ newWidget.resize(this._containerContentBox);
+ }
+ }
+
+ if(oldWidget){
+ oldWidget._wrapperWidget.set("selected", false);
+ if(!animate){
+ this._hideChild(oldWidget);
+ }
+ }
+
+ if(animate){
+ var newContents = newWidget._wrapperWidget.containerNode,
+ oldContents = oldWidget._wrapperWidget.containerNode;
+
+ // During the animation we will be showing two dijitAccordionChildWrapper nodes at once,
+ // which on claro takes up 4px extra space (compared to stable AccordionContainer).
+ // Have to compensate for that by immediately shrinking the pane being closed.
+ var wrapperContainerNode = newWidget._wrapperWidget.containerNode,
+ wrapperContainerNodeMargin = dojo._getMarginExtents(wrapperContainerNode),
+ wrapperContainerNodePadBorder = dojo._getPadBorderExtents(wrapperContainerNode),
+ animationHeightOverhead = wrapperContainerNodeMargin.h + wrapperContainerNodePadBorder.h;
+
+ oldContents.style.height = (self._verticalSpace - animationHeightOverhead) + "px";
+
+ this._animation = new dojo.Animation({
+ node: newContents,
+ duration: this.duration,
+ curve: [1, this._verticalSpace - animationHeightOverhead - 1],
+ onAnimate: function(value){
+ value = Math.floor(value); // avoid fractional values
+ newContents.style.height = value + "px";
+ oldContents.style.height = (self._verticalSpace - animationHeightOverhead - value) + "px";
+ },
+ onEnd: function(){
+ delete self._animation;
+ newContents.style.height = "auto";
+ oldWidget._wrapperWidget.containerNode.style.display = "none";
+ oldContents.style.height = "auto";
+ self._hideChild(oldWidget);
+ }
+ });
+ this._animation.onStop = this._animation.onEnd;
+ this._animation.play();
+ }
+
+ return d; // If child has an href, promise that fires when the widget has finished loading
+ },
+
+ // note: we are treating the container as controller here
+ _onKeyPress: function(/*Event*/ e, /*dijit._Widget*/ fromTitle){
+ // summary:
+ // Handle keypress events
+ // description:
+ // This is called from a handler on AccordionContainer.domNode
+ // (setup in StackContainer), and is also called directly from
+ // the click handler for accordion labels
+ if(this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
+ return;
+ }
+ var k = dojo.keys,
+ c = e.charOrCode;
+ if((fromTitle && (c == k.LEFT_ARROW || c == k.UP_ARROW)) ||
+ (e.ctrlKey && c == k.PAGE_UP)){
+ this._adjacent(false)._buttonWidget._onTitleClick();
+ dojo.stopEvent(e);
+ }else if((fromTitle && (c == k.RIGHT_ARROW || c == k.DOWN_ARROW)) ||
+ (e.ctrlKey && (c == k.PAGE_DOWN || c == k.TAB))){
+ this._adjacent(true)._buttonWidget._onTitleClick();
+ dojo.stopEvent(e);
+ }
+ }
+ }
+);
+
+dojo.declare("dijit.layout._AccordionInnerContainer",
+ [dijit._Widget, dijit._CssStateMixin], {
+ // summary:
+ // Internal widget placed as direct child of AccordionContainer.containerNode.
+ // When other widgets are added as children to an AccordionContainer they are wrapped in
+ // this widget.
+
+/*=====
+ // buttonWidget: String
+ // Name of class to use to instantiate title
+ // (Wish we didn't have a separate widget for just the title but maintaining it
+ // for backwards compatibility, is it worth it?)
+ buttonWidget: null,
+=====*/
+
+/*=====
+ // contentWidget: dijit._Widget
+ // Pointer to the real child widget
+ contentWidget: null,
+=====*/
+
+ baseClass: "dijitAccordionInnerContainer",
+
+ // tell nested layout widget that we will take care of sizing
+ isContainer: true,
+ isLayoutContainer: true,
+
+ buildRendering: function(){
+ // Builds a template like:
+ // <div class=dijitAccordionInnerContainer>
+ // Button
+ // <div class=dijitAccordionChildWrapper>
+ // ContentPane
+ // </div>
+ // </div>
+
+ // Create wrapper div, placed where the child is now
+ this.domNode = dojo.place("<div class='" + this.baseClass + "'>", this.contentWidget.domNode, "after");
+
+ // wrapper div's first child is the button widget (ie, the title bar)
+ var child = this.contentWidget,
+ cls = dojo.getObject(this.buttonWidget);
+ this.button = child._buttonWidget = (new cls({
+ contentWidget: child,
+ label: child.title,
+ title: child.tooltip,
+ dir: child.dir,
+ lang: child.lang,
+ iconClass: child.iconClass,
+ id: child.id + "_button",
+ parent: this.parent
+ })).placeAt(this.domNode);
+
+ // and then the actual content widget (changing it from prior-sibling to last-child),
+ // wrapped by a <div class=dijitAccordionChildWrapper>
+ this.containerNode = dojo.place("<div class='dijitAccordionChildWrapper' style='display:none'>", this.domNode);
+ dojo.place(this.contentWidget.domNode, this.containerNode);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Map changes in content widget's title etc. to changes in the button
+ var button = this.button;
+ this._contentWidgetWatches = [
+ this.contentWidget.watch('title', dojo.hitch(this, function(name, oldValue, newValue){
+ button.set("label", newValue);
+ })),
+ this.contentWidget.watch('tooltip', dojo.hitch(this, function(name, oldValue, newValue){
+ button.set("title", newValue);
+ })),
+ this.contentWidget.watch('iconClass', dojo.hitch(this, function(name, oldValue, newValue){
+ button.set("iconClass", newValue);
+ }))
+ ];
+ },
+
+ _setSelectedAttr: function(/*Boolean*/ isSelected){
+ this._set("selected", isSelected);
+ this.button.set("selected", isSelected);
+ if(isSelected){
+ var cw = this.contentWidget;
+ if(cw.onSelected){ cw.onSelected(); }
+ }
+ },
+
+ startup: function(){
+ // Called by _Container.addChild()
+ this.contentWidget.startup();
+ },
+
+ destroy: function(){
+ this.button.destroyRecursive();
+
+ dojo.forEach(this._contentWidgetWatches || [], function(w){ w.unwatch(); });
+
+ delete this.contentWidget._buttonWidget;
+ delete this.contentWidget._wrapperWidget;
+
+ this.inherited(arguments);
+ },
+
+ destroyDescendants: function(){
+ // since getChildren isn't working for me, have to code this manually
+ this.contentWidget.destroyRecursive();
+ }
});
-this.inherited(arguments);
-},_transition:function(_10,_11,_12){
-if(this._inTransition){
-return;
-}
-var _13=[];
-var _14=this._verticalSpace;
-if(_10){
-_10._wrapperWidget.set("selected",true);
-this._showChild(_10);
-if(this.doLayout&&_10.resize){
-_10.resize(this._containerContentBox);
-}
-var _15=_10.domNode;
-dojo.addClass(_15,"dijitVisible");
-dojo.removeClass(_15,"dijitHidden");
-if(_12){
-var _16=_15.style.overflow;
-_15.style.overflow="hidden";
-_13.push(dojo.animateProperty({node:_15,duration:this.duration,properties:{height:{start:1,end:this._getTargetHeight(_15)}},onEnd:function(){
-_15.style.overflow=_16;
-if(dojo.isIE){
-setTimeout(function(){
-dojo.removeClass(_15.parentNode,"dijitAccordionInnerContainerFocused");
-setTimeout(function(){
-dojo.addClass(_15.parentNode,"dijitAccordionInnerContainerFocused");
-},0);
-},0);
-}
-}}));
-}
-}
-if(_11){
-_11._wrapperWidget.set("selected",false);
-var _17=_11.domNode;
-if(_12){
-var _18=_17.style.overflow;
-_17.style.overflow="hidden";
-_13.push(dojo.animateProperty({node:_17,duration:this.duration,properties:{height:{start:this._getTargetHeight(_17),end:1}},onEnd:function(){
-dojo.addClass(_17,"dijitHidden");
-dojo.removeClass(_17,"dijitVisible");
-_17.style.overflow=_18;
-if(_11.onHide){
-_11.onHide();
-}
-}}));
-}else{
-dojo.addClass(_17,"dijitHidden");
-dojo.removeClass(_17,"dijitVisible");
-if(_11.onHide){
-_11.onHide();
-}
-}
-}
-if(_12){
-this._inTransition=true;
-var _19=dojo.fx.combine(_13);
-_19.onEnd=dojo.hitch(this,function(){
-delete this._inTransition;
+
+dojo.declare("dijit.layout._AccordionButton",
+ [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
+ {
+ // summary:
+ // The title bar to click to open up an accordion pane.
+ // Internal widget used by AccordionContainer.
+ // tags:
+ // private
+
+ templateString: dojo.cache("dijit.layout", "templates/AccordionButton.html", "<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' role=\"tab\" aria-expanded=\"false\"\n\t\t><span class='dijitInline dijitAccordionArrow' role=\"presentation\"></span\n\t\t><span class='arrowTextUp' role=\"presentation\">+</span\n\t\t><span class='arrowTextDown' role=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" role=\"presentation\"/>\n\t\t<span role=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"),
+ attributeMap: dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap), {
+ label: {node: "titleTextNode", type: "innerHTML" },
+ title: {node: "titleTextNode", type: "attribute", attribute: "title"},
+ iconClass: { node: "iconNode", type: "class" }
+ }),
+
+ baseClass: "dijitAccordionTitle",
+
+ getParent: function(){
+ // summary:
+ // Returns the AccordionContainer parent.
+ // tags:
+ // private
+ return this.parent;
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ var titleTextNodeId = this.id.replace(' ','_');
+ dojo.attr(this.titleTextNode, "id", titleTextNodeId+"_title");
+ dijit.setWaiState(this.focusNode, "labelledby", dojo.attr(this.titleTextNode, "id"));
+ dojo.setSelectable(this.domNode, false);
+ },
+
+ getTitleHeight: function(){
+ // summary:
+ // Returns the height of the title dom node.
+ return dojo._getMarginSize(this.domNode).h; // Integer
+ },
+
+ // TODO: maybe the parent should set these methods directly rather than forcing the code
+ // into the button widget?
+ _onTitleClick: function(){
+ // summary:
+ // Callback when someone clicks my title.
+ var parent = this.getParent();
+ parent.selectChild(this.contentWidget, true);
+ dijit.focus(this.focusNode);
+ },
+
+ _onTitleKeyPress: function(/*Event*/ evt){
+ return this.getParent()._onKeyPress(evt, this.contentWidget);
+ },
+
+ _setSelectedAttr: function(/*Boolean*/ isSelected){
+ this._set("selected", isSelected);
+ dijit.setWaiState(this.focusNode, "expanded", isSelected);
+ dijit.setWaiState(this.focusNode, "selected", isSelected);
+ this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
+ }
});
-_19.play();
-}
-},_onKeyPress:function(e,_1a){
-if(this._inTransition||this.disabled||e.altKey||!(_1a||e.ctrlKey)){
-if(this._inTransition){
-dojo.stopEvent(e);
-}
-return;
-}
-var k=dojo.keys,c=e.charOrCode;
-if((_1a&&(c==k.LEFT_ARROW||c==k.UP_ARROW))||(e.ctrlKey&&c==k.PAGE_UP)){
-this._adjacent(false)._buttonWidget._onTitleClick();
-dojo.stopEvent(e);
-}else{
-if((_1a&&(c==k.RIGHT_ARROW||c==k.DOWN_ARROW))||(e.ctrlKey&&(c==k.PAGE_DOWN||c==k.TAB))){
-this._adjacent(true)._buttonWidget._onTitleClick();
-dojo.stopEvent(e);
-}
-}
-}});
-dojo.declare("dijit.layout._AccordionInnerContainer",[dijit._Widget,dijit._CssStateMixin],{baseClass:"dijitAccordionInnerContainer",isContainer:true,isLayoutContainer:true,buildRendering:function(){
-this.domNode=dojo.place("<div class='"+this.baseClass+"'>",this.contentWidget.domNode,"after");
-var _1b=this.contentWidget,cls=dojo.getObject(this.buttonWidget);
-this.button=_1b._buttonWidget=(new cls({contentWidget:_1b,label:_1b.title,title:_1b.tooltip,dir:_1b.dir,lang:_1b.lang,iconClass:_1b.iconClass,id:_1b.id+"_button",parent:this.parent})).placeAt(this.domNode);
-dojo.place(this.contentWidget.domNode,this.domNode);
-},postCreate:function(){
-this.inherited(arguments);
-this.connect(this.contentWidget,"set",function(_1c,_1d){
-var _1e={title:"label",tooltip:"title",iconClass:"iconClass"}[_1c];
-if(_1e){
-this.button.set(_1e,_1d);
-}
-},this);
-},_setSelectedAttr:function(_1f){
-this.selected=_1f;
-this.button.set("selected",_1f);
-if(_1f){
-var cw=this.contentWidget;
-if(cw.onSelected){
-cw.onSelected();
-}
-}
-},startup:function(){
-this.contentWidget.startup();
-},destroy:function(){
-this.button.destroyRecursive();
-delete this.contentWidget._buttonWidget;
-delete this.contentWidget._wrapperWidget;
-this.inherited(arguments);
-},destroyDescendants:function(){
-this.contentWidget.destroyRecursive();
-}});
-dojo.declare("dijit.layout._AccordionButton",[dijit._Widget,dijit._Templated,dijit._CssStateMixin],{templateString:dojo.cache("dijit.layout","templates/AccordionButton.html","<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' wairole=\"tab\" waiState=\"expanded-false\"\n\t\t><span class='dijitInline dijitAccordionArrow' waiRole=\"presentation\"></span\n\t\t><span class='arrowTextUp' waiRole=\"presentation\">+</span\n\t\t><span class='arrowTextDown' waiRole=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" waiRole=\"presentation\"/>\n\t\t<span waiRole=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"),attributeMap:dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap),{label:{node:"titleTextNode",type:"innerHTML"},title:{node:"titleTextNode",type:"attribute",attribute:"title"},iconClass:{node:"iconNode",type:"class"}}),baseClass:"dijitAccordionTitle",getParent:function(){
-return this.parent;
-},postCreate:function(){
-this.inherited(arguments);
-dojo.setSelectable(this.domNode,false);
-var _20=dojo.attr(this.domNode,"id").replace(" ","_");
-dojo.attr(this.titleTextNode,"id",_20+"_title");
-dijit.setWaiState(this.focusNode,"labelledby",dojo.attr(this.titleTextNode,"id"));
-},getTitleHeight:function(){
-return dojo.marginBox(this.domNode).h;
-},_onTitleClick:function(){
-var _21=this.getParent();
-if(!_21._inTransition){
-_21.selectChild(this.contentWidget,true);
-dijit.focus(this.focusNode);
-}
-},_onTitleKeyPress:function(evt){
-return this.getParent()._onKeyPress(evt,this.contentWidget);
-},_setSelectedAttr:function(_22){
-this.selected=_22;
-dijit.setWaiState(this.focusNode,"expanded",_22);
-dijit.setWaiState(this.focusNode,"selected",_22);
-this.focusNode.setAttribute("tabIndex",_22?"0":"-1");
-}});
+
}
diff --git a/lib/dijit/layout/AccordionPane.js b/lib/dijit/layout/AccordionPane.js
index 98b92f8e8..394ba346c 100644
--- a/lib/dijit/layout/AccordionPane.js
+++ b/lib/dijit/layout/AccordionPane.js
@@ -1,16 +1,30 @@
/*
- 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.AccordionPane"]){
-dojo._hasResource["dijit.layout.AccordionPane"]=true;
+if(!dojo._hasResource["dijit.layout.AccordionPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.AccordionPane"] = true;
dojo.provide("dijit.layout.AccordionPane");
dojo.require("dijit.layout.ContentPane");
-dojo.declare("dijit.layout.AccordionPane",dijit.layout.ContentPane,{constructor:function(){
-dojo.deprecated("dijit.layout.AccordionPane deprecated, use ContentPane instead","","2.0");
-},onSelected:function(){
-}});
+
+
+dojo.declare("dijit.layout.AccordionPane", dijit.layout.ContentPane, {
+ // summary:
+ // Deprecated widget. Use `dijit.layout.ContentPane` instead.
+ // tags:
+ // deprecated
+
+ constructor: function(){
+ dojo.deprecated("dijit.layout.AccordionPane deprecated, use ContentPane instead", "", "2.0");
+ },
+
+ onSelected: function(){
+ // summary:
+ // called when this pane is selected
+ }
+});
+
}
diff --git a/lib/dijit/layout/BorderContainer.js b/lib/dijit/layout/BorderContainer.js
index 426a66216..c053256d4 100644
--- a/lib/dijit/layout/BorderContainer.js
+++ b/lib/dijit/layout/BorderContainer.js
@@ -1,327 +1,527 @@
/*
- 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.BorderContainer"]){
-dojo._hasResource["dijit.layout.BorderContainer"]=true;
+if(!dojo._hasResource["dijit.layout.BorderContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.BorderContainer"] = true;
dojo.provide("dijit.layout.BorderContainer");
dojo.require("dijit.layout._LayoutWidget");
dojo.require("dojo.cookie");
-dojo.declare("dijit.layout.BorderContainer",dijit.layout._LayoutWidget,{design:"headline",gutters:true,liveSplitters:true,persist:false,baseClass:"dijitBorderContainer",_splitterClass:"dijit.layout._Splitter",postMixInProperties:function(){
-if(!this.gutters){
-this.baseClass+="NoGutter";
-}
-this.inherited(arguments);
-},postCreate:function(){
-this.inherited(arguments);
-this._splitters={};
-this._splitterThickness={};
-},startup:function(){
-if(this._started){
-return;
-}
-dojo.forEach(this.getChildren(),this._setupChild,this);
-this.inherited(arguments);
-},_setupChild:function(_1){
-var _2=_1.region;
-if(_2){
-this.inherited(arguments);
-dojo.addClass(_1.domNode,this.baseClass+"Pane");
-var _3=this.isLeftToRight();
-if(_2=="leading"){
-_2=_3?"left":"right";
-}
-if(_2=="trailing"){
-_2=_3?"right":"left";
-}
-this["_"+_2]=_1.domNode;
-this["_"+_2+"Widget"]=_1;
-if((_1.splitter||this.gutters)&&!this._splitters[_2]){
-var _4=dojo.getObject(_1.splitter?this._splitterClass:"dijit.layout._Gutter");
-var _5=new _4({id:_1.id+"_splitter",container:this,child:_1,region:_2,live:this.liveSplitters});
-_5.isSplitter=true;
-this._splitters[_2]=_5.domNode;
-dojo.place(this._splitters[_2],_1.domNode,"after");
-_5.startup();
-}
-_1.region=_2;
-}
-},_computeSplitterThickness:function(_6){
-this._splitterThickness[_6]=this._splitterThickness[_6]||dojo.marginBox(this._splitters[_6])[(/top|bottom/.test(_6)?"h":"w")];
-},layout:function(){
-for(var _7 in this._splitters){
-this._computeSplitterThickness(_7);
-}
-this._layoutChildren();
-},addChild:function(_8,_9){
-this.inherited(arguments);
-if(this._started){
-this.layout();
-}
-},removeChild:function(_a){
-var _b=_a.region;
-var _c=this._splitters[_b];
-if(_c){
-dijit.byNode(_c).destroy();
-delete this._splitters[_b];
-delete this._splitterThickness[_b];
-}
-this.inherited(arguments);
-delete this["_"+_b];
-delete this["_"+_b+"Widget"];
-if(this._started){
-this._layoutChildren();
-}
-dojo.removeClass(_a.domNode,this.baseClass+"Pane");
-},getChildren:function(){
-return dojo.filter(this.inherited(arguments),function(_d){
-return !_d.isSplitter;
+dojo.require("dijit._Templated");
+
+
+dojo.declare(
+ "dijit.layout.BorderContainer",
+ dijit.layout._LayoutWidget,
+{
+ // summary:
+ // Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
+ //
+ // description:
+ // A BorderContainer is a box with a specified size, such as style="width: 500px; height: 500px;",
+ // that contains a child widget marked region="center" and optionally children widgets marked
+ // region equal to "top", "bottom", "leading", "trailing", "left" or "right".
+ // Children along the edges will be laid out according to width or height dimensions and may
+ // include optional splitters (splitter="true") to make them resizable by the user. The remaining
+ // space is designated for the center region.
+ //
+ // The outer size must be specified on the BorderContainer node. Width must be specified for the sides
+ // and height for the top and bottom, respectively. No dimensions should be specified on the center;
+ // it will fill the remaining space. Regions named "leading" and "trailing" may be used just like
+ // "left" and "right" except that they will be reversed in right-to-left environments.
+ //
+ // For complex layouts, multiple children can be specified for a single region. In this case, the
+ // layoutPriority flag on the children determines which child is closer to the edge (low layoutPriority)
+ // and which child is closer to the center (high layoutPriority). layoutPriority can also be used
+ // instead of the design attribute to conrol layout precedence of horizontal vs. vertical panes.
+ // example:
+ // | <div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="false"
+ // | style="width: 400px; height: 300px;">
+ // | <div dojoType="dijit.layout.ContentPane" region="top">header text</div>
+ // | <div dojoType="dijit.layout.ContentPane" region="right" splitter="true" style="width: 200px;">table of contents</div>
+ // | <div dojoType="dijit.layout.ContentPane" region="center">client area</div>
+ // | </div>
+
+ // design: String
+ // Which design is used for the layout:
+ // - "headline" (default) where the top and bottom extend
+ // the full width of the container
+ // - "sidebar" where the left and right sides extend from top to bottom.
+ design: "headline",
+
+ // gutters: [const] Boolean
+ // Give each pane a border and margin.
+ // Margin determined by domNode.paddingLeft.
+ // When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
+ gutters: true,
+
+ // liveSplitters: [const] Boolean
+ // Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
+ liveSplitters: true,
+
+ // persist: Boolean
+ // Save splitter positions in a cookie.
+ persist: false,
+
+ baseClass: "dijitBorderContainer",
+
+ // _splitterClass: String
+ // Optional hook to override the default Splitter widget used by BorderContainer
+ _splitterClass: "dijit.layout._Splitter",
+
+ postMixInProperties: function(){
+ // change class name to indicate that BorderContainer is being used purely for
+ // layout (like LayoutContainer) rather than for pretty formatting.
+ if(!this.gutters){
+ this.baseClass += "NoGutter";
+ }
+ this.inherited(arguments);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ dojo.forEach(this.getChildren(), this._setupChild, this);
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*dijit._Widget*/ child){
+ // Override _LayoutWidget._setupChild().
+
+ var region = child.region;
+ if(region){
+ this.inherited(arguments);
+
+ dojo.addClass(child.domNode, this.baseClass+"Pane");
+
+ var ltr = this.isLeftToRight();
+ if(region == "leading"){ region = ltr ? "left" : "right"; }
+ if(region == "trailing"){ region = ltr ? "right" : "left"; }
+
+ // Create draggable splitter for resizing pane,
+ // or alternately if splitter=false but BorderContainer.gutters=true then
+ // insert dummy div just for spacing
+ if(region != "center" && (child.splitter || this.gutters) && !child._splitterWidget){
+ var _Splitter = dojo.getObject(child.splitter ? this._splitterClass : "dijit.layout._Gutter");
+ var splitter = new _Splitter({
+ id: child.id + "_splitter",
+ container: this,
+ child: child,
+ region: region,
+ live: this.liveSplitters
+ });
+ splitter.isSplitter = true;
+ child._splitterWidget = splitter;
+
+ dojo.place(splitter.domNode, child.domNode, "after");
+
+ // Splitters aren't added as Contained children, so we need to call startup explicitly
+ splitter.startup();
+ }
+ child.region = region; // TODO: technically wrong since it overwrites "trailing" with "left" etc.
+ }
+ },
+
+ layout: function(){
+ // Implement _LayoutWidget.layout() virtual method.
+ this._layoutChildren();
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // Override _LayoutWidget.addChild().
+ this.inherited(arguments);
+ if(this._started){
+ this.layout(); //OPT
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ child){
+ // Override _LayoutWidget.removeChild().
+
+ var region = child.region;
+ var splitter = child._splitterWidget
+ if(splitter){
+ splitter.destroy();
+ delete child._splitterWidget;
+ }
+ this.inherited(arguments);
+
+ if(this._started){
+ this._layoutChildren();
+ }
+ // Clean up whatever style changes we made to the child pane.
+ // Unclear how height and width should be handled.
+ dojo.removeClass(child.domNode, this.baseClass+"Pane");
+ dojo.style(child.domNode, {
+ top: "auto",
+ bottom: "auto",
+ left: "auto",
+ right: "auto",
+ position: "static"
+ });
+ dojo.style(child.domNode, region == "top" || region == "bottom" ? "width" : "height", "auto");
+ },
+
+ getChildren: function(){
+ // Override _LayoutWidget.getChildren() to only return real children, not the splitters.
+ return dojo.filter(this.inherited(arguments), function(widget){
+ return !widget.isSplitter;
+ });
+ },
+
+ // TODO: remove in 2.0
+ getSplitter: function(/*String*/region){
+ // summary:
+ // Returns the widget responsible for rendering the splitter associated with region
+ // tags:
+ // deprecated
+ return dojo.filter(this.getChildren(), function(child){
+ return child.region == region;
+ })[0]._splitterWidget;
+ },
+
+ resize: function(newSize, currentSize){
+ // Overrides _LayoutWidget.resize().
+
+ // resetting potential padding to 0px to provide support for 100% width/height + padding
+ // TODO: this hack doesn't respect the box model and is a temporary fix
+ if(!this.cs || !this.pe){
+ var node = this.domNode;
+ this.cs = dojo.getComputedStyle(node);
+ this.pe = dojo._getPadExtents(node, this.cs);
+ this.pe.r = dojo._toPixelValue(node, this.cs.paddingRight);
+ this.pe.b = dojo._toPixelValue(node, this.cs.paddingBottom);
+
+ dojo.style(node, "padding", "0px");
+ }
+
+ this.inherited(arguments);
+ },
+
+ _layoutChildren: function(/*String?*/ changedChildId, /*Number?*/ changedChildSize){
+ // summary:
+ // This is the main routine for setting size/position of each child.
+ // description:
+ // With no arguments, measures the height of top/bottom panes, the width
+ // of left/right panes, and then sizes all panes accordingly.
+ //
+ // With changedRegion specified (as "left", "top", "bottom", or "right"),
+ // it changes that region's width/height to changedRegionSize and
+ // then resizes other regions that were affected.
+ // changedChildId:
+ // Id of the child which should be resized because splitter was dragged.
+ // changedChildSize:
+ // The new width/height (in pixels) to make specified child
+
+ if(!this._borderBox || !this._borderBox.h){
+ // We are currently hidden, or we haven't been sized by our parent yet.
+ // Abort. Someone will resize us later.
+ return;
+ }
+
+ // Generate list of wrappers of my children in the order that I want layoutChildren()
+ // to process them (i.e. from the outside to the inside)
+ var wrappers = dojo.map(this.getChildren(), function(child, idx){
+ return {
+ pane: child,
+ weight: [
+ child.region == "center" ? Infinity : 0,
+ child.layoutPriority,
+ (this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
+ idx
+ ]
+ };
+ }, this);
+ wrappers.sort(function(a, b){
+ var aw = a.weight, bw = b.weight;
+ for(var i=0; i<aw.length; i++){
+ if(aw[i] != bw[i]){
+ return aw[i] - bw[i];
+ }
+ }
+ return 0;
+ });
+
+ // Make new list, combining the externally specified children with splitters and gutters
+ var childrenAndSplitters = [];
+ dojo.forEach(wrappers, function(wrapper){
+ var pane = wrapper.pane;
+ childrenAndSplitters.push(pane);
+ if(pane._splitterWidget){
+ childrenAndSplitters.push(pane._splitterWidget);
+ }
+ });
+
+ // Compute the box in which to lay out my children
+ var dim = {
+ l: this.pe.l,
+ t: this.pe.t,
+ w: this._borderBox.w - this.pe.w,
+ h: this._borderBox.h - this.pe.h
+ };
+
+ // Layout the children, possibly changing size due to a splitter drag
+ dijit.layout.layoutChildren(this.domNode, dim, childrenAndSplitters,
+ changedChildId, changedChildSize);
+ },
+
+ destroyRecursive: function(){
+ // Destroy splitters first, while getChildren() still works
+ dojo.forEach(this.getChildren(), function(child){
+ var splitter = child._splitterWidget;
+ if(splitter){
+ splitter.destroy();
+ }
+ delete child._splitterWidget;
+ });
+
+ // Then destroy the real children, and myself
+ this.inherited(arguments);
+ }
});
-},getSplitter:function(_e){
-var _f=this._splitters[_e];
-return _f?dijit.byNode(_f):null;
-},resize:function(_10,_11){
-if(!this.cs||!this.pe){
-var _12=this.domNode;
-this.cs=dojo.getComputedStyle(_12);
-this.pe=dojo._getPadExtents(_12,this.cs);
-this.pe.r=dojo._toPixelValue(_12,this.cs.paddingRight);
-this.pe.b=dojo._toPixelValue(_12,this.cs.paddingBottom);
-dojo.style(_12,"padding","0px");
-}
-this.inherited(arguments);
-},_layoutChildren:function(_13,_14){
-if(!this._borderBox||!this._borderBox.h){
-return;
-}
-var _15=(this.design=="sidebar");
-var _16=0,_17=0,_18=0,_19=0;
-var _1a={},_1b={},_1c={},_1d={},_1e=(this._center&&this._center.style)||{};
-var _1f=/left|right/.test(_13);
-var _20=!_13||(!_1f&&!_15);
-var _21=!_13||(_1f&&_15);
-if(this._top){
-_1a=(_13=="top"||_21)&&this._top.style;
-_16=_13=="top"?_14:dojo.marginBox(this._top).h;
-}
-if(this._left){
-_1b=(_13=="left"||_20)&&this._left.style;
-_18=_13=="left"?_14:dojo.marginBox(this._left).w;
-}
-if(this._right){
-_1c=(_13=="right"||_20)&&this._right.style;
-_19=_13=="right"?_14:dojo.marginBox(this._right).w;
-}
-if(this._bottom){
-_1d=(_13=="bottom"||_21)&&this._bottom.style;
-_17=_13=="bottom"?_14:dojo.marginBox(this._bottom).h;
-}
-var _22=this._splitters;
-var _23=_22.top,_24=_22.bottom,_25=_22.left,_26=_22.right;
-var _27=this._splitterThickness;
-var _28=_27.top||0,_29=_27.left||0,_2a=_27.right||0,_2b=_27.bottom||0;
-if(_29>50||_2a>50){
-setTimeout(dojo.hitch(this,function(){
-this._splitterThickness={};
-for(var _2c in this._splitters){
-this._computeSplitterThickness(_2c);
-}
-this._layoutChildren();
-}),50);
-return false;
-}
-var pe=this.pe;
-var _2d={left:(_15?_18+_29:0)+pe.l+"px",right:(_15?_19+_2a:0)+pe.r+"px"};
-if(_23){
-dojo.mixin(_23.style,_2d);
-_23.style.top=_16+pe.t+"px";
-}
-if(_24){
-dojo.mixin(_24.style,_2d);
-_24.style.bottom=_17+pe.b+"px";
-}
-_2d={top:(_15?0:_16+_28)+pe.t+"px",bottom:(_15?0:_17+_2b)+pe.b+"px"};
-if(_25){
-dojo.mixin(_25.style,_2d);
-_25.style.left=_18+pe.l+"px";
-}
-if(_26){
-dojo.mixin(_26.style,_2d);
-_26.style.right=_19+pe.r+"px";
-}
-dojo.mixin(_1e,{top:pe.t+_16+_28+"px",left:pe.l+_18+_29+"px",right:pe.r+_19+_2a+"px",bottom:pe.b+_17+_2b+"px"});
-var _2e={top:_15?pe.t+"px":_1e.top,bottom:_15?pe.b+"px":_1e.bottom};
-dojo.mixin(_1b,_2e);
-dojo.mixin(_1c,_2e);
-_1b.left=pe.l+"px";
-_1c.right=pe.r+"px";
-_1a.top=pe.t+"px";
-_1d.bottom=pe.b+"px";
-if(_15){
-_1a.left=_1d.left=_18+_29+pe.l+"px";
-_1a.right=_1d.right=_19+_2a+pe.r+"px";
-}else{
-_1a.left=_1d.left=pe.l+"px";
-_1a.right=_1d.right=pe.r+"px";
-}
-var _2f=this._borderBox.h-pe.t-pe.b,_30=_2f-(_16+_28+_17+_2b),_31=_15?_2f:_30;
-var _32=this._borderBox.w-pe.l-pe.r,_33=_32-(_18+_29+_19+_2a),_34=_15?_33:_32;
-var dim={top:{w:_34,h:_16},bottom:{w:_34,h:_17},left:{w:_18,h:_31},right:{w:_19,h:_31},center:{h:_30,w:_33}};
-if(_13){
-var _35=this["_"+_13+"Widget"],mb={};
-mb[/top|bottom/.test(_13)?"h":"w"]=_14;
-_35.resize?_35.resize(mb,dim[_35.region]):dojo.marginBox(_35.domNode,mb);
-}
-var _36=dojo.isIE<8||(dojo.isIE&&dojo.isQuirks)||dojo.some(this.getChildren(),function(_37){
-return _37.domNode.tagName=="TEXTAREA"||_37.domNode.tagName=="INPUT";
+
+// This argument can be specified for the children of a BorderContainer.
+// Since any widget can be specified as a LayoutContainer child, mix it
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget, {
+ // region: [const] String
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Values: "top", "bottom", "leading", "trailing", "left", "right", "center".
+ // See the `dijit.layout.BorderContainer` description for details.
+ region: '',
+
+ // layoutPriority: [const] Number
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Children with a higher layoutPriority will be placed closer to the BorderContainer center,
+ // between children with a lower layoutPriority.
+ layoutPriority: 0,
+
+ // splitter: [const] Boolean
+ // Parameter for child of `dijit.layout.BorderContainer` where region != "center".
+ // If true, enables user to resize the widget by putting a draggable splitter between
+ // this widget and the region=center widget.
+ splitter: false,
+
+ // minSize: [const] Number
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Specifies a minimum size (in pixels) for this widget when resized by a splitter.
+ minSize: 0,
+
+ // maxSize: [const] Number
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Specifies a maximum size (in pixels) for this widget when resized by a splitter.
+ maxSize: Infinity
});
-if(_36){
-var _38=function(_39,_3a,_3b){
-if(_39){
-(_39.resize?_39.resize(_3a,_3b):dojo.marginBox(_39.domNode,_3a));
-}
-};
-if(_25){
-_25.style.height=_31;
-}
-if(_26){
-_26.style.height=_31;
-}
-_38(this._leftWidget,{h:_31},dim.left);
-_38(this._rightWidget,{h:_31},dim.right);
-if(_23){
-_23.style.width=_34;
-}
-if(_24){
-_24.style.width=_34;
-}
-_38(this._topWidget,{w:_34},dim.top);
-_38(this._bottomWidget,{w:_34},dim.bottom);
-_38(this._centerWidget,dim.center);
-}else{
-var _3c=!_13||(/top|bottom/.test(_13)&&this.design!="sidebar"),_3d=!_13||(/left|right/.test(_13)&&this.design=="sidebar"),_3e={center:true,left:_3c,right:_3c,top:_3d,bottom:_3d};
-dojo.forEach(this.getChildren(),function(_3f){
-if(_3f.resize&&_3e[_3f.region]){
-_3f.resize(null,dim[_3f.region]);
-}
-},this);
-}
-},destroy:function(){
-for(var _40 in this._splitters){
-var _41=this._splitters[_40];
-dijit.byNode(_41).destroy();
-dojo.destroy(_41);
-}
-delete this._splitters;
-delete this._splitterThickness;
-this.inherited(arguments);
-}});
-dojo.extend(dijit._Widget,{region:"",splitter:false,minSize:0,maxSize:Infinity});
-dojo.require("dijit._Templated");
-dojo.declare("dijit.layout._Splitter",[dijit._Widget,dijit._Templated],{live:true,templateString:"<div class=\"dijitSplitter\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse\" tabIndex=\"0\" waiRole=\"separator\"><div class=\"dijitSplitterThumb\"></div></div>",postCreate:function(){
-this.inherited(arguments);
-this.horizontal=/top|bottom/.test(this.region);
-dojo.addClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V"));
-this._factor=/top|left/.test(this.region)?1:-1;
-this._cookieName=this.container.id+"_"+this.region;
-if(this.container.persist){
-var _42=dojo.cookie(this._cookieName);
-if(_42){
-this.child.domNode.style[this.horizontal?"height":"width"]=_42;
-}
-}
-},_computeMaxSize:function(){
-var dim=this.horizontal?"h":"w",_43=this.container._splitterThickness[this.region];
-var _44={left:"right",right:"left",top:"bottom",bottom:"top",leading:"trailing",trailing:"leading"},_45=this.container["_"+_44[this.region]];
-var _46=dojo.contentBox(this.container.domNode)[dim]-(_45?dojo.marginBox(_45)[dim]:0)-20-_43*2;
-return Math.min(this.child.maxSize,_46);
-},_startDrag:function(e){
-if(!this.cover){
-this.cover=dojo.doc.createElement("div");
-dojo.addClass(this.cover,"dijitSplitterCover");
-dojo.place(this.cover,this.child.domNode,"after");
-}
-dojo.addClass(this.cover,"dijitSplitterCoverActive");
-if(this.fake){
-dojo.destroy(this.fake);
-}
-if(!(this._resize=this.live)){
-(this.fake=this.domNode.cloneNode(true)).removeAttribute("id");
-dojo.addClass(this.domNode,"dijitSplitterShadow");
-dojo.place(this.fake,this.domNode,"after");
-}
-dojo.addClass(this.domNode,"dijitSplitterActive");
-dojo.addClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V")+"Active");
-if(this.fake){
-dojo.removeClass(this.fake,"dijitSplitterHover");
-dojo.removeClass(this.fake,"dijitSplitter"+(this.horizontal?"H":"V")+"Hover");
-}
-var _47=this._factor,max=this._computeMaxSize(),min=this.child.minSize||20,_48=this.horizontal,_49=_48?"pageY":"pageX",_4a=e[_49],_4b=this.domNode.style,dim=_48?"h":"w",_4c=dojo.marginBox(this.child.domNode)[dim],_4d=this.region,_4e=parseInt(this.domNode.style[_4d],10),_4f=this._resize,_50=this.child.domNode,_51=dojo.hitch(this.container,this.container._layoutChildren),de=dojo.doc;
-this._handlers=(this._handlers||[]).concat([dojo.connect(de,"onmousemove",this._drag=function(e,_52){
-var _53=e[_49]-_4a,_54=_47*_53+_4c,_55=Math.max(Math.min(_54,max),min);
-if(_4f||_52){
-_51(_4d,_55);
-}
-_4b[_4d]=_47*_53+_4e+(_55-_54)+"px";
-}),dojo.connect(de,"ondragstart",dojo.stopEvent),dojo.connect(dojo.body(),"onselectstart",dojo.stopEvent),dojo.connect(de,"onmouseup",this,"_stopDrag")]);
-dojo.stopEvent(e);
-},_onMouse:function(e){
-var o=(e.type=="mouseover"||e.type=="mouseenter");
-dojo.toggleClass(this.domNode,"dijitSplitterHover",o);
-dojo.toggleClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V")+"Hover",o);
-},_stopDrag:function(e){
-try{
-if(this.cover){
-dojo.removeClass(this.cover,"dijitSplitterCoverActive");
-}
-if(this.fake){
-dojo.destroy(this.fake);
-}
-dojo.removeClass(this.domNode,"dijitSplitterActive");
-dojo.removeClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V")+"Active");
-dojo.removeClass(this.domNode,"dijitSplitterShadow");
-this._drag(e);
-this._drag(e,true);
-}
-finally{
-this._cleanupHandlers();
-delete this._drag;
-}
-if(this.container.persist){
-dojo.cookie(this._cookieName,this.child.domNode.style[this.horizontal?"height":"width"],{expires:365});
-}
-},_cleanupHandlers:function(){
-dojo.forEach(this._handlers,dojo.disconnect);
-delete this._handlers;
-},_onKeyPress:function(e){
-this._resize=true;
-var _56=this.horizontal;
-var _57=1;
-var dk=dojo.keys;
-switch(e.charOrCode){
-case _56?dk.UP_ARROW:dk.LEFT_ARROW:
-_57*=-1;
-case _56?dk.DOWN_ARROW:dk.RIGHT_ARROW:
-break;
-default:
-return;
-}
-var _58=dojo.marginBox(this.child.domNode)[_56?"h":"w"]+this._factor*_57;
-this.container._layoutChildren(this.region,Math.max(Math.min(_58,this._computeMaxSize()),this.child.minSize));
-dojo.stopEvent(e);
-},destroy:function(){
-this._cleanupHandlers();
-delete this.child;
-delete this.container;
-delete this.cover;
-delete this.fake;
-this.inherited(arguments);
-}});
-dojo.declare("dijit.layout._Gutter",[dijit._Widget,dijit._Templated],{templateString:"<div class=\"dijitGutter\" waiRole=\"presentation\"></div>",postCreate:function(){
-this.horizontal=/top|bottom/.test(this.region);
-dojo.addClass(this.domNode,"dijitGutter"+(this.horizontal?"H":"V"));
-}});
+
+dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
+{
+ // summary:
+ // A draggable spacer between two items in a `dijit.layout.BorderContainer`.
+ // description:
+ // This is instantiated by `dijit.layout.BorderContainer`. Users should not
+ // create it directly.
+ // tags:
+ // private
+
+/*=====
+ // container: [const] dijit.layout.BorderContainer
+ // Pointer to the parent BorderContainer
+ container: null,
+
+ // child: [const] dijit.layout._LayoutWidget
+ // Pointer to the pane associated with this splitter
+ child: null,
+
+ // region: [const] String
+ // Region of pane associated with this splitter.
+ // "top", "bottom", "left", "right".
+ region: null,
+=====*/
+
+ // live: [const] Boolean
+ // If true, the child's size changes and the child widget is redrawn as you drag the splitter;
+ // otherwise, the size doesn't change until you drop the splitter (by mouse-up)
+ live: true,
+
+ templateString: '<div class="dijitSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse" tabIndex="0" role="separator"><div class="dijitSplitterThumb"></div></div>',
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+
+ this.horizontal = /top|bottom/.test(this.region);
+ this._factor = /top|left/.test(this.region) ? 1 : -1;
+ this._cookieName = this.container.id + "_" + this.region;
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
+
+ if(this.container.persist){
+ // restore old size
+ var persistSize = dojo.cookie(this._cookieName);
+ if(persistSize){
+ this.child.domNode.style[this.horizontal ? "height" : "width"] = persistSize;
+ }
+ }
+ },
+
+ _computeMaxSize: function(){
+ // summary:
+ // Return the maximum size that my corresponding pane can be set to
+
+ var dim = this.horizontal ? 'h' : 'w',
+ childSize = dojo.marginBox(this.child.domNode)[dim],
+ center = dojo.filter(this.container.getChildren(), function(child){ return child.region == "center";})[0],
+ spaceAvailable = dojo.marginBox(center.domNode)[dim]; // can expand until center is crushed to 0
+
+ return Math.min(this.child.maxSize, childSize + spaceAvailable);
+ },
+
+ _startDrag: function(e){
+ if(!this.cover){
+ this.cover = dojo.doc.createElement('div');
+ dojo.addClass(this.cover, "dijitSplitterCover");
+ dojo.place(this.cover, this.child.domNode, "after");
+ }
+ dojo.addClass(this.cover, "dijitSplitterCoverActive");
+
+ // Safeguard in case the stop event was missed. Shouldn't be necessary if we always get the mouse up.
+ if(this.fake){ dojo.destroy(this.fake); }
+ if(!(this._resize = this.live)){ //TODO: disable live for IE6?
+ // create fake splitter to display at old position while we drag
+ (this.fake = this.domNode.cloneNode(true)).removeAttribute("id");
+ dojo.addClass(this.domNode, "dijitSplitterShadow");
+ dojo.place(this.fake, this.domNode, "after");
+ }
+ dojo.addClass(this.domNode, "dijitSplitterActive dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
+ if(this.fake){
+ dojo.removeClass(this.fake, "dijitSplitterHover dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
+ }
+
+ //Performance: load data info local vars for onmousevent function closure
+ var factor = this._factor,
+ isHorizontal = this.horizontal,
+ axis = isHorizontal ? "pageY" : "pageX",
+ pageStart = e[axis],
+ splitterStyle = this.domNode.style,
+ dim = isHorizontal ? 'h' : 'w',
+ childStart = dojo.marginBox(this.child.domNode)[dim],
+ max = this._computeMaxSize(),
+ min = this.child.minSize || 20,
+ region = this.region,
+ splitterAttr = region == "top" || region == "bottom" ? "top" : "left", // style attribute of splitter to adjust
+ splitterStart = parseInt(splitterStyle[splitterAttr], 10),
+ resize = this._resize,
+ layoutFunc = dojo.hitch(this.container, "_layoutChildren", this.child.id),
+ de = dojo.doc;
+
+ this._handlers = (this._handlers || []).concat([
+ dojo.connect(de, "onmousemove", this._drag = function(e, forceResize){
+ var delta = e[axis] - pageStart,
+ childSize = factor * delta + childStart,
+ boundChildSize = Math.max(Math.min(childSize, max), min);
+
+ if(resize || forceResize){
+ layoutFunc(boundChildSize);
+ }
+ // TODO: setting style directly (usually) sets content box size, need to set margin box size
+ splitterStyle[splitterAttr] = delta + splitterStart + factor*(boundChildSize - childSize) + "px";
+ }),
+ dojo.connect(de, "ondragstart", dojo.stopEvent),
+ dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent),
+ dojo.connect(de, "onmouseup", this, "_stopDrag")
+ ]);
+ dojo.stopEvent(e);
+ },
+
+ _onMouse: function(e){
+ var o = (e.type == "mouseover" || e.type == "mouseenter");
+ dojo.toggleClass(this.domNode, "dijitSplitterHover", o);
+ dojo.toggleClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover", o);
+ },
+
+ _stopDrag: function(e){
+ try{
+ if(this.cover){
+ dojo.removeClass(this.cover, "dijitSplitterCoverActive");
+ }
+ if(this.fake){ dojo.destroy(this.fake); }
+ dojo.removeClass(this.domNode, "dijitSplitterActive dijitSplitter"
+ + (this.horizontal ? "H" : "V") + "Active dijitSplitterShadow");
+ this._drag(e); //TODO: redundant with onmousemove?
+ this._drag(e, true);
+ }finally{
+ this._cleanupHandlers();
+ delete this._drag;
+ }
+
+ if(this.container.persist){
+ dojo.cookie(this._cookieName, this.child.domNode.style[this.horizontal ? "height" : "width"], {expires:365});
+ }
+ },
+
+ _cleanupHandlers: function(){
+ dojo.forEach(this._handlers, dojo.disconnect);
+ delete this._handlers;
+ },
+
+ _onKeyPress: function(/*Event*/ e){
+ // should we apply typematic to this?
+ this._resize = true;
+ var horizontal = this.horizontal;
+ var tick = 1;
+ var dk = dojo.keys;
+ switch(e.charOrCode){
+ case horizontal ? dk.UP_ARROW : dk.LEFT_ARROW:
+ tick *= -1;
+// break;
+ case horizontal ? dk.DOWN_ARROW : dk.RIGHT_ARROW:
+ break;
+ default:
+// this.inherited(arguments);
+ return;
+ }
+ var childSize = dojo._getMarginSize(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
+ this.container._layoutChildren(this.child.id, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
+ dojo.stopEvent(e);
+ },
+
+ destroy: function(){
+ this._cleanupHandlers();
+ delete this.child;
+ delete this.container;
+ delete this.cover;
+ delete this.fake;
+ this.inherited(arguments);
+ }
+});
+
+dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated],
+{
+ // summary:
+ // Just a spacer div to separate side pane from center pane.
+ // Basically a trick to lookup the gutter/splitter width from the theme.
+ // description:
+ // Instantiated by `dijit.layout.BorderContainer`. Users should not
+ // create directly.
+ // tags:
+ // private
+
+ templateString: '<div class="dijitGutter" role="presentation"></div>',
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.horizontal = /top|bottom/.test(this.region);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.addClass(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
+ }
+});
+
}
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(){
-}});
+
}
diff --git a/lib/dijit/layout/LayoutContainer.js b/lib/dijit/layout/LayoutContainer.js
index 9d9fdc6a4..11204346f 100644
--- a/lib/dijit/layout/LayoutContainer.js
+++ b/lib/dijit/layout/LayoutContainer.js
@@ -1,28 +1,86 @@
/*
- 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.LayoutContainer"]){
-dojo._hasResource["dijit.layout.LayoutContainer"]=true;
+if(!dojo._hasResource["dijit.layout.LayoutContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.LayoutContainer"] = true;
dojo.provide("dijit.layout.LayoutContainer");
dojo.require("dijit.layout._LayoutWidget");
-dojo.declare("dijit.layout.LayoutContainer",dijit.layout._LayoutWidget,{baseClass:"dijitLayoutContainer",constructor:function(){
-dojo.deprecated("dijit.layout.LayoutContainer is deprecated","use BorderContainer instead",2);
-},layout:function(){
-dijit.layout.layoutChildren(this.domNode,this._contentBox,this.getChildren());
-},addChild:function(_1,_2){
-this.inherited(arguments);
-if(this._started){
-dijit.layout.layoutChildren(this.domNode,this._contentBox,this.getChildren());
-}
-},removeChild:function(_3){
-this.inherited(arguments);
-if(this._started){
-dijit.layout.layoutChildren(this.domNode,this._contentBox,this.getChildren());
-}
-}});
-dojo.extend(dijit._Widget,{layoutAlign:"none"});
+
+
+dojo.declare("dijit.layout.LayoutContainer",
+ dijit.layout._LayoutWidget,
+ {
+ // summary:
+ // Deprecated. Use `dijit.layout.BorderContainer` instead.
+ //
+ // description:
+ // Provides Delphi-style panel layout semantics.
+ //
+ // A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
+ // that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
+ // It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
+ // and then it takes the child marked "client" and puts it into the remaining space in the middle.
+ //
+ // Left/right positioning is similar to CSS's "float: left" and "float: right",
+ // and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
+ // CSS.
+ //
+ // Note that there can only be one client element, but there can be multiple left, right, top,
+ // or bottom elements.
+ //
+ // example:
+ // | <style>
+ // | html, body{ height: 100%; width: 100%; }
+ // | </style>
+ // | <div dojoType="dijit.layout.LayoutContainer" style="width: 100%; height: 100%">
+ // | <div dojoType="dijit.layout.ContentPane" layoutAlign="top">header text</div>
+ // | <div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="width: 200px;">table of contents</div>
+ // | <div dojoType="dijit.layout.ContentPane" layoutAlign="client">client area</div>
+ // | </div>
+ //
+ // Lays out each child in the natural order the children occur in.
+ // Basically each child is laid out into the "remaining space", where "remaining space" is initially
+ // the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
+ // tags:
+ // deprecated
+
+ baseClass: "dijitLayoutContainer",
+
+ constructor: function(){
+ dojo.deprecated("dijit.layout.LayoutContainer is deprecated", "use BorderContainer instead", 2.0);
+ },
+
+ layout: function(){
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ this.inherited(arguments);
+ if(this._started){
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ widget){
+ this.inherited(arguments);
+ if(this._started){
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
+ }
+ }
+});
+
+// This argument can be specified for the children of a LayoutContainer.
+// Since any widget can be specified as a LayoutContainer child, mix it
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget, {
+ // layoutAlign: String
+ // "none", "left", "right", "bottom", "top", and "client".
+ // See the LayoutContainer description for details on this parameter.
+ layoutAlign: 'none'
+});
+
}
diff --git a/lib/dijit/layout/LinkPane.js b/lib/dijit/layout/LinkPane.js
index 38e6567e7..34e2d92bb 100644
--- a/lib/dijit/layout/LinkPane.js
+++ b/lib/dijit/layout/LinkPane.js
@@ -1,20 +1,51 @@
/*
- 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.LinkPane"]){
-dojo._hasResource["dijit.layout.LinkPane"]=true;
+if(!dojo._hasResource["dijit.layout.LinkPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.LinkPane"] = true;
dojo.provide("dijit.layout.LinkPane");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit._Templated");
-dojo.declare("dijit.layout.LinkPane",[dijit.layout.ContentPane,dijit._Templated],{templateString:"<div class=\"dijitLinkPane\" dojoAttachPoint=\"containerNode\"></div>",postMixInProperties:function(){
-if(this.srcNodeRef){
-this.title+=this.srcNodeRef.innerHTML;
-}
-this.inherited(arguments);
-},_fillContent:function(_1){
-}});
+
+
+dojo.declare("dijit.layout.LinkPane",
+ [dijit.layout.ContentPane, dijit._Templated],
+ {
+ // summary:
+ // A ContentPane with an href where (when declared in markup)
+ // the title is specified as innerHTML rather than as a title attribute.
+ // description:
+ // LinkPane is just a ContentPane that is declared in markup similarly
+ // to an anchor. The anchor's body (the words between `<a>` and `</a>`)
+ // become the title of the widget (used for TabContainer, AccordionContainer, etc.)
+ // example:
+ // | <a href="foo.html">my title</a>
+
+ // I'm using a template because the user may specify the input as
+ // <a href="foo.html">title</a>, in which case we need to get rid of the
+ // <a> because we don't want a link.
+ templateString: '<div class="dijitLinkPane" dojoAttachPoint="containerNode"></div>',
+
+ postMixInProperties: function(){
+ // If user has specified node contents, they become the title
+ // (the link must be plain text)
+ if(this.srcNodeRef){
+ this.title += this.srcNodeRef.innerHTML;
+ }
+ this.inherited(arguments);
+ },
+
+ _fillContent: function(/*DomNode*/ source){
+ // Overrides _Templated._fillContent().
+
+ // _Templated._fillContent() relocates srcNodeRef innerHTML to templated container node,
+ // but in our case the srcNodeRef innerHTML is the title, so shouldn't be
+ // copied
+ }
+});
+
}
diff --git a/lib/dijit/layout/ScrollingTabController.js b/lib/dijit/layout/ScrollingTabController.js
index 4ee0bd16e..a91c526de 100644
--- a/lib/dijit/layout/ScrollingTabController.js
+++ b/lib/dijit/layout/ScrollingTabController.js
@@ -1,199 +1,483 @@
/*
- 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.ScrollingTabController"]){
-dojo._hasResource["dijit.layout.ScrollingTabController"]=true;
+if(!dojo._hasResource["dijit.layout.ScrollingTabController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.ScrollingTabController"] = true;
dojo.provide("dijit.layout.ScrollingTabController");
dojo.require("dijit.layout.TabController");
dojo.require("dijit.Menu");
-dojo.declare("dijit.layout.ScrollingTabController",dijit.layout.TabController,{templateString:dojo.cache("dijit.layout","templates/ScrollingTabController.html","<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\" iconClass=\"dijitTabStripMenuIcon\"\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=false>&#9660;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=false>&#9664;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=false>&#9654;</div>\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\n\t\t<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>\n"),useMenu:true,useSlider:true,tabStripClass:"",widgetsInTemplate:true,_minScroll:5,attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{"class":"containerNode"}),postCreate:function(){
-this.inherited(arguments);
-var n=this.domNode;
-this.scrollNode=this.tablistWrapper;
-this._initButtons();
-if(!this.tabStripClass){
-this.tabStripClass="dijitTabContainer"+this.tabPosition.charAt(0).toUpperCase()+this.tabPosition.substr(1).replace(/-.*/,"")+"None";
-dojo.addClass(n,"tabStrip-disabled");
-}
-dojo.addClass(this.tablistWrapper,this.tabStripClass);
-},onStartup:function(){
-this.inherited(arguments);
-dojo.style(this.domNode,"visibility","visible");
-this._postStartup=true;
-},onAddChild:function(_1,_2){
-this.inherited(arguments);
-var _3;
-if(this.useMenu){
-var _4=this.containerId;
-_3=new dijit.MenuItem({id:_1.id+"_stcMi",label:_1.title,dir:_1.dir,lang:_1.lang,onClick:dojo.hitch(this,function(){
-var _5=dijit.byId(_4);
-_5.selectChild(_1);
-})});
-this._menuChildren[_1.id]=_3;
-this._menu.addChild(_3,_2);
-}
-this.pane2handles[_1.id].push(this.connect(this.pane2button[_1.id],"set",function(_6,_7){
-if(this._postStartup){
-if(_6=="label"){
-if(_3){
-_3.set(_6,_7);
-}
-if(this._dim){
-this.resize(this._dim);
-}
-}
-}
-}));
-dojo.style(this.containerNode,"width",(dojo.style(this.containerNode,"width")+200)+"px");
-},onRemoveChild:function(_8,_9){
-var _a=this.pane2button[_8.id];
-if(this._selectedTab===_a.domNode){
-this._selectedTab=null;
-}
-if(this.useMenu&&_8&&_8.id&&this._menuChildren[_8.id]){
-this._menu.removeChild(this._menuChildren[_8.id]);
-this._menuChildren[_8.id].destroy();
-delete this._menuChildren[_8.id];
-}
-this.inherited(arguments);
-},_initButtons:function(){
-this._menuChildren={};
-this._btnWidth=0;
-this._buttons=dojo.query("> .tabStripButton",this.domNode).filter(function(_b){
-if((this.useMenu&&_b==this._menuBtn.domNode)||(this.useSlider&&(_b==this._rightBtn.domNode||_b==this._leftBtn.domNode))){
-this._btnWidth+=dojo.marginBox(_b).w;
-return true;
-}else{
-dojo.style(_b,"display","none");
-return false;
-}
-},this);
-if(this.useMenu){
-this._menu=new dijit.Menu({id:this.id+"_menu",dir:this.dir,lang:this.lang,targetNodeIds:[this._menuBtn.domNode],leftClickToOpen:true,refocus:false});
-this._supportingWidgets.push(this._menu);
-}
-},_getTabsWidth:function(){
-var _c=this.getChildren();
-if(_c.length){
-var _d=_c[this.isLeftToRight()?0:_c.length-1].domNode,_e=_c[this.isLeftToRight()?_c.length-1:0].domNode;
-return _e.offsetLeft+dojo.style(_e,"width")-_d.offsetLeft;
-}else{
-return 0;
-}
-},_enableBtn:function(_f){
-var _10=this._getTabsWidth();
-_f=_f||dojo.style(this.scrollNode,"width");
-return _10>0&&_f<_10;
-},resize:function(dim){
-if(this.domNode.offsetWidth==0){
-return;
-}
-this._dim=dim;
-this.scrollNode.style.height="auto";
-this._contentBox=dijit.layout.marginBox2contentBox(this.domNode,{h:0,w:dim.w});
-this._contentBox.h=this.scrollNode.offsetHeight;
-dojo.contentBox(this.domNode,this._contentBox);
-var _11=this._enableBtn(this._contentBox.w);
-this._buttons.style("display",_11?"":"none");
-this._leftBtn.layoutAlign="left";
-this._rightBtn.layoutAlign="right";
-this._menuBtn.layoutAlign=this.isLeftToRight()?"right":"left";
-dijit.layout.layoutChildren(this.domNode,this._contentBox,[this._menuBtn,this._leftBtn,this._rightBtn,{domNode:this.scrollNode,layoutAlign:"client"}]);
-if(this._selectedTab){
-if(this._anim&&this._anim.status()=="playing"){
-this._anim.stop();
-}
-var w=this.scrollNode,sl=this._convertToScrollLeft(this._getScrollForSelectedTab());
-w.scrollLeft=sl;
-}
-this._setButtonClass(this._getScroll());
-this._postResize=true;
-},_getScroll:function(){
-var sl=(this.isLeftToRight()||dojo.isIE<8||(dojo.isIE&&dojo.isQuirks)||dojo.isWebKit)?this.scrollNode.scrollLeft:dojo.style(this.containerNode,"width")-dojo.style(this.scrollNode,"width")+(dojo.isIE==8?-1:1)*this.scrollNode.scrollLeft;
-return sl;
-},_convertToScrollLeft:function(val){
-if(this.isLeftToRight()||dojo.isIE<8||(dojo.isIE&&dojo.isQuirks)||dojo.isWebKit){
-return val;
-}else{
-var _12=dojo.style(this.containerNode,"width")-dojo.style(this.scrollNode,"width");
-return (dojo.isIE==8?-1:1)*(val-_12);
-}
-},onSelectChild:function(_13){
-var tab=this.pane2button[_13.id];
-if(!tab||!_13){
-return;
-}
-var _14=tab.domNode;
-if(this._postResize&&_14!=this._selectedTab){
-this._selectedTab=_14;
-var sl=this._getScroll();
-if(sl>_14.offsetLeft||sl+dojo.style(this.scrollNode,"width")<_14.offsetLeft+dojo.style(_14,"width")){
-this.createSmoothScroll().play();
-}
-}
-this.inherited(arguments);
-},_getScrollBounds:function(){
-var _15=this.getChildren(),_16=dojo.style(this.scrollNode,"width"),_17=dojo.style(this.containerNode,"width"),_18=_17-_16,_19=this._getTabsWidth();
-if(_15.length&&_19>_16){
-return {min:this.isLeftToRight()?0:_15[_15.length-1].domNode.offsetLeft,max:this.isLeftToRight()?(_15[_15.length-1].domNode.offsetLeft+dojo.style(_15[_15.length-1].domNode,"width"))-_16:_18};
-}else{
-var _1a=this.isLeftToRight()?0:_18;
-return {min:_1a,max:_1a};
-}
-},_getScrollForSelectedTab:function(){
-var w=this.scrollNode,n=this._selectedTab,_1b=dojo.style(this.scrollNode,"width"),_1c=this._getScrollBounds();
-var pos=(n.offsetLeft+dojo.style(n,"width")/2)-_1b/2;
-pos=Math.min(Math.max(pos,_1c.min),_1c.max);
-return pos;
-},createSmoothScroll:function(x){
-if(arguments.length>0){
-var _1d=this._getScrollBounds();
-x=Math.min(Math.max(x,_1d.min),_1d.max);
-}else{
-x=this._getScrollForSelectedTab();
-}
-if(this._anim&&this._anim.status()=="playing"){
-this._anim.stop();
-}
-var _1e=this,w=this.scrollNode,_1f=new dojo._Animation({beforeBegin:function(){
-if(this.curve){
-delete this.curve;
-}
-var _20=w.scrollLeft,_21=_1e._convertToScrollLeft(x);
-_1f.curve=new dojo._Line(_20,_21);
-},onAnimate:function(val){
-w.scrollLeft=val;
-}});
-this._anim=_1f;
-this._setButtonClass(x);
-return _1f;
-},_getBtnNode:function(e){
-var n=e.target;
-while(n&&!dojo.hasClass(n,"tabStripButton")){
-n=n.parentNode;
-}
-return n;
-},doSlideRight:function(e){
-this.doSlide(1,this._getBtnNode(e));
-},doSlideLeft:function(e){
-this.doSlide(-1,this._getBtnNode(e));
-},doSlide:function(_22,_23){
-if(_23&&dojo.hasClass(_23,"dijitTabDisabled")){
-return;
-}
-var _24=dojo.style(this.scrollNode,"width");
-var d=(_24*0.75)*_22;
-var to=this._getScroll()+d;
-this._setButtonClass(to);
-this.createSmoothScroll(to).play();
-},_setButtonClass:function(_25){
-var _26=this._getScrollBounds();
-this._leftBtn.set("disabled",_25<=_26.min);
-this._rightBtn.set("disabled",_25>=_26.max);
-}});
-dojo.declare("dijit.layout._ScrollingTabControllerButton",dijit.form.Button,{baseClass:"dijitTab tabStripButton",templateString:dojo.cache("dijit.layout","templates/_ScrollingTabControllerButton.html","<div dojoAttachEvent=\"onclick:_onButtonClick\">\n\t<div waiRole=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\n\t\t<div waiRole=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\n\t\t\t<img waiRole=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>\n"),tabIndex:"-1"});
+dojo.require("dijit.form.Button");
+dojo.require("dijit._HasDropDown");
+
+
+dojo.declare("dijit.layout.ScrollingTabController",
+ dijit.layout.TabController,
+ {
+ // summary:
+ // Set of tabs with left/right arrow keys and a menu to switch between tabs not
+ // all fitting on a single row.
+ // Works only for horizontal tabs (either above or below the content, not to the left
+ // or right).
+ // tags:
+ // private
+
+ templateString: dojo.cache("dijit.layout", "templates/ScrollingTabController.html", "<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerMenuButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\" containerId=\"${containerId}\" iconClass=\"dijitTabStripMenuIcon\"\n\t\t\tdropDownPosition=\"below-alt, above-alt\"\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=\"false\">&#9660;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=\"false\">&#9664;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=\"false\">&#9654;</div>\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\n\t\t<div role='tablist' dojoAttachEvent='onkeypress:onkeypress'\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>\n"),
+
+ // useMenu: [const] Boolean
+ // True if a menu should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useMenu: true,
+
+ // useSlider: [const] Boolean
+ // True if a slider should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useSlider: true,
+
+ // tabStripClass: [const] String
+ // The css class to apply to the tab strip, if it is visible.
+ tabStripClass: "",
+
+ widgetsInTemplate: true,
+
+ // _minScroll: Number
+ // The distance in pixels from the edge of the tab strip which,
+ // if a scroll animation is less than, forces the scroll to
+ // go all the way to the left/right.
+ _minScroll: 5,
+
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ "class": "containerNode"
+ }),
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ var n = this.domNode;
+
+ this.scrollNode = this.tablistWrapper;
+ this._initButtons();
+
+ if(!this.tabStripClass){
+ this.tabStripClass = "dijitTabContainer" +
+ this.tabPosition.charAt(0).toUpperCase() +
+ this.tabPosition.substr(1).replace(/-.*/, "") +
+ "None";
+ dojo.addClass(n, "tabStrip-disabled")
+ }
+
+ dojo.addClass(this.tablistWrapper, this.tabStripClass);
+ },
+
+ onStartup: function(){
+ this.inherited(arguments);
+
+ // Do not show the TabController until the related
+ // StackController has added it's children. This gives
+ // a less visually jumpy instantiation.
+ dojo.style(this.domNode, "visibility", "visible");
+ this._postStartup = true;
+ },
+
+ onAddChild: function(page, insertIndex){
+ this.inherited(arguments);
+
+ // changes to the tab button label or iconClass will have changed the width of the
+ // buttons, so do a resize
+ dojo.forEach(["label", "iconClass"], function(attr){
+ this.pane2watches[page.id].push(
+ this.pane2button[page.id].watch(attr, dojo.hitch(this, function(name, oldValue, newValue){
+ if(this._postStartup && this._dim){
+ this.resize(this._dim);
+ }
+ }))
+ );
+ }, this);
+
+ // Increment the width of the wrapper when a tab is added
+ // This makes sure that the buttons never wrap.
+ // The value 200 is chosen as it should be bigger than most
+ // Tab button widths.
+ dojo.style(this.containerNode, "width",
+ (dojo.style(this.containerNode, "width") + 200) + "px");
+ },
+
+ onRemoveChild: function(page, insertIndex){
+ // null out _selectedTab because we are about to delete that dom node
+ var button = this.pane2button[page.id];
+ if(this._selectedTab === button.domNode){
+ this._selectedTab = null;
+ }
+
+ this.inherited(arguments);
+ },
+
+ _initButtons: function(){
+ // summary:
+ // Creates the buttons used to scroll to view tabs that
+ // may not be visible if the TabContainer is too narrow.
+
+ // Make a list of the buttons to display when the tab labels become
+ // wider than the TabContainer, and hide the other buttons.
+ // Also gets the total width of the displayed buttons.
+ this._btnWidth = 0;
+ this._buttons = dojo.query("> .tabStripButton", this.domNode).filter(function(btn){
+ if((this.useMenu && btn == this._menuBtn.domNode) ||
+ (this.useSlider && (btn == this._rightBtn.domNode || btn == this._leftBtn.domNode))){
+ this._btnWidth += dojo._getMarginSize(btn).w;
+ return true;
+ }else{
+ dojo.style(btn, "display", "none");
+ return false;
+ }
+ }, this);
+ },
+
+ _getTabsWidth: function(){
+ var children = this.getChildren();
+ if(children.length){
+ var leftTab = children[this.isLeftToRight() ? 0 : children.length - 1].domNode,
+ rightTab = children[this.isLeftToRight() ? children.length - 1 : 0].domNode;
+ return rightTab.offsetLeft + dojo.style(rightTab, "width") - leftTab.offsetLeft;
+ }else{
+ return 0;
+ }
+ },
+
+ _enableBtn: function(width){
+ // summary:
+ // Determines if the tabs are wider than the width of the TabContainer, and
+ // thus that we need to display left/right/menu navigation buttons.
+ var tabsWidth = this._getTabsWidth();
+ width = width || dojo.style(this.scrollNode, "width");
+ return tabsWidth > 0 && width < tabsWidth;
+ },
+
+ resize: function(dim){
+ // summary:
+ // Hides or displays the buttons used to scroll the tab list and launch the menu
+ // that selects tabs.
+
+ if(this.domNode.offsetWidth == 0){
+ return;
+ }
+
+ // Save the dimensions to be used when a child is renamed.
+ this._dim = dim;
+
+ // Set my height to be my natural height (tall enough for one row of tab labels),
+ // and my content-box width based on margin-box width specified in dim parameter.
+ // But first reset scrollNode.height in case it was set by layoutChildren() call
+ // in a previous run of this method.
+ this.scrollNode.style.height = "auto";
+ this._contentBox = dijit.layout.marginBox2contentBox(this.domNode, {h: 0, w: dim.w});
+ this._contentBox.h = this.scrollNode.offsetHeight;
+ dojo.contentBox(this.domNode, this._contentBox);
+
+ // Show/hide the left/right/menu navigation buttons depending on whether or not they
+ // are needed.
+ var enable = this._enableBtn(this._contentBox.w);
+ this._buttons.style("display", enable ? "" : "none");
+
+ // Position and size the navigation buttons and the tablist
+ this._leftBtn.layoutAlign = "left";
+ this._rightBtn.layoutAlign = "right";
+ this._menuBtn.layoutAlign = this.isLeftToRight() ? "right" : "left";
+ dijit.layout.layoutChildren(this.domNode, this._contentBox,
+ [this._menuBtn, this._leftBtn, this._rightBtn, {domNode: this.scrollNode, layoutAlign: "client"}]);
+
+ // set proper scroll so that selected tab is visible
+ if(this._selectedTab){
+ if(this._anim && this._anim.status() == "playing"){
+ this._anim.stop();
+ }
+ var w = this.scrollNode,
+ sl = this._convertToScrollLeft(this._getScrollForSelectedTab());
+ w.scrollLeft = sl;
+ }
+
+ // Enable/disabled left right buttons depending on whether or not user can scroll to left or right
+ this._setButtonClass(this._getScroll());
+
+ this._postResize = true;
+
+ // Return my size so layoutChildren() can use it.
+ // Also avoids IE9 layout glitch on browser resize when scroll buttons present
+ return {h: this._contentBox.h, w: dim.w};
+ },
+
+ _getScroll: function(){
+ // summary:
+ // Returns the current scroll of the tabs where 0 means
+ // "scrolled all the way to the left" and some positive number, based on #
+ // of pixels of possible scroll (ex: 1000) means "scrolled all the way to the right"
+ var sl = (this.isLeftToRight() || dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.isWebKit) ? this.scrollNode.scrollLeft :
+ dojo.style(this.containerNode, "width") - dojo.style(this.scrollNode, "width")
+ + (dojo.isIE == 8 ? -1 : 1) * this.scrollNode.scrollLeft;
+ return sl;
+ },
+
+ _convertToScrollLeft: function(val){
+ // summary:
+ // Given a scroll value where 0 means "scrolled all the way to the left"
+ // and some positive number, based on # of pixels of possible scroll (ex: 1000)
+ // means "scrolled all the way to the right", return value to set this.scrollNode.scrollLeft
+ // to achieve that scroll.
+ //
+ // This method is to adjust for RTL funniness in various browsers and versions.
+ if(this.isLeftToRight() || dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.isWebKit){
+ return val;
+ }else{
+ var maxScroll = dojo.style(this.containerNode, "width") - dojo.style(this.scrollNode, "width");
+ return (dojo.isIE == 8 ? -1 : 1) * (val - maxScroll);
+ }
+ },
+
+ onSelectChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Smoothly scrolls to a tab when it is selected.
+
+ var tab = this.pane2button[page.id];
+ if(!tab || !page){return;}
+
+ // Scroll to the selected tab, except on startup, when scrolling is handled in resize()
+ var node = tab.domNode;
+ if(this._postResize && node != this._selectedTab){
+ this._selectedTab = node;
+
+ var sl = this._getScroll();
+
+ if(sl > node.offsetLeft ||
+ sl + dojo.style(this.scrollNode, "width") <
+ node.offsetLeft + dojo.style(node, "width")){
+ this.createSmoothScroll().play();
+ }
+ }
+
+ this.inherited(arguments);
+ },
+
+ _getScrollBounds: function(){
+ // summary:
+ // Returns the minimum and maximum scroll setting to show the leftmost and rightmost
+ // tabs (respectively)
+ var children = this.getChildren(),
+ scrollNodeWidth = dojo.style(this.scrollNode, "width"), // about 500px
+ containerWidth = dojo.style(this.containerNode, "width"), // 50,000px
+ maxPossibleScroll = containerWidth - scrollNodeWidth, // scrolling until right edge of containerNode visible
+ tabsWidth = this._getTabsWidth();
+
+ if(children.length && tabsWidth > scrollNodeWidth){
+ // Scrolling should happen
+ return {
+ min: this.isLeftToRight() ? 0 : children[children.length-1].domNode.offsetLeft,
+ max: this.isLeftToRight() ?
+ (children[children.length-1].domNode.offsetLeft + dojo.style(children[children.length-1].domNode, "width")) - scrollNodeWidth :
+ maxPossibleScroll
+ };
+ }else{
+ // No scrolling needed, all tabs visible, we stay either scrolled to far left or far right (depending on dir)
+ var onlyScrollPosition = this.isLeftToRight() ? 0 : maxPossibleScroll;
+ return {
+ min: onlyScrollPosition,
+ max: onlyScrollPosition
+ };
+ }
+ },
+
+ _getScrollForSelectedTab: function(){
+ // summary:
+ // Returns the scroll value setting so that the selected tab
+ // will appear in the center
+ var w = this.scrollNode,
+ n = this._selectedTab,
+ scrollNodeWidth = dojo.style(this.scrollNode, "width"),
+ scrollBounds = this._getScrollBounds();
+
+ // TODO: scroll minimal amount (to either right or left) so that
+ // selected tab is fully visible, and just return if it's already visible?
+ var pos = (n.offsetLeft + dojo.style(n, "width")/2) - scrollNodeWidth/2;
+ pos = Math.min(Math.max(pos, scrollBounds.min), scrollBounds.max);
+
+ // TODO:
+ // If scrolling close to the left side or right side, scroll
+ // all the way to the left or right. See this._minScroll.
+ // (But need to make sure that doesn't scroll the tab out of view...)
+ return pos;
+ },
+
+ createSmoothScroll: function(x){
+ // summary:
+ // Creates a dojo._Animation object that smoothly scrolls the tab list
+ // either to a fixed horizontal pixel value, or to the selected tab.
+ // description:
+ // If an number argument is passed to the function, that horizontal
+ // pixel position is scrolled to. Otherwise the currently selected
+ // tab is scrolled to.
+ // x: Integer?
+ // An optional pixel value to scroll to, indicating distance from left.
+
+ // Calculate position to scroll to
+ if(arguments.length > 0){
+ // position specified by caller, just make sure it's within bounds
+ var scrollBounds = this._getScrollBounds();
+ x = Math.min(Math.max(x, scrollBounds.min), scrollBounds.max);
+ }else{
+ // scroll to center the current tab
+ x = this._getScrollForSelectedTab();
+ }
+
+ if(this._anim && this._anim.status() == "playing"){
+ this._anim.stop();
+ }
+
+ var self = this,
+ w = this.scrollNode,
+ anim = new dojo._Animation({
+ beforeBegin: function(){
+ if(this.curve){ delete this.curve; }
+ var oldS = w.scrollLeft,
+ newS = self._convertToScrollLeft(x);
+ anim.curve = new dojo._Line(oldS, newS);
+ },
+ onAnimate: function(val){
+ w.scrollLeft = val;
+ }
+ });
+ this._anim = anim;
+
+ // Disable/enable left/right buttons according to new scroll position
+ this._setButtonClass(x);
+
+ return anim; // dojo._Animation
+ },
+
+ _getBtnNode: function(/*Event*/ e){
+ // summary:
+ // Gets a button DOM node from a mouse click event.
+ // e:
+ // The mouse click event.
+ var n = e.target;
+ while(n && !dojo.hasClass(n, "tabStripButton")){
+ n = n.parentNode;
+ }
+ return n;
+ },
+
+ doSlideRight: function(/*Event*/ e){
+ // summary:
+ // Scrolls the menu to the right.
+ // e:
+ // The mouse click event.
+ this.doSlide(1, this._getBtnNode(e));
+ },
+
+ doSlideLeft: function(/*Event*/ e){
+ // summary:
+ // Scrolls the menu to the left.
+ // e:
+ // The mouse click event.
+ this.doSlide(-1,this._getBtnNode(e));
+ },
+
+ doSlide: function(/*Number*/ direction, /*DomNode*/ node){
+ // summary:
+ // Scrolls the tab list to the left or right by 75% of the widget width.
+ // direction:
+ // If the direction is 1, the widget scrolls to the right, if it is
+ // -1, it scrolls to the left.
+
+ if(node && dojo.hasClass(node, "dijitTabDisabled")){return;}
+
+ var sWidth = dojo.style(this.scrollNode, "width");
+ var d = (sWidth * 0.75) * direction;
+
+ var to = this._getScroll() + d;
+
+ this._setButtonClass(to);
+
+ this.createSmoothScroll(to).play();
+ },
+
+ _setButtonClass: function(/*Number*/ scroll){
+ // summary:
+ // Disables the left scroll button if the tabs are scrolled all the way to the left,
+ // or the right scroll button in the opposite case.
+ // scroll: Integer
+ // amount of horizontal scroll
+
+ var scrollBounds = this._getScrollBounds();
+ this._leftBtn.set("disabled", scroll <= scrollBounds.min);
+ this._rightBtn.set("disabled", scroll >= scrollBounds.max);
+ }
+});
+
+
+dojo.declare("dijit.layout._ScrollingTabControllerButtonMixin", null, {
+ baseClass: "dijitTab tabStripButton",
+
+ templateString: dojo.cache("dijit.layout", "templates/_ScrollingTabControllerButton.html", "<div dojoAttachEvent=\"onclick:_onButtonClick\">\n\t<div role=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\n\t\t<div role=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\n\t\t\t<img role=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>\n"),
+
+ // Override inherited tabIndex: 0 from dijit.form.Button, because user shouldn't be
+ // able to tab to the left/right/menu buttons
+ tabIndex: "",
+
+ // Similarly, override FormWidget.isFocusable() because clicking a button shouldn't focus it
+ // either (this override avoids focus() call in FormWidget.js)
+ isFocusable: function(){ return false; }
+});
+
+dojo.declare("dijit.layout._ScrollingTabControllerButton",
+ [dijit.form.Button, dijit.layout._ScrollingTabControllerButtonMixin]);
+
+dojo.declare(
+ "dijit.layout._ScrollingTabControllerMenuButton",
+ [dijit.form.Button, dijit._HasDropDown, dijit.layout._ScrollingTabControllerButtonMixin],
+{
+ // id of the TabContainer itself
+ containerId: "",
+
+ // -1 so user can't tab into the button, but so that button can still be focused programatically.
+ // Because need to move focus to the button (or somewhere) before the menu is hidden or IE6 will crash.
+ tabIndex: "-1",
+
+ isLoaded: function(){
+ // recreate menu every time, in case the TabContainer's list of children (or their icons/labels) have changed
+ return false;
+ },
+
+ loadDropDown: function(callback){
+ this.dropDown = new dijit.Menu({
+ id: this.containerId + "_menu",
+ dir: this.dir,
+ lang: this.lang
+ });
+ var container = dijit.byId(this.containerId);
+ dojo.forEach(container.getChildren(), function(page){
+ var menuItem = new dijit.MenuItem({
+ id: page.id + "_stcMi",
+ label: page.title,
+ iconClass: page.iconClass,
+ dir: page.dir,
+ lang: page.lang,
+ onClick: function(){
+ container.selectChild(page);
+ }
+ });
+ this.dropDown.addChild(menuItem);
+ }, this);
+ callback();
+ },
+
+ closeDropDown: function(/*Boolean*/ focus){
+ this.inherited(arguments);
+ if(this.dropDown){
+ this.dropDown.destroyRecursive();
+ delete this.dropDown;
+ }
+ }
+});
+
}
diff --git a/lib/dijit/layout/SplitContainer.js b/lib/dijit/layout/SplitContainer.js
index b0db3e465..cb18273e4 100644
--- a/lib/dijit/layout/SplitContainer.js
+++ b/lib/dijit/layout/SplitContainer.js
@@ -1,348 +1,589 @@
/*
- 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.SplitContainer"]){
-dojo._hasResource["dijit.layout.SplitContainer"]=true;
+if(!dojo._hasResource["dijit.layout.SplitContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.SplitContainer"] = true;
dojo.provide("dijit.layout.SplitContainer");
dojo.require("dojo.cookie");
dojo.require("dijit.layout._LayoutWidget");
-dojo.declare("dijit.layout.SplitContainer",dijit.layout._LayoutWidget,{constructor:function(){
-dojo.deprecated("dijit.layout.SplitContainer is deprecated","use BorderContainer with splitter instead",2);
-},activeSizing:false,sizerWidth:7,orientation:"horizontal",persist:true,baseClass:"dijitSplitContainer",postMixInProperties:function(){
-this.inherited("postMixInProperties",arguments);
-this.isHorizontal=(this.orientation=="horizontal");
-},postCreate:function(){
-this.inherited(arguments);
-this.sizers=[];
-if(dojo.isMozilla){
-this.domNode.style.overflow="-moz-scrollbars-none";
-}
-if(typeof this.sizerWidth=="object"){
-try{
-this.sizerWidth=parseInt(this.sizerWidth.toString());
-}
-catch(e){
-this.sizerWidth=7;
-}
-}
-var _1=dojo.doc.createElement("div");
-this.virtualSizer=_1;
-_1.style.position="relative";
-_1.style.zIndex=10;
-_1.className=this.isHorizontal?"dijitSplitContainerVirtualSizerH":"dijitSplitContainerVirtualSizerV";
-this.domNode.appendChild(_1);
-dojo.setSelectable(_1,false);
-},destroy:function(){
-delete this.virtualSizer;
-dojo.forEach(this._ownconnects,dojo.disconnect);
-this.inherited(arguments);
-},startup:function(){
-if(this._started){
-return;
-}
-dojo.forEach(this.getChildren(),function(_2,i,_3){
-this._setupChild(_2);
-if(i<_3.length-1){
-this._addSizer();
-}
-},this);
-if(this.persist){
-this._restoreState();
-}
-this.inherited(arguments);
-},_setupChild:function(_4){
-this.inherited(arguments);
-_4.domNode.style.position="absolute";
-dojo.addClass(_4.domNode,"dijitSplitPane");
-},_onSizerMouseDown:function(e){
-if(e.target.id){
-for(var i=0;i<this.sizers.length;i++){
-if(this.sizers[i].id==e.target.id){
-break;
-}
-}
-if(i<this.sizers.length){
-this.beginSizing(e,i);
-}
-}
-},_addSizer:function(_5){
-_5=_5===undefined?this.sizers.length:_5;
-var _6=dojo.doc.createElement("div");
-_6.id=dijit.getUniqueId("dijit_layout_SplitterContainer_Splitter");
-this.sizers.splice(_5,0,_6);
-this.domNode.appendChild(_6);
-_6.className=this.isHorizontal?"dijitSplitContainerSizerH":"dijitSplitContainerSizerV";
-var _7=dojo.doc.createElement("div");
-_7.className="thumb";
-_6.appendChild(_7);
-this.connect(_6,"onmousedown","_onSizerMouseDown");
-dojo.setSelectable(_6,false);
-},removeChild:function(_8){
-if(this.sizers.length){
-var i=dojo.indexOf(this.getChildren(),_8);
-if(i!=-1){
-if(i==this.sizers.length){
-i--;
-}
-dojo.destroy(this.sizers[i]);
-this.sizers.splice(i,1);
-}
-}
-this.inherited(arguments);
-if(this._started){
-this.layout();
-}
-},addChild:function(_9,_a){
-this.inherited(arguments);
-if(this._started){
-var _b=this.getChildren();
-if(_b.length>1){
-this._addSizer(_a);
-}
-this.layout();
-}
-},layout:function(){
-this.paneWidth=this._contentBox.w;
-this.paneHeight=this._contentBox.h;
-var _c=this.getChildren();
-if(!_c.length){
-return;
-}
-var _d=this.isHorizontal?this.paneWidth:this.paneHeight;
-if(_c.length>1){
-_d-=this.sizerWidth*(_c.length-1);
-}
-var _e=0;
-dojo.forEach(_c,function(_f){
-_e+=_f.sizeShare;
-});
-var _10=_d/_e;
-var _11=0;
-dojo.forEach(_c.slice(0,_c.length-1),function(_12){
-var _13=Math.round(_10*_12.sizeShare);
-_12.sizeActual=_13;
-_11+=_13;
-});
-_c[_c.length-1].sizeActual=_d-_11;
-this._checkSizes();
-var pos=0;
-var _14=_c[0].sizeActual;
-this._movePanel(_c[0],pos,_14);
-_c[0].position=pos;
-pos+=_14;
-if(!this.sizers){
-return;
-}
-dojo.some(_c.slice(1),function(_15,i){
-if(!this.sizers[i]){
-return true;
-}
-this._moveSlider(this.sizers[i],pos,this.sizerWidth);
-this.sizers[i].position=pos;
-pos+=this.sizerWidth;
-_14=_15.sizeActual;
-this._movePanel(_15,pos,_14);
-_15.position=pos;
-pos+=_14;
-},this);
-},_movePanel:function(_16,pos,_17){
-if(this.isHorizontal){
-_16.domNode.style.left=pos+"px";
-_16.domNode.style.top=0;
-var box={w:_17,h:this.paneHeight};
-if(_16.resize){
-_16.resize(box);
-}else{
-dojo.marginBox(_16.domNode,box);
-}
-}else{
-_16.domNode.style.left=0;
-_16.domNode.style.top=pos+"px";
-var box={w:this.paneWidth,h:_17};
-if(_16.resize){
-_16.resize(box);
-}else{
-dojo.marginBox(_16.domNode,box);
-}
-}
-},_moveSlider:function(_18,pos,_19){
-if(this.isHorizontal){
-_18.style.left=pos+"px";
-_18.style.top=0;
-dojo.marginBox(_18,{w:_19,h:this.paneHeight});
-}else{
-_18.style.left=0;
-_18.style.top=pos+"px";
-dojo.marginBox(_18,{w:this.paneWidth,h:_19});
-}
-},_growPane:function(_1a,_1b){
-if(_1a>0){
-if(_1b.sizeActual>_1b.sizeMin){
-if((_1b.sizeActual-_1b.sizeMin)>_1a){
-_1b.sizeActual=_1b.sizeActual-_1a;
-_1a=0;
-}else{
-_1a-=_1b.sizeActual-_1b.sizeMin;
-_1b.sizeActual=_1b.sizeMin;
-}
-}
-}
-return _1a;
-},_checkSizes:function(){
-var _1c=0;
-var _1d=0;
-var _1e=this.getChildren();
-dojo.forEach(_1e,function(_1f){
-_1d+=_1f.sizeActual;
-_1c+=_1f.sizeMin;
-});
-if(_1c<=_1d){
-var _20=0;
-dojo.forEach(_1e,function(_21){
-if(_21.sizeActual<_21.sizeMin){
-_20+=_21.sizeMin-_21.sizeActual;
-_21.sizeActual=_21.sizeMin;
-}
-});
-if(_20>0){
-var _22=this.isDraggingLeft?_1e.reverse():_1e;
-dojo.forEach(_22,function(_23){
-_20=this._growPane(_20,_23);
-},this);
-}
-}else{
-dojo.forEach(_1e,function(_24){
-_24.sizeActual=Math.round(_1d*(_24.sizeMin/_1c));
+
+
+//
+// FIXME: make it prettier
+// FIXME: active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
+//
+
+
+dojo.declare("dijit.layout.SplitContainer",
+ dijit.layout._LayoutWidget,
+ {
+ // summary:
+ // Deprecated. Use `dijit.layout.BorderContainer` instead.
+ // description:
+ // A Container widget with sizing handles in-between each child.
+ // Contains multiple children widgets, all of which are displayed side by side
+ // (either horizontally or vertically); there's a bar between each of the children,
+ // and you can adjust the relative size of each child by dragging the bars.
+ //
+ // You must specify a size (width and height) for the SplitContainer.
+ // tags:
+ // deprecated
+
+ constructor: function(){
+ dojo.deprecated("dijit.layout.SplitContainer is deprecated", "use BorderContainer with splitter instead", 2.0);
+ },
+
+ // activeSizing: Boolean
+ // If true, the children's size changes as you drag the bar;
+ // otherwise, the sizes don't change until you drop the bar (by mouse-up)
+ activeSizing: false,
+
+ // sizerWidth: Integer
+ // Size in pixels of the bar between each child
+ sizerWidth: 7, // FIXME: this should be a CSS attribute (at 7 because css wants it to be 7 until we fix to css)
+
+ // orientation: String
+ // either 'horizontal' or vertical; indicates whether the children are
+ // arranged side-by-side or up/down.
+ orientation: 'horizontal',
+
+ // persist: Boolean
+ // Save splitter positions in a cookie
+ persist: true,
+
+ baseClass: "dijitSplitContainer",
+
+ postMixInProperties: function(){
+ this.inherited("postMixInProperties",arguments);
+ this.isHorizontal = (this.orientation == 'horizontal');
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.sizers = [];
+
+ // overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
+ // to keep other combined css classes from inadvertantly making the overflow visible
+ if(dojo.isMozilla){
+ this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work
+ }
+
+ // create the fake dragger
+ if(typeof this.sizerWidth == "object"){
+ try{ //FIXME: do this without a try/catch
+ this.sizerWidth = parseInt(this.sizerWidth.toString());
+ }catch(e){ this.sizerWidth = 7; }
+ }
+ var sizer = dojo.doc.createElement('div');
+ this.virtualSizer = sizer;
+ sizer.style.position = 'relative';
+
+ // #1681: work around the dreaded 'quirky percentages in IE' layout bug
+ // If the splitcontainer's dimensions are specified in percentages, it
+ // will be resized when the virtualsizer is displayed in _showSizingLine
+ // (typically expanding its bounds unnecessarily). This happens because
+ // we use position: relative for .dijitSplitContainer.
+ // The workaround: instead of changing the display style attribute,
+ // switch to changing the zIndex (bring to front/move to back)
+
+ sizer.style.zIndex = 10;
+ sizer.className = this.isHorizontal ? 'dijitSplitContainerVirtualSizerH' : 'dijitSplitContainerVirtualSizerV';
+ this.domNode.appendChild(sizer);
+ dojo.setSelectable(sizer, false);
+ },
+
+ destroy: function(){
+ delete this.virtualSizer;
+ dojo.forEach(this._ownconnects, dojo.disconnect);
+ this.inherited(arguments);
+ },
+ startup: function(){
+ if(this._started){ return; }
+
+ dojo.forEach(this.getChildren(), function(child, i, children){
+ // attach the children and create the draggers
+ this._setupChild(child);
+
+ if(i < children.length-1){
+ this._addSizer();
+ }
+ }, this);
+
+ if(this.persist){
+ this._restoreState();
+ }
+
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*dijit._Widget*/ child){
+ this.inherited(arguments);
+ child.domNode.style.position = "absolute";
+ dojo.addClass(child.domNode, "dijitSplitPane");
+ },
+
+ _onSizerMouseDown: function(e){
+ if(e.target.id){
+ for(var i=0;i<this.sizers.length;i++){
+ if(this.sizers[i].id == e.target.id){
+ break;
+ }
+ }
+ if(i<this.sizers.length){
+ this.beginSizing(e,i);
+ }
+ }
+ },
+ _addSizer: function(index){
+ index = index === undefined ? this.sizers.length : index;
+
+ // TODO: use a template for this!!!
+ var sizer = dojo.doc.createElement('div');
+ sizer.id=dijit.getUniqueId('dijit_layout_SplitterContainer_Splitter');
+ this.sizers.splice(index,0,sizer);
+ this.domNode.appendChild(sizer);
+
+ sizer.className = this.isHorizontal ? 'dijitSplitContainerSizerH' : 'dijitSplitContainerSizerV';
+
+ // add the thumb div
+ var thumb = dojo.doc.createElement('div');
+ thumb.className = 'thumb';
+ sizer.appendChild(thumb);
+
+ // FIXME: are you serious? why aren't we using mover start/stop combo?
+ this.connect(sizer, "onmousedown", '_onSizerMouseDown');
+
+ dojo.setSelectable(sizer, false);
+ },
+
+ removeChild: function(widget){
+ // summary:
+ // Remove sizer, but only if widget is really our child and
+ // we have at least one sizer to throw away
+ if(this.sizers.length){
+ var i=dojo.indexOf(this.getChildren(), widget)
+ if(i != -1){
+ if(i == this.sizers.length){
+ i--;
+ }
+ dojo.destroy(this.sizers[i]);
+ this.sizers.splice(i,1);
+ }
+ }
+
+ // Remove widget and repaint
+ this.inherited(arguments);
+ if(this._started){
+ this.layout();
+ }
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // summary:
+ // Add a child widget to the container
+ // child:
+ // a widget to add
+ // insertIndex:
+ // postion in the "stack" to add the child widget
+
+ this.inherited(arguments);
+
+ if(this._started){
+ // Do the stuff that startup() does for each widget
+ var children = this.getChildren();
+ if(children.length > 1){
+ this._addSizer(insertIndex);
+ }
+
+ // and then reposition (ie, shrink) every pane to make room for the new guy
+ this.layout();
+ }
+ },
+
+ layout: function(){
+ // summary:
+ // Do layout of panels
+
+ // base class defines this._contentBox on initial creation and also
+ // on resize
+ this.paneWidth = this._contentBox.w;
+ this.paneHeight = this._contentBox.h;
+
+ var children = this.getChildren();
+ if(!children.length){ return; }
+
+ //
+ // calculate space
+ //
+
+ var space = this.isHorizontal ? this.paneWidth : this.paneHeight;
+ if(children.length > 1){
+ space -= this.sizerWidth * (children.length - 1);
+ }
+
+ //
+ // calculate total of SizeShare values
+ //
+ var outOf = 0;
+ dojo.forEach(children, function(child){
+ outOf += child.sizeShare;
+ });
+
+ //
+ // work out actual pixels per sizeshare unit
+ //
+ var pixPerUnit = space / outOf;
+
+ //
+ // set the SizeActual member of each pane
+ //
+ var totalSize = 0;
+ dojo.forEach(children.slice(0, children.length - 1), function(child){
+ var size = Math.round(pixPerUnit * child.sizeShare);
+ child.sizeActual = size;
+ totalSize += size;
+ });
+
+ children[children.length-1].sizeActual = space - totalSize;
+
+ //
+ // make sure the sizes are ok
+ //
+ this._checkSizes();
+
+ //
+ // now loop, positioning each pane and letting children resize themselves
+ //
+
+ var pos = 0;
+ var size = children[0].sizeActual;
+ this._movePanel(children[0], pos, size);
+ children[0].position = pos;
+ pos += size;
+
+ // if we don't have any sizers, our layout method hasn't been called yet
+ // so bail until we are called..TODO: REVISIT: need to change the startup
+ // algorithm to guaranteed the ordering of calls to layout method
+ if(!this.sizers){
+ return;
+ }
+
+ dojo.some(children.slice(1), function(child, i){
+ // error-checking
+ if(!this.sizers[i]){
+ return true;
+ }
+ // first we position the sizing handle before this pane
+ this._moveSlider(this.sizers[i], pos, this.sizerWidth);
+ this.sizers[i].position = pos;
+ pos += this.sizerWidth;
+
+ size = child.sizeActual;
+ this._movePanel(child, pos, size);
+ child.position = pos;
+ pos += size;
+ }, this);
+ },
+
+ _movePanel: function(panel, pos, size){
+ if(this.isHorizontal){
+ panel.domNode.style.left = pos + 'px'; // TODO: resize() takes l and t parameters too, don't need to set manually
+ panel.domNode.style.top = 0;
+ var box = {w: size, h: this.paneHeight};
+ if(panel.resize){
+ panel.resize(box);
+ }else{
+ dojo.marginBox(panel.domNode, box);
+ }
+ }else{
+ panel.domNode.style.left = 0; // TODO: resize() takes l and t parameters too, don't need to set manually
+ panel.domNode.style.top = pos + 'px';
+ var box = {w: this.paneWidth, h: size};
+ if(panel.resize){
+ panel.resize(box);
+ }else{
+ dojo.marginBox(panel.domNode, box);
+ }
+ }
+ },
+
+ _moveSlider: function(slider, pos, size){
+ if(this.isHorizontal){
+ slider.style.left = pos + 'px';
+ slider.style.top = 0;
+ dojo.marginBox(slider, { w: size, h: this.paneHeight });
+ }else{
+ slider.style.left = 0;
+ slider.style.top = pos + 'px';
+ dojo.marginBox(slider, { w: this.paneWidth, h: size });
+ }
+ },
+
+ _growPane: function(growth, pane){
+ if(growth > 0){
+ if(pane.sizeActual > pane.sizeMin){
+ if((pane.sizeActual - pane.sizeMin) > growth){
+
+ // stick all the growth in this pane
+ pane.sizeActual = pane.sizeActual - growth;
+ growth = 0;
+ }else{
+ // put as much growth in here as we can
+ growth -= pane.sizeActual - pane.sizeMin;
+ pane.sizeActual = pane.sizeMin;
+ }
+ }
+ }
+ return growth;
+ },
+
+ _checkSizes: function(){
+
+ var totalMinSize = 0;
+ var totalSize = 0;
+ var children = this.getChildren();
+
+ dojo.forEach(children, function(child){
+ totalSize += child.sizeActual;
+ totalMinSize += child.sizeMin;
+ });
+
+ // only make adjustments if we have enough space for all the minimums
+
+ if(totalMinSize <= totalSize){
+
+ var growth = 0;
+
+ dojo.forEach(children, function(child){
+ if(child.sizeActual < child.sizeMin){
+ growth += child.sizeMin - child.sizeActual;
+ child.sizeActual = child.sizeMin;
+ }
+ });
+
+ if(growth > 0){
+ var list = this.isDraggingLeft ? children.reverse() : children;
+ dojo.forEach(list, function(child){
+ growth = this._growPane(growth, child);
+ }, this);
+ }
+ }else{
+ dojo.forEach(children, function(child){
+ child.sizeActual = Math.round(totalSize * (child.sizeMin / totalMinSize));
+ });
+ }
+ },
+
+ beginSizing: function(e, i){
+ var children = this.getChildren();
+ this.paneBefore = children[i];
+ this.paneAfter = children[i+1];
+
+ this.isSizing = true;
+ this.sizingSplitter = this.sizers[i];
+
+ if(!this.cover){
+ this.cover = dojo.create('div', {
+ style: {
+ position:'absolute',
+ zIndex:5,
+ top: 0,
+ left: 0,
+ width: "100%",
+ height: "100%"
+ }
+ }, this.domNode);
+ }else{
+ this.cover.style.zIndex = 5;
+ }
+ this.sizingSplitter.style.zIndex = 6;
+
+ // TODO: REVISIT - we want MARGIN_BOX and core hasn't exposed that yet (but can't we use it anyway if we pay attention? we do elsewhere.)
+ this.originPos = dojo.position(children[0].domNode, true);
+ if(this.isHorizontal){
+ var client = e.layerX || e.offsetX || 0;
+ var screen = e.pageX;
+ this.originPos = this.originPos.x;
+ }else{
+ var client = e.layerY || e.offsetY || 0;
+ var screen = e.pageY;
+ this.originPos = this.originPos.y;
+ }
+ this.startPoint = this.lastPoint = screen;
+ this.screenToClientOffset = screen - client;
+ this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position;
+
+ if(!this.activeSizing){
+ this._showSizingLine();
+ }
+
+ //
+ // attach mouse events
+ //
+ this._ownconnects = [];
+ this._ownconnects.push(dojo.connect(dojo.doc.documentElement, "onmousemove", this, "changeSizing"));
+ this._ownconnects.push(dojo.connect(dojo.doc.documentElement, "onmouseup", this, "endSizing"));
+
+ dojo.stopEvent(e);
+ },
+
+ changeSizing: function(e){
+ if(!this.isSizing){ return; }
+ this.lastPoint = this.isHorizontal ? e.pageX : e.pageY;
+ this.movePoint();
+ if(this.activeSizing){
+ this._updateSize();
+ }else{
+ this._moveSizingLine();
+ }
+ dojo.stopEvent(e);
+ },
+
+ endSizing: function(e){
+ if(!this.isSizing){ return; }
+ if(this.cover){
+ this.cover.style.zIndex = -1;
+ }
+ if(!this.activeSizing){
+ this._hideSizingLine();
+ }
+
+ this._updateSize();
+
+ this.isSizing = false;
+
+ if(this.persist){
+ this._saveState(this);
+ }
+
+ dojo.forEach(this._ownconnects, dojo.disconnect);
+ },
+
+ movePoint: function(){
+
+ // make sure lastPoint is a legal point to drag to
+ var p = this.lastPoint - this.screenToClientOffset;
+
+ var a = p - this.dragOffset;
+ a = this.legaliseSplitPoint(a);
+ p = a + this.dragOffset;
+
+ this.lastPoint = p + this.screenToClientOffset;
+ },
+
+ legaliseSplitPoint: function(a){
+
+ a += this.sizingSplitter.position;
+
+ this.isDraggingLeft = !!(a > 0);
+
+ if(!this.activeSizing){
+ var min = this.paneBefore.position + this.paneBefore.sizeMin;
+ if(a < min){
+ a = min;
+ }
+
+ var max = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin));
+ if(a > max){
+ a = max;
+ }
+ }
+
+ a -= this.sizingSplitter.position;
+
+ this._checkSizes();
+
+ return a;
+ },
+
+ _updateSize: function(){
+ //FIXME: sometimes this.lastPoint is NaN
+ var pos = this.lastPoint - this.dragOffset - this.originPos;
+
+ var start_region = this.paneBefore.position;
+ var end_region = this.paneAfter.position + this.paneAfter.sizeActual;
+
+ this.paneBefore.sizeActual = pos - start_region;
+ this.paneAfter.position = pos + this.sizerWidth;
+ this.paneAfter.sizeActual = end_region - this.paneAfter.position;
+
+ dojo.forEach(this.getChildren(), function(child){
+ child.sizeShare = child.sizeActual;
+ });
+
+ if(this._started){
+ this.layout();
+ }
+ },
+
+ _showSizingLine: function(){
+
+ this._moveSizingLine();
+
+ dojo.marginBox(this.virtualSizer,
+ this.isHorizontal ? { w: this.sizerWidth, h: this.paneHeight } : { w: this.paneWidth, h: this.sizerWidth });
+
+ this.virtualSizer.style.display = 'block';
+ },
+
+ _hideSizingLine: function(){
+ this.virtualSizer.style.display = 'none';
+ },
+
+ _moveSizingLine: function(){
+ var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position;
+ dojo.style(this.virtualSizer,(this.isHorizontal ? "left" : "top"),pos+"px");
+ // this.virtualSizer.style[ this.isHorizontal ? "left" : "top" ] = pos + 'px'; // FIXME: remove this line if the previous is better
+ },
+
+ _getCookieName: function(i){
+ return this.id + "_" + i;
+ },
+
+ _restoreState: function(){
+ dojo.forEach(this.getChildren(), function(child, i){
+ var cookieName = this._getCookieName(i);
+ var cookieValue = dojo.cookie(cookieName);
+ if(cookieValue){
+ var pos = parseInt(cookieValue);
+ if(typeof pos == "number"){
+ child.sizeShare = pos;
+ }
+ }
+ }, this);
+ },
+
+ _saveState: function(){
+ if(!this.persist){
+ return;
+ }
+ dojo.forEach(this.getChildren(), function(child, i){
+ dojo.cookie(this._getCookieName(i), child.sizeShare, {expires:365});
+ }, this);
+ }
});
-}
-},beginSizing:function(e,i){
-var _25=this.getChildren();
-this.paneBefore=_25[i];
-this.paneAfter=_25[i+1];
-this.isSizing=true;
-this.sizingSplitter=this.sizers[i];
-if(!this.cover){
-this.cover=dojo.create("div",{style:{position:"absolute",zIndex:5,top:0,left:0,width:"100%",height:"100%"}},this.domNode);
-}else{
-this.cover.style.zIndex=5;
-}
-this.sizingSplitter.style.zIndex=6;
-this.originPos=dojo.position(_25[0].domNode,true);
-if(this.isHorizontal){
-var _26=e.layerX||e.offsetX||0;
-var _27=e.pageX;
-this.originPos=this.originPos.x;
-}else{
-var _26=e.layerY||e.offsetY||0;
-var _27=e.pageY;
-this.originPos=this.originPos.y;
-}
-this.startPoint=this.lastPoint=_27;
-this.screenToClientOffset=_27-_26;
-this.dragOffset=this.lastPoint-this.paneBefore.sizeActual-this.originPos-this.paneBefore.position;
-if(!this.activeSizing){
-this._showSizingLine();
-}
-this._ownconnects=[];
-this._ownconnects.push(dojo.connect(dojo.doc.documentElement,"onmousemove",this,"changeSizing"));
-this._ownconnects.push(dojo.connect(dojo.doc.documentElement,"onmouseup",this,"endSizing"));
-dojo.stopEvent(e);
-},changeSizing:function(e){
-if(!this.isSizing){
-return;
-}
-this.lastPoint=this.isHorizontal?e.pageX:e.pageY;
-this.movePoint();
-if(this.activeSizing){
-this._updateSize();
-}else{
-this._moveSizingLine();
-}
-dojo.stopEvent(e);
-},endSizing:function(e){
-if(!this.isSizing){
-return;
-}
-if(this.cover){
-this.cover.style.zIndex=-1;
-}
-if(!this.activeSizing){
-this._hideSizingLine();
-}
-this._updateSize();
-this.isSizing=false;
-if(this.persist){
-this._saveState(this);
-}
-dojo.forEach(this._ownconnects,dojo.disconnect);
-},movePoint:function(){
-var p=this.lastPoint-this.screenToClientOffset;
-var a=p-this.dragOffset;
-a=this.legaliseSplitPoint(a);
-p=a+this.dragOffset;
-this.lastPoint=p+this.screenToClientOffset;
-},legaliseSplitPoint:function(a){
-a+=this.sizingSplitter.position;
-this.isDraggingLeft=!!(a>0);
-if(!this.activeSizing){
-var min=this.paneBefore.position+this.paneBefore.sizeMin;
-if(a<min){
-a=min;
-}
-var max=this.paneAfter.position+(this.paneAfter.sizeActual-(this.sizerWidth+this.paneAfter.sizeMin));
-if(a>max){
-a=max;
-}
-}
-a-=this.sizingSplitter.position;
-this._checkSizes();
-return a;
-},_updateSize:function(){
-var pos=this.lastPoint-this.dragOffset-this.originPos;
-var _28=this.paneBefore.position;
-var _29=this.paneAfter.position+this.paneAfter.sizeActual;
-this.paneBefore.sizeActual=pos-_28;
-this.paneAfter.position=pos+this.sizerWidth;
-this.paneAfter.sizeActual=_29-this.paneAfter.position;
-dojo.forEach(this.getChildren(),function(_2a){
-_2a.sizeShare=_2a.sizeActual;
+
+// These arguments can be specified for the children of a SplitContainer.
+// Since any widget can be specified as a SplitContainer child, mix them
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget, {
+ // sizeMin: [deprecated] Integer
+ // Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
+ // Minimum size (width or height) of a child of a SplitContainer.
+ // The value is relative to other children's sizeShare properties.
+ sizeMin: 10,
+
+ // sizeShare: [deprecated] Integer
+ // Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
+ // Size (width or height) of a child of a SplitContainer.
+ // The value is relative to other children's sizeShare properties.
+ // For example, if there are two children and each has sizeShare=10, then
+ // each takes up 50% of the available space.
+ sizeShare: 10
});
-if(this._started){
-this.layout();
-}
-},_showSizingLine:function(){
-this._moveSizingLine();
-dojo.marginBox(this.virtualSizer,this.isHorizontal?{w:this.sizerWidth,h:this.paneHeight}:{w:this.paneWidth,h:this.sizerWidth});
-this.virtualSizer.style.display="block";
-},_hideSizingLine:function(){
-this.virtualSizer.style.display="none";
-},_moveSizingLine:function(){
-var pos=(this.lastPoint-this.startPoint)+this.sizingSplitter.position;
-dojo.style(this.virtualSizer,(this.isHorizontal?"left":"top"),pos+"px");
-},_getCookieName:function(i){
-return this.id+"_"+i;
-},_restoreState:function(){
-dojo.forEach(this.getChildren(),function(_2b,i){
-var _2c=this._getCookieName(i);
-var _2d=dojo.cookie(_2c);
-if(_2d){
-var pos=parseInt(_2d);
-if(typeof pos=="number"){
-_2b.sizeShare=pos;
-}
-}
-},this);
-},_saveState:function(){
-if(!this.persist){
-return;
-}
-dojo.forEach(this.getChildren(),function(_2e,i){
-dojo.cookie(this._getCookieName(i),_2e.sizeShare,{expires:365});
-},this);
-}});
-dojo.extend(dijit._Widget,{sizeMin:10,sizeShare:10});
+
}
diff --git a/lib/dijit/layout/StackContainer.js b/lib/dijit/layout/StackContainer.js
index 78a49021d..98af4c942 100644
--- a/lib/dijit/layout/StackContainer.js
+++ b/lib/dijit/layout/StackContainer.js
@@ -1,148 +1,336 @@
/*
- 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.StackContainer"]){
-dojo._hasResource["dijit.layout.StackContainer"]=true;
+if(!dojo._hasResource["dijit.layout.StackContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.StackContainer"] = true;
dojo.provide("dijit.layout.StackContainer");
dojo.require("dijit._Templated");
dojo.require("dijit.layout._LayoutWidget");
-dojo.requireLocalization("dijit","common",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.requireLocalization("dijit", "common", 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.require("dojo.cookie");
-dojo.declare("dijit.layout.StackContainer",dijit.layout._LayoutWidget,{doLayout:true,persist:false,baseClass:"dijitStackContainer",postCreate:function(){
-this.inherited(arguments);
-dojo.addClass(this.domNode,"dijitLayoutContainer");
-dijit.setWaiRole(this.containerNode,"tabpanel");
-this.connect(this.domNode,"onkeypress",this._onKeyPress);
-},startup:function(){
-if(this._started){
-return;
-}
-var _1=this.getChildren();
-dojo.forEach(_1,this._setupChild,this);
-if(this.persist){
-this.selectedChildWidget=dijit.byId(dojo.cookie(this.id+"_selectedChild"));
-}else{
-dojo.some(_1,function(_2){
-if(_2.selected){
-this.selectedChildWidget=_2;
-}
-return _2.selected;
-},this);
-}
-var _3=this.selectedChildWidget;
-if(!_3&&_1[0]){
-_3=this.selectedChildWidget=_1[0];
-_3.selected=true;
-}
-dojo.publish(this.id+"-startup",[{children:_1,selected:_3}]);
-this.inherited(arguments);
-},resize:function(){
-var _4=this.selectedChildWidget;
-if(_4&&!this._hasBeenShown){
-this._hasBeenShown=true;
-this._showChild(_4);
-}
-this.inherited(arguments);
-},_setupChild:function(_5){
-this.inherited(arguments);
-dojo.removeClass(_5.domNode,"dijitVisible");
-dojo.addClass(_5.domNode,"dijitHidden");
-_5.domNode.title="";
-},addChild:function(_6,_7){
-this.inherited(arguments);
-if(this._started){
-dojo.publish(this.id+"-addChild",[_6,_7]);
-this.layout();
-if(!this.selectedChildWidget){
-this.selectChild(_6);
-}
-}
-},removeChild:function(_8){
-this.inherited(arguments);
-if(this._started){
-dojo.publish(this.id+"-removeChild",[_8]);
-}
-if(this._beingDestroyed){
-return;
-}
-if(this.selectedChildWidget===_8){
-this.selectedChildWidget=undefined;
-if(this._started){
-var _9=this.getChildren();
-if(_9.length){
-this.selectChild(_9[0]);
-}
-}
-}
-if(this._started){
-this.layout();
-}
-},selectChild:function(_a,_b){
-_a=dijit.byId(_a);
-if(this.selectedChildWidget!=_a){
-this._transition(_a,this.selectedChildWidget,_b);
-this.selectedChildWidget=_a;
-dojo.publish(this.id+"-selectChild",[_a]);
-if(this.persist){
-dojo.cookie(this.id+"_selectedChild",this.selectedChildWidget.id);
-}
-}
-},_transition:function(_c,_d){
-if(_d){
-this._hideChild(_d);
-}
-this._showChild(_c);
-if(_c.resize){
-if(this.doLayout){
-_c.resize(this._containerContentBox||this._contentBox);
-}else{
-_c.resize();
-}
-}
-},_adjacent:function(_e){
-var _f=this.getChildren();
-var _10=dojo.indexOf(_f,this.selectedChildWidget);
-_10+=_e?1:_f.length-1;
-return _f[_10%_f.length];
-},forward:function(){
-this.selectChild(this._adjacent(true),true);
-},back:function(){
-this.selectChild(this._adjacent(false),true);
-},_onKeyPress:function(e){
-dojo.publish(this.id+"-containerKeyPress",[{e:e,page:this}]);
-},layout:function(){
-if(this.doLayout&&this.selectedChildWidget&&this.selectedChildWidget.resize){
-this.selectedChildWidget.resize(this._containerContentBox||this._contentBox);
-}
-},_showChild:function(_11){
-var _12=this.getChildren();
-_11.isFirstChild=(_11==_12[0]);
-_11.isLastChild=(_11==_12[_12.length-1]);
-_11.selected=true;
-dojo.removeClass(_11.domNode,"dijitHidden");
-dojo.addClass(_11.domNode,"dijitVisible");
-_11._onShow();
-},_hideChild:function(_13){
-_13.selected=false;
-dojo.removeClass(_13.domNode,"dijitVisible");
-dojo.addClass(_13.domNode,"dijitHidden");
-_13.onHide();
-},closeChild:function(_14){
-var _15=_14.onClose(this,_14);
-if(_15){
-this.removeChild(_14);
-_14.destroyRecursive();
-}
-},destroyDescendants:function(_16){
-dojo.forEach(this.getChildren(),function(_17){
-this.removeChild(_17);
-_17.destroyRecursive(_16);
-},this);
-}});
dojo.require("dijit.layout.StackController");
-dojo.extend(dijit._Widget,{selected:false,closable:false,iconClass:"",showTitle:true});
+
+
+dojo.declare(
+ "dijit.layout.StackContainer",
+ dijit.layout._LayoutWidget,
+ {
+ // summary:
+ // A container that has multiple children, but shows only
+ // one child at a time
+ //
+ // description:
+ // A container for widgets (ContentPanes, for example) That displays
+ // only one Widget at a time.
+ //
+ // Publishes topics [widgetId]-addChild, [widgetId]-removeChild, and [widgetId]-selectChild
+ //
+ // Can be base class for container, Wizard, Show, etc.
+
+ // doLayout: Boolean
+ // If true, change the size of my currently displayed child to match my size
+ doLayout: true,
+
+ // persist: Boolean
+ // Remembers the selected child across sessions
+ persist: false,
+
+ baseClass: "dijitStackContainer",
+
+/*=====
+ // selectedChildWidget: [readonly] dijit._Widget
+ // References the currently selected child widget, if any.
+ // Adjust selected child with selectChild() method.
+ selectedChildWidget: null,
+=====*/
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.addClass(this.domNode, "dijitLayoutContainer");
+ dijit.setWaiRole(this.containerNode, "tabpanel");
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.domNode, "onkeypress", this._onKeyPress);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ var children = this.getChildren();
+
+ // Setup each page panel to be initially hidden
+ dojo.forEach(children, this._setupChild, this);
+
+ // Figure out which child to initially display, defaulting to first one
+ if(this.persist){
+ this.selectedChildWidget = dijit.byId(dojo.cookie(this.id + "_selectedChild"));
+ }else{
+ dojo.some(children, function(child){
+ if(child.selected){
+ this.selectedChildWidget = child;
+ }
+ return child.selected;
+ }, this);
+ }
+ var selected = this.selectedChildWidget;
+ if(!selected && children[0]){
+ selected = this.selectedChildWidget = children[0];
+ selected.selected = true;
+ }
+
+ // Publish information about myself so any StackControllers can initialize.
+ // This needs to happen before this.inherited(arguments) so that for
+ // TabContainer, this._contentBox doesn't include the space for the tab labels.
+ dojo.publish(this.id+"-startup", [{children: children, selected: selected}]);
+
+ // Startup each child widget, and do initial layout like setting this._contentBox,
+ // then calls this.resize() which does the initial sizing on the selected child.
+ this.inherited(arguments);
+ },
+
+ resize: function(){
+ // Resize is called when we are first made visible (it's called from startup()
+ // if we are initially visible). If this is the first time we've been made
+ // visible then show our first child.
+ var selected = this.selectedChildWidget;
+ if(selected && !this._hasBeenShown){
+ this._hasBeenShown = true;
+ this._showChild(selected);
+ }
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*dijit._Widget*/ child){
+ // Overrides _LayoutWidget._setupChild()
+
+ this.inherited(arguments);
+
+ dojo.replaceClass(child.domNode, "dijitHidden", "dijitVisible");
+
+ // remove the title attribute so it doesn't show up when i hover
+ // over a node
+ child.domNode.title = "";
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // Overrides _Container.addChild() to do layout and publish events
+
+ this.inherited(arguments);
+
+ if(this._started){
+ dojo.publish(this.id+"-addChild", [child, insertIndex]);
+
+ // in case the tab titles have overflowed from one line to two lines
+ // (or, if this if first child, from zero lines to one line)
+ // TODO: w/ScrollingTabController this is no longer necessary, although
+ // ScrollTabController.resize() does need to get called to show/hide
+ // the navigation buttons as appropriate, but that's handled in ScrollingTabController.onAddChild()
+ this.layout();
+
+ // if this is the first child, then select it
+ if(!this.selectedChildWidget){
+ this.selectChild(child);
+ }
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ page){
+ // Overrides _Container.removeChild() to do layout and publish events
+
+ this.inherited(arguments);
+
+ if(this._started){
+ // this will notify any tablists to remove a button; do this first because it may affect sizing
+ dojo.publish(this.id + "-removeChild", [page]);
+ }
+
+ // If we are being destroyed than don't run the code below (to select another page), because we are deleting
+ // every page one by one
+ if(this._beingDestroyed){ return; }
+
+ // Select new page to display, also updating TabController to show the respective tab.
+ // Do this before layout call because it can affect the height of the TabController.
+ if(this.selectedChildWidget === page){
+ this.selectedChildWidget = undefined;
+ if(this._started){
+ var children = this.getChildren();
+ if(children.length){
+ this.selectChild(children[0]);
+ }
+ }
+ }
+
+ if(this._started){
+ // In case the tab titles now take up one line instead of two lines
+ // (note though that ScrollingTabController never overflows to multiple lines),
+ // or the height has changed slightly because of addition/removal of tab which close icon
+ this.layout();
+ }
+ },
+
+ selectChild: function(/*dijit._Widget|String*/ page, /*Boolean*/ animate){
+ // summary:
+ // Show the given widget (which must be one of my children)
+ // page:
+ // Reference to child widget or id of child widget
+
+ page = dijit.byId(page);
+
+ if(this.selectedChildWidget != page){
+ // Deselect old page and select new one
+ var d = this._transition(page, this.selectedChildWidget, animate);
+ this._set("selectedChildWidget", page);
+ dojo.publish(this.id+"-selectChild", [page]);
+
+ if(this.persist){
+ dojo.cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
+ }
+ }
+
+ return d; // If child has an href, promise that fires when the child's href finishes loading
+ },
+
+ _transition: function(/*dijit._Widget*/ newWidget, /*dijit._Widget*/ oldWidget, /*Boolean*/ animate){
+ // summary:
+ // Hide the old widget and display the new widget.
+ // Subclasses should override this.
+ // tags:
+ // protected extension
+ if(oldWidget){
+ this._hideChild(oldWidget);
+ }
+ var d = this._showChild(newWidget);
+
+ // Size the new widget, in case this is the first time it's being shown,
+ // or I have been resized since the last time it was shown.
+ // Note that page must be visible for resizing to work.
+ if(newWidget.resize){
+ if(this.doLayout){
+ newWidget.resize(this._containerContentBox || this._contentBox);
+ }else{
+ // the child should pick it's own size but we still need to call resize()
+ // (with no arguments) to let the widget lay itself out
+ newWidget.resize();
+ }
+ }
+
+ return d; // If child has an href, promise that fires when the child's href finishes loading
+ },
+
+ _adjacent: function(/*Boolean*/ forward){
+ // summary:
+ // Gets the next/previous child widget in this container from the current selection.
+ var children = this.getChildren();
+ var index = dojo.indexOf(children, this.selectedChildWidget);
+ index += forward ? 1 : children.length - 1;
+ return children[ index % children.length ]; // dijit._Widget
+ },
+
+ forward: function(){
+ // summary:
+ // Advance to next page.
+ return this.selectChild(this._adjacent(true), true);
+ },
+
+ back: function(){
+ // summary:
+ // Go back to previous page.
+ return this.selectChild(this._adjacent(false), true);
+ },
+
+ _onKeyPress: function(e){
+ dojo.publish(this.id+"-containerKeyPress", [{ e: e, page: this}]);
+ },
+
+ layout: function(){
+ // Implement _LayoutWidget.layout() virtual method.
+ if(this.doLayout && this.selectedChildWidget && this.selectedChildWidget.resize){
+ this.selectedChildWidget.resize(this._containerContentBox || this._contentBox);
+ }
+ },
+
+ _showChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Show the specified child by changing it's CSS, and call _onShow()/onShow() so
+ // it can do any updates it needs regarding loading href's etc.
+ // returns:
+ // Promise that fires when page has finished showing, or true if there's no href
+ var children = this.getChildren();
+ page.isFirstChild = (page == children[0]);
+ page.isLastChild = (page == children[children.length-1]);
+ page._set("selected", true);
+
+ dojo.replaceClass(page.domNode, "dijitVisible", "dijitHidden");
+
+ return page._onShow() || true;
+ },
+
+ _hideChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Hide the specified child by changing it's CSS, and call _onHide() so
+ // it's notified.
+ page._set("selected", false);
+ dojo.replaceClass(page.domNode, "dijitHidden", "dijitVisible");
+
+ page.onHide();
+ },
+
+ closeChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Callback when user clicks the [X] to remove a page.
+ // If onClose() returns true then remove and destroy the child.
+ // tags:
+ // private
+ var remove = page.onClose(this, page);
+ if(remove){
+ this.removeChild(page);
+ // makes sure we can clean up executeScripts in ContentPane onUnLoad
+ page.destroyRecursive();
+ }
+ },
+
+ destroyDescendants: function(/*Boolean*/ preserveDom){
+ dojo.forEach(this.getChildren(), function(child){
+ this.removeChild(child);
+ child.destroyRecursive(preserveDom);
+ }, this);
+ }
+});
+
+// For back-compat, remove for 2.0
+
+
+// These arguments can be specified for the children of a StackContainer.
+// Since any widget can be specified as a StackContainer child, mix them
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget, {
+ // selected: Boolean
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // Specifies that this widget should be the initially displayed pane.
+ // Note: to change the selected child use `dijit.layout.StackContainer.selectChild`
+ selected: false,
+
+ // closable: Boolean
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
+ closable: false,
+
+ // iconClass: String
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // CSS Class specifying icon to use in label associated with this pane.
+ iconClass: "",
+
+ // showTitle: Boolean
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // When true, display title of this widget as tab label etc., rather than just using
+ // icon specified in iconClass
+ showTitle: true
+});
+
}
diff --git a/lib/dijit/layout/StackController.js b/lib/dijit/layout/StackController.js
index 033dadf6f..e0d2075bb 100644
--- a/lib/dijit/layout/StackController.js
+++ b/lib/dijit/layout/StackController.js
@@ -1,174 +1,334 @@
/*
- 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.StackController"]){
-dojo._hasResource["dijit.layout.StackController"]=true;
+if(!dojo._hasResource["dijit.layout.StackController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.StackController"] = true;
dojo.provide("dijit.layout.StackController");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit._Container");
dojo.require("dijit.form.ToggleButton");
-dojo.requireLocalization("dijit","common",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.StackController",[dijit._Widget,dijit._Templated,dijit._Container],{templateString:"<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",containerId:"",buttonWidget:"dijit.layout._StackButton",postCreate:function(){
-dijit.setWaiRole(this.domNode,"tablist");
-this.pane2button={};
-this.pane2handles={};
-this.subscribe(this.containerId+"-startup","onStartup");
-this.subscribe(this.containerId+"-addChild","onAddChild");
-this.subscribe(this.containerId+"-removeChild","onRemoveChild");
-this.subscribe(this.containerId+"-selectChild","onSelectChild");
-this.subscribe(this.containerId+"-containerKeyPress","onContainerKeyPress");
-},onStartup:function(_1){
-dojo.forEach(_1.children,this.onAddChild,this);
-if(_1.selected){
-this.onSelectChild(_1.selected);
-}
-},destroy:function(){
-for(var _2 in this.pane2button){
-this.onRemoveChild(dijit.byId(_2));
-}
-this.inherited(arguments);
-},onAddChild:function(_3,_4){
-var _5=dojo.getObject(this.buttonWidget);
-var _6=new _5({id:this.id+"_"+_3.id,label:_3.title,dir:_3.dir,lang:_3.lang,showLabel:_3.showTitle,iconClass:_3.iconClass,closeButton:_3.closable,title:_3.tooltip});
-dijit.setWaiState(_6.focusNode,"selected","false");
-this.pane2handles[_3.id]=[this.connect(_3,"set",function(_7,_8){
-var _9={title:"label",showTitle:"showLabel",iconClass:"iconClass",closable:"closeButton",tooltip:"title"}[_7];
-if(_9){
-_6.set(_9,_8);
-}
-}),this.connect(_6,"onClick",dojo.hitch(this,"onButtonClick",_3)),this.connect(_6,"onClickCloseButton",dojo.hitch(this,"onCloseButtonClick",_3))];
-this.addChild(_6,_4);
-this.pane2button[_3.id]=_6;
-_3.controlButton=_6;
-if(!this._currentChild){
-_6.focusNode.setAttribute("tabIndex","0");
-dijit.setWaiState(_6.focusNode,"selected","true");
-this._currentChild=_3;
-}
-if(!this.isLeftToRight()&&dojo.isIE&&this._rectifyRtlTabList){
-this._rectifyRtlTabList();
-}
-},onRemoveChild:function(_a){
-if(this._currentChild===_a){
-this._currentChild=null;
-}
-dojo.forEach(this.pane2handles[_a.id],this.disconnect,this);
-delete this.pane2handles[_a.id];
-var _b=this.pane2button[_a.id];
-if(_b){
-this.removeChild(_b);
-delete this.pane2button[_a.id];
-_b.destroy();
-}
-delete _a.controlButton;
-},onSelectChild:function(_c){
-if(!_c){
-return;
-}
-if(this._currentChild){
-var _d=this.pane2button[this._currentChild.id];
-_d.set("checked",false);
-dijit.setWaiState(_d.focusNode,"selected","false");
-_d.focusNode.setAttribute("tabIndex","-1");
-}
-var _e=this.pane2button[_c.id];
-_e.set("checked",true);
-dijit.setWaiState(_e.focusNode,"selected","true");
-this._currentChild=_c;
-_e.focusNode.setAttribute("tabIndex","0");
-var _f=dijit.byId(this.containerId);
-dijit.setWaiState(_f.containerNode,"labelledby",_e.id);
-},onButtonClick:function(_10){
-var _11=dijit.byId(this.containerId);
-_11.selectChild(_10);
-},onCloseButtonClick:function(_12){
-var _13=dijit.byId(this.containerId);
-_13.closeChild(_12);
-if(this._currentChild){
-var b=this.pane2button[this._currentChild.id];
-if(b){
-dijit.focus(b.focusNode||b.domNode);
-}
-}
-},adjacent:function(_14){
-if(!this.isLeftToRight()&&(!this.tabPosition||/top|bottom/.test(this.tabPosition))){
-_14=!_14;
-}
-var _15=this.getChildren();
-var _16=dojo.indexOf(_15,this.pane2button[this._currentChild.id]);
-var _17=_14?1:_15.length-1;
-return _15[(_16+_17)%_15.length];
-},onkeypress:function(e){
-if(this.disabled||e.altKey){
-return;
-}
-var _18=null;
-if(e.ctrlKey||!e._djpage){
-var k=dojo.keys;
-switch(e.charOrCode){
-case k.LEFT_ARROW:
-case k.UP_ARROW:
-if(!e._djpage){
-_18=false;
-}
-break;
-case k.PAGE_UP:
-if(e.ctrlKey){
-_18=false;
-}
-break;
-case k.RIGHT_ARROW:
-case k.DOWN_ARROW:
-if(!e._djpage){
-_18=true;
-}
-break;
-case k.PAGE_DOWN:
-if(e.ctrlKey){
-_18=true;
-}
-break;
-case k.DELETE:
-if(this._currentChild.closable){
-this.onCloseButtonClick(this._currentChild);
-}
-dojo.stopEvent(e);
-break;
-default:
-if(e.ctrlKey){
-if(e.charOrCode===k.TAB){
-this.adjacent(!e.shiftKey).onClick();
-dojo.stopEvent(e);
-}else{
-if(e.charOrCode=="w"){
-if(this._currentChild.closable){
-this.onCloseButtonClick(this._currentChild);
-}
-dojo.stopEvent(e);
-}
-}
-}
-}
-if(_18!==null){
-this.adjacent(_18).onClick();
-dojo.stopEvent(e);
-}
-}
-},onContainerKeyPress:function(_19){
-_19.e._djpage=_19.page;
-this.onkeypress(_19.e);
-}});
-dojo.declare("dijit.layout._StackButton",dijit.form.ToggleButton,{tabIndex:"-1",postCreate:function(evt){
-dijit.setWaiRole((this.focusNode||this.domNode),"tab");
-this.inherited(arguments);
-},onClick:function(evt){
-dijit.focus(this.focusNode);
-},onClickCloseButton:function(evt){
-evt.stopPropagation();
-}});
+dojo.requireLocalization("dijit", "common", 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.StackController",
+ [dijit._Widget, dijit._Templated, dijit._Container],
+ {
+ // summary:
+ // Set of buttons to select a page in a page list.
+ // description:
+ // Monitors the specified StackContainer, and whenever a page is
+ // added, deleted, or selected, updates itself accordingly.
+
+ templateString: "<span role='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",
+
+ // containerId: [const] String
+ // The id of the page container that I point to
+ containerId: "",
+
+ // buttonWidget: [const] String
+ // The name of the button widget to create to correspond to each page
+ buttonWidget: "dijit.layout._StackButton",
+
+ constructor: function(){
+ this.pane2button = {}; // mapping from pane id to buttons
+ this.pane2connects = {}; // mapping from pane id to this.connect() handles
+ this.pane2watches = {}; // mapping from pane id to watch() handles
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dijit.setWaiRole(this.domNode, "tablist"); // TODO: unneeded? it's in template above.
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Listen to notifications from StackContainer
+ this.subscribe(this.containerId+"-startup", "onStartup");
+ this.subscribe(this.containerId+"-addChild", "onAddChild");
+ this.subscribe(this.containerId+"-removeChild", "onRemoveChild");
+ this.subscribe(this.containerId+"-selectChild", "onSelectChild");
+ this.subscribe(this.containerId+"-containerKeyPress", "onContainerKeyPress");
+ },
+
+ onStartup: function(/*Object*/ info){
+ // summary:
+ // Called after StackContainer has finished initializing
+ // tags:
+ // private
+ dojo.forEach(info.children, this.onAddChild, this);
+ if(info.selected){
+ // Show button corresponding to selected pane (unless selected
+ // is null because there are no panes)
+ this.onSelectChild(info.selected);
+ }
+ },
+
+ destroy: function(){
+ for(var pane in this.pane2button){
+ this.onRemoveChild(dijit.byId(pane));
+ }
+ this.inherited(arguments);
+ },
+
+ onAddChild: function(/*dijit._Widget*/ page, /*Integer?*/ insertIndex){
+ // summary:
+ // Called whenever a page is added to the container.
+ // Create button corresponding to the page.
+ // tags:
+ // private
+
+ // create an instance of the button widget
+ var cls = dojo.getObject(this.buttonWidget);
+ var button = new cls({
+ id: this.id + "_" + page.id,
+ label: page.title,
+ dir: page.dir,
+ lang: page.lang,
+ showLabel: page.showTitle,
+ iconClass: page.iconClass,
+ closeButton: page.closable,
+ title: page.tooltip
+ });
+ dijit.setWaiState(button.focusNode,"selected", "false");
+
+
+ // map from page attribute to corresponding tab button attribute
+ var pageAttrList = ["title", "showTitle", "iconClass", "closable", "tooltip"],
+ buttonAttrList = ["label", "showLabel", "iconClass", "closeButton", "title"];
+
+ // watch() so events like page title changes are reflected in tab button
+ this.pane2watches[page.id] = dojo.map(pageAttrList, function(pageAttr, idx){
+ return page.watch(pageAttr, function(name, oldVal, newVal){
+ button.set(buttonAttrList[idx], newVal);
+ });
+ });
+
+ // connections so that clicking a tab button selects the corresponding page
+ this.pane2connects[page.id] = [
+ this.connect(button, 'onClick', dojo.hitch(this,"onButtonClick", page)),
+ this.connect(button, 'onClickCloseButton', dojo.hitch(this,"onCloseButtonClick", page))
+ ];
+
+ this.addChild(button, insertIndex);
+ this.pane2button[page.id] = button;
+ page.controlButton = button; // this value might be overwritten if two tabs point to same container
+ if(!this._currentChild){ // put the first child into the tab order
+ button.focusNode.setAttribute("tabIndex", "0");
+ dijit.setWaiState(button.focusNode, "selected", "true");
+ this._currentChild = page;
+ }
+ // make sure all tabs have the same length
+ if(!this.isLeftToRight() && dojo.isIE && this._rectifyRtlTabList){
+ this._rectifyRtlTabList();
+ }
+ },
+
+ onRemoveChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called whenever a page is removed from the container.
+ // Remove the button corresponding to the page.
+ // tags:
+ // private
+
+ if(this._currentChild === page){ this._currentChild = null; }
+
+ // disconnect/unwatch connections/watches related to page being removed
+ dojo.forEach(this.pane2connects[page.id], dojo.hitch(this, "disconnect"));
+ delete this.pane2connects[page.id];
+ dojo.forEach(this.pane2watches[page.id], function(w){ w.unwatch(); });
+ delete this.pane2watches[page.id];
+
+ var button = this.pane2button[page.id];
+ if(button){
+ this.removeChild(button);
+ delete this.pane2button[page.id];
+ button.destroy();
+ }
+ delete page.controlButton;
+ },
+
+ onSelectChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called when a page has been selected in the StackContainer, either by me or by another StackController
+ // tags:
+ // private
+
+ if(!page){ return; }
+
+ if(this._currentChild){
+ var oldButton=this.pane2button[this._currentChild.id];
+ oldButton.set('checked', false);
+ dijit.setWaiState(oldButton.focusNode, "selected", "false");
+ oldButton.focusNode.setAttribute("tabIndex", "-1");
+ }
+
+ var newButton=this.pane2button[page.id];
+ newButton.set('checked', true);
+ dijit.setWaiState(newButton.focusNode, "selected", "true");
+ this._currentChild = page;
+ newButton.focusNode.setAttribute("tabIndex", "0");
+ var container = dijit.byId(this.containerId);
+ dijit.setWaiState(container.containerNode, "labelledby", newButton.id);
+ },
+
+ onButtonClick: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called whenever one of my child buttons is pressed in an attempt to select a page
+ // tags:
+ // private
+
+ var container = dijit.byId(this.containerId);
+ container.selectChild(page);
+ },
+
+ onCloseButtonClick: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called whenever one of my child buttons [X] is pressed in an attempt to close a page
+ // tags:
+ // private
+
+ var container = dijit.byId(this.containerId);
+ container.closeChild(page);
+ if(this._currentChild){
+ var b = this.pane2button[this._currentChild.id];
+ if(b){
+ dijit.focus(b.focusNode || b.domNode);
+ }
+ }
+ },
+
+ // TODO: this is a bit redundant with forward, back api in StackContainer
+ adjacent: function(/*Boolean*/ forward){
+ // summary:
+ // Helper for onkeypress to find next/previous button
+ // tags:
+ // private
+
+ if(!this.isLeftToRight() && (!this.tabPosition || /top|bottom/.test(this.tabPosition))){ forward = !forward; }
+ // find currently focused button in children array
+ var children = this.getChildren();
+ var current = dojo.indexOf(children, this.pane2button[this._currentChild.id]);
+ // pick next button to focus on
+ var offset = forward ? 1 : children.length - 1;
+ return children[ (current + offset) % children.length ]; // dijit._Widget
+ },
+
+ onkeypress: function(/*Event*/ e){
+ // summary:
+ // Handle keystrokes on the page list, for advancing to next/previous button
+ // and closing the current page if the page is closable.
+ // tags:
+ // private
+
+ if(this.disabled || e.altKey ){ return; }
+ var forward = null;
+ if(e.ctrlKey || !e._djpage){
+ var k = dojo.keys;
+ switch(e.charOrCode){
+ case k.LEFT_ARROW:
+ case k.UP_ARROW:
+ if(!e._djpage){ forward = false; }
+ break;
+ case k.PAGE_UP:
+ if(e.ctrlKey){ forward = false; }
+ break;
+ case k.RIGHT_ARROW:
+ case k.DOWN_ARROW:
+ if(!e._djpage){ forward = true; }
+ break;
+ case k.PAGE_DOWN:
+ if(e.ctrlKey){ forward = true; }
+ break;
+ case k.HOME:
+ case k.END:
+ var children = this.getChildren();
+ if(children && children.length){
+ children[e.charOrCode == k.HOME ? 0 : children.length-1].onClick();
+ }
+ dojo.stopEvent(e);
+ break;
+ case k.DELETE:
+ if(this._currentChild.closable){
+ this.onCloseButtonClick(this._currentChild);
+ }
+ dojo.stopEvent(e);
+ break;
+ default:
+ if(e.ctrlKey){
+ if(e.charOrCode === k.TAB){
+ this.adjacent(!e.shiftKey).onClick();
+ dojo.stopEvent(e);
+ }else if(e.charOrCode == "w"){
+ if(this._currentChild.closable){
+ this.onCloseButtonClick(this._currentChild);
+ }
+ dojo.stopEvent(e); // avoid browser tab closing.
+ }
+ }
+ }
+ // handle next/previous page navigation (left/right arrow, etc.)
+ if(forward !== null){
+ this.adjacent(forward).onClick();
+ dojo.stopEvent(e);
+ }
+ }
+ },
+
+ onContainerKeyPress: function(/*Object*/ info){
+ // summary:
+ // Called when there was a keypress on the container
+ // tags:
+ // private
+ info.e._djpage = info.page;
+ this.onkeypress(info.e);
+ }
+ });
+
+
+dojo.declare("dijit.layout._StackButton",
+ dijit.form.ToggleButton,
+ {
+ // summary:
+ // Internal widget used by StackContainer.
+ // description:
+ // The button-like or tab-like object you click to select or delete a page
+ // tags:
+ // private
+
+ // Override _FormWidget.tabIndex.
+ // StackContainer buttons are not in the tab order by default.
+ // Probably we should be calling this.startupKeyNavChildren() instead.
+ tabIndex: "-1",
+
+ buildRendering: function(/*Event*/ evt){
+ this.inherited(arguments);
+ dijit.setWaiRole((this.focusNode || this.domNode), "tab");
+ },
+
+ onClick: function(/*Event*/ evt){
+ // summary:
+ // This is for TabContainer where the tabs are <span> rather than button,
+ // so need to set focus explicitly (on some browsers)
+ // Note that you shouldn't override this method, but you can connect to it.
+ dijit.focus(this.focusNode);
+
+ // ... now let StackController catch the event and tell me what to do
+ },
+
+ onClickCloseButton: function(/*Event*/ evt){
+ // summary:
+ // StackContainer connects to this function; if your widget contains a close button
+ // then clicking it should call this function.
+ // Note that you shouldn't override this method, but you can connect to it.
+ evt.stopPropagation();
+ }
+ });
+
}
diff --git a/lib/dijit/layout/TabContainer.js b/lib/dijit/layout/TabContainer.js
index d765cf7e4..009422464 100644
--- a/lib/dijit/layout/TabContainer.js
+++ b/lib/dijit/layout/TabContainer.js
@@ -1,23 +1,76 @@
/*
- 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.TabContainer"]){
-dojo._hasResource["dijit.layout.TabContainer"]=true;
+if(!dojo._hasResource["dijit.layout.TabContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.TabContainer"] = true;
dojo.provide("dijit.layout.TabContainer");
dojo.require("dijit.layout._TabContainerBase");
dojo.require("dijit.layout.TabController");
dojo.require("dijit.layout.ScrollingTabController");
-dojo.declare("dijit.layout.TabContainer",dijit.layout._TabContainerBase,{useMenu:true,useSlider:true,controllerWidget:"",_makeController:function(_1){
-var _2=this.baseClass+"-tabs"+(this.doLayout?"":" dijitTabNoLayout"),_3=dojo.getObject(this.controllerWidget);
-return new _3({id:this.id+"_tablist",dir:this.dir,lang:this.lang,tabPosition:this.tabPosition,doLayout:this.doLayout,containerId:this.id,"class":_2,nested:this.nested,useMenu:this.useMenu,useSlider:this.useSlider,tabStripClass:this.tabStrip?this.baseClass+(this.tabStrip?"":"No")+"Strip":null},_1);
-},postMixInProperties:function(){
-this.inherited(arguments);
-if(!this.controllerWidget){
-this.controllerWidget=(this.tabPosition=="top"||this.tabPosition=="bottom")&&!this.nested?"dijit.layout.ScrollingTabController":"dijit.layout.TabController";
-}
-}});
+
+
+dojo.declare("dijit.layout.TabContainer",
+ dijit.layout._TabContainerBase,
+ {
+ // summary:
+ // A Container with tabs to select each child (only one of which is displayed at a time).
+ // description:
+ // A TabContainer is a container that has multiple panes, but shows only
+ // one pane at a time. There are a set of tabs corresponding to each pane,
+ // where each tab has the name (aka title) of the pane, and optionally a close button.
+
+ // useMenu: [const] Boolean
+ // True if a menu should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useMenu: true,
+
+ // useSlider: [const] Boolean
+ // True if a slider should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useSlider: true,
+
+ // controllerWidget: String
+ // An optional parameter to override the widget used to display the tab labels
+ controllerWidget: "",
+
+ _makeController: function(/*DomNode*/ srcNode){
+ // summary:
+ // Instantiate tablist controller widget and return reference to it.
+ // Callback from _TabContainerBase.postCreate().
+ // tags:
+ // protected extension
+
+ var cls = this.baseClass + "-tabs" + (this.doLayout ? "" : " dijitTabNoLayout"),
+ TabController = dojo.getObject(this.controllerWidget);
+
+ return new TabController({
+ id: this.id + "_tablist",
+ dir: this.dir,
+ lang: this.lang,
+ tabPosition: this.tabPosition,
+ doLayout: this.doLayout,
+ containerId: this.id,
+ "class": cls,
+ nested: this.nested,
+ useMenu: this.useMenu,
+ useSlider: this.useSlider,
+ tabStripClass: this.tabStrip ? this.baseClass + (this.tabStrip ? "":"No") + "Strip": null
+ }, srcNode);
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+
+ // Scrolling controller only works for horizontal non-nested tabs
+ if(!this.controllerWidget){
+ this.controllerWidget = (this.tabPosition == "top" || this.tabPosition == "bottom") && !this.nested ?
+ "dijit.layout.ScrollingTabController" : "dijit.layout.TabController";
+ }
+ }
+});
+
}
diff --git a/lib/dijit/layout/TabController.js b/lib/dijit/layout/TabController.js
index edb3930c5..0a2276aca 100644
--- a/lib/dijit/layout/TabController.js
+++ b/lib/dijit/layout/TabController.js
@@ -1,77 +1,161 @@
/*
- 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.TabController"]){
-dojo._hasResource["dijit.layout.TabController"]=true;
+if(!dojo._hasResource["dijit.layout.TabController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.TabController"] = true;
dojo.provide("dijit.layout.TabController");
dojo.require("dijit.layout.StackController");
dojo.require("dijit.Menu");
dojo.require("dijit.MenuItem");
-dojo.requireLocalization("dijit","common",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.TabController",dijit.layout.StackController,{templateString:"<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",tabPosition:"top",buttonWidget:"dijit.layout._TabButton",_rectifyRtlTabList:function(){
-if(0>=this.tabPosition.indexOf("-h")){
-return;
-}
-if(!this.pane2button){
-return;
-}
-var _1=0;
-for(var _2 in this.pane2button){
-var ow=this.pane2button[_2].innerDiv.scrollWidth;
-_1=Math.max(_1,ow);
-}
-for(_2 in this.pane2button){
-this.pane2button[_2].innerDiv.style.width=_1+"px";
-}
-}});
-dojo.declare("dijit.layout._TabButton",dijit.layout._StackButton,{baseClass:"dijitTab",cssStateNodes:{closeNode:"dijitTabCloseButton"},templateString:dojo.cache("dijit.layout","templates/_TabButton.html","<div waiRole=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\n <div waiRole=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n <div waiRole=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n \t<div waiRole=\"presentation\" dojoAttachPoint='focusNode'>\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' />\n\t\t <span dojoAttachPoint='containerNode' class='tabLabel'></span>\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\n\t\t \t\tdojoAttachEvent='onclick: onClickCloseButton' waiRole=\"presentation\">\n\t\t <span dojoAttachPoint='closeText' class='dijitTabCloseText'>x</span\n\t\t ></span>\n\t\t\t</div>\n </div>\n </div>\n</div>\n"),scrollOnFocus:false,postMixInProperties:function(){
-if(!this.iconClass){
-this.iconClass="dijitTabButtonIcon";
-}
-},postCreate:function(){
-this.inherited(arguments);
-dojo.setSelectable(this.containerNode,false);
-if(this.iconNode.className=="dijitTabButtonIcon"){
-dojo.style(this.iconNode,"width","1px");
-}
-},startup:function(){
-this.inherited(arguments);
-var n=this.domNode;
-setTimeout(function(){
-n.className=n.className;
-},1);
-},_setCloseButtonAttr:function(_3){
-this.closeButton=_3;
-dojo.toggleClass(this.innerDiv,"dijitClosable",_3);
-this.closeNode.style.display=_3?"":"none";
-if(_3){
-var _4=dojo.i18n.getLocalization("dijit","common");
-if(this.closeNode){
-dojo.attr(this.closeNode,"title",_4.itemClose);
-}
-var _4=dojo.i18n.getLocalization("dijit","common");
-this._closeMenu=new dijit.Menu({id:this.id+"_Menu",dir:this.dir,lang:this.lang,targetNodeIds:[this.domNode]});
-this._closeMenu.addChild(new dijit.MenuItem({label:_4.itemClose,dir:this.dir,lang:this.lang,onClick:dojo.hitch(this,"onClickCloseButton")}));
-}else{
-if(this._closeMenu){
-this._closeMenu.destroyRecursive();
-delete this._closeMenu;
-}
-}
-},_setLabelAttr:function(_5){
-this.inherited(arguments);
-if(this.showLabel==false&&!this.params.title){
-this.iconNode.alt=dojo.trim(this.containerNode.innerText||this.containerNode.textContent||"");
-}
-},destroy:function(){
-if(this._closeMenu){
-this._closeMenu.destroyRecursive();
-delete this._closeMenu;
-}
-this.inherited(arguments);
-}});
+dojo.requireLocalization("dijit", "common", 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");
+
+
+// Menu is used for an accessible close button, would be nice to have a lighter-weight solution
+
+
+dojo.declare("dijit.layout.TabController",
+ dijit.layout.StackController,
+{
+ // summary:
+ // Set of tabs (the things with titles and a close button, that you click to show a tab panel).
+ // Used internally by `dijit.layout.TabContainer`.
+ // description:
+ // Lets the user select the currently shown pane in a TabContainer or StackContainer.
+ // TabController also monitors the TabContainer, and whenever a pane is
+ // added or deleted updates itself accordingly.
+ // tags:
+ // private
+
+ templateString: "<div role='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",
+
+ // tabPosition: String
+ // Defines where tabs go relative to the content.
+ // "top", "bottom", "left-h", "right-h"
+ tabPosition: "top",
+
+ // buttonWidget: String
+ // The name of the tab widget to create to correspond to each page
+ buttonWidget: "dijit.layout._TabButton",
+
+ _rectifyRtlTabList: function(){
+ // summary:
+ // For left/right TabContainer when page is RTL mode, rectify the width of all tabs to be equal, otherwise the tab widths are different in IE
+
+ if(0 >= this.tabPosition.indexOf('-h')){ return; }
+ if(!this.pane2button){ return; }
+
+ var maxWidth = 0;
+ for(var pane in this.pane2button){
+ var ow = this.pane2button[pane].innerDiv.scrollWidth;
+ maxWidth = Math.max(maxWidth, ow);
+ }
+ //unify the length of all the tabs
+ for(pane in this.pane2button){
+ this.pane2button[pane].innerDiv.style.width = maxWidth + 'px';
+ }
+ }
+});
+
+dojo.declare("dijit.layout._TabButton",
+ dijit.layout._StackButton,
+ {
+ // summary:
+ // A tab (the thing you click to select a pane).
+ // description:
+ // Contains the title of the pane, and optionally a close-button to destroy the pane.
+ // This is an internal widget and should not be instantiated directly.
+ // tags:
+ // private
+
+ // baseClass: String
+ // The CSS class applied to the domNode.
+ baseClass: "dijitTab",
+
+ // Apply dijitTabCloseButtonHover when close button is hovered
+ cssStateNodes: {
+ closeNode: "dijitTabCloseButton"
+ },
+
+ templateString: dojo.cache("dijit.layout", "templates/_TabButton.html", "<div role=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\n <div role=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n <div role=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n \t<div role=\"presentation\" dojoAttachPoint='focusNode'>\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitTabButtonIcon\" dojoAttachPoint='iconNode' />\n\t\t <span dojoAttachPoint='containerNode' class='tabLabel'></span>\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\n\t\t \t\tdojoAttachEvent='onclick: onClickCloseButton' role=\"presentation\">\n\t\t <span dojoAttachPoint='closeText' class='dijitTabCloseText'>[x]</span\n\t\t ></span>\n\t\t\t</div>\n </div>\n </div>\n</div>\n"),
+
+ // Override _FormWidget.scrollOnFocus.
+ // Don't scroll the whole tab container into view when the button is focused.
+ scrollOnFocus: false,
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ dojo.setSelectable(this.containerNode, false);
+ },
+
+ startup: function(){
+ this.inherited(arguments);
+ var n = this.domNode;
+
+ // Required to give IE6 a kick, as it initially hides the
+ // tabs until they are focused on.
+ setTimeout(function(){
+ n.className = n.className;
+ }, 1);
+ },
+
+ _setCloseButtonAttr: function(/*Boolean*/ disp){
+ // summary:
+ // Hide/show close button
+ this._set("closeButton", disp);
+ dojo.toggleClass(this.innerDiv, "dijitClosable", disp);
+ this.closeNode.style.display = disp ? "" : "none";
+ if(disp){
+ var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
+ if(this.closeNode){
+ dojo.attr(this.closeNode,"title", _nlsResources.itemClose);
+ }
+ // add context menu onto title button
+ var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
+ this._closeMenu = new dijit.Menu({
+ id: this.id+"_Menu",
+ dir: this.dir,
+ lang: this.lang,
+ targetNodeIds: [this.domNode]
+ });
+
+ this._closeMenu.addChild(new dijit.MenuItem({
+ label: _nlsResources.itemClose,
+ dir: this.dir,
+ lang: this.lang,
+ onClick: dojo.hitch(this, "onClickCloseButton")
+ }));
+ }else{
+ if(this._closeMenu){
+ this._closeMenu.destroyRecursive();
+ delete this._closeMenu;
+ }
+ }
+ },
+ _setLabelAttr: function(/*String*/ content){
+ // summary:
+ // Hook for set('label', ...) to work.
+ // description:
+ // takes an HTML string.
+ // Inherited ToggleButton implementation will Set the label (text) of the button;
+ // Need to set the alt attribute of icon on tab buttons if no label displayed
+ this.inherited(arguments);
+ if(this.showLabel == false && !this.params.title){
+ this.iconNode.alt = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
+ }
+ },
+
+ destroy: function(){
+ if(this._closeMenu){
+ this._closeMenu.destroyRecursive();
+ delete this._closeMenu;
+ }
+ this.inherited(arguments);
+ }
+});
+
}
diff --git a/lib/dijit/layout/_ContentPaneResizeMixin.js b/lib/dijit/layout/_ContentPaneResizeMixin.js
new file mode 100644
index 000000000..fe361bee5
--- /dev/null
+++ b/lib/dijit/layout/_ContentPaneResizeMixin.js
@@ -0,0 +1,260 @@
+/*
+ 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._ContentPaneResizeMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._ContentPaneResizeMixin"] = true;
+dojo.provide("dijit.layout._ContentPaneResizeMixin");
+dojo.require("dijit._Contained");
+dojo.require("dijit.layout._LayoutWidget");
+
+
+dojo.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,
+
+ // 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,
+
+ _startChildren: function(){
+ // summary:
+ // Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
+
+ // This starts all the widgets
+ dojo.forEach(this.getChildren(), function(child){
+ child.startup();
+ child._started = 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 = 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;
+
+ this.inherited(arguments);
+
+ this._startChildren();
+
+ if(this._isShown()){
+ this._onShow();
+ }
+
+ if(!this._childOfLayoutWidget){
+ // If my parent isn't a layout container, since my style *may be* width=height=100%
+ // or something similar (either set directly or via a CSS class),
+ // monitor when my size changes so that I can re-layout.
+ // For browsers where I can't directly monitor when my size changes,
+ // monitor when the viewport changes size, which *may* indicate a size change for me.
+ this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){
+ // Using function(){} closure to ensure no arguments to resize.
+ this._needLayout = !this._childOfLayoutWidget;
+ 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.
+
+ 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, "data-dojo-type") || 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);
+ },
+
+ 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 (see [20099]).
+ // However, don't load href for closed TitlePanes.
+ if(!this._wasShown && this.open !== false){
+ this._onShow();
+ }
+
+ 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 a Container widget, each of my children expects me to
+ // call resize() or layout() on them.
+ //
+ // 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
+
+ // 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);
+ }
+
+ this._layoutChildren();
+
+ delete this._needLayout;
+ },
+
+ _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.
+ 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();
+ }
+ });
+ }
+ },
+
+ _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') && !dojo.hasClass(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)
+
+ 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);
+
+ // Need to keep track of whether ContentPane has been shown (which is different than
+ // whether or not it's currently visible).
+ this._wasShown = true;
+ }
+});
+
+}
diff --git a/lib/dijit/layout/_LayoutWidget.js b/lib/dijit/layout/_LayoutWidget.js
index ec7be37b7..cbbf71009 100644
--- a/lib/dijit/layout/_LayoutWidget.js
+++ b/lib/dijit/layout/_LayoutWidget.js
@@ -1,126 +1,313 @@
/*
- 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._LayoutWidget"]){
-dojo._hasResource["dijit.layout._LayoutWidget"]=true;
+if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._LayoutWidget"] = true;
dojo.provide("dijit.layout._LayoutWidget");
dojo.require("dijit._Widget");
dojo.require("dijit._Container");
dojo.require("dijit._Contained");
-dojo.declare("dijit.layout._LayoutWidget",[dijit._Widget,dijit._Container,dijit._Contained],{baseClass:"dijitLayoutContainer",isLayoutContainer:true,postCreate:function(){
-dojo.addClass(this.domNode,"dijitContainer");
-this.inherited(arguments);
-},startup:function(){
-if(this._started){
-return;
-}
-this.inherited(arguments);
-var _1=this.getParent&&this.getParent();
-if(!(_1&&_1.isLayoutContainer)){
-this.resize();
-this.connect(dojo.isIE?this.domNode:dojo.global,"onresize",function(){
-this.resize();
-});
-}
-},resize:function(_2,_3){
-var _4=this.domNode;
-if(_2){
-dojo.marginBox(_4,_2);
-if(_2.t){
-_4.style.top=_2.t+"px";
-}
-if(_2.l){
-_4.style.left=_2.l+"px";
-}
-}
-var mb=_3||{};
-dojo.mixin(mb,_2||{});
-if(!("h" in mb)||!("w" in mb)){
-mb=dojo.mixin(dojo.marginBox(_4),mb);
-}
-var cs=dojo.getComputedStyle(_4);
-var me=dojo._getMarginExtents(_4,cs);
-var be=dojo._getBorderExtents(_4,cs);
-var bb=(this._borderBox={w:mb.w-(me.w+be.w),h:mb.h-(me.h+be.h)});
-var pe=dojo._getPadExtents(_4,cs);
-this._contentBox={l:dojo._toPixelValue(_4,cs.paddingLeft),t:dojo._toPixelValue(_4,cs.paddingTop),w:bb.w-pe.w,h:bb.h-pe.h};
-this.layout();
-},layout:function(){
-},_setupChild:function(_5){
-dojo.addClass(_5.domNode,this.baseClass+"-child");
-if(_5.baseClass){
-dojo.addClass(_5.domNode,this.baseClass+"-"+_5.baseClass);
-}
-},addChild:function(_6,_7){
-this.inherited(arguments);
-if(this._started){
-this._setupChild(_6);
-}
-},removeChild:function(_8){
-dojo.removeClass(_8.domNode,this.baseClass+"-child");
-if(_8.baseClass){
-dojo.removeClass(_8.domNode,this.baseClass+"-"+_8.baseClass);
-}
-this.inherited(arguments);
-}});
-dijit.layout.marginBox2contentBox=function(_9,mb){
-var cs=dojo.getComputedStyle(_9);
-var me=dojo._getMarginExtents(_9,cs);
-var pb=dojo._getPadBorderExtents(_9,cs);
-return {l:dojo._toPixelValue(_9,cs.paddingLeft),t:dojo._toPixelValue(_9,cs.paddingTop),w:mb.w-(me.w+pb.w),h:mb.h-(me.h+pb.h)};
+
+
+dojo.declare("dijit.layout._LayoutWidget",
+ [dijit._Widget, dijit._Container, dijit._Contained],
+ {
+ // summary:
+ // Base class for a _Container widget which is responsible for laying out its children.
+ // Widgets which mixin this code must define layout() to manage placement and sizing of the children.
+
+ // baseClass: [protected extension] String
+ // This class name is applied to the widget's domNode
+ // and also may be used to generate names for sub nodes,
+ // for example dijitTabContainer-content.
+ baseClass: "dijitLayoutContainer",
+
+ // isLayoutContainer: [protected] Boolean
+ // Indicates that this widget is going to call resize() on its
+ // children widgets, setting their size, when they become visible.
+ isLayoutContainer: true,
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.addClass(this.domNode, "dijitContainer");
+ },
+
+ startup: function(){
+ // summary:
+ // Called after all the widgets have been instantiated and their
+ // dom nodes have been inserted somewhere under dojo.doc.body.
+ //
+ // Widgets should override this method to do any initialization
+ // dependent on other widgets existing, and then call
+ // this superclass method to finish things off.
+ //
+ // startup() in subclasses shouldn't do anything
+ // size related because the size of the widget hasn't been set yet.
+
+ if(this._started){ return; }
+
+ // Need to call inherited first - so that child widgets get started
+ // up correctly
+ this.inherited(arguments);
+
+ // If I am a not being controlled by a parent layout widget...
+ var parent = this.getParent && this.getParent()
+ if(!(parent && parent.isLayoutContainer)){
+ // Do recursive sizing and layout of all my descendants
+ // (passing in no argument to resize means that it has to glean the size itself)
+ this.resize();
+
+ // 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 my size changes so that I can re-layout.
+ // For browsers where I can't directly monitor when my size changes,
+ // monitor when the viewport changes size, which *may* indicate a size change for me.
+ this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){
+ // Using function(){} closure to ensure no arguments to resize.
+ this.resize();
+ });
+ }
+ },
+
+ resize: function(changeSize, resultSize){
+ // summary:
+ // Call this to resize a widget, or after its size has changed.
+ // description:
+ // Change size mode:
+ // When changeSize is specified, changes the marginBox of this widget
+ // and forces it to relayout its contents accordingly.
+ // changeSize may specify height, width, or both.
+ //
+ // If resultSize is specified it indicates the size the widget will
+ // become after changeSize has been applied.
+ //
+ // Notification mode:
+ // When changeSize is null, indicates that the caller has already changed
+ // the size of the widget, or perhaps it changed because the browser
+ // window was resized. Tells widget to relayout its contents accordingly.
+ //
+ // If resultSize is also specified it indicates the size the widget has
+ // become.
+ //
+ // In either mode, this method also:
+ // 1. Sets this._borderBox and this._contentBox to the new size of
+ // the widget. Queries the current domNode size if necessary.
+ // 2. Calls layout() to resize contents (and maybe adjust child widgets).
+ //
+ // changeSize: Object?
+ // Sets the widget to this margin-box size and position.
+ // May include any/all of the following properties:
+ // | {w: int, h: int, l: int, t: int}
+ //
+ // resultSize: Object?
+ // The margin-box size of this widget after applying changeSize (if
+ // changeSize is specified). If caller knows this size and
+ // passes it in, we don't need to query the browser to get the size.
+ // | {w: int, h: int}
+
+ var node = this.domNode;
+
+ // set margin box size, unless it wasn't specified, in which case use current size
+ if(changeSize){
+ dojo.marginBox(node, changeSize);
+
+ // set offset of the node
+ if(changeSize.t){ node.style.top = changeSize.t + "px"; }
+ if(changeSize.l){ node.style.left = changeSize.l + "px"; }
+ }
+
+ // 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 mb = resultSize || {};
+ dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
+ if( !("h" in mb) || !("w" in mb) ){
+ mb = dojo.mixin(dojo.marginBox(node), mb); // just use dojo.marginBox() to fill in missing values
+ }
+
+ // Compute and save the size of my border box and content box
+ // (w/out calling dojo.contentBox() since that may fail if size was recently set)
+ var cs = dojo.getComputedStyle(node);
+ var me = dojo._getMarginExtents(node, cs);
+ var be = dojo._getBorderExtents(node, cs);
+ var bb = (this._borderBox = {
+ w: mb.w - (me.w + be.w),
+ h: mb.h - (me.h + be.h)
+ });
+ var pe = dojo._getPadExtents(node, cs);
+ this._contentBox = {
+ l: dojo._toPixelValue(node, cs.paddingLeft),
+ t: dojo._toPixelValue(node, cs.paddingTop),
+ w: bb.w - pe.w,
+ h: bb.h - pe.h
+ };
+
+ // Callback for widget to adjust size of its children
+ this.layout();
+ },
+
+ layout: function(){
+ // summary:
+ // Widgets override this method to size and position their contents/children.
+ // When this is called this._contentBox is guaranteed to be set (see resize()).
+ //
+ // This is called after startup(), and also when the widget's size has been
+ // changed.
+ // tags:
+ // protected extension
+ },
+
+ _setupChild: function(/*dijit._Widget*/child){
+ // summary:
+ // Common setup for initial children and children which are added after startup
+ // tags:
+ // protected extension
+
+ var cls = this.baseClass + "-child "
+ + (child.baseClass ? this.baseClass + "-" + child.baseClass : "");
+ dojo.addClass(child.domNode, cls);
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // Overrides _Container.addChild() to call _setupChild()
+ this.inherited(arguments);
+ if(this._started){
+ this._setupChild(child);
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ child){
+ // Overrides _Container.removeChild() to remove class added by _setupChild()
+ var cls = this.baseClass + "-child"
+ + (child.baseClass ?
+ " " + this.baseClass + "-" + child.baseClass : "");
+ dojo.removeClass(child.domNode, cls);
+
+ this.inherited(arguments);
+ }
+ }
+);
+
+dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
+ // summary:
+ // Given the margin-box size of a node, return its content box size.
+ // Functions like dojo.contentBox() but is more reliable since it doesn't have
+ // to wait for the browser to compute sizes.
+ var cs = dojo.getComputedStyle(node);
+ var me = dojo._getMarginExtents(node, cs);
+ var pb = dojo._getPadBorderExtents(node, cs);
+ return {
+ l: dojo._toPixelValue(node, cs.paddingLeft),
+ t: dojo._toPixelValue(node, cs.paddingTop),
+ w: mb.w - (me.w + pb.w),
+ h: mb.h - (me.h + pb.h)
+ };
};
+
(function(){
-var _a=function(_b){
-return _b.substring(0,1).toUpperCase()+_b.substring(1);
-};
-var _c=function(_d,_e){
-_d.resize?_d.resize(_e):dojo.marginBox(_d.domNode,_e);
-dojo.mixin(_d,dojo.marginBox(_d.domNode));
-dojo.mixin(_d,_e);
-};
-dijit.layout.layoutChildren=function(_f,dim,_10){
-dim=dojo.mixin({},dim);
-dojo.addClass(_f,"dijitLayoutContainer");
-_10=dojo.filter(_10,function(_11){
-return _11.layoutAlign!="client";
-}).concat(dojo.filter(_10,function(_12){
-return _12.layoutAlign=="client";
-}));
-dojo.forEach(_10,function(_13){
-var elm=_13.domNode,pos=_13.layoutAlign;
-var _14=elm.style;
-_14.left=dim.l+"px";
-_14.top=dim.t+"px";
-_14.bottom=_14.right="auto";
-dojo.addClass(elm,"dijitAlign"+_a(pos));
-if(pos=="top"||pos=="bottom"){
-_c(_13,{w:dim.w});
-dim.h-=_13.h;
-if(pos=="top"){
-dim.t+=_13.h;
-}else{
-_14.top=dim.t+dim.h+"px";
-}
-}else{
-if(pos=="left"||pos=="right"){
-_c(_13,{h:dim.h});
-dim.w-=_13.w;
-if(pos=="left"){
-dim.l+=_13.w;
-}else{
-_14.left=dim.l+dim.w+"px";
-}
-}else{
-if(pos=="client"){
-_c(_13,dim);
-}
-}
-}
-});
-};
+ var capitalize = function(word){
+ return word.substring(0,1).toUpperCase() + word.substring(1);
+ };
+
+ var size = function(widget, dim){
+ // size the child
+ var newSize = widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
+
+ // record child's size
+ if(newSize){
+ // if the child returned it's new size then use that
+ dojo.mixin(widget, newSize);
+ }else{
+ // otherwise, call marginBox(), but favor our own numbers when we have them.
+ // the browser lies sometimes
+ dojo.mixin(widget, dojo.marginBox(widget.domNode));
+ dojo.mixin(widget, dim);
+ }
+ };
+
+ dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Widget[]*/ children,
+ /*String?*/ changedRegionId, /*Number?*/ changedRegionSize){
+ // summary
+ // Layout a bunch of child dom nodes within a parent dom node
+ // container:
+ // parent node
+ // dim:
+ // {l, t, w, h} object specifying dimensions of container into which to place children
+ // children:
+ // an array of Widgets or at least objects containing:
+ // * domNode: pointer to DOM node to position
+ // * region or layoutAlign: position to place DOM node
+ // * resize(): (optional) method to set size of node
+ // * id: (optional) Id of widgets, referenced from resize object, below.
+ // changedRegionId:
+ // If specified, the slider for the region with the specified id has been dragged, and thus
+ // the region's height or width should be adjusted according to changedRegionSize
+ // changedRegionSize:
+ // See changedRegionId.
+
+ // copy dim because we are going to modify it
+ dim = dojo.mixin({}, dim);
+
+ dojo.addClass(container, "dijitLayoutContainer");
+
+ // Move "client" elements to the end of the array for layout. a11y dictates that the author
+ // needs to be able to put them in the document in tab-order, but this algorithm requires that
+ // client be last. TODO: move these lines to LayoutContainer? Unneeded other places I think.
+ children = dojo.filter(children, function(item){ return item.region != "center" && item.layoutAlign != "client"; })
+ .concat(dojo.filter(children, function(item){ return item.region == "center" || item.layoutAlign == "client"; }));
+
+ // set positions/sizes
+ dojo.forEach(children, function(child){
+ var elm = child.domNode,
+ pos = (child.region || child.layoutAlign);
+
+ // set elem to upper left corner of unused space; may move it later
+ var elmStyle = elm.style;
+ elmStyle.left = dim.l+"px";
+ elmStyle.top = dim.t+"px";
+ elmStyle.position = "absolute";
+
+ dojo.addClass(elm, "dijitAlign" + capitalize(pos));
+
+ // Size adjustments to make to this child widget
+ var sizeSetting = {};
+
+ // Check for optional size adjustment due to splitter drag (height adjustment for top/bottom align
+ // panes and width adjustment for left/right align panes.
+ if(changedRegionId && changedRegionId == child.id){
+ sizeSetting[child.region == "top" || child.region == "bottom" ? "h" : "w"] = changedRegionSize;
+ }
+
+ // set size && adjust record of remaining space.
+ // note that setting the width of a <div> 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);
+ }
+ });
+ };
+
})();
+
}
diff --git a/lib/dijit/layout/_TabContainerBase.js b/lib/dijit/layout/_TabContainerBase.js
index 0ba42ec35..5e07cb653 100644
--- a/lib/dijit/layout/_TabContainerBase.js
+++ b/lib/dijit/layout/_TabContainerBase.js
@@ -1,68 +1,145 @@
/*
- 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._TabContainerBase"]){
-dojo._hasResource["dijit.layout._TabContainerBase"]=true;
+if(!dojo._hasResource["dijit.layout._TabContainerBase"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._TabContainerBase"] = true;
dojo.provide("dijit.layout._TabContainerBase");
dojo.require("dijit.layout.StackContainer");
dojo.require("dijit._Templated");
-dojo.declare("dijit.layout._TabContainerBase",[dijit.layout.StackContainer,dijit._Templated],{tabPosition:"top",baseClass:"dijitTabContainer",tabStrip:false,nested:false,templateString:dojo.cache("dijit.layout","templates/TabContainer.html","<div class=\"dijitTabContainer\">\n\t<div class=\"dijitTabListWrapper\" dojoAttachPoint=\"tablistNode\"></div>\n\t<div dojoAttachPoint=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n"),postMixInProperties:function(){
-this.baseClass+=this.tabPosition.charAt(0).toUpperCase()+this.tabPosition.substr(1).replace(/-.*/,"");
-this.srcNodeRef&&dojo.style(this.srcNodeRef,"visibility","hidden");
-this.inherited(arguments);
-},postCreate:function(){
-this.inherited(arguments);
-this.tablist=this._makeController(this.tablistNode);
-if(!this.doLayout){
-dojo.addClass(this.domNode,"dijitTabContainerNoLayout");
-}
-if(this.nested){
-dojo.addClass(this.domNode,"dijitTabContainerNested");
-dojo.addClass(this.tablist.containerNode,"dijitTabContainerTabListNested");
-dojo.addClass(this.tablistSpacer,"dijitTabContainerSpacerNested");
-dojo.addClass(this.containerNode,"dijitTabPaneWrapperNested");
-}else{
-dojo.addClass(this.domNode,"tabStrip-"+(this.tabStrip?"enabled":"disabled"));
-}
-},_setupChild:function(_1){
-dojo.addClass(_1.domNode,"dijitTabPane");
-this.inherited(arguments);
-},startup:function(){
-if(this._started){
-return;
-}
-this.tablist.startup();
-this.inherited(arguments);
-},layout:function(){
-if(!this._contentBox||typeof (this._contentBox.l)=="undefined"){
-return;
-}
-var sc=this.selectedChildWidget;
-if(this.doLayout){
-var _2=this.tabPosition.replace(/-h/,"");
-this.tablist.layoutAlign=_2;
-var _3=[this.tablist,{domNode:this.tablistSpacer,layoutAlign:_2},{domNode:this.containerNode,layoutAlign:"client"}];
-dijit.layout.layoutChildren(this.domNode,this._contentBox,_3);
-this._containerContentBox=dijit.layout.marginBox2contentBox(this.containerNode,_3[2]);
-if(sc&&sc.resize){
-sc.resize(this._containerContentBox);
-}
-}else{
-if(this.tablist.resize){
-this.tablist.resize({w:dojo.contentBox(this.domNode).w});
-}
-if(sc&&sc.resize){
-sc.resize();
-}
-}
-},destroy:function(){
-if(this.tablist){
-this.tablist.destroy();
-}
-this.inherited(arguments);
-}});
+
+
+dojo.declare("dijit.layout._TabContainerBase",
+ [dijit.layout.StackContainer, dijit._Templated],
+ {
+ // summary:
+ // Abstract base class for TabContainer. Must define _makeController() to instantiate
+ // and return the widget that displays the tab labels
+ // description:
+ // A TabContainer is a container that has multiple panes, but shows only
+ // one pane at a time. There are a set of tabs corresponding to each pane,
+ // where each tab has the name (aka title) of the pane, and optionally a close button.
+
+ // tabPosition: String
+ // Defines where tabs go relative to tab content.
+ // "top", "bottom", "left-h", "right-h"
+ tabPosition: "top",
+
+ baseClass: "dijitTabContainer",
+
+ // tabStrip: [const] Boolean
+ // Defines whether the tablist gets an extra class for layouting, putting a border/shading
+ // around the set of tabs. Not supported by claro theme.
+ tabStrip: false,
+
+ // nested: [const] Boolean
+ // If true, use styling for a TabContainer nested inside another TabContainer.
+ // For tundra etc., makes tabs look like links, and hides the outer
+ // border since the outer TabContainer already has a border.
+ nested: false,
+
+ templateString: dojo.cache("dijit.layout", "templates/TabContainer.html", "<div class=\"dijitTabContainer\">\n\t<div class=\"dijitTabListWrapper\" dojoAttachPoint=\"tablistNode\"></div>\n\t<div dojoAttachPoint=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n"),
+
+ postMixInProperties: function(){
+ // set class name according to tab position, ex: dijitTabContainerTop
+ this.baseClass += this.tabPosition.charAt(0).toUpperCase() + this.tabPosition.substr(1).replace(/-.*/, "");
+
+ this.srcNodeRef && dojo.style(this.srcNodeRef, "visibility", "hidden");
+
+ this.inherited(arguments);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ // Create the tab list that will have a tab (a.k.a. tab button) for each tab panel
+ this.tablist = this._makeController(this.tablistNode);
+
+ if(!this.doLayout){ dojo.addClass(this.domNode, "dijitTabContainerNoLayout"); }
+
+ if(this.nested){
+ /* workaround IE's lack of support for "a > b" selectors by
+ * tagging each node in the template.
+ */
+ dojo.addClass(this.domNode, "dijitTabContainerNested");
+ dojo.addClass(this.tablist.containerNode, "dijitTabContainerTabListNested");
+ dojo.addClass(this.tablistSpacer, "dijitTabContainerSpacerNested");
+ dojo.addClass(this.containerNode, "dijitTabPaneWrapperNested");
+ }else{
+ dojo.addClass(this.domNode, "tabStrip-" + (this.tabStrip ? "enabled" : "disabled"));
+ }
+ },
+
+ _setupChild: function(/*dijit._Widget*/ tab){
+ // Overrides StackContainer._setupChild().
+ dojo.addClass(tab.domNode, "dijitTabPane");
+ this.inherited(arguments);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ // wire up the tablist and its tabs
+ this.tablist.startup();
+
+ this.inherited(arguments);
+ },
+
+ layout: function(){
+ // Overrides StackContainer.layout().
+ // Configure the content pane to take up all the space except for where the tabs are
+
+ if(!this._contentBox || typeof(this._contentBox.l) == "undefined"){return;}
+
+ var sc = this.selectedChildWidget;
+
+ if(this.doLayout){
+ // position and size the titles and the container node
+ var titleAlign = this.tabPosition.replace(/-h/, "");
+ this.tablist.layoutAlign = titleAlign;
+ var children = [this.tablist, {
+ domNode: this.tablistSpacer,
+ layoutAlign: titleAlign
+ }, {
+ domNode: this.containerNode,
+ layoutAlign: "client"
+ }];
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, children);
+
+ // Compute size to make each of my children.
+ // children[2] is the margin-box size of this.containerNode, set by layoutChildren() call above
+ this._containerContentBox = dijit.layout.marginBox2contentBox(this.containerNode, children[2]);
+
+ if(sc && sc.resize){
+ sc.resize(this._containerContentBox);
+ }
+ }else{
+ // just layout the tab controller, so it can position left/right buttons etc.
+ if(this.tablist.resize){
+ //make the tabs zero width so that they don't interfere with width calc, then reset
+ var s = this.tablist.domNode.style;
+ s.width="0";
+ var width = dojo.contentBox(this.domNode).w;
+ s.width="";
+ this.tablist.resize({w: width});
+ }
+
+ // and call resize() on the selected pane just to tell it that it's been made visible
+ if(sc && sc.resize){
+ sc.resize();
+ }
+ }
+ },
+
+ destroy: function(){
+ if(this.tablist){
+ this.tablist.destroy();
+ }
+ this.inherited(arguments);
+ }
+});
+
}