sproutcore 1.11.0.rc3 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +6 -14
  2. data/CHANGELOG +5 -0
  3. data/VERSION.yml +1 -1
  4. data/lib/frameworks/sproutcore/Buildfile +3 -2
  5. data/lib/frameworks/sproutcore/CHANGELOG.md +59 -10
  6. data/lib/frameworks/sproutcore/apps/showcase/resources/main_page.js +1 -0
  7. data/lib/frameworks/sproutcore/apps/showcase/resources/stylesheet.css +9 -4
  8. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/manipulation.js +1 -1
  9. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +0 -10
  10. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +1 -1
  11. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +10 -45
  12. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/selection_set.js +3 -3
  13. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/touch.js +76 -0
  14. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/{touch.js → touch_test.js} +64 -0
  15. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/append_remove.js +1 -1
  16. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/design_mode_test.js +61 -24
  17. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/createChildViews.js +1 -2
  18. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/destroy.js +0 -3
  19. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/{layoutStyle.js → layout_style_test.js} +4 -4
  20. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layout_test.js +602 -0
  21. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/viewDidResize.js +0 -23
  22. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +18 -17
  23. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +5 -5
  24. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/design_mode.js +64 -24
  25. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +904 -871
  26. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +1 -3
  27. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/statechart.js +40 -24
  28. data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures.js +2 -2
  29. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +5 -5
  30. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +14 -14
  31. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +1 -1
  32. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +2 -2
  33. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +36 -33
  34. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/writeAttribute.js +1 -1
  35. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/autonomous_dataSourceCallbacks.js +6 -6
  36. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitChangesFromNestedStore.js +1 -1
  37. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitRecord.js +1 -1
  38. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataSourceCallbacks.js +7 -7
  39. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/destroyRecord.js +2 -2
  40. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/recordDidChange.js +2 -2
  41. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/retrieveRecord.js +4 -4
  42. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +11 -11
  43. data/lib/frameworks/sproutcore/frameworks/designer/coders/object.js +1 -1
  44. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +30 -1
  45. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +12 -1
  46. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +5 -3
  47. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroller_view.js +0 -36
  48. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll_view.js +3 -3
  49. data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +1 -1
  50. data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +1 -1
  51. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/pinch_gesture.js +286 -0
  52. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/swipe_gesture.js +449 -0
  53. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/tap_gesture.js +259 -0
  54. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/gesturable.js +218 -30
  55. data/lib/frameworks/sproutcore/frameworks/foundation/system/gesture.js +259 -158
  56. data/lib/frameworks/sproutcore/frameworks/foundation/system/string.js +58 -50
  57. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_measurement.js +1 -1
  58. data/lib/frameworks/sproutcore/frameworks/foundation/tests/gestures/pinch_gesture_test.js +321 -0
  59. data/lib/frameworks/sproutcore/frameworks/foundation/tests/gestures/swipe_gesture_test.js +154 -0
  60. data/lib/frameworks/sproutcore/frameworks/foundation/tests/gestures/tap_gesture_test.js +55 -0
  61. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/gesturable_test.js +233 -0
  62. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/staticLayout.js +2 -2
  63. data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/gesture_test.js +254 -0
  64. data/lib/frameworks/sproutcore/frameworks/foundation/views/container.js +1 -0
  65. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +1 -1
  66. data/lib/frameworks/sproutcore/frameworks/legacy/object_keys_polyfill.js +51 -0
  67. data/lib/frameworks/sproutcore/frameworks/{core_foundation/system/req_anim_frame.js → legacy/request_animation_frame_polyfill.js} +10 -3
  68. data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +19 -25
  69. data/lib/frameworks/sproutcore/frameworks/media/views/controls.js +7 -7
  70. data/lib/frameworks/sproutcore/frameworks/media/views/mini_controls.js +3 -3
  71. data/lib/frameworks/sproutcore/frameworks/media/views/simple_controls.js +9 -9
  72. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
  73. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/insertAt.js +2 -2
  74. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/removeAt.js +1 -1
  75. data/lib/frameworks/sproutcore/frameworks/runtime/ext/array.js +1 -1
  76. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +2 -2
  77. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/freezable.js +2 -2
  78. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +66 -5
  79. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/tree.js +44 -0
  80. data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_queue.js +4 -1
  81. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +0 -25
  82. data/lib/frameworks/sproutcore/frameworks/runtime/system/enumerator.js +1 -1
  83. data/lib/frameworks/sproutcore/frameworks/runtime/system/error.js +67 -15
  84. data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +6 -11
  85. data/lib/frameworks/sproutcore/frameworks/runtime/system/set.js +6 -6
  86. data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +1 -1
  87. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/{observable.js → observable_test.js} +110 -16
  88. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/error.js +21 -0
  89. data/lib/frameworks/sproutcore/frameworks/statechart/system/statechart.js +2 -2
  90. data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars.js +1 -1
  91. data/lib/frameworks/sproutcore/frameworks/testing/system/plan.js +1 -1
  92. data/lib/sproutcore/render_engines/haml.rb +1 -1
  93. metadata +610 -604
  94. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layout.js +0 -210
  95. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutDidChange.js +0 -275
  96. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/pinch.js +0 -119
  97. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/swipe.js +0 -234
  98. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/tap.js +0 -157
@@ -142,3 +142,67 @@ test("Touch event handling and juggling.", function() {
142
142
  equals(outerEnd, 1, "outerView.touchEnd should have been called:");
143
143
 
144
144
  });
