summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/layout/ToggleSplitter.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dojox/layout/ToggleSplitter.js')
-rw-r--r--js/dojo/dojox/layout/ToggleSplitter.js296
1 files changed, 296 insertions, 0 deletions
diff --git a/js/dojo/dojox/layout/ToggleSplitter.js b/js/dojo/dojox/layout/ToggleSplitter.js
new file mode 100644
index 0000000..40f0383
--- /dev/null
+++ b/js/dojo/dojox/layout/ToggleSplitter.js
@@ -0,0 +1,296 @@
+//>>built
+define("dojox/layout/ToggleSplitter", ["dojo", "dijit", "dijit/layout/BorderContainer"], function(dojo, dijit) {
+
+dojo.experimental("dojox.layout.ToggleSplitter");
+
+dojo.declare("dojox.layout.ToggleSplitter", dijit.layout._Splitter, {
+ // summary:
+ // A draggable and clickable 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,
+=====*/
+
+ // state: String
+ // the initial and current state of the splitter (and its attached pane)
+ // It has three values: full, collapsed (optional), closed
+ state: "full",
+
+ // _closedSize: String
+ // the css height/width value to apply by default when the attached pane is closed
+ _closedSize: "0",
+
+ baseClass: "dojoxToggleSplitter",
+
+ templateString: '<div class="dijitSplitter dojoxToggleSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse">' +
+ '<div dojoAttachPoint="toggleNode" class="dijitSplitterThumb dojoxToggleSplitterIcon" tabIndex="0" role="separator" ' +
+ 'dojoAttachEvent="onmousedown:_onToggleNodeMouseDown,onclick:_toggle,onmouseenter:_onToggleNodeMouseMove,onmouseleave:_onToggleNodeMouseMove,onfocus:_onToggleNodeMouseMove,onblur:_onToggleNodeMouseMove">' +
+ '<span class="dojoxToggleSplitterA11y" dojoAttachPoint="a11yText"></span></div>' +
+ '</div>',
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // add a region css hook so that it can figure out the region correctly
+ var region = this.region;
+ dojo.addClass(this.domNode, this.baseClass + region.charAt(0).toUpperCase() + region.substring(1));
+ },
+
+ startup: function(){
+ this.inherited(arguments);
+
+ // we have to wait until startup to be sure the child exists in the dom
+ // and has non-zero size (if its supposed to be showing)
+ var parentPane = this.child,
+ paneNode = this.child.domNode,
+ intPaneSize = dojo.style(paneNode, (this.horizontal ? "height" : "width"));
+
+ this.domNode.setAttribute("aria-controls", paneNode.id);
+
+ // creation of splitters is an opaque process in BorderContainer,
+ // so if we want to get init params, we have to retrieve them from the attached BC child
+ // NOTE: for this to work we have to extend the prototype of dijit._Widget (some more)
+ dojo.forEach(["toggleSplitterState", "toggleSplitterFullSize", "toggleSplitterCollapsedSize"], function(name){
+ var pname = name.substring("toggleSplitter".length);
+ pname = pname.charAt(0).toLowerCase() + pname.substring(1);
+ if(name in this.child){
+ this[pname] = this.child[name];
+ }
+ }, this);
+
+ if(!this.fullSize){
+ // Store the current size as the fullSize if none was provided
+ // dojo.style always returns a integer (pixel) value for height/width
+ // use an arbitrary default if a pane was initialized closed and no fullSize provided
+ // If collapsedSize is not specified, collapsed state does not exist.
+ this.fullSize = this.state == "full" ? intPaneSize + "px" : "75px";
+ }
+
+ this._openStyleProps = this._getStyleProps(paneNode, "full");
+
+ // update state
+ this._started = true;
+ this.set("state", this.state);
+
+ return this;
+ },
+
+ _onKeyPress: function(evt){
+ if(this.state == "full"){
+ this.inherited(arguments);
+ }
+ if(evt.charCode == dojo.keys.SPACE || evt.keyCode == dojo.keys.ENTER){
+ this._toggle(evt);
+ }
+ },
+
+ _onToggleNodeMouseDown: function(evt){
+ dojo.stopEvent(evt);
+ this.toggleNode.focus();
+ },
+
+ _startDrag: function(e){
+ if(this.state == "full"){
+ this.inherited(arguments);
+ }
+ },
+
+ _stopDrag: function(e){
+ this.inherited(arguments);
+ this.toggleNode.blur();
+ },
+
+ _toggle: function(evt){
+ var state;
+ switch(this.state){
+ case "full":
+ state = this.collapsedSize ? "collapsed" : "closed";
+ break;
+ case "collapsed":
+ state = "closed";
+ break;
+ default:
+ state = "full";
+ }
+ this.set("state", state);
+ },
+
+ _onToggleNodeMouseMove: function(evt){
+ var baseClass = this.baseClass,
+ toggleNode = this.toggleNode,
+ on = this.state == "full" || this.state == "collapsed",
+ leave = evt.type == "mouseout" || evt.type == "blur";
+
+ dojo.toggleClass(toggleNode, baseClass + "IconOpen", leave && on);
+ dojo.toggleClass(toggleNode, baseClass + "IconOpenHover", !leave && on);
+ dojo.toggleClass(toggleNode, baseClass + "IconClosed", leave && !on);
+ dojo.toggleClass(toggleNode, baseClass + "IconClosedHover", !leave && !on);
+ },
+
+ _handleOnChange: function(preState){
+ // summary
+ // Effect the state change with the new value of this.state
+ var paneNode = this.child.domNode,
+ openProps, paneStyle,
+ dim = this.horizontal ? "height" : "width";
+
+ if(this.state == "full"){
+ // change to full open state
+ var styleProps = dojo.mixin({
+ display: "block",
+ overflow: "auto",
+ visibility: "visible"
+ }, this._openStyleProps);
+ styleProps[dim] = (this._openStyleProps && this._openStyleProps[dim]) ? this._openStyleProps[dim] : this.fullSize;
+
+ dojo.style(this.domNode, "cursor", "");
+ dojo.style(paneNode, styleProps);
+ }else if(this.state == "collapsed"){
+ paneStyle = dojo.getComputedStyle(paneNode);
+ openProps = this._getStyleProps(paneNode, "full", paneStyle);
+ this._openStyleProps = openProps;
+
+ dojo.style(this.domNode, "cursor", "auto");
+ dojo.style(paneNode, dim, this.collapsedSize);
+ }else{
+ // change to closed state
+ if(!this.collapsedSize){
+ paneStyle = dojo.getComputedStyle(paneNode);
+ openProps = this._getStyleProps(paneNode, "full", paneStyle);
+ this._openStyleProps = openProps;
+ }
+ var closedProps = this._getStyleProps(paneNode, "closed", paneStyle);
+
+ dojo.style(this.domNode, "cursor", "auto");
+ dojo.style(paneNode, closedProps);
+ }
+ this._setStateClass();
+ if(this.container._started){
+ this.container._layoutChildren(this.region);
+ }
+ },
+
+ _getStyleProps: function(paneNode, state, paneStyle){
+ // summary:
+ // Create an object with the style property name: values
+ // that will need to be applied to the child pane render the given state
+ if(!paneStyle){
+ paneStyle = dojo.getComputedStyle(paneNode);
+ }
+ var styleProps = {},
+ dim = this.horizontal ? "height" : "width";
+
+ styleProps["overflow"] = (state != "closed") ? paneStyle["overflow"] : "hidden";
+ styleProps["visibility"] = (state != "closed") ? paneStyle["visibility"] : "hidden";
+
+ // Use the inline width/height style value, in preference to the computedStyle
+ // for the open width/height
+ styleProps[dim] = (state != "closed") ? paneNode.style[dim] || paneStyle[dim] : this._closedSize;
+
+ // We include the padding, border, margin width values for restoring on state full open
+ var edgeNames = ["Top", "Right", "Bottom", "Left"];
+ dojo.forEach(["padding", "margin", "border"], function(pname){
+ for(var i = 0; i < edgeNames.length; i++){
+ var fullName = pname + edgeNames[i];
+ if(pname == "border"){
+ fullName += "Width";
+ }
+ if(undefined !== paneStyle[fullName]){
+ styleProps[fullName] = (state != "closed") ? paneStyle[fullName] : 0;
+ }
+ }
+ });
+
+ return styleProps;
+ },
+
+ _setStateClass: function(){
+ // Summary:
+ // Apply the appropriate classes for the current open state
+ var arrow = "&#9652", region = this.region.toLowerCase(),
+ baseClass = this.baseClass,
+ toggleNode = this.toggleNode,
+ on = this.state == "full" || this.state == "collapsed",
+ focused = this.focused;
+
+ dojo.toggleClass(toggleNode, baseClass + "IconOpen", on && !focused);
+ dojo.toggleClass(toggleNode, baseClass + "IconClosed", !on && !focused);
+ dojo.toggleClass(toggleNode, baseClass + "IconOpenHover", on && focused);
+ dojo.toggleClass(toggleNode, baseClass + "IconClosedHover", !on && focused);
+
+ // For a11y
+ if(region == "top" && on || region == "bottom" && !on){
+ arrow = "&#9650";
+ }else if(region == "top" && !on || region == "bottom" && on){
+ arrow = "&#9660";
+ }else if(region == "right" && on || region == "left" && !on){
+ arrow = "&#9654";
+ }else if(region == "right" && !on || region == "left" && on){
+ arrow = "&#9664";
+ }
+
+ this.a11yText.innerHTML = arrow;
+ },
+
+ _setStateAttr: function(/*Strring*/ state){
+ // summary:
+ // setter for the state property
+ if(!this._started) {
+ return;
+ }
+ var preState = this.state;
+ this.state = state;
+
+ this._handleOnChange(preState);
+ var evtName;
+ switch(state){
+ case "full":
+ this.domNode.setAttribute("aria-expanded", true);
+ evtName = "onOpen";
+ break;
+ case "collapsed":
+ this.domNode.setAttribute("aria-expanded", true);
+ evtName = "onCollapsed";
+ break;
+ default:
+ this.domNode.setAttribute("aria-expanded", false);
+ evtName = "onClosed";
+ }
+ this[evtName](this.child);
+ },
+
+ onOpen: function(pane){ /*Stub*/ },
+ onCollapsed: function(pane){ /*Stub*/ },
+ onClosed: function(pane){ /*Stub*/ }
+});
+
+// As BC places no constraints on what kind of widgets can be children
+// we have to extend the base class to ensure the properties we need can be set (both in markup and programatically)
+dojo.extend(dijit._Widget, {
+ // toggleSplitterOpen: Boolean
+ toggleSplitterState: "full",
+
+ // toggleSplitterClosedThreshold: String
+ // A css size value (e.g. "100px")
+ toggleSplitterFullSize: "",
+
+ toggleSplitterCollapsedSize: ""
+});
+
+}); \ No newline at end of file