Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Support assigning multiple panes to the same !BorderContainer region,…

… so !BorderContainer can be used in place of !SplitContainer or !LayoutContainer without requiring nested !BorderContainer widgets.

Panes can specify a "layoutPriority" attribute that controls which panes are closer to the edges of the !BorderContainer whenever two panes have the same region, or top and left / bottom and right panes are competing.

Also includes a bug fix for display of dragged bottom/right splitter when it's moved beyond its maximum allowed value.

Fixes #11030 !strict.
  • Loading branch information...
commit efe42d1ba357e76141f79c2c2aa7762bd9988977 1 parent accef4e
Bill Keese authored
43  layout/BorderContainer.js
@@ -15,13 +15,15 @@ dojo.declare(
15 15
 	//		include optional splitters (splitter="true") to make them resizable by the user.  The remaining
16 16
 	//		space is designated for the center region.
17 17
 	//
18  
-	//		NOTE: Splitters must not be more than 50 pixels in width.
19  
-	//
20 18
 	//		The outer size must be specified on the BorderContainer node.  Width must be specified for the sides
21 19
 	//		and height for the top and bottom, respectively.  No dimensions should be specified on the center;
22 20
 	//		it will fill the remaining space.  Regions named "leading" and "trailing" may be used just like
23 21
 	//		"left" and "right" except that they will be reversed in right-to-left environments.
24 22
 	//
  23
+	//		For complex layouts, multiple children can be specified for a single region.   In this case, the
  24
+	//		layoutPriority flag on the children determines which child is closer to the edge (low layoutPriority)
  25
+	//		and which child is closer to the center (high layoutPriority).   layoutPriority can also be used
  26
+	//		instead of the design attribute to conrol layout precedence of horizontal vs. vertical panes.
25 27
 	// example:
26 28
 	// |	<div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="false"
27 29
 	// |            style="width: 400px; height: 300px;">
@@ -57,11 +59,6 @@ dojo.declare(
57 59
 	// 		Optional hook to override the default Splitter widget used by BorderContainer
58 60
 	_splitterClass: "dijit.layout._Splitter",
59 61
 
60  
-	constructor: function(){
61  
-		this._splitters = {};
62  
-		this._splitterThickness = {};
63  
-	},
64  
-
65 62
 	postMixInProperties: function(){
66 63
 		// change class name to indicate that BorderContainer is being used purely for
67 64
 		// layout (like LayoutContainer) rather than for pretty formatting.
@@ -213,21 +210,28 @@ dojo.declare(
213 210
 
214 211
 		// Generate list of wrappers of my children in the order that I want layoutChildren()
215 212
 		// to process them (i.e. from the outside to the inside)
216  
-		var wrappers = dojo.map(this.getChildren(), function(child){
  213
+		var wrappers = dojo.map(this.getChildren(), function(child, idx){
217 214
 			return {
218 215
 				pane: child,
219  
-				firstPriority: child.region == "center" ? Infinity : 0,
220  
-				secondPriority: (this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1)
  216
+				weight: [
  217
+					child.region == "center" ? Infinity : 0,
  218
+					child.layoutPriority,
  219
+					(this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
  220
+					idx
  221
+				]
221 222
 			};
222 223
 		}, this);
223 224
 		wrappers.sort(function(a, b){
224  
-			var res = a.firstPriority != b.firstPriority ?
225  
-				a.firstPriority - b.firstPriority :
226  
-				a.secondPriority - b.secondPriority;
227  
-			return res;
  225
+			var aw = a.weight, bw = b.weight;
  226
+			for(var i=0; i<aw.length; i++){
  227
+				if(aw[i] != bw[i]){
  228
+					return aw[i] - bw[i];
  229
+				}
  230
+			}
  231
+			return 0;
228 232
 		});
229 233
 
230  
-		// Make new list, combining the external children with splitters and gutters
  234
+		// Make new list, combining the externally specified children with splitters and gutters
231 235
 		var childrenAndSplitters = [];
232 236
 		dojo.forEach(wrappers, function(wrapper){
233 237
 			var pane = wrapper.pane;
@@ -272,6 +276,12 @@ dojo.extend(dijit._Widget, {
272 276
 	//		See the `dijit.layout.BorderContainer` description for details.
273 277
 	region: '',
274 278
 
  279
+	// layoutPriority: [const] Number
  280
+	//		Parameter for children of `dijit.layout.BorderContainer`.
  281
+	//		Children with a higher layoutPriority will be placed closer to the BorderContainer center,
  282
+	//		between children with a lower layoutPriority.
  283
+	layoutPriority: 0,
  284
+
275 285
 	// splitter: [const] Boolean
276 286
 	//		Parameter for child of `dijit.layout.BorderContainer` where region != "center".
277 287
 	//		If true, enables user to resize the widget by putting a draggable splitter between
@@ -403,7 +413,7 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
403 413
 					layoutFunc(boundChildSize);
404 414
 				}
405 415
 				// TODO: setting style directly (usually) sets content box size, need to set margin box size
406  
-				splitterStyle[splitterAttr] = delta + splitterStart + (boundChildSize - childSize) + "px";
  416
+				splitterStyle[splitterAttr] = delta + splitterStart + factor*(boundChildSize - childSize) + "px";
407 417
 			}),
408 418
 			dojo.connect(de, "ondragstart", dojo.stopEvent),
409 419
 			dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent),
@@ -487,7 +497,6 @@ dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated],
487 497
 
488 498
 	templateString: '<div class="dijitGutter" role="presentation"></div>',
489 499
 
490  
-	// TODO: unneeded?   why set this.horizontal?
491 500
 	postMixInProperties: function(){
492 501
 		this.inherited(arguments);
493 502
 		this.horizontal = /top|bottom/.test(this.region);
57  tests/layout/robot/BorderContainer_nested.html
@@ -22,33 +22,36 @@
22 22
 			dojo.addOnLoad(function(){
23 23
 				doh.robot.initRobot('../test_BorderContainer_nested.html');
24 24
 
25  
-				doh.register("API", [
26  
-					function initialConditions(){
27  
-						checkBCpanes(dijit.byId("bc1"));
28  
-						doh.t(isVisible(dijit.byId("bc1")));
29  
-						checkInside(dijit.byId("bc1"), dijit.byId("tc"));
30  
-					}
31  
-				]);
32  
-				
33  
-				doh.register("testTab2", [
34  
-					{
35  
-						name: "tab2",
36  
-						timeout: 10000,
37  
-						runTest: function(t){
38  
-							var d = new doh.Deferred();
39  
-									
40  
-							doh.robot.mouseMoveAt("tc_tablist_bc2", 500);		
41  
-							doh.robot.mouseClick({left:true}, 500);							
42  
-							
43  
-							doh.robot.sequence(d.getTestCallback(function(){
44  
-								checkBCpanes(dijit.byId("bc2"));
45  
-								doh.t(isVisible(dijit.byId("bc2")));
46  
-								checkInside(dijit.byId("bc2"), dijit.byId("tc"));
47  
-							}), 1000);
48  
-							
49  
-							return d;
50  
-						}
51  
-					}
  25
+				doh.register("initial layout", [
  26
+					function nestedBC(){
  27
+						checkBCpanes(dijit.byId("nbc"));
  28
+						doh.t(isVisible(dijit.byId("nbc")));
  29
+						checkInside("nbc", "tc");
  30
+					},
  31
+					function layoutPriorityBC(){
  32
+						dijit.byId("tc").selectChild(dijit.byId("pbc"));	
  33
+						doh.t(isVisible(dijit.byId("pbc")), "second pane visible");
  34
+
  35
+						// Check layout of BorderContainer panes relative to each other
  36
+						checkAbove("top bar above second top bar", "top1", "top2");
  37
+						checkAbove("second top bar above inner top bar", "top2", "top3");
  38
+						checkLeft("outer left vs. inner left", "left1", "left2");
  39
+						checkLeft("inner left vs. inner top", "left2", "top3");
  40
+						checkLeft("inner left vs. inner bottom", "left2", "bottom3");
  41
+						checkAbove("inner top vs. center", "top3", "center");
  42
+						checkAbove("center vs. inner bottom", "center", "bottom3");
  43
+						checkLeft("inner right vs. inner top", "top3", "right2");
  44
+						checkLeft("inner right vs. center", "center", "right2");
  45
+						checkAbove("inner bottom bar above second bottom bar", "bottom3", "bottom2");
  46
+						checkAbove("second bottom bar above bottom bar", "bottom2", "bottom1");
  47
+
  48
+						// Check that all panes within BC borders
  49
+						var children = dijit.byId("pbc").getChildren();
  50
+						doh.is(11, children.length, "# of children");
  51
+						dojo.forEach(children, function(child){
  52
+							checkInside(child, dijit.byId("pbc"));
  53
+						});
  54
+					}							
52 55
 				]);
53 56
 				
54 57
 				doh.run();
17  tests/layout/robot/borderContainerTestFunctions.js
... ...
@@ -1,19 +1,26 @@
1  
-			function checkInside(/*Widget*/ child, /*Widget*/ parent){
  1
+			function checkInside(/*Widget*/ child, /*Widget*/ parent, /*String?*/ comment){
2 2
 				// summary:
3 3
 				//		Test that child is fully inside of parent
  4
+
  5
+				child = dijit.byId(child);
  6
+				parent = dijit.byId(parent);
  7
+
4 8
 				var cp = dojo.position(child.domNode, true),
5 9
 					pp = dojo.position(parent.domNode, true);
6 10
 
7 11
 				doh.t(
8 12
 					cp.y >= pp.y && cp.y+cp.h <= pp.y+pp.h &&
9 13
 					cp.x >= pp.x && cp.x+cp.w <= pp.x+pp.w,
10  
-					child.region + " inside " + parent.id + dojo.toJson(cp) + dojo.toJson(pp)
  14
+					(comment ? comment + ": " : "") + child.region + " inside " + parent.id + dojo.toJson(cp) + dojo.toJson(pp)
11 15
 				);
12 16
 			}
13 17
 			function checkAbove(/*String*/ comment, /*Widget*/ above, /*Widget*/ below){
14 18
 				// summary:
15 19
 				//		Test that child is fully above parent
16 20
 
  21
+				above = dijit.byId(above);
  22
+				below = dijit.byId(below);
  23
+
17 24
 				var ap = dojo.position(above.domNode, true),
18 25
 					bp = dojo.position(below.domNode, true);
19 26
 
@@ -25,6 +32,9 @@
25 32
 				// summary:
26 33
 				//		Test that child is fully left of parent
27 34
 
  35
+				left = dijit.byId(left);
  36
+				right = dijit.byId(right);
  37
+
28 38
 				var lp = dojo.position(left.domNode, true),
29 39
 					rp = dojo.position(right.domNode, true);
30 40
 
@@ -36,7 +46,8 @@
36 46
 			function checkBCpanes(/*BorderContainer*/ bc){
37 47
 				// summary:
38 48
 				//		Check that all the panes in this BorderContainer are in sane
39  
-				//		positions relative to each other
  49
+				//		positions relative to each other.   Assumes at most one pane
  50
+				//		in each region.
40 51
 				var children = bc.getChildren(),
41 52
 					regions = {};
42 53
 
94  tests/layout/test_BorderContainer_nested.html
@@ -30,11 +30,17 @@
30 30
 <body class="claro">
31 31
 
32 32
 	<h2 class="testTitle">dijit.layout.BorderContainer tests</h2>
33  
-	<p>Basic layout</p>
  33
+
  34
+	<p>
  35
+		The second tab holds a single BorderContainer but specifying layoutPriority on it's children to have multiple children
  36
+		for each region.
  37
+	</p>
  38
+	<p>
  39
+		The first tab holds a BorderContainer which nests another BorderContainer, simulating multiple children in a single region.
  40
+	</p>
34 41
 
35 42
 	<div id="tc" data-dojo-type="dijit.layout.TabContainer" data-dojo-props='style:"width:800px;height:600px;"'>
36  
-		<div id="bc1" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props='title:"Tab 1",
37  
-			style:"border: 2px solid black; width: 90%; height: 500px; padding: 10px;"'>
  43
+		<div id="nbc" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props='title:"Nested BC"'>
38 44
 			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"left", style:"background-color: #acb386; width: 100px;"'>
39 45
 				left
40 46
 			</div>
@@ -48,19 +54,18 @@ <h2 class="testTitle">dijit.layout.BorderContainer tests</h2>
48 54
 				bottom bar
49 55
 			</div>
50 56
 
51  
-			<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props='region:"center", design:"sidebar",
52  
-				style:"border: 2px solid black; padding: 0px;"'>
  57
+			<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props='region:"center", design:"sidebar"'>
53 58
 				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"left", style:"background-color: #acb386; width: 100px;"'>
54  
-					left
  59
+					left inner
55 60
 				</div>
56 61
 				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"right", style:"background-color: #acb386; width: 100px;"'>
57  
-					right
  62
+					right inner
58 63
 				</div>
59 64
 				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"top", style:"background-color: #b39b86; height: 100px;"'>
60  
-					top bar
  65
+					inner top bar
61 66
 				</div>
62 67
 				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"bottom", style:"background-color: #b39b86; height: 100px;"'>
63  
-					bottom bar
  68
+					inner bottom bar
64 69
 				</div>
65 70
 				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"center", style:"background-color: #f5ffbf; padding: 10px;"'>
66 71
 					main panel with <a href="http://www.dojotoolkit.org/">a link</a>.<br />
@@ -74,44 +79,47 @@ <h2 class="testTitle">dijit.layout.BorderContainer tests</h2>
74 79
 				</div>
75 80
 			</div>
76 81
 		</div>
77  
-		<div id="bc2" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props='title:"Tab 2"'>
78  
-			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"left", splitter:true, style:"background-color: #770; width: 100px;"'>
79  
-				left
  82
+
  83
+		<div id="pbc" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props='title:"layoutPriority BC"'>
  84
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"left1", region:"left", splitter:true, layoutPriority: 3, style:"background-color: #770; width: 100px;"'>
  85
+				left (layoutPriority == 3)
80 86
 			</div>
81  
-			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"right", splitter:true, style:"background-color: #077; width: 100px;"'>
82  
-				right
  87
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"right1", region:"right", splitter:true, layoutPriority: 3, style:"background-color: #770; width: 100px;"'>
  88
+				right (layoutPriority == 3)
83 89
 			</div>
84  
-			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"top", splitter:true, style:"background-color: #700; height: 100px;"'>
85  
-				top bar
  90
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"top1", region:"top", splitter:true, layoutPriority: 1, style:"background-color: #077; color: white; height: 50px;"'>
  91
+				top bar (layoutPriority == 1)
86 92
 			</div>
87  
-			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"bottom", splitter:true, style:"background-color: #007; height: 100px;"'>
88  
-				bottom bar
  93
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id: "bottom1", region:"bottom", splitter:true, layoutPriority: 1, style:"background-color: #077; color: white; height: 50px;"'>
  94
+				bottom bar (layoutPriority == 1)
89 95
 			</div>
90  
-
91  
-			<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props='region:"center", design:"sidebar",
92  
-				style:"border: 2px solid black; padding: 0px;"'>
93  
-				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"left", style:"background-color: #acb386; width: 100px;"'>
94  
-					left
95  
-				</div>
96  
-				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"right", style:"background-color: #acb386; width: 100px;"'>
97  
-					right
98  
-				</div>
99  
-				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"top", style:"background-color: #b39b86; height: 100px;"'>
100  
-					top bar
101  
-				</div>
102  
-				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"bottom", style:"background-color: #b39b86; height: 100px;"'>
103  
-					bottom bar
104  
-				</div>
105  
-				<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='region:"center", style:"background-color: #f5ffbf; padding: 10px;"'>
106  
-					main panel with <a href="http://www.dojotoolkit.org/">a link</a>.<br />
107  
-					(to check we're copying children around properly).<br />
108  
-					<select data-dojo-type="dijit.form.FilteringSelect">
109  
-						<option value="1">foo</option>
110  
-						<option value="2">bar</option>
111  
-						<option value="3">baz</option>
112  
-					</select>
113  
-					Here's some text that comes AFTER the combo box.
114  
-				</div>
  96
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"top2", region:"top", splitter:true, layoutPriority: 2, style:"background-color: #f5ffbf; height: 50px;"'>
  97
+				second top bar (layoutPriority == 2)
  98
+			</div>
  99
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"bottom2", region:"bottom", splitter:true, layoutPriority: 2, style:"background-color: #f5ffbf; height: 50px;"'>
  100
+				second bottom bar (layoutPriority == 2)
  101
+			</div>
  102
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"left2", region:"left", splitter:true, layoutPriority: 4, style:"background-color: #acb386; width: 100px;"'>
  103
+				inner left (layoutPriority == 4)
  104
+			</div>
  105
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"right2", region:"right", splitter:true, layoutPriority: 4, style:"background-color: #acb386; width: 100px;"'>
  106
+				inner right (layoutPriority == 4)
  107
+			</div>
  108
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"top3", region:"top", splitter:true, layoutPriority: 5, style:"background-color: #b39b86; height: 50px;"'>
  109
+				inner top bar (layoutPriority == 5)
  110
+			</div>
  111
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"bottom3", region:"bottom", splitter:true, layoutPriority: 5, style:"background-color: #b39b86; height: 50px;"'>
  112
+				inner bottom bar (layoutPriority == 5)
  113
+			</div>
  114
+			<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props='id:"center", region:"center", style:"background-color: #f5ffbf; padding: 10px;"'>
  115
+				main panel with <a href="http://www.dojotoolkit.org/">a link</a>.<br />
  116
+				(to check we're copying children around properly).<br />
  117
+				<select data-dojo-type="dijit.form.FilteringSelect">
  118
+					<option value="1">foo</option>
  119
+					<option value="2">bar</option>
  120
+					<option value="3">baz</option>
  121
+				</select>
  122
+				Here's some text that comes AFTER the combo box.
115 123
 			</div>
116 124
 		</div>
117 125
 	</div>

0 notes on commit efe42d1

Please sign in to comment.
Something went wrong with that request. Please try again.