145
+
146
+ module("SC.Touch", {
147
+ });
148
+
149
+ /* Class Methods */
150
+
151
+ // This method creates a new SC.Touch.
152
+ test("Class Method: create", function () {
153
+ equals(SC.Touch.create({ identifier: 'test-touch' }).constructor, SC.Touch.prototype.constructor, "The method returns instance of type");
154
+ });
155
+
156
+ // This method returns the average of all the given touches.
157
+ test("Class Method: averagedTouch", function () {
158
+ var touch1 = SC.Touch.create({ identifier: 'touch-1', pageX: 0, pageY: 0, velocityX: 0, velocityY: 0 }),
159
+ touch2 = SC.Touch.create({ identifier: 'touch-2', pageX: 100, pageY: 100, velocityX: 0, velocityY: 0 }),
160
+ touch3 = SC.Touch.create({ identifier: 'touch-3', pageX: 200, pageY: 200, velocityX: 0, velocityY: 0 }),
161
+ avgTouch;
162
+
163
+ // Test two touches.
164
+ avgTouch = SC.Touch.averagedTouch([touch1, touch2]);
165
+ equals(avgTouch.x.toFixed(1), '50.0', "The value of x is");
166
+ equals(avgTouch.y.toFixed(1), '50.0', "The value of y is");
167
+ equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is");
168
+ equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is");
169
+ equals(avgTouch.d.toFixed(1), '70.7', "The value of d is");
170
+
171
+ // Test two touches in reverse.
172
+ avgTouch = SC.Touch.averagedTouch([touch2, touch1]);
173
+ equals(avgTouch.x.toFixed(1), '50.0', "The value of x is");
174
+ equals(avgTouch.y.toFixed(1), '50.0', "The value of y is");
175
+ equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is");
176
+ equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is");
177
+ equals(avgTouch.d.toFixed(1), '70.7', "The value of d is");
178
+
179
+ // Test three touches.
180
+ avgTouch = SC.Touch.averagedTouch([touch1, touch2, touch3]);
181
+ equals(avgTouch.x.toFixed(1), '100.0', "The value of x is");
182
+ equals(avgTouch.y.toFixed(1), '100.0', "The value of y is");
183
+ equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is");
184
+ equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is");
185
+ equals(avgTouch.d.toFixed(1), '94.3', "The value of d is");
186
+
187
+ // Test three touches in different order.
188
+ avgTouch = SC.Touch.averagedTouch([touch2, touch3, touch1]);
189
+ equals(avgTouch.x.toFixed(1), '100.0', "The value of x is");
190
+ equals(avgTouch.y.toFixed(1), '100.0', "The value of y is");
191
+ equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is");
192
+ equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is");
193
+ equals(avgTouch.d.toFixed(1), '94.3', "The value of d is");
194
+ });
195
+
196
+ /* Properties */
197
+
198
+ test("Default Properties:", function () {
199
+ var touch = SC.Touch.create({ identifier: 'test-touch' });
200
+
201
+ equals(touch.identifier, 'test-touch', "The default value of identifier is");
202
+ });
203
+
204
+ /* Methods */
205
+
206
+ // This method registers _sc_pinchAnchorScale to the value of the view's scale.
207
+ test("Method: touchSessionStarted", function () {
208
+ });
@@ -192,7 +192,7 @@ test("removeFromParent throws an exception", function() {
192
192
  pane.append();
193
193
  pane.removeFromParent();
194
194
  } catch(e) {
195
- exceptionCaught = (e instanceof SC.Error);
195
+ exceptionCaught = true;
196
196
  } finally {
197
197
  pane.remove();
198
198
  }
@@ -8,6 +8,7 @@
8
8
 
9
9
  var pane, view1, view2, view3, view4, view5;
10
10
 
11
+ SC.LOG_DESIGN_MODE = true;
11
12
 
12
13
  // Localized layout.
13
14
  SC.metricsFor('English', {
@@ -203,20 +204,20 @@ test("When updateDesignMode() is called on a pane, it sets designMode properly o
203
204
  view4.set.expect(1);
204
205
 
205
206
  var modeName = orientation === SC.PORTRAIT_ORIENTATION ? 'l_p' : 'l_l';
206
- equals(view1.get('designMode'), modeName, "view1 designMode should be");
207
- equals(view2.get('designMode'), modeName, "view2 designMode should be");
208
- equals(view3.get('designMode'), modeName, "view3 designMode should be");
209
- equals(view4.get('designMode'), modeName, "view4 designMode should be");
207
+ equals(view1.get('designMode'), modeName, "Test 1 view1 designMode should be");
208
+ equals(view2.get('designMode'), modeName, "Test 1 view2 designMode should be");
209
+ equals(view3.get('designMode'), modeName, "Test 1 view3 designMode should be");
210
+ equals(view4.get('designMode'), modeName, "Test 1 view4 designMode should be");
210
211
 
211
- same(view1.get('layout'), largeLayout, "layout of view1 should be");
212
- same(view2.get('layout'), largeLayout, "layout of view2 should be");
213
- same(view3.get('layout'), normalLayout, "layout of view3 should be");
214
- same(view4.get('layout'), largeLayout, "layout of view4 should be");
212
+ same(view1.get('layout'), largeLayout, "Test 1 layout of view1 should be");
213
+ same(view2.get('layout'), largeLayout, "Test 1 layout of view2 should be");
214
+ same(view3.get('layout'), normalLayout, "Test 1 layout of view3 should be");
215
+ same(view4.get('layout'), largeLayout, "Test 1 layout of view4 should be");
215
216
 
216
- same(view1.get('classNames'), ['sc-view', 'sc-large'], "classNames of view1 should be");
217
- same(view2.get('classNames'), ['sc-view', 'sc-large'], "classNames of view2 should be");
218
- same(view3.get('classNames'), ['sc-view', 'sc-large'], "classNames of view3 should be");
219
- same(view4.get('classNames'), ['sc-view', 'sc-large'], "classNames of view4 should be");
217
+ same(view1.get('classNames'), ['sc-view', 'sc-large'], "Test 1 classNames of view1 should be");
218
+ same(view2.get('classNames'), ['sc-view', 'sc-large'], "Test 1 classNames of view2 should be");
219
+ same(view3.get('classNames'), ['sc-view', 'sc-large'], "Test 1 classNames of view3 should be");
220
+ same(view4.get('classNames'), ['sc-view', 'sc-large'], "Test 1 classNames of view4 should be");
220
221
 
221
222
  var newModeName = orientation === SC.PORTRAIT_ORIENTATION ? 's_p' : 's_l';
222
223
 
@@ -230,20 +231,20 @@ test("When updateDesignMode() is called on a pane, it sets designMode properly o
230
231
  view3.set.expect(2);
231
232
  view4.set.expect(2);
232
233
 
233
- equals(view1.get('designMode'), newModeName, "view1 designMode should be");
234
- equals(view2.get('designMode'), newModeName, "view2 designMode should be");
235
- equals(view3.get('designMode'), newModeName, "view3 designMode should be");
236
- equals(view4.get('designMode'), newModeName, "view4 designMode should be");
234
+ equals(view1.get('designMode'), newModeName, "Test 2 view1 designMode should be");
235
+ equals(view2.get('designMode'), newModeName, "Test 2 view2 designMode should be");
236
+ equals(view3.get('designMode'), newModeName, "Test 2 view3 designMode should be");
237
+ equals(view4.get('designMode'), newModeName, "Test 2 view4 designMode should be");
237
238
 
238
- same(view1.get('layout'), smallLayout, "layout of view1 should be");
239
- same(view2.get('layout'), smallLayout, "layout of view2 should be");
240
- same(view3.get('layout'), smallLayout, "layout of view3 should be");
241
- same(view4.get('layout'), smallLayout, "layout of view4 should be");
239
+ same(view1.get('layout'), smallLayout, "Test 2 layout of view1 should be");
240
+ same(view2.get('layout'), smallLayout, "Test 2 layout of view2 should be");
241
+ same(view3.get('layout'), smallLayout, "Test 2 layout of view3 should be");
242
+ same(view4.get('layout'), smallLayout, "Test 2 layout of view4 should be");
242
243
 
243
- same(view1.get('classNames'), ['sc-view', 'sc-small'], "classNames of view1 should be");
244
- same(view2.get('classNames'), ['sc-view', 'sc-small'], "classNames of view2 should be");
245
- same(view3.get('classNames'), ['sc-view', 'sc-small'], "classNames of view3 should be");
246
- same(view4.get('classNames'), ['sc-view', 'sc-small'], "classNames of view4 should be");
244
+ same(view1.get('classNames'), ['sc-view', 'sc-small'], "Test 2 classNames of view1 should be");
245
+ same(view2.get('classNames'), ['sc-view', 'sc-small'], "Test 2 classNames of view2 should be");
246
+ same(view3.get('classNames'), ['sc-view', 'sc-small'], "Test 2 classNames of view3 should be");
247
+ same(view4.get('classNames'), ['sc-view', 'sc-small'], "Test 2 classNames of view4 should be");
247
248
  });
248
249
 
249
250
  test("When RootResponder has designModes, and you add a view to a pane, it sets designMode on the new view.", function () {
@@ -397,6 +398,42 @@ test("When you change designModes on RootResponder, it sets designMode on the pa
397
398
  same(view4.get('classNames'), ['sc-view', 'sc-medium'], "classNames for view4 should be");
398
399
  });
399
400
 
401
+ test("When the design mode changes, overrides are reverted.");
402
+ // This is extremely complex to achieve. Left as a warning for now.
403
+ // , function () {
404
+ // var windowSize,
405
+ // responder = SC.RootResponder.responder,
406
+ // orientation = SC.device.orientation;
407
+
408
+ // windowSize = responder.get('currentWindowSize');
409
+ // responder.set('designModes', { s: ((windowSize.width - 10) * (windowSize.height - 10)) / window.devicePixelRatio, l: Infinity });
410
+
411
+ // SC.run(function () {
412
+ // pane = pane.create().append();
413
+ // });
414
+
415
+ // same(view1.get('layout'), largeLayout, "Test 1 layout of view1 should be");
416
+ // same(view2.get('layout'), largeLayout, "Test 1 layout of view2 should be");
417
+
418
+ // SC.run(function () {
419
+ // view1.adjust('top', 10); // Original layout goes from implied top: 0 to top: 10.
420
+ // view2.adjust('height', 100); // Original layout goes from implied bottom: 0 to bottom: undefined.
421
+ // });
422
+
423
+ // var modeName = orientation === SC.PORTRAIT_ORIENTATION ? 'l_p' : 'l_l';
424
+ // var newModeName = orientation === SC.PORTRAIT_ORIENTATION ? 's_p' : 's_l';
425
+
426
+ // SC.run(function () {
427
+ // pane.updateDesignMode(modeName, newModeName);
428
+ // });
429
+
430
+ // var adjustedSmallLayout1 = { top: 10, bottom: 0, left: 10, right: 10 },
431
+ // adjustedSmallLayout2 = { top: 0, height: 100, left: 10, right: 10 };
432
+
433
+ // same(view1.get('layout'), adjustedSmallLayout1, "Test 2 layout for view1 should be");
434
+ // same(view2.get('layout'), adjustedSmallLayout2, "Test 2 layout for view2 should be");
435
+ // });
436
+
400
437
  test("When you unset designModes on RootResponder, it clears designMode on its panes and their childViews.", function () {
401
438
  var windowSize,
402
439
  responder = SC.RootResponder.responder,
@@ -109,9 +109,8 @@ test("should create view from class with any passed attributes", function() {
109
109
  equals(v.foo, 'baz', 'view did get custom attributes');
110
110
  });
111
111
 
112
- test("should set newView.owner & parentView to receiver", function() {
112
+ test("should set newView.parentView to receiver", function() {
113
113
  var v = view.createChildView(myViewClass) ;
114
- equals(v.get('owner'), view, 'v.owner == view');
115
114
  equals(v.get('parentView'), view, 'v.parentView == view');
116
115
  });
117
116
 
@@ -26,9 +26,7 @@ test('childViews specified as classes are also destroyed.', function() {
26
26
 
27
27
  SC.run(function() {
28
28
  ok(!v2.get('parentView'), 'destroying a parent removes the parentView reference from the child.');
29
- ok(v2.get('owner') === null, 'destroying a parent removes the owner reference from the child.');
30
29
  ok(!v3.get('parentView'), 'destroying a parent removes the parentView reference from the grandchild.');
31
- ok(v3.get('owner') === null, 'destroying a parent removes the owner reference from the grandchild.');
32
30
  });
33
31
  });
34
32
 
@@ -40,7 +38,6 @@ test('childViews specified as instances are also destroyed.', function() {
40
38
 
41
39
  SC.run(function() {
42
40
  ok(!v2.get('parentView'), 'destroying a parent removes the parentView reference from the child.');
43
- ok(v2.get('owner') === null, 'destroying a parent removes the owner reference from the child.');
44
41
  });
45
42
  });
46
43
 
@@ -8,7 +8,7 @@
8
8
  // View Layout Unit Tests
9
9
  // ========================================================================
10
10
 
11
- /*global module test ok same equals */
11
+ /*globals module, test, ok, same, equals */
12
12
 
13
13
 
14
14
  /* These unit tests verify: layout(), frame(), styleLayout() and clippingFrame(). */
@@ -919,7 +919,7 @@
919
919
 
920
920
 
921
921
  test("layout {centerX, centerY, width:auto, height:auto}", function () {
922
- var error = 'NONE';
922
+ var error = null;
923
923
  var layout = { centerX: 0.1, centerY: 0.1, width: 'auto', height: 'auto' };
924
924
 
925
925
  try {
@@ -931,7 +931,7 @@
931
931
  error = e;
932
932
  }
933
933
 
934
- equals(SC.T_ERROR, SC.typeOf(error), 'Layout style functions should throw an ' +
934
+ ok(error, 'Layout style functions should throw an ' +
935
935
  'error if centerx/y and width/height are set at the same time ' + error);
936
936
  });
937
937
 
@@ -1220,7 +1220,7 @@
1220
1220
  same(view.get('layout'), { bottom: 10, right: 10, width: 200, height: 50 }, "Test the value of the computed layout.");
1221
1221
  layoutStyle = view.get('layoutStyle');
1222
1222
  expectedLayoutStyle = { bottom: "10px", right: "10px", width: "200px", height: "50px" };
1223
- for (var key in layoutStyle) {
1223
+ for (key in layoutStyle) {
1224
1224
  equals(layoutStyle[key], expectedLayoutStyle[key], "Test the value of %@ in the layout style.".fmt(key));
1225
1225
  }
1226
1226
 
@@ -0,0 +1,602 @@
1
+ // ==========================================================================
2
+ // Project: SproutCore - JavaScript Application Framework
3
+ // Copyright: ©2006-2011 Strobe Inc. and contributors.
4
+ // ©2008-2011 Apple Inc. All rights reserved.
5
+ // License: Licensed under MIT license (see license.js)
6
+ // ==========================================================================
7
+
8
+ /*global module, test, equals, ok, same */
9
+
10
+ var view;
11
+
12
+ module("SC.View layout.js", {
13
+
14
+ setup: function () {
15
+ view = SC.View;
16
+ },
17
+
18
+ teardown: function () {
19
+ if (view.destroy) { view.destroy(); }
20
+ view = null;
21
+ }
22
+ });
23
+
24
+ /* Properties */
25
+
26
+ test("Default Properties:", function () {
27
+ view = view.create();
28
+ equals(view.hasLayout, true, "The default value of hasLayout is");
29
+ equals(view.backgroundColor, null, "The default value of backgroundColor is");
30
+ equals(view.useStaticLayout, false, "The default value of useStaticLayout is");
31
+ same(view.layout, { top: 0, left: 0, bottom: 0, right: 0 }, "The default value of layout is");
32
+ equals(view.childViewsNeedLayout, false, "The default value of childViewsNeedLayout is");
33
+ equals(view.childViewLayout, null, "The default value of childViewLayout is");
34
+ equals(view.childViewLayoutOptions, null, "The default value of childViewLayoutOptions is");
35
+ equals(view.isChildViewLayoutLive, true, "The default value of isChildViewLayoutLive is");
36
+ equals(view.transitionAdjust, null, "The default value of transitionAdjust is");
37
+ equals(view.transitionAdjustOptions, null, "The default value of transitionAdjustOptions is");
38
+ same(view.get('borderFrame'), { x: 0, y: 0, width: 0, height: 0 }, "The default value of borderFrame is");
39
+ same(view.get('explicitLayout'), { top: 0, left: 0, bottom: 0, right: 0 }, "The default value of explicitLayout is");
40
+ equals(view.get('isFixedLayout'), false, "The default value of isFixedLayout is");
41
+ equals(view.get('isFixedPosition'), true, "The default value of isFixedPosition is");
42
+ equals(view.get('isFixedSize'), false, "The default value of isFixedSize is");
43
+ equals(view.get('isFixedHeight'), false, "The default value of isFixedHeight is");
44
+ equals(view.get('isFixedWidth'), false, "The default value of isFixedWidth is");
45
+ equals(view.get('layoutView'), null, "The default value of layoutView is");
46
+ });
47
+
48
+ /* Methods */
49
+
50
+ // This method returns true if the layout change results in a change in size. This is based on a
51
+ // cache of the previous layout.
52
+ test("Method: _sc_checkForResize", function () {
53
+ view = view.create();
54
+
55
+ ok(view._sc_checkForResize !== undefined, 'defined', 'defined', "The method is");
56
+
57
+ // Fully flexible layout.
58
+ var previousLayout = { bottom: 0, left: 0, right: 0, top: 0 };
59
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 0, right: 0, top: 0 }), false, "When same flexible layout is checked, the method returns");
60
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 0, right: 0, top: 5 }), true, "When top of flexible height layout changes, the method returns");
61
+ equals(view._sc_checkForResize(previousLayout, { bottom: 5, left: 0, right: 0, top: 0 }), true, "When bottom of flexible height layout changes, the method returns");
62
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 5, right: 0, top: 0 }), true, "When left of flexible width layout changes, the method returns");
63
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 0, right: 5, top: 0 }), true, "When right of flexible width layout changes, the method returns");
64
+
65
+ // Vertically flexible layout.
66
+ previousLayout = { bottom: 0, left: 0, width: 100, top: 0 };
67
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 0, width: 100, top: 0 }), false, "When same vertically flexible layout is checked, the method returns");
68
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 0, width: 100, top: 5 }), true, "When top of vertically flexible height layout changes, the method returns");
69
+ equals(view._sc_checkForResize(previousLayout, { bottom: 5, left: 0, width: 100, top: 0 }), true, "When bottom of vertically flexible height layout changes, the method returns");
70
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 5, width: 100, top: 0 }), false, "When left of vertically flexible width layout changes, the method returns");
71
+ equals(view._sc_checkForResize(previousLayout, { bottom: 0, left: 0, width: 105, top: 0 }), true, "When width of vertically flexible width layout changes, the method returns");
72
+
73
+ // Horizontally flexible layout.
74
+ previousLayout = { height: 100, left: 0, right: 0, top: 0 };
75
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 0, right: 0, top: 0 }), false, "When same horizontally flexible layout is checked, the method returns");
76
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 0, right: 0, top: 5 }), false, "When top of horizontally flexible height layout changes, the method returns");
77
+ equals(view._sc_checkForResize(previousLayout, { height: 105, left: 0, right: 0, top: 0 }), true, "When height of horizontally flexible height layout changes, the method returns");
78
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 5, right: 0, top: 0 }), true, "When left of horizontally flexible width layout changes, the method returns");
79
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 0, right: 5, top: 0 }), true, "When right of horizontally flexible width layout changes, the method returns");
80
+
81
+ // Fully fixed top/left layout.
82
+ previousLayout = { height: 100, left: 0, width: 100, top: 0 };
83
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 0, width: 100, top: 0 }), false, "When same fully fixed top/left layout is checked, the method returns");
84
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 0, width: 100, top: 5 }), false, "When top of fully fixed top/left height layout changes, the method returns");
85
+ equals(view._sc_checkForResize(previousLayout, { height: 105, left: 0, width: 100, top: 0 }), true, "When height of fully fixed top/left height layout changes, the method returns");
86
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 5, width: 100, top: 0 }), false, "When left of fully fixed top/left width layout changes, the method returns");
87
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 0, width: 105, top: 0 }), true, "When width of fully fixed top/left width layout changes, the method returns");
88
+
89
+ // Fully fixed bottom/right layout.
90
+ previousLayout = { height: 100, right: 0, width: 100, bottom: 0 };
91
+ equals(view._sc_checkForResize(previousLayout, { height: 100, right: 0, width: 100, bottom: 0 }), false, "When same fully fixed bottom/right layout is checked, the method returns");
92
+ equals(view._sc_checkForResize(previousLayout, { height: 100, right: 0, width: 100, bottom: 5 }), false, "When bottom of fully fixed bottom/right height layout changes, the method returns");
93
+ equals(view._sc_checkForResize(previousLayout, { height: 105, right: 0, width: 100, bottom: 0 }), true, "When height of fully fixed bottom/right height layout changes, the method returns");
94
+ equals(view._sc_checkForResize(previousLayout, { height: 100, right: 5, width: 100, bottom: 0 }), false, "When right of fully fixed bottom/right width layout changes, the method returns");
95
+ equals(view._sc_checkForResize(previousLayout, { height: 100, right: 0, width: 105, bottom: 0 }), true, "When width of fully fixed bottom/right width layout changes, the method returns");
96
+
97
+ // Switch between flexible to fixed layout.
98
+ previousLayout = { bottom: 10, left: 10, right: 10, top: 10 };
99
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 10, width: 100, top: 10 }), true, "When switching from fully flexible to fully fixed top/left layout, the method returns");
100
+
101
+ previousLayout = { bottom: 10, left: 10, width: 100, top: 10 };
102
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 10, width: 100, top: 10 }), true, "When switching from vertically flexible to fully fixed top/left layout, the method returns");
103
+
104
+ previousLayout = { height: 100, left: 10, right: 10, top: 10 };
105
+ equals(view._sc_checkForResize(previousLayout, { height: 100, left: 10, width: 100, top: 10 }), true, "When switching from horizontally flexible to fully fixed top/left layout, the method returns");
106
+
107
+ // Switch between fixed layout with different anchor.
108
+ previousLayout = { height: 100, left: 10, width: 100, top: 10 };
109
+ equals(view._sc_checkForResize(previousLayout, { height: 100, right: 10, width: 100, bottom: 10 }), false, "When switching from fully fixed top/left to fully fixed bottom/right layout, the method returns");
110
+ });
111
+
112
+ /** Test isFixedLayout via isFixedSize and isFixedPosition properties. */
113
+ module("SC.View.prototype.isFixedLayout", {
114
+
115
+ setup: function () {
116
+ // Create a basic view.
117
+ view = SC.View.create({});
118
+ },
119
+
120
+ teardown: function () {
121
+ // Clean up.
122
+ view.destroy();
123
+ view = null;
124
+ }
125
+
126
+ });
127
+
128
+ test("Test isFixedHeight, isFixedWidth and isFixedSize for various layouts.", function () {
129
+ ok(!view.get('isFixedSize'), "The default layout doesn't correspond to a fixed size.");
130
+
131
+ SC.run(function () { view.set('layout', { width: 100 }); });
132
+ ok(view.get('isFixedWidth'), "A width alone gives a fixed width.");
133
+ ok(!view.get('isFixedHeight'), "A width alone doesn't give a fixed height.");
134
+ ok(!view.get('isFixedSize'), "A width alone doesn't correspond to a fixed size.");
135
+
136
+ SC.run(function () { view.set('layout', { height: 100 }); });
137
+ ok(!view.get('isFixedWidth'), "A height alone doesn't give a fixed width.");
138
+ ok(view.get('isFixedHeight'), "A height alone gives a fixed height.");
139
+ ok(!view.get('isFixedSize'), "A height alone doesn't correspond to a fixed size.");
140
+
141
+ SC.run(function () { view.set('layout', { width: 100, height: 100 }); });
142
+ ok(view.get('isFixedWidth'), "A width & height give a fixed width.");
143
+ ok(view.get('isFixedHeight'), "A width & height give a fixed height.");
144
+ ok(view.get('isFixedSize'), "A width & height corresponds to a fixed size.");
145
+ });
146
+
147
+ test("Test isFixedPosition for various layouts.", function () {
148
+ ok(view.get('isFixedPosition'), "The default layout corresponds to a fixed position.");
149
+
150
+ SC.run(function () { view.set('layout', { left: 0 }); });
151
+ ok(view.get('isFixedPosition'), "A left: 0 (implied top, bottom, right) corresponds to a fixed position.");
152
+
153
+ SC.run(function () { view.set('layout', { top: 0 }); });
154
+ ok(view.get('isFixedPosition'), "A top: 0 (implied left, bottom, right) corresponds to a fixed position.");
155
+
156
+ SC.run(function () { view.set('layout', { left: 0, top: 0 }); });
157
+ ok(view.get('isFixedPosition'), "A left: 0, top: 0 corresponds to a fixed position.");
158
+
159
+ SC.run(function () { view.set('layout', { left: 50 }); });
160
+ ok(view.get('isFixedPosition'), "A left: 50 corresponds to a fixed position.");
161
+
162
+ SC.run(function () { view.set('layout', { top: 50 }); });
163
+ ok(view.get('isFixedPosition'), "A top: 50 corresponds to a fixed position.");
164
+
165
+ SC.run(function () { view.set('layout', { left: 50, top: 50 }); });
166
+ ok(view.get('isFixedPosition'), "A left: 50, top: 50 corresponds to a fixed position.");
167
+
168
+ SC.run(function () { view.set('layout', { right: 0 }); });
169
+ ok(view.get('isFixedPosition'), "A right: 0 (implied left) corresponds to a fixed position.");
170
+
171
+ SC.run(function () { view.set('layout', { bottom: 0 }); });
172
+ ok(view.get('isFixedPosition'), "A bottom: 0 (implied top) corresponds to a fixed position.");
173
+
174
+ SC.run(function () { view.set('layout', { right: 50 }); });
175
+ ok(view.get('isFixedPosition'), "A right: 50 (implied left) corresponds to a fixed position.");
176
+
177
+ SC.run(function () { view.set('layout', { bottom: 50 }); });
178
+ ok(view.get('isFixedPosition'), "A bottom: 50 (implied top) corresponds to a fixed position.");
179
+
180
+ SC.run(function () { view.set('layout', { width: 100 }); });
181
+ ok(view.get('isFixedPosition'), "A width: 100 (implied left) corresponds to a fixed position.");
182
+
183
+ SC.run(function () { view.set('layout', { height: 100 }); });
184
+ ok(view.get('isFixedPosition'), "A height: 100 (implied top) corresponds to a fixed position.");
185
+
186
+ SC.run(function () { view.set('layout', { right: 0, width: 100 }); });
187
+ ok(!view.get('isFixedPosition'), "A right: 0, width: 100 (overridden left) doesn't correspond to a fixed position.");
188
+
189
+ SC.run(function () { view.set('layout', { bottom: 0, height: 100 }); });
190
+ ok(!view.get('isFixedPosition'), "A bottom: 0, height: 100 (overridden top) doesn't correspond to a fixed position.");
191
+
192
+ SC.run(function () { view.set('layout', { centerX: 0, width: 100 }); });
193
+ ok(!view.get('isFixedPosition'), "A centerX: 0, width: 100 (overridden left) doesn't correspond to a fixed position.");
194
+
195
+ SC.run(function () { view.set('layout', { centerY: 0, height: 100 }); });
196
+ ok(!view.get('isFixedPosition'), "A centerY: 0, height: 100 (overridden top) doesn't correspond to a fixed position.");
197
+
198
+ SC.run(function () { view.set('layout', { left: 0.2 }); });
199
+ ok(!view.get('isFixedPosition'), "A left: 0.2 (percentage left) doesn't correspond to a fixed position.");
200
+
201
+ SC.run(function () { view.set('layout', { top: 0.2 }); });
202
+ ok(!view.get('isFixedPosition'), "A top: 0.2 (percentage top) doesn't correspond to a fixed position.");
203
+
204
+ SC.run(function () { view.set('layout', { left: SC.LAYOUT_AUTO }); });
205
+ ok(!view.get('isFixedPosition'), "A left: SC.LAYOUT_AUTO (auto left) doesn't correspond to a fixed position.");
206
+
207
+ SC.run(function () { view.set('layout', { top: SC.LAYOUT_AUTO }); });
208
+ ok(!view.get('isFixedPosition'), "A top: SC.LAYOUT_AUTO (auto top) doesn't correspond to a fixed position.");
209
+ });
210
+
211
+ test("Test explicitLayout for various valid layouts.", function () {
212
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0 }, "No layout is implied as");
213
+
214
+ SC.run(function () { view.set('layout', { left: 5 }); });
215
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 5 }, "{ left: 5 } is implied as");
216
+
217
+ SC.run(function () { view.set('layout', { top: 5 }); });
218
+ same(view.get('explicitLayout'), { top: 5, right: 0, bottom: 0, left: 0 }, "{ top: 5 } is implied as");
219
+
220
+ SC.run(function () { view.set('layout', { bottom: 5 }); });
221
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 5, left: 0 }, "{ bottom: 5 } is implied as");
222
+
223
+ SC.run(function () { view.set('layout', { right: 5 }); });
224
+ same(view.get('explicitLayout'), { top: 0, right: 5, bottom: 0, left: 0 }, "{ right: 5 } is implied as");
225
+
226
+ SC.run(function () { view.set('layout', { bottom: 5, left: 5 }); });
227
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 5, left: 5 }, "{ bottom: 5, left: 5 } is implied as");
228
+
229
+ SC.run(function () { view.set('layout', { right: 5, bottom: 5, left: 5 }); });
230
+ same(view.get('explicitLayout'), { top: 0, right: 5, bottom: 5, left: 5 }, "{ right: 5, bottom: 5, left: 5 } is implied as");
231
+
232
+ SC.run(function () { view.set('layout', { top: 5, right: 5, bottom: 5, left: 5 }); });
233
+ same(view.get('explicitLayout'), { top: 5, right: 5, bottom: 5, left: 5 }, "{ top: 5, right: 5, bottom: 5, left: 5 } is implied as");
234
+
235
+ SC.run(function () { view.set('layout', { top: 5, right: 5, bottom: 5 }); });
236
+ same(view.get('explicitLayout'), { top: 5, right: 5, bottom: 5, left: 0 }, "{ top: 5, right: 5, bottom: 5 } is implied as");
237
+
238
+ SC.run(function () { view.set('layout', { top: 5, right: 5 }); });
239
+ same(view.get('explicitLayout'), { top: 5, right: 5, bottom: 0, left: 0 }, "{ top: 5, right: 5 } is implied as");
240
+
241
+ SC.run(function () { view.set('layout', { width: 100 }); });
242
+ same(view.get('explicitLayout'), { top: 0, width: 100, bottom: 0, left: 0 }, "{ width: 100 } is implied as");
243
+
244
+ SC.run(function () { view.set('layout', { width: 100, right: 5 }); });
245
+ same(view.get('explicitLayout'), { top: 0, width: 100, bottom: 0, right: 5 }, "{ width: 100, right: 5 } is implied as");
246
+
247
+ SC.run(function () { view.set('layout', { height: 100 }); });
248
+ same(view.get('explicitLayout'), { top: 0, height: 100, right: 0, left: 0 }, "{ height: 100 } is implied as");
249
+
250
+ SC.run(function () { view.set('layout', { height: 100, bottom: 5 }); });
251
+ same(view.get('explicitLayout'), { right: 0, height: 100, bottom: 5, left: 0 }, "{ height: 100, bottom: 5 } is implied as");
252
+
253
+ // MIN/MAX
254
+
255
+ SC.run(function () { view.set('layout', { minWidth: 100, maxHeight: 100 }); });
256
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, minWidth: 100, maxHeight: 100 }, "{ minWidth: 100, maxHeight: 100 } is implied as");
257
+
258
+ SC.run(function () { view.set('layout', { maxWidth: 100, minHeight: 100 }); });
259
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, maxWidth: 100, minHeight: 100 }, "{ maxWidth: 100, minHeight: 100 } is implied as");
260
+
261
+ // CENTERS
262
+
263
+ SC.run(function () { view.set('layout', { centerX: 0, width: 100 }); });
264
+ same(view.get('explicitLayout'), { top: 0, centerX: 0, width: 100, bottom: 0 }, "{ centerX: 0, width: 100 } is implied as");
265
+
266
+ SC.run(function () { view.set('layout', { centerY: 0, height: 100 }); });
267
+ same(view.get('explicitLayout'), { right: 0, centerY: 0, height: 100, left: 0 }, "{ centerY: 0, height: 100 } is implied as");
268
+
269
+ // OPACITY
270
+
271
+ SC.run(function () { view.set('layout', { opacity: 0.25 }); });
272
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, opacity: 0.25 }, "{ opacity: 0.25 } is implied as");
273
+
274
+ // TRANSFORMS
275
+
276
+ SC.run(function () { view.set('layout', { scale: 0.25 }); });
277
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, scale: 0.25 }, "{ scale: 0.25 } is implied as");
278
+
279
+ SC.run(function () { view.set('layout', { transformOriginX: 0, transformOriginY: 1 }); });
280
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, transformOriginX: 0, transformOriginY: 1 }, "{ transformOriginX: 0, transformOriginY: 1 } is implied as");
281
+
282
+ // BORDERS
283
+
284
+ SC.run(function () { view.set('layout', { border: 1 }); });
285
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, borderTop: 1, borderRight: 1, borderBottom: 1, borderLeft: 1 }, "{ border: 1 } is implied as");
286
+
287
+ SC.run(function () { view.set('layout', { border: 1, borderTop: 2 }); });
288
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, borderTop: 2, borderRight: 1, borderBottom: 1, borderLeft: 1 }, "{ border: 1, borderTop: 2 } is implied as");
289
+
290
+ SC.run(function () { view.set('layout', { borderBottom: 1, borderTop: 2 }); });
291
+ same(view.get('explicitLayout'), { top: 0, right: 0, bottom: 0, left: 0, borderTop: 2, borderBottom: 1 }, "{ borderBottom: 1, borderTop: 2 } is implied as");
292
+ });
293
+
294
+ test("Test explicitLayout for various invalid layouts.", function () {
295
+ // Centered without a size dimension.
296
+ SC.run(function () { view.set('layout', { centerX: 0 }); });
297
+ same(view.get('explicitLayout'), { top: 0, centerX: 0, bottom: 0 }, "{ centerX: 0 } is implied as");
298
+
299
+ // Centered without a size dimension.
300
+ SC.run(function () { view.set('layout', { centerY: 0 }); });
301
+ same(view.get('explicitLayout'), { left: 0, centerY: 0, right: 0 }, "{ centerY: 0 } is implied as");
302
+
303
+ // Left, right & width
304
+ SC.run(function () { view.set('layout', { left: 5, width: 100, right: 5 }); });
305
+ same(view.get('explicitLayout'), { top: 0, left: 5, bottom: 0, width: 100 }, "{ left: 5, width: 100, right: 5 } is implied as");
306
+
307
+ // Top, bottom & height
308
+ SC.run(function () { view.set('layout', { top: 5, height: 100, bottom: 5 }); });
309
+ same(view.get('explicitLayout'), { left: 0, top: 5, right: 0, height: 100 }, "{ top: 5, height: 100, bottom: 5 } is implied as");
310
+ });
311
+
312
+
313
+ module("SC.View.prototype.layoutDidChange");
314
+
315
+ test("notifies layoutStyle & frame change", function () {
316
+
317
+ var view = SC.View.create();
318
+ var layoutStyleCallCount = 0, frameCallCount = 0;
319
+
320
+ view.addObserver('layoutStyle', function () { layoutStyleCallCount++; });
321
+ view.addObserver('frame', function () { frameCallCount++; });
322
+
323
+ SC.run(function () {
324
+ // Manually indicate a layout change.
325
+ view.layoutDidChange();
326
+ });
327
+
328
+ equals(frameCallCount, 1, 'should trigger observer for frame');
329
+ equals(layoutStyleCallCount, 0, 'should not trigger observers for layoutStyle');
330
+
331
+ // Attach to the document.
332
+ var parent = SC.Pane.create();
333
+ parent.append();
334
+ parent.appendChild(view);
335
+
336
+ equals(frameCallCount, 2, 'should trigger observers for frame when adopted');
337
+ equals(layoutStyleCallCount, 0, 'should still not trigger observers for layoutStyle');
338
+
339
+ SC.run(function () {
340
+ view.adjust('top', 20);
341
+ });
342
+
343
+ equals(frameCallCount, 3, 'should trigger observers for frame when adjusted');
344
+ equals(layoutStyleCallCount, 1, 'should trigger observers for layoutStyle when adjusted');
345
+
346
+ // Clean up.
347
+ view.destroy();
348
+ parent.destroy();
349
+ });
350
+
351
+ test("invokes layoutDidChangeFor() on layoutView each time it is called", function () {
352
+
353
+ var callCount = 0;
354
+ var layoutView = SC.View.create({
355
+ layoutDidChangeFor: function (changedView) {
356
+ equals(this.get('childViewsNeedLayout'), YES, 'should set childViewsNeedLayout to YES before calling layoutDidChangeFor()');
357
+
358
+ equals(view, changedView, 'should pass view');
359
+ callCount++;
360
+
361
+ // Original
362
+ var set = this._needLayoutViews;
363
+ if (!set) set = this._needLayoutViews = SC.CoreSet.create();
364
+ set.add(changedView);
365
+ }
366
+ });
367
+
368
+ var view = SC.View.create({ layoutView: layoutView });
369
+
370
+ SC.run(function () {
371
+ view.layoutDidChange();
372
+ view.layoutDidChange();
373
+ view.layoutDidChange();
374
+ });
375
+
376
+ equals(callCount, 3, 'should call layoutView.layoutDidChangeFor each time');
377
+
378
+ // Clean up.
379
+ layoutView.destroy();
380
+ view.destroy();
381
+ });
382
+
383
+ test("invokes layoutChildViewsIfNeeded() on layoutView once per runloop", function () {
384
+
385
+ var callCount = 0;
386
+ var layoutView = SC.View.create({
387
+ layoutChildViewsIfNeeded: function () {
388
+ callCount++;
389
+ }
390
+ });
391
+
392
+ var view = SC.View.create({ layoutView: layoutView });
393
+
394
+ SC.run(function () {
395
+ view.layoutDidChange();
396
+ view.layoutDidChange();
397
+ view.layoutDidChange();
398
+ });
399
+
400
+ equals(callCount, 1, 'should call layoutView.layoutChildViewsIfNeeded one time');
401
+
402
+ // Clean up.
403
+ layoutView.destroy();
404
+ view.destroy();
405
+ });
406
+
407
+ test("should not invoke layoutChildViewsIfNeeded() if layoutDidChangeFor() sets childViewsNeedLayout to NO each time", function () {
408
+
409
+ var callCount = 0;
410
+ var layoutView = SC.View.create({
411
+ layoutDidChangeFor: function () {
412
+ this.set('childViewsNeedLayout', NO);
413
+ },
414
+
415
+ layoutChildViewsIfNeeded: function () {
416
+ callCount++;
417
+ }
418
+ });
419
+
420
+ var view = SC.View.create({ layoutView: layoutView });
421
+
422
+ SC.run(function () {
423
+ view.layoutDidChange();
424
+ view.layoutDidChange();
425
+ view.layoutDidChange();
426
+ });
427
+
428
+ equals(callCount, 0, 'should not call layoutView.layoutChildViewsIfNeeded');
429
+
430
+ // Clean up.
431
+ layoutView.destroy();
432
+ view.destroy();
433
+ });
434
+
435
+ test('returns receiver', function () {
436
+ var view = SC.View.create();
437
+
438
+ SC.run(function () {
439
+ equals(view.layoutDidChange(), view, 'should return receiver');
440
+ });
441
+
442
+ // Clean up.
443
+ view.destroy();
444
+ });
445
+
446
+ test("is invoked whenever layout property changes", function () {
447
+
448
+ var callCount = 0;
449
+ var layoutView = SC.View.create({
450
+ layoutDidChangeFor: function (changedView) {
451
+ callCount++;
452
+
453
+ // Original
454
+ var set = this._needLayoutViews;
455
+ if (!set) set = this._needLayoutViews = SC.CoreSet.create();
456
+ set.add(changedView);
457
+ }
458
+ });
459
+
460
+ var view = SC.View.create({ layoutView: layoutView });
461
+
462
+ SC.run(function () {
463
+ view.set('layout', { top: 0, left: 10 });
464
+ });
465
+ equals(callCount, 1, 'should call layoutDidChangeFor when setting layout of child view');
466
+
467
+ // Clean up.
468
+ layoutView.destroy();
469
+ view.destroy();
470
+ });
471
+
472
+ test("is invoked on parentView if no layoutView whenever layout property changes", function () {
473
+
474
+ var callCount = 0;
475
+ var parentView = SC.View.create({
476
+ layoutDidChangeFor: function (changedView) {
477
+ callCount++;
478
+
479
+ // Original
480
+ var set = this._needLayoutViews;
481
+ if (!set) set = this._needLayoutViews = SC.CoreSet.create();
482
+ set.add(changedView);
483
+ }
484
+ });
485
+
486
+ var view = SC.View.create({});
487
+ view.set('parentView', parentView);
488
+
489
+ SC.run(function () {
490
+ view.set('layout', { top: 0, left: 10 });
491
+ });
492
+ equals(callCount, 1, 'should call layoutDidChangeFor when setting layout of child view');
493
+
494
+ // Clean up.
495
+ parentView.destroy();
496
+ view.destroy();
497
+ });
498
+
499
+ test("proxies rotate to rotateZ when 3D transforms are supported", function () {
500
+ // Retain CSS support information so we can return to it.
501
+ var actualSupport = SC.platform.get('supportsCSS3DTransforms'),
502
+ view;
503
+
504
+ // YES SUPPORT
505
+ SC.platform.set('supportsCSS3DTransforms', YES);
506
+ view = SC.View.create();
507
+ SC.run(function () {
508
+ view.set('layout', { rotate: 45 });
509
+ });
510
+ equals(view.get('layout').rotate, undefined, "should clear rotate");
511
+ equals(view.get('layout').rotateZ, 45, "should set rotateZ");
512
+ // Clean up.
513
+ view.destroy();
514
+
515
+ // NO SUPPORT
516
+ SC.platform.set('supportsCSS3DTransforms', NO);
517
+ view = SC.View.create();
518
+ SC.run(function () {
519
+ view.set('layout', { rotate: 45 });
520
+ });
521
+ equals(view.get('layout').rotate, 45, "should retain rotate");
522
+ equals(view.get('layout').rotateZ, undefined, "should not set rotateZ");
523
+ // Clean up.
524
+ view.destroy();
525
+
526
+ // Clean up bigger picture.
527
+ SC.platform.set('supportsCSS3DTransforms', actualSupport);
528
+ });
529
+
530
+ test("rotateZ and rotate together", function () {
531
+ var view = SC.View.create({});
532
+
533
+ SC.run(function () {
534
+ view.set('layout', { rotate: 45, rotateZ: 90 });
535
+ });
536
+
537
+ equals(view.get('layout').rotate, 45, "if both rotate and rotateZ values are present, both should be retained; rotate is");
538
+
539
+ equals(view.get('layout').rotateZ, 90, "if both rotate and rotateZ values are present, both should be retained; rotateZ is");
540
+
541
+ // Clean up.
542
+ view.destroy();
543
+ });
544
+
545
+ // The default implementation for viewDidResize calls internal layout-related
546
+ // methods on child views. This test confirms that child views that do not
547
+ // support layout do not cause this process to explode.
548
+ test("Calling viewDidResize on a view notifies its child views", function () {
549
+ var regularViewCounter = 0, coreViewCounter = 0;
550
+
551
+ var view = SC.View.create({
552
+ childViews: ['regular', 'core'],
553
+
554
+ regular: SC.View.extend({
555
+ viewDidResize: function () {
556
+ regularViewCounter++;
557
+ // Make sure we call the default implementation to
558
+ // ensure potential blow-uppy behavior is invoked
559
+ sc_super();
560
+ }
561
+ }),
562
+
563
+ core: SC.CoreView.extend({
564
+ viewDidResize: function () {
565
+ coreViewCounter++;
566
+ sc_super();
567
+ }
568
+ })
569
+ });
570
+
571
+ view.viewDidResize();
572
+
573
+ equals(regularViewCounter, 1, "regular view's viewDidResize gets called");
574
+ equals(coreViewCounter, 1, "core view's viewDidResize gets called");
575
+
576
+ // Clean up.
577
+ view.destroy();
578
+ });
579
+
580
+
581
+ /**
582
+ When a view's layout changes, _sc_checkForResize determines whether the size has changed using a comparison of the previously
583
+ cached layout and the new (current) layout. If it seems that the view has resized, it calls `viewDidResize`. Previously
584
+ it would call viewDidResize and then update the _sc_previousLayout cache afterward. This meant that any adjustments that
585
+ were triggered by viewDidResize (which would in turn call _sc_checkForResize) would compare the new layout against the
586
+ previous previous layout, instead of just the previous layout.
587
+
588
+ Long story short, to ensure that _sc_checkForResize is checking the current layout against the *last* layout, it's important
589
+ that the last layout, _sc_previousLayout, is updated *before* continuing on.
590
+ */
591
+ test("SC.View.prototype.layoutDidChange() updates the _sc_previousLayout cache before calling viewDidResize", function () {
592
+ var view1 = SC.View.create({
593
+ layout: { width: 200, height: 200 },
594
+ viewDidResize: function () {
595
+ ok(this._sc_previousLayout !== originalPreviousLayout, "The previous layout should not be the same anymore.");
596
+ }
597
+ }),
598
+ originalPreviousLayout;
599
+
600
+ originalPreviousLayout = view1.get('layout');
601
+ SC.run(function () { view1.adjust({ width: 100 }); });
602
+ });