1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2010 Sprout Systems, Inc. and contributors.
  4 //            portions copyright ©2011 Apple Inc.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 /*
  9   Tests SplitView logic responsible for automatically creating divider views.
 10   There are a few different parts to this:
 11 
 12   - The automatic creation of dividers.
 13   - The splitDividerView property.
 14   - The splitViewDividerBetween method.
 15 
 16   We don't have to worry about orientation; the code being tested creates
 17   child views, but does nothing related to laying them out.
 18 
 19   Note: We do NOT test the properties added to the split children (nextView, etc.);
 20   Those are tested in children.js.
 21 
 22 */
 23 var createSplitView;
 24 
 25 module("SplitView Dividers", {
 26   setup: function() {
 27     // Rather than instantiate one here, we'll create a function that
 28     // instantiates with the supplied options.
 29     var SplitView = SC.SplitView.extend({
 30       childViews: [
 31         'left',
 32         'right'
 33       ],
 34 
 35       left:  SC.View.extend(SC.SplitChild, { name: 'left', canCollapse: YES, collapseAtSize: 50 }),
 36       right: SC.View.extend(SC.SplitChild, { name: 'right', canCollapse: YES, collapseAtSize: 50 }),
 37 
 38       layout: { left: 0, top: 0, width: 500, height: 500 }
 39     });
 40 
 41     createSplitView = function(opts) {
 42       opts = opts || {};
 43       SC.RunLoop.begin();
 44       var ret = SplitView.create(opts);
 45       SC.RunLoop.end();
 46       return ret;
 47     };
 48   },
 49 
 50   teardown: function() {
 51 
 52   }
 53 });
 54 
 55 test("SC.SplitDividerView is automatically created between child views", function(){
 56   var view = createSplitView();
 57   equals(view.childViews.length, 3, "Should have created 3 views: left, divider, and right.");
 58   ok(view.childViews[1].kindOf(SC.SplitDividerView), "Middle view is an SC.SplitDividerView");
 59 });
 60 
 61 test("SC.SplitDividerView uses splitDividerView property", function(){
 62   var MyDividerType = SC.SplitDividerView.extend();
 63   var view = createSplitView({ splitDividerView: MyDividerType });
 64   equals(view.childViews.length, 3, "Should have created 3 views: left, divider, and right.");
 65   ok(view.childViews[1].kindOf(MyDividerType), "Middle view is a MyDividerType");
 66 });
 67 
 68 test("SC.SplitDividerView uses splitViewDividerBetween method", function(){
 69   var MyDividerType = SC.SplitDividerView.extend();
 70   var view = createSplitView({ splitViewDividerBetween: function(split, view1, view2) { return MyDividerType.create(); } });
 71   equals(view.childViews.length, 3, "Should have created 3 views: left, divider, and right.");
 72   ok(view.childViews[1].kindOf(MyDividerType), "Middle view is a MyDividerType");
 73 });
 74 
 75 test("splitViewDividerBetween works properly", function(){
 76   var MyDividerType1 = SC.SplitDividerView.extend({ dividerType: 1 });
 77   var MyDividerType2 = SC.SplitDividerView.extend({ dividerType: 2 });
 78 
 79   var view = createSplitView({
 80     childViews: 'left middle right'.w(),
 81     middle: SC.View.design(SC.SplitChild, { name: 'middle' }),
 82     splitViewDividerBetween: function(split, view1, view2) {
 83       if (view1 === split.left) return MyDividerType1.create();
 84       if (view1 === split.middle) return MyDividerType2.create();
 85     }
 86   });
 87 
 88   equals(view.childViews.length, 5, "Should have created 5 views: left, divider, middle, divider, and right.");
 89   ok(view.childViews[1].kindOf(MyDividerType1), "2nd view is a MyDividerType1");
 90   ok(view.childViews[3].kindOf(MyDividerType2), "4th view is a MyDividerType2");
 91 });
 92 
 93 function checkDividers(view, number) {
 94   var shouldBeDivider = NO;
 95 
 96   equals(view.childViews.length, number * 2 - 1, "There should be " + (number * 2 - 1) + " children");
 97 
 98   for (var i = 1; i < number; i++) {
 99     equals(
100       view.childViews[i - 1].isSplitDivider, shouldBeDivider,
101       "View " + i + (shouldBeDivider ? " SHOULD " : " SHOULD NOT ") + "be a divider"
102     );
103     shouldBeDivider = !shouldBeDivider;
104   }
105 }
106 
107 test("Adding/removing from end adds/removes dividers appropriately", function() {
108   var view = createSplitView({
109     childViews: 'left middle right'.w(),
110     middle: SC.View.design(SC.SplitChild, { name: 'middle' })
111   });
112 
113   // do an initial check: should be three views with dividers.
114   checkDividers(view, 3);
115 
116   // add one, and check again.
117   var add = SC.View.create(SC.SplitChild, { name: 'add' });
118 
119   SC.RunLoop.begin();
120   view.appendChild(add);
121   SC.RunLoop.end();
122 
123   checkDividers(view, 4);
124 
125   // remove the one we added, and check again
126   SC.RunLoop.begin();
127   view.removeChild(add);
128   SC.RunLoop.end();
129 
130   checkDividers(view, 3);
131 
132 });
133 
134 test("Adding/removing from beginning adds/removes dividers appropriately", function() {
135   var view = createSplitView({
136     childViews: 'left middle right'.w(),
137     middle: SC.View.design(SC.SplitChild, { name: 'middle' })
138   });
139 
140   // do an initial check: should be three views with dividers.
141   checkDividers(view, 3);
142 
143   // add one, and check again.
144   var add = SC.View.create(SC.SplitChild, { name: 'add' });
145 
146   SC.RunLoop.begin();
147   view.insertBefore(add, view.childViews[0]);
148   SC.RunLoop.end();
149 
150   checkDividers(view, 4);
151 
152   // remove the one we added, and check again
153   SC.RunLoop.begin();
154   view.removeChild(add);
155   SC.RunLoop.end();
156 
157   checkDividers(view, 3);
158 
159 });
160 
161 test("Adding/removing in middle adds/removes dividers appropriately", function() {
162   var view = createSplitView({
163     childViews: 'left middle right'.w(),
164     middle: SC.View.design(SC.SplitChild, { name: 'middle' })
165   });
166 
167   // do an initial check: should be three views with dividers.
168   checkDividers(view, 3);
169 
170   // add one, and check again.
171   var add = SC.View.create(SC.SplitChild, { name: 'add' });
172 
173   SC.RunLoop.begin();
174   view.insertBefore(add, view.childViews[2]); // note: 2 is the middle view
175   SC.RunLoop.end();
176 
177   checkDividers(view, 4);
178 
179   // remove the one we added, and check again
180   SC.RunLoop.begin();
181   view.removeChild(add);
182   SC.RunLoop.end();
183 
184   checkDividers(view, 3);
185 
186 });
187 
188 test("Adding and removing before a divider doesn't screw things majorly", function() {
189 
190   var view = createSplitView({
191     childViews: 'left middle right'.w(),
192     middle: SC.View.design(SC.SplitChild, { name: 'middle' })
193   });
194 
195   // do an initial check: should be three views with dividers.
196   checkDividers(view, 3);
197 
198   // add one, and check again.
199   var add = SC.View.create(SC.SplitChild, { name: 'add' });
200 
201   SC.RunLoop.begin();
202   view.insertBefore(add, view.childViews[1]);
203   SC.RunLoop.end();
204 
205   checkDividers(view, 4);
206 
207   // remove the one we added, and check again
208   SC.RunLoop.begin();
209   view.removeChild(add);
210   SC.RunLoop.end();
211 
212   checkDividers(view, 3);
213 
214 });
215 
216 test("Adding and removing several views doesn't screw things up", function() {
217   var view = createSplitView({
218     childViews: 'left middle right'.w(),
219     middle: SC.View.design(SC.SplitChild, { name: 'middle' })
220   });
221 
222   // do an initial check: should be three views with dividers.
223   checkDividers(view, 3);
224 
225   // add one, and check again.
226   var add1 = SC.View.create(SC.SplitChild, { name: 'add' });
227   var add2 = SC.View.create(SC.SplitChild, { name: 'add' });
228   var add3 = SC.View.create(SC.SplitChild, { name: 'add' });
229   var add4 = SC.View.create(SC.SplitChild, { name: 'add' });
230 
231   SC.RunLoop.begin();
232   view.removeChild(view.childViews[2]);
233   view.removeChild(view.childViews[3]);
234 
235   // semi-random (I just picked 4 numbers):
236   view.insertBefore(add1, view.childViews[0]);
237   view.insertBefore(add2, view.childViews[0]);
238   view.insertBefore(add3, view.childViews[4]);
239   view.insertBefore(add4, view.childViews[3]);
240   SC.RunLoop.end();
241 
242   checkDividers(view, 5);
243 });
244 
245 test("SplitView#layoutDirection is correctly propagated to its dividers.", function() {
246   var view = createSplitView(),
247       layoutDirection = view.get('layoutDirection'),
248       nextLayoutDirection = layoutDirection === SC.LAYOUT_VERTICAL ? SC.LAYOUT_HORIZONTAL : SC.LAYOUT_VERTICAL; // hey just in case the default changes
249 
250   var divider = view.childViews[1];
251   ok(divider.isSplitDivider, "PRELIM: We found the divider.");
252 
253   equals(divider.get('layoutDirection'), layoutDirection, "The divider's layoutDirection should match that of the SplitView.");
254 
255   SC.RunLoop.begin();
256   view.set('layoutDirection', nextLayoutDirection);
257   SC.RunLoop.end();
258 
259   equals(divider.get('layoutDirection'), nextLayoutDirection, "The divider's layoutDirection should update when the SplitView's does.");
260 
261   view.destroy();
262 });
263