mirror of
https://git.tt-rss.org/git/tt-rss.git
synced 2025-12-13 17:45:55 +00:00
dojo: remove uncompressed files
This commit is contained in:
@@ -1,555 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/layout/templates/AccordionButton.html':"<div data-dojo-attach-event='onclick:_onTitleClick' class='dijitAccordionTitle' role=\"presentation\">\n\t<div data-dojo-attach-point='titleNode,focusNode' data-dojo-attach-event='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' role=\"tab\" aria-expanded=\"false\"\n\t\t><span class='dijitInline dijitAccordionArrow' role=\"presentation\"></span\n\t\t><span class='arrowTextUp' role=\"presentation\">+</span\n\t\t><span class='arrowTextDown' role=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" data-dojo-attach-point='iconNode' style=\"vertical-align: middle\" role=\"presentation\"/>\n\t\t<span role=\"presentation\" data-dojo-attach-point='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"}});
|
||||
define("dijit/layout/AccordionContainer", [
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/event", // event.stop
|
||||
"dojo/_base/fx", // fx.Animation
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-attr", // domAttr.attr
|
||||
"dojo/dom-class", // domClass.remove
|
||||
"dojo/dom-construct", // domConstruct.place
|
||||
"dojo/dom-geometry",
|
||||
"dojo/_base/kernel",
|
||||
"dojo/keys", // keys
|
||||
"dojo/_base/lang", // lang.getObject lang.hitch
|
||||
"dojo/_base/sniff", // has("ie")
|
||||
"dojo/topic", // publish
|
||||
"../focus", // focus.focus()
|
||||
"../_base/manager", // manager.defaultDuration
|
||||
"dojo/ready",
|
||||
"../_Widget",
|
||||
"../_Container",
|
||||
"../_TemplatedMixin",
|
||||
"../_CssStateMixin",
|
||||
"./StackContainer",
|
||||
"./ContentPane",
|
||||
"dojo/text!./templates/AccordionButton.html"
|
||||
], function(require, array, declare, event, fx, dom, domAttr, domClass, domConstruct, domGeometry,
|
||||
kernel, keys, lang, has, topic, focus, manager, ready,
|
||||
_Widget, _Container, _TemplatedMixin, _CssStateMixin, StackContainer, ContentPane, template){
|
||||
|
||||
/*=====
|
||||
var _Widget = dijit._Widget;
|
||||
var _Container = dijit._Container;
|
||||
var _TemplatedMixin = dijit._TemplatedMixin;
|
||||
var _CssStateMixin = dijit._CssStateMixin;
|
||||
var StackContainer = dijit.layout.StackContainer;
|
||||
var ContentPane = dijit.layout.ContentPane;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/AccordionContainer
|
||||
// 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.
|
||||
|
||||
|
||||
// Design notes:
|
||||
//
|
||||
// An AccordionContainer is a StackContainer, but each child (typically ContentPane)
|
||||
// is wrapped in a _AccordionInnerContainer. This is hidden from the caller.
|
||||
//
|
||||
// The resulting markup will look like:
|
||||
//
|
||||
// <div class=dijitAccordionContainer>
|
||||
// <div class=dijitAccordionInnerContainer> (one pane)
|
||||
// <div class=dijitAccordionTitle> (title bar) ... </div>
|
||||
// <div class=dijtAccordionChildWrapper> (content pane) </div>
|
||||
// </div>
|
||||
// </div>
|
||||
//
|
||||
// Normally the dijtAccordionChildWrapper is hidden for all but one child (the shown
|
||||
// child), so the space for the content pane is all the title bars + the one dijtAccordionChildWrapper,
|
||||
// which on claro has a 1px border plus a 2px bottom margin.
|
||||
//
|
||||
// During animation there are two dijtAccordionChildWrapper's shown, so we need
|
||||
// to compensate for that.
|
||||
|
||||
|
||||
var AccordionButton = declare("dijit.layout._AccordionButton", [_Widget, _TemplatedMixin, _CssStateMixin], {
|
||||
// summary:
|
||||
// The title bar to click to open up an accordion pane.
|
||||
// Internal widget used by AccordionContainer.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
templateString: template,
|
||||
|
||||
// label: String
|
||||
// Title of the pane
|
||||
label: "",
|
||||
_setLabelAttr: {node: "titleTextNode", type: "innerHTML" },
|
||||
|
||||
// title: String
|
||||
// Tooltip that appears on hover
|
||||
title: "",
|
||||
_setTitleAttr: {node: "titleTextNode", type: "attribute", attribute: "title"},
|
||||
|
||||
// iconClassAttr: String
|
||||
// CSS class for icon to left of label
|
||||
iconClassAttr: "",
|
||||
_setIconClassAttr: { node: "iconNode", type: "class" },
|
||||
|
||||
baseClass: "dijitAccordionTitle",
|
||||
|
||||
getParent: function(){
|
||||
// summary:
|
||||
// Returns the AccordionContainer parent.
|
||||
// tags:
|
||||
// private
|
||||
return this.parent;
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
var titleTextNodeId = this.id.replace(' ','_');
|
||||
domAttr.set(this.titleTextNode, "id", titleTextNodeId+"_title");
|
||||
this.focusNode.setAttribute("aria-labelledby", domAttr.get(this.titleTextNode, "id"));
|
||||
dom.setSelectable(this.domNode, false);
|
||||
},
|
||||
|
||||
getTitleHeight: function(){
|
||||
// summary:
|
||||
// Returns the height of the title dom node.
|
||||
return domGeometry.getMarginSize(this.domNode).h; // Integer
|
||||
},
|
||||
|
||||
// TODO: maybe the parent should set these methods directly rather than forcing the code
|
||||
// into the button widget?
|
||||
_onTitleClick: function(){
|
||||
// summary:
|
||||
// Callback when someone clicks my title.
|
||||
var parent = this.getParent();
|
||||
parent.selectChild(this.contentWidget, true);
|
||||
focus.focus(this.focusNode);
|
||||
},
|
||||
|
||||
_onTitleKeyPress: function(/*Event*/ evt){
|
||||
return this.getParent()._onKeyPress(evt, this.contentWidget);
|
||||
},
|
||||
|
||||
_setSelectedAttr: function(/*Boolean*/ isSelected){
|
||||
this._set("selected", isSelected);
|
||||
this.focusNode.setAttribute("aria-expanded", isSelected);
|
||||
this.focusNode.setAttribute("aria-selected", isSelected);
|
||||
this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
|
||||
}
|
||||
});
|
||||
|
||||
var AccordionInnerContainer = declare("dijit.layout._AccordionInnerContainer", [_Widget, _CssStateMixin], {
|
||||
// summary:
|
||||
// Internal widget placed as direct child of AccordionContainer.containerNode.
|
||||
// When other widgets are added as children to an AccordionContainer they are wrapped in
|
||||
// this widget.
|
||||
|
||||
/*=====
|
||||
// buttonWidget: Function || String
|
||||
// Class to use to instantiate title
|
||||
// (Wish we didn't have a separate widget for just the title but maintaining it
|
||||
// for backwards compatibility, is it worth it?)
|
||||
buttonWidget: null,
|
||||
=====*/
|
||||
|
||||
/*=====
|
||||
// contentWidget: dijit._Widget
|
||||
// Pointer to the real child widget
|
||||
contentWidget: null,
|
||||
=====*/
|
||||
|
||||
baseClass: "dijitAccordionInnerContainer",
|
||||
|
||||
// tell nested layout widget that we will take care of sizing
|
||||
isLayoutContainer: true,
|
||||
|
||||
buildRendering: function(){
|
||||
// Builds a template like:
|
||||
// <div class=dijitAccordionInnerContainer>
|
||||
// Button
|
||||
// <div class=dijitAccordionChildWrapper>
|
||||
// ContentPane
|
||||
// </div>
|
||||
// </div>
|
||||
|
||||
// Create wrapper div, placed where the child is now
|
||||
this.domNode = domConstruct.place("<div class='" + this.baseClass +
|
||||
"' role='presentation'>", this.contentWidget.domNode, "after");
|
||||
|
||||
// wrapper div's first child is the button widget (ie, the title bar)
|
||||
var child = this.contentWidget,
|
||||
cls = lang.isString(this.buttonWidget) ? lang.getObject(this.buttonWidget) : this.buttonWidget;
|
||||
this.button = child._buttonWidget = (new cls({
|
||||
contentWidget: child,
|
||||
label: child.title,
|
||||
title: child.tooltip,
|
||||
dir: child.dir,
|
||||
lang: child.lang,
|
||||
textDir: child.textDir,
|
||||
iconClass: child.iconClass,
|
||||
id: child.id + "_button",
|
||||
parent: this.parent
|
||||
})).placeAt(this.domNode);
|
||||
|
||||
// and then the actual content widget (changing it from prior-sibling to last-child),
|
||||
// wrapped by a <div class=dijitAccordionChildWrapper>
|
||||
this.containerNode = domConstruct.place("<div class='dijitAccordionChildWrapper' style='display:none'>", this.domNode);
|
||||
domConstruct.place(this.contentWidget.domNode, this.containerNode);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Map changes in content widget's title etc. to changes in the button
|
||||
var button = this.button;
|
||||
this._contentWidgetWatches = [
|
||||
this.contentWidget.watch('title', lang.hitch(this, function(name, oldValue, newValue){
|
||||
button.set("label", newValue);
|
||||
})),
|
||||
this.contentWidget.watch('tooltip', lang.hitch(this, function(name, oldValue, newValue){
|
||||
button.set("title", newValue);
|
||||
})),
|
||||
this.contentWidget.watch('iconClass', lang.hitch(this, function(name, oldValue, newValue){
|
||||
button.set("iconClass", newValue);
|
||||
}))
|
||||
];
|
||||
},
|
||||
|
||||
_setSelectedAttr: function(/*Boolean*/ isSelected){
|
||||
this._set("selected", isSelected);
|
||||
this.button.set("selected", isSelected);
|
||||
if(isSelected){
|
||||
var cw = this.contentWidget;
|
||||
if(cw.onSelected){ cw.onSelected(); }
|
||||
}
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
// Called by _Container.addChild()
|
||||
this.contentWidget.startup();
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
this.button.destroyRecursive();
|
||||
|
||||
array.forEach(this._contentWidgetWatches || [], function(w){ w.unwatch(); });
|
||||
|
||||
delete this.contentWidget._buttonWidget;
|
||||
delete this.contentWidget._wrapperWidget;
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
destroyDescendants: function(/*Boolean*/ preserveDom){
|
||||
// since getChildren isn't working for me, have to code this manually
|
||||
this.contentWidget.destroyRecursive(preserveDom);
|
||||
}
|
||||
});
|
||||
|
||||
var AccordionContainer = declare("dijit.layout.AccordionContainer", 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 data-dojo-type="dijit.layout.AccordionContainer">
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" title="pane 1">
|
||||
// | </div>
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" title="pane 2">
|
||||
// | <p>This is some text</p>
|
||||
// | </div>
|
||||
// | </div>
|
||||
|
||||
// duration: Integer
|
||||
// Amount of time (in ms) it takes to slide panes
|
||||
duration: manager.defaultDuration,
|
||||
|
||||
// buttonWidget: [const] String
|
||||
// The name of the widget used to display the title of each pane
|
||||
buttonWidget: AccordionButton,
|
||||
|
||||
/*=====
|
||||
// _verticalSpace: Number
|
||||
// Pixels of space available for the open pane
|
||||
// (my content box size minus the cumulative size of all the title bars)
|
||||
_verticalSpace: 0,
|
||||
=====*/
|
||||
baseClass: "dijitAccordionContainer",
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
this.domNode.style.overflow = "hidden"; // TODO: put this in dijit.css
|
||||
this.domNode.setAttribute("role", "tablist"); // TODO: put this in template
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
if(this._started){ return; }
|
||||
this.inherited(arguments);
|
||||
if(this.selectedChildWidget){
|
||||
var style = this.selectedChildWidget.containerNode.style;
|
||||
style.display = "";
|
||||
style.overflow = "auto";
|
||||
this.selectedChildWidget._wrapperWidget.set("selected", true);
|
||||
}
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// Implement _LayoutWidget.layout() virtual method.
|
||||
// Set the height of the open pane based on what room remains.
|
||||
|
||||
var openPane = this.selectedChildWidget;
|
||||
|
||||
if(!openPane){ return;}
|
||||
|
||||
// space taken up by title, plus wrapper div (with border/margin) for open pane
|
||||
var wrapperDomNode = openPane._wrapperWidget.domNode,
|
||||
wrapperDomNodeMargin = domGeometry.getMarginExtents(wrapperDomNode),
|
||||
wrapperDomNodePadBorder = domGeometry.getPadBorderExtents(wrapperDomNode),
|
||||
wrapperContainerNode = openPane._wrapperWidget.containerNode,
|
||||
wrapperContainerNodeMargin = domGeometry.getMarginExtents(wrapperContainerNode),
|
||||
wrapperContainerNodePadBorder = domGeometry.getPadBorderExtents(wrapperContainerNode),
|
||||
mySize = this._contentBox;
|
||||
|
||||
// get cumulative height of all the unselected title bars
|
||||
var totalCollapsedHeight = 0;
|
||||
array.forEach(this.getChildren(), function(child){
|
||||
if(child != openPane){
|
||||
// Using domGeometry.getMarginSize() rather than domGeometry.position() since claro has 1px bottom margin
|
||||
// to separate accordion panes. Not sure that works perfectly, it's probably putting a 1px
|
||||
// margin below the bottom pane (even though we don't want one).
|
||||
totalCollapsedHeight += domGeometry.getMarginSize(child._wrapperWidget.domNode).h;
|
||||
}
|
||||
});
|
||||
this._verticalSpace = mySize.h - totalCollapsedHeight - wrapperDomNodeMargin.h
|
||||
- wrapperDomNodePadBorder.h - wrapperContainerNodeMargin.h - wrapperContainerNodePadBorder.h
|
||||
- openPane._buttonWidget.getTitleHeight();
|
||||
|
||||
// Memo size to make displayed child
|
||||
this._containerContentBox = {
|
||||
h: this._verticalSpace,
|
||||
w: this._contentBox.w - wrapperDomNodeMargin.w - wrapperDomNodePadBorder.w
|
||||
- wrapperContainerNodeMargin.w - wrapperContainerNodePadBorder.w
|
||||
};
|
||||
|
||||
if(openPane){
|
||||
openPane.resize(this._containerContentBox);
|
||||
}
|
||||
},
|
||||
|
||||
_setupChild: function(child){
|
||||
// Overrides _LayoutWidget._setupChild().
|
||||
// Put wrapper widget around the child widget, showing title
|
||||
|
||||
child._wrapperWidget = AccordionInnerContainer({
|
||||
contentWidget: child,
|
||||
buttonWidget: this.buttonWidget,
|
||||
id: child.id + "_wrapper",
|
||||
dir: child.dir,
|
||||
lang: child.lang,
|
||||
textDir: child.textDir,
|
||||
parent: this
|
||||
});
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
|
||||
if(this._started){
|
||||
// Adding a child to a started Accordion is complicated because children have
|
||||
// wrapper widgets. Default code path (calling this.inherited()) would add
|
||||
// the new child inside another child's wrapper.
|
||||
|
||||
// First add in child as a direct child of this AccordionContainer
|
||||
var refNode = this.containerNode;
|
||||
if(insertIndex && typeof insertIndex == "number"){
|
||||
var children = _Widget.prototype.getChildren.call(this); // get wrapper panes
|
||||
if(children && children.length >= insertIndex){
|
||||
refNode = children[insertIndex-1].domNode;
|
||||
insertIndex = "after";
|
||||
}
|
||||
}
|
||||
domConstruct.place(child.domNode, refNode, insertIndex);
|
||||
|
||||
if(!child._started){
|
||||
child.startup();
|
||||
}
|
||||
|
||||
// Then stick the wrapper widget around the child widget
|
||||
this._setupChild(child);
|
||||
|
||||
// Code below copied from StackContainer
|
||||
topic.publish(this.id+"-addChild", child, insertIndex); // publish
|
||||
this.layout();
|
||||
if(!this.selectedChildWidget){
|
||||
this.selectChild(child);
|
||||
}
|
||||
}else{
|
||||
// We haven't been started yet so just add in the child widget directly,
|
||||
// and the wrapper will be created on startup()
|
||||
this.inherited(arguments);
|
||||
}
|
||||
},
|
||||
|
||||
removeChild: function(child){
|
||||
// Overrides _LayoutWidget.removeChild().
|
||||
|
||||
// Destroy wrapper widget first, before StackContainer.getChildren() call.
|
||||
// Replace wrapper widget with true child widget (ContentPane etc.).
|
||||
// This step only happens if the AccordionContainer has been started; otherwise there's no wrapper.
|
||||
if(child._wrapperWidget){
|
||||
domConstruct.place(child.domNode, child._wrapperWidget.domNode, "after");
|
||||
child._wrapperWidget.destroy();
|
||||
delete child._wrapperWidget;
|
||||
}
|
||||
|
||||
domClass.remove(child.domNode, "dijitHidden");
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
getChildren: function(){
|
||||
// Overrides _Container.getChildren() to return content panes rather than internal AccordionInnerContainer panes
|
||||
return array.map(this.inherited(arguments), function(child){
|
||||
return child.declaredClass == "dijit.layout._AccordionInnerContainer" ? child.contentWidget : child;
|
||||
}, this);
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
if(this._animation){
|
||||
this._animation.stop();
|
||||
}
|
||||
array.forEach(this.getChildren(), function(child){
|
||||
// If AccordionContainer has been started, then each child has a wrapper widget which
|
||||
// also needs to be destroyed.
|
||||
if(child._wrapperWidget){
|
||||
child._wrapperWidget.destroy();
|
||||
}else{
|
||||
child.destroyRecursive();
|
||||
}
|
||||
});
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_showChild: function(child){
|
||||
// Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
|
||||
child._wrapperWidget.containerNode.style.display="block";
|
||||
return this.inherited(arguments);
|
||||
},
|
||||
|
||||
_hideChild: function(child){
|
||||
// Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
|
||||
child._wrapperWidget.containerNode.style.display="none";
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_transition: function(/*dijit._Widget?*/ newWidget, /*dijit._Widget?*/ oldWidget, /*Boolean*/ animate){
|
||||
// Overrides StackContainer._transition() to provide sliding of title bars etc.
|
||||
|
||||
if(has("ie") < 8){
|
||||
// workaround animation bugs by not animating; not worth supporting animation for IE6 & 7
|
||||
animate = false;
|
||||
}
|
||||
|
||||
if(this._animation){
|
||||
// there's an in-progress animation. speedily end it so we can do the newly requested one
|
||||
this._animation.stop(true);
|
||||
delete this._animation;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
if(newWidget){
|
||||
newWidget._wrapperWidget.set("selected", true);
|
||||
|
||||
var d = this._showChild(newWidget); // prepare widget to be slid in
|
||||
|
||||
// Size the new widget, in case this is the first time it's being shown,
|
||||
// or I have been resized since the last time it was shown.
|
||||
// Note that page must be visible for resizing to work.
|
||||
if(this.doLayout && newWidget.resize){
|
||||
newWidget.resize(this._containerContentBox);
|
||||
}
|
||||
}
|
||||
|
||||
if(oldWidget){
|
||||
oldWidget._wrapperWidget.set("selected", false);
|
||||
if(!animate){
|
||||
this._hideChild(oldWidget);
|
||||
}
|
||||
}
|
||||
|
||||
if(animate){
|
||||
var newContents = newWidget._wrapperWidget.containerNode,
|
||||
oldContents = oldWidget._wrapperWidget.containerNode;
|
||||
|
||||
// During the animation we will be showing two dijitAccordionChildWrapper nodes at once,
|
||||
// which on claro takes up 4px extra space (compared to stable AccordionContainer).
|
||||
// Have to compensate for that by immediately shrinking the pane being closed.
|
||||
var wrapperContainerNode = newWidget._wrapperWidget.containerNode,
|
||||
wrapperContainerNodeMargin = domGeometry.getMarginExtents(wrapperContainerNode),
|
||||
wrapperContainerNodePadBorder = domGeometry.getPadBorderExtents(wrapperContainerNode),
|
||||
animationHeightOverhead = wrapperContainerNodeMargin.h + wrapperContainerNodePadBorder.h;
|
||||
|
||||
oldContents.style.height = (self._verticalSpace - animationHeightOverhead) + "px";
|
||||
|
||||
this._animation = new fx.Animation({
|
||||
node: newContents,
|
||||
duration: this.duration,
|
||||
curve: [1, this._verticalSpace - animationHeightOverhead - 1],
|
||||
onAnimate: function(value){
|
||||
value = Math.floor(value); // avoid fractional values
|
||||
newContents.style.height = value + "px";
|
||||
oldContents.style.height = (self._verticalSpace - animationHeightOverhead - value) + "px";
|
||||
},
|
||||
onEnd: function(){
|
||||
delete self._animation;
|
||||
newContents.style.height = "auto";
|
||||
oldWidget._wrapperWidget.containerNode.style.display = "none";
|
||||
oldContents.style.height = "auto";
|
||||
self._hideChild(oldWidget);
|
||||
}
|
||||
});
|
||||
this._animation.onStop = this._animation.onEnd;
|
||||
this._animation.play();
|
||||
}
|
||||
|
||||
return d; // If child has an href, promise that fires when the widget has finished loading
|
||||
},
|
||||
|
||||
// note: we are treating the container as controller here
|
||||
_onKeyPress: function(/*Event*/ e, /*dijit._Widget*/ fromTitle){
|
||||
// summary:
|
||||
// Handle keypress events
|
||||
// description:
|
||||
// This is called from a handler on AccordionContainer.domNode
|
||||
// (setup in StackContainer), and is also called directly from
|
||||
// the click handler for accordion labels
|
||||
if(this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
|
||||
return;
|
||||
}
|
||||
var c = e.charOrCode;
|
||||
if((fromTitle && (c == keys.LEFT_ARROW || c == keys.UP_ARROW)) ||
|
||||
(e.ctrlKey && c == keys.PAGE_UP)){
|
||||
this._adjacent(false)._buttonWidget._onTitleClick();
|
||||
event.stop(e);
|
||||
}else if((fromTitle && (c == keys.RIGHT_ARROW || c == keys.DOWN_ARROW)) ||
|
||||
(e.ctrlKey && (c == keys.PAGE_DOWN || c == keys.TAB))){
|
||||
this._adjacent(true)._buttonWidget._onTitleClick();
|
||||
event.stop(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Back compat w/1.6, remove for 2.0
|
||||
if(!kernel.isAsync){
|
||||
ready(0, function(){
|
||||
var requires = ["dijit/layout/AccordionPane"];
|
||||
require(requires); // use indirection so modules not rolled into a build
|
||||
});
|
||||
}
|
||||
|
||||
// For monkey patching
|
||||
AccordionContainer._InnerContainer = AccordionInnerContainer;
|
||||
AccordionContainer._Button = AccordionButton;
|
||||
|
||||
return AccordionContainer;
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
define("dijit/layout/AccordionPane", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"./ContentPane"
|
||||
], function(declare, kernel, ContentPane){
|
||||
|
||||
/*=====
|
||||
var ContentPane = dijit.layout.ContentPane;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/AccordionPane
|
||||
// summary:
|
||||
// Deprecated widget. Use `dijit.layout.ContentPane` instead.
|
||||
|
||||
return declare("dijit.layout.AccordionPane", ContentPane, {
|
||||
// summary:
|
||||
// Deprecated widget. Use `dijit.layout.ContentPane` instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
|
||||
constructor: function(){
|
||||
kernel.deprecated("dijit.layout.AccordionPane deprecated, use ContentPane instead", "", "2.0");
|
||||
},
|
||||
|
||||
onSelected: function(){
|
||||
// summary:
|
||||
// called when this pane is selected
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,556 +0,0 @@
|
||||
define("dijit/layout/BorderContainer", [
|
||||
"dojo/_base/array", // array.filter array.forEach array.map
|
||||
"dojo/cookie", // cookie
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.add domClass.remove domClass.toggle
|
||||
"dojo/dom-construct", // domConstruct.destroy domConstruct.place
|
||||
"dojo/dom-geometry", // domGeometry.marginBox
|
||||
"dojo/dom-style", // domStyle.style
|
||||
"dojo/_base/event", // event.stop
|
||||
"dojo/keys",
|
||||
"dojo/_base/lang", // lang.getObject lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/touch",
|
||||
"dojo/_base/window", // win.body win.doc win.doc.createElement
|
||||
"../_WidgetBase",
|
||||
"../_Widget",
|
||||
"../_TemplatedMixin",
|
||||
"./_LayoutWidget",
|
||||
"./utils" // layoutUtils.layoutChildren
|
||||
], function(array, cookie, declare, domClass, domConstruct, domGeometry, domStyle, event, keys, lang, on, touch, win,
|
||||
_WidgetBase, _Widget, _TemplatedMixin, _LayoutWidget, layoutUtils){
|
||||
|
||||
/*=====
|
||||
var _WidgetBase = dijit._WidgetBase;
|
||||
var _Widget = dijit._Widget;
|
||||
var _TemplatedMixin = dijit._TemplatedMixin;
|
||||
var _LayoutWidget = dijit.layout._LayoutWidget;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/BorderContainer
|
||||
// summary:
|
||||
// Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
|
||||
|
||||
var _Splitter = declare("dijit.layout._Splitter", [_Widget, _TemplatedMixin ],
|
||||
{
|
||||
// summary:
|
||||
// A draggable spacer between two items in a `dijit.layout.BorderContainer`.
|
||||
// description:
|
||||
// This is instantiated by `dijit.layout.BorderContainer`. Users should not
|
||||
// create it directly.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
/*=====
|
||||
// container: [const] dijit.layout.BorderContainer
|
||||
// Pointer to the parent BorderContainer
|
||||
container: null,
|
||||
|
||||
// child: [const] dijit.layout._LayoutWidget
|
||||
// Pointer to the pane associated with this splitter
|
||||
child: null,
|
||||
|
||||
// region: [const] String
|
||||
// Region of pane associated with this splitter.
|
||||
// "top", "bottom", "left", "right".
|
||||
region: null,
|
||||
=====*/
|
||||
|
||||
// live: [const] Boolean
|
||||
// If true, the child's size changes and the child widget is redrawn as you drag the splitter;
|
||||
// otherwise, the size doesn't change until you drop the splitter (by mouse-up)
|
||||
live: true,
|
||||
|
||||
templateString: '<div class="dijitSplitter" data-dojo-attach-event="onkeypress:_onKeyPress,press:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse" tabIndex="0" role="separator"><div class="dijitSplitterThumb"></div></div>',
|
||||
|
||||
constructor: function(){
|
||||
this._handlers = [];
|
||||
},
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
this.horizontal = /top|bottom/.test(this.region);
|
||||
this._factor = /top|left/.test(this.region) ? 1 : -1;
|
||||
this._cookieName = this.container.id + "_" + this.region;
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
domClass.add(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
|
||||
|
||||
if(this.container.persist){
|
||||
// restore old size
|
||||
var persistSize = cookie(this._cookieName);
|
||||
if(persistSize){
|
||||
this.child.domNode.style[this.horizontal ? "height" : "width"] = persistSize;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_computeMaxSize: function(){
|
||||
// summary:
|
||||
// Return the maximum size that my corresponding pane can be set to
|
||||
|
||||
var dim = this.horizontal ? 'h' : 'w',
|
||||
childSize = domGeometry.getMarginBox(this.child.domNode)[dim],
|
||||
center = array.filter(this.container.getChildren(), function(child){ return child.region == "center";})[0],
|
||||
spaceAvailable = domGeometry.getMarginBox(center.domNode)[dim]; // can expand until center is crushed to 0
|
||||
|
||||
return Math.min(this.child.maxSize, childSize + spaceAvailable);
|
||||
},
|
||||
|
||||
_startDrag: function(e){
|
||||
if(!this.cover){
|
||||
this.cover = win.doc.createElement('div');
|
||||
domClass.add(this.cover, "dijitSplitterCover");
|
||||
domConstruct.place(this.cover, this.child.domNode, "after");
|
||||
}
|
||||
domClass.add(this.cover, "dijitSplitterCoverActive");
|
||||
|
||||
// Safeguard in case the stop event was missed. Shouldn't be necessary if we always get the mouse up.
|
||||
if(this.fake){ domConstruct.destroy(this.fake); }
|
||||
if(!(this._resize = this.live)){ //TODO: disable live for IE6?
|
||||
// create fake splitter to display at old position while we drag
|
||||
(this.fake = this.domNode.cloneNode(true)).removeAttribute("id");
|
||||
domClass.add(this.domNode, "dijitSplitterShadow");
|
||||
domConstruct.place(this.fake, this.domNode, "after");
|
||||
}
|
||||
domClass.add(this.domNode, "dijitSplitterActive dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
|
||||
if(this.fake){
|
||||
domClass.remove(this.fake, "dijitSplitterHover dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
|
||||
}
|
||||
|
||||
//Performance: load data info local vars for onmousevent function closure
|
||||
var factor = this._factor,
|
||||
isHorizontal = this.horizontal,
|
||||
axis = isHorizontal ? "pageY" : "pageX",
|
||||
pageStart = e[axis],
|
||||
splitterStyle = this.domNode.style,
|
||||
dim = isHorizontal ? 'h' : 'w',
|
||||
childStart = domGeometry.getMarginBox(this.child.domNode)[dim],
|
||||
max = this._computeMaxSize(),
|
||||
min = this.child.minSize || 20,
|
||||
region = this.region,
|
||||
splitterAttr = region == "top" || region == "bottom" ? "top" : "left", // style attribute of splitter to adjust
|
||||
splitterStart = parseInt(splitterStyle[splitterAttr], 10),
|
||||
resize = this._resize,
|
||||
layoutFunc = lang.hitch(this.container, "_layoutChildren", this.child.id),
|
||||
de = win.doc;
|
||||
|
||||
this._handlers = this._handlers.concat([
|
||||
on(de, touch.move, this._drag = function(e, forceResize){
|
||||
var delta = e[axis] - pageStart,
|
||||
childSize = factor * delta + childStart,
|
||||
boundChildSize = Math.max(Math.min(childSize, max), min);
|
||||
|
||||
if(resize || forceResize){
|
||||
layoutFunc(boundChildSize);
|
||||
}
|
||||
// TODO: setting style directly (usually) sets content box size, need to set margin box size
|
||||
splitterStyle[splitterAttr] = delta + splitterStart + factor*(boundChildSize - childSize) + "px";
|
||||
}),
|
||||
on(de, "dragstart", event.stop),
|
||||
on(win.body(), "selectstart", event.stop),
|
||||
on(de, touch.release, lang.hitch(this, "_stopDrag"))
|
||||
]);
|
||||
event.stop(e);
|
||||
},
|
||||
|
||||
_onMouse: function(e){
|
||||
// summary:
|
||||
// Handler for onmouseenter / onmouseleave events
|
||||
var o = (e.type == "mouseover" || e.type == "mouseenter");
|
||||
domClass.toggle(this.domNode, "dijitSplitterHover", o);
|
||||
domClass.toggle(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover", o);
|
||||
},
|
||||
|
||||
_stopDrag: function(e){
|
||||
try{
|
||||
if(this.cover){
|
||||
domClass.remove(this.cover, "dijitSplitterCoverActive");
|
||||
}
|
||||
if(this.fake){ domConstruct.destroy(this.fake); }
|
||||
domClass.remove(this.domNode, "dijitSplitterActive dijitSplitter"
|
||||
+ (this.horizontal ? "H" : "V") + "Active dijitSplitterShadow");
|
||||
this._drag(e); //TODO: redundant with onmousemove?
|
||||
this._drag(e, true);
|
||||
}finally{
|
||||
this._cleanupHandlers();
|
||||
delete this._drag;
|
||||
}
|
||||
|
||||
if(this.container.persist){
|
||||
cookie(this._cookieName, this.child.domNode.style[this.horizontal ? "height" : "width"], {expires:365});
|
||||
}
|
||||
},
|
||||
|
||||
_cleanupHandlers: function(){
|
||||
var h;
|
||||
while(h = this._handlers.pop()){ h.remove(); }
|
||||
},
|
||||
|
||||
_onKeyPress: function(/*Event*/ e){
|
||||
// should we apply typematic to this?
|
||||
this._resize = true;
|
||||
var horizontal = this.horizontal;
|
||||
var tick = 1;
|
||||
switch(e.charOrCode){
|
||||
case horizontal ? keys.UP_ARROW : keys.LEFT_ARROW:
|
||||
tick *= -1;
|
||||
// break;
|
||||
case horizontal ? keys.DOWN_ARROW : keys.RIGHT_ARROW:
|
||||
break;
|
||||
default:
|
||||
// this.inherited(arguments);
|
||||
return;
|
||||
}
|
||||
var childSize = domGeometry.getMarginSize(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
|
||||
this.container._layoutChildren(this.child.id, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
|
||||
event.stop(e);
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
this._cleanupHandlers();
|
||||
delete this.child;
|
||||
delete this.container;
|
||||
delete this.cover;
|
||||
delete this.fake;
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
var _Gutter = declare("dijit.layout._Gutter", [_Widget, _TemplatedMixin],
|
||||
{
|
||||
// summary:
|
||||
// Just a spacer div to separate side pane from center pane.
|
||||
// Basically a trick to lookup the gutter/splitter width from the theme.
|
||||
// description:
|
||||
// Instantiated by `dijit.layout.BorderContainer`. Users should not
|
||||
// create directly.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
templateString: '<div class="dijitGutter" role="presentation"></div>',
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
this.horizontal = /top|bottom/.test(this.region);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
domClass.add(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
|
||||
}
|
||||
});
|
||||
|
||||
var BorderContainer = declare("dijit.layout.BorderContainer", _LayoutWidget, {
|
||||
// summary:
|
||||
// Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
|
||||
//
|
||||
// description:
|
||||
// A BorderContainer is a box with a specified size, such as style="width: 500px; height: 500px;",
|
||||
// that contains a child widget marked region="center" and optionally children widgets marked
|
||||
// region equal to "top", "bottom", "leading", "trailing", "left" or "right".
|
||||
// Children along the edges will be laid out according to width or height dimensions and may
|
||||
// include optional splitters (splitter="true") to make them resizable by the user. The remaining
|
||||
// space is designated for the center region.
|
||||
//
|
||||
// The outer size must be specified on the BorderContainer node. Width must be specified for the sides
|
||||
// and height for the top and bottom, respectively. No dimensions should be specified on the center;
|
||||
// it will fill the remaining space. Regions named "leading" and "trailing" may be used just like
|
||||
// "left" and "right" except that they will be reversed in right-to-left environments.
|
||||
//
|
||||
// For complex layouts, multiple children can be specified for a single region. In this case, the
|
||||
// layoutPriority flag on the children determines which child is closer to the edge (low layoutPriority)
|
||||
// and which child is closer to the center (high layoutPriority). layoutPriority can also be used
|
||||
// instead of the design attribute to control layout precedence of horizontal vs. vertical panes.
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'sidebar', gutters: false"
|
||||
// | style="width: 400px; height: 300px;">
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'top'">header text</div>
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'right', splitter: true" style="width: 200px;">table of contents</div>
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'center'">client area</div>
|
||||
// | </div>
|
||||
|
||||
// design: String
|
||||
// Which design is used for the layout:
|
||||
// - "headline" (default) where the top and bottom extend
|
||||
// the full width of the container
|
||||
// - "sidebar" where the left and right sides extend from top to bottom.
|
||||
design: "headline",
|
||||
|
||||
// gutters: [const] Boolean
|
||||
// Give each pane a border and margin.
|
||||
// Margin determined by domNode.paddingLeft.
|
||||
// When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
|
||||
gutters: true,
|
||||
|
||||
// liveSplitters: [const] Boolean
|
||||
// Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
|
||||
liveSplitters: true,
|
||||
|
||||
// persist: Boolean
|
||||
// Save splitter positions in a cookie.
|
||||
persist: false,
|
||||
|
||||
baseClass: "dijitBorderContainer",
|
||||
|
||||
// _splitterClass: Function||String
|
||||
// Optional hook to override the default Splitter widget used by BorderContainer
|
||||
_splitterClass: _Splitter,
|
||||
|
||||
postMixInProperties: function(){
|
||||
// change class name to indicate that BorderContainer is being used purely for
|
||||
// layout (like LayoutContainer) rather than for pretty formatting.
|
||||
if(!this.gutters){
|
||||
this.baseClass += "NoGutter";
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
if(this._started){ return; }
|
||||
array.forEach(this.getChildren(), this._setupChild, this);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_setupChild: function(/*dijit._Widget*/ child){
|
||||
// Override _LayoutWidget._setupChild().
|
||||
|
||||
var region = child.region;
|
||||
if(region){
|
||||
this.inherited(arguments);
|
||||
|
||||
domClass.add(child.domNode, this.baseClass+"Pane");
|
||||
|
||||
var ltr = this.isLeftToRight();
|
||||
if(region == "leading"){ region = ltr ? "left" : "right"; }
|
||||
if(region == "trailing"){ region = ltr ? "right" : "left"; }
|
||||
|
||||
// Create draggable splitter for resizing pane,
|
||||
// or alternately if splitter=false but BorderContainer.gutters=true then
|
||||
// insert dummy div just for spacing
|
||||
if(region != "center" && (child.splitter || this.gutters) && !child._splitterWidget){
|
||||
var _Splitter = child.splitter ? this._splitterClass : _Gutter;
|
||||
if(lang.isString(_Splitter)){
|
||||
_Splitter = lang.getObject(_Splitter); // for back-compat, remove in 2.0
|
||||
}
|
||||
var splitter = new _Splitter({
|
||||
id: child.id + "_splitter",
|
||||
container: this,
|
||||
child: child,
|
||||
region: region,
|
||||
live: this.liveSplitters
|
||||
});
|
||||
splitter.isSplitter = true;
|
||||
child._splitterWidget = splitter;
|
||||
|
||||
domConstruct.place(splitter.domNode, child.domNode, "after");
|
||||
|
||||
// Splitters aren't added as Contained children, so we need to call startup explicitly
|
||||
splitter.startup();
|
||||
}
|
||||
child.region = region; // TODO: technically wrong since it overwrites "trailing" with "left" etc.
|
||||
}
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// Implement _LayoutWidget.layout() virtual method.
|
||||
this._layoutChildren();
|
||||
},
|
||||
|
||||
addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
|
||||
// Override _LayoutWidget.addChild().
|
||||
this.inherited(arguments);
|
||||
if(this._started){
|
||||
this.layout(); //OPT
|
||||
}
|
||||
},
|
||||
|
||||
removeChild: function(/*dijit._Widget*/ child){
|
||||
// Override _LayoutWidget.removeChild().
|
||||
|
||||
var region = child.region;
|
||||
var splitter = child._splitterWidget;
|
||||
if(splitter){
|
||||
splitter.destroy();
|
||||
delete child._splitterWidget;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
|
||||
if(this._started){
|
||||
this._layoutChildren();
|
||||
}
|
||||
// Clean up whatever style changes we made to the child pane.
|
||||
// Unclear how height and width should be handled.
|
||||
domClass.remove(child.domNode, this.baseClass+"Pane");
|
||||
domStyle.set(child.domNode, {
|
||||
top: "auto",
|
||||
bottom: "auto",
|
||||
left: "auto",
|
||||
right: "auto",
|
||||
position: "static"
|
||||
});
|
||||
domStyle.set(child.domNode, region == "top" || region == "bottom" ? "width" : "height", "auto");
|
||||
},
|
||||
|
||||
getChildren: function(){
|
||||
// Override _LayoutWidget.getChildren() to only return real children, not the splitters.
|
||||
return array.filter(this.inherited(arguments), function(widget){
|
||||
return !widget.isSplitter;
|
||||
});
|
||||
},
|
||||
|
||||
// TODO: remove in 2.0
|
||||
getSplitter: function(/*String*/region){
|
||||
// summary:
|
||||
// Returns the widget responsible for rendering the splitter associated with region
|
||||
// tags:
|
||||
// deprecated
|
||||
return array.filter(this.getChildren(), function(child){
|
||||
return child.region == region;
|
||||
})[0]._splitterWidget;
|
||||
},
|
||||
|
||||
resize: function(newSize, currentSize){
|
||||
// Overrides _LayoutWidget.resize().
|
||||
|
||||
// resetting potential padding to 0px to provide support for 100% width/height + padding
|
||||
// TODO: this hack doesn't respect the box model and is a temporary fix
|
||||
if(!this.cs || !this.pe){
|
||||
var node = this.domNode;
|
||||
this.cs = domStyle.getComputedStyle(node);
|
||||
this.pe = domGeometry.getPadExtents(node, this.cs);
|
||||
this.pe.r = domStyle.toPixelValue(node, this.cs.paddingRight);
|
||||
this.pe.b = domStyle.toPixelValue(node, this.cs.paddingBottom);
|
||||
|
||||
domStyle.set(node, "padding", "0px");
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_layoutChildren: function(/*String?*/ changedChildId, /*Number?*/ changedChildSize){
|
||||
// summary:
|
||||
// This is the main routine for setting size/position of each child.
|
||||
// description:
|
||||
// With no arguments, measures the height of top/bottom panes, the width
|
||||
// of left/right panes, and then sizes all panes accordingly.
|
||||
//
|
||||
// With changedRegion specified (as "left", "top", "bottom", or "right"),
|
||||
// it changes that region's width/height to changedRegionSize and
|
||||
// then resizes other regions that were affected.
|
||||
// changedChildId:
|
||||
// Id of the child which should be resized because splitter was dragged.
|
||||
// changedChildSize:
|
||||
// The new width/height (in pixels) to make specified child
|
||||
|
||||
if(!this._borderBox || !this._borderBox.h){
|
||||
// We are currently hidden, or we haven't been sized by our parent yet.
|
||||
// Abort. Someone will resize us later.
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate list of wrappers of my children in the order that I want layoutChildren()
|
||||
// to process them (i.e. from the outside to the inside)
|
||||
var wrappers = array.map(this.getChildren(), function(child, idx){
|
||||
return {
|
||||
pane: child,
|
||||
weight: [
|
||||
child.region == "center" ? Infinity : 0,
|
||||
child.layoutPriority,
|
||||
(this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
|
||||
idx
|
||||
]
|
||||
};
|
||||
}, this);
|
||||
wrappers.sort(function(a, b){
|
||||
var aw = a.weight, bw = b.weight;
|
||||
for(var i=0; i<aw.length; i++){
|
||||
if(aw[i] != bw[i]){
|
||||
return aw[i] - bw[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Make new list, combining the externally specified children with splitters and gutters
|
||||
var childrenAndSplitters = [];
|
||||
array.forEach(wrappers, function(wrapper){
|
||||
var pane = wrapper.pane;
|
||||
childrenAndSplitters.push(pane);
|
||||
if(pane._splitterWidget){
|
||||
childrenAndSplitters.push(pane._splitterWidget);
|
||||
}
|
||||
});
|
||||
|
||||
// Compute the box in which to lay out my children
|
||||
var dim = {
|
||||
l: this.pe.l,
|
||||
t: this.pe.t,
|
||||
w: this._borderBox.w - this.pe.w,
|
||||
h: this._borderBox.h - this.pe.h
|
||||
};
|
||||
|
||||
// Layout the children, possibly changing size due to a splitter drag
|
||||
layoutUtils.layoutChildren(this.domNode, dim, childrenAndSplitters,
|
||||
changedChildId, changedChildSize);
|
||||
},
|
||||
|
||||
destroyRecursive: function(){
|
||||
// Destroy splitters first, while getChildren() still works
|
||||
array.forEach(this.getChildren(), function(child){
|
||||
var splitter = child._splitterWidget;
|
||||
if(splitter){
|
||||
splitter.destroy();
|
||||
}
|
||||
delete child._splitterWidget;
|
||||
});
|
||||
|
||||
// Then destroy the real children, and myself
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
// 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.)
|
||||
lang.extend(_WidgetBase, {
|
||||
// region: [const] String
|
||||
// Parameter for children of `dijit.layout.BorderContainer`.
|
||||
// Values: "top", "bottom", "leading", "trailing", "left", "right", "center".
|
||||
// See the `dijit.layout.BorderContainer` description for details.
|
||||
region: '',
|
||||
|
||||
// layoutPriority: [const] Number
|
||||
// Parameter for children of `dijit.layout.BorderContainer`.
|
||||
// Children with a higher layoutPriority will be placed closer to the BorderContainer center,
|
||||
// between children with a lower layoutPriority.
|
||||
layoutPriority: 0,
|
||||
|
||||
// splitter: [const] Boolean
|
||||
// Parameter for child of `dijit.layout.BorderContainer` where region != "center".
|
||||
// If true, enables user to resize the widget by putting a draggable splitter between
|
||||
// this widget and the region=center widget.
|
||||
splitter: false,
|
||||
|
||||
// minSize: [const] Number
|
||||
// Parameter for children of `dijit.layout.BorderContainer`.
|
||||
// Specifies a minimum size (in pixels) for this widget when resized by a splitter.
|
||||
minSize: 0,
|
||||
|
||||
// maxSize: [const] Number
|
||||
// Parameter for children of `dijit.layout.BorderContainer`.
|
||||
// Specifies a maximum size (in pixels) for this widget when resized by a splitter.
|
||||
maxSize: Infinity
|
||||
});
|
||||
|
||||
// For monkey patching
|
||||
BorderContainer._Splitter = _Splitter;
|
||||
BorderContainer._Gutter = _Gutter;
|
||||
|
||||
return BorderContainer;
|
||||
});
|
||||
@@ -1,611 +0,0 @@
|
||||
define("dijit/layout/ContentPane", [
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/_base/lang", // lang.mixin lang.delegate lang.hitch lang.isFunction lang.isObject
|
||||
"../_Widget",
|
||||
"./_ContentPaneResizeMixin",
|
||||
"dojo/string", // string.substitute
|
||||
"dojo/html", // html._ContentSetter html._emptyNode
|
||||
"dojo/i18n!../nls/loading",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/Deferred", // Deferred
|
||||
"dojo/dom", // dom.byId
|
||||
"dojo/dom-attr", // domAttr.attr
|
||||
"dojo/_base/window", // win.body win.doc.createDocumentFragment
|
||||
"dojo/_base/xhr", // xhr.get
|
||||
"dojo/i18n" // i18n.getLocalization
|
||||
], function(kernel, lang, _Widget, _ContentPaneResizeMixin, string, html, nlsLoading,
|
||||
array, declare, Deferred, dom, domAttr, win, xhr, i18n){
|
||||
|
||||
/*=====
|
||||
var _Widget = dijit._Widget;
|
||||
var _ContentPaneResizeMixin = dijit.layout._ContentPaneResizeMixin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/ContentPane
|
||||
// summary:
|
||||
// A widget containing an HTML fragment, specified inline
|
||||
// or by uri. Fragment may include widgets.
|
||||
|
||||
|
||||
return declare("dijit.layout.ContentPane", [_Widget, _ContentPaneResizeMixin], {
|
||||
// summary:
|
||||
// A widget containing an HTML fragment, specified inline
|
||||
// or by uri. Fragment may include widgets.
|
||||
//
|
||||
// description:
|
||||
// This widget embeds a document fragment in the page, specified
|
||||
// either by uri, javascript generated markup or DOM reference.
|
||||
// Any widgets within this content are instantiated and managed,
|
||||
// but laid out according to the HTML structure. Unlike IFRAME,
|
||||
// ContentPane embeds a document fragment as would be found
|
||||
// inside the BODY tag of a full HTML document. It should not
|
||||
// contain the HTML, HEAD, or BODY tags.
|
||||
// For more advanced functionality with scripts and
|
||||
// stylesheets, see dojox.layout.ContentPane. This widget may be
|
||||
// used stand alone or as a base class for other widgets.
|
||||
// ContentPane is useful as a child of other layout containers
|
||||
// such as BorderContainer or TabContainer, but note that those
|
||||
// widgets can contain any widget as a child.
|
||||
//
|
||||
// example:
|
||||
// Some quick samples:
|
||||
// To change the innerHTML: cp.set('content', '<b>new content</b>')
|
||||
//
|
||||
// Or you can send it a NodeList: cp.set('content', dojo.query('div [class=selected]', userSelection))
|
||||
//
|
||||
// To do an ajax update: cp.set('href', url)
|
||||
|
||||
// href: String
|
||||
// The href of the content that displays now.
|
||||
// Set this at construction if you want to load data externally when the
|
||||
// pane is shown. (Set preload=true to load it immediately.)
|
||||
// Changing href after creation doesn't have any effect; Use set('href', ...);
|
||||
href: "",
|
||||
|
||||
// content: String || DomNode || NodeList || dijit._Widget
|
||||
// The innerHTML of the ContentPane.
|
||||
// Note that the initialization parameter / argument to set("content", ...)
|
||||
// can be a String, DomNode, Nodelist, or _Widget.
|
||||
content: "",
|
||||
|
||||
// extractContent: Boolean
|
||||
// Extract visible content from inside of <body> .... </body>.
|
||||
// I.e., strip <html> and <head> (and it's contents) from the href
|
||||
extractContent: false,
|
||||
|
||||
// parseOnLoad: Boolean
|
||||
// Parse content and create the widgets, if any.
|
||||
parseOnLoad: true,
|
||||
|
||||
// parserScope: String
|
||||
// Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
|
||||
// will search for data-dojo-type (or dojoType). For backwards compatibility
|
||||
// reasons defaults to dojo._scopeName (which is "dojo" except when
|
||||
// multi-version support is used, when it will be something like dojo16, dojo20, etc.)
|
||||
parserScope: kernel._scopeName,
|
||||
|
||||
// preventCache: Boolean
|
||||
// Prevent caching of data from href's by appending a timestamp to the href.
|
||||
preventCache: false,
|
||||
|
||||
// preload: Boolean
|
||||
// Force load of data on initialization even if pane is hidden.
|
||||
preload: false,
|
||||
|
||||
// refreshOnShow: Boolean
|
||||
// Refresh (re-download) content when pane goes from hidden to shown
|
||||
refreshOnShow: false,
|
||||
|
||||
// loadingMessage: String
|
||||
// Message that shows while downloading
|
||||
loadingMessage: "<span class='dijitContentPaneLoading'><span class='dijitInline dijitIconLoading'></span>${loadingState}</span>",
|
||||
|
||||
// errorMessage: String
|
||||
// Message that shows if an error occurs
|
||||
errorMessage: "<span class='dijitContentPaneError'><span class='dijitInline dijitIconError'></span>${errorState}</span>",
|
||||
|
||||
// isLoaded: [readonly] Boolean
|
||||
// True if the ContentPane has data in it, either specified
|
||||
// during initialization (via href or inline content), or set
|
||||
// via set('content', ...) / set('href', ...)
|
||||
//
|
||||
// False if it doesn't have any content, or if ContentPane is
|
||||
// still in the process of downloading href.
|
||||
isLoaded: false,
|
||||
|
||||
baseClass: "dijitContentPane",
|
||||
|
||||
/*======
|
||||
// ioMethod: dojo.xhrGet|dojo.xhrPost
|
||||
// Function that should grab the content specified via href.
|
||||
ioMethod: dojo.xhrGet,
|
||||
======*/
|
||||
|
||||
// ioArgs: Object
|
||||
// Parameters to pass to xhrGet() request, for example:
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="href: './bar', ioArgs: {timeout: 500}">
|
||||
ioArgs: {},
|
||||
|
||||
// onLoadDeferred: [readonly] dojo.Deferred
|
||||
// This is the `dojo.Deferred` returned by set('href', ...) and refresh().
|
||||
// Calling onLoadDeferred.addCallback() or addErrback() registers your
|
||||
// callback to be called only once, when the prior set('href', ...) call or
|
||||
// the initial href parameter to the constructor finishes loading.
|
||||
//
|
||||
// This is different than an onLoad() handler which gets called any time any href
|
||||
// or content is loaded.
|
||||
onLoadDeferred: null,
|
||||
|
||||
// Cancel _WidgetBase's _setTitleAttr because we don't want the title attribute (used to specify
|
||||
// tab labels) to be copied to ContentPane.domNode... otherwise a tooltip shows up over the
|
||||
// entire pane.
|
||||
_setTitleAttr: null,
|
||||
|
||||
// Flag to parser that I'll parse my contents, so it shouldn't.
|
||||
stopParser: true,
|
||||
|
||||
// template: [private] Boolean
|
||||
// Flag from the parser that this ContentPane is inside a template
|
||||
// so the contents are pre-parsed.
|
||||
// (TODO: this declaration can be commented out in 2.0)
|
||||
template: false,
|
||||
|
||||
create: function(params, srcNodeRef){
|
||||
// Convert a srcNodeRef argument into a content parameter, so that the original contents are
|
||||
// processed in the same way as contents set via set("content", ...), calling the parser etc.
|
||||
// Avoid modifying original params object since that breaks NodeList instantiation, see #11906.
|
||||
if((!params || !params.template) && srcNodeRef && !("href" in params) && !("content" in params)){
|
||||
var df = win.doc.createDocumentFragment();
|
||||
srcNodeRef = dom.byId(srcNodeRef);
|
||||
while(srcNodeRef.firstChild){
|
||||
df.appendChild(srcNodeRef.firstChild);
|
||||
}
|
||||
params = lang.delegate(params, {content: df});
|
||||
}
|
||||
this.inherited(arguments, [params, srcNodeRef]);
|
||||
},
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
var messages = i18n.getLocalization("dijit", "loading", this.lang);
|
||||
this.loadingMessage = string.substitute(this.loadingMessage, messages);
|
||||
this.errorMessage = string.substitute(this.errorMessage, messages);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Since we have no template we need to set this.containerNode ourselves, to make getChildren() work.
|
||||
// For subclasses of ContentPane that do have a template, does nothing.
|
||||
if(!this.containerNode){
|
||||
this.containerNode = this.domNode;
|
||||
}
|
||||
|
||||
// remove the title attribute so it doesn't show up when hovering
|
||||
// over a node (TODO: remove in 2.0, no longer needed after #11490)
|
||||
this.domNode.title = "";
|
||||
|
||||
if(!domAttr.get(this.domNode,"role")){
|
||||
this.domNode.setAttribute("role", "group");
|
||||
}
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
// summary:
|
||||
// Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
|
||||
|
||||
// This starts all the widgets
|
||||
this.inherited(arguments);
|
||||
|
||||
// And this catches stuff like dojo.dnd.Source
|
||||
if(this._contentSetter){
|
||||
array.forEach(this._contentSetter.parseResults, function(obj){
|
||||
if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){
|
||||
obj.startup();
|
||||
obj._started = true;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
setHref: function(/*String|Uri*/ href){
|
||||
// summary:
|
||||
// Deprecated. Use set('href', ...) instead.
|
||||
kernel.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.", "", "2.0");
|
||||
return this.set("href", href);
|
||||
},
|
||||
_setHrefAttr: function(/*String|Uri*/ href){
|
||||
// summary:
|
||||
// Hook so set("href", ...) works.
|
||||
// description:
|
||||
// Reset the (external defined) content of this pane and replace with new url
|
||||
// Note: It delays the download until widget is shown if preload is false.
|
||||
// href:
|
||||
// url to the page you want to get, must be within the same domain as your mainpage
|
||||
|
||||
// Cancel any in-flight requests (a set('href', ...) will cancel any in-flight set('href', ...))
|
||||
this.cancel();
|
||||
|
||||
this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
|
||||
this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
|
||||
|
||||
this._set("href", href);
|
||||
|
||||
// _setHrefAttr() is called during creation and by the user, after creation.
|
||||
// Assuming preload == false, only in the second case do we actually load the URL;
|
||||
// otherwise it's done in startup(), and only if this widget is shown.
|
||||
if(this.preload || (this._created && this._isShown())){
|
||||
this._load();
|
||||
}else{
|
||||
// Set flag to indicate that href needs to be loaded the next time the
|
||||
// ContentPane is made visible
|
||||
this._hrefChanged = true;
|
||||
}
|
||||
|
||||
return this.onLoadDeferred; // Deferred
|
||||
},
|
||||
|
||||
setContent: function(/*String|DomNode|Nodelist*/data){
|
||||
// summary:
|
||||
// Deprecated. Use set('content', ...) instead.
|
||||
kernel.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.", "", "2.0");
|
||||
this.set("content", data);
|
||||
},
|
||||
_setContentAttr: function(/*String|DomNode|Nodelist*/data){
|
||||
// summary:
|
||||
// Hook to make set("content", ...) work.
|
||||
// Replaces old content with data content, include style classes from old content
|
||||
// data:
|
||||
// the new Content may be String, DomNode or NodeList
|
||||
//
|
||||
// if data is a NodeList (or an array of nodes) nodes are copied
|
||||
// so you can import nodes from another document implicitly
|
||||
|
||||
// clear href so we can't run refresh and clear content
|
||||
// refresh should only work if we downloaded the content
|
||||
this._set("href", "");
|
||||
|
||||
// Cancel any in-flight requests (a set('content', ...) will cancel any in-flight set('href', ...))
|
||||
this.cancel();
|
||||
|
||||
// Even though user is just setting content directly, still need to define an onLoadDeferred
|
||||
// because the _onLoadHandler() handler is still getting called from setContent()
|
||||
this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
|
||||
if(this._created){
|
||||
// For back-compat reasons, call onLoad() for set('content', ...)
|
||||
// calls but not for content specified in srcNodeRef (ie: <div data-dojo-type=ContentPane>...</div>)
|
||||
// or as initialization parameter (ie: new ContentPane({content: ...})
|
||||
this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
|
||||
}
|
||||
|
||||
this._setContent(data || "");
|
||||
|
||||
this._isDownloaded = false; // mark that content is from a set('content') not a set('href')
|
||||
|
||||
return this.onLoadDeferred; // Deferred
|
||||
},
|
||||
_getContentAttr: function(){
|
||||
// summary:
|
||||
// Hook to make get("content") work
|
||||
return this.containerNode.innerHTML;
|
||||
},
|
||||
|
||||
cancel: function(){
|
||||
// summary:
|
||||
// Cancels an in-flight download of content
|
||||
if(this._xhrDfd && (this._xhrDfd.fired == -1)){
|
||||
this._xhrDfd.cancel();
|
||||
}
|
||||
delete this._xhrDfd; // garbage collect
|
||||
|
||||
this.onLoadDeferred = null;
|
||||
},
|
||||
|
||||
uninitialize: function(){
|
||||
if(this._beingDestroyed){
|
||||
this.cancel();
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
destroyRecursive: function(/*Boolean*/ preserveDom){
|
||||
// summary:
|
||||
// Destroy the ContentPane and its contents
|
||||
|
||||
// if we have multiple controllers destroying us, bail after the first
|
||||
if(this._beingDestroyed){
|
||||
return;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onShow: function(){
|
||||
// summary:
|
||||
// Called when the ContentPane is made visible
|
||||
// description:
|
||||
// For a plain ContentPane, this is called on initialization, from startup().
|
||||
// If the ContentPane is a hidden pane of a TabContainer etc., then it's
|
||||
// called whenever the pane is made visible.
|
||||
//
|
||||
// Does necessary processing, including href download and layout/resize of
|
||||
// child widget(s)
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
if(this.href){
|
||||
if(!this._xhrDfd && // if there's an href that isn't already being loaded
|
||||
(!this.isLoaded || this._hrefChanged || this.refreshOnShow)
|
||||
){
|
||||
return this.refresh(); // If child has an href, promise that fires when the load is complete
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(){
|
||||
// summary:
|
||||
// [Re]download contents of href and display
|
||||
// description:
|
||||
// 1. cancels any currently in-flight requests
|
||||
// 2. posts "loading..." message
|
||||
// 3. sends XHR to download new data
|
||||
|
||||
// Cancel possible prior in-flight request
|
||||
this.cancel();
|
||||
|
||||
this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
|
||||
this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
|
||||
this._load();
|
||||
return this.onLoadDeferred; // If child has an href, promise that fires when refresh is complete
|
||||
},
|
||||
|
||||
_load: function(){
|
||||
// summary:
|
||||
// Load/reload the href specified in this.href
|
||||
|
||||
// display loading message
|
||||
this._setContent(this.onDownloadStart(), true);
|
||||
|
||||
var self = this;
|
||||
var getArgs = {
|
||||
preventCache: (this.preventCache || this.refreshOnShow),
|
||||
url: this.href,
|
||||
handleAs: "text"
|
||||
};
|
||||
if(lang.isObject(this.ioArgs)){
|
||||
lang.mixin(getArgs, this.ioArgs);
|
||||
}
|
||||
|
||||
var hand = (this._xhrDfd = (this.ioMethod || xhr.get)(getArgs));
|
||||
|
||||
hand.addCallback(function(html){
|
||||
try{
|
||||
self._isDownloaded = true;
|
||||
self._setContent(html, false);
|
||||
self.onDownloadEnd();
|
||||
}catch(err){
|
||||
self._onError('Content', err); // onContentError
|
||||
}
|
||||
delete self._xhrDfd;
|
||||
return html;
|
||||
});
|
||||
|
||||
hand.addErrback(function(err){
|
||||
if(!hand.canceled){
|
||||
// show error message in the pane
|
||||
self._onError('Download', err); // onDownloadError
|
||||
}
|
||||
delete self._xhrDfd;
|
||||
return err;
|
||||
});
|
||||
|
||||
// Remove flag saying that a load is needed
|
||||
delete this._hrefChanged;
|
||||
},
|
||||
|
||||
_onLoadHandler: function(data){
|
||||
// summary:
|
||||
// This is called whenever new content is being loaded
|
||||
this._set("isLoaded", true);
|
||||
try{
|
||||
this.onLoadDeferred.callback(data);
|
||||
}catch(e){
|
||||
console.error('Error '+this.widgetId+' running custom onLoad code: ' + e.message);
|
||||
}
|
||||
},
|
||||
|
||||
_onUnloadHandler: function(){
|
||||
// summary:
|
||||
// This is called whenever the content is being unloaded
|
||||
this._set("isLoaded", false);
|
||||
try{
|
||||
this.onUnload();
|
||||
}catch(e){
|
||||
console.error('Error '+this.widgetId+' running custom onUnload code: ' + e.message);
|
||||
}
|
||||
},
|
||||
|
||||
destroyDescendants: function(/*Boolean*/ preserveDom){
|
||||
// summary:
|
||||
// Destroy all the widgets inside the ContentPane and empty containerNode
|
||||
|
||||
// Make sure we call onUnload (but only when the ContentPane has real content)
|
||||
if(this.isLoaded){
|
||||
this._onUnloadHandler();
|
||||
}
|
||||
|
||||
// Even if this.isLoaded == false there might still be a "Loading..." message
|
||||
// to erase, so continue...
|
||||
|
||||
// For historical reasons we need to delete all widgets under this.containerNode,
|
||||
// even ones that the user has created manually.
|
||||
var setter = this._contentSetter;
|
||||
array.forEach(this.getChildren(), function(widget){
|
||||
if(widget.destroyRecursive){
|
||||
widget.destroyRecursive(preserveDom);
|
||||
}
|
||||
});
|
||||
if(setter){
|
||||
// Most of the widgets in setter.parseResults have already been destroyed, but
|
||||
// things like Menu that have been moved to <body> haven't yet
|
||||
array.forEach(setter.parseResults, function(widget){
|
||||
if(widget.destroyRecursive && widget.domNode && widget.domNode.parentNode == win.body()){
|
||||
widget.destroyRecursive(preserveDom);
|
||||
}
|
||||
});
|
||||
delete setter.parseResults;
|
||||
}
|
||||
|
||||
// And then clear away all the DOM nodes
|
||||
if(!preserveDom){
|
||||
html._emptyNode(this.containerNode);
|
||||
}
|
||||
|
||||
// Delete any state information we have about current contents
|
||||
delete this._singleChild;
|
||||
},
|
||||
|
||||
_setContent: function(/*String|DocumentFragment*/ cont, /*Boolean*/ isFakeContent){
|
||||
// summary:
|
||||
// Insert the content into the container node
|
||||
|
||||
// first get rid of child widgets
|
||||
this.destroyDescendants();
|
||||
|
||||
// html.set will take care of the rest of the details
|
||||
// we provide an override for the error handling to ensure the widget gets the errors
|
||||
// configure the setter instance with only the relevant widget instance properties
|
||||
// NOTE: unless we hook into attr, or provide property setters for each property,
|
||||
// we need to re-configure the ContentSetter with each use
|
||||
var setter = this._contentSetter;
|
||||
if(! (setter && setter instanceof html._ContentSetter)){
|
||||
setter = this._contentSetter = new html._ContentSetter({
|
||||
node: this.containerNode,
|
||||
_onError: lang.hitch(this, this._onError),
|
||||
onContentError: lang.hitch(this, function(e){
|
||||
// fires if a domfault occurs when we are appending this.errorMessage
|
||||
// like for instance if domNode is a UL and we try append a DIV
|
||||
var errMess = this.onContentError(e);
|
||||
try{
|
||||
this.containerNode.innerHTML = errMess;
|
||||
}catch(e){
|
||||
console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
|
||||
}
|
||||
})/*,
|
||||
_onError */
|
||||
});
|
||||
}
|
||||
|
||||
var setterParams = lang.mixin({
|
||||
cleanContent: this.cleanContent,
|
||||
extractContent: this.extractContent,
|
||||
parseContent: !cont.domNode && this.parseOnLoad,
|
||||
parserScope: this.parserScope,
|
||||
startup: false,
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
textDir: this.textDir
|
||||
}, this._contentSetterParams || {});
|
||||
|
||||
setter.set( (lang.isObject(cont) && cont.domNode) ? cont.domNode : cont, setterParams );
|
||||
|
||||
// setter params must be pulled afresh from the ContentPane each time
|
||||
delete this._contentSetterParams;
|
||||
|
||||
if(this.doLayout){
|
||||
this._checkIfSingleChild();
|
||||
}
|
||||
|
||||
if(!isFakeContent){
|
||||
if(this._started){
|
||||
// Startup each top level child widget (and they will start their children, recursively)
|
||||
delete this._started;
|
||||
this.startup();
|
||||
|
||||
// Call resize() on each of my child layout widgets,
|
||||
// or resize() on my single child layout widget...
|
||||
// either now (if I'm currently visible) or when I become visible
|
||||
this._scheduleLayout();
|
||||
}
|
||||
|
||||
this._onLoadHandler(cont);
|
||||
}
|
||||
},
|
||||
|
||||
_onError: function(type, err, consoleText){
|
||||
this.onLoadDeferred.errback(err);
|
||||
|
||||
// shows user the string that is returned by on[type]Error
|
||||
// override on[type]Error and return your own string to customize
|
||||
var errText = this['on' + type + 'Error'].call(this, err);
|
||||
if(consoleText){
|
||||
console.error(consoleText, err);
|
||||
}else if(errText){// a empty string won't change current content
|
||||
this._setContent(errText, true);
|
||||
}
|
||||
},
|
||||
|
||||
// EVENT's, should be overide-able
|
||||
onLoad: function(/*===== data =====*/){
|
||||
// summary:
|
||||
// Event hook, is called after everything is loaded and widgetified
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onUnload: function(){
|
||||
// summary:
|
||||
// Event hook, is called before old content is cleared
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onDownloadStart: function(){
|
||||
// summary:
|
||||
// Called before download starts.
|
||||
// description:
|
||||
// The string returned by this function will be the html
|
||||
// that tells the user we are loading something.
|
||||
// Override with your own function if you want to change text.
|
||||
// tags:
|
||||
// extension
|
||||
return this.loadingMessage;
|
||||
},
|
||||
|
||||
onContentError: function(/*Error*/ /*===== error =====*/){
|
||||
// summary:
|
||||
// Called on DOM faults, require faults etc. in content.
|
||||
//
|
||||
// In order to display an error message in the pane, return
|
||||
// the error message from this method, as an HTML string.
|
||||
//
|
||||
// By default (if this method is not overriden), it returns
|
||||
// nothing, so the error message is just printed to the console.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
onDownloadError: function(/*Error*/ /*===== error =====*/){
|
||||
// summary:
|
||||
// Called when download error occurs.
|
||||
//
|
||||
// In order to display an error message in the pane, return
|
||||
// the error message from this method, as an HTML string.
|
||||
//
|
||||
// Default behavior (if this method is not overriden) is to display
|
||||
// the error message inside the pane.
|
||||
// tags:
|
||||
// extension
|
||||
return this.errorMessage;
|
||||
},
|
||||
|
||||
onDownloadEnd: function(){
|
||||
// summary:
|
||||
// Called when download is finished.
|
||||
// tags:
|
||||
// callback
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,91 +0,0 @@
|
||||
define("dijit/layout/LayoutContainer", [
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/_base/lang",
|
||||
"dojo/_base/declare", // declare
|
||||
"../_WidgetBase",
|
||||
"./_LayoutWidget",
|
||||
"./utils" // layoutUtils.layoutChildren
|
||||
], function(kernel, lang, declare, _WidgetBase, _LayoutWidget, layoutUtils){
|
||||
|
||||
/*=====
|
||||
var _WidgetBase = dijit._WidgetBase;
|
||||
var _LayoutWidget = dijit.layout._LayoutWidget;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/LayoutContainer
|
||||
// summary:
|
||||
// Deprecated. Use `dijit.layout.BorderContainer` instead.
|
||||
|
||||
|
||||
// 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.)
|
||||
lang.extend(_WidgetBase, {
|
||||
// layoutAlign: String
|
||||
// "none", "left", "right", "bottom", "top", and "client".
|
||||
// See the LayoutContainer description for details on this parameter.
|
||||
layoutAlign: 'none'
|
||||
});
|
||||
|
||||
return declare("dijit.layout.LayoutContainer", _LayoutWidget, {
|
||||
// summary:
|
||||
// Deprecated. Use `dijit.layout.BorderContainer` instead.
|
||||
//
|
||||
// description:
|
||||
// Provides Delphi-style panel layout semantics.
|
||||
//
|
||||
// A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
|
||||
// that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
|
||||
// It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
|
||||
// and then it takes the child marked "client" and puts it into the remaining space in the middle.
|
||||
//
|
||||
// Left/right positioning is similar to CSS's "float: left" and "float: right",
|
||||
// and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
|
||||
// CSS.
|
||||
//
|
||||
// Note that there can only be one client element, but there can be multiple left, right, top,
|
||||
// or bottom elements.
|
||||
//
|
||||
// example:
|
||||
// | <style>
|
||||
// | html, body{ height: 100%; width: 100%; }
|
||||
// | </style>
|
||||
// | <div data-dojo-type="dijit.layout.LayoutContainer" style="width: 100%; height: 100%">
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="layoutAlign: 'top'">header text</div>
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="layoutAlign: 'left'" style="width: 200px;">table of contents</div>
|
||||
// | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="layoutAlign: 'client'">client area</div>
|
||||
// | </div>
|
||||
//
|
||||
// Lays out each child in the natural order the children occur in.
|
||||
// Basically each child is laid out into the "remaining space", where "remaining space" is initially
|
||||
// the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
|
||||
// tags:
|
||||
// deprecated
|
||||
|
||||
baseClass: "dijitLayoutContainer",
|
||||
|
||||
constructor: function(){
|
||||
kernel.deprecated("dijit.layout.LayoutContainer is deprecated", "use BorderContainer instead", 2.0);
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
layoutUtils.layoutChildren(this.domNode, this._contentBox, this.getChildren());
|
||||
},
|
||||
|
||||
addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
|
||||
this.inherited(arguments);
|
||||
if(this._started){
|
||||
layoutUtils.layoutChildren(this.domNode, this._contentBox, this.getChildren());
|
||||
}
|
||||
},
|
||||
|
||||
removeChild: function(/*dijit._Widget*/ widget){
|
||||
this.inherited(arguments);
|
||||
if(this._started){
|
||||
layoutUtils.layoutChildren(this.domNode, this._contentBox, this.getChildren());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
define("dijit/layout/LinkPane", [
|
||||
"./ContentPane",
|
||||
"../_TemplatedMixin",
|
||||
"dojo/_base/declare" // declare
|
||||
], function(ContentPane, _TemplatedMixin, declare){
|
||||
|
||||
/*=====
|
||||
var _TemplatedMixin = dijit._TemplatedMixin;
|
||||
var ContentPane = dijit.layout.ContentPane;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/LinkPane
|
||||
// summary:
|
||||
// A ContentPane with an href where (when declared in markup)
|
||||
// the title is specified as innerHTML rather than as a title attribute.
|
||||
|
||||
|
||||
return declare("dijit.layout.LinkPane", [ContentPane, _TemplatedMixin], {
|
||||
// summary:
|
||||
// A ContentPane with an href where (when declared in markup)
|
||||
// the title is specified as innerHTML rather than as a title attribute.
|
||||
// description:
|
||||
// LinkPane is just a ContentPane that is declared in markup similarly
|
||||
// to an anchor. The anchor's body (the words between `<a>` and `</a>`)
|
||||
// become the title of the widget (used for TabContainer, AccordionContainer, etc.)
|
||||
// example:
|
||||
// | <a href="foo.html">my title</a>
|
||||
|
||||
// I'm using a template because the user may specify the input as
|
||||
// <a href="foo.html">title</a>, in which case we need to get rid of the
|
||||
// <a> because we don't want a link.
|
||||
templateString: '<div class="dijitLinkPane" data-dojo-attach-point="containerNode"></div>',
|
||||
|
||||
postMixInProperties: function(){
|
||||
// If user has specified node contents, they become the title
|
||||
// (the link must be plain text)
|
||||
if(this.srcNodeRef){
|
||||
this.title += this.srcNodeRef.innerHTML;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_fillContent: function(){
|
||||
// Overrides _Templated._fillContent().
|
||||
|
||||
// _Templated._fillContent() relocates srcNodeRef innerHTML to templated container node,
|
||||
// but in our case the srcNodeRef innerHTML is the title, so shouldn't be
|
||||
// copied
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,514 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/layout/templates/ScrollingTabController.html':"<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div data-dojo-type=\"dijit.layout._ScrollingTabControllerMenuButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\"\n\t\t\tdata-dojo-props=\"containerId: '${containerId}', iconClass: 'dijitTabStripMenuIcon',\n\t\t\t\t\tdropDownPosition: ['below-alt', 'above-alt']\"\n\t\t\tdata-dojo-attach-point=\"_menuBtn\" showLabel=\"false\" title=\"\">▼</div>\n\t<div data-dojo-type=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\"\n\t\t\tdata-dojo-props=\"iconClass:'dijitTabStripSlideLeftIcon', showLabel:false, title:''\"\n\t\t\tdata-dojo-attach-point=\"_leftBtn\" data-dojo-attach-event=\"onClick: doSlideLeft\">◀</div>\n\t<div data-dojo-type=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\"\n\t\t\tdata-dojo-props=\"iconClass:'dijitTabStripSlideRightIcon', showLabel:false, title:''\"\n\t\t\tdata-dojo-attach-point=\"_rightBtn\" data-dojo-attach-event=\"onClick: doSlideRight\">▶</div>\n\t<div class='dijitTabListWrapper' data-dojo-attach-point='tablistWrapper'>\n\t\t<div role='tablist' data-dojo-attach-event='onkeypress:onkeypress'\n\t\t\t\tdata-dojo-attach-point='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>",
|
||||
'url:dijit/layout/templates/_ScrollingTabControllerButton.html':"<div data-dojo-attach-event=\"onclick:_onClick\">\n\t<div role=\"presentation\" class=\"dijitTabInnerDiv\" data-dojo-attach-point=\"innerDiv,focusNode\">\n\t\t<div role=\"presentation\" class=\"dijitTabContent dijitButtonContents\" data-dojo-attach-point=\"tabContent\">\n\t\t\t<img role=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" data-dojo-attach-point=\"iconNode\"/>\n\t\t\t<span data-dojo-attach-point=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>"}});
|
||||
define("dijit/layout/ScrollingTabController", [
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.add domClass.contains
|
||||
"dojo/dom-geometry", // domGeometry.contentBox
|
||||
"dojo/dom-style", // domStyle.style
|
||||
"dojo/_base/fx", // Animation
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/query", // query
|
||||
"dojo/_base/sniff", // has("ie"), has("webkit"), has("quirks")
|
||||
"../registry", // registry.byId()
|
||||
"dojo/text!./templates/ScrollingTabController.html",
|
||||
"dojo/text!./templates/_ScrollingTabControllerButton.html",
|
||||
"./TabController",
|
||||
"./utils", // marginBox2contextBox, layoutChildren
|
||||
"../_WidgetsInTemplateMixin",
|
||||
"../Menu",
|
||||
"../MenuItem",
|
||||
"../form/Button",
|
||||
"../_HasDropDown",
|
||||
"dojo/NodeList-dom" // NodeList.style
|
||||
], function(array, declare, domClass, domGeometry, domStyle, fx, lang, query, has,
|
||||
registry, tabControllerTemplate, buttonTemplate, TabController, layoutUtils, _WidgetsInTemplateMixin,
|
||||
Menu, MenuItem, Button, _HasDropDown){
|
||||
|
||||
/*=====
|
||||
var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
|
||||
var Menu = dijit.Menu;
|
||||
var _HasDropDown = dijit._HasDropDown;
|
||||
var TabController = dijit.layout.TabController;
|
||||
=====*/
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/layout/ScrollingTabController
|
||||
// summary:
|
||||
// Set of tabs with left/right arrow keys and a menu to switch between tabs not
|
||||
// all fitting on a single row.
|
||||
|
||||
|
||||
var ScrollingTabController = declare("dijit.layout.ScrollingTabController", [TabController, _WidgetsInTemplateMixin], {
|
||||
// summary:
|
||||
// Set of tabs with left/right arrow keys and a menu to switch between tabs not
|
||||
// all fitting on a single row.
|
||||
// Works only for horizontal tabs (either above or below the content, not to the left
|
||||
// or right).
|
||||
// tags:
|
||||
// private
|
||||
|
||||
baseClass: "dijitTabController dijitScrollingTabController",
|
||||
|
||||
templateString: tabControllerTemplate,
|
||||
|
||||
// useMenu: [const] Boolean
|
||||
// True if a menu should be used to select tabs when they are too
|
||||
// wide to fit the TabContainer, false otherwise.
|
||||
useMenu: true,
|
||||
|
||||
// useSlider: [const] Boolean
|
||||
// True if a slider should be used to select tabs when they are too
|
||||
// wide to fit the TabContainer, false otherwise.
|
||||
useSlider: true,
|
||||
|
||||
// tabStripClass: [const] String
|
||||
// The css class to apply to the tab strip, if it is visible.
|
||||
tabStripClass: "",
|
||||
|
||||
widgetsInTemplate: true,
|
||||
|
||||
// _minScroll: Number
|
||||
// The distance in pixels from the edge of the tab strip which,
|
||||
// if a scroll animation is less than, forces the scroll to
|
||||
// go all the way to the left/right.
|
||||
_minScroll: 5,
|
||||
|
||||
// Override default behavior mapping class to DOMNode
|
||||
_setClassAttr: { node: "containerNode", type: "class" },
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
var n = this.domNode;
|
||||
|
||||
this.scrollNode = this.tablistWrapper;
|
||||
this._initButtons();
|
||||
|
||||
if(!this.tabStripClass){
|
||||
this.tabStripClass = "dijitTabContainer" +
|
||||
this.tabPosition.charAt(0).toUpperCase() +
|
||||
this.tabPosition.substr(1).replace(/-.*/, "") +
|
||||
"None";
|
||||
domClass.add(n, "tabStrip-disabled")
|
||||
}
|
||||
|
||||
domClass.add(this.tablistWrapper, this.tabStripClass);
|
||||
},
|
||||
|
||||
onStartup: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// TabController is hidden until it finishes drawing, to give
|
||||
// a less visually jumpy instantiation. When it's finished, set visibility to ""
|
||||
// to that the tabs are hidden/shown depending on the container's visibility setting.
|
||||
domStyle.set(this.domNode, "visibility", "");
|
||||
this._postStartup = true;
|
||||
},
|
||||
|
||||
onAddChild: function(page, insertIndex){
|
||||
this.inherited(arguments);
|
||||
|
||||
// changes to the tab button label or iconClass will have changed the width of the
|
||||
// buttons, so do a resize
|
||||
array.forEach(["label", "iconClass"], function(attr){
|
||||
this.pane2watches[page.id].push(
|
||||
this.pane2button[page.id].watch(attr, lang.hitch(this, function(){
|
||||
if(this._postStartup && this._dim){
|
||||
this.resize(this._dim);
|
||||
}
|
||||
}))
|
||||
);
|
||||
}, this);
|
||||
|
||||
// Increment the width of the wrapper when a tab is added
|
||||
// This makes sure that the buttons never wrap.
|
||||
// The value 200 is chosen as it should be bigger than most
|
||||
// Tab button widths.
|
||||
domStyle.set(this.containerNode, "width",
|
||||
(domStyle.get(this.containerNode, "width") + 200) + "px");
|
||||
},
|
||||
|
||||
onRemoveChild: function(page, insertIndex){
|
||||
// null out _selectedTab because we are about to delete that dom node
|
||||
var button = this.pane2button[page.id];
|
||||
if(this._selectedTab === button.domNode){
|
||||
this._selectedTab = null;
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_initButtons: function(){
|
||||
// summary:
|
||||
// Creates the buttons used to scroll to view tabs that
|
||||
// may not be visible if the TabContainer is too narrow.
|
||||
|
||||
// Make a list of the buttons to display when the tab labels become
|
||||
// wider than the TabContainer, and hide the other buttons.
|
||||
// Also gets the total width of the displayed buttons.
|
||||
this._btnWidth = 0;
|
||||
this._buttons = query("> .tabStripButton", this.domNode).filter(function(btn){
|
||||
if((this.useMenu && btn == this._menuBtn.domNode) ||
|
||||
(this.useSlider && (btn == this._rightBtn.domNode || btn == this._leftBtn.domNode))){
|
||||
this._btnWidth += domGeometry.getMarginSize(btn).w;
|
||||
return true;
|
||||
}else{
|
||||
domStyle.set(btn, "display", "none");
|
||||
return false;
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
_getTabsWidth: function(){
|
||||
var children = this.getChildren();
|
||||
if(children.length){
|
||||
var leftTab = children[this.isLeftToRight() ? 0 : children.length - 1].domNode,
|
||||
rightTab = children[this.isLeftToRight() ? children.length - 1 : 0].domNode;
|
||||
return rightTab.offsetLeft + domStyle.get(rightTab, "width") - leftTab.offsetLeft;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
_enableBtn: function(width){
|
||||
// summary:
|
||||
// Determines if the tabs are wider than the width of the TabContainer, and
|
||||
// thus that we need to display left/right/menu navigation buttons.
|
||||
var tabsWidth = this._getTabsWidth();
|
||||
width = width || domStyle.get(this.scrollNode, "width");
|
||||
return tabsWidth > 0 && width < tabsWidth;
|
||||
},
|
||||
|
||||
resize: function(dim){
|
||||
// summary:
|
||||
// Hides or displays the buttons used to scroll the tab list and launch the menu
|
||||
// that selects tabs.
|
||||
|
||||
// Save the dimensions to be used when a child is renamed.
|
||||
this._dim = dim;
|
||||
|
||||
// Set my height to be my natural height (tall enough for one row of tab labels),
|
||||
// and my content-box width based on margin-box width specified in dim parameter.
|
||||
// But first reset scrollNode.height in case it was set by layoutChildren() call
|
||||
// in a previous run of this method.
|
||||
this.scrollNode.style.height = "auto";
|
||||
var cb = this._contentBox = layoutUtils.marginBox2contentBox(this.domNode, {h: 0, w: dim.w});
|
||||
cb.h = this.scrollNode.offsetHeight;
|
||||
domGeometry.setContentSize(this.domNode, cb);
|
||||
|
||||
// Show/hide the left/right/menu navigation buttons depending on whether or not they
|
||||
// are needed.
|
||||
var enable = this._enableBtn(this._contentBox.w);
|
||||
this._buttons.style("display", enable ? "" : "none");
|
||||
|
||||
// Position and size the navigation buttons and the tablist
|
||||
this._leftBtn.layoutAlign = "left";
|
||||
this._rightBtn.layoutAlign = "right";
|
||||
this._menuBtn.layoutAlign = this.isLeftToRight() ? "right" : "left";
|
||||
layoutUtils.layoutChildren(this.domNode, this._contentBox,
|
||||
[this._menuBtn, this._leftBtn, this._rightBtn, {domNode: this.scrollNode, layoutAlign: "client"}]);
|
||||
|
||||
// set proper scroll so that selected tab is visible
|
||||
if(this._selectedTab){
|
||||
if(this._anim && this._anim.status() == "playing"){
|
||||
this._anim.stop();
|
||||
}
|
||||
this.scrollNode.scrollLeft = this._convertToScrollLeft(this._getScrollForSelectedTab());
|
||||
}
|
||||
|
||||
// Enable/disabled left right buttons depending on whether or not user can scroll to left or right
|
||||
this._setButtonClass(this._getScroll());
|
||||
|
||||
this._postResize = true;
|
||||
|
||||
// Return my size so layoutChildren() can use it.
|
||||
// Also avoids IE9 layout glitch on browser resize when scroll buttons present
|
||||
return {h: this._contentBox.h, w: dim.w};
|
||||
},
|
||||
|
||||
_getScroll: function(){
|
||||
// summary:
|
||||
// Returns the current scroll of the tabs where 0 means
|
||||
// "scrolled all the way to the left" and some positive number, based on #
|
||||
// of pixels of possible scroll (ex: 1000) means "scrolled all the way to the right"
|
||||
return (this.isLeftToRight() || has("ie") < 8 || (has("ie") && has("quirks")) || has("webkit")) ? this.scrollNode.scrollLeft :
|
||||
domStyle.get(this.containerNode, "width") - domStyle.get(this.scrollNode, "width")
|
||||
+ (has("ie") == 8 ? -1 : 1) * this.scrollNode.scrollLeft;
|
||||
},
|
||||
|
||||
_convertToScrollLeft: function(val){
|
||||
// summary:
|
||||
// Given a scroll value where 0 means "scrolled all the way to the left"
|
||||
// and some positive number, based on # of pixels of possible scroll (ex: 1000)
|
||||
// means "scrolled all the way to the right", return value to set this.scrollNode.scrollLeft
|
||||
// to achieve that scroll.
|
||||
//
|
||||
// This method is to adjust for RTL funniness in various browsers and versions.
|
||||
if(this.isLeftToRight() || has("ie") < 8 || (has("ie") && has("quirks")) || has("webkit")){
|
||||
return val;
|
||||
}else{
|
||||
var maxScroll = domStyle.get(this.containerNode, "width") - domStyle.get(this.scrollNode, "width");
|
||||
return (has("ie") == 8 ? -1 : 1) * (val - maxScroll);
|
||||
}
|
||||
},
|
||||
|
||||
onSelectChild: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Smoothly scrolls to a tab when it is selected.
|
||||
|
||||
var tab = this.pane2button[page.id];
|
||||
if(!tab || !page){return;}
|
||||
|
||||
var node = tab.domNode;
|
||||
|
||||
// Save the selection
|
||||
if(node != this._selectedTab){
|
||||
this._selectedTab = node;
|
||||
|
||||
// Scroll to the selected tab, except on startup, when scrolling is handled in resize()
|
||||
if(this._postResize){
|
||||
var sl = this._getScroll();
|
||||
|
||||
if(sl > node.offsetLeft ||
|
||||
sl + domStyle.get(this.scrollNode, "width") <
|
||||
node.offsetLeft + domStyle.get(node, "width")){
|
||||
this.createSmoothScroll().play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_getScrollBounds: function(){
|
||||
// summary:
|
||||
// Returns the minimum and maximum scroll setting to show the leftmost and rightmost
|
||||
// tabs (respectively)
|
||||
var children = this.getChildren(),
|
||||
scrollNodeWidth = domStyle.get(this.scrollNode, "width"), // about 500px
|
||||
containerWidth = domStyle.get(this.containerNode, "width"), // 50,000px
|
||||
maxPossibleScroll = containerWidth - scrollNodeWidth, // scrolling until right edge of containerNode visible
|
||||
tabsWidth = this._getTabsWidth();
|
||||
|
||||
if(children.length && tabsWidth > scrollNodeWidth){
|
||||
// Scrolling should happen
|
||||
return {
|
||||
min: this.isLeftToRight() ? 0 : children[children.length-1].domNode.offsetLeft,
|
||||
max: this.isLeftToRight() ?
|
||||
(children[children.length-1].domNode.offsetLeft + domStyle.get(children[children.length-1].domNode, "width")) - scrollNodeWidth :
|
||||
maxPossibleScroll
|
||||
};
|
||||
}else{
|
||||
// No scrolling needed, all tabs visible, we stay either scrolled to far left or far right (depending on dir)
|
||||
var onlyScrollPosition = this.isLeftToRight() ? 0 : maxPossibleScroll;
|
||||
return {
|
||||
min: onlyScrollPosition,
|
||||
max: onlyScrollPosition
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
_getScrollForSelectedTab: function(){
|
||||
// summary:
|
||||
// Returns the scroll value setting so that the selected tab
|
||||
// will appear in the center
|
||||
var w = this.scrollNode,
|
||||
n = this._selectedTab,
|
||||
scrollNodeWidth = domStyle.get(this.scrollNode, "width"),
|
||||
scrollBounds = this._getScrollBounds();
|
||||
|
||||
// TODO: scroll minimal amount (to either right or left) so that
|
||||
// selected tab is fully visible, and just return if it's already visible?
|
||||
var pos = (n.offsetLeft + domStyle.get(n, "width")/2) - scrollNodeWidth/2;
|
||||
pos = Math.min(Math.max(pos, scrollBounds.min), scrollBounds.max);
|
||||
|
||||
// TODO:
|
||||
// If scrolling close to the left side or right side, scroll
|
||||
// all the way to the left or right. See this._minScroll.
|
||||
// (But need to make sure that doesn't scroll the tab out of view...)
|
||||
return pos;
|
||||
},
|
||||
|
||||
createSmoothScroll: function(x){
|
||||
// summary:
|
||||
// Creates a dojo._Animation object that smoothly scrolls the tab list
|
||||
// either to a fixed horizontal pixel value, or to the selected tab.
|
||||
// description:
|
||||
// If an number argument is passed to the function, that horizontal
|
||||
// pixel position is scrolled to. Otherwise the currently selected
|
||||
// tab is scrolled to.
|
||||
// x: Integer?
|
||||
// An optional pixel value to scroll to, indicating distance from left.
|
||||
|
||||
// Calculate position to scroll to
|
||||
if(arguments.length > 0){
|
||||
// position specified by caller, just make sure it's within bounds
|
||||
var scrollBounds = this._getScrollBounds();
|
||||
x = Math.min(Math.max(x, scrollBounds.min), scrollBounds.max);
|
||||
}else{
|
||||
// scroll to center the current tab
|
||||
x = this._getScrollForSelectedTab();
|
||||
}
|
||||
|
||||
if(this._anim && this._anim.status() == "playing"){
|
||||
this._anim.stop();
|
||||
}
|
||||
|
||||
var self = this,
|
||||
w = this.scrollNode,
|
||||
anim = new fx.Animation({
|
||||
beforeBegin: function(){
|
||||
if(this.curve){ delete this.curve; }
|
||||
var oldS = w.scrollLeft,
|
||||
newS = self._convertToScrollLeft(x);
|
||||
anim.curve = new fx._Line(oldS, newS);
|
||||
},
|
||||
onAnimate: function(val){
|
||||
w.scrollLeft = val;
|
||||
}
|
||||
});
|
||||
this._anim = anim;
|
||||
|
||||
// Disable/enable left/right buttons according to new scroll position
|
||||
this._setButtonClass(x);
|
||||
|
||||
return anim; // dojo._Animation
|
||||
},
|
||||
|
||||
_getBtnNode: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Gets a button DOM node from a mouse click event.
|
||||
// e:
|
||||
// The mouse click event.
|
||||
var n = e.target;
|
||||
while(n && !domClass.contains(n, "tabStripButton")){
|
||||
n = n.parentNode;
|
||||
}
|
||||
return n;
|
||||
},
|
||||
|
||||
doSlideRight: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Scrolls the menu to the right.
|
||||
// e:
|
||||
// The mouse click event.
|
||||
this.doSlide(1, this._getBtnNode(e));
|
||||
},
|
||||
|
||||
doSlideLeft: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Scrolls the menu to the left.
|
||||
// e:
|
||||
// The mouse click event.
|
||||
this.doSlide(-1,this._getBtnNode(e));
|
||||
},
|
||||
|
||||
doSlide: function(/*Number*/ direction, /*DomNode*/ node){
|
||||
// summary:
|
||||
// Scrolls the tab list to the left or right by 75% of the widget width.
|
||||
// direction:
|
||||
// If the direction is 1, the widget scrolls to the right, if it is
|
||||
// -1, it scrolls to the left.
|
||||
|
||||
if(node && domClass.contains(node, "dijitTabDisabled")){return;}
|
||||
|
||||
var sWidth = domStyle.get(this.scrollNode, "width");
|
||||
var d = (sWidth * 0.75) * direction;
|
||||
|
||||
var to = this._getScroll() + d;
|
||||
|
||||
this._setButtonClass(to);
|
||||
|
||||
this.createSmoothScroll(to).play();
|
||||
},
|
||||
|
||||
_setButtonClass: function(/*Number*/ scroll){
|
||||
// summary:
|
||||
// Disables the left scroll button if the tabs are scrolled all the way to the left,
|
||||
// or the right scroll button in the opposite case.
|
||||
// scroll: Integer
|
||||
// amount of horizontal scroll
|
||||
|
||||
var scrollBounds = this._getScrollBounds();
|
||||
this._leftBtn.set("disabled", scroll <= scrollBounds.min);
|
||||
this._rightBtn.set("disabled", scroll >= scrollBounds.max);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var ScrollingTabControllerButtonMixin = declare("dijit.layout._ScrollingTabControllerButtonMixin", null, {
|
||||
baseClass: "dijitTab tabStripButton",
|
||||
|
||||
templateString: buttonTemplate,
|
||||
|
||||
// Override inherited tabIndex: 0 from dijit.form.Button, because user shouldn't be
|
||||
// able to tab to the left/right/menu buttons
|
||||
tabIndex: "",
|
||||
|
||||
// Similarly, override FormWidget.isFocusable() because clicking a button shouldn't focus it
|
||||
// either (this override avoids focus() call in FormWidget.js)
|
||||
isFocusable: function(){ return false; }
|
||||
});
|
||||
/*=====
|
||||
ScrollingTabControllerButtonMixin = dijit.layout._ScrollingTabControllerButtonMixin;
|
||||
=====*/
|
||||
|
||||
// Class used in template
|
||||
declare("dijit.layout._ScrollingTabControllerButton",
|
||||
[Button, ScrollingTabControllerButtonMixin]);
|
||||
|
||||
// Class used in template
|
||||
declare(
|
||||
"dijit.layout._ScrollingTabControllerMenuButton",
|
||||
[Button, _HasDropDown, ScrollingTabControllerButtonMixin],
|
||||
{
|
||||
// id of the TabContainer itself
|
||||
containerId: "",
|
||||
|
||||
// -1 so user can't tab into the button, but so that button can still be focused programatically.
|
||||
// Because need to move focus to the button (or somewhere) before the menu is hidden or IE6 will crash.
|
||||
tabIndex: "-1",
|
||||
|
||||
isLoaded: function(){
|
||||
// recreate menu every time, in case the TabContainer's list of children (or their icons/labels) have changed
|
||||
return false;
|
||||
},
|
||||
|
||||
loadDropDown: function(callback){
|
||||
this.dropDown = new Menu({
|
||||
id: this.containerId + "_menu",
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
textDir: this.textDir
|
||||
});
|
||||
var container = registry.byId(this.containerId);
|
||||
array.forEach(container.getChildren(), function(page){
|
||||
var menuItem = new MenuItem({
|
||||
id: page.id + "_stcMi",
|
||||
label: page.title,
|
||||
iconClass: page.iconClass,
|
||||
dir: page.dir,
|
||||
lang: page.lang,
|
||||
textDir: page.textDir,
|
||||
onClick: function(){
|
||||
container.selectChild(page);
|
||||
}
|
||||
});
|
||||
this.dropDown.addChild(menuItem);
|
||||
}, this);
|
||||
callback();
|
||||
},
|
||||
|
||||
closeDropDown: function(/*Boolean*/ focus){
|
||||
this.inherited(arguments);
|
||||
if(this.dropDown){
|
||||
this.dropDown.destroyRecursive();
|
||||
delete this.dropDown;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return ScrollingTabController;
|
||||
});
|
||||
@@ -1,611 +0,0 @@
|
||||
define("dijit/layout/SplitContainer", [
|
||||
"dojo/_base/array", // array.forEach array.indexOf array.some
|
||||
"dojo/cookie", // cookie
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-class", // domClass.add
|
||||
"dojo/dom-construct", // domConstruct.create domConstruct.destroy
|
||||
"dojo/dom-geometry", // domGeometry.marginBox domGeometry.position
|
||||
"dojo/dom-style", // domStyle.style
|
||||
"dojo/_base/event", // event.stop
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/_base/lang", // lang.extend lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/_base/sniff", // has("mozilla")
|
||||
"dojo/_base/window", // win.doc.createElement win.doc.documentElement
|
||||
"../registry", // registry.getUniqueId()
|
||||
"../_WidgetBase",
|
||||
"./_LayoutWidget"
|
||||
], function(array, cookie, declare, dom, domClass, domConstruct, domGeometry, domStyle,
|
||||
event, kernel, lang, on, has, win, registry, _WidgetBase, _LayoutWidget){
|
||||
|
||||
/*=====
|
||||
var _WidgetBase = dijit._WidgetBase;
|
||||
var _LayoutWidget = dijit.layout._LayoutWidget;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/SplitContainer
|
||||
// summary:
|
||||
// Deprecated. Use `dijit.layout.BorderContainer` instead.
|
||||
|
||||
//
|
||||
// FIXME: make it prettier
|
||||
// FIXME: active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
|
||||
// FIXME: sizeWidth should be a CSS attribute (at 7 because css wants it to be 7 until we fix to css)
|
||||
//
|
||||
|
||||
// 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.)
|
||||
lang.extend(_WidgetBase, {
|
||||
// sizeMin: [deprecated] Integer
|
||||
// Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
|
||||
// Minimum size (width or height) of a child of a SplitContainer.
|
||||
// The value is relative to other children's sizeShare properties.
|
||||
sizeMin: 10,
|
||||
|
||||
// sizeShare: [deprecated] Integer
|
||||
// Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
|
||||
// Size (width or height) of a child of a SplitContainer.
|
||||
// The value is relative to other children's sizeShare properties.
|
||||
// For example, if there are two children and each has sizeShare=10, then
|
||||
// each takes up 50% of the available space.
|
||||
sizeShare: 10
|
||||
});
|
||||
|
||||
return declare("dijit.layout.SplitContainer", _LayoutWidget, {
|
||||
// summary:
|
||||
// Deprecated. Use `dijit.layout.BorderContainer` instead.
|
||||
// description:
|
||||
// A Container widget with sizing handles in-between each child.
|
||||
// Contains multiple children widgets, all of which are displayed side by side
|
||||
// (either horizontally or vertically); there's a bar between each of the children,
|
||||
// and you can adjust the relative size of each child by dragging the bars.
|
||||
//
|
||||
// You must specify a size (width and height) for the SplitContainer.
|
||||
// tags:
|
||||
// deprecated
|
||||
|
||||
constructor: function(){
|
||||
kernel.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,
|
||||
|
||||
// orientation: String
|
||||
// either 'horizontal' or vertical; indicates whether the children are
|
||||
// arranged side-by-side or up/down.
|
||||
orientation: 'horizontal',
|
||||
|
||||
// persist: Boolean
|
||||
// Save splitter positions in a cookie
|
||||
persist: true,
|
||||
|
||||
baseClass: "dijitSplitContainer",
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited("postMixInProperties",arguments);
|
||||
this.isHorizontal = (this.orientation == 'horizontal');
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this.sizers = [];
|
||||
|
||||
// overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
|
||||
// to keep other combined css classes from inadvertantly making the overflow visible
|
||||
if(has("mozilla")){
|
||||
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 = win.doc.createElement('div');
|
||||
this.virtualSizer = sizer;
|
||||
sizer.style.position = 'relative';
|
||||
|
||||
// #1681: work around the dreaded 'quirky percentages in IE' layout bug
|
||||
// If the splitcontainer's dimensions are specified in percentages, it
|
||||
// will be resized when the virtualsizer is displayed in _showSizingLine
|
||||
// (typically expanding its bounds unnecessarily). This happens because
|
||||
// we use position: relative for .dijitSplitContainer.
|
||||
// The workaround: instead of changing the display style attribute,
|
||||
// switch to changing the zIndex (bring to front/move to back)
|
||||
|
||||
sizer.style.zIndex = 10;
|
||||
sizer.className = this.isHorizontal ? 'dijitSplitContainerVirtualSizerH' : 'dijitSplitContainerVirtualSizerV';
|
||||
this.domNode.appendChild(sizer);
|
||||
dom.setSelectable(sizer, false);
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
delete this.virtualSizer;
|
||||
if(this._ownconnects){
|
||||
var h;
|
||||
while(h = this._ownconnects.pop()){ h.remove(); }
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
startup: function(){
|
||||
if(this._started){ return; }
|
||||
|
||||
array.forEach(this.getChildren(), function(child, i, children){
|
||||
// attach the children and create the draggers
|
||||
this._setupChild(child);
|
||||
|
||||
if(i < children.length-1){
|
||||
this._addSizer();
|
||||
}
|
||||
}, this);
|
||||
|
||||
if(this.persist){
|
||||
this._restoreState();
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_setupChild: function(/*dijit._Widget*/ child){
|
||||
this.inherited(arguments);
|
||||
child.domNode.style.position = "absolute";
|
||||
domClass.add(child.domNode, "dijitSplitPane");
|
||||
},
|
||||
|
||||
_onSizerMouseDown: function(e){
|
||||
if(e.target.id){
|
||||
for(var i=0;i<this.sizers.length;i++){
|
||||
if(this.sizers[i].id == e.target.id){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i<this.sizers.length){
|
||||
this.beginSizing(e,i);
|
||||
}
|
||||
}
|
||||
},
|
||||
_addSizer: function(index){
|
||||
index = index === undefined ? this.sizers.length : index;
|
||||
|
||||
// TODO: use a template for this!!!
|
||||
var sizer = win.doc.createElement('div');
|
||||
sizer.id=registry.getUniqueId('dijit_layout_SplitterContainer_Splitter');
|
||||
this.sizers.splice(index,0,sizer);
|
||||
this.domNode.appendChild(sizer);
|
||||
|
||||
sizer.className = this.isHorizontal ? 'dijitSplitContainerSizerH' : 'dijitSplitContainerSizerV';
|
||||
|
||||
// add the thumb div
|
||||
var thumb = win.doc.createElement('div');
|
||||
thumb.className = 'thumb';
|
||||
sizer.appendChild(thumb);
|
||||
|
||||
// FIXME: are you serious? why aren't we using mover start/stop combo?
|
||||
this.connect(sizer, "onmousedown", '_onSizerMouseDown');
|
||||
|
||||
dom.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 = array.indexOf(this.getChildren(), widget);
|
||||
if(i != -1){
|
||||
if(i == this.sizers.length){
|
||||
i--;
|
||||
}
|
||||
domConstruct.destroy(this.sizers[i]);
|
||||
this.sizers.splice(i,1);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove widget and repaint
|
||||
this.inherited(arguments);
|
||||
if(this._started){
|
||||
this.layout();
|
||||
}
|
||||
},
|
||||
|
||||
addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
|
||||
// summary:
|
||||
// Add a child widget to the container
|
||||
// child:
|
||||
// a widget to add
|
||||
// insertIndex:
|
||||
// postion in the "stack" to add the child widget
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
if(this._started){
|
||||
// Do the stuff that startup() does for each widget
|
||||
var children = this.getChildren();
|
||||
if(children.length > 1){
|
||||
this._addSizer(insertIndex);
|
||||
}
|
||||
|
||||
// and then reposition (ie, shrink) every pane to make room for the new guy
|
||||
this.layout();
|
||||
}
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// summary:
|
||||
// Do layout of panels
|
||||
|
||||
// base class defines this._contentBox on initial creation and also
|
||||
// on resize
|
||||
this.paneWidth = this._contentBox.w;
|
||||
this.paneHeight = this._contentBox.h;
|
||||
|
||||
var children = this.getChildren();
|
||||
if(!children.length){ return; }
|
||||
|
||||
//
|
||||
// calculate space
|
||||
//
|
||||
|
||||
var space = this.isHorizontal ? this.paneWidth : this.paneHeight;
|
||||
if(children.length > 1){
|
||||
space -= this.sizerWidth * (children.length - 1);
|
||||
}
|
||||
|
||||
//
|
||||
// calculate total of SizeShare values
|
||||
//
|
||||
var outOf = 0;
|
||||
array.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;
|
||||
array.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;
|
||||
}
|
||||
|
||||
array.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){
|
||||
var box;
|
||||
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;
|
||||
box = {w: size, h: this.paneHeight};
|
||||
if(panel.resize){
|
||||
panel.resize(box);
|
||||
}else{
|
||||
domGeometry.setMarginBox(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';
|
||||
box = {w: this.paneWidth, h: size};
|
||||
if(panel.resize){
|
||||
panel.resize(box);
|
||||
}else{
|
||||
domGeometry.setMarginBox(panel.domNode, box);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_moveSlider: function(slider, pos, size){
|
||||
if(this.isHorizontal){
|
||||
slider.style.left = pos + 'px';
|
||||
slider.style.top = 0;
|
||||
domGeometry.setMarginBox(slider, { w: size, h: this.paneHeight });
|
||||
}else{
|
||||
slider.style.left = 0;
|
||||
slider.style.top = pos + 'px';
|
||||
domGeometry.setMarginBox(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();
|
||||
|
||||
array.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;
|
||||
|
||||
array.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;
|
||||
array.forEach(list, function(child){
|
||||
growth = this._growPane(growth, child);
|
||||
}, this);
|
||||
}
|
||||
}else{
|
||||
array.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 = domConstruct.create('div', {
|
||||
style: {
|
||||
position:'absolute',
|
||||
zIndex:5,
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%"
|
||||
}
|
||||
}, this.domNode);
|
||||
}else{
|
||||
this.cover.style.zIndex = 5;
|
||||
}
|
||||
this.sizingSplitter.style.zIndex = 6;
|
||||
|
||||
// TODO: REVISIT - we want MARGIN_BOX and core hasn't exposed that yet (but can't we use it anyway if we pay attention? we do elsewhere.)
|
||||
this.originPos = domGeometry.position(children[0].domNode, true);
|
||||
var client, screen;
|
||||
if(this.isHorizontal){
|
||||
client = e.layerX || e.offsetX || 0;
|
||||
screen = e.pageX;
|
||||
this.originPos = this.originPos.x;
|
||||
}else{
|
||||
client = e.layerY || e.offsetY || 0;
|
||||
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 = [
|
||||
on(win.doc.documentElement, "mousemove", lang.hitch(this, "changeSizing")),
|
||||
on(win.doc.documentElement, "mouseup", lang.hitch(this, "endSizing"))
|
||||
];
|
||||
|
||||
event.stop(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();
|
||||
}
|
||||
event.stop(e);
|
||||
},
|
||||
|
||||
endSizing: function(){
|
||||
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);
|
||||
}
|
||||
|
||||
var h;
|
||||
while(h = this._ownconnects.pop()){ h.remove(); }
|
||||
},
|
||||
|
||||
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;
|
||||
|
||||
array.forEach(this.getChildren(), function(child){
|
||||
child.sizeShare = child.sizeActual;
|
||||
});
|
||||
|
||||
if(this._started){
|
||||
this.layout();
|
||||
}
|
||||
},
|
||||
|
||||
_showSizingLine: function(){
|
||||
|
||||
this._moveSizingLine();
|
||||
|
||||
domGeometry.setMarginBox(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;
|
||||
domStyle.set(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(){
|
||||
array.forEach(this.getChildren(), function(child, i){
|
||||
var cookieName = this._getCookieName(i);
|
||||
var cookieValue = cookie(cookieName);
|
||||
if(cookieValue){
|
||||
var pos = parseInt(cookieValue);
|
||||
if(typeof pos == "number"){
|
||||
child.sizeShare = pos;
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
_saveState: function(){
|
||||
if(!this.persist){
|
||||
return;
|
||||
}
|
||||
array.forEach(this.getChildren(), function(child, i){
|
||||
cookie(this._getCookieName(i), child.sizeShare, {expires:365});
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,368 +0,0 @@
|
||||
define("dijit/layout/StackContainer", [
|
||||
"dojo/_base/array", // array.forEach array.indexOf array.some
|
||||
"dojo/cookie", // cookie
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.add domClass.replace
|
||||
"dojo/_base/kernel", // kernel.isAsync
|
||||
"dojo/_base/lang", // lang.extend
|
||||
"dojo/ready",
|
||||
"dojo/topic", // publish
|
||||
"../registry", // registry.byId
|
||||
"../_WidgetBase",
|
||||
"./_LayoutWidget",
|
||||
"dojo/i18n!../nls/common"
|
||||
], function(array, cookie, declare, domClass, kernel, lang, ready, topic,
|
||||
registry, _WidgetBase, _LayoutWidget){
|
||||
|
||||
/*=====
|
||||
var _WidgetBase = dijit._WidgetBase;
|
||||
var _LayoutWidget = dijit.layout._LayoutWidget;
|
||||
var StackController = dijit.layout.StackController;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/StackContainer
|
||||
// summary:
|
||||
// A container that has multiple children, but shows only one child at a time.
|
||||
|
||||
// Back compat w/1.6, remove for 2.0
|
||||
if(!kernel.isAsync){
|
||||
ready(0, function(){
|
||||
var requires = ["dijit/layout/StackController"];
|
||||
require(requires); // use indirection so modules not rolled into a build
|
||||
});
|
||||
}
|
||||
|
||||
// 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.)
|
||||
lang.extend(_WidgetBase, {
|
||||
// selected: Boolean
|
||||
// Parameter for children of `dijit.layout.StackContainer` or subclasses.
|
||||
// Specifies that this widget should be the initially displayed pane.
|
||||
// Note: to change the selected child use `dijit.layout.StackContainer.selectChild`
|
||||
selected: false,
|
||||
|
||||
// closable: Boolean
|
||||
// Parameter for children of `dijit.layout.StackContainer` or subclasses.
|
||||
// True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
|
||||
closable: false,
|
||||
|
||||
// iconClass: String
|
||||
// Parameter for children of `dijit.layout.StackContainer` or subclasses.
|
||||
// CSS Class specifying icon to use in label associated with this pane.
|
||||
iconClass: "dijitNoIcon",
|
||||
|
||||
// showTitle: Boolean
|
||||
// Parameter for children of `dijit.layout.StackContainer` or subclasses.
|
||||
// When true, display title of this widget as tab label etc., rather than just using
|
||||
// icon specified in iconClass
|
||||
showTitle: true
|
||||
});
|
||||
|
||||
return declare("dijit.layout.StackContainer", _LayoutWidget, {
|
||||
// summary:
|
||||
// A container that has multiple children, but shows only
|
||||
// one child at a time
|
||||
//
|
||||
// description:
|
||||
// A container for widgets (ContentPanes, for example) That displays
|
||||
// only one Widget at a time.
|
||||
//
|
||||
// Publishes topics [widgetId]-addChild, [widgetId]-removeChild, and [widgetId]-selectChild
|
||||
//
|
||||
// Can be base class for container, Wizard, Show, etc.
|
||||
|
||||
// doLayout: Boolean
|
||||
// If true, change the size of my currently displayed child to match my size
|
||||
doLayout: true,
|
||||
|
||||
// persist: Boolean
|
||||
// Remembers the selected child across sessions
|
||||
persist: false,
|
||||
|
||||
baseClass: "dijitStackContainer",
|
||||
|
||||
/*=====
|
||||
// selectedChildWidget: [readonly] dijit._Widget
|
||||
// References the currently selected child widget, if any.
|
||||
// Adjust selected child with selectChild() method.
|
||||
selectedChildWidget: null,
|
||||
=====*/
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
domClass.add(this.domNode, "dijitLayoutContainer");
|
||||
this.containerNode.setAttribute("role", "tabpanel");
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this.connect(this.domNode, "onkeypress", this._onKeyPress);
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
if(this._started){ return; }
|
||||
|
||||
var children = this.getChildren();
|
||||
|
||||
// Setup each page panel to be initially hidden
|
||||
array.forEach(children, this._setupChild, this);
|
||||
|
||||
// Figure out which child to initially display, defaulting to first one
|
||||
if(this.persist){
|
||||
this.selectedChildWidget = registry.byId(cookie(this.id + "_selectedChild"));
|
||||
}else{
|
||||
array.some(children, function(child){
|
||||
if(child.selected){
|
||||
this.selectedChildWidget = child;
|
||||
}
|
||||
return child.selected;
|
||||
}, this);
|
||||
}
|
||||
var selected = this.selectedChildWidget;
|
||||
if(!selected && children[0]){
|
||||
selected = this.selectedChildWidget = children[0];
|
||||
selected.selected = true;
|
||||
}
|
||||
|
||||
// Publish information about myself so any StackControllers can initialize.
|
||||
// This needs to happen before this.inherited(arguments) so that for
|
||||
// TabContainer, this._contentBox doesn't include the space for the tab labels.
|
||||
topic.publish(this.id+"-startup", {children: children, selected: selected});
|
||||
|
||||
// Startup each child widget, and do initial layout like setting this._contentBox,
|
||||
// then calls this.resize() which does the initial sizing on the selected child.
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
resize: function(){
|
||||
// Resize is called when we are first made visible (it's called from startup()
|
||||
// if we are initially visible). If this is the first time we've been made
|
||||
// visible then show our first child.
|
||||
if(!this._hasBeenShown){
|
||||
this._hasBeenShown = true;
|
||||
var selected = this.selectedChildWidget;
|
||||
if(selected){
|
||||
this._showChild(selected);
|
||||
}
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_setupChild: function(/*dijit._Widget*/ child){
|
||||
// Overrides _LayoutWidget._setupChild()
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
domClass.replace(child.domNode, "dijitHidden", "dijitVisible");
|
||||
|
||||
// remove the title attribute so it doesn't show up when i hover
|
||||
// over a node
|
||||
child.domNode.title = "";
|
||||
},
|
||||
|
||||
addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
|
||||
// Overrides _Container.addChild() to do layout and publish events
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
if(this._started){
|
||||
topic.publish(this.id+"-addChild", child, insertIndex); // publish
|
||||
|
||||
// in case the tab titles have overflowed from one line to two lines
|
||||
// (or, if this if first child, from zero lines to one line)
|
||||
// TODO: w/ScrollingTabController this is no longer necessary, although
|
||||
// ScrollTabController.resize() does need to get called to show/hide
|
||||
// the navigation buttons as appropriate, but that's handled in ScrollingTabController.onAddChild().
|
||||
// If this is updated to not layout [except for initial child added / last child removed], update
|
||||
// "childless startup" test in StackContainer.html to check for no resize event after second addChild()
|
||||
this.layout();
|
||||
|
||||
// if this is the first child, then select it
|
||||
if(!this.selectedChildWidget){
|
||||
this.selectChild(child);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeChild: function(/*dijit._Widget*/ page){
|
||||
// Overrides _Container.removeChild() to do layout and publish events
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
if(this._started){
|
||||
// this will notify any tablists to remove a button; do this first because it may affect sizing
|
||||
topic.publish(this.id + "-removeChild", page); // publish
|
||||
}
|
||||
|
||||
// If all our children 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._descendantsBeingDestroyed){ return; }
|
||||
|
||||
// Select new page to display, also updating TabController to show the respective tab.
|
||||
// Do this before layout call because it can affect the height of the TabController.
|
||||
if(this.selectedChildWidget === page){
|
||||
this.selectedChildWidget = undefined;
|
||||
if(this._started){
|
||||
var children = this.getChildren();
|
||||
if(children.length){
|
||||
this.selectChild(children[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(this._started){
|
||||
// In case the tab titles now take up one line instead of two lines
|
||||
// (note though that ScrollingTabController never overflows to multiple lines),
|
||||
// or the height has changed slightly because of addition/removal of tab which close icon
|
||||
this.layout();
|
||||
}
|
||||
},
|
||||
|
||||
selectChild: function(/*dijit._Widget|String*/ page, /*Boolean*/ animate){
|
||||
// summary:
|
||||
// Show the given widget (which must be one of my children)
|
||||
// page:
|
||||
// Reference to child widget or id of child widget
|
||||
|
||||
page = registry.byId(page);
|
||||
|
||||
if(this.selectedChildWidget != page){
|
||||
// Deselect old page and select new one
|
||||
var d = this._transition(page, this.selectedChildWidget, animate);
|
||||
this._set("selectedChildWidget", page);
|
||||
topic.publish(this.id+"-selectChild", page); // publish
|
||||
|
||||
if(this.persist){
|
||||
cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
|
||||
}
|
||||
}
|
||||
|
||||
return d; // If child has an href, promise that fires when the child's href finishes loading
|
||||
},
|
||||
|
||||
_transition: function(newWidget, oldWidget /*===== , animate =====*/){
|
||||
// summary:
|
||||
// Hide the old widget and display the new widget.
|
||||
// Subclasses should override this.
|
||||
// newWidget: dijit._Widget
|
||||
// The newly selected widget.
|
||||
// oldWidget: dijit._Widget
|
||||
// The previously selected widget.
|
||||
// animate: Boolean
|
||||
// Used by AccordionContainer to turn on/off slide effect.
|
||||
// tags:
|
||||
// protected extension
|
||||
if(oldWidget){
|
||||
this._hideChild(oldWidget);
|
||||
}
|
||||
var d = this._showChild(newWidget);
|
||||
|
||||
// Size the new widget, in case this is the first time it's being shown,
|
||||
// or I have been resized since the last time it was shown.
|
||||
// Note that page must be visible for resizing to work.
|
||||
if(newWidget.resize){
|
||||
if(this.doLayout){
|
||||
newWidget.resize(this._containerContentBox || this._contentBox);
|
||||
}else{
|
||||
// the child should pick it's own size but we still need to call resize()
|
||||
// (with no arguments) to let the widget lay itself out
|
||||
newWidget.resize();
|
||||
}
|
||||
}
|
||||
|
||||
return d; // If child has an href, promise that fires when the child's href finishes loading
|
||||
},
|
||||
|
||||
_adjacent: function(/*Boolean*/ forward){
|
||||
// summary:
|
||||
// Gets the next/previous child widget in this container from the current selection.
|
||||
var children = this.getChildren();
|
||||
var index = array.indexOf(children, this.selectedChildWidget);
|
||||
index += forward ? 1 : children.length - 1;
|
||||
return children[ index % children.length ]; // dijit._Widget
|
||||
},
|
||||
|
||||
forward: function(){
|
||||
// summary:
|
||||
// Advance to next page.
|
||||
return this.selectChild(this._adjacent(true), true);
|
||||
},
|
||||
|
||||
back: function(){
|
||||
// summary:
|
||||
// Go back to previous page.
|
||||
return this.selectChild(this._adjacent(false), true);
|
||||
},
|
||||
|
||||
_onKeyPress: function(e){
|
||||
topic.publish(this.id+"-containerKeyPress", { e: e, page: this}); // publish
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// Implement _LayoutWidget.layout() virtual method.
|
||||
var child = this.selectedChildWidget;
|
||||
if(child && child.resize){
|
||||
if(this.doLayout){
|
||||
child.resize(this._containerContentBox || this._contentBox);
|
||||
}else{
|
||||
child.resize();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_showChild: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Show the specified child by changing it's CSS, and call _onShow()/onShow() so
|
||||
// it can do any updates it needs regarding loading href's etc.
|
||||
// returns:
|
||||
// Promise that fires when page has finished showing, or true if there's no href
|
||||
var children = this.getChildren();
|
||||
page.isFirstChild = (page == children[0]);
|
||||
page.isLastChild = (page == children[children.length-1]);
|
||||
page._set("selected", true);
|
||||
|
||||
domClass.replace(page.domNode, "dijitVisible", "dijitHidden");
|
||||
|
||||
return (page._onShow && page._onShow()) || true;
|
||||
},
|
||||
|
||||
_hideChild: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Hide the specified child by changing it's CSS, and call _onHide() so
|
||||
// it's notified.
|
||||
page._set("selected", false);
|
||||
domClass.replace(page.domNode, "dijitHidden", "dijitVisible");
|
||||
|
||||
page.onHide && page.onHide();
|
||||
},
|
||||
|
||||
closeChild: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Callback when user clicks the [X] to remove a page.
|
||||
// If onClose() returns true then remove and destroy the child.
|
||||
// tags:
|
||||
// private
|
||||
var remove = page.onClose(this, page);
|
||||
if(remove){
|
||||
this.removeChild(page);
|
||||
// makes sure we can clean up executeScripts in ContentPane onUnLoad
|
||||
page.destroyRecursive();
|
||||
}
|
||||
},
|
||||
|
||||
destroyDescendants: function(/*Boolean*/ preserveDom){
|
||||
this._descendantsBeingDestroyed = true;
|
||||
this.selectedChildWidget = undefined;
|
||||
array.forEach(this.getChildren(), function(child){
|
||||
if(!preserveDom){
|
||||
this.removeChild(child);
|
||||
}
|
||||
child.destroyRecursive(preserveDom);
|
||||
}, this);
|
||||
this._descendantsBeingDestroyed = false;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,356 +0,0 @@
|
||||
define("dijit/layout/StackController", [
|
||||
"dojo/_base/array", // array.forEach array.indexOf array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/event", // event.stop
|
||||
"dojo/keys", // keys
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/_base/sniff", // has("ie")
|
||||
"../focus", // focus.focus()
|
||||
"../registry", // registry.byId
|
||||
"../_Widget",
|
||||
"../_TemplatedMixin",
|
||||
"../_Container",
|
||||
"../form/ToggleButton",
|
||||
"dojo/i18n!../nls/common"
|
||||
], function(array, declare, event, keys, lang, has,
|
||||
focus, registry, _Widget, _TemplatedMixin, _Container, ToggleButton){
|
||||
|
||||
/*=====
|
||||
var _Widget = dijit._Widget;
|
||||
var _TemplatedMixin = dijit._TemplatedMixin;
|
||||
var _Container = dijit._Container;
|
||||
var ToggleButton = dijit.form.ToggleButton;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/StackController
|
||||
// summary:
|
||||
// Set of buttons to select a page in a `dijit.layout.StackContainer`
|
||||
|
||||
var StackButton = declare("dijit.layout._StackButton", ToggleButton, {
|
||||
// summary:
|
||||
// Internal widget used by StackContainer.
|
||||
// description:
|
||||
// The button-like or tab-like object you click to select or delete a page
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// Override _FormWidget.tabIndex.
|
||||
// StackContainer buttons are not in the tab order by default.
|
||||
// Probably we should be calling this.startupKeyNavChildren() instead.
|
||||
tabIndex: "-1",
|
||||
|
||||
// closeButton: Boolean
|
||||
// When true, display close button for this tab
|
||||
closeButton: false,
|
||||
|
||||
_setCheckedAttr: function(/*Boolean*/ value, /*Boolean?*/ priorityChange){
|
||||
this.inherited(arguments);
|
||||
this.focusNode.removeAttribute("aria-pressed");
|
||||
},
|
||||
|
||||
buildRendering: function(/*Event*/ evt){
|
||||
this.inherited(arguments);
|
||||
(this.focusNode || this.domNode).setAttribute("role", "tab");
|
||||
},
|
||||
|
||||
onClick: function(/*Event*/ /*===== evt =====*/){
|
||||
// summary:
|
||||
// This is for TabContainer where the tabs are <span> rather than button,
|
||||
// so need to set focus explicitly (on some browsers)
|
||||
// Note that you shouldn't override this method, but you can connect to it.
|
||||
focus.focus(this.focusNode);
|
||||
|
||||
// ... now let StackController catch the event and tell me what to do
|
||||
},
|
||||
|
||||
onClickCloseButton: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// StackContainer connects to this function; if your widget contains a close button
|
||||
// then clicking it should call this function.
|
||||
// Note that you shouldn't override this method, but you can connect to it.
|
||||
evt.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var StackController = declare("dijit.layout.StackController", [_Widget, _TemplatedMixin, _Container], {
|
||||
// summary:
|
||||
// Set of buttons to select a page in a `dijit.layout.StackContainer`
|
||||
// description:
|
||||
// Monitors the specified StackContainer, and whenever a page is
|
||||
// added, deleted, or selected, updates itself accordingly.
|
||||
|
||||
baseClass: "dijitStackController",
|
||||
|
||||
templateString: "<span role='tablist' data-dojo-attach-event='onkeypress'></span>",
|
||||
|
||||
// containerId: [const] String
|
||||
// The id of the page container that I point to
|
||||
containerId: "",
|
||||
|
||||
// buttonWidget: [const] Constructor
|
||||
// The button widget to create to correspond to each page
|
||||
buttonWidget: StackButton,
|
||||
|
||||
constructor: function(){
|
||||
this.pane2button = {}; // mapping from pane id to buttons
|
||||
this.pane2connects = {}; // mapping from pane id to this.connect() handles
|
||||
this.pane2watches = {}; // mapping from pane id to watch() handles
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Listen to notifications from StackContainer
|
||||
this.subscribe(this.containerId+"-startup", "onStartup");
|
||||
this.subscribe(this.containerId+"-addChild", "onAddChild");
|
||||
this.subscribe(this.containerId+"-removeChild", "onRemoveChild");
|
||||
this.subscribe(this.containerId+"-selectChild", "onSelectChild");
|
||||
this.subscribe(this.containerId+"-containerKeyPress", "onContainerKeyPress");
|
||||
},
|
||||
|
||||
onStartup: function(/*Object*/ info){
|
||||
// summary:
|
||||
// Called after StackContainer has finished initializing
|
||||
// tags:
|
||||
// private
|
||||
array.forEach(info.children, this.onAddChild, this);
|
||||
if(info.selected){
|
||||
// Show button corresponding to selected pane (unless selected
|
||||
// is null because there are no panes)
|
||||
this.onSelectChild(info.selected);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
for(var pane in this.pane2button){
|
||||
this.onRemoveChild(registry.byId(pane));
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
onAddChild: function(/*dijit._Widget*/ page, /*Integer?*/ insertIndex){
|
||||
// summary:
|
||||
// Called whenever a page is added to the container.
|
||||
// Create button corresponding to the page.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// create an instance of the button widget
|
||||
// (remove typeof buttonWidget == string support in 2.0)
|
||||
var cls = lang.isString(this.buttonWidget) ? lang.getObject(this.buttonWidget) : this.buttonWidget;
|
||||
var button = new cls({
|
||||
id: this.id + "_" + page.id,
|
||||
label: page.title,
|
||||
dir: page.dir,
|
||||
lang: page.lang,
|
||||
textDir: page.textDir,
|
||||
showLabel: page.showTitle,
|
||||
iconClass: page.iconClass,
|
||||
closeButton: page.closable,
|
||||
title: page.tooltip
|
||||
});
|
||||
button.focusNode.setAttribute("aria-selected", "false");
|
||||
|
||||
|
||||
// map from page attribute to corresponding tab button attribute
|
||||
var pageAttrList = ["title", "showTitle", "iconClass", "closable", "tooltip"],
|
||||
buttonAttrList = ["label", "showLabel", "iconClass", "closeButton", "title"];
|
||||
|
||||
// watch() so events like page title changes are reflected in tab button
|
||||
this.pane2watches[page.id] = array.map(pageAttrList, function(pageAttr, idx){
|
||||
return page.watch(pageAttr, function(name, oldVal, newVal){
|
||||
button.set(buttonAttrList[idx], newVal);
|
||||
});
|
||||
});
|
||||
|
||||
// connections so that clicking a tab button selects the corresponding page
|
||||
this.pane2connects[page.id] = [
|
||||
this.connect(button, 'onClick', lang.hitch(this,"onButtonClick", page)),
|
||||
this.connect(button, 'onClickCloseButton', lang.hitch(this,"onCloseButtonClick", page))
|
||||
];
|
||||
|
||||
this.addChild(button, insertIndex);
|
||||
this.pane2button[page.id] = button;
|
||||
page.controlButton = button; // this value might be overwritten if two tabs point to same container
|
||||
if(!this._currentChild){ // put the first child into the tab order
|
||||
button.focusNode.setAttribute("tabIndex", "0");
|
||||
button.focusNode.setAttribute("aria-selected", "true");
|
||||
this._currentChild = page;
|
||||
}
|
||||
// make sure all tabs have the same length
|
||||
if(!this.isLeftToRight() && has("ie") && this._rectifyRtlTabList){
|
||||
this._rectifyRtlTabList();
|
||||
}
|
||||
},
|
||||
|
||||
onRemoveChild: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Called whenever a page is removed from the container.
|
||||
// Remove the button corresponding to the page.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this._currentChild === page){ this._currentChild = null; }
|
||||
|
||||
// disconnect/unwatch connections/watches related to page being removed
|
||||
array.forEach(this.pane2connects[page.id], lang.hitch(this, "disconnect"));
|
||||
delete this.pane2connects[page.id];
|
||||
array.forEach(this.pane2watches[page.id], function(w){ w.unwatch(); });
|
||||
delete this.pane2watches[page.id];
|
||||
|
||||
var button = this.pane2button[page.id];
|
||||
if(button){
|
||||
this.removeChild(button);
|
||||
delete this.pane2button[page.id];
|
||||
button.destroy();
|
||||
}
|
||||
delete page.controlButton;
|
||||
},
|
||||
|
||||
onSelectChild: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Called when a page has been selected in the StackContainer, either by me or by another StackController
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(!page){ return; }
|
||||
|
||||
if(this._currentChild){
|
||||
var oldButton=this.pane2button[this._currentChild.id];
|
||||
oldButton.set('checked', false);
|
||||
oldButton.focusNode.setAttribute("aria-selected", "false");
|
||||
oldButton.focusNode.setAttribute("tabIndex", "-1");
|
||||
}
|
||||
|
||||
var newButton=this.pane2button[page.id];
|
||||
newButton.set('checked', true);
|
||||
newButton.focusNode.setAttribute("aria-selected", "true");
|
||||
this._currentChild = page;
|
||||
newButton.focusNode.setAttribute("tabIndex", "0");
|
||||
var container = registry.byId(this.containerId);
|
||||
container.containerNode.setAttribute("aria-labelledby", newButton.id);
|
||||
},
|
||||
|
||||
onButtonClick: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Called whenever one of my child buttons is pressed in an attempt to select a page
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this._currentChild.id === page.id) {
|
||||
//In case the user clicked the checked button, keep it in the checked state because it remains to be the selected stack page.
|
||||
var button=this.pane2button[page.id];
|
||||
button.set('checked', true);
|
||||
}
|
||||
var container = registry.byId(this.containerId);
|
||||
container.selectChild(page);
|
||||
},
|
||||
|
||||
onCloseButtonClick: function(/*dijit._Widget*/ page){
|
||||
// summary:
|
||||
// Called whenever one of my child buttons [X] is pressed in an attempt to close a page
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var container = registry.byId(this.containerId);
|
||||
container.closeChild(page);
|
||||
if(this._currentChild){
|
||||
var b = this.pane2button[this._currentChild.id];
|
||||
if(b){
|
||||
focus.focus(b.focusNode || b.domNode);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: this is a bit redundant with forward, back api in StackContainer
|
||||
adjacent: function(/*Boolean*/ forward){
|
||||
// summary:
|
||||
// Helper for onkeypress to find next/previous button
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(!this.isLeftToRight() && (!this.tabPosition || /top|bottom/.test(this.tabPosition))){ forward = !forward; }
|
||||
// find currently focused button in children array
|
||||
var children = this.getChildren();
|
||||
var current = array.indexOf(children, this.pane2button[this._currentChild.id]);
|
||||
// pick next button to focus on
|
||||
var offset = forward ? 1 : children.length - 1;
|
||||
return children[ (current + offset) % children.length ]; // dijit._Widget
|
||||
},
|
||||
|
||||
onkeypress: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Handle keystrokes on the page list, for advancing to next/previous button
|
||||
// and closing the current page if the page is closable.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.disabled || e.altKey ){ return; }
|
||||
var forward = null;
|
||||
if(e.ctrlKey || !e._djpage){
|
||||
switch(e.charOrCode){
|
||||
case keys.LEFT_ARROW:
|
||||
case keys.UP_ARROW:
|
||||
if(!e._djpage){ forward = false; }
|
||||
break;
|
||||
case keys.PAGE_UP:
|
||||
if(e.ctrlKey){ forward = false; }
|
||||
break;
|
||||
case keys.RIGHT_ARROW:
|
||||
case keys.DOWN_ARROW:
|
||||
if(!e._djpage){ forward = true; }
|
||||
break;
|
||||
case keys.PAGE_DOWN:
|
||||
if(e.ctrlKey){ forward = true; }
|
||||
break;
|
||||
case keys.HOME:
|
||||
case keys.END:
|
||||
var children = this.getChildren();
|
||||
if(children && children.length){
|
||||
children[e.charOrCode == keys.HOME ? 0 : children.length-1].onClick();
|
||||
}
|
||||
event.stop(e);
|
||||
break;
|
||||
case keys.DELETE:
|
||||
if(this._currentChild.closable){
|
||||
this.onCloseButtonClick(this._currentChild);
|
||||
}
|
||||
event.stop(e);
|
||||
break;
|
||||
default:
|
||||
if(e.ctrlKey){
|
||||
if(e.charOrCode === keys.TAB){
|
||||
this.adjacent(!e.shiftKey).onClick();
|
||||
event.stop(e);
|
||||
}else if(e.charOrCode == "w"){
|
||||
if(this._currentChild.closable){
|
||||
this.onCloseButtonClick(this._currentChild);
|
||||
}
|
||||
event.stop(e); // avoid browser tab closing.
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle next/previous page navigation (left/right arrow, etc.)
|
||||
if(forward !== null){
|
||||
this.adjacent(forward).onClick();
|
||||
event.stop(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onContainerKeyPress: function(/*Object*/ info){
|
||||
// summary:
|
||||
// Called when there was a keypress on the container
|
||||
// tags:
|
||||
// private
|
||||
info.e._djpage = info.page;
|
||||
this.onkeypress(info.e);
|
||||
}
|
||||
});
|
||||
|
||||
StackController.StackButton = StackButton; // for monkey patching
|
||||
|
||||
return StackController;
|
||||
});
|
||||
@@ -1,79 +0,0 @@
|
||||
define("dijit/layout/TabContainer", [
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/_base/declare", // declare
|
||||
"./_TabContainerBase",
|
||||
"./TabController",
|
||||
"./ScrollingTabController"
|
||||
], function(lang, declare, _TabContainerBase, TabController, ScrollingTabController){
|
||||
|
||||
/*=====
|
||||
var _TabContainerBase = dijit.layout._TabContainerBase;
|
||||
var TabController = dijit.layout.TabController;
|
||||
var ScrollingTabController = dijit.layout.ScrollingTabController;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/TabContainer
|
||||
// summary:
|
||||
// A Container with tabs to select each child (only one of which is displayed at a time).
|
||||
|
||||
|
||||
return declare("dijit.layout.TabContainer", _TabContainerBase, {
|
||||
// summary:
|
||||
// A Container with tabs to select each child (only one of which is displayed at a time).
|
||||
// description:
|
||||
// A TabContainer is a container that has multiple panes, but shows only
|
||||
// one pane at a time. There are a set of tabs corresponding to each pane,
|
||||
// where each tab has the name (aka title) of the pane, and optionally a close button.
|
||||
|
||||
// useMenu: [const] Boolean
|
||||
// True if a menu should be used to select tabs when they are too
|
||||
// wide to fit the TabContainer, false otherwise.
|
||||
useMenu: true,
|
||||
|
||||
// useSlider: [const] Boolean
|
||||
// True if a slider should be used to select tabs when they are too
|
||||
// wide to fit the TabContainer, false otherwise.
|
||||
useSlider: true,
|
||||
|
||||
// controllerWidget: String
|
||||
// An optional parameter to override the widget used to display the tab labels
|
||||
controllerWidget: "",
|
||||
|
||||
_makeController: function(/*DomNode*/ srcNode){
|
||||
// summary:
|
||||
// Instantiate tablist controller widget and return reference to it.
|
||||
// Callback from _TabContainerBase.postCreate().
|
||||
// tags:
|
||||
// protected extension
|
||||
|
||||
var cls = this.baseClass + "-tabs" + (this.doLayout ? "" : " dijitTabNoLayout"),
|
||||
TabController = lang.getObject(this.controllerWidget);
|
||||
|
||||
return new TabController({
|
||||
id: this.id + "_tablist",
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
textDir: this.textDir,
|
||||
tabPosition: this.tabPosition,
|
||||
doLayout: this.doLayout,
|
||||
containerId: this.id,
|
||||
"class": cls,
|
||||
nested: this.nested,
|
||||
useMenu: this.useMenu,
|
||||
useSlider: this.useSlider,
|
||||
tabStripClass: this.tabStrip ? this.baseClass + (this.tabStrip ? "":"No") + "Strip": null
|
||||
}, srcNode);
|
||||
},
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Scrolling controller only works for horizontal non-nested tabs
|
||||
if(!this.controllerWidget){
|
||||
this.controllerWidget = (this.tabPosition == "top" || this.tabPosition == "bottom") && !this.nested ?
|
||||
"dijit.layout.ScrollingTabController" : "dijit.layout.TabController";
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,172 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/layout/templates/_TabButton.html':"<div role=\"presentation\" data-dojo-attach-point=\"titleNode\" data-dojo-attach-event='onclick:onClick'>\n <div role=\"presentation\" class='dijitTabInnerDiv' data-dojo-attach-point='innerDiv'>\n <div role=\"presentation\" class='dijitTabContent' data-dojo-attach-point='tabContent'>\n \t<div role=\"presentation\" data-dojo-attach-point='focusNode'>\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitTabButtonIcon\" data-dojo-attach-point='iconNode' />\n\t\t <span data-dojo-attach-point='containerNode' class='tabLabel'></span>\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" data-dojo-attach-point='closeNode'\n\t\t \t\tdata-dojo-attach-event='onclick: onClickCloseButton' role=\"presentation\">\n\t\t <span data-dojo-attach-point='closeText' class='dijitTabCloseText'>[x]</span\n\t\t ></span>\n\t\t\t</div>\n </div>\n </div>\n</div>\n"}});
|
||||
define("dijit/layout/TabController", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-attr", // domAttr.attr
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/lang", // lang.hitch lang.trim
|
||||
"./StackController",
|
||||
"../Menu",
|
||||
"../MenuItem",
|
||||
"dojo/text!./templates/_TabButton.html",
|
||||
"dojo/i18n!../nls/common"
|
||||
], function(declare, dom, domAttr, domClass, i18n, lang, StackController, Menu, MenuItem, template){
|
||||
|
||||
/*=====
|
||||
var StackController = dijit.layout.StackController;
|
||||
var Menu = dijit.Menu;
|
||||
var MenuItem = dijit.MenuItem;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/TabController
|
||||
// summary:
|
||||
// Set of tabs (the things with titles and a close button, that you click to show a tab panel).
|
||||
// Used internally by `dijit.layout.TabContainer`.
|
||||
|
||||
var TabButton = declare("dijit.layout._TabButton", StackController.StackButton, {
|
||||
// summary:
|
||||
// A tab (the thing you click to select a pane).
|
||||
// description:
|
||||
// Contains the title of the pane, and optionally a close-button to destroy the pane.
|
||||
// This is an internal widget and should not be instantiated directly.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// baseClass: String
|
||||
// The CSS class applied to the domNode.
|
||||
baseClass: "dijitTab",
|
||||
|
||||
// Apply dijitTabCloseButtonHover when close button is hovered
|
||||
cssStateNodes: {
|
||||
closeNode: "dijitTabCloseButton"
|
||||
},
|
||||
|
||||
templateString: template,
|
||||
|
||||
// Override _FormWidget.scrollOnFocus.
|
||||
// Don't scroll the whole tab container into view when the button is focused.
|
||||
scrollOnFocus: false,
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
dom.setSelectable(this.containerNode, false);
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
this.inherited(arguments);
|
||||
var n = this.domNode;
|
||||
|
||||
// Required to give IE6 a kick, as it initially hides the
|
||||
// tabs until they are focused on.
|
||||
setTimeout(function(){
|
||||
n.className = n.className;
|
||||
}, 1);
|
||||
},
|
||||
|
||||
_setCloseButtonAttr: function(/*Boolean*/ disp){
|
||||
// summary:
|
||||
// Hide/show close button
|
||||
this._set("closeButton", disp);
|
||||
domClass.toggle(this.innerDiv, "dijitClosable", disp);
|
||||
this.closeNode.style.display = disp ? "" : "none";
|
||||
if(disp){
|
||||
var _nlsResources = i18n.getLocalization("dijit", "common");
|
||||
if(this.closeNode){
|
||||
domAttr.set(this.closeNode,"title", _nlsResources.itemClose);
|
||||
}
|
||||
// add context menu onto title button
|
||||
this._closeMenu = new Menu({
|
||||
id: this.id+"_Menu",
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
textDir: this.textDir,
|
||||
targetNodeIds: [this.domNode]
|
||||
});
|
||||
|
||||
this._closeMenu.addChild(new MenuItem({
|
||||
label: _nlsResources.itemClose,
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
textDir: this.textDir,
|
||||
onClick: lang.hitch(this, "onClickCloseButton")
|
||||
}));
|
||||
}else{
|
||||
if(this._closeMenu){
|
||||
this._closeMenu.destroyRecursive();
|
||||
delete this._closeMenu;
|
||||
}
|
||||
}
|
||||
},
|
||||
_setLabelAttr: function(/*String*/ content){
|
||||
// summary:
|
||||
// Hook for set('label', ...) to work.
|
||||
// description:
|
||||
// takes an HTML string.
|
||||
// Inherited ToggleButton implementation will Set the label (text) of the button;
|
||||
// Need to set the alt attribute of icon on tab buttons if no label displayed
|
||||
this.inherited(arguments);
|
||||
if(!this.showLabel && !this.params.title){
|
||||
this.iconNode.alt = lang.trim(this.containerNode.innerText || this.containerNode.textContent || '');
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
if(this._closeMenu){
|
||||
this._closeMenu.destroyRecursive();
|
||||
delete this._closeMenu;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
var TabController = declare("dijit.layout.TabController", StackController, {
|
||||
// summary:
|
||||
// Set of tabs (the things with titles and a close button, that you click to show a tab panel).
|
||||
// Used internally by `dijit.layout.TabContainer`.
|
||||
// description:
|
||||
// Lets the user select the currently shown pane in a TabContainer or StackContainer.
|
||||
// TabController also monitors the TabContainer, and whenever a pane is
|
||||
// added or deleted updates itself accordingly.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
baseClass: "dijitTabController",
|
||||
|
||||
templateString: "<div role='tablist' data-dojo-attach-event='onkeypress:onkeypress'></div>",
|
||||
|
||||
// tabPosition: String
|
||||
// Defines where tabs go relative to the content.
|
||||
// "top", "bottom", "left-h", "right-h"
|
||||
tabPosition: "top",
|
||||
|
||||
// buttonWidget: Constructor
|
||||
// The tab widget to create to correspond to each page
|
||||
buttonWidget: TabButton,
|
||||
|
||||
_rectifyRtlTabList: function(){
|
||||
// summary:
|
||||
// For left/right TabContainer when page is RTL mode, rectify the width of all tabs to be equal, otherwise the tab widths are different in IE
|
||||
|
||||
if(0 >= this.tabPosition.indexOf('-h')){ return; }
|
||||
if(!this.pane2button){ return; }
|
||||
|
||||
var maxWidth = 0;
|
||||
for(var pane in this.pane2button){
|
||||
var ow = this.pane2button[pane].innerDiv.scrollWidth;
|
||||
maxWidth = Math.max(maxWidth, ow);
|
||||
}
|
||||
//unify the length of all the tabs
|
||||
for(pane in this.pane2button){
|
||||
this.pane2button[pane].innerDiv.style.width = maxWidth + 'px';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
TabController.TabButton = TabButton; // for monkey patching
|
||||
|
||||
return TabController;
|
||||
});
|
||||
@@ -1,255 +0,0 @@
|
||||
define("dijit/layout/_ContentPaneResizeMixin", [
|
||||
"dojo/_base/array", // array.filter array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.has
|
||||
"dojo/dom-class", // domClass.contains domClass.toggle
|
||||
"dojo/dom-geometry",// domGeometry.contentBox domGeometry.marginBox
|
||||
"dojo/_base/lang", // lang.mixin
|
||||
"dojo/query", // query
|
||||
"dojo/_base/sniff", // has("ie")
|
||||
"dojo/_base/window", // win.global
|
||||
"../registry", // registry.byId
|
||||
"./utils", // marginBox2contextBox
|
||||
"../_Contained"
|
||||
], function(array, declare, domAttr, domClass, domGeometry, lang, query, has, win,
|
||||
registry, layoutUtils, _Contained){
|
||||
|
||||
/*=====
|
||||
var _Contained = dijit._Contained;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/_ContentPaneResizeMixin
|
||||
// summary:
|
||||
// Resize() functionality of ContentPane. If there's a single layout widget
|
||||
// child then it will call resize() with the same dimensions as the ContentPane.
|
||||
// Otherwise just calls resize on each child.
|
||||
|
||||
|
||||
return declare("dijit.layout._ContentPaneResizeMixin", null, {
|
||||
// summary:
|
||||
// Resize() functionality of ContentPane. If there's a single layout widget
|
||||
// child then it will call resize() with the same dimensions as the ContentPane.
|
||||
// Otherwise just calls resize on each child.
|
||||
//
|
||||
// Also implements basic startup() functionality, where starting the parent
|
||||
// will start the children
|
||||
|
||||
// doLayout: Boolean
|
||||
// - false - don't adjust size of children
|
||||
// - true - if there is a single visible child widget, set it's size to
|
||||
// however big the ContentPane is
|
||||
doLayout: true,
|
||||
|
||||
// isLayoutContainer: [protected] Boolean
|
||||
// Indicates that this widget will call resize() on it's child widgets
|
||||
// when they become visible.
|
||||
isLayoutContainer: true,
|
||||
|
||||
startup: function(){
|
||||
// summary:
|
||||
// See `dijit.layout._LayoutWidget.startup` for description.
|
||||
// Although ContentPane doesn't extend _LayoutWidget, it does implement
|
||||
// the same API.
|
||||
|
||||
if(this._started){ return; }
|
||||
|
||||
var parent = this.getParent();
|
||||
this._childOfLayoutWidget = parent && parent.isLayoutContainer;
|
||||
|
||||
// I need to call resize() on my child/children (when I become visible), unless
|
||||
// I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
|
||||
this._needLayout = !this._childOfLayoutWidget;
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
if(this._isShown()){
|
||||
this._onShow();
|
||||
}
|
||||
|
||||
if(!this._childOfLayoutWidget){
|
||||
// If my parent isn't a layout container, since my style *may be* width=height=100%
|
||||
// or something similar (either set directly or via a CSS class),
|
||||
// monitor when my size changes so that I can re-layout.
|
||||
// For browsers where I can't directly monitor when my size changes,
|
||||
// monitor when the viewport changes size, which *may* indicate a size change for me.
|
||||
this.connect(has("ie") ? this.domNode : win.global, 'onresize', function(){
|
||||
// Using function(){} closure to ensure no arguments to resize.
|
||||
this._needLayout = !this._childOfLayoutWidget;
|
||||
this.resize();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_checkIfSingleChild: function(){
|
||||
// summary:
|
||||
// Test if we have exactly one visible widget as a child,
|
||||
// and if so assume that we are a container for that widget,
|
||||
// and should propagate startup() and resize() calls to it.
|
||||
// Skips over things like data stores since they aren't visible.
|
||||
|
||||
var childNodes = query("> *", this.containerNode).filter(function(node){
|
||||
return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
|
||||
}),
|
||||
childWidgetNodes = childNodes.filter(function(node){
|
||||
return domAttr.has(node, "data-dojo-type") || domAttr.has(node, "dojoType") || domAttr.has(node, "widgetId");
|
||||
}),
|
||||
candidateWidgets = array.filter(childWidgetNodes.map(registry.byNode), function(widget){
|
||||
return widget && widget.domNode && widget.resize;
|
||||
});
|
||||
|
||||
if(
|
||||
// all child nodes are widgets
|
||||
childNodes.length == childWidgetNodes.length &&
|
||||
|
||||
// all but one are invisible (like dojo.data)
|
||||
candidateWidgets.length == 1
|
||||
){
|
||||
this._singleChild = candidateWidgets[0];
|
||||
}else{
|
||||
delete this._singleChild;
|
||||
}
|
||||
|
||||
// So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
|
||||
domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
|
||||
},
|
||||
|
||||
resize: function(changeSize, resultSize){
|
||||
// summary:
|
||||
// See `dijit.layout._LayoutWidget.resize` for description.
|
||||
// Although ContentPane doesn't extend _LayoutWidget, it does implement
|
||||
// the same API.
|
||||
|
||||
// For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
|
||||
// never called, so resize() is our trigger to do the initial href download (see [20099]).
|
||||
// However, don't load href for closed TitlePanes.
|
||||
if(!this._wasShown && this.open !== false){
|
||||
this._onShow();
|
||||
}
|
||||
|
||||
this._resizeCalled = true;
|
||||
|
||||
this._scheduleLayout(changeSize, resultSize);
|
||||
},
|
||||
|
||||
_scheduleLayout: function(changeSize, resultSize){
|
||||
// summary:
|
||||
// Resize myself, and call resize() on each of my child layout widgets, either now
|
||||
// (if I'm currently visible) or when I become visible
|
||||
if(this._isShown()){
|
||||
this._layout(changeSize, resultSize);
|
||||
}else{
|
||||
this._needLayout = true;
|
||||
this._changeSize = changeSize;
|
||||
this._resultSize = resultSize;
|
||||
}
|
||||
},
|
||||
|
||||
_layout: function(changeSize, resultSize){
|
||||
// summary:
|
||||
// Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
|
||||
// Also, since I am a Container widget, each of my children expects me to
|
||||
// call resize() or layout() on them.
|
||||
//
|
||||
// Should be called on initialization and also whenever we get new content
|
||||
// (from an href, or from set('content', ...))... but deferred until
|
||||
// the ContentPane is visible
|
||||
|
||||
// Set margin box size, unless it wasn't specified, in which case use current size.
|
||||
if(changeSize){
|
||||
domGeometry.setMarginBox(this.domNode, changeSize);
|
||||
}
|
||||
|
||||
// Compute content box size of containerNode in case we [later] need to size our single child.
|
||||
var cn = this.containerNode;
|
||||
if(cn === this.domNode){
|
||||
// If changeSize or resultSize was passed to this method and this.containerNode ==
|
||||
// this.domNode then we can compute the content-box size without querying the node,
|
||||
// which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
|
||||
var mb = resultSize || {};
|
||||
lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
|
||||
if(!("h" in mb) || !("w" in mb)){
|
||||
mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values
|
||||
}
|
||||
this._contentBox = layoutUtils.marginBox2contentBox(cn, mb);
|
||||
}else{
|
||||
this._contentBox = domGeometry.getContentBox(cn);
|
||||
}
|
||||
|
||||
this._layoutChildren();
|
||||
|
||||
delete this._needLayout;
|
||||
},
|
||||
|
||||
_layoutChildren: function(){
|
||||
// Call _checkIfSingleChild() again in case app has manually mucked w/the content
|
||||
// of the ContentPane (rather than changing it through the set("content", ...) API.
|
||||
if(this.doLayout){
|
||||
this._checkIfSingleChild();
|
||||
}
|
||||
|
||||
if(this._singleChild && this._singleChild.resize){
|
||||
var cb = this._contentBox || domGeometry.getContentBox(this.containerNode);
|
||||
|
||||
// note: if widget has padding this._contentBox will have l and t set,
|
||||
// but don't pass them to resize() or it will doubly-offset the child
|
||||
this._singleChild.resize({w: cb.w, h: cb.h});
|
||||
}else{
|
||||
// All my child widgets are independently sized (rather than matching my size),
|
||||
// but I still need to call resize() on each child to make it layout.
|
||||
array.forEach(this.getChildren(), function(widget){
|
||||
if(widget.resize){
|
||||
widget.resize();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_isShown: function(){
|
||||
// summary:
|
||||
// Returns true if the content is currently shown.
|
||||
// description:
|
||||
// If I am a child of a layout widget then it actually returns true if I've ever been visible,
|
||||
// not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
|
||||
// tree every call, and at least solves the performance problem on page load by deferring loading
|
||||
// hidden ContentPanes until they are first shown
|
||||
|
||||
if(this._childOfLayoutWidget){
|
||||
// If we are TitlePane, etc - we return that only *IF* we've been resized
|
||||
if(this._resizeCalled && "open" in this){
|
||||
return this.open;
|
||||
}
|
||||
return this._resizeCalled;
|
||||
}else if("open" in this){
|
||||
return this.open; // for TitlePane, etc.
|
||||
}else{
|
||||
var node = this.domNode, parent = this.domNode.parentNode;
|
||||
return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") &&
|
||||
parent && parent.style && (parent.style.display != 'none');
|
||||
}
|
||||
},
|
||||
|
||||
_onShow: function(){
|
||||
// summary:
|
||||
// Called when the ContentPane is made visible
|
||||
// description:
|
||||
// For a plain ContentPane, this is called on initialization, from startup().
|
||||
// If the ContentPane is a hidden pane of a TabContainer etc., then it's
|
||||
// called whenever the pane is made visible.
|
||||
//
|
||||
// Does layout/resize of child widget(s)
|
||||
|
||||
if(this._needLayout){
|
||||
// If a layout has been scheduled for when we become visible, do it now
|
||||
this._layout(this._changeSize, this._resultSize);
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
// Need to keep track of whether ContentPane has been shown (which is different than
|
||||
// whether or not it's currently visible).
|
||||
this._wasShown = true;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,197 +0,0 @@
|
||||
define("dijit/layout/_LayoutWidget", [
|
||||
"dojo/_base/lang", // lang.mixin
|
||||
"../_Widget",
|
||||
"../_Container",
|
||||
"../_Contained",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.add domClass.remove
|
||||
"dojo/dom-geometry", // domGeometry.marginBox
|
||||
"dojo/dom-style", // domStyle.getComputedStyle
|
||||
"dojo/_base/sniff", // has("ie")
|
||||
"dojo/_base/window" // win.global
|
||||
], function(lang, _Widget, _Container, _Contained,
|
||||
declare, domClass, domGeometry, domStyle, has, win){
|
||||
|
||||
/*=====
|
||||
var _Widget = dijit._Widget;
|
||||
var _Container = dijit._Container;
|
||||
var _Contained = dijit._Contained;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/_LayoutWidget
|
||||
// summary:
|
||||
// _LayoutWidget Base class for a _Container widget which is responsible for laying out its children.
|
||||
// Widgets which mixin this code must define layout() to manage placement and sizing of the children.
|
||||
|
||||
|
||||
return declare("dijit.layout._LayoutWidget", [_Widget, _Container, _Contained], {
|
||||
// summary:
|
||||
// Base class for a _Container widget which is responsible for laying out its children.
|
||||
// Widgets which mixin this code must define layout() to manage placement and sizing of the children.
|
||||
|
||||
// baseClass: [protected extension] String
|
||||
// This class name is applied to the widget's domNode
|
||||
// and also may be used to generate names for sub nodes,
|
||||
// for example dijitTabContainer-content.
|
||||
baseClass: "dijitLayoutContainer",
|
||||
|
||||
// isLayoutContainer: [protected] Boolean
|
||||
// Indicates that this widget is going to call resize() on its
|
||||
// children widgets, setting their size, when they become visible.
|
||||
isLayoutContainer: true,
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
domClass.add(this.domNode, "dijitContainer");
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
// summary:
|
||||
// Called after all the widgets have been instantiated and their
|
||||
// dom nodes have been inserted somewhere under win.doc.body.
|
||||
//
|
||||
// Widgets should override this method to do any initialization
|
||||
// dependent on other widgets existing, and then call
|
||||
// this superclass method to finish things off.
|
||||
//
|
||||
// startup() in subclasses shouldn't do anything
|
||||
// size related because the size of the widget hasn't been set yet.
|
||||
|
||||
if(this._started){ return; }
|
||||
|
||||
// Need to call inherited first - so that child widgets get started
|
||||
// up correctly
|
||||
this.inherited(arguments);
|
||||
|
||||
// If I am a not being controlled by a parent layout widget...
|
||||
var parent = this.getParent && this.getParent();
|
||||
if(!(parent && parent.isLayoutContainer)){
|
||||
// Do recursive sizing and layout of all my descendants
|
||||
// (passing in no argument to resize means that it has to glean the size itself)
|
||||
this.resize();
|
||||
|
||||
// Since my parent isn't a layout container, and my style *may be* width=height=100%
|
||||
// or something similar (either set directly or via a CSS class),
|
||||
// monitor when viewport size changes so that I can re-layout.
|
||||
this.connect(win.global, 'onresize', function(){
|
||||
// Using function(){} closure to ensure no arguments passed to resize().
|
||||
this.resize();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
resize: function(changeSize, resultSize){
|
||||
// summary:
|
||||
// Call this to resize a widget, or after its size has changed.
|
||||
// description:
|
||||
// Change size mode:
|
||||
// When changeSize is specified, changes the marginBox of this widget
|
||||
// and forces it to relayout its contents accordingly.
|
||||
// changeSize may specify height, width, or both.
|
||||
//
|
||||
// If resultSize is specified it indicates the size the widget will
|
||||
// become after changeSize has been applied.
|
||||
//
|
||||
// Notification mode:
|
||||
// When changeSize is null, indicates that the caller has already changed
|
||||
// the size of the widget, or perhaps it changed because the browser
|
||||
// window was resized. Tells widget to relayout its contents accordingly.
|
||||
//
|
||||
// If resultSize is also specified it indicates the size the widget has
|
||||
// become.
|
||||
//
|
||||
// In either mode, this method also:
|
||||
// 1. Sets this._borderBox and this._contentBox to the new size of
|
||||
// the widget. Queries the current domNode size if necessary.
|
||||
// 2. Calls layout() to resize contents (and maybe adjust child widgets).
|
||||
//
|
||||
// changeSize: Object?
|
||||
// Sets the widget to this margin-box size and position.
|
||||
// May include any/all of the following properties:
|
||||
// | {w: int, h: int, l: int, t: int}
|
||||
//
|
||||
// resultSize: Object?
|
||||
// The margin-box size of this widget after applying changeSize (if
|
||||
// changeSize is specified). If caller knows this size and
|
||||
// passes it in, we don't need to query the browser to get the size.
|
||||
// | {w: int, h: int}
|
||||
|
||||
var node = this.domNode;
|
||||
|
||||
// set margin box size, unless it wasn't specified, in which case use current size
|
||||
if(changeSize){
|
||||
domGeometry.setMarginBox(node, changeSize);
|
||||
}
|
||||
|
||||
// If either height or width wasn't specified by the user, then query node for it.
|
||||
// But note that setting the margin box and then immediately querying dimensions may return
|
||||
// inaccurate results, so try not to depend on it.
|
||||
var mb = resultSize || {};
|
||||
lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
|
||||
if( !("h" in mb) || !("w" in mb) ){
|
||||
mb = lang.mixin(domGeometry.getMarginBox(node), mb); // just use domGeometry.marginBox() to fill in missing values
|
||||
}
|
||||
|
||||
// Compute and save the size of my border box and content box
|
||||
// (w/out calling domGeometry.getContentBox() since that may fail if size was recently set)
|
||||
var cs = domStyle.getComputedStyle(node);
|
||||
var me = domGeometry.getMarginExtents(node, cs);
|
||||
var be = domGeometry.getBorderExtents(node, cs);
|
||||
var bb = (this._borderBox = {
|
||||
w: mb.w - (me.w + be.w),
|
||||
h: mb.h - (me.h + be.h)
|
||||
});
|
||||
var pe = domGeometry.getPadExtents(node, cs);
|
||||
this._contentBox = {
|
||||
l: domStyle.toPixelValue(node, cs.paddingLeft),
|
||||
t: domStyle.toPixelValue(node, cs.paddingTop),
|
||||
w: bb.w - pe.w,
|
||||
h: bb.h - pe.h
|
||||
};
|
||||
|
||||
// Callback for widget to adjust size of its children
|
||||
this.layout();
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// summary:
|
||||
// Widgets override this method to size and position their contents/children.
|
||||
// When this is called this._contentBox is guaranteed to be set (see resize()).
|
||||
//
|
||||
// This is called after startup(), and also when the widget's size has been
|
||||
// changed.
|
||||
// tags:
|
||||
// protected extension
|
||||
},
|
||||
|
||||
_setupChild: function(/*dijit._Widget*/child){
|
||||
// summary:
|
||||
// Common setup for initial children and children which are added after startup
|
||||
// tags:
|
||||
// protected extension
|
||||
|
||||
var cls = this.baseClass + "-child "
|
||||
+ (child.baseClass ? this.baseClass + "-" + child.baseClass : "");
|
||||
domClass.add(child.domNode, cls);
|
||||
},
|
||||
|
||||
addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
|
||||
// Overrides _Container.addChild() to call _setupChild()
|
||||
this.inherited(arguments);
|
||||
if(this._started){
|
||||
this._setupChild(child);
|
||||
}
|
||||
},
|
||||
|
||||
removeChild: function(/*dijit._Widget*/ child){
|
||||
// Overrides _Container.removeChild() to remove class added by _setupChild()
|
||||
var cls = this.baseClass + "-child"
|
||||
+ (child.baseClass ?
|
||||
" " + this.baseClass + "-" + child.baseClass : "");
|
||||
domClass.remove(child.domNode, cls);
|
||||
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,155 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/layout/templates/TabContainer.html':"<div class=\"dijitTabContainer\">\n\t<div class=\"dijitTabListWrapper\" data-dojo-attach-point=\"tablistNode\"></div>\n\t<div data-dojo-attach-point=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" data-dojo-attach-point=\"containerNode\"></div>\n</div>\n"}});
|
||||
define("dijit/layout/_TabContainerBase", [
|
||||
"dojo/text!./templates/TabContainer.html",
|
||||
"./StackContainer",
|
||||
"./utils", // marginBox2contextBox, layoutChildren
|
||||
"../_TemplatedMixin",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.add
|
||||
"dojo/dom-geometry", // domGeometry.contentBox
|
||||
"dojo/dom-style" // domStyle.style
|
||||
], function(template, StackContainer, layoutUtils, _TemplatedMixin, declare, domClass, domGeometry, domStyle){
|
||||
|
||||
|
||||
/*=====
|
||||
var StackContainer = dijit.layout.StackContainer;
|
||||
var _TemplatedMixin = dijit._TemplatedMixin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/layout/_TabContainerBase
|
||||
// summary:
|
||||
// Abstract base class for TabContainer. Must define _makeController() to instantiate
|
||||
// and return the widget that displays the tab labels
|
||||
|
||||
|
||||
return declare("dijit.layout._TabContainerBase", [StackContainer, _TemplatedMixin], {
|
||||
// summary:
|
||||
// Abstract base class for TabContainer. Must define _makeController() to instantiate
|
||||
// and return the widget that displays the tab labels
|
||||
// description:
|
||||
// A TabContainer is a container that has multiple panes, but shows only
|
||||
// one pane at a time. There are a set of tabs corresponding to each pane,
|
||||
// where each tab has the name (aka title) of the pane, and optionally a close button.
|
||||
|
||||
// tabPosition: String
|
||||
// Defines where tabs go relative to tab content.
|
||||
// "top", "bottom", "left-h", "right-h"
|
||||
tabPosition: "top",
|
||||
|
||||
baseClass: "dijitTabContainer",
|
||||
|
||||
// tabStrip: [const] Boolean
|
||||
// Defines whether the tablist gets an extra class for layouting, putting a border/shading
|
||||
// around the set of tabs. Not supported by claro theme.
|
||||
tabStrip: false,
|
||||
|
||||
// nested: [const] Boolean
|
||||
// If true, use styling for a TabContainer nested inside another TabContainer.
|
||||
// For tundra etc., makes tabs look like links, and hides the outer
|
||||
// border since the outer TabContainer already has a border.
|
||||
nested: false,
|
||||
|
||||
templateString: template,
|
||||
|
||||
postMixInProperties: function(){
|
||||
// set class name according to tab position, ex: dijitTabContainerTop
|
||||
this.baseClass += this.tabPosition.charAt(0).toUpperCase() + this.tabPosition.substr(1).replace(/-.*/, "");
|
||||
|
||||
this.srcNodeRef && domStyle.set(this.srcNodeRef, "visibility", "hidden");
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Create the tab list that will have a tab (a.k.a. tab button) for each tab panel
|
||||
this.tablist = this._makeController(this.tablistNode);
|
||||
|
||||
if(!this.doLayout){ domClass.add(this.domNode, "dijitTabContainerNoLayout"); }
|
||||
|
||||
if(this.nested){
|
||||
/* workaround IE's lack of support for "a > b" selectors by
|
||||
* tagging each node in the template.
|
||||
*/
|
||||
domClass.add(this.domNode, "dijitTabContainerNested");
|
||||
domClass.add(this.tablist.containerNode, "dijitTabContainerTabListNested");
|
||||
domClass.add(this.tablistSpacer, "dijitTabContainerSpacerNested");
|
||||
domClass.add(this.containerNode, "dijitTabPaneWrapperNested");
|
||||
}else{
|
||||
domClass.add(this.domNode, "tabStrip-" + (this.tabStrip ? "enabled" : "disabled"));
|
||||
}
|
||||
},
|
||||
|
||||
_setupChild: function(/*dijit._Widget*/ tab){
|
||||
// Overrides StackContainer._setupChild().
|
||||
domClass.add(tab.domNode, "dijitTabPane");
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
if(this._started){ return; }
|
||||
|
||||
// wire up the tablist and its tabs
|
||||
this.tablist.startup();
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// Overrides StackContainer.layout().
|
||||
// Configure the content pane to take up all the space except for where the tabs are
|
||||
|
||||
if(!this._contentBox || typeof(this._contentBox.l) == "undefined"){return;}
|
||||
|
||||
var sc = this.selectedChildWidget;
|
||||
|
||||
if(this.doLayout){
|
||||
// position and size the titles and the container node
|
||||
var titleAlign = this.tabPosition.replace(/-h/, "");
|
||||
this.tablist.layoutAlign = titleAlign;
|
||||
var children = [this.tablist, {
|
||||
domNode: this.tablistSpacer,
|
||||
layoutAlign: titleAlign
|
||||
}, {
|
||||
domNode: this.containerNode,
|
||||
layoutAlign: "client"
|
||||
}];
|
||||
layoutUtils.layoutChildren(this.domNode, this._contentBox, children);
|
||||
|
||||
// Compute size to make each of my children.
|
||||
// children[2] is the margin-box size of this.containerNode, set by layoutChildren() call above
|
||||
this._containerContentBox = layoutUtils.marginBox2contentBox(this.containerNode, children[2]);
|
||||
|
||||
if(sc && sc.resize){
|
||||
sc.resize(this._containerContentBox);
|
||||
}
|
||||
}else{
|
||||
// just layout the tab controller, so it can position left/right buttons etc.
|
||||
if(this.tablist.resize){
|
||||
//make the tabs zero width so that they don't interfere with width calc, then reset
|
||||
var s = this.tablist.domNode.style;
|
||||
s.width="0";
|
||||
var width = domGeometry.getContentBox(this.domNode).w;
|
||||
s.width="";
|
||||
this.tablist.resize({w: width});
|
||||
}
|
||||
|
||||
// and call resize() on the selected pane just to tell it that it's been made visible
|
||||
if(sc && sc.resize){
|
||||
sc.resize();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
if(this.tablist){
|
||||
this.tablist.destroy();
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,141 +0,0 @@
|
||||
define("dijit/layout/utils", [
|
||||
"dojo/_base/array", // array.filter array.forEach
|
||||
"dojo/dom-class", // domClass.add domClass.remove
|
||||
"dojo/dom-geometry", // domGeometry.marginBox
|
||||
"dojo/dom-style", // domStyle.getComputedStyle
|
||||
"dojo/_base/lang", // lang.mixin
|
||||
".." // for exporting symbols to dijit, remove in 2.0
|
||||
], function(array, domClass, domGeometry, domStyle, lang, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/layout/utils
|
||||
// summary:
|
||||
// marginBox2contentBox() and layoutChildren()
|
||||
|
||||
var layout = lang.getObject("layout", true, dijit);
|
||||
/*===== layout = dijit.layout =====*/
|
||||
|
||||
layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
|
||||
// summary:
|
||||
// Given the margin-box size of a node, return its content box size.
|
||||
// Functions like domGeometry.contentBox() but is more reliable since it doesn't have
|
||||
// to wait for the browser to compute sizes.
|
||||
var cs = domStyle.getComputedStyle(node);
|
||||
var me = domGeometry.getMarginExtents(node, cs);
|
||||
var pb = domGeometry.getPadBorderExtents(node, cs);
|
||||
return {
|
||||
l: domStyle.toPixelValue(node, cs.paddingLeft),
|
||||
t: domStyle.toPixelValue(node, cs.paddingTop),
|
||||
w: mb.w - (me.w + pb.w),
|
||||
h: mb.h - (me.h + pb.h)
|
||||
};
|
||||
};
|
||||
|
||||
function capitalize(word){
|
||||
return word.substring(0,1).toUpperCase() + word.substring(1);
|
||||
}
|
||||
|
||||
function size(widget, dim){
|
||||
// size the child
|
||||
var newSize = widget.resize ? widget.resize(dim) : domGeometry.setMarginBox(widget.domNode, dim);
|
||||
|
||||
// record child's size
|
||||
if(newSize){
|
||||
// if the child returned it's new size then use that
|
||||
lang.mixin(widget, newSize);
|
||||
}else{
|
||||
// otherwise, call getMarginBox(), but favor our own numbers when we have them.
|
||||
// the browser lies sometimes
|
||||
lang.mixin(widget, domGeometry.getMarginBox(widget.domNode));
|
||||
lang.mixin(widget, dim);
|
||||
}
|
||||
}
|
||||
|
||||
layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Widget[]*/ children,
|
||||
/*String?*/ changedRegionId, /*Number?*/ changedRegionSize){
|
||||
// summary:
|
||||
// Layout a bunch of child dom nodes within a parent dom node
|
||||
// container:
|
||||
// parent node
|
||||
// dim:
|
||||
// {l, t, w, h} object specifying dimensions of container into which to place children
|
||||
// children:
|
||||
// an array of Widgets or at least objects containing:
|
||||
// * domNode: pointer to DOM node to position
|
||||
// * region or layoutAlign: position to place DOM node
|
||||
// * resize(): (optional) method to set size of node
|
||||
// * id: (optional) Id of widgets, referenced from resize object, below.
|
||||
// changedRegionId:
|
||||
// If specified, the slider for the region with the specified id has been dragged, and thus
|
||||
// the region's height or width should be adjusted according to changedRegionSize
|
||||
// changedRegionSize:
|
||||
// See changedRegionId.
|
||||
|
||||
// copy dim because we are going to modify it
|
||||
dim = lang.mixin({}, dim);
|
||||
|
||||
domClass.add(container, "dijitLayoutContainer");
|
||||
|
||||
// Move "client" elements to the end of the array for layout. a11y dictates that the author
|
||||
// needs to be able to put them in the document in tab-order, but this algorithm requires that
|
||||
// client be last. TODO: move these lines to LayoutContainer? Unneeded other places I think.
|
||||
children = array.filter(children, function(item){ return item.region != "center" && item.layoutAlign != "client"; })
|
||||
.concat(array.filter(children, function(item){ return item.region == "center" || item.layoutAlign == "client"; }));
|
||||
|
||||
// set positions/sizes
|
||||
array.forEach(children, function(child){
|
||||
var elm = child.domNode,
|
||||
pos = (child.region || child.layoutAlign);
|
||||
if(!pos){
|
||||
throw new Error("No region setting for " + child.id)
|
||||
}
|
||||
|
||||
// set elem to upper left corner of unused space; may move it later
|
||||
var elmStyle = elm.style;
|
||||
elmStyle.left = dim.l+"px";
|
||||
elmStyle.top = dim.t+"px";
|
||||
elmStyle.position = "absolute";
|
||||
|
||||
domClass.add(elm, "dijitAlign" + capitalize(pos));
|
||||
|
||||
// Size adjustments to make to this child widget
|
||||
var sizeSetting = {};
|
||||
|
||||
// Check for optional size adjustment due to splitter drag (height adjustment for top/bottom align
|
||||
// panes and width adjustment for left/right align panes.
|
||||
if(changedRegionId && changedRegionId == child.id){
|
||||
sizeSetting[child.region == "top" || child.region == "bottom" ? "h" : "w"] = changedRegionSize;
|
||||
}
|
||||
|
||||
// set size && adjust record of remaining space.
|
||||
// note that setting the width of a <div> may affect its height.
|
||||
if(pos == "top" || pos == "bottom"){
|
||||
sizeSetting.w = dim.w;
|
||||
size(child, sizeSetting);
|
||||
dim.h -= child.h;
|
||||
if(pos == "top"){
|
||||
dim.t += child.h;
|
||||
}else{
|
||||
elmStyle.top = dim.t + dim.h + "px";
|
||||
}
|
||||
}else if(pos == "left" || pos == "right"){
|
||||
sizeSetting.h = dim.h;
|
||||
size(child, sizeSetting);
|
||||
dim.w -= child.w;
|
||||
if(pos == "left"){
|
||||
dim.l += child.w;
|
||||
}else{
|
||||
elmStyle.left = dim.l + dim.w + "px";
|
||||
}
|
||||
}else if(pos == "client" || pos == "center"){
|
||||
size(child, dim);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
marginBox2contentBox: layout.marginBox2contentBox,
|
||||
layoutChildren: layout.layoutChildren
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user