summaryrefslogtreecommitdiff
path: root/includes/js/dijit/layout
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dijit/layout')
-rw-r--r--includes/js/dijit/layout/AccordionContainer.js229
-rw-r--r--includes/js/dijit/layout/BorderContainer.js515
-rw-r--r--includes/js/dijit/layout/ContentPane.js445
-rw-r--r--includes/js/dijit/layout/LayoutContainer.js74
-rw-r--r--includes/js/dijit/layout/LinkPane.js36
-rw-r--r--includes/js/dijit/layout/SplitContainer.js553
-rw-r--r--includes/js/dijit/layout/StackContainer.js493
-rw-r--r--includes/js/dijit/layout/TabContainer.js184
-rw-r--r--includes/js/dijit/layout/_LayoutWidget.js188
-rw-r--r--includes/js/dijit/layout/templates/AccordionPane.html11
-rw-r--r--includes/js/dijit/layout/templates/TabContainer.html4
-rw-r--r--includes/js/dijit/layout/templates/TooltipDialog.html6
-rw-r--r--includes/js/dijit/layout/templates/_TabButton.html10
13 files changed, 2748 insertions, 0 deletions
diff --git a/includes/js/dijit/layout/AccordionContainer.js b/includes/js/dijit/layout/AccordionContainer.js
new file mode 100644
index 0000000..12f8945
--- /dev/null
+++ b/includes/js/dijit/layout/AccordionContainer.js
@@ -0,0 +1,229 @@
+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.layout.StackContainer");
+dojo.require("dijit.layout.ContentPane");
+
+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.AccordionPane" title="pane 1">
+ // | <div dojoType="dijit.layout.ContentPane">...</div>
+ // | </div>
+ // | <div dojoType="dijit.layout.AccordionPane" title="pane 2">
+ // | <p>This is some text</p>
+ // || ...
+ // | </div>
+ //
+ // duration: Integer
+ // Amount of time (in ms) it takes to slide panes
+ duration: 250,
+
+ _verticalSpace: 0,
+
+ postCreate: function(){
+ this.domNode.style.overflow="hidden";
+ this.inherited("postCreate",arguments);
+ dijit.setWaiRole(this.domNode, "tablist");
+ dojo.addClass(this.domNode,"dijitAccordionContainer");
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ this.inherited("startup",arguments);
+ if(this.selectedChildWidget){
+ var style = this.selectedChildWidget.containerNode.style;
+ style.display = "";
+ style.overflow = "auto";
+ this.selectedChildWidget._setSelectedState(true);
+ }
+ },
+
+ layout: function(){
+ // summary:
+ // Set the height of the open pane based on what room remains
+
+ // get cumulative height of all the title bars, and figure out which pane is open
+ var totalCollapsedHeight = 0;
+ var openPane = this.selectedChildWidget;
+ dojo.forEach(this.getChildren(), function(child){
+ totalCollapsedHeight += child.getTitleHeight();
+ });
+ var mySize = this._contentBox;
+ this._verticalSpace = (mySize.h - totalCollapsedHeight);
+ if(openPane){
+ openPane.containerNode.style.height = this._verticalSpace + "px";
+/***
+TODO: this is wrong. probably you wanted to call resize on the SplitContainer
+inside the AccordionPane??
+ if(openPane.resize){
+ openPane.resize({h: this._verticalSpace});
+ }
+***/
+ }
+ },
+
+ _setupChild: function(/*Widget*/ page){
+ // Summary: prepare the given child
+ return page;
+ },
+
+ _transition: function(/*Widget?*/newWidget, /*Widget?*/oldWidget){
+//TODO: should be able to replace this with calls to slideIn/slideOut
+ if(this._inTransition){ return; }
+ this._inTransition = true;
+ var animations = [];
+ var paneHeight = this._verticalSpace;
+ if(newWidget){
+ newWidget.setSelected(true);
+ var newContents = newWidget.containerNode;
+ newContents.style.display = "";
+
+ animations.push(dojo.animateProperty({
+ node: newContents,
+ duration: this.duration,
+ properties: {
+ height: { start: "1", end: paneHeight }
+ },
+ onEnd: function(){
+ newContents.style.overflow = "auto";
+ }
+ }));
+ }
+ if(oldWidget){
+ oldWidget.setSelected(false);
+ var oldContents = oldWidget.containerNode;
+ oldContents.style.overflow = "hidden";
+ animations.push(dojo.animateProperty({
+ node: oldContents,
+ duration: this.duration,
+ properties: {
+ height: { start: paneHeight, end: "1" }
+ },
+ onEnd: function(){
+ oldContents.style.display = "none";
+ }
+ }));
+ }
+
+ this._inTransition = false;
+
+ dojo.fx.combine(animations).play();
+ },
+
+ // note: we are treating the container as controller here
+ _onKeyPress: function(/*Event*/ e){
+ if(this.disabled || e.altKey || !(e._dijitWidget || e.ctrlKey)){ return; }
+ var k = dojo.keys;
+ var fromTitle = e._dijitWidget;
+ switch(e.keyCode){
+ case k.LEFT_ARROW:
+ case k.UP_ARROW:
+ if (fromTitle){
+ this._adjacent(false)._onTitleClick();
+ dojo.stopEvent(e);
+ }
+ break;
+ case k.PAGE_UP:
+ if (e.ctrlKey){
+ this._adjacent(false)._onTitleClick();
+ dojo.stopEvent(e);
+ }
+ break;
+ case k.RIGHT_ARROW:
+ case k.DOWN_ARROW:
+ if (fromTitle){
+ this._adjacent(true)._onTitleClick();
+ dojo.stopEvent(e);
+ }
+ break;
+ case k.PAGE_DOWN:
+ if (e.ctrlKey){
+ this._adjacent(true)._onTitleClick();
+ dojo.stopEvent(e);
+ }
+ break;
+ default:
+ if(e.ctrlKey && e.keyCode == k.TAB){
+ this._adjacent(e._dijitWidget, !e.shiftKey)._onTitleClick();
+ dojo.stopEvent(e);
+ }
+
+ }
+ }
+ }
+);
+
+dojo.declare("dijit.layout.AccordionPane",
+ [dijit.layout.ContentPane, dijit._Templated, dijit._Contained],
+ {
+ // summary:
+ // AccordionPane is a ContentPane with a title that may contain another widget.
+ // Nested layout widgets, such as SplitContainer, are not supported at this time.
+ // example:
+ // | see dijit.layout.AccordionContainer
+
+ templateString:"<div class='dijitAccordionPane'\n\t><div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onTitleKeyPress,onfocus:_handleFocus,onblur:_handleFocus'\n\t\tclass='dijitAccordionTitle' wairole=\"tab\"\n\t\t><div class='dijitAccordionArrow' waiRole=\"presentation\"></div\n\t\t><div class='arrowTextUp' waiRole=\"presentation\">&#9650;</div\n\t\t><div class='arrowTextDown' waiRole=\"presentation\">&#9660;</div\n\t\t><div waiRole=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'>${title}</div></div\n\t><div><div dojoAttachPoint='containerNode' style='overflow: hidden; height: 1px; display: none'\n\t\tclass='dijitAccordionBody' wairole=\"tabpanel\"\n\t></div></div>\n</div>\n",
+
+ postCreate: function(){
+ this.inherited("postCreate",arguments)
+ dojo.setSelectable(this.titleNode, false);
+ this.setSelected(this.selected);
+ },
+
+ getTitleHeight: function(){
+ // summary: returns the height of the title dom node
+ return dojo.marginBox(this.titleNode).h; // Integer
+ },
+
+ _onTitleClick: function(){
+ // summary: callback when someone clicks my title
+ var parent = this.getParent();
+ if(!parent._inTransition){
+ parent.selectChild(this);
+ dijit.focus(this.focusNode);
+ }
+ },
+
+ _onTitleKeyPress: function(/*Event*/ evt){
+ evt._dijitWidget = this;
+ return this.getParent()._onKeyPress(evt);
+ },
+
+ _setSelectedState: function(/*Boolean*/ isSelected){
+ this.selected = isSelected;
+ dojo[(isSelected ? "addClass" : "removeClass")](this.titleNode,"dijitAccordionTitle-selected");
+ this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
+ },
+
+ _handleFocus: function(/*Event*/e){
+ // summary: handle the blur and focus state of this widget
+ dojo[(e.type=="focus" ? "addClass" : "removeClass")](this.focusNode,"dijitAccordionFocused");
+ },
+
+ setSelected: function(/*Boolean*/ isSelected){
+ // summary: change the selected state on this pane
+ this._setSelectedState(isSelected);
+ if(isSelected){
+ this.onSelected();
+ this._loadCheck(true); // if href specified, trigger load
+ }
+ },
+
+ onSelected: function(){
+ // summary: called when this pane is selected
+ }
+});
+
+}
diff --git a/includes/js/dijit/layout/BorderContainer.js b/includes/js/dijit/layout/BorderContainer.js
new file mode 100644
index 0000000..4419fe4
--- /dev/null
+++ b/includes/js/dijit/layout/BorderContainer.js
@@ -0,0 +1,515 @@
+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._Widget, dijit._Container, dijit._Contained],
+ dijit.layout._LayoutWidget,
+{
+ // summary:
+ // Provides layout in 5 regions, a center and borders along its 4 sides.
+ //
+ // description:
+ // A BorderContainer is a box with a specified size (like 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. 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.
+ // Optional splitters may be specified on the edge widgets only to make them resizable by the user.
+ //
+ // example:
+ // | <style>
+ // | html, body { height: 100%; width: 100%; }
+ // | </style>
+ // | <div dojoType="BorderContainer" design="sidebar" style="width: 100%; height: 100%">
+ // | <div dojoType="ContentPane" region="top">header text</div>
+ // | <div dojoType="ContentPane" region="right" style="width: 200px;">table of contents</div>
+ // | <div dojoType="ContentPane" region="center">client area</div>
+ // | </div>
+ //
+ // design: String
+ // choose which design is used for the layout: "headline" (default) where the top and bottom extend
+ // the full width of the container, or "sidebar" where the left and right sides extend from top to bottom.
+ design: "headline",
+
+ // liveSplitters: 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, // Boolean
+
+ // _splitterClass: String
+ // Optional hook to override the default Splitter widget used by BorderContainer
+ _splitterClass: "dijit.layout._Splitter",
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ this._splitters = {};
+ this._splitterThickness = {};
+ dojo.addClass(this.domNode, "dijitBorderContainer");
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ dojo.forEach(this.getChildren(), this._setupChild, this);
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*Widget*/child){
+ var region = child.region;
+ if(region){
+// dojo.addClass(child.domNode, "dijitBorderContainerPane");
+ child.domNode.style.position = "absolute"; // bill says not to set this in CSS, since we can't keep others
+ // from destroying the class list
+
+ var ltr = this.isLeftToRight();
+ if(region == "leading"){ region = ltr ? "left" : "right"; }
+ if(region == "trailing"){ region = ltr ? "right" : "left"; }
+
+ this["_"+region] = child.domNode;
+ this["_"+region+"Widget"] = child;
+
+ if(child.splitter){
+ var _Splitter = dojo.getObject(this._splitterClass);
+ var flip = {left:'right', right:'left', top:'bottom', bottom:'top', leading:'trailing', trailing:'leading'};
+ var oppNodeList = dojo.query('[region=' + flip[child.region] + ']', this.domNode);
+ var splitter = new _Splitter({ container: this, child: child, region: region,
+ oppNode: oppNodeList[0], live: this.liveSplitters });
+ this._splitters[region] = splitter.domNode;
+ dojo.place(splitter.domNode, child.domNode, "after");
+ this._computeSplitterThickness(region);
+ }
+ child.region = region;
+ }
+ },
+
+ _computeSplitterThickness: function(region){
+ var re = new RegExp("top|bottom");
+ this._splitterThickness[region] =
+ dojo.marginBox(this._splitters[region])[(re.test(region) ? 'h' : 'w')];
+ },
+
+ layout: function(){
+ this._layoutChildren();
+ },
+
+ addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){
+ this.inherited(arguments);
+ this._setupChild(child);
+ if(this._started){
+ this._layoutChildren(); //OPT
+ }
+ },
+
+ removeChild: function(/*Widget*/ child){
+ var region = child.region;
+ var splitter = this._splitters[region];
+ if(splitter){
+ dijit.byNode(splitter).destroy();
+ delete this._splitters[region];
+ delete this._splitterThickness[region];
+ }
+ this.inherited(arguments);
+ delete this["_"+region];
+ delete this["_" +region+"Widget"];
+ if(this._started){
+ this._layoutChildren(child.region);
+ }
+ },
+
+ _layoutChildren: function(/*String?*/changedRegion){
+ var sidebarLayout = (this.design == "sidebar");
+ var topHeight = 0, bottomHeight = 0, leftWidth = 0, rightWidth = 0;
+ var topStyle = {}, leftStyle = {}, rightStyle = {}, bottomStyle = {},
+ centerStyle = (this._center && this._center.style) || {};
+
+ var changedSide = /left|right/.test(changedRegion);
+
+ var layoutSides = !changedRegion || (!changedSide && !sidebarLayout);
+ var layoutTopBottom = !changedRegion || (changedSide && sidebarLayout);
+ if(this._top){
+ topStyle = layoutTopBottom && this._top.style;
+ topHeight = dojo.marginBox(this._top).h;
+ }
+ if(this._left){
+ leftStyle = layoutSides && this._left.style;
+ leftWidth = dojo.marginBox(this._left).w;
+ }
+ if(this._right){
+ rightStyle = layoutSides && this._right.style;
+ rightWidth = dojo.marginBox(this._right).w;
+ }
+ if(this._bottom){
+ bottomStyle = layoutTopBottom && this._bottom.style;
+ bottomHeight = dojo.marginBox(this._bottom).h;
+ }
+
+ var splitters = this._splitters;
+ var topSplitter = splitters.top;
+ var bottomSplitter = splitters.bottom;
+ var leftSplitter = splitters.left;
+ var rightSplitter = splitters.right;
+ var splitterThickness = this._splitterThickness;
+ var topSplitterThickness = splitterThickness.top || 0;
+ var leftSplitterThickness = splitterThickness.left || 0;
+ var rightSplitterThickness = splitterThickness.right || 0;
+ var bottomSplitterThickness = splitterThickness.bottom || 0;
+
+ // Check for race condition where CSS hasn't finished loading, so
+ // the splitter width == the viewport width (#5824)
+ if(leftSplitterThickness > 50 || rightSplitterThickness > 50){
+ setTimeout(dojo.hitch(this, function(){
+ for(var region in this._splitters){
+ this._computeSplitterThickness(region);
+ }
+ this._layoutChildren();
+ }), 50);
+ return false;
+ }
+
+ var splitterBounds = {
+ left: (sidebarLayout ? leftWidth + leftSplitterThickness: "0") + "px",
+ right: (sidebarLayout ? rightWidth + rightSplitterThickness: "0") + "px"
+ };
+
+ if(topSplitter){
+ dojo.mixin(topSplitter.style, splitterBounds);
+ topSplitter.style.top = topHeight + "px";
+ }
+
+ if(bottomSplitter){
+ dojo.mixin(bottomSplitter.style, splitterBounds);
+ bottomSplitter.style.bottom = bottomHeight + "px";
+ }
+
+ splitterBounds = {
+ top: (sidebarLayout ? "0" : topHeight + topSplitterThickness) + "px",
+ bottom: (sidebarLayout ? "0" : bottomHeight + bottomSplitterThickness) + "px"
+ };
+
+ if(leftSplitter){
+ dojo.mixin(leftSplitter.style, splitterBounds);
+ leftSplitter.style.left = leftWidth + "px";
+ }
+
+ if(rightSplitter){
+ dojo.mixin(rightSplitter.style, splitterBounds);
+ rightSplitter.style.right = rightWidth + "px";
+ }
+
+ dojo.mixin(centerStyle, {
+ top: topHeight + topSplitterThickness + "px",
+ left: leftWidth + leftSplitterThickness + "px",
+ right: rightWidth + rightSplitterThickness + "px",
+ bottom: bottomHeight + bottomSplitterThickness + "px"
+ });
+
+ var bounds = {
+ top: sidebarLayout ? "0" : centerStyle.top,
+ bottom: sidebarLayout ? "0" : centerStyle.bottom
+ };
+ dojo.mixin(leftStyle, bounds);
+ dojo.mixin(rightStyle, bounds);
+ leftStyle.left = rightStyle.right = topStyle.top = bottomStyle.bottom = "0";
+ if(sidebarLayout){
+ topStyle.left = bottomStyle.left = leftWidth + (this.isLeftToRight() ? leftSplitterThickness : 0) + "px";
+ topStyle.right = bottomStyle.right = rightWidth + (this.isLeftToRight() ? 0 : rightSplitterThickness) + "px";
+ }else{
+ topStyle.left = topStyle.right = bottomStyle.left = bottomStyle.right = "0";
+ }
+
+ // Nodes in IE respond to t/l/b/r, and TEXTAREA doesn't respond in any browser
+ var janky = dojo.isIE || dojo.some(this.getChildren(), function(child){
+ return child.domNode.tagName == "TEXTAREA";
+ });
+ if(janky){
+ // Set the size of the children the old fashioned way, by calling
+ // childNode.resize({h: int, w: int}) for each child node)
+
+ var borderBox = function(n, b){
+ n=dojo.byId(n);
+ var s = dojo.getComputedStyle(n);
+ if(!b){ return dojo._getBorderBox(n, s); }
+ var me = dojo._getMarginExtents(n, s);
+ dojo._setMarginBox(n, b.l, b.t, b.w + me.w, b.h + me.h, s);
+ return null;
+ };
+
+ var resizeWidget = function(widget, dim){
+ if(widget){
+ widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
+ }
+ };
+
+ // TODO: use dim passed in to resize() (see _LayoutWidget.js resize())
+ // Then can make borderBox setBorderBox(), since no longer need to ever get the borderBox() size
+ var thisBorderBox = borderBox(this.domNode);
+
+ var containerHeight = thisBorderBox.h;
+ var middleHeight = containerHeight;
+ if(this._top){ middleHeight -= topHeight; }
+ if(this._bottom){ middleHeight -= bottomHeight; }
+ if(topSplitter){ middleHeight -= topSplitterThickness; }
+ if(bottomSplitter){ middleHeight -= bottomSplitterThickness; }
+ var centerDim = { h: middleHeight };
+
+ var sidebarHeight = sidebarLayout ? containerHeight : middleHeight;
+ if(leftSplitter){ leftSplitter.style.height = sidebarHeight; }
+ if(rightSplitter){ rightSplitter.style.height = sidebarHeight; }
+ resizeWidget(this._leftWidget, {h: sidebarHeight});
+ resizeWidget(this._rightWidget, {h: sidebarHeight});
+
+ var containerWidth = thisBorderBox.w;
+ var middleWidth = containerWidth;
+ if(this._left){ middleWidth -= leftWidth; }
+ if(this._right){ middleWidth -= rightWidth; }
+ if(leftSplitter){ middleWidth -= leftSplitterThickness; }
+ if(rightSplitter){ middleWidth -= rightSplitterThickness; }
+ centerDim.w = middleWidth;
+
+ var sidebarWidth = sidebarLayout ? middleWidth : containerWidth;
+ if(topSplitter){ topSplitter.style.width = sidebarWidth; }
+ if(bottomSplitter){ bottomSplitter.style.width = sidebarWidth; }
+ resizeWidget(this._topWidget, {w: sidebarWidth});
+ resizeWidget(this._bottomWidget, {w: sidebarWidth});
+
+ resizeWidget(this._centerWidget, centerDim);
+ }else{
+
+ // We've already sized the children by setting style.top/bottom/left/right...
+ // Now just need to call resize() on those children so they can re-layout themselves
+
+ // TODO: calling child.resize() without an argument is bad, because it forces
+ // the child to query it's own size (even though this function already knows
+ // the size), plus which querying the size of a node right after setting it
+ // is known to cause problems (incorrect answer or an exception).
+ // This is a setback from older layout widgets, which
+ // don't do that. See #3399, #2678, #3624 and #2955, #1988
+
+ var resizeList = {};
+ if(changedRegion){
+ resizeList[changedRegion] = resizeList.center = true;
+ if(/top|bottom/.test(changedRegion) && this.design != "sidebar"){
+ resizeList.left = resizeList.right = true;
+ }else if(/left|right/.test(changedRegion) && this.design == "sidebar"){
+ resizeList.top = resizeList.bottom = true;
+ }
+ }
+
+ dojo.forEach(this.getChildren(), function(child){
+ if(child.resize && (!changedRegion || child.region in resizeList)){
+ // console.log(this.id, ": resizing child id=" + child.id + " (region=" + child.region + "), style before resize is " +
+ // "{ t: " + child.domNode.style.top +
+ // ", b: " + child.domNode.style.bottom +
+ // ", l: " + child.domNode.style.left +
+ // ", r: " + child.domNode.style.right +
+ // ", w: " + child.domNode.style.width +
+ // ", h: " + child.domNode.style.height +
+ // "}"
+ // );
+ child.resize();
+ // console.log(this.id, ": after resize of child id=" + child.id + " (region=" + child.region + ") " +
+ // "{ t: " + child.domNode.style.top +
+ // ", b: " + child.domNode.style.bottom +
+ // ", l: " + child.domNode.style.left +
+ // ", r: " + child.domNode.style.right +
+ // ", w: " + child.domNode.style.width +
+ // ", h: " + child.domNode.style.height +
+ // "}"
+ // );
+ }
+ }, this);
+ }
+ }
+});
+
+// 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: String
+ // "top", "bottom", "leading", "trailing", "left", "right", "center".
+ // See the BorderContainer description for details on this parameter.
+ region: '',
+
+ // splitter: Boolean
+ splitter: false,
+
+ // minSize: Number
+ minSize: 0,
+
+ // maxSize: Number
+ maxSize: Infinity
+});
+
+dojo.require("dijit._Templated");
+
+dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
+{
+/*=====
+ container: null,
+ child: null,
+ region: null,
+=====*/
+
+ // live: 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,
+
+ // summary: A draggable spacer between two items in a BorderContainer
+ templateString: '<div class="dijitSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag" 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"));
+// dojo.addClass(this.child.domNode, "dijitSplitterPane");
+// dojo.setSelectable(this.domNode, false); //TODO is this necessary?
+
+ this._factor = /top|left/.test(this.region) ? 1 : -1;
+ this._minSize = this.child.minSize;
+
+ this._computeMaxSize();
+ //TODO: might be more accurate to recompute constraints on resize?
+ this.connect(this.container, "layout", dojo.hitch(this, this._computeMaxSize));
+
+ this._cookieName = this.container.id + "_" + this.region;
+ 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(){
+ var dim = this.horizontal ? 'h' : 'w';
+ var available = dojo.contentBox(this.container.domNode)[dim] - (this.oppNode ? dojo.marginBox(this.oppNode)[dim] : 0);
+ this._maxSize = Math.min(this.child.maxSize, available);
+ },
+
+ _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");
+ }else{
+ this.cover.style.zIndex = 1;
+ }
+
+ // Safeguard in case the stop event was missed. Shouldn't be necessary if we always get the mouse up.
+ if(this.fake){ dojo._destroyElement(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");
+
+ //Performance: load data info local vars for onmousevent function closure
+ var factor = this._factor,
+ max = this._maxSize,
+ min = this._minSize || 10;
+ var axis = this.horizontal ? "pageY" : "pageX";
+ var pageStart = e[axis];
+ var splitterStyle = this.domNode.style;
+ var dim = this.horizontal ? 'h' : 'w';
+ var childStart = dojo.marginBox(this.child.domNode)[dim];
+ var splitterStart = parseInt(this.domNode.style[this.region]);
+ var resize = this._resize;
+ var region = this.region;
+ var mb = {};
+ var childNode = this.child.domNode;
+ var layoutFunc = dojo.hitch(this.container, this.container._layoutChildren);
+
+ var de = dojo.doc.body;
+ 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){
+ mb[dim] = boundChildSize;
+ // TODO: inefficient; we set the marginBox here and then immediately layoutFunc() needs to query it
+ dojo.marginBox(childNode, mb);
+ layoutFunc(region);
+ }
+ splitterStyle[region] = factor * delta + splitterStart + (boundChildSize - childSize) + "px";
+ }),
+ dojo.connect(de, "onmouseup", this, "_stopDrag")
+ ]);
+ dojo.stopEvent(e);
+ },
+
+ _stopDrag: function(e){
+ try{
+ if(this.cover){ this.cover.style.zIndex = -1; }
+ if(this.fake){ dojo._destroyElement(this.fake); }
+ dojo.removeClass(this.domNode, "dijitSplitterActive");
+ dojo.removeClass(this.domNode, "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"]);
+ }
+ },
+
+ _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.keyCode){
+ 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.marginBox(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
+ var mb = {};
+ mb[ this.horizontal ? "h" : "w"] = Math.max(Math.min(childSize, this._maxSize), this._minSize);
+ dojo.marginBox(this.child.domNode, mb);
+ this.container._layoutChildren(this.region);
+ dojo.stopEvent(e);
+ },
+
+ destroy: function(){
+ this._cleanupHandlers();
+ delete this.child;
+ delete this.container;
+ delete this.fake;
+ this.inherited(arguments);
+ }
+});
+
+}
diff --git a/includes/js/dijit/layout/ContentPane.js b/includes/js/dijit/layout/ContentPane.js
new file mode 100644
index 0000000..c3a4ca4
--- /dev/null
+++ b/includes/js/dijit/layout/ContentPane.js
@@ -0,0 +1,445 @@
+if(!dojo._hasResource["dijit.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.ContentPane"] = true;
+dojo.provide("dijit.layout.ContentPane");
+
+dojo.require("dijit._Widget");
+dojo.require("dijit.layout._LayoutWidget");
+
+dojo.require("dojo.parser");
+dojo.require("dojo.string");
+dojo.requireLocalization("dijit", "loading", null, "zh,pt,da,tr,ru,ROOT,de,sv,ja,he,fi,nb,el,ar,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu");
+
+dojo.declare(
+ "dijit.layout.ContentPane",
+ dijit._Widget,
+{
+ // summary:
+ // A widget that acts as a Container for other widgets, and includes a ajax interface
+ // description:
+ // A widget that can be used as a standalone widget
+ // or as a baseclass for other widgets
+ // Handles replacement of document fragment using either external uri or javascript
+ // generated markup or DOM content, instantiating widgets within that content.
+ // Don't confuse it with an iframe, it only needs/wants document fragments.
+ // It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
+ // But note that those classes can contain any widget as a child.
+ // example:
+ // Some quick samples:
+ // To change the innerHTML use .setContent('<b>new content</b>')
+ //
+ // Or you can send it a NodeList, .setContent(dojo.query('div [class=selected]', userSelection))
+ // please note that the nodes in NodeList will copied, not moved
+ //
+ // To do a ajax update use .setHref('url')
+ //
+ // href: String
+ // The href of the content that displays now.
+ // Set this at construction if you want to load data externally when the
+ // pane is shown. (Set preload=true to load it immediately.)
+ // Changing href after creation doesn't have any effect; see setHref();
+ href: "",
+
+ // extractContent: Boolean
+ // Extract visible content from inside of <body> .... </body>
+ extractContent: false,
+
+ // parseOnLoad: Boolean
+ // parse content and create the widgets, if any
+ parseOnLoad: true,
+
+ // preventCache: Boolean
+ // Cache content retreived externally
+ preventCache: false,
+
+ // preload: Boolean
+ // Force load of data even if pane is hidden.
+ preload: false,
+
+ // refreshOnShow: Boolean
+ // Refresh (re-download) content when pane goes from hidden to shown
+ refreshOnShow: false,
+
+ // loadingMessage: String
+ // Message that shows while downloading
+ loadingMessage: "<span class='dijitContentPaneLoading'>${loadingState}</span>",
+
+ // errorMessage: String
+ // Message that shows if an error occurs
+ errorMessage: "<span class='dijitContentPaneError'>${errorState}</span>",
+
+ // isLoaded: Boolean
+ // Tells loading status see onLoad|onUnload for event hooks
+ isLoaded: false,
+
+ // class: String
+ // Class name to apply to ContentPane dom nodes
+ // TODO: this should be called "baseClass" like in the other widgets
+ "class": "dijitContentPane",
+
+ // doLayout: String/Boolean
+ // false - don't adjust size of children
+ // true - looks for the first sizable child widget (ie, having resize() method) and sets it's size to
+ // however big the ContentPane is (TODO: implement)
+ // auto - if there is a single sizable child widget (ie, having resize() method), set it's size to
+ // however big the ContentPane is
+ doLayout: "auto",
+
+ postCreate: function(){
+ // remove the title attribute so it doesn't show up when i hover
+ // over a node
+ this.domNode.title = "";
+
+ if(!this.containerNode){
+ // make getDescendants() work
+ this.containerNode = this.domNode;
+ }
+
+ if(this.preload){
+ this._loadCheck();
+ }
+
+ var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
+ this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
+ this.errorMessage = dojo.string.substitute(this.errorMessage, messages);
+ var curRole = dijit.getWaiRole(this.domNode);
+ if (!curRole){
+ dijit.setWaiRole(this.domNode, "group");
+ }
+
+ // for programatically created ContentPane (with <span> tag), need to muck w/CSS
+ // or it's as though overflow:visible is set
+ dojo.addClass(this.domNode, this["class"]);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ if(this.doLayout != "false" && this.doLayout !== false){
+ this._checkIfSingleChild();
+ if(this._singleChild){
+ this._singleChild.startup();
+ }
+ }
+ this._loadCheck();
+ this.inherited(arguments);
+ },
+
+ _checkIfSingleChild: function(){
+ // summary:
+ // Test if we have exactly one widget as a child, and if so assume that we are a container for that widget,
+ // and should propogate startup() and resize() calls to it.
+
+ // TODO: if there are two child widgets (a data store and a TabContainer, for example),
+ // should still find the TabContainer
+ var childNodes = dojo.query(">", this.containerNode || this.domNode),
+ childWidgets = childNodes.filter("[widgetId]");
+
+ if(childNodes.length == 1 && childWidgets.length == 1){
+ this.isContainer = true;
+ this._singleChild = dijit.byNode(childWidgets[0]);
+ }else{
+ delete this.isContainer;
+ delete this._singleChild;
+ }
+ },
+
+ refresh: function(){
+ // summary:
+ // Force a refresh (re-download) of content, be sure to turn off cache
+
+ // we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
+ return this._prepareLoad(true);
+ },
+
+ setHref: function(/*String|Uri*/ href){
+ // summary:
+ // Reset the (external defined) content of this pane and replace with new url
+ // Note: It delays the download until widget is shown if preload is false
+ // href:
+ // url to the page you want to get, must be within the same domain as your mainpage
+ this.href = href;
+
+ // we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
+ return this._prepareLoad();
+ },
+
+ setContent: function(/*String|DomNode|Nodelist*/data){
+ // summary:
+ // Replaces old content with data content, include style classes from old content
+ // data:
+ // the new Content may be String, DomNode or NodeList
+ //
+ // if data is a NodeList (or an array of nodes) nodes are copied
+ // so you can import nodes from another document implicitly
+
+ // clear href so we cant run refresh and clear content
+ // refresh should only work if we downloaded the content
+ if(!this._isDownloaded){
+ this.href = "";
+ this._onUnloadHandler();
+ }
+
+ this._setContent(data || "");
+
+ this._isDownloaded = false; // must be set after _setContent(..), pathadjust in dojox.layout.ContentPane
+
+ if(this.parseOnLoad){
+ this._createSubWidgets();
+ }
+
+ if(this.doLayout != "false" && this.doLayout !== false){
+ this._checkIfSingleChild();
+ if(this._singleChild && this._singleChild.resize){
+ this._singleChild.startup();
+ this._singleChild.resize(this._contentBox || dojo.contentBox(this.containerNode || this.domNode));
+ }
+ }
+
+ this._onLoadHandler();
+ },
+
+ cancel: function(){
+ // summary:
+ // Cancels a inflight download of content
+ if(this._xhrDfd && (this._xhrDfd.fired == -1)){
+ this._xhrDfd.cancel();
+ }
+ delete this._xhrDfd; // garbage collect
+ },
+
+ destroy: function(){
+ // if we have multiple controllers destroying us, bail after the first
+ if(this._beingDestroyed){
+ return;
+ }
+ // make sure we call onUnload
+ this._onUnloadHandler();
+ this._beingDestroyed = true;
+ this.inherited("destroy",arguments);
+ },
+
+ resize: function(size){
+ dojo.marginBox(this.domNode, size);
+
+ // Compute content box size in case we [later] need to size child
+ // If either height or width wasn't specified by the user, then query node for it.
+ // But note that setting the margin box and then immediately querying dimensions may return
+ // inaccurate results, so try not to depend on it.
+ var node = this.containerNode || this.domNode,
+ mb = dojo.mixin(dojo.marginBox(node), size||{});
+
+ this._contentBox = dijit.layout.marginBox2contentBox(node, mb);
+
+ // If we have a single widget child then size it to fit snugly within my borders
+ if(this._singleChild && this._singleChild.resize){
+ this._singleChild.resize(this._contentBox);
+ }
+ },
+
+ _prepareLoad: function(forceLoad){
+ // sets up for a xhrLoad, load is deferred until widget onShow
+ // cancels a inflight download
+ this.cancel();
+ this.isLoaded = false;
+ this._loadCheck(forceLoad);
+ },
+
+ _isShown: function(){
+ // summary: returns true if the content is currently shown
+ if("open" in this){
+ return this.open; // for TitlePane, etc.
+ }else{
+ var node = this.domNode;
+ return (node.style.display != 'none') && (node.style.visibility != 'hidden');
+ }
+ },
+
+ _loadCheck: function(/*Boolean*/ forceLoad){
+ // call this when you change onShow (onSelected) status when selected in parent container
+ // it's used as a trigger for href download when this.domNode.display != 'none'
+
+ // sequence:
+ // if no href -> bail
+ // forceLoad -> always load
+ // this.preload -> load when download not in progress, domNode display doesn't matter
+ // this.refreshOnShow -> load when download in progress bails, domNode display !='none' AND
+ // this.open !== false (undefined is ok), isLoaded doesn't matter
+ // else -> load when download not in progress, if this.open !== false (undefined is ok) AND
+ // domNode display != 'none', isLoaded must be false
+
+ var displayState = this._isShown();
+
+ if(this.href &&
+ (forceLoad ||
+ (this.preload && !this._xhrDfd) ||
+ (this.refreshOnShow && displayState && !this._xhrDfd) ||
+ (!this.isLoaded && displayState && !this._xhrDfd)
+ )
+ ){
+ this._downloadExternalContent();
+ }
+ },
+
+ _downloadExternalContent: function(){
+ this._onUnloadHandler();
+
+ // display loading message
+ this._setContent(
+ this.onDownloadStart.call(this)
+ );
+
+ var self = this;
+ var getArgs = {
+ preventCache: (this.preventCache || this.refreshOnShow),
+ url: this.href,
+ handleAs: "text"
+ };
+ if(dojo.isObject(this.ioArgs)){
+ dojo.mixin(getArgs, this.ioArgs);
+ }
+
+ var hand = this._xhrDfd = (this.ioMethod || dojo.xhrGet)(getArgs);
+
+ hand.addCallback(function(html){
+ try{
+ self.onDownloadEnd.call(self);
+ self._isDownloaded = true;
+ self.setContent.call(self, html); // onload event is called from here
+ }catch(err){
+ self._onError.call(self, 'Content', err); // onContentError
+ }
+ delete self._xhrDfd;
+ return html;
+ });
+
+ hand.addErrback(function(err){
+ if(!hand.cancelled){
+ // show error message in the pane
+ self._onError.call(self, 'Download', err); // onDownloadError
+ }
+ delete self._xhrDfd;
+ return err;
+ });
+ },
+
+ _onLoadHandler: function(){
+ this.isLoaded = true;
+ try{
+ this.onLoad.call(this);
+ }catch(e){
+ console.error('Error '+this.widgetId+' running custom onLoad code');
+ }
+ },
+
+ _onUnloadHandler: function(){
+ this.isLoaded = false;
+ this.cancel();
+ try{
+ this.onUnload.call(this);
+ }catch(e){
+ console.error('Error '+this.widgetId+' running custom onUnload code');
+ }
+ },
+
+ _setContent: function(cont){
+ this.destroyDescendants();
+
+ try{
+ var node = this.containerNode || this.domNode;
+ while(node.firstChild){
+ dojo._destroyElement(node.firstChild);
+ }
+ if(typeof cont == "string"){
+ // dijit.ContentPane does only minimal fixes,
+ // No pathAdjustments, script retrieval, style clean etc
+ // some of these should be available in the dojox.layout.ContentPane
+ if(this.extractContent){
+ match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+ if(match){ cont = match[1]; }
+ }
+ node.innerHTML = cont;
+ }else{
+ // domNode or NodeList
+ if(cont.nodeType){ // domNode (htmlNode 1 or textNode 3)
+ node.appendChild(cont);
+ }else{// nodelist or array such as dojo.Nodelist
+ dojo.forEach(cont, function(n){
+ node.appendChild(n.cloneNode(true));
+ });
+ }
+ }
+ }catch(e){
+ // check if a domfault occurs when we are appending this.errorMessage
+ // like for instance if domNode is a UL and we try append a DIV
+ var errMess = this.onContentError(e);
+ try{
+ node.innerHTML = errMess;
+ }catch(e){
+ console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
+ }
+ }
+ },
+
+ _onError: function(type, err, consoleText){
+ // shows user the string that is returned by on[type]Error
+ // overide on[type]Error and return your own string to customize
+ var errText = this['on' + type + 'Error'].call(this, err);
+ if(consoleText){
+ console.error(consoleText, err);
+ }else if(errText){// a empty string won't change current content
+ this._setContent.call(this, errText);
+ }
+ },
+
+ _createSubWidgets: function(){
+ // summary: scan my contents and create subwidgets
+ var rootNode = this.containerNode || this.domNode;
+ try{
+ dojo.parser.parse(rootNode, true);
+ }catch(e){
+ this._onError('Content', e, "Couldn't create widgets in "+this.id
+ +(this.href ? " from "+this.href : ""));
+ }
+ },
+
+ // EVENT's, should be overide-able
+ onLoad: function(e){
+ // summary:
+ // Event hook, is called after everything is loaded and widgetified
+ },
+
+ onUnload: function(e){
+ // summary:
+ // Event hook, is called before old content is cleared
+ },
+
+ onDownloadStart: function(){
+ // summary:
+ // called before download starts
+ // the string returned by this function will be the html
+ // that tells the user we are loading something
+ // override with your own function if you want to change text
+ return this.loadingMessage;
+ },
+
+ onContentError: function(/*Error*/ error){
+ // summary:
+ // called on DOM faults, require fault etc in content
+ // default is to display errormessage inside pane
+ },
+
+ onDownloadError: function(/*Error*/ error){
+ // summary:
+ // Called when download error occurs, default is to display
+ // errormessage inside pane. Overide function to change that.
+ // The string returned by this function will be the html
+ // that tells the user a error happend
+ return this.errorMessage;
+ },
+
+ onDownloadEnd: function(){
+ // summary:
+ // called when download is finished
+ }
+});
+
+}
diff --git a/includes/js/dijit/layout/LayoutContainer.js b/includes/js/dijit/layout/LayoutContainer.js
new file mode 100644
index 0000000..11b8c9f
--- /dev/null
+++ b/includes/js/dijit/layout/LayoutContainer.js
@@ -0,0 +1,74 @@
+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,
+ {
+ // summary:
+ // Provides Delphi-style panel layout semantics.
+ //
+ // description:
+ // 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.
+ //
+
+ 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(/*Widget*/ child, /*Integer?*/ insertIndex){
+ dijit._Container.prototype.addChild.apply(this, arguments);
+ if(this._started){
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
+ }
+ },
+
+ removeChild: function(/*Widget*/ widget){
+ dijit._Container.prototype.removeChild.apply(this, 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/includes/js/dijit/layout/LinkPane.js b/includes/js/dijit/layout/LinkPane.js
new file mode 100644
index 0000000..cddaaee
--- /dev/null
+++ b/includes/js/dijit/layout/LinkPane.js
@@ -0,0 +1,36 @@
+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],
+ {
+ // summary:
+ // A ContentPane that loads data remotely
+ // description:
+ // LinkPane is just a ContentPane that loads data remotely (via the href attribute),
+ // and has markup similar 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"></div>',
+
+ postCreate: 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("postCreate",arguments);
+ }
+});
+
+}
diff --git a/includes/js/dijit/layout/SplitContainer.js b/includes/js/dijit/layout/SplitContainer.js
new file mode 100644
index 0000000..671d1fc
--- /dev/null
+++ b/includes/js/dijit/layout/SplitContainer.js
@@ -0,0 +1,553 @@
+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");
+
+//
+// FIXME: make it prettier
+// FIXME: active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
+//
+
+dojo.require("dojo.cookie");
+dojo.require("dijit.layout._LayoutWidget");
+
+dojo.declare("dijit.layout.SplitContainer",
+ dijit.layout._LayoutWidget,
+ {
+ // summary:
+ // A Container widget with sizing handles in-between each child
+ // description:
+ // 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.
+
+ 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,
+
+ postMixInProperties: function(){
+ this.inherited("postMixInProperties",arguments);
+ this.isHorizontal = (this.orientation == 'horizontal');
+ },
+
+ postCreate: function(){
+ this.inherited("postCreate",arguments);
+ this.sizers = [];
+ dojo.addClass(this.domNode, "dijitSplitContainer");
+ // 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 = this.virtualSizer = dojo.doc.createElement('div');
+ 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._injectChild(child);
+
+ if(i < children.length-1){
+ this._addSizer();
+ }
+ }, this);
+
+ if(this.persist){
+ this._restoreState();
+ }
+
+ this.inherited(arguments);
+ },
+
+ _injectChild: function(child){
+ child.domNode.style.position = "absolute";
+ dojo.addClass(child.domNode, "dijitSplitPane");
+ },
+
+ _addSizer: function(){
+ var i = this.sizers.length;
+
+ // TODO: use a template for this!!!
+ var sizer = this.sizers[i] = dojo.doc.createElement('div');
+ 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?
+ var self = this;
+ var handler = (function(){ var sizer_i = i; return function(e){ self.beginSizing(e, sizer_i); } })();
+ this.connect(sizer, "onmousedown", handler);
+
+ 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._destroyElement(this.sizers[i]);
+ this.sizers.splice(i,1);
+ }
+ }
+
+ // Remove widget and repaint
+ this.inherited(arguments);
+ if(this._started){
+ this.layout();
+ }
+ },
+
+ addChild: function(/*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("addChild",arguments);
+
+ if(this._started){
+ // Do the stuff that startup() does for each widget
+ this._injectChild(child);
+ var children = this.getChildren();
+ if(children.length > 1){
+ this._addSizer();
+ }
+
+ // 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.doc.createElement('div');
+ this.domNode.appendChild(this.cover);
+ var s = this.cover.style;
+ s.position = 'absolute';
+ s.zIndex = 1;
+ s.top = 0;
+ s.left = 0;
+ s.width = "100%";
+ s.height = "100%";
+ }else{
+ this.cover.style.zIndex = 1;
+ }
+ this.sizingSplitter.style.zIndex = 2;
+
+ // 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.coords(children[0].domNode, true);
+ if(this.isHorizontal){
+ var client = (e.layerX ? e.layerX : e.offsetX);
+ var screen = e.pageX;
+ this.originPos = this.originPos.x;
+ }else{
+ var client = (e.layerY ? e.layerY : e.offsetY);
+ 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(){
+ dojo.forEach(this.getChildren(), function(child, i){
+ dojo.cookie(this._getCookieName(i), child.sizeShare);
+ }, this);
+ }
+});
+
+// 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: Integer
+ // Minimum size (width or height) of a child of a SplitContainer.
+ // The value is relative to other children's sizeShare properties.
+ sizeMin: 10,
+
+ // sizeShare: Integer
+ // 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
+});
+
+}
diff --git a/includes/js/dijit/layout/StackContainer.js b/includes/js/dijit/layout/StackContainer.js
new file mode 100644
index 0000000..3119972
--- /dev/null
+++ b/includes/js/dijit/layout/StackContainer.js
@@ -0,0 +1,493 @@
+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.require("dijit.form.Button");
+dojo.require("dijit.Menu");
+dojo.requireLocalization("dijit", "common", null, "zh,pt,da,tr,ru,de,sv,ja,he,fi,nb,el,ar,ROOT,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu");
+
+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,
+
+ _started: false,
+/*=====
+ // selectedChildWidget: Widget
+ // References the currently selected child widget, if any
+ //
+ selectedChildWidget: null,
+=====*/
+ postCreate: function(){
+ dijit.setWaiRole((this.containerNode || this.domNode), "tabpanel");
+ this.connect(this.domNode, "onkeypress", this._onKeyPress);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ var children = this.getChildren();
+
+ // Setup each page panel
+ dojo.forEach(children, this._setupChild, this);
+
+ // Figure out which child to initially display
+ dojo.some(children, function(child){
+ if(child.selected){
+ this.selectedChildWidget = child;
+ }
+ return child.selected;
+ }, this);
+
+ var selected = this.selectedChildWidget;
+
+ // Default to the first child
+ if(!selected && children[0]){
+ selected = this.selectedChildWidget = children[0];
+ selected.selected = true;
+ }
+ if(selected){
+ this._showChild(selected);
+ }
+
+ // Now publish information about myself so any StackControllers can initialize..
+ dojo.publish(this.id+"-startup", [{children: children, selected: selected}]);
+
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*Widget*/ page){
+ // Summary: prepare the given child
+
+ page.domNode.style.display = "none";
+
+ // since we are setting the width/height of the child elements, they need
+ // to be position:relative, or IE has problems (See bug #2033)
+ page.domNode.style.position = "relative";
+
+ return page; // dijit._Widget
+ },
+
+ addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){
+ // summary: Adds a widget to the stack
+
+ dijit._Container.prototype.addChild.apply(this, arguments);
+ child = this._setupChild(child);
+
+ if(this._started){
+ // in case the tab titles have overflowed from one line to two lines
+ this.layout();
+
+ dojo.publish(this.id+"-addChild", [child, insertIndex]);
+
+ // if this is the first child, then select it
+ if(!this.selectedChildWidget){
+ this.selectChild(child);
+ }
+ }
+ },
+
+ removeChild: function(/*Widget*/ page){
+ // summary: Removes the pane from the stack
+
+ dijit._Container.prototype.removeChild.apply(this, arguments);
+
+ // 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; }
+
+ 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]);
+
+ // in case the tab titles now take up one line instead of two lines
+ this.layout();
+ }
+
+ if(this.selectedChildWidget === page){
+ this.selectedChildWidget = undefined;
+ if(this._started){
+ var children = this.getChildren();
+ if(children.length){
+ this.selectChild(children[0]);
+ }
+ }
+ }
+ },
+
+ selectChild: function(/*Widget*/ page){
+ // summary:
+ // Show the given widget (which must be one of my children)
+
+ page = dijit.byId(page);
+
+ if(this.selectedChildWidget != page){
+ // Deselect old page and select new one
+ this._transition(page, this.selectedChildWidget);
+ this.selectedChildWidget = page;
+ dojo.publish(this.id+"-selectChild", [page]);
+ }
+ },
+
+ _transition: function(/*Widget*/newWidget, /*Widget*/oldWidget){
+ if(oldWidget){
+ this._hideChild(oldWidget);
+ }
+ 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.
+ // page must be visible for resizing to work
+ if(this.doLayout && newWidget.resize){
+ newWidget.resize(this._containerContentBox || this._contentBox);
+ }
+ },
+
+ _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
+ this.selectChild(this._adjacent(true));
+ },
+
+ back: function(){
+ // Summary: go back to previous page
+ this.selectChild(this._adjacent(false));
+ },
+
+ _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._contentBox);
+ }
+ },
+
+ _showChild: function(/*Widget*/ page){
+ var children = this.getChildren();
+ page.isFirstChild = (page == children[0]);
+ page.isLastChild = (page == children[children.length-1]);
+ page.selected = true;
+
+ page.domNode.style.display="";
+ if(page._loadCheck){
+ page._loadCheck(); // trigger load in ContentPane
+ }
+ if(page.onShow){
+ page.onShow();
+ }
+ },
+
+ _hideChild: function(/*Widget*/ page){
+ page.selected=false;
+ page.domNode.style.display="none";
+ if(page.onHide){
+ page.onHide();
+ }
+ },
+
+ closeChild: function(/*Widget*/ page){
+ // summary:
+ // callback when user clicks the [X] to remove a page
+ // if onClose() returns true then remove and destroy the child
+ var remove = page.onClose(this, page);
+ if(remove){
+ this.removeChild(page);
+ // makes sure we can clean up executeScripts in ContentPane onUnLoad
+ page.destroyRecursive();
+ }
+ },
+
+ destroy: function(){
+ this._beingDestroyed = true;
+ this.inherited(arguments);
+ }
+});
+
+dojo.declare(
+ "dijit.layout.StackController",
+ [dijit._Widget, dijit._Templated, dijit._Container],
+ {
+ // summary:
+ // Set of buttons to select a page in a page list.
+ // Monitors the specified StackContainer, and whenever a page is
+ // added, deleted, or selected, updates itself accordingly.
+
+ templateString: "<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",
+
+ // containerId: String
+ // the id of the page container that I point to
+ containerId: "",
+
+ // buttonWidget: String
+ // the name of the button widget to create to correspond to each page
+ buttonWidget: "dijit.layout._StackButton",
+
+ postCreate: function(){
+ dijit.setWaiRole(this.domNode, "tablist");
+
+ // TODO: change key from object to id, to get more separation from StackContainer
+ this.pane2button = {}; // mapping from panes to buttons
+ this.pane2menu = {}; // mapping from panes to close menu
+
+ this._subscriptions=[
+ dojo.subscribe(this.containerId+"-startup", this, "onStartup"),
+ dojo.subscribe(this.containerId+"-addChild", this, "onAddChild"),
+ dojo.subscribe(this.containerId+"-removeChild", this, "onRemoveChild"),
+ dojo.subscribe(this.containerId+"-selectChild", this, "onSelectChild"),
+ dojo.subscribe(this.containerId+"-containerKeyPress", this, "onContainerKeyPress")
+ ];
+ },
+
+ onStartup: function(/*Object*/ info){
+ // summary: called after StackContainer has finished initializing
+ dojo.forEach(info.children, this.onAddChild, this);
+ this.onSelectChild(info.selected);
+ },
+
+ destroy: function(){
+ for(var pane in this.pane2button){
+ this.onRemoveChild(pane);
+ }
+ dojo.forEach(this._subscriptions, dojo.unsubscribe);
+ this.inherited(arguments);
+ },
+
+ onAddChild: function(/*Widget*/ page, /*Integer?*/ insertIndex){
+ // summary:
+ // Called whenever a page is added to the container.
+ // Create button corresponding to the page.
+
+ // add a node that will be promoted to the button widget
+ var refNode = dojo.doc.createElement("span");
+ this.domNode.appendChild(refNode);
+ // create an instance of the button widget
+ var cls = dojo.getObject(this.buttonWidget);
+ var button = new cls({label: page.title, closeButton: page.closable}, refNode);
+ this.addChild(button, insertIndex);
+ this.pane2button[page] = button;
+ page.controlButton = button; // this value might be overwritten if two tabs point to same container
+
+ dojo.connect(button, "onClick", dojo.hitch(this,"onButtonClick",page));
+ if(page.closable){
+ dojo.connect(button, "onClickCloseButton", dojo.hitch(this,"onCloseButtonClick",page));
+ // add context menu onto title button
+ var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
+ var closeMenu = new dijit.Menu({targetNodeIds:[button.id], id:button.id+"_Menu"});
+ var mItem = new dijit.MenuItem({label:_nlsResources.itemClose});
+ dojo.connect(mItem, "onClick", dojo.hitch(this, "onCloseButtonClick", page));
+ closeMenu.addChild(mItem);
+ this.pane2menu[page] = closeMenu;
+ }
+ if(!this._currentChild){ // put the first child into the tab order
+ button.focusNode.setAttribute("tabIndex", "0");
+ this._currentChild = page;
+ }
+ //make sure all tabs have the same length
+ if(!this.isLeftToRight() && dojo.isIE && this._rectifyRtlTabList){
+ this._rectifyRtlTabList();
+ }
+ },
+
+ onRemoveChild: function(/*Widget*/ page){
+ // summary:
+ // Called whenever a page is removed from the container.
+ // Remove the button corresponding to the page.
+ if(this._currentChild === page){ this._currentChild = null; }
+ var button = this.pane2button[page];
+ var menu = this.pane2menu[page];
+ if (menu){
+ menu.destroy();
+ }
+ if(button){
+ // TODO? if current child { reassign }
+ button.destroy();
+ }
+ this.pane2button[page] = null;
+ },
+
+ onSelectChild: function(/*Widget*/ page){
+ // summary:
+ // Called when a page has been selected in the StackContainer, either by me or by another StackController
+
+ if(!page){ return; }
+
+ if(this._currentChild){
+ var oldButton=this.pane2button[this._currentChild];
+ oldButton.setAttribute('checked', false);
+ oldButton.focusNode.setAttribute("tabIndex", "-1");
+ }
+
+ var newButton=this.pane2button[page];
+ newButton.setAttribute('checked', true);
+ this._currentChild = page;
+ newButton.focusNode.setAttribute("tabIndex", "0");
+ var container = dijit.byId(this.containerId);
+ dijit.setWaiState(container.containerNode || container.domNode, "labelledby", newButton.id);
+ },
+
+ onButtonClick: function(/*Widget*/ page){
+ // summary:
+ // Called whenever one of my child buttons is pressed in an attempt to select a page
+ var container = dijit.byId(this.containerId); // TODO: do this via topics?
+ container.selectChild(page);
+ },
+
+ onCloseButtonClick: function(/*Widget*/ page){
+ // summary:
+ // Called whenever one of my child buttons [X] is pressed in an attempt to close a page
+ var container = dijit.byId(this.containerId);
+ container.closeChild(page);
+ var b = this.pane2button[this._currentChild];
+ if(b){
+ dijit.focus(b.focusNode || b.domNode);
+ }
+ },
+
+ // TODO: this is a bit redundant with forward, back api in StackContainer
+ adjacent: function(/*Boolean*/ forward){
+ 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]);
+ // 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.
+
+ if(this.disabled || e.altKey ){ return; }
+ var forward = null;
+ if(e.ctrlKey || !e._djpage){
+ var k = dojo.keys;
+ switch(e.keyCode){
+ 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.DELETE:
+ if(this._currentChild.closable){
+ this.onCloseButtonClick(this._currentChild);
+ }
+ dojo.stopEvent(e);
+ break;
+ default:
+ if(e.ctrlKey){
+ if(e.keyCode == k.TAB){
+ this.adjacent(!e.shiftKey).onClick();
+ dojo.stopEvent(e);
+ }else if(e.keyChar == "w"){
+ if(this._currentChild.closable){
+ this.onCloseButtonClick(this._currentChild);
+ }
+ dojo.stopEvent(e); // avoid browser tab closing.
+ }
+ }
+ }
+ // handle page navigation
+ if(forward !== null){
+ this.adjacent(forward).onClick();
+ dojo.stopEvent(e);
+ }
+ }
+ },
+
+ onContainerKeyPress: function(/*Object*/ info){
+ info.e._djpage = info.page;
+ this.onkeypress(info.e);
+ }
+});
+
+dojo.declare("dijit.layout._StackButton",
+ dijit.form.ToggleButton,
+ {
+ // summary
+ // Internal widget used by StackContainer.
+ // The button-like or tab-like object you click to select or delete a page
+
+ tabIndex: "-1", // StackContainer buttons are not in the tab order by default
+
+ postCreate: function(/*Event*/ evt){
+ dijit.setWaiRole((this.focusNode || this.domNode), "tab");
+ this.inherited(arguments);
+ },
+
+ 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)
+ 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.
+ evt.stopPropagation();
+ }
+});
+
+// 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, {
+ // title: String
+ // Title of this widget. Used by TabContainer to the name the tab, etc.
+ title: "",
+
+ // selected: Boolean
+ // Is this child currently selected?
+ selected: false,
+
+ // closable: Boolean
+ // True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
+ closable: false, // true if user can close this tab pane
+
+ onClose: function(){
+ // summary: Callback if someone tries to close the child, child will be closed if func returns true
+ return true;
+ }
+});
+
+}
diff --git a/includes/js/dijit/layout/TabContainer.js b/includes/js/dijit/layout/TabContainer.js
new file mode 100644
index 0000000..769a25f
--- /dev/null
+++ b/includes/js/dijit/layout/TabContainer.js
@@ -0,0 +1,184 @@
+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.StackContainer");
+dojo.require("dijit._Templated");
+
+dojo.declare("dijit.layout.TabContainer",
+ [dijit.layout.StackContainer, dijit._Templated],
+ {
+ // summary:
+ // A Container with Title Tabs, each one pointing at a pane in the container.
+ // 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 title (aka title) of the pane, and optionally a close button.
+ //
+ // Publishes topics [widgetId]-addChild, [widgetId]-removeChild, and [widgetId]-selectChild
+ // (where [widgetId] is the id of the TabContainer itself.
+ //
+ // tabPosition: String
+ // Defines where tabs go relative to tab content.
+ // "top", "bottom", "left-h", "right-h"
+ tabPosition: "top",
+
+ templateString: null, // override setting in StackContainer
+ templateString:"<div class=\"dijitTabContainer\">\n\t<div dojoAttachPoint=\"tablistNode\"></div>\n\t<div class=\"dijitTabPaneWrapper\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n",
+
+ // _controllerWidget: String
+ // An optional parameter to overrider the default TabContainer controller used.
+ _controllerWidget: "dijit.layout.TabController",
+
+ postCreate: function(){
+ this.inherited(arguments);
+ // create the tab list that will have a tab (a.k.a. tab button) for each tab panel
+ var TabController = dojo.getObject(this._controllerWidget);
+ this.tablist = new TabController({
+ id: this.id + "_tablist",
+ tabPosition: this.tabPosition,
+ doLayout: this.doLayout,
+ containerId: this.id
+ }, this.tablistNode);
+ },
+
+ _setupChild: function(/* Widget */tab){
+ dojo.addClass(tab.domNode, "dijitTabPane");
+ this.inherited(arguments);
+ return tab; // Widget
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ // wire up the tablist and its tabs
+ this.tablist.startup();
+ this.inherited(arguments);
+
+ if(dojo.isSafari){
+ // sometimes safari 3.0.3 miscalculates the height of the tab labels, see #4058
+ setTimeout(dojo.hitch(this, "layout"), 0);
+ }
+
+ if(dojo.isIE && !this.isLeftToRight() && this.tabPosition == "right-h" &&
+ this.tablist && this.tablist.pane2button){
+ //need rectify non-closable tab in IE, only for "right-h" mode
+ for(var pane in this.tablist.pane2button){
+ var tabButton = this.tablist.pane2button[pane];
+ if(!tabButton.closeButton){ continue; }
+ tabButtonStyle = tabButton.closeButtonNode.style;
+ tabButtonStyle.position ="absolute";
+ if(dojo.isIE < 7){
+ tabButtonStyle.left = tabButton.domNode.offsetWidth + "px";
+ }else{
+ tabButtonStyle.padding = "0px";
+ }
+ }
+ }
+ },
+
+ layout: function(){
+ // Summary: Configure the content pane to take up all the space except for where the tabs are
+ if(!this.doLayout){ return; }
+
+ // position and size the titles and the container node
+ var titleAlign = this.tabPosition.replace(/-h/,"");
+ var children = [
+ { domNode: this.tablist.domNode, layoutAlign: titleAlign },
+ { domNode: this.containerNode, layoutAlign: "client" }
+ ];
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, children);
+
+ // Compute size to make each of my children.
+ // children[1] is the margin-box size of this.containerNode, set by layoutChildren() call above
+ this._containerContentBox = dijit.layout.marginBox2contentBox(this.containerNode, children[1]);
+
+ if(this.selectedChildWidget){
+ this._showChild(this.selectedChildWidget);
+ if(this.doLayout && this.selectedChildWidget.resize){
+ this.selectedChildWidget.resize(this._containerContentBox);
+ }
+ }
+ },
+
+ destroy: function(){
+ if(this.tablist){
+ this.tablist.destroy();
+ }
+ this.inherited(arguments);
+ }
+});
+
+//TODO: make private?
+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).
+ // 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.
+
+ templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",
+
+ // tabPosition: String
+ // Defines where tabs go relative to the content.
+ // "top", "bottom", "left-h", "right-h"
+ tabPosition: "top",
+
+ // doLayout: Boolean
+ // TODOC: deprecate doLayout? not sure.
+ doLayout: true,
+
+ // buttonWidget: String
+ // The name of the tab widget to create to correspond to each page
+ buttonWidget: "dijit.layout._TabButton",
+
+ postMixInProperties: function(){
+ this["class"] = "dijitTabLabels-" + this.tabPosition + (this.doLayout ? "" : " dijitTabNoLayout");
+ this.inherited(arguments);
+ },
+
+//TODO: can this be accomplished in CSS?
+ _rectifyRtlTabList: function(){
+ //Summary: Rectify the length of all tabs in rtl, otherwise the tab lengths are different in IE
+ if(0 >= this.tabPosition.indexOf('-h')){ return; }
+ if(!this.pane2button){ return; }
+
+ var maxLen = 0;
+ for(var pane in this.pane2button){
+ maxLen = Math.max(maxLen, dojo.marginBox(this.pane2button[pane].innerDiv).w);
+ }
+ //unify the length of all the tabs
+ for(pane in this.pane2button){
+ this.pane2button[pane].innerDiv.style.width = maxLen + '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.
+
+ baseClass: "dijitTab",
+
+ templateString:"<div waiRole=\"presentation\" dojoAttachEvent='onclick:onClick,onmouseenter:_onMouse,onmouseleave:_onMouse'>\n <div waiRole=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n <div waiRole=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n\t <span dojoAttachPoint='containerNode,focusNode' class='tabLabel'>${!label}</span>\n\t <span dojoAttachPoint='closeButtonNode' class='closeImage' dojoAttachEvent='onmouseenter:_onMouse, onmouseleave:_onMouse, onclick:onClickCloseButton' stateModifier='CloseButton'>\n\t <span dojoAttachPoint='closeText' class='closeText'>x</span>\n\t </span>\n </div>\n </div>\n</div>\n",
+
+ postCreate: function(){
+ if(this.closeButton){
+ dojo.addClass(this.innerDiv, "dijitClosable");
+ }else{
+ this.closeButtonNode.style.display="none";
+ }
+ this.inherited(arguments);
+ dojo.setSelectable(this.containerNode, false);
+ }
+});
+
+}
diff --git a/includes/js/dijit/layout/_LayoutWidget.js b/includes/js/dijit/layout/_LayoutWidget.js
new file mode 100644
index 0000000..3877802
--- /dev/null
+++ b/includes/js/dijit/layout/_LayoutWidget.js
@@ -0,0 +1,188 @@
+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.declare("dijit.layout._LayoutWidget",
+ [dijit._Widget, dijit._Container, dijit._Contained],
+ {
+ // summary
+ // Mixin for widgets that contain a list of children like SplitContainer.
+ // Widgets which mixin this code must define layout() to lay out the children
+
+ isLayoutContainer: true,
+
+ postCreate: function(){
+ 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; }
+
+ dojo.forEach(this.getChildren(), function(child){ child.startup(); });
+
+ // If I am a top level widget
+ if(!this.getParent || !this.getParent()){
+ // 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 is width=height=100% (or something similar),
+ // then I need to watch when the window resizes, and size myself accordingly
+ // (passing in no argument to resize means that it has to glean the size itself)
+ this.connect(window, 'onresize', function(){this.resize();});
+ }
+
+ this.inherited(arguments);
+ },
+
+ resize: function(args){
+ // summary:
+ // Explicitly set this widget's size (in pixels),
+ // and then call layout() to resize contents (and maybe adjust child widgets)
+ //
+ // args: Object?
+ // {w: int, h: int, l: int, t: int}
+
+ var node = this.domNode;
+
+ // set margin box size, unless it wasn't specified, in which case use current size
+ if(args){
+ dojo.marginBox(node, args);
+
+ // set offset of the node
+ if(args.t){ node.style.top = args.t + "px"; }
+ if(args.l){ node.style.left = args.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 = dojo.mixin(dojo.marginBox(node), args||{});
+
+// console.log(this, ": setting size to ", mb);
+
+ // Save the size of my content box.
+ this._contentBox = dijit.layout.marginBox2contentBox(node, mb);
+
+ // Callback for widget to adjust size of it's children
+ this.layout();
+ },
+
+ layout: function(){
+ // summary
+ // Widgets override this method to size & 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.
+ }
+ }
+);
+
+dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
+ // summary:
+ // Given the margin-box size of a node, return it's 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 capitalize = function(word){
+ return word.substring(0,1).toUpperCase() + word.substring(1);
+ };
+
+ var size = function(widget, dim){
+ // size the child
+ widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
+
+ // record child's size, 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, /*Object[]*/ children){
+ /**
+ * 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 like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
+ */
+
+ // 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.
+ children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
+ .concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));
+
+ // set positions/sizes
+ dojo.forEach(children, function(child){
+ var elm = child.domNode,
+ pos = 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.bottom = elmStyle.right = "auto";
+
+ dojo.addClass(elm, "dijitAlign" + capitalize(pos));
+
+ // set size && adjust record of remaining space.
+ // note that setting the width of a <div> may affect it's height.
+ if(pos=="top" || pos=="bottom"){
+ size(child, { w: dim.w });
+ 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"){
+ size(child, { h: dim.h });
+ dim.w -= child.w;
+ if(pos=="left"){
+ dim.l += child.w;
+ }else{
+ elmStyle.left = dim.l + dim.w + "px";
+ }
+ }else if(pos=="client"){
+ size(child, dim);
+ }
+ });
+ };
+
+})();
+
+}
diff --git a/includes/js/dijit/layout/templates/AccordionPane.html b/includes/js/dijit/layout/templates/AccordionPane.html
new file mode 100644
index 0000000..a675d3a
--- /dev/null
+++ b/includes/js/dijit/layout/templates/AccordionPane.html
@@ -0,0 +1,11 @@
+<div class='dijitAccordionPane'
+ ><div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onTitleKeyPress,onfocus:_handleFocus,onblur:_handleFocus'
+ class='dijitAccordionTitle' wairole="tab"
+ ><div class='dijitAccordionArrow' waiRole="presentation"></div
+ ><div class='arrowTextUp' waiRole="presentation">&#9650;</div
+ ><div class='arrowTextDown' waiRole="presentation">&#9660;</div
+ ><div waiRole="presentation" dojoAttachPoint='titleTextNode' class='dijitAccordionText'>${title}</div></div
+ ><div><div dojoAttachPoint='containerNode' style='overflow: hidden; height: 1px; display: none'
+ class='dijitAccordionBody' wairole="tabpanel"
+ ></div></div>
+</div>
diff --git a/includes/js/dijit/layout/templates/TabContainer.html b/includes/js/dijit/layout/templates/TabContainer.html
new file mode 100644
index 0000000..105e8c6
--- /dev/null
+++ b/includes/js/dijit/layout/templates/TabContainer.html
@@ -0,0 +1,4 @@
+<div class="dijitTabContainer">
+ <div dojoAttachPoint="tablistNode"></div>
+ <div class="dijitTabPaneWrapper" dojoAttachPoint="containerNode"></div>
+</div>
diff --git a/includes/js/dijit/layout/templates/TooltipDialog.html b/includes/js/dijit/layout/templates/TooltipDialog.html
new file mode 100644
index 0000000..5925500
--- /dev/null
+++ b/includes/js/dijit/layout/templates/TooltipDialog.html
@@ -0,0 +1,6 @@
+<div class="dijitTooltipDialog" waiRole="presentation">
+ <div class="dijitTooltipContainer" waiRole="presentation">
+ <div class ="dijitTooltipContents dijitTooltipFocusNode" dojoAttachPoint="containerNode" tabindex="-1" waiRole="dialog"></div>
+ </div>
+ <div class="dijitTooltipConnector" waiRole="presenation"></div>
+</div>
diff --git a/includes/js/dijit/layout/templates/_TabButton.html b/includes/js/dijit/layout/templates/_TabButton.html
new file mode 100644
index 0000000..b7b37ac
--- /dev/null
+++ b/includes/js/dijit/layout/templates/_TabButton.html
@@ -0,0 +1,10 @@
+<div waiRole="presentation" dojoAttachEvent='onclick:onClick,onmouseenter:_onMouse,onmouseleave:_onMouse'>
+ <div waiRole="presentation" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>
+ <div waiRole="presentation" class='dijitTabContent' dojoAttachPoint='tabContent'>
+ <span dojoAttachPoint='containerNode,focusNode' class='tabLabel'>${!label}</span>
+ <span dojoAttachPoint='closeButtonNode' class='closeImage' dojoAttachEvent='onmouseenter:_onMouse, onmouseleave:_onMouse, onclick:onClickCloseButton' stateModifier='CloseButton'>
+ <span dojoAttachPoint='closeText' class='closeText'>x</span>
+ </span>
+ </div>
+ </div>
+</div>