sproutcore 1.11.0.rc3 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ });