sproutcore 1.11.0.rc2 → 1.11.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG +10 -0
  3. data/VERSION.yml +1 -1
  4. data/lib/frameworks/sproutcore/CHANGELOG.md +114 -1
  5. data/lib/frameworks/sproutcore/apps/showcase/views/views_item_view.js +1 -7
  6. data/lib/frameworks/sproutcore/apps/showcase/views/views_list_view.js +9 -9
  7. data/lib/frameworks/sproutcore/frameworks/ajax/system/request.js +167 -5
  8. data/lib/frameworks/sproutcore/frameworks/ajax/system/response.js +24 -8
  9. data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/stack_layout.js +737 -0
  10. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/layout.js +0 -6
  11. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +11 -7
  12. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane_statechart.js +7 -11
  13. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/child_view_layout_protocol.js +8 -3
  14. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/observable_protocol.js +9 -6
  15. data/lib/frameworks/sproutcore/frameworks/{desktop/protocols/responder.js → core_foundation/protocols/responder_protocol.js} +83 -17
  16. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/{sparse_array_delegate.js → sparse_array_delegate_protocol.js} +11 -7
  17. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/view_transition_protocol.js +11 -6
  18. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/color.js +2 -2
  19. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/page.js +0 -22
  20. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +61 -56
  21. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/main_pane.js +2 -2
  22. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/append_remove.js +3 -3
  23. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/animation.js +63 -39
  24. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/border_frame_test.js +28 -28
  25. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/createLayer.js +10 -4
  26. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layout.js +102 -1
  27. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutDidChange.js +4 -4
  28. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +103 -103
  29. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/replaceAllChildren_test.js +1 -1
  30. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/view.js +77 -1
  31. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/view_states_test.js +18 -17
  32. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +42 -49
  33. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +5 -6
  34. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/enabled.js +16 -5
  35. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +241 -102
  36. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +1 -4
  37. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +0 -11
  38. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/statechart.js +993 -610
  39. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/theming.js +3 -2
  40. data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +6 -11
  41. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +94 -27
  42. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +133 -53
  43. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +30 -35
  44. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/writeAttribute.js +3 -2
  45. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/writeDataHash.js +73 -29
  46. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/conflictedStoreKeys_test.js +156 -0
  47. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataSourceCallbacks.js +61 -37
  48. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/find.js +2 -2
  49. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +68 -39
  50. data/lib/frameworks/sproutcore/frameworks/designer/tests/coders/page.js +1 -2
  51. data/lib/frameworks/sproutcore/frameworks/desktop/panes/panel.js +8 -6
  52. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +80 -14
  53. data/lib/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +2 -2
  54. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/{drag_data_source.js → drag_data_source_protocol.js} +16 -10
  55. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/{drag_source.js → drag_source_protocol.js} +28 -26
  56. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/{drop_target.js → drop_target_protocol.js} +73 -75
  57. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +4 -4
  58. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/ui.js +39 -23
  59. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/mouse.js +120 -97
  60. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowSizeForContentIndex.js +26 -25
  61. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/ui.js +3 -3
  62. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +5 -0
  63. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/split/{dividers.js → dividers_test.js} +38 -38
  64. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +29 -14
  65. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +2 -1
  66. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll_view.js +13 -18
  67. data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +41 -35
  68. data/lib/frameworks/sproutcore/frameworks/desktop/views/slider.js +14 -14
  69. data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +41 -26
  70. data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +2 -12
  71. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/tap.js +2 -2
  72. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +14 -10
  73. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/gesturable.js +104 -63
  74. data/lib/frameworks/sproutcore/frameworks/foundation/protocols/swap_transition_protocol.js +9 -4
  75. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_mixin_tests.js +1 -2
  76. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_resize_test.js +33 -33
  77. data/lib/frameworks/sproutcore/frameworks/foundation/tests/transitions/view_transitions_test.js +5 -5
  78. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/methods.js +0 -4
  79. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/transition_test.js +0 -4
  80. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/ui.js +0 -2
  81. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +12 -8
  82. data/lib/frameworks/sproutcore/frameworks/media/resources/silence.mp3 +0 -0
  83. data/lib/frameworks/sproutcore/frameworks/media/tests/audio.js +69 -0
  84. data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +1 -0
  85. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
  86. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +11 -4
  87. data/lib/frameworks/sproutcore/frameworks/runtime/protocols/mixin_protocol.js +150 -0
  88. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +447 -137
  89. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +9 -15
  90. data/lib/frameworks/sproutcore/frameworks/runtime/system/set.js +19 -17
  91. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +188 -16
  92. data/lib/frameworks/sproutcore/frameworks/statechart/system/state.js +1 -1
  93. data/lib/frameworks/sproutcore/frameworks/template_view/panes/template.js +0 -3
  94. data/lib/frameworks/sproutcore/frameworks/template_view/tests/panes/template.js +0 -17
  95. data/lib/frameworks/sproutcore/frameworks/template_view/tests/views/template/collection.js +43 -26
  96. data/lib/frameworks/sproutcore/frameworks/template_view/views/bindable_span.js +9 -2
  97. data/lib/frameworks/sproutcore/themes/ace/resources/collection/normal/list.css +0 -1
  98. data/lib/frameworks/sproutcore/themes/ace/resources/scroll/scroll.css +3 -0
  99. data/sproutcore.gemspec +3 -3
  100. metadata +19 -17
  101. data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/horizontal_stack_layout.js +0 -465
  102. data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/vertical_stack_layout.js +0 -472
  103. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/build.js +0 -87
  104. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/build_children.js +0 -89
