define("dojox/layout/ToggleSplitter", ["dojo", "dijit", "dijit/layout/BorderContainer"], function(dojo, dijit) { dojo.experimental("dojox.layout.ToggleSplitter"); var 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: '
' + '' + '
', 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 = "▴", 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 = "▲"; }else if(region == "top" && !on || region == "bottom" && on){ arrow = "▼"; }else if(region == "right" && on || region == "left" && !on){ arrow = "▶"; }else if(region == "right" && !on || region == "left" && on){ arrow = "◀"; } this.a11yText.innerHTML = arrow; }, _setStateAttr: function(/*String*/ 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: "" }); return ToggleSplitter; });