@@ -260,10 +260,7 @@ SC.View.LayoutStyleCalculator = {
260
260
 
261
261
  // Calculate the margin offset used to center the value along this axis.
262
262
  if (SC.none(sizeValue)) {
263
- //@if(debug)
264
- // This error message happens whenever width or height is not set.
265
- SC.warn("Developer Warning: When setting '" + center + "' in the layout, you must also set '" + size + "'.");
266
- //@endif
263
+ // Invalid!
267
264
  style[margin] = "50%";
268
265
  } else {
269
266
  value = centerValue - sizeValue / 2;
@@ -56,17 +56,6 @@ SC.View.reopen(
56
56
 
57
57
  view.endPropertyChanges();
58
58
 
59
- // Make sure all notifications are delayed since the appending
60
- // doesn't complete until the end of the RunLoop
61
- // There may be better ways to do this than with invokeLast,
62
- // but it's the best I can do for now - PDW
63
- // this.invokeLast(function () {
64
- // var pane = view.get('pane');
65
- // if (pane && pane.get('isPaneAttached')) {
66
- // view._notifyDidAppendToDocument();
67
- // }
68
- // });
69
-
70
59
  return this ;
71
60
  },
72
61
 
@@ -6,16 +6,16 @@ SC.LOG_VIEW_STATES = false;
6
6
  SC.LOG_VIEW_STATES_STYLE = {
7
7
  0x0200: 'color: #67b7db; font-style: italic;', // UNRENDERED
8
8
  0x0300: 'color: #67b7db; font-style: italic;', // UNATTACHED
9
- 0x0301: 'color: #67b7db; font-style: italic;', // UNATTACHED_BY_PARENT
9
+ 0x0380: 'color: #67b7db; font-style: italic;', // ATTACHED_PARTIAL
10
10
  0x03C0: 'color: #23abf5; font-style: italic;', // ATTACHED_SHOWN
11
- 0x03C3: 'color: #1fe7a8; font-style: italic;', // ATTACHED_SHOWN_ANIMATING
11
+ 0x03C4: 'color: #1fe7a8; font-style: italic;', // ATTACHED_SHOWN_ANIMATING
12
12
  0x03A0: 'color: #67b7db; font-style: italic;', // ATTACHED_HIDDEN
13
13
  0x03A1: 'color: #67b7db; font-style: italic;', // ATTACHED_HIDDEN_BY_PARENT
14
14
  0x03C1: 'color: #b800db; font-style: italic;', // ATTACHED_BUILDING_IN
15
15
  0x0381: 'color: #b800db; font-style: italic;', // ATTACHED_BUILDING_OUT
16
16
  0x0382: 'color: #b800db; font-style: italic;', // ATTACHED_BUILDING_OUT_BY_PARENT
17
17
  0x03C2: 'color: #b800db; font-style: italic;', // ATTACHED_SHOWING
18
- 0x03A2: 'color: #b800db; font-style: italic;' // ATTACHED_HIDING
18
+ 0x03C3: 'color: #b800db; font-style: italic;' // ATTACHED_HIDING
19
19
  };
20
20
  //@endif
21
21
 
@@ -23,6 +23,11 @@ SC.LOG_VIEW_STATES_STYLE = {
23
23
  SC.CoreView.mixin(
24
24
  /** @scope SC.CoreView */ {
25
25
 
26
+ // State bit masks
27
+
28
+ // Logically always present, so not necessary, but here for logical ordering.
29
+ // IS_CREATED: 0x0200, // 10 0000 0000, 512
30
+
26
31
  /**
27
32
  The view has been rendered.
28
33
 
@@ -33,7 +38,7 @@ SC.CoreView.mixin(
33
38
  @static
34
39
  @constant
35
40
  */
36
- IS_RENDERED: 0x0100, // 256
41
+ IS_RENDERED: 0x0100, // 01 0000 0000, 256
37
42
 
38
43
  /**
39
44
  The view has been attached.
@@ -45,7 +50,7 @@ SC.CoreView.mixin(
45
50
  @static
46
51
  @constant
47
52
  */
48
- IS_ATTACHED: 0x0080, // 128
53
+ IS_ATTACHED: 0x0080, // 00 1000 0000, 128
49
54
 
50
55
  /**
51
56
  The view is visible in the display.
@@ -57,7 +62,7 @@ SC.CoreView.mixin(
57
62
  @static
58
63
  @constant
59
64
  */
60
- IS_SHOWN: 0x0040, // 64
65
+ IS_SHOWN: 0x0040, // 00 0100 0000, 64
61
66
 
62
67
  /**
63
68
  The view is invisible in the display.
@@ -69,7 +74,9 @@ SC.CoreView.mixin(
69
74
  @static
70
75
  @constant
71
76
  */
72
- IS_HIDDEN: 0x0020, // 32
77
+ IS_HIDDEN: 0x0020, // 00 0010 0000, 32
78
+
79
+ // Main states
73
80
 
74
81
  /**
75
82
  The view has been created, but has not been rendered or attached.
@@ -77,7 +84,7 @@ SC.CoreView.mixin(
77
84
  @static
78
85
  @constant
79
86
  */
80
- UNRENDERED: 0x0200, // 512
87
+ UNRENDERED: 0x0200, // 10 0000 0000, 512 (IS_CREATED)
81
88
 
82
89
  /**
83
90
  The view has been created and rendered, but has not been attached
@@ -86,43 +93,37 @@ SC.CoreView.mixin(
86
93
  @static
87
94
  @constant
88
95
  */
89
- UNATTACHED: 0x0300, // 768
96
+ UNATTACHED: 0x0300, // 11 0000 0000, 768 (IS_CREATED + IS_RENDERED)
90
97
 
91
98
  /**
92
- The view has been created and rendered, but an ancestor is not attached.
99
+ The view has been created and rendered and attached to a parent, but an ancestor is not
100
+ attached.
93
101
 
94
102
  @static
95
103
  @constant
96
104
  */
97
- UNATTACHED_BY_PARENT: 0x0301, // 769
105
+ ATTACHED_PARTIAL: 0x0380, // 11 1000 0000, 896 (IS_CREATED + IS_RENDERED + IS_ATTACHED)
98
106
 
99
107
  /**
100
- The view has been created, rendered and attached and is visible in the
108
+ The view has been created, rendered and attached, but is not visible in the
101
109
  display.
102
110
 
111
+ Test with & SC.CoreView.IS_HIDDEN
103
112
  @static
104
113
  @constant
105
114
  */
106
- ATTACHED_SHOWN: 0x03C0, // 960
107
-
108
- /**
109
- The view has been created, rendered and attached, is visible in the
110
- display and is being animated via a call to `animate()`.
111
-
112
- @static
113
- @constant
114
- */
115
- ATTACHED_SHOWN_ANIMATING: 0x03C3, // 963
115
+ ATTACHED_HIDDEN: 0x03A0, // 11 1010 0000, 928 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_HIDDEN)
116
116
 
117
117
  /**
118
- The view has been created, rendered and attached, but is not visible in the
118
+ The view has been created, rendered and attached and is visible in the
119
119
  display.
120
120
 
121
- Test with & SC.CoreView.IS_HIDDEN
122
121
  @static
123
122
  @constant
124
123
  */
125
- ATTACHED_HIDDEN: 0x03A0, // 928
124
+ ATTACHED_SHOWN: 0x03C0, // 11 1100 0000, 960 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_SHOWN)
125
+
126
+ // Minor states
126
127
 
127
128
  /**
128
129
  The view has been created, rendered and attached, but is not visible in the
@@ -131,7 +132,7 @@ SC.CoreView.mixin(
131
132
  @static
132
133
  @constant
133
134
  */
134
- ATTACHED_HIDDEN_BY_PARENT: 0x03A1, // 929
135
+ ATTACHED_HIDDEN_BY_PARENT: 0x03A1, // 929 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_HIDDEN +)
135
136
 
136
137
  /**
137
138
  The view has been created, rendered and attached and is visible in the
@@ -141,7 +142,7 @@ SC.CoreView.mixin(
141
142
  @static
142
143
  @constant
143
144
  */
144
- ATTACHED_BUILDING_IN: 0x03C1, // 961
145
+ ATTACHED_BUILDING_IN: 0x03C1, // 961 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_SHOWN +)
145
146
 
146
147
  /**
147
148
  The view has been created, rendered and attached. It is currently
@@ -151,7 +152,7 @@ SC.CoreView.mixin(
151
152
  @static
152
153
  @constant
153
154
  */
154
- ATTACHED_BUILDING_OUT: 0x0381, // 897
155
+ ATTACHED_BUILDING_OUT: 0x03C4, // 964 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_SHOWN +)
155
156
 
156
157
  /**
157
158
  The view has been created, rendered and attached. It is currently
@@ -162,7 +163,7 @@ SC.CoreView.mixin(
162
163
  @static
163
164
  @constant
164
165
  */
165
- ATTACHED_BUILDING_OUT_BY_PARENT: 0x0382, // 898
166
+ ATTACHED_BUILDING_OUT_BY_PARENT: 0x03C5, // 965 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_SHOWN +)
166
167
 
167
168
  /**
168
169
  The view has been created, rendered and attached and is visible in the
@@ -172,7 +173,7 @@ SC.CoreView.mixin(
172
173
  @static
173
174
  @constant
174
175
  */
175
- ATTACHED_SHOWING: 0x03C2, // 962
176
+ ATTACHED_SHOWING: 0x03C2, // 962 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_SHOWN +)
176
177
 
177
178
  /**
178
179
  The view has been created, rendered and attached. It is currently
@@ -182,7 +183,16 @@ SC.CoreView.mixin(
182
183
  @static
183
184
  @constant
184
185
  */
185
- ATTACHED_HIDING: 0x03A2 // 930
186
+ ATTACHED_HIDING: 0x03C3, // 963 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_SHOWN +)
187
+
188
+ /**
189
+ The view has been created, rendered and attached, is visible in the
190
+ display and is being animated via a call to `animate()`.
191
+
192
+ @static
193
+ @constant
194
+ */
195
+ ATTACHED_SHOWN_ANIMATING: 0x03C6 // 966 (IS_CREATED + IS_RENDERED + IS_ATTACHED + IS_SHOWN +)
186
196
 
187
197
  });
188
198
 
@@ -219,7 +229,7 @@ SC.CoreView.reopen(
219
229
  //
220
230
 
221
231
  /* @private Internal variable used to store the number of children building out while we wait to be detached. */
222
- _buildingOutCount: null,
232
+ _sc_buildOutCount: null,
223
233
 
224
234
  /* @private Internal variable used to track the original view being detached that we are delaying so that we can build out. */
225
235
  _owningView: null,
@@ -245,7 +255,7 @@ SC.CoreView.reopen(
245
255
 
246
256
  * SC.CoreView.UNRENDERED
247
257
  * SC.CoreView.UNATTACHED
248
- * SC.CoreView.UNATTACHED_BY_PARENT
258
+ * SC.CoreView.ATTACHED_PARTIAL
249
259
  * SC.CoreView.ATTACHED_SHOWING
250
260
  * SC.CoreView.ATTACHED_SHOWN
251
261
  * SC.CoreView.ATTACHED_SHOWN_ANIMATING
@@ -263,9 +273,9 @@ SC.CoreView.reopen(
263
273
  viewState: SC.CoreView.UNRENDERED,
264
274
 
265
275
  /**
266
- Whether the view's layer is attached to the document or not.
276
+ Whether the view's layer is attached to a parent or not.
267
277
 
268
- When the view's layer is attached to the document, this value will be true.
278
+ When the view's layer is attached to a parent view, this value will be true.
269
279
 
270
280
  @field
271
281
  @type Boolean
@@ -273,8 +283,7 @@ SC.CoreView.reopen(
273
283
  @readonly
274
284
  */
275
285
  isAttached: function () {
276
- var state = this.get('viewState');
277
- return state & SC.CoreView.IS_ATTACHED;
286
+ return (this.get('viewState') & SC.CoreView.IS_ATTACHED) > 0;
278
287
  }.property('viewState').cacheable(),
279
288
 
280
289
  /** @private
@@ -290,7 +299,7 @@ SC.CoreView.reopen(
290
299
  */
291
300
  // NOTE: This property is of little value, so it's private in case we decide to toss it.
292
301
  _isRendered: function () {
293
- return this.get('viewState') !== SC.CoreView.UNRENDERED;
302
+ return (this.get('viewState') & SC.CoreView.IS_RENDERED) > 0;
294
303
  }.property('viewState').cacheable(),
295
304
 
296
305
  /**
@@ -312,10 +321,7 @@ SC.CoreView.reopen(
312
321
  @readonly
313
322
  */
314
323
  isVisibleInWindow: function () {
315
- var state = this.get('viewState');
316
- return state & SC.CoreView.IS_ATTACHED &&
317
- state !== SC.CoreView.ATTACHED_HIDDEN &&
318
- state !== SC.CoreView.ATTACHED_HIDDEN_BY_PARENT;
324
+ return( this.get('viewState') & SC.CoreView.IS_SHOWN) > 0;
319
325
  }.property('viewState').cacheable(),
320
326
 
321
327
 
@@ -329,7 +335,7 @@ SC.CoreView.reopen(
329
335
  handled = true;
330
336
 
331
337
  //@if (debug)
332
- if (SC.LOG_VIEW_STATES) {
338
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
333
339
  SC.Logger.log('%c%@ — _doAdopt(%@, %@)'.fmt(this, parentView, beforeView), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
334
340
  }
335
341
  //@endif
@@ -353,11 +359,11 @@ SC.CoreView.reopen(
353
359
  parentViewState = parentView.get('viewState'),
354
360
  parentNode, nextNode, nextView, siblings;
355
361
 
356
- // Notify *will* (top-down from parent to children).
362
+ // Notify that the child view will be added to the parent view.
357
363
  if (parentView.willAddChild) { parentView.willAddChild(this, beforeView); }
358
364
  if (this.willAddToParent) { this.willAddToParent(parentView, beforeView); }
359
365
 
360
- // Set parentView.
366
+ // Set the parentView.
361
367
  this.set('parentView', parentView);
362
368
 
363
369
  // Add to the new parent's childViews array.
@@ -369,9 +375,10 @@ SC.CoreView.reopen(
369
375
  // Pass the current designMode to the view (and its children).
370
376
  this.updateDesignMode(this.get('designMode'), parentView.get('designMode'));
371
377
 
372
- // Notify adopted (on self and all child views).
373
- this._adopted();
378
+ // Notify adopted.
379
+ this._adopted(beforeView);
374
380
 
381
+ // When a view is adopted, it should go to the same state as its new parent.
375
382
  switch (this.get('viewState')) {
376
383
  case SC.CoreView.UNRENDERED:
377
384
  switch (parentViewState) {
@@ -412,10 +419,6 @@ SC.CoreView.reopen(
412
419
  this._doAttach(parentNode, nextNode);
413
420
  }
414
421
  }
415
-
416
- // Notify *did* (bottom-up from children to parent).
417
- if (this.didAddToParent) { this.didAddToParent(parentView, beforeView); }
418
- if (parentView.didAddChild) { parentView.didAddChild(this, beforeView); }
419
422
  } else {
420
423
  handled = false;
421
424
  }
@@ -431,7 +434,7 @@ SC.CoreView.reopen(
431
434
  isHandled = false;
432
435
 
433
436
  //@if (debug)
434
- if (SC.LOG_VIEW_STATES) {
437
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
435
438
  SC.Logger.log('%c%@ — _doAttach(%@, %@)'.fmt(this, parentNode, nextNode), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
436
439
  }
437
440
  //@endif
@@ -444,23 +447,23 @@ SC.CoreView.reopen(
444
447
 
445
448
  this._executeQueuedUpdates();
446
449
 
447
- // Attach to parentNode
450
+ // Attach to parentNode.
448
451
  // IE doesn't support insertBefore(blah, undefined) in version IE9.
449
452
  parentNode.insertBefore(node, nextNode || null);
450
453
 
451
454
  parentView = this.get('parentView');
452
455
  if (!parentView || (parentView && parentView.get('isAttached'))) {
453
- // Update states after *will* and before *did* notifications!
454
- this._routeOnAttached();
455
-
456
- // Give child views a chance to notify and update state.
457
- this._callOnChildViews('_parentDidAppendToDocument');
456
+ // Attach the view.
457
+ this._executeDoAttach();
458
458
 
459
- // Notify *did* (bottom-up from children to parent).
460
- this._notifyDidAttach();
459
+ // If there is a transition in, run it.
460
+ if (transitionIn) {
461
+ this._transitionIn(false);
462
+ }
461
463
  } else {
462
- // Update states after *will* and before *did* notifications!
463
- this._gotoUnattachedByParentState();
464
+ // Attaching an unattached view to an unattached view, simply moves it to unattached by
465
+ // parent state. Don't do any notifications.
466
+ this._gotoAttachedPartialState();
464
467
  }
465
468
 
466
469
  isHandled = true;
@@ -468,30 +471,29 @@ SC.CoreView.reopen(
468
471
 
469
472
  // Special case: view switched from building out to building in.
470
473
  case SC.CoreView.ATTACHED_BUILDING_OUT:
471
- // If already building out, we need to cancel and possibly build in.
474
+ // If already building out, we need to cancel and possibly build in. Top-down so that any
475
+ // children that are hidden or building out on their own allow us to bail out early.
472
476
  this._callOnChildViews('_parentDidCancelBuildOut');
473
477
 
474
478
  // Remove the shared building out count if it exists.
475
- this._buildingOutCount = null;
479
+ this._sc_buildOutCount = null;
476
480
 
477
481
  // Note: We can be in ATTACHED_BUILDING_OUT state without a transition out while we wait for child views.
478
- // Update states after *will* and before *did* notifications!
479
482
  if (this.get('transitionOut')) {
480
- if (transitionIn) {
481
- // this.invokeNext(function () {
482
- this._transitionIn();
483
- // });
483
+ // Cancel the building out transition (in place if we are going to switch to transitioning back in).
484
+ this.cancelAnimation(transitionIn ? SC.LayoutState.CURRENT : undefined);
484
485
 
485
- this._gotoAttachedBuildingInState();
486
- } else {
487
- // Update state first!
488
- this._gotoAttachedShownState();
486
+ // Set the proper state.
487
+ this._gotoAttachedShownState();
489
488
 
490
- this._cancelTransition();
489
+ if (transitionIn) {
490
+ this._transitionIn(true);
491
491
  }
492
+
493
+ // Waiting for child view transition outs.
492
494
  } else {
493
495
 
494
- // Route.
496
+ // Set the proper state.
495
497
  this._gotoAttachedShownState();
496
498
  }
497
499
 
@@ -518,7 +520,7 @@ SC.CoreView.reopen(
518
520
  }
519
521
  //@endif
520
522
  break;
521
- case SC.CoreView.UNATTACHED_BY_PARENT:
523
+ case SC.CoreView.ATTACHED_PARTIAL:
522
524
  //@if(debug)
523
525
  SC.warn("Developer Warning: You can not attach the child view, %@, directly.".fmt(this));
524
526
  //@endif
@@ -534,7 +536,7 @@ SC.CoreView.reopen(
534
536
  isHandled = false;
535
537
 
536
538
  //@if (debug)
537
- if (SC.LOG_VIEW_STATES) {
539
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
538
540
  SC.Logger.log('%c%@ — _doDestroyLayer()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
539
541
  }
540
542
  //@endif
@@ -551,24 +553,17 @@ SC.CoreView.reopen(
551
553
  case SC.CoreView.ATTACHED_SHOWING:
552
554
  case SC.CoreView.ATTACHED_SHOWN:
553
555
  case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
554
- case SC.CoreView.UNATTACHED_BY_PARENT:
555
556
  case SC.CoreView.ATTACHED_BUILDING_OUT:
557
+ case SC.CoreView.ATTACHED_PARTIAL:
556
558
  break;
557
559
 
558
560
  // Normal case (SC.CoreView.UNATTACHED): view is rendered and its layer is being destroyed.
559
561
  default:
560
- // Notify *will* (top-down from parent to children).
561
- this._notifyWillDestroyLayer();
562
- this._callOnChildViews('_notifyWillDestroyLayer');
563
-
564
- // Remove our reference to the layer (our self and all our child views).
565
- this._executeDoDestroyLayer();
566
- this._callOnChildViews('_executeDoDestroyLayer');
567
-
568
- // UNUSED.
569
- // Notify *did* (bottom-up from children to parent).
570
- // this._callOnChildViews('_notifyDidDestroyLayer');
571
- // this._notifyDidDestroyLayer();
562
+ // Notify that the layer will be destroyed. Bottom-up so that each child is in the proper
563
+ // state before its parent potentially alters its state. For example, a parent could modify
564
+ // children in `willDestroyLayer`.
565
+ this._callOnChildViews('_teardownLayer', false);
566
+ this._teardownLayer();
572
567
 
573
568
  isHandled = true;
574
569
  }
@@ -580,83 +575,109 @@ SC.CoreView.reopen(
580
575
  _doDetach: function (immediately) {
581
576
  var state = this.get('viewState'),
582
577
  transitionOut = this.get('transitionOut'),
583
- inPlace = false,
584
- isHandled = true;
578
+ shouldHandle = true;
585
579
 
586
580
  //@if (debug)
587
- if (SC.LOG_VIEW_STATES) {
581
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
588
582
  SC.Logger.log('%c%@ — _doDetach()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
589
583
  }
590
584
  //@endif
591
585
 
586
+ // Handle all 12 possible view states.
592
587
  switch (state) {
593
588
 
594
- // Normal case: Attached visible view being detached.
589
+ // Scenario: The view is shown.
590
+ // Result: Allow the view and/or any of its child views to build out or else execute the detach.
595
591
  case SC.CoreView.ATTACHED_SHOWN:
592
+ this._executeDoBuildOut(immediately);
593
+
596
594
  break;
597
595
 
598
- // Normal case: Attached non-visible view being detached.
599
- case SC.CoreView.UNATTACHED_BY_PARENT:
596
+ // Scenario: The view is attached but isn't visible (possibly because an ancestor is detached or hidden).
597
+ // Result: Detach the view immediately.
598
+ case SC.CoreView.ATTACHED_PARTIAL:
600
599
  case SC.CoreView.ATTACHED_HIDDEN:
601
600
  case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT:
602
- // No need to transition out, since we're hidden.
603
- immediately = true;
601
+ // Detach immediately.
602
+ this._executeDoDetach();
603
+
604
604
  break;
605
605
 
606
- // Near normal case: Attached visible view that is in the middle of an animation.
607
- case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
606
+ // Scenario: The view is in the middle of a hiding transition.
607
+ // Result: Cancel the animation and then run as normal.
608
+ case SC.CoreView.ATTACHED_HIDING:
609
+ // Cancel the animation (in the future we will be able to let it run out while building out).
608
610
  this.cancelAnimation();
611
+
612
+ // Set the proper state.
613
+ this._gotoAttachedHiddenState();
614
+
615
+ // Detach immediately.
616
+ this._executeDoDetach();
617
+
609
618
  break;
610
619
 
611
- // Near normal case: Attached showing view. We cancel the incoming animation
612
- // rather than swapping to a build out (difficult to get right, because we lose track of the correct final layout).
620
+ // Scenario: The view is in the middle of an animation or showing transition.
621
+ // Result: Cancel the animation and then run as normal.
613
622
  case SC.CoreView.ATTACHED_SHOWING:
614
- this.cancelAnimation(); // Fires didTransitionIn callback (state changes to ATTACHED_SHOWN/notifications sent).
615
- break;
623
+ case SC.CoreView.ATTACHED_SHOWN_ANIMATING: // TODO: We need concurrent states!
624
+ // Cancel the animation (in the future we will be able to let it run out while building out).
625
+ this.cancelAnimation();
616
626
 
617
- // Near normal case: Attached hiding view. We cancel the outgoing animation
618
- // rather than swapping to a build out (difficult to get right, because we lose track of the correct final layout).
619
- case SC.CoreView.ATTACHED_HIDING:
620
- this.cancelAnimation(); // Fires didTransitionOut callback (state changes to ATTACHED_HIDDEN/notifications sent).
627
+ // Set the proper state.
628
+ this._gotoAttachedShownState();
629
+
630
+ this._executeDoBuildOut(immediately);
621
631
 
622
- // No need to transition out, since we're hidden.
623
- immediately = true;
624
632
  break;
625
633
 
626
- // Near normal case: Attached building in view. We cancel the incoming
627
- // animation and build out the view in place.
634
+ // Scenario: The view is building in.
635
+ // Result: If it has a build out transition, swap to it. Otherwise, cancel.
628
636
  case SC.CoreView.ATTACHED_BUILDING_IN:
629
- if (immediately || !transitionOut) {
630
- this.cancelAnimation(); // Fires didTransitionIn callback (state changes to ATTACHED_SHOWN/notifications sent).
631
- } else {
632
- // Set the state manually so the callback doesn't do clean up and notify.
633
- this._gotoAttachedShownState();
637
+ // Cancel the build in transition.
638
+ if (transitionOut) {
639
+ //@if (debug)
640
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
641
+ SC.Logger.log('%c — cancelling build in in place'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
642
+ }
643
+ //@endif
634
644
 
635
- // Cancel the animation in place (setup properties still exist and will be cleared by transitionOut)
636
- this.cancelAnimation(SC.LayoutState.CURRENT); // Fires didTransitionIn callback (no state change/no notifications).
645
+ this.cancelAnimation(SC.LayoutState.CURRENT);
646
+ } else {
647
+ //@if (debug)
648
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
649
+ SC.Logger.log('%c — cancelling build in outright'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
650
+ }
651
+ //@endif
637
652
 
638
- // Transition out in place.
639
- inPlace = true;
653
+ this.cancelAnimation();
640
654
  }
655
+
656
+ // Set the proper state.
657
+ this._gotoAttachedShownState();
658
+
659
+ // Build out in place.
660
+ this._executeDoBuildOut(immediately, true);
641
661
  break;
642
662
 
643
- // Special case: Already building out, because parent is building out. Stop
644
- // the transition in place so that it can continue in place on its own.
645
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT: // FAST PATH!
646
- // Note: *will* detach notice already sent.
663
+ // Scenario: View is already building out because of an ancestor.
664
+ // Result: Stop the transition so that it can continue in place on its own.
665
+ case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
666
+ // Cancel the build out transition.
647
667
  this.cancelAnimation(SC.LayoutState.CURRENT); // Fires didTransitionOut callback (necessary to clean up parent view build out wait)
648
668
 
649
- // Switch state to regular state (the view should only have been able to get to ATTACHED_BUILDING_OUT_BY_PARENT from ATTACHED_SHOWN).
669
+ // Set the proper state. (the view should only have been able to get to ATTACHED_BUILDING_OUT_BY_PARENT from ATTACHED_SHOWN).
650
670
  this._gotoAttachedShownState();
651
671
 
652
672
  // TODO: Grab the build out count for all child views of this view. What a nightmare for an edge case!
653
673
 
654
- // Transition out in place.
655
- inPlace = true;
674
+ // Build out in place.
675
+ this._executeDoBuildOut(immediately, true);
656
676
 
657
677
  break;
658
678
 
659
- // Special case: Already building out. Fast path!
679
+ // Scenario: View is already building out.
680
+ // Result: Stop if forced to.
660
681
  case SC.CoreView.ATTACHED_BUILDING_OUT:
661
682
  // If immediately is passed, cancel the build out prematurely.
662
683
  if (immediately) {
@@ -667,129 +688,120 @@ SC.CoreView.reopen(
667
688
  this._executeDoDetach();
668
689
  }
669
690
 
670
- // Don't try to notify or run transition out code again.
671
- return true;
672
-
673
- // Invalid states that have no effect. Fast path!
674
- case SC.CoreView.UNRENDERED:
675
- case SC.CoreView.UNATTACHED:
676
- return false;
677
- }
678
-
679
- // Notify *will* (top-down from parent to children). The children will be
680
- // notified only when they are actually about to be removed.
681
- // this._notifyWillDetach();
682
-
683
- if (immediately) {
684
- // Detach immediately.
685
- this._executeDoDetach();
686
- } else {
687
- // In order to allow the removal of a parent to be delayed by children's
688
- // transitions, we track which views are building out and finish
689
- // only when they're all done.
690
- this._buildingOutCount = 0;
691
-
692
- // Tell all the child views so that any with a transitionOut may run it.
693
- this._callOnChildViews('_parentWillBuildOutFromDocument', this);
694
-
695
- if (transitionOut) {
696
- // this.invokeNext(function () {
697
- this._transitionOut(inPlace, this);
698
- // });
691
+ break;
699
692
 
700
- // Update states after *will* and before *did* notifications!
701
- this._gotoAttachedBuildingOutState();
702
- } else if (this._buildingOutCount > 0) {
703
- // Some children are building out, we will have to wait for them.
704
- this._gotoAttachedBuildingOutState();
705
- } else {
706
- this._buildingOutCount = null;
693
+ // Invalid states.
694
+ default:
695
+ //@if(debug)
696
+ // Add some debugging only warnings for if the view statechart code is being improperly used.
697
+ // Telling the view to detach when it is already detached isn't correct: UNRENDERED, UNATTACHED
698
+ SC.warn("Core Developer Warning: Found invalid state for view, %@, in _doDetach".fmt(this));
699
+ //@endif
707
700
 
708
- // Detach immediately.
709
- this._executeDoDetach();
710
- }
701
+ shouldHandle = false;
711
702
  }
712
703
 
713
- return isHandled;
704
+ return shouldHandle;
714
705
  },
715
706
 
716
707
  /** @private Hide this view action. */
717
708
  _doHide: function () {
718
709
  var state = this.get('viewState'),
719
- transitionHide = this.get('transitionHide');
710
+ transitionHide = this.get('transitionHide'),
711
+ shouldHandle = true;
720
712
 
721
713
  //@if (debug)
722
- if (SC.LOG_VIEW_STATES) {
714
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
723
715
  SC.Logger.log('%c%@ — _doHide()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
724
716
  }
725
717
  //@endif
726
718
 
719
+ // Handle all 12 possible view states.
727
720
  switch (state) {
728
- case SC.CoreView.UNRENDERED: // FAST PATH!
729
- case SC.CoreView.ATTACHED_HIDDEN: // FAST PATH!
730
- case SC.CoreView.ATTACHED_HIDING: // FAST PATH!
731
- return false;
732
- case SC.CoreView.UNATTACHED: // FAST PATH!
733
- case SC.CoreView.UNATTACHED_BY_PARENT: // FAST PATH!
734
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT: // FAST PATH!
735
- case SC.CoreView.ATTACHED_BUILDING_OUT: // FAST PATH!
736
- // Queue the visibility update for the next time we display.
737
- this._visibleStyleNeedsUpdate = true;
738
721
 
739
- return true;
740
- case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT: // FAST PATH!
741
- // Note that visibility update is NOT conditional for this state.
742
- this._doUpdateVisibleStyle();
722
+ // Scenario: The view is shown.
723
+ // Result: Notify that the view will hide and then either hide or run hide transition.
724
+ case SC.CoreView.ATTACHED_SHOWN:
725
+ case SC.CoreView.ATTACHED_BUILDING_IN:
726
+ case SC.CoreView.ATTACHED_BUILDING_OUT:
727
+ case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
728
+ case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
729
+ // ATTACHED_HIDDEN_BY_PARENT, ATTACHED_BUILDING_IN, ATTACHED_BUILDING_OUT_BY_PARENT, ATTACHED_BUILDING_OUT
743
730
 
744
- // Update states after *will* and before *did* notifications!
745
- this._gotoAttachedHiddenState();
731
+ // TODO: How do we check for conflicts in the hide transition against other concurrent transitions/animations?
732
+ if (transitionHide) {
733
+ // this.invokeNext(function () {
734
+ this._transitionHide();
735
+ // });
736
+ } else {
737
+ // Hide the view.
738
+ this._executeDoHide();
739
+ }
746
740
 
747
- return true;
748
- case SC.CoreView.ATTACHED_BUILDING_IN:
749
- case SC.CoreView.ATTACHED_SHOWING:
750
- // Cancel the animation and revert to hidden.
751
- this.cancelAnimation();
752
- this._teardownTransition();
753
- this._gotoAttachedHiddenState();
754
741
  break;
755
742
 
756
- // Near normal case: Attached visible view that is in the middle of an animation.
757
- case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
758
- this.cancelAnimation();
759
- break;
743
+ // Scenario: The view was showing at the time it was told to hide.
744
+ // Result: Cancel the animation.
745
+ case SC.CoreView.ATTACHED_SHOWING:
746
+ // Cancel the showing transition.
747
+ if (transitionHide) {
748
+ this.cancelAnimation(SC.LayoutState.CURRENT);
749
+ } else {
750
+ this.cancelAnimation();
751
+ }
760
752
 
761
- case SC.CoreView.ATTACHED_SHOWN:
762
- break;
763
- default:
764
- }
753
+ // Set the proper state.
754
+ this._gotoAttachedShownState();
765
755
 
766
- // Notify *will* (top-down from parent to children).
767
- if (this.willHideInDocument) { this.willHideInDocument(); }
756
+ // Hide the view.
757
+ if (transitionHide) {
758
+ this._transitionHide(true);
759
+ } else {
760
+ this._executeDoHide();
761
+ }
768
762
 
769
- if (transitionHide) {
770
- // Update states after *will* and before *did* notifications!
771
- this._gotoAttachedHidingState();
763
+ break;
772
764
 
773
- // this.invokeNext(function () {
774
- this._transitionHide();
775
- // });
765
+ // Scenario: The view is rendered but is not attached.
766
+ // Result: Queue an update to the visibility style.
767
+ case SC.CoreView.UNATTACHED:
768
+ case SC.CoreView.ATTACHED_PARTIAL:
769
+ // Queue the visibility update for the next time we display.
770
+ this._visibleStyleNeedsUpdate = true;
776
771
 
777
- } else {
778
- // Clear out any child views that are still transitioning before we hide.
779
- this._callOnChildViews('_parentWillHideInDocument');
772
+ break;
773
+
774
+ // Scenario: The view is not even rendered.
775
+ // Result: Nothing is required.
776
+ case SC.CoreView.UNRENDERED:
777
+ shouldHandle = false;
778
+ break;
780
779
 
780
+ case SC.CoreView.ATTACHED_HIDDEN: // FAST PATH!
781
+ case SC.CoreView.ATTACHED_HIDING: // FAST PATH!
782
+ return false;
783
+ case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT: // FAST PATH!
781
784
  // Note that visibility update is NOT conditional for this state.
782
- this.invokeOnce(this._doUpdateVisibleStyle);
785
+ this._doUpdateVisibleStyle();
783
786
 
784
787
  // Update states after *will* and before *did* notifications!
785
788
  this._gotoAttachedHiddenState();
786
- this._callOnChildViews('_parentDidHideInDocument');
787
789
 
788
- // Notify *did* (bottom-up from children to parent).
789
- if (this.didHideInDocument) { this.didHideInDocument(); }
790
+ return true;
791
+
792
+ // Invalid states.
793
+ default:
794
+ //@if(debug)
795
+ // Add some debugging only warnings for if the view statechart code is being improperly used.
796
+ // Telling the view to hide when it is already hidden isn't correct:
797
+ //
798
+ SC.warn("Core Developer Warning: Found invalid state for view, %@, in _doHide".fmt(this));
799
+ //@endif
800
+
801
+ shouldHandle = false;
790
802
  }
791
803
 
792
- return true;
804
+ return shouldHandle;
793
805
  },
794
806
 
795
807
  /** @private Orphan this view action. */
@@ -798,7 +810,7 @@ SC.CoreView.reopen(
798
810
  handled = true;
799
811
 
800
812
  //@if (debug)
801
- if (SC.LOG_VIEW_STATES) {
813
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
802
814
  SC.Logger.log('%c%@ — _doOrphan()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
803
815
  }
804
816
  //@endif
@@ -824,41 +836,23 @@ SC.CoreView.reopen(
824
836
 
825
837
  /** @private Render this view action. */
826
838
  _doRender: function () {
827
- var state = this.get('viewState');
839
+ var state = this.get('viewState'),
840
+ shouldHandle = true;
828
841
 
829
842
  //@if (debug)
830
- if (SC.LOG_VIEW_STATES) {
843
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
831
844
  SC.Logger.log('%c%@ — _doRender()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
832
845
  }
833
846
  //@endif
834
847
 
848
+ // Handle all 12 possible view states.
835
849
  switch (state) {
836
- case SC.CoreView.ATTACHED_SHOWING: // FAST PATHS!
837
- case SC.CoreView.ATTACHED_SHOWN:
838
- case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
839
- case SC.CoreView.ATTACHED_HIDING:
840
- case SC.CoreView.ATTACHED_HIDDEN:
841
- case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT:
842
- case SC.CoreView.ATTACHED_BUILDING_IN:
843
- case SC.CoreView.ATTACHED_BUILDING_OUT:
844
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
845
- case SC.CoreView.UNATTACHED:
846
- case SC.CoreView.UNATTACHED_BY_PARENT:
847
- return false;
848
- case SC.CoreView.UNRENDERED:
849
- // Render the layer.
850
- var context = this.renderContext(this.get('tagName'));
851
850
 
852
- this.renderToContext(context);
853
- this.set('layer', context.element());
854
-
855
- // Update states after *will* and before *did* notifications!
856
- this._gotoUnattachedState();
857
- this._callOnChildViews('_gotoUnattachedByParentState');
858
-
859
- // Notify *did* (top-down from parent to children).
860
- this._rendered();
861
- this._callOnChildViews('_rendered');
851
+ // Scenario: The view is not rendered.
852
+ // Result: Render the layer and then notify.
853
+ case SC.CoreView.UNRENDERED:
854
+ // Render the view.
855
+ this._executeDoRender();
862
856
 
863
857
  // Bypass the unattached state for adopted views.
864
858
  var parentView = this.get('parentView');
@@ -874,93 +868,126 @@ SC.CoreView.reopen(
874
868
  this._doAttach(parentNode, nextNode);
875
869
  }
876
870
 
877
- return true;
871
+ break;
872
+
873
+ // Invalid states.
874
+ default:
875
+ //@if(debug)
876
+ // Add some debugging only warnings for if the view statechart code is being improperly used.
877
+ // All other states should be impossible if parent was UNATTACHED:
878
+ // ATTACHED_SHOWING, ATTACHED_SHOWN, ATTACHED_SHOWN_ANIMATING, ATTACHED_HIDING, ATTACHED_HIDDEN, ATTACHED_HIDDEN_BY_PARENT, ATTACHED_BUILDING_IN, ATTACHED_BUILDING_OUT, ATTACHED_BUILDING_OUT_BY_PARENT, UNATTACHED, ATTACHED_PARTIAL
879
+ SC.warn("Core Developer Warning: Found invalid state for view, %@, in _doRender".fmt(this));
880
+ //@endif
881
+ shouldHandle = false;
878
882
  }
883
+
884
+ return shouldHandle;
879
885
  },
880
886
 
881
887
  /** @private Show this view action. */
882
888
  _doShow: function () {
883
889
  var state = this.get('viewState'),
884
- parentView = this.get('parentView'),
885
- // Views without a parent are not limited by a parent's current state.
886
- isParentShown = parentView ? parentView.get('viewState') & SC.CoreView.IS_SHOWN : true,
887
- transitionShow = this.get('transitionShow');
890
+ transitionShow = this.get('transitionShow'),
891
+ shouldHandle = true;
888
892
 
889
893
  //@if (debug)
890
- if (SC.LOG_VIEW_STATES) {
894
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
891
895
  SC.Logger.log('%c%@ — _doShow()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
892
896
  }
893
897
  //@endif
894
898
 
899
+ // Handle all 12 possible view states.
895
900
  switch (state) {
896
901
 
897
- // Normal case: view is hidden and is being shown.
902
+ // Scenario: The view is hidden.
903
+ // Result: Depends on whether the parent view is shown or hidden by an ancestor.
898
904
  case SC.CoreView.ATTACHED_HIDDEN:
905
+ var parentView = this.get('parentView'),
906
+ // Views without a parent are not limited by a parent's current state.
907
+ isParentShown = parentView ? parentView.get('viewState') & SC.CoreView.IS_SHOWN : true;
908
+
909
+ // Scenario: The view is hidden and its ancestors are all visible.
910
+ // Result: Notify that the view and relevant child views will be shown.
899
911
  if (isParentShown) {
900
- // Update before showing (note that visibility update is NOT conditional for this state).
901
- this._doUpdateVisibleStyle();
912
+ var notifyStack = []; // Only those views that changed state get added to the stack.
913
+
914
+ // Run any queued updates.
915
+ this._executeQueuedUpdates();
916
+
917
+ // The children are updated top-down so that hidden or unattached children allow us to bail out early.
918
+ this._callOnChildViews('_parentWillShowInDocument', true, notifyStack);
919
+
920
+ // Notify for each child (that will change state) in reverse so that each child is in the proper
921
+ // state before its parent potentially alters its state. For example, a parent could modify
922
+ // children in `willShowInDocument`.
923
+ for (var i = notifyStack.length - 1; i >= 0; i--) {
924
+ var childView = notifyStack[i];
925
+
926
+ childView._notifyWillShowInDocument();
927
+ }
928
+ this._notifyWillShowInDocument();
929
+
930
+ // Show the view.
931
+ this._executeDoShow();
932
+ if (transitionShow) {
933
+ this._transitionShow(false);
934
+ }
902
935
 
903
- // Notify *will* (top-down from parent to children).
904
- this._callOnChildViews('_parentWillShowInDocument');
905
- if (this.willShowInDocument) { this.willShowInDocument(); }
936
+ // Scenario: The view is hidden, but one of its ancestors is also hidden.
937
+ // Result: Track that the visible style needs update and go to hidden by parent state.
906
938
  } else {
907
939
  // Queue the visibility update for the next time we display.
908
940
  this._visibleStyleNeedsUpdate = true;
909
941
 
910
- // Update states after *will* and before *did* notifications!
942
+ // Set the proper state.
911
943
  this._gotoAttachedHiddenByParentState();
912
-
913
- return true;
914
944
  }
945
+
915
946
  break;
916
947
 
948
+ // Scenario: The view was hiding at the time it was told to show.
949
+ // Result: Revert or reverse the hiding transition.
917
950
  case SC.CoreView.ATTACHED_HIDING:
918
- // Cancel the animation and revert to shown.
919
- this.cancelAnimation();
920
- this._teardownTransition();
951
+ // Cancel the hiding transition (in place if we are going to switch to transitioning back in).
952
+ this.cancelAnimation(transitionShow ? SC.LayoutState.CURRENT : SC.LayoutState.START);
953
+
954
+ // Set the proper state.
921
955
  this._gotoAttachedShownState();
956
+
957
+ if (transitionShow) {
958
+ this._transitionShow(true);
959
+ }
960
+
922
961
  break;
923
962
 
924
- // Special case: Layer exists but is not attached. Queue an update to the visibility style.
963
+ // Scenario: The view is rendered but is not attached.
964
+ // Result: Queue an update to the visibility style.
925
965
  case SC.CoreView.UNATTACHED:
926
- case SC.CoreView.UNATTACHED_BY_PARENT:
966
+ case SC.CoreView.ATTACHED_PARTIAL:
927
967
  // Queue the visibility update for the next time we display.
928
968
  this._visibleStyleNeedsUpdate = true;
929
- return true;
930
-
931
- // Invalid states that have no effect.
932
- case SC.CoreView.UNRENDERED: // FAST PATH!
933
- case SC.CoreView.ATTACHED_SHOWN: // FAST PATH!
934
- case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
935
- case SC.CoreView.ATTACHED_SHOWING: // FAST PATH!
936
- case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT: // FAST PATH!
937
- case SC.CoreView.ATTACHED_BUILDING_IN: // FAST PATH!
938
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT: // FAST PATH!
939
- case SC.CoreView.ATTACHED_BUILDING_OUT: // FAST PATH!
940
- return false;
941
-
942
- default:
943
- }
944
969
 
945
- this._executeQueuedUpdates();
970
+ break;
946
971
 
947
- if (transitionShow) {
948
- // Update states after *will* and before *did* notifications!
949
- this._gotoAttachedShowingState();
972
+ // Scenario: The view is not even rendered.
973
+ // Result: Nothing is required.
974
+ case SC.CoreView.UNRENDERED:
975
+ shouldHandle = false;
976
+ break;
950
977
 
951
- // this.invokeNext(function () {
952
- this._transitionShow();
953
- // });
954
- } else {
955
- // Update states after *will* and before *did* notifications!
956
- this._gotoAttachedShownState();
978
+ // Invalid states.
979
+ default:
980
+ //@if(debug)
981
+ // Add some debugging only warnings for if the view statechart code is being improperly used.
982
+ // Telling the view to show when it is already visible isn't correct:
983
+ // ATTACHED_SHOWN, ATTACHED_SHOWN_ANIMATING, ATTACHED_SHOWING, ATTACHED_HIDDEN_BY_PARENT, ATTACHED_BUILDING_IN, ATTACHED_BUILDING_OUT_BY_PARENT, ATTACHED_BUILDING_OUT
984
+ SC.warn("Core Developer Warning: Found invalid state for view, %@, in _doShow".fmt(this));
985
+ //@endif
957
986
 
958
- // Notify *did* (bottom-up from children to parent).
959
- if (this.didShowInDocument) { this.didShowInDocument(); }
960
- this._callOnChildViews('_parentDidShowInDocument');
987
+ shouldHandle = false;
961
988
  }
962
989
 
963
- return true;
990
+ return shouldHandle;
964
991
  },
965
992
 
966
993
  /** @private Update this view's contents action. */
@@ -969,7 +996,7 @@ SC.CoreView.reopen(
969
996
  handled = true;
970
997
 
971
998
  //@if (debug)
972
- if (SC.LOG_VIEW_STATES) {
999
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
973
1000
  SC.Logger.log('%c%@ — _doUpdateContent(%@)'.fmt(this, force), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
974
1001
  }
975
1002
  //@endif
@@ -1005,7 +1032,7 @@ SC.CoreView.reopen(
1005
1032
  var state = this.get('viewState');
1006
1033
 
1007
1034
  //@if (debug)
1008
- if (SC.LOG_VIEW_STATES) {
1035
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
1009
1036
  SC.Logger.log('%c%@ — didTransitionIn()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
1010
1037
  }
1011
1038
  //@endif
@@ -1014,14 +1041,8 @@ SC.CoreView.reopen(
1014
1041
  state === SC.CoreView.ATTACHED_BUILDING_IN) {
1015
1042
  this._teardownTransition();
1016
1043
 
1017
- // Update states after *will* and before *did* notifications!
1044
+ // Set the proper state.
1018
1045
  this._gotoAttachedShownState();
1019
-
1020
- // Notify *did* (bottom-up from children to parent).
1021
- if (this.didShowInDocument) { this.didShowInDocument(); }
1022
- // if (state === SC.CoreView.ATTACHED_SHOWING) {
1023
- // this._callOnChildViews('_parentDidShowInDocument');
1024
- // }
1025
1046
  }
1026
1047
  },
1027
1048
 
@@ -1037,7 +1058,7 @@ SC.CoreView.reopen(
1037
1058
  var state = this.get('viewState');
1038
1059
 
1039
1060
  //@if (debug)
1040
- if (SC.LOG_VIEW_STATES) {
1061
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
1041
1062
  SC.Logger.log('%c%@ — didTransitionOut()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
1042
1063
  }
1043
1064
  //@endif
@@ -1050,9 +1071,9 @@ SC.CoreView.reopen(
1050
1071
  var owningView = this._owningView;
1051
1072
  // We can't clean up the transition until the parent is done. For
1052
1073
  // example, a fast child build out inside of a slow parent build out.
1053
- owningView._buildingOutCount--;
1074
+ owningView._sc_buildOutCount--;
1054
1075
 
1055
- if (owningView._buildingOutCount === 0) {
1076
+ if (owningView._sc_buildOutCount === 0) {
1056
1077
  owningView._executeDoDetach();
1057
1078
 
1058
1079
  // Clean up.
@@ -1061,80 +1082,36 @@ SC.CoreView.reopen(
1061
1082
  } else if (state === SC.CoreView.ATTACHED_HIDING) {
1062
1083
  this._teardownTransition();
1063
1084
 
1064
- // Notify *will* (top-down from parent to children).
1065
- this._callOnChildViews('_parentWillHideInDocument');
1066
-
1067
- // Note that visibility update is NOT conditional for this state.
1068
- this._doUpdateVisibleStyle();
1069
-
1070
- // Update states after *will* and before *did* notifications!
1071
- this._gotoAttachedHiddenState();
1072
-
1073
- // Notify *did* (bottom-up from children to parent).
1074
- this._callOnChildViews('_parentDidHideInDocument');
1075
- if (this.didHideInDocument) { this.didHideInDocument(); }
1085
+ // Hide immediately.
1086
+ this._executeDoHide();
1076
1087
  }
1077
1088
  },
1078
1089
 
1079
1090
  /** @private The 'adopted' event. */
1080
- _adopted: function () {
1081
- // This has been moved to the _notifyDidAttach event.
1082
- // this.notifyPropertyChange('frame');
1091
+ _adopted: function (beforeView) {
1092
+ // Notify all of our descendents that our parent has changed. They will update their `pane` value
1093
+ // for one. Bottom-up in case a parent view modifies children when its pane changes for any
1094
+ // reason.
1095
+ this._callOnChildViews('_ancestorDidChangeParent', false);
1096
+
1097
+ // Notify that the child view has been added to the parent view.
1098
+ var parentView = this.get('parentView');
1099
+ if (this.didAddToParent) { this.didAddToParent(parentView, beforeView); }
1100
+ if (parentView.didAddChild) { parentView.didAddChild(this, beforeView); }
1083
1101
  },
1084
1102
 
1085
1103
  /** @private The 'orphaned' event. */
1086
1104
  _orphaned: function (oldParentView) {
1087
- // Notify.
1088
- if (oldParentView.didRemoveChild) { oldParentView.didRemoveChild(this); }
1089
- if (this.didRemoveFromParent) { this.didRemoveFromParent(oldParentView); }
1090
- },
1091
-
1092
- /** @private The 'rendered' event. */
1093
- _rendered: function () {
1094
- var displayProperties,
1095
- len, idx;
1096
-
1097
- // Register display property observers.
1098
- displayProperties = this.get('displayProperties');
1099
- for (idx = 0, len = displayProperties.length; idx < len; idx++) {
1100
- this.addObserver(displayProperties[idx], this, this.displayDidChange);
1105
+ // It's not necessary to send notice to destroyed views.
1106
+ if (!this.isDestroyed) {
1107
+ // Notify all of our descendents that our parent has changed. They will update their `pane` value
1108
+ // for one. Bottom-up in case a parent view modifies children when its pane changes for any
1109
+ // reason.
1110
+ this._callOnChildViews('_ancestorDidChangeParent', false);
1111
+
1112
+ if (oldParentView.didRemoveChild) { oldParentView.didRemoveChild(this); }
1113
+ if (this.didRemoveFromParent) { this.didRemoveFromParent(oldParentView); }
1101
1114
  }
1102
-
1103
- // Begin observing isVisible & isFirstResponder.
1104
- this.addObserver('isVisible', this, this._isVisibleDidChange);
1105
- this.addObserver('isFirstResponder', this, this._isFirstResponderDidChange);
1106
-
1107
- // TODO: we should be able to fix this with states
1108
- // if (this.get('useStaticLayout')) this.viewDidResize();
1109
-
1110
- // var childView, childViews = this.get('childViews');
1111
- // for (var i = childViews.length - 1; i >= 0; i--) {
1112
- // childView = childViews[i];
1113
-
1114
- // // We allow missing childViews in the array so ignore them.
1115
- // if (!childView) { continue; }
1116
-
1117
- // A parent view creating a layer might result in the creation of a
1118
- // child view's DOM node being created via a render context without
1119
- // createLayer() being invoked on the child. In such cases, if anyone
1120
- // had requested 'layer' and it was cached as null, we need to
1121
- // invalidate it.
1122
- // TODO: we should be able to fix this with states
1123
- // childView.notifyPropertyChange('layer');
1124
-
1125
- // A strange case, that a childView's frame won't be correct before
1126
- // we have a layer, if the childView doesn't have a fixed layout
1127
- // and we are using static layout.
1128
- // TODO: we should be able to fix this with states
1129
- // if (this.get('useStaticLayout')) {
1130
- // if (!childView.get('isFixedLayout')) { childView.viewDidResize(); }
1131
- // }
1132
-
1133
- // childView._rendered();
1134
- // }
1135
-
1136
- // Notify.
1137
- this._notifyDidRender();
1138
1115
  },
1139
1116
 
1140
1117
  // ------------------------------------------------------------------------
@@ -1143,67 +1120,56 @@ SC.CoreView.reopen(
1143
1120
 
1144
1121
  /** @private */
1145
1122
  _gotoAttachedBuildingInState: function () {
1146
- // Update the state.
1147
1123
  this.set('viewState', SC.CoreView.ATTACHED_BUILDING_IN);
1148
1124
  },
1149
1125
 
1150
1126
  /** @private */
1151
1127
  _gotoAttachedBuildingOutState: function () {
1152
- // Update the state.
1153
1128
  this.set('viewState', SC.CoreView.ATTACHED_BUILDING_OUT);
1154
1129
  },
1155
1130
 
1156
1131
  /** @private */
1157
1132
  _gotoAttachedBuildingOutByParentState: function () {
1158
- // Update the state.
1159
1133
  this.set('viewState', SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT);
1160
1134
  },
1161
1135
 
1162
1136
  /** @private */
1163
1137
  _gotoAttachedHiddenState: function () {
1164
- // Update the state.
1165
1138
  this.set('viewState', SC.CoreView.ATTACHED_HIDDEN);
1166
1139
  },
1167
1140
 
1168
1141
  /** @private */
1169
1142
  _gotoAttachedHiddenByParentState: function () {
1170
- // Update the state.
1171
1143
  this.set('viewState', SC.CoreView.ATTACHED_HIDDEN_BY_PARENT);
1172
1144
  },
1173
1145
 
1174
1146
  /** @private */
1175
1147
  _gotoAttachedHidingState: function () {
1176
- // Update the state.
1177
1148
  this.set('viewState', SC.CoreView.ATTACHED_HIDING);
1178
1149
  },
1179
1150
 
1180
1151
  /** @private */
1181
1152
  _gotoAttachedShowingState: function () {
1182
- // Update the state.
1183
1153
  this.set('viewState', SC.CoreView.ATTACHED_SHOWING);
1184
1154
  },
1185
1155
 
1186
1156
  /** @private */
1187
1157
  _gotoAttachedShownState: function () {
1188
- // Update the state.
1189
1158
  this.set('viewState', SC.CoreView.ATTACHED_SHOWN);
1190
1159
  },
1191
1160
 
1192
1161
  /** @private */
1193
1162
  _gotoUnattachedState: function () {
1194
- // Update the state.
1195
1163
  this.set('viewState', SC.CoreView.UNATTACHED);
1196
1164
  },
1197
1165
 
1198
1166
  /** @private */
1199
- _gotoUnattachedByParentState: function () {
1200
- // Update the state.
1201
- this.set('viewState', SC.CoreView.UNATTACHED_BY_PARENT);
1167
+ _gotoAttachedPartialState: function () {
1168
+ this.set('viewState', SC.CoreView.ATTACHED_PARTIAL);
1202
1169
  },
1203
1170
 
1204
1171
  /** @private */
1205
1172
  _gotoUnrenderedState: function () {
1206
- // Update the state.
1207
1173
  this.set('viewState', SC.CoreView.UNRENDERED);
1208
1174
  },
1209
1175
 
@@ -1211,12 +1177,34 @@ SC.CoreView.reopen(
1211
1177
  // Methods
1212
1178
  //
1213
1179
 
1214
- /** @private Clear building in transition. */
1215
- _cancelTransition: function () {
1216
- // Cancel conflicting transitions. This causes the animation callback to fire.
1217
- this.cancelAnimation();
1218
- // this._teardownTransition();
1219
- },
1180
+ /** @private Adds observers once a view has a layer. */
1181
+ _sc_addRenderedStateObservers: function () {
1182
+ var displayProperties,
1183
+ len, idx;
1184
+
1185
+ // Register display property observers.
1186
+ displayProperties = this.get('displayProperties');
1187
+ for (idx = 0, len = displayProperties.length; idx < len; idx++) {
1188
+ this.addObserver(displayProperties[idx], this, this.displayDidChange);
1189
+ }
1190
+
1191
+ // Begin observing isVisible & isFirstResponder.
1192
+ this.addObserver('isVisible', this, this._isVisibleDidChange);
1193
+ this.addObserver('isFirstResponder', this, this._isFirstResponderDidChange);
1194
+ },
1195
+
1196
+ /** @private Called when an ancestor's parent changed. */
1197
+ _ancestorDidChangeParent: function () {
1198
+ // When an ancestor changes, the pane may have changed.
1199
+ this.notifyPropertyChange('pane');
1200
+ },
1201
+
1202
+ /** @private Clear building in transition. */
1203
+ _cancelTransition: function () {
1204
+ // Cancel conflicting transitions. This causes the animation callback to fire.
1205
+ this.cancelAnimation();
1206
+ // this._teardownTransition();
1207
+ },
1220
1208
 
1221
1209
  /** @private */
1222
1210
  _doUpdateVisibleStyle: function () {
@@ -1230,13 +1218,12 @@ SC.CoreView.reopen(
1230
1218
  },
1231
1219
 
1232
1220
  /** @private Destroys the layer and updates the state. */
1233
- _executeDoDestroyLayer: function () {
1221
+ _teardownLayer: function () {
1222
+ this._notifyWillDestroyLayer();
1223
+
1234
1224
  var displayProperties,
1235
1225
  idx, len;
1236
1226
 
1237
- // Remove the layer reference.
1238
- this.set('layer', null);
1239
-
1240
1227
  // Unregister display property observers.
1241
1228
  displayProperties = this.get('displayProperties');
1242
1229
  for (idx = 0, len = displayProperties.length; idx < len; idx++) {
@@ -1247,26 +1234,203 @@ SC.CoreView.reopen(
1247
1234
  this.removeObserver('isVisible', this, this._isVisibleDidChange);
1248
1235
  this.removeObserver('isFirstResponder', this, this._isFirstResponderDidChange);
1249
1236
 
1237
+ // Remove the layer reference.
1238
+ this.set('layer', null);
1239
+
1250
1240
  // Update states after *will* and before *did* notifications!
1251
1241
  this._gotoUnrenderedState();
1252
1242
  },
1253
1243
 
1244
+ /** @private Attaches the view. */
1245
+ _executeDoAttach: function () {
1246
+ var notifyStack = []; // Only those views that changed state get added to the stack.
1247
+
1248
+ // Run any queued updates.
1249
+ this._executeQueuedUpdates();
1250
+
1251
+ // Update the state and children state. The children are updated top-down so that hidden or
1252
+ // unattached children allow us to bail out early.
1253
+ this._gotoSomeAttachedState();
1254
+ this._callOnChildViews('_parentDidAttach', true, notifyStack);
1255
+
1256
+ // Notify for each child (that changed state) in reverse so that each child is in the proper
1257
+ // state before its parent potentially alters its state. For example, a parent could modify
1258
+ // children in `didAppendToDocument`.
1259
+ for (var i = notifyStack.length - 1; i >= 0; i--) {
1260
+ var childView = notifyStack[i];
1261
+
1262
+ childView._notifyDidAttach();
1263
+ }
1264
+ this._notifyDidAttach();
1265
+ },
1266
+
1267
+ /** @private Builds out the view. */
1268
+ _executeDoBuildOut: function (immediately, inPlace) {
1269
+ if (immediately) {
1270
+ // Detach immediately.
1271
+ this._executeDoDetach();
1272
+ } else {
1273
+ // In order to allow the removal of a parent to be delayed by its children's transitions, we
1274
+ // track which views are building out and finish only when they're all done.
1275
+ this._sc_buildOutCount = 0;
1276
+
1277
+ // Tell all the child views so that any with a transitionOut may run it. Top-down so that
1278
+ // any hidden or already building out child views allow us to bail out early.
1279
+ this._callOnChildViews('_parentWillBuildOutFromDocument', true, this);
1280
+
1281
+ var transitionOut = this.get('transitionOut');
1282
+ if (transitionOut) {
1283
+ inPlace = inPlace || false;
1284
+ this._transitionOut(inPlace, this);
1285
+
1286
+ } else if (this._sc_buildOutCount > 0) {
1287
+ // Some children are building out, we will have to wait for them.
1288
+ this._gotoAttachedBuildingOutState();
1289
+ } else {
1290
+ this._sc_buildOutCount = null;
1291
+
1292
+ // Detach immediately.
1293
+ this._executeDoDetach();
1294
+ }
1295
+ }
1296
+ },
1297
+
1254
1298
  /** @private Detaches the view and updates the state. */
1255
1299
  _executeDoDetach: function () {
1256
- // Notify *will* (top-down from parent to children).
1300
+ var notifyStack = []; // Only those views that changed state get added to the stack.
1301
+
1302
+ // The children are updated top-down so that hidden or unattached children allow us to bail out early.
1303
+ this._callOnChildViews('_parentWillDetach', true, notifyStack);
1304
+
1305
+ // Notify for each child (that will change state) in reverse so that each child is in the proper
1306
+ // state before its parent potentially alters its state. For example, a parent could modify
1307
+ // children in `willRemoveFromDocument`.
1308
+ for (var i = notifyStack.length - 1; i >= 0; i--) {
1309
+ var childView = notifyStack[i];
1310
+
1311
+ childView._notifyWillDetach();
1312
+ }
1257
1313
  this._notifyWillDetach();
1258
- this._callOnChildViews('_parentWillRemoveFromDocument');
1314
+
1315
+ // Cancel any remaining animations (e.g. a concurrent hide).
1316
+ var viewState = this.get('viewState');
1317
+ switch (viewState) {
1318
+ case SC.CoreView.ATTACHED_HIDING:
1319
+ case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
1320
+ this.cancelAnimation();
1321
+ break;
1322
+ }
1259
1323
 
1260
1324
  // Detach the layer.
1261
1325
  var node = this.get('layer');
1262
1326
  node.parentNode.removeChild(node);
1263
1327
 
1264
- // Update states after *will* and before *did* notifications!
1328
+ // Update the state and children state. The children are updated top-down so that unattached
1329
+ // children allow us to bail out early.
1265
1330
  this._gotoUnattachedState();
1266
- this._callOnChildViews('_parentDidRemoveFromDocument');
1331
+ this._callOnChildViews('_parentDidDetach', true);
1267
1332
  },
1268
1333
 
1269
- /** @private */
1334
+ /** @private Hides the view. */
1335
+ _executeDoHide: function () {
1336
+ var notifyStack = []; // Only those views that changed state get added to the stack.
1337
+
1338
+ // The children are updated top-down so that hidden or unattached children allow us to bail out early.
1339
+ this._callOnChildViews('_parentWillHideInDocument', true, notifyStack);
1340
+
1341
+ // Notify for each child (that will change state) in reverse so that each child is in the proper
1342
+ // state before its parent potentially alters its state. For example, a parent could modify
1343
+ // children in `willHideInDocument`.
1344
+ for (var i = notifyStack.length - 1; i >= 0; i--) {
1345
+ var childView = notifyStack[i];
1346
+
1347
+ childView._notifyWillHideInDocument();
1348
+ }
1349
+ this._notifyWillHideInDocument();
1350
+
1351
+ // Cancel any remaining animations (e.g. a concurrent build in or build out).
1352
+ var viewState = this.get('viewState');
1353
+ switch (viewState) {
1354
+ case SC.CoreView.ATTACHED_BUILDING_IN:
1355
+ case SC.CoreView.ATTACHED_BUILDING_OUT:
1356
+ case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
1357
+ case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
1358
+ this.cancelAnimation();
1359
+ break;
1360
+ }
1361
+
1362
+ // Update the visible style.
1363
+ this._doUpdateVisibleStyle();
1364
+
1365
+ // Update the state and children state. The children are updated top-down so that hidden or
1366
+ // unattached children allow us to bail out early.
1367
+ this._gotoAttachedHiddenState();
1368
+ this._callOnChildViews('_parentDidHideInDocument', true); // , notifyStack
1369
+
1370
+ // Notify for each child (that changed state) in reverse so that each child is in the proper
1371
+ // state before its parent potentially alters its state. For example, a parent could modify
1372
+ // children in `didHideInDocument`.
1373
+ // for (var i = notifyStack.length - 1; i >= 0; i--) {
1374
+ // var childView = notifyStack[i];
1375
+
1376
+ // childView._notifyDidHideInDocument();
1377
+ // }
1378
+ this._notifyDidHideInDocument();
1379
+ },
1380
+
1381
+ /** @private Render the view's layer. */
1382
+ _executeDoRender: function () {
1383
+ var notifyStack = []; // Only those views that changed state get added to the stack.
1384
+
1385
+ // Render the layer.
1386
+ var context = this.renderContext(this.get('tagName'));
1387
+
1388
+ this.renderToContext(context);
1389
+ this.set('layer', context.element());
1390
+
1391
+ // Update the state and children state. The children are updated top-down so that invalid state
1392
+ // children allow us to bail out early.
1393
+ this._gotoUnattachedState();
1394
+ this._callOnChildViews('_parentDidRender', true, notifyStack);
1395
+
1396
+ this._sc_addRenderedStateObservers();
1397
+
1398
+ // Notify for each child (that changed state) in reverse so that each child is in the proper
1399
+ // state before its parent potentially alters its state. For example, a parent could modify
1400
+ // children in `didCreateLayer`.
1401
+ for (var i = notifyStack.length - 1; i >= 0; i--) {
1402
+ var childView = notifyStack[i];
1403
+
1404
+ childView._notifyDidRender();
1405
+ }
1406
+ this._notifyDidRender();
1407
+ },
1408
+
1409
+ /** @private Shows the view. */
1410
+ _executeDoShow: function () {
1411
+ // var notifyStack = []; // Only those views that changed state get added to the stack.
1412
+
1413
+ // Update the visible style.
1414
+ this._doUpdateVisibleStyle();
1415
+
1416
+ // Update the state and children state. The children are updated top-down so that hidden or
1417
+ // unattached children allow us to bail out early. This view's state is going to be transitioning,
1418
+ // but all child views are now considered shown.
1419
+ this._gotoAttachedShownState();
1420
+ this._callOnChildViews('_parentDidShowInDocument', true); // , notifyStack
1421
+
1422
+ // Notify for each child (that changed state) in reverse so that each child is in the proper
1423
+ // state before its parent potentially alters its state. For example, a parent could modify
1424
+ // children in `didShowInDocument`.
1425
+ // for (var i = notifyStack.length - 1; i >= 0; i--) {
1426
+ // var childView = notifyStack[i];
1427
+
1428
+ // childView._notifyDidShowInDocument();
1429
+ // }
1430
+ this._notifyDidShowInDocument();
1431
+ },
1432
+
1433
+ /** @private Updates the layer. */
1270
1434
  _executeDoUpdateContent: function () {
1271
1435
  var mixins = this.renderMixin,
1272
1436
  context = this.renderContext(this.get('layer'));
@@ -1349,6 +1513,21 @@ SC.CoreView.reopen(
1349
1513
  this.$().toggleClass('focus', isFirstResponder);
1350
1514
  },
1351
1515
 
1516
+ /** @private Attempts to call `didAppendToDocument` on the view. */
1517
+ _notifyDidAttach: function () {
1518
+ // If we don't have the layout module then we don't know the frame until appended to the document.
1519
+ this.notifyPropertyChange('frame');
1520
+
1521
+ // Notify.
1522
+ if (this.didAppendToDocument) { this.didAppendToDocument(); }
1523
+ },
1524
+
1525
+ /** @private Attempts to call `didHideInDocument` on the view. */
1526
+ _notifyDidHideInDocument: function () {
1527
+ if (this.didHideInDocument) { this.didHideInDocument(); }
1528
+ },
1529
+
1530
+ /** @private Attempts to call `didCreateLayer` on the view. */
1352
1531
  _notifyDidRender: function () {
1353
1532
  var mixins = this.didCreateLayerMixin,
1354
1533
  idx, len;
@@ -1363,21 +1542,12 @@ SC.CoreView.reopen(
1363
1542
  }
1364
1543
  },
1365
1544
 
1366
- /** @private Notify on attached. */
1367
- _notifyDidAttach: function () {
1368
- // If we don't have the layout module then we don't know the frame until appended to the document.
1369
- this.notifyPropertyChange('frame');
1370
-
1371
- // Notify.
1372
- if (this.didAppendToDocument) { this.didAppendToDocument(); }
1373
- },
1374
-
1375
- /** @private Notify on detaching. */
1376
- _notifyWillDetach: function () {
1377
- if (this.willRemoveFromDocument) { this.willRemoveFromDocument(); }
1545
+ /** @private Attempts to call `didShowInDocument` on the view. */
1546
+ _notifyDidShowInDocument: function () {
1547
+ if (this.didShowInDocument) { this.didShowInDocument(); }
1378
1548
  },
1379
1549
 
1380
- /** @private Notify before destroying layer. */
1550
+ /** @private Attempts to call `willDestroyLayer` on the view. */
1381
1551
  _notifyWillDestroyLayer: function () {
1382
1552
  var idx, len,
1383
1553
  mixins;
@@ -1393,37 +1563,96 @@ SC.CoreView.reopen(
1393
1563
  if (this.willDestroyLayer) { this.willDestroyLayer(); }
1394
1564
  },
1395
1565
 
1566
+ /** @private Attempts to call `willRemoveFromDocument` on the view. */
1567
+ _notifyWillDetach: function () {
1568
+ if (this.willRemoveFromDocument) { this.willRemoveFromDocument(); }
1569
+ },
1570
+
1571
+ /** @private Attempts to call `willHideInDocument` on the view. */
1572
+ _notifyWillHideInDocument: function () {
1573
+ if (this.willHideInDocument) { this.willHideInDocument(); }
1574
+ },
1575
+
1576
+ /** @private Attempts to call `willShowInDocument` on the view. */
1577
+ _notifyWillShowInDocument: function () {
1578
+ if (this.willShowInDocument) { this.willShowInDocument(); }
1579
+ },
1580
+
1396
1581
  /** @private Routes according to parent did append. */
1397
- _parentDidAppendToDocument: function () {
1398
- // Run any queued updates.
1399
- this._executeQueuedUpdates();
1582
+ _parentDidAttach: function (notifyStack) {
1583
+ var state = this.get('viewState'),
1584
+ shouldContinue = true;
1400
1585
 
1401
- // Update states after *will* and before *did* notifications!
1402
- this._routeOnAttached();
1586
+ // Handle all 12 possible view states.
1587
+ switch (state) {
1403
1588
 
1404
- // Notify.
1405
- this._notifyDidAttach();
1589
+ // Scenario: The child view was attached to the parent, which was unattached.
1590
+ // Result: Update the child and then move it to the proper attached state.
1591
+ case SC.CoreView.ATTACHED_PARTIAL:
1592
+ // Run any queued updates.
1593
+ this._executeQueuedUpdates();
1594
+
1595
+ // Go to the proper state.
1596
+ this._gotoSomeAttachedState();
1597
+
1598
+ // If there is a transition in, run it. TODO: Check state here?
1599
+ var transitionIn = this.get('transitionIn');
1600
+ if (transitionIn) {
1601
+ this._transitionIn(false);
1602
+ }
1603
+
1604
+ break;
1605
+
1606
+ // Scenario: The child is unrendered or unattached.
1607
+ // Result: The child would need to be forced into this state by its parent (otherwise it should
1608
+ // be in an ATTACHED_PARTIAL state), so just leave it alone and don't notify.
1609
+ case SC.CoreView.UNRENDERED: // Render + attach?
1610
+ case SC.CoreView.UNATTACHED: // Attach?
1611
+ // There's no need to continue to further child views.
1612
+ shouldContinue = false;
1613
+ break;
1614
+
1615
+ // Invalid states.
1616
+ default:
1617
+ //@if(debug)
1618
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1619
+ // All other states should be impossible if parent was UNATTACHED:
1620
+ // ATTACHED_BUILDING_IN, ATTACHED_SHOWING, ATTACHED_SHOWN, ATTACHED_SHOWN_ANIMATING, ATTACHED_BUILDING_OUT, ATTACHED_BUILDING_OUT_BY_PARENT, ATTACHED_HIDING, ATTACHED_HIDDEN, ATTACHED_HIDDEN_BY_PARENT
1621
+ SC.warn("Core Developer Warning: Found invalid state for view, %@, in _parentDidAttach".fmt(this));
1622
+ //@endif
1623
+
1624
+ // There's no need to continue to further child views.
1625
+ shouldContinue = false;
1626
+ }
1627
+
1628
+ if (shouldContinue) {
1629
+ // Allow children that have changed state to notify that they have been attached.
1630
+ notifyStack.push(this);
1631
+ }
1632
+
1633
+ return shouldContinue;
1406
1634
  },
1407
1635
 
1408
1636
  /** @private Updates according to parent did cancel build out. */
1409
1637
  _parentDidCancelBuildOut: function () {
1410
- var state = this.get('viewState'),
1411
- transitionIn = this.get('transitionIn');
1638
+ var state = this.get('viewState');
1412
1639
 
1640
+ // If the view was building out because its parent was building out, attempt to reverse or
1641
+ // revert the transition.
1413
1642
  if (state === SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT) {
1414
- if (transitionIn) {
1415
- // this.invokeNext(function () {
1416
- this._transitionIn();
1417
- // });
1643
+ var transitionIn = this.get('transitionIn');
1418
1644
 
1419
- // Update states after *will* and before *did* notifications!
1420
- this._gotoAttachedBuildingInState();
1421
- } else {
1422
- this._cancelTransition();
1645
+ // Cancel the building out transition (in place if we are going to switch to transitioning back in).
1646
+ this.cancelAnimation(transitionIn ? SC.LayoutState.CURRENT : undefined);
1423
1647
 
1424
- // Update states after *will* and before *did* notifications!
1425
- this._gotoAttachedShownState();
1648
+ // Set the proper state.
1649
+ this._gotoAttachedShownState();
1650
+
1651
+ if (transitionIn) {
1652
+ this._transitionIn(true);
1426
1653
  }
1654
+
1655
+ // If the view was building out on its own or is hidden we can ignore it.
1427
1656
  } else if (state === SC.CoreView.ATTACHED_BUILDING_OUT || state &
1428
1657
  SC.CoreView.IS_HIDDEN) {
1429
1658
  // There's no need to continue to further child views.
@@ -1431,203 +1660,355 @@ SC.CoreView.reopen(
1431
1660
  }
1432
1661
  },
1433
1662
 
1434
- /** @private Starts building out view if appropriate. */
1435
- _parentWillBuildOutFromDocument: function (owningView) {
1663
+ /** @private Update child view states when the parent hides. Top-down! */
1664
+ _parentDidHideInDocument: function () { // notifyStack
1436
1665
  var state = this.get('viewState'),
1437
- transitionOut = this.get('transitionOut');
1666
+ shouldContinue = false;
1438
1667
 
1668
+ // Handle all 12 possible view states.
1439
1669
  switch (state) {
1440
- case SC.CoreView.UNRENDERED:
1441
- case SC.CoreView.UNATTACHED:
1442
- case SC.CoreView.UNATTACHED_BY_PARENT:
1443
- case SC.CoreView.ATTACHED_BUILDING_OUT:
1444
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
1445
- // There's no need to continue to further child views.
1446
- // return false;
1447
- case SC.CoreView.ATTACHED_HIDDEN:
1448
- case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT:
1449
- case SC.CoreView.ATTACHED_HIDING:
1450
- // Notify *will* (top-down from parent to children).
1451
- // this._notifyWillDetach();
1452
1670
 
1453
- return false;
1454
- case SC.CoreView.ATTACHED_SHOWING:
1455
- case SC.CoreView.ATTACHED_BUILDING_IN:
1671
+ // Scenario: The child view was shown.
1672
+ // Result: Go to hidden by parent state.
1456
1673
  case SC.CoreView.ATTACHED_SHOWN:
1457
- // Notify *will* (top-down from parent to children).
1458
- // this._notifyWillDetach();
1459
-
1460
- if (transitionOut) {
1461
- this._owningView = owningView;
1462
-
1463
- // this.invokeNext(function () {
1464
- this._transitionOut(false, owningView);
1465
- // });
1466
-
1467
- // Update states after *will* and before *did* notifications!
1468
- this._gotoAttachedBuildingOutByParentState();
1469
- }
1470
- return true;
1471
- default:
1472
- }
1473
- },
1674
+ // Go to the proper state.
1675
+ this._gotoAttachedHiddenByParentState();
1474
1676
 
1475
- /** @private Clean up before parent is detached. */
1476
- _parentWillRemoveFromDocument: function () {
1477
- var state = this.get('viewState');
1677
+ shouldContinue = true;
1678
+ break;
1478
1679
 
1479
- switch (state) {
1680
+ // Scenario: The child view was hidden or forced to unrendered or unattached state.
1681
+ // Result: Do nothing.
1480
1682
  case SC.CoreView.UNRENDERED:
1481
1683
  case SC.CoreView.UNATTACHED:
1482
- case SC.CoreView.UNATTACHED_BY_PARENT:
1483
- // There's no need to continue to further child views.
1484
- return false;
1485
- // Cancel any outstanding isVisible transitions and mark for visibility update.
1486
- case SC.CoreView.ATTACHED_SHOWING:
1487
- case SC.CoreView.ATTACHED_HIDING:
1488
- this._cancelTransition();
1489
- this._teardownTransition();
1490
- this._visibleStyleNeedsUpdate = true;
1491
- break;
1492
- // Cancel any other outstanding transitions.
1493
- case SC.CoreView.ATTACHED_BUILDING_IN:
1494
- case SC.CoreView.ATTACHED_BUILDING_OUT:
1495
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
1496
- this._cancelTransition();
1497
- this._teardownTransition();
1498
- break;
1499
1684
  case SC.CoreView.ATTACHED_HIDDEN:
1500
- case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT:
1501
- case SC.CoreView.ATTACHED_SHOWN:
1502
1685
  break;
1686
+
1687
+ // Invalid states.
1503
1688
  default:
1504
- // Attached and not in a transitionary state.
1689
+ //@if(debug)
1690
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1691
+ // All animating states should have been canceled when parent will hide is called.
1692
+ // ATTACHED_HIDING, ATTACHED_BUILDING_IN, ATTACHED_SHOWING, ATTACHED_BUILDING_OUT, ATTACHED_BUILDING_OUT_BY_PARENT, ATTACHED_PARTIAL, ATTACHED_HIDDEN_BY_PARENT, ATTACHED_SHOWN_ANIMATING
1693
+ SC.warn("Core Developer Warning: Found invalid state for view %@ in _parentDidHideInDocument".fmt(this));
1694
+ //@endif
1505
1695
  }
1506
1696
 
1507
- // Notify *will*.
1508
- this._notifyWillDetach();
1509
- },
1697
+ // if (shouldContinue) {
1698
+ // // Allow children that have changed state to notify that they have been hidden.
1699
+ // notifyStack.push(this);
1700
+ // }
1510
1701
 
1511
- _ancestorDidChangeParent: function () {
1512
- this.notifyPropertyChange('pane');
1702
+ return shouldContinue;
1513
1703
  },
1514
1704
 
1515
1705
  /** @private Routes according to parent did detach. */
1516
- _parentDidRemoveFromDocument: function () {
1706
+ _parentDidDetach: function () {
1517
1707
  var state = this.get('viewState');
1518
1708
 
1519
1709
  if (state & SC.CoreView.IS_ATTACHED) {
1520
1710
  // Update states after *will* and before *did* notifications!
1521
- this._gotoUnattachedByParentState();
1711
+ this._gotoAttachedPartialState();
1522
1712
  } else {
1523
1713
  // There's no need to continue to further child views.
1524
1714
  return false;
1525
1715
  }
1526
1716
  },
1527
1717
 
1528
- /** @private Routes according to parent did hide. */
1529
- _parentDidHideInDocument: function () {
1530
- var state = this.get('viewState');
1718
+ /** @private Configure child views when parent did render. */
1719
+ _parentDidRender: function (notifyStack) {
1720
+ var state = this.get('viewState'),
1721
+ shouldContinue = true;
1531
1722
 
1723
+ // Handle all 12 possible view states.
1532
1724
  switch (state) {
1533
- case SC.CoreView.UNRENDERED: // FAST PATH!
1534
- case SC.CoreView.UNATTACHED: // FAST PATH!
1535
- case SC.CoreView.UNATTACHED_BY_PARENT:
1536
- case SC.CoreView.ATTACHED_HIDING:
1537
- case SC.CoreView.ATTACHED_BUILDING_OUT:
1538
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
1539
- case SC.CoreView.ATTACHED_HIDDEN: // FAST PATH!
1725
+
1726
+ // Scenario: The child view was unrendered and now is rendered.
1727
+ // Result: Add rendered state observers and move it to the proper rendered state.
1728
+ case SC.CoreView.UNRENDERED:
1729
+ this._sc_addRenderedStateObservers();
1730
+
1731
+ // Go to the proper state.
1732
+ this._gotoAttachedPartialState();
1733
+ break;
1734
+
1735
+ // Invalid states.
1736
+ default:
1737
+ //@if(debug)
1738
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1739
+ // All other states should be impossible if parent was UNRENDERED:
1740
+ // ATTACHED_BUILDING_IN, ATTACHED_SHOWING, ATTACHED_SHOWN, ATTACHED_SHOWN_ANIMATING, ATTACHED_BUILDING_OUT, ATTACHED_BUILDING_OUT_BY_PARENT, ATTACHED_HIDING, ATTACHED_HIDDEN, ATTACHED_HIDDEN_BY_PARENT, ATTACHED_PARTIAL, UNATTACHED
1741
+ SC.warn("Core Developer Warning: Found invalid state for view %@ in _parentDidRender".fmt(this));
1742
+ //@endif
1743
+
1744
+ // There's no need to continue to further child views.
1745
+ shouldContinue = false;
1746
+ }
1747
+
1748
+ if (shouldContinue) {
1749
+ // Allow children that have changed state to notify that they have been rendered.
1750
+ notifyStack.push(this);
1751
+ }
1752
+
1753
+ return shouldContinue;
1754
+ },
1755
+
1756
+ /** @private Update child view states when the parent shows. Top-down! */
1757
+ _parentDidShowInDocument: function () { // notifyStack
1758
+ var state = this.get('viewState'),
1759
+ shouldContinue = true;
1760
+
1761
+ // Handle all 12 possible view states.
1762
+ switch (state) {
1763
+
1764
+ // Scenario: The child view is only hidden because of the parent.
1765
+ // Result: Go to shown state. This will notify.
1540
1766
  case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT:
1767
+ this._gotoAttachedShownState();
1768
+
1769
+ break;
1770
+
1771
+ // Scenario: The child view is hidden on its own or has been forced to an unrendered or unattached state.
1772
+ // Result: Do nothing and don't notify.
1773
+ case SC.CoreView.UNRENDERED:
1774
+ case SC.CoreView.UNATTACHED:
1775
+ case SC.CoreView.ATTACHED_HIDDEN:
1541
1776
  // There's no need to continue to further child views.
1542
- return false;
1543
- case SC.CoreView.ATTACHED_BUILDING_IN:
1544
- case SC.CoreView.ATTACHED_SHOWING:
1545
- case SC.CoreView.ATTACHED_SHOWN:
1777
+ shouldContinue = false;
1546
1778
  break;
1779
+
1780
+ // Invalid states.
1547
1781
  default:
1782
+ //@if(debug)
1783
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1784
+ // These states should be impossible if the parent was HIDDEN.
1785
+ // ATTACHED_SHOWN, ATTACHED_SHOWN_ANIMATING, ATTACHED_SHOWING, ATTACHED_HIDING, ATTACHED_BUILDING_IN, ATTACHED_BUILDING_OUT, ATTACHED_BUILDING_OUT_BY_PARENT
1786
+ // This state should be impossible if its parent was UNATTACHED (it should have been trimmed above):
1787
+ // ATTACHED_PARTIAL
1788
+ SC.warn("Core Developer Warning: Found invalid state for view %@ in _parentDidShowInDocument".fmt(this));
1789
+ //@endif
1790
+ // There's no need to continue to further child views.
1791
+ shouldContinue = false;
1548
1792
  }
1549
1793
 
1550
- // Update states after *will* and before *did* notifications!
1551
- this._gotoAttachedHiddenByParentState();
1794
+ // if (shouldContinue) {
1795
+ // // Allow children that have changed state to notify that they have been made visible.
1796
+ // notifyStack.push(this);
1797
+ // }
1552
1798
 
1553
- // Notify *did* (bottom-up from children to parent).
1554
- if (this.didHideInDocument) { this.didHideInDocument(); }
1799
+ return shouldContinue;
1555
1800
  },
1556
1801
 
1557
- /** @private Routes according to parent will hide. */
1558
- _parentWillHideInDocument: function () {
1559
- var state = this.get('viewState');
1802
+ /** @private Starts building out view if appropriate. */
1803
+ _parentWillBuildOutFromDocument: function (owningView) {
1804
+ var state = this.get('viewState'),
1805
+ transitionOut = this.get('transitionOut'),
1806
+ shouldContinue = true;
1560
1807
 
1561
1808
  switch (state) {
1562
- case SC.CoreView.UNRENDERED: // FAST PATH!
1563
- case SC.CoreView.UNATTACHED: // FAST PATH!
1564
- // case SC.CoreView.UNATTACHED_BY_PARENT:
1565
- case SC.CoreView.ATTACHED_HIDDEN: // FAST PATH!
1566
- // case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT:
1809
+ case SC.CoreView.UNRENDERED:
1810
+ case SC.CoreView.UNATTACHED:
1811
+ case SC.CoreView.ATTACHED_BUILDING_OUT:
1812
+ case SC.CoreView.ATTACHED_HIDDEN:
1567
1813
  // There's no need to continue to further child views.
1568
- return false;
1569
- case SC.CoreView.ATTACHED_HIDING: // FAST PATH!
1570
- // Clear out any child views that are transitioning before we hide.
1571
- // Notify *will* (top-down from parent to children).
1572
- // this._callOnChildViews('_parentWillHideInDocument');
1814
+ shouldContinue = false;
1815
+ break;
1573
1816
 
1574
- // // Update states after *will* and before *did* notifications!
1575
- // this._gotoAttachedHiddenState();
1817
+ // Scenario: The child view is building in at the same time that its ancestor wants to detach.
1818
+ // Result: If the child wants to build out, switch to building out by parent, otherwise let the build in run for as long as it can.
1819
+ case SC.CoreView.ATTACHED_BUILDING_IN:
1576
1820
 
1577
- // Cancel our hiding transition.
1578
- this._cancelTransition();
1821
+ // Cancel the build in transition.
1822
+ if (transitionOut) {
1823
+ this.cancelAnimation(SC.LayoutState.CURRENT);
1824
+ } else {
1825
+ this.cancelAnimation();
1826
+ }
1579
1827
 
1580
- // We didn't quite hide in time so indicate that visibility needs update next time we display.
1581
- // this._visibleStyleNeedsUpdate = true;
1828
+ // Set the proper state.
1829
+ this._gotoAttachedShownState();
1830
+
1831
+ // Build out the view by parent.
1832
+ if (transitionOut) {
1833
+ this._transitionOut(true, owningView);
1834
+ }
1582
1835
 
1583
- return false;
1584
- case SC.CoreView.ATTACHED_BUILDING_IN: // FAST PATH!
1585
- case SC.CoreView.ATTACHED_SHOWING: // FAST PATH!
1586
- this._cancelTransition();
1587
1836
  break;
1588
- // case SC.CoreView.ATTACHED_BUILDING_OUT:
1589
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
1590
- this._cancelTransition();
1837
+
1838
+ // Scenario: The view is shown and possibly transitioning.
1839
+ // Result: Allow any transitions to continue concurrent with build out transition (may be conflicts).
1840
+ case SC.CoreView.ATTACHED_HIDING:
1841
+ case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
1842
+ case SC.CoreView.ATTACHED_SHOWING:
1843
+ case SC.CoreView.ATTACHED_SHOWN:
1844
+
1845
+ // Build out the view by parent.
1846
+ if (transitionOut) {
1847
+ this._transitionOut(false, owningView);
1848
+ }
1591
1849
  break;
1850
+
1851
+ // Invalid states.
1852
+ default:
1853
+ //@if(debug)
1854
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1855
+ // These states should not be reachable here: ATTACHED_PARTIAL, ATTACHED_HIDDEN_BY_PARENT, ATTACHED_BUILDING_OUT_BY_PARENT
1856
+ SC.warn("Core Developer Warning: Found invalid state for view %@ in _parentWillBuildOutFromDocument".fmt(this));
1857
+ //@endif
1858
+ // There's no need to continue to further child views.
1859
+ shouldContinue = false;
1860
+ }
1861
+
1862
+ return shouldContinue;
1863
+ },
1864
+
1865
+ /** @private Prepares according to parent will hide. This is called before the parent view hides
1866
+ completely, which may be after a hide transition completes. */
1867
+ _parentWillHideInDocument: function () { // notifyStack
1868
+ var state = this.get('viewState'),
1869
+ shouldContinue = true;
1870
+
1871
+ // Handle all 12 possible view states.
1872
+ switch (state) {
1873
+
1874
+ // Scenario: The child view is visible.
1875
+ // Result: Do nothing and continue.
1592
1876
  case SC.CoreView.ATTACHED_SHOWN:
1593
1877
  break;
1878
+
1879
+ // Scenario: The child view is animating.
1880
+ // Result: Complete its animation immediately and continue.
1881
+ case SC.CoreView.ATTACHED_SHOWN_ANIMATING:
1882
+ case SC.CoreView.ATTACHED_SHOWING:
1883
+ case SC.CoreView.ATTACHED_BUILDING_IN:
1884
+ case SC.CoreView.ATTACHED_BUILDING_OUT:
1885
+ case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
1886
+ case SC.CoreView.ATTACHED_HIDING:
1887
+ this.cancelAnimation();
1888
+ break;
1889
+
1890
+ // Scenario: The child view is hidden or has been forced to an unrendered or unattached state.
1891
+ // Result: Do nothing and don't notify.
1892
+ case SC.CoreView.UNRENDERED:
1893
+ case SC.CoreView.UNATTACHED:
1894
+ case SC.CoreView.ATTACHED_HIDDEN:
1895
+ // There's no need to continue to further child views.
1896
+ break;
1897
+
1898
+ // Invalid states.
1594
1899
  default:
1595
- // Attached and not in a transitionary state.
1900
+ //@if(debug)
1901
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1902
+ // This state should be impossible if its parent was UNATTACHED or HIDDEN/HIDING (it should have been trimmed above):
1903
+ // ATTACHED_PARTIAL, ATTACHED_HIDDEN_BY_PARENT
1904
+ SC.warn("Core Developer Warning: Found invalid state for view %@ in _parentWillHideInDocument".fmt(this));
1905
+ //@endif
1906
+ // There's no need to continue to further child views.
1907
+ shouldContinue = false;
1596
1908
  }
1597
1909
 
1598
- // Notify *will* (top-down from parent to children).
1599
- if (this.willHideInDocument) { this.willHideInDocument(); }
1910
+ // if (shouldContinue) {
1911
+ // // Allow children that have changed state to notify that they will be shown.
1912
+ // notifyStack.push(this);
1913
+ // }
1914
+
1915
+ return shouldContinue;
1600
1916
  },
1601
1917
 
1602
- /** @private Routes according to parent did show. */
1603
- _parentDidShowInDocument: function () {
1604
- var state = this.get('viewState');
1918
+ /** @private Clean up before parent is detached. */
1919
+ _parentWillDetach: function (notifyStack) {
1920
+ var state = this.get('viewState'),
1921
+ shouldContinue = true;
1605
1922
 
1606
- if (state === SC.CoreView.ATTACHED_HIDDEN_BY_PARENT) {
1607
- // Update states after *will* and before *did* notifications!
1608
- this._gotoAttachedShownState();
1923
+ // Handle all 12 possible view states.
1924
+ switch (state) {
1609
1925
 
1610
- // Notify *did* (bottom-up from children to parent).
1611
- if (this.didShowInDocument) { this.didShowInDocument(); }
1612
- } else {
1926
+ // Scenario: The child view is visible.
1927
+ // Result: Do nothing and continue.
1928
+ case SC.CoreView.ATTACHED_SHOWN:
1929
+ break;
1930
+
1931
+ // Scenario: The child view is animating.
1932
+ // Result: Complete its animation immediately and continue.
1933
+ case SC.CoreView.ATTACHED_SHOWN_ANIMATING: // TODO: We need concurrent states!
1934
+ case SC.CoreView.ATTACHED_SHOWING:
1935
+ case SC.CoreView.ATTACHED_BUILDING_IN: // Was building in and didn't have a build out.
1936
+ case SC.CoreView.ATTACHED_BUILDING_OUT: // Was building out on its own at the same time.
1937
+ case SC.CoreView.ATTACHED_HIDING:
1938
+ this.cancelAnimation();
1939
+ break;
1940
+
1941
+ // Scenario: The child view has forced to unattached or unrendered state, or it's hidden.
1942
+ // Result: Don't continue.
1943
+ case SC.CoreView.UNRENDERED:
1944
+ case SC.CoreView.UNATTACHED:
1945
+ case SC.CoreView.ATTACHED_HIDDEN:
1946
+ shouldContinue = false;
1947
+ break;
1948
+
1949
+ // Invalid states.
1950
+ default:
1951
+ //@if(debug)
1952
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1953
+ // These states should not be reachable here: ATTACHED_PARTIAL, ATTACHED_HIDDEN_BY_PARENT, ATTACHED_BUILDING_OUT_BY_PARENT
1954
+ SC.warn("Core Developer Warning: Found invalid state for view %@ in _parentWillDetach".fmt(this));
1955
+ //@endif
1613
1956
  // There's no need to continue to further child views.
1614
- return false;
1957
+ shouldContinue = false;
1958
+ }
1959
+
1960
+ if (shouldContinue) {
1961
+ // Allow children that have changed state to notify that they will be shown.
1962
+ notifyStack.push(this);
1615
1963
  }
1964
+
1965
+ return shouldContinue;
1616
1966
  },
1617
1967
 
1618
1968
  /** @private Prepares according to parent will show. */
1619
- _parentWillShowInDocument: function () {
1620
- var state = this.get('viewState');
1969
+ _parentWillShowInDocument: function (notifyStack) {
1970
+ var state = this.get('viewState'),
1971
+ shouldContinue = true;
1621
1972
 
1622
- if (state === SC.CoreView.ATTACHED_HIDDEN_BY_PARENT) {
1973
+ // Handle all 12 possible view states.
1974
+ switch (state) {
1975
+
1976
+ // Scenario: The child view is only hidden because of the parent.
1977
+ // Result: Run queued updates. This will notify.
1978
+ case SC.CoreView.ATTACHED_HIDDEN_BY_PARENT:
1623
1979
  this._executeQueuedUpdates();
1624
1980
 
1625
- // Notify *will* (top-dow`n from parent to children).
1626
- if (this.willShowInDocument) { this.willShowInDocument(); }
1627
- } else {
1981
+ break;
1982
+
1983
+ // Scenario: The child view is hidden on its own or has been forced to an unrendered or unattached state.
1984
+ // Result: Do nothing and don't notify.
1985
+ case SC.CoreView.UNRENDERED:
1986
+ case SC.CoreView.UNATTACHED:
1987
+ case SC.CoreView.ATTACHED_HIDDEN:
1628
1988
  // There's no need to continue to further child views.
1629
- return false;
1989
+ shouldContinue = false;
1990
+ break;
1991
+
1992
+ // Invalid states.
1993
+ default:
1994
+ //@if(debug)
1995
+ // Add some debugging only warnings for if the view statechart is breaking assumptions.
1996
+ // These states should be impossible if the parent was HIDDEN.
1997
+ // ATTACHED_SHOWN, ATTACHED_SHOWN_ANIMATING, ATTACHED_SHOWING, ATTACHED_HIDING, ATTACHED_BUILDING_IN, ATTACHED_BUILDING_OUT, ATTACHED_BUILDING_OUT_BY_PARENT
1998
+ // This state should be impossible if its parent was UNATTACHED (it should have been trimmed above):
1999
+ // ATTACHED_PARTIAL
2000
+ SC.warn("Core Developer Warning: Found invalid state for view %@ in _parentWillShowInDocument".fmt(this));
2001
+ //@endif
2002
+ // There's no need to continue to further child views.
2003
+ shouldContinue = false;
1630
2004
  }
2005
+
2006
+ if (shouldContinue) {
2007
+ // Allow children that have changed state to notify that they will be shown.
2008
+ notifyStack.push(this);
2009
+ }
2010
+
2011
+ return shouldContinue;
1631
2012
  },
1632
2013
 
1633
2014
  /** @private */
@@ -1671,12 +2052,12 @@ SC.CoreView.reopen(
1671
2052
  },
1672
2053
 
1673
2054
  /** @private Attempts to run a transition hide, ensuring any incoming transitions are stopped in place. */
1674
- _transitionHide: function () {
2055
+ _transitionHide: function (inPlace) {
1675
2056
  var transitionHide = this.get('transitionHide'),
1676
2057
  options = this.get('transitionHideOptions') || {};
1677
2058
 
1678
2059
  //@if (debug)
1679
- if (SC.LOG_VIEW_STATES) {
2060
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
1680
2061
  SC.Logger.log('%c%@ — _transitionHide()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
1681
2062
  }
1682
2063
  //@endif
@@ -1688,32 +2069,35 @@ SC.CoreView.reopen(
1688
2069
  // inPlace = true;
1689
2070
  // break;
1690
2071
  // default:
1691
- this._setupTransition(transitionHide);
2072
+ if (!inPlace) {
2073
+ this._setupTransition(transitionHide);
2074
+ }
1692
2075
  // }
1693
2076
 
1694
2077
  // Set up the hiding transition.
1695
2078
  if (transitionHide.setup) {
1696
- transitionHide.setup(this, options);
2079
+ transitionHide.setup(this, options, inPlace);
1697
2080
  }
1698
2081
 
1699
2082
  // Execute the hiding transition.
1700
2083
  transitionHide.run(this, options, this._preTransitionLayout, this._preTransitionFrame);
2084
+
2085
+ // Set the proper state.
2086
+ this._gotoAttachedHidingState();
1701
2087
  },
1702
2088
 
1703
2089
  /** @private Attempts to run a transition in, ensuring any outgoing transitions are stopped in place. */
1704
- _transitionIn: function () {
1705
- var state = this.get('viewState'),
1706
- transitionIn = this.get('transitionIn'),
1707
- options = this.get('transitionInOptions') || {},
1708
- inPlace = false;
2090
+ _transitionIn: function (inPlace) {
2091
+ var transitionIn = this.get('transitionIn'),
2092
+ options = this.get('transitionInOptions') || {};
1709
2093
 
1710
- switch (state) {
1711
- case SC.CoreView.ATTACHED_BUILDING_OUT_BY_PARENT:
1712
- case SC.CoreView.ATTACHED_BUILDING_OUT:
1713
- this.cancelAnimation(SC.LayoutState.CURRENT);
1714
- inPlace = true;
1715
- break;
1716
- default:
2094
+ //@if (debug)
2095
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
2096
+ SC.Logger.log('%c%@ — _transitionIn()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
2097
+ }
2098
+ //@endif
2099
+
2100
+ if (!inPlace) {
1717
2101
  this._setupTransition(transitionIn);
1718
2102
  }
1719
2103
 
@@ -1724,6 +2108,9 @@ SC.CoreView.reopen(
1724
2108
 
1725
2109
  // Execute the incoming transition.
1726
2110
  transitionIn.run(this, options, this._preTransitionLayout, this._preTransitionFrame);
2111
+
2112
+ // Set the proper state.
2113
+ this._gotoAttachedBuildingInState();
1727
2114
  },
1728
2115
 
1729
2116
  /** @private Attempts to run a transition out, ensuring any incoming transitions are stopped in place. */
@@ -1736,7 +2123,7 @@ SC.CoreView.reopen(
1736
2123
  }
1737
2124
 
1738
2125
  // Increment the shared building out count.
1739
- owningView._buildingOutCount++;
2126
+ owningView._sc_buildOutCount++;
1740
2127
 
1741
2128
  // Set up the outgoing transition.
1742
2129
  if (transitionOut.setup) {
@@ -1745,25 +2132,29 @@ SC.CoreView.reopen(
1745
2132
 
1746
2133
  // Execute the outgoing transition.
1747
2134
  transitionOut.run(this, options, this._preTransitionLayout, this._preTransitionFrame);
2135
+
2136
+ // Set the proper state.
2137
+ if (owningView === this) {
2138
+ this._gotoAttachedBuildingOutState();
2139
+ } else {
2140
+ this._gotoAttachedBuildingOutByParentState();
2141
+ }
1748
2142
  },
1749
2143
 
1750
2144
  /** @private Attempts to run a transition show, ensuring any hiding transitions are stopped in place. */
1751
- _transitionShow: function () {
2145
+ _transitionShow: function (inPlace) {
1752
2146
  var transitionShow = this.get('transitionShow'),
1753
- options = this.get('transitionShowOptions') || {},
1754
- inPlace = false;
2147
+ options = this.get('transitionShowOptions') || {};
1755
2148
 
1756
2149
  //@if (debug)
1757
- if (SC.LOG_VIEW_STATES) {
2150
+ if (SC.LOG_VIEW_STATES || this.SC_LOG_VIEW_STATE) {
1758
2151
  SC.Logger.log('%c%@ — _transitionShow()'.fmt(this), SC.LOG_VIEW_STATES_STYLE[this.get('viewState')]);
1759
2152
  }
1760
2153
  //@endif
1761
- // if (state === SC.CoreView.ATTACHED_HIDING) {
1762
- // this.cancelAnimation(SC.LayoutState.CURRENT);
1763
- // inPlace = true;
1764
- // } else {
1765
- this._setupTransition(transitionShow);
1766
- // }
2154
+
2155
+ if (!inPlace) {
2156
+ this._setupTransition(transitionShow);
2157
+ }
1767
2158
 
1768
2159
  // Set up the showing transition.
1769
2160
  if (transitionShow.setup) {
@@ -1773,36 +2164,28 @@ SC.CoreView.reopen(
1773
2164
  // Execute the showing transition.
1774
2165
  transitionShow.run(this, options, this._preTransitionLayout, this._preTransitionFrame);
1775
2166
 
1776
- // This view's state is going to be transitioning, but all child views are now considered shown.
1777
- this._callOnChildViews('_parentDidShowInDocument');
2167
+ // Set the proper state.
2168
+ this._gotoAttachedShowingState();
1778
2169
  },
1779
2170
 
1780
- /** @private */
1781
- _routeOnAttached: function () {
2171
+ /** @private Goes to the proper attached state depending on its parents state*/
2172
+ _gotoSomeAttachedState: function () {
1782
2173
  var parentView = this.get('parentView'),
2174
+ isParentHidden = parentView ? parentView.get('viewState') & SC.CoreView.IS_HIDDEN : false,
1783
2175
  // Views without a parent are not limited by a parent's current state.
1784
2176
  isParentShown = parentView ? parentView.get('viewState') & SC.CoreView.IS_SHOWN : true;
1785
2177
 
1786
- // Update states after *will* and before *did* notifications!
1787
- if (this.get('isVisible')) {
1788
- if (isParentShown) {
1789
- // Route.
1790
- var transitionIn = this.get('transitionIn');
1791
- if (transitionIn) {
1792
- this._gotoAttachedBuildingInState();
1793
-
1794
- // this.invokeNext(function () {
1795
- this._transitionIn();
1796
- // });
1797
-
1798
- } else {
1799
- this._gotoAttachedShownState();
1800
- }
2178
+ // Set the proper state.
2179
+ if (isParentShown) {
2180
+ if (this.get('isVisible')) {
2181
+ this._gotoAttachedShownState();
1801
2182
  } else {
1802
- this._gotoAttachedHiddenByParentState();
2183
+ this._gotoAttachedHiddenState();
1803
2184
  }
2185
+ } else if (isParentHidden) {
2186
+ this._gotoAttachedHiddenByParentState();
1804
2187
  } else {
1805
- this._gotoAttachedHiddenState();
2188
+ this._gotoAttachedPartialState();
1806
2189
  }
1807
2190
  }
1808
2191