sproutcore 1.10.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +8 -8
  2. data/VERSION.yml +1 -1
  3. data/bin/sc-phantom +13 -0
  4. data/lib/Buildfile +3 -0
  5. data/lib/buildtasks/manifest.rake +3 -0
  6. data/lib/frameworks/sproutcore/CHANGELOG.md +24 -1
  7. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +1 -0
  8. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +1 -1
  9. data/lib/frameworks/sproutcore/frameworks/designer/views/designer_drop_target.js +1 -2
  10. data/lib/frameworks/sproutcore/frameworks/designer/views/high_light.js +1 -2
  11. data/lib/frameworks/sproutcore/frameworks/designer/views/page_item_view.js +1 -2
  12. data/lib/frameworks/sproutcore/frameworks/designer/views/selection_handles.js +1 -2
  13. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +4 -3
  14. data/lib/frameworks/sproutcore/frameworks/desktop/resources/progress.css +4 -0
  15. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +44 -35
  16. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +167 -91
  17. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/touch.js +215 -0
  18. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/grid/drag_and_drop.js +7 -2
  19. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/drag_and_drop.js +7 -1
  20. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/stacked/ui_comments.js +26 -24
  21. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +9 -18
  22. data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +25 -20
  23. data/lib/frameworks/sproutcore/frameworks/desktop/views/list.js +29 -29
  24. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +107 -106
  25. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +120 -134
  26. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +14 -7
  27. data/lib/frameworks/sproutcore/frameworks/desktop/views/stacked.js +2 -1
  28. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_value_support.js +4 -4
  29. data/lib/frameworks/sproutcore/frameworks/foundation/system/module.js +197 -196
  30. data/lib/frameworks/sproutcore/frameworks/foundation/views/inline_text_field.js +7 -0
  31. data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +22 -10
  32. data/lib/frameworks/sproutcore/frameworks/routing/tests/system/routes.js +43 -0
  33. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +1 -1
  34. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +2 -3
  35. data/lib/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +14 -14
  36. data/lib/frameworks/sproutcore/frameworks/statechart/system/statechart.js +90 -79
  37. data/lib/frameworks/sproutcore/frameworks/statechart/tests/event_handling/advanced/event_queuing.js +104 -0
  38. data/lib/frameworks/sproutcore/frameworks/table/views/table.js +3 -0
  39. data/lib/frameworks/sproutcore/frameworks/template_view/handlebars.js +2 -1
  40. data/lib/frameworks/sproutcore/themes/ace/resources/collection/normal/grid.css +17 -0
  41. data/lib/frameworks/sproutcore/themes/ace/resources/menu/menu.css +1 -0
  42. data/lib/frameworks/sproutcore/themes/ace/resources/menu/menu.png +0 -0
  43. data/lib/frameworks/sproutcore/themes/ace/resources/menu/menu@2x.png +0 -0
  44. data/lib/frameworks/sproutcore/themes/ace/resources/panel/panel.css +2 -2
  45. data/lib/frameworks/sproutcore/themes/empty_theme/theme.js +1 -1
  46. data/lib/sproutcore/tools.rb +2 -1
  47. data/lib/sproutcore/tools/phantom.rb +36 -0
  48. data/sproutcore.gemspec +1 -1
  49. data/vendor/chance/lib/chance/instance.rb +5 -2
  50. metadata +11 -4
@@ -107,6 +107,13 @@ SC.InlineTextFieldView = SC.TextFieldView.extend(SC.InlineEditor,
107
107
  */
108
108
  layout: { height: 0, width: 0 },
109
109
 
110
+ /*
111
+ @private
112
+
113
+ Prevents the view from taking part in child view layout plugins.
114
+ */
115
+ useAbsoluteLayout: YES,
116
+
110
117
  /*
111
118
  * @private
112
119
  * @method
@@ -198,7 +198,18 @@ SC.routes = SC.Object.create(
198
198
  @type {String}
199
199
  */
200
200
  location: function(key, value) {
201
+ var lsk;
201
202
  this._skipRoute = NO;
203
+ if (value !== undefined) {
204
+ // The 'location' and 'informLocation' properties essentially
205
+ // represent a single property, but with different behavior
206
+ // when setting the value. Because of this, we manually
207
+ // update the cached value for the opposite property to
208
+ // ensure they remain in sync. You shouldn't do this in
209
+ // your own code unless you REALLY know what you are doing.
210
+ lsk = this.informLocation.lastSetValueKey;
211
+ if (lsk && this._kvo_cache) this._kvo_cache[lsk] = value;
212
+ }
202
213
  return this._extractLocation(key, value);
203
214
  }.property(),
204
215
 
@@ -207,17 +218,18 @@ SC.routes = SC.Object.create(
207
218
  you want to just change the location w/out triggering the routes
208
219
  */
209
220
  informLocation: function(key, value){
221
+ var lsk;
210
222
  this._skipRoute = YES;
211
- // This is a very special case where this property
212
- // has a very heavy influence on the 'location' property
213
- // this is a case where you might want to use idempotent
214
- // but you would take a performance hit because it is possible
215
- // call set() multiple time and we don't want to take the extra
216
- // cost, so we just invalidate the cached set() value ourselves
217
- // you shouldn't do this in your own code unless you REALLY
218
- // know what you are doing.
219
- var lsk = this.location.lastSetValueKey;
220
- if (lsk && this._kvo_cache) this._kvo_cache[lsk] = value;
223
+ if (value !== undefined) {
224
+ // The 'location' and 'informLocation' properties essentially
225
+ // represent a single property, but with different behavior
226
+ // when setting the value. Because of this, we manually
227
+ // update the cached value for the opposite property to
228
+ // ensure they remain in sync. You shouldn't do this in
229
+ // your own code unless you REALLY know what you are doing.
230
+ lsk = this.location.lastSetValueKey;
231
+ if (lsk && this._kvo_cache) this._kvo_cache[lsk] = value;
232
+ }
221
233
  return this._extractLocation(key, value);
222
234
  }.property(),
223
235
 
@@ -150,6 +150,49 @@ test('Already escaped route', function() {
150
150
  routeWorks('%C3%A9%C3%A0%20%C3%A7%C3%B9%20%C3%9F%E2%82%AC', 'already escaped');
151
151
  });
152
152
 
153
+ module('SC.routes informLocation', {
154
+
155
+ teardown: function() {
156
+ SC.routes.set('informLocation', null);
157
+ }
158
+
159
+ });
160
+
161
+ test('informLocation updates location', function() {
162
+ SC.routes.set('informLocation', 'simple');
163
+ stop();
164
+
165
+ setTimeout(function() {
166
+ equals(SC.routes.get('location'), 'simple');
167
+ start();
168
+ }, 300);
169
+ });
170
+
171
+ test('informLocation and location invalidate each others caches', function() {
172
+ SC.routes.set('location', '');
173
+ stop();
174
+
175
+ setTimeout(function() {
176
+ equals(SC.routes.get('location'), '');
177
+ SC.routes.set('informLocation', 'simple');
178
+
179
+ setTimeout(function() {
180
+ equals(SC.routes.get('location'), 'simple');
181
+ SC.routes.set('location', '');
182
+
183
+ setTimeout(function() {
184
+ equals(SC.routes.get('location'), '');
185
+ SC.routes.set('informLocation', 'simple');
186
+
187
+ setTimeout(function() {
188
+ equals(SC.routes.get('location'), 'simple');
189
+ start();
190
+ }, 300);
191
+ }, 300);
192
+ }, 300);
193
+ }, 300);
194
+ });
195
+
153
196
  module('SC.routes defined routes', {
154
197
 
155
198
  setup: function() {
@@ -59,7 +59,7 @@ window.SproutCore = window.SproutCore || SC;
59
59
  */
60
60
  SC = window.SC; // This is dumb but necessary for jsdoc to get it right
61
61
 
62
- SC.VERSION = '1.10.0';
62
+ SC.VERSION = '1.10.1';
63
63
 
64
64
  /**
65
65
  @private
@@ -948,8 +948,7 @@ SC.mixin(SC.Object.prototype, SC.Observable);
948
948
  through all the top-level properties looking for classes. When it finds
949
949
  one, it saves the class path name.
950
950
  */
951
- function findClassNames() {
952
-
951
+ SC.findClassNames = function () {
953
952
  if (SC._object_foundObjectClassNames) return;
954
953
  SC._object_foundObjectClassNames = true;
955
954
 
@@ -1051,7 +1050,7 @@ SC.kindOf = function (scObject, scClass) {
1051
1050
  */
1052
1051
  SC._object_className = function (obj) {
1053
1052
  if (SC.isReady === NO) return ''; // class names are not available until ready
1054
- if (!obj._object_className) findClassNames();
1053
+ if (!obj._object_className) SC.findClassNames();
1055
1054
  if (obj._object_className) return obj._object_className;
1056
1055
 
1057
1056
  // if no direct classname was found, walk up class chain looking for a
@@ -8,6 +8,15 @@
8
8
  sc_require('ext/function');
9
9
  sc_require('private/observer_set');
10
10
 
11
+
12
+ // When in debug mode, users can log deferred calls (such as .invokeOnce()) by
13
+ // setting SC.LOG_DEFERRED_CALLS. We'll declare the variable explicitly to make
14
+ // life easier for people who want to enter it inside consoles that auto-
15
+ // complete.
16
+ //@if (debug)
17
+ if (!SC.LOG_DEFERRED_CALLS) SC.LOG_DEFERRED_CALLS = false;
18
+ //@endif
19
+
11
20
  /**
12
21
  @class
13
22
 
@@ -27,27 +36,18 @@ sc_require('private/observer_set');
27
36
  This is how you could write your mouseup handler in jQuery:
28
37
 
29
38
  $('#okButton').on('click', function () {
30
- SC.RunLoop.begin();
39
+ SC.run(function () {
31
40
 
32
- // handle click event...
41
+ // handle click event...
33
42
 
34
- SC.RunLoop.end(); // allows bindings to trigger...
43
+ }); // allows bindings to trigger...
35
44
  });
36
45
 
37
46
  @extends SC.Object
38
47
  @since SproutCore 1.0
39
48
  */
40
-
41
-
42
- // When in debug mode, users can log deferred calls (such as .invokeOnce()) by
43
- // setting SC.LOG_DEFERRED_CALLS. We'll declare the variable explicitly to make
44
- // life easier for people who want to enter it inside consoles that auto-
45
- // complete.
46
- //@if (debug)
47
- if (!SC.LOG_DEFERRED_CALLS) SC.LOG_DEFERRED_CALLS = false;
48
- //@endif
49
-
50
- SC.RunLoop = SC.Object.extend(/** @scope SC.RunLoop.prototype */ {
49
+ SC.RunLoop = SC.Object.extend(
50
+ /** @scope SC.RunLoop.prototype */ {
51
51
 
52
52
  /**
53
53
  Call this method whenver you begin executing code.
@@ -174,13 +174,13 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
174
174
  /* BEGIN DEBUG ONLY PROPERTIES AND METHODS */
175
175
 
176
176
  /** @private @property */
177
- allowStatechartTracing: function() {
177
+ allowStatechartTracing: function () {
178
178
  var key = this.get('statechartTraceKey');
179
179
  return this.get(key);
180
180
  }.property().cacheable(),
181
181
 
182
182
  /** @private */
183
- _statechartTraceDidChange: function() {
183
+ _statechartTraceDidChange: function () {
184
184
  this.notifyPropertyChange('allowStatechartTracing');
185
185
  },
186
186
 
@@ -201,13 +201,13 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
201
201
 
202
202
  @returns {Hash}
203
203
  */
204
- details: function() {
204
+ details: function () {
205
205
  var details = {
206
206
  'initialized': this.get('statechartIsInitialized')
207
207
  };
208
208
 
209
209
  if (this.get('name')) {
210
- details['name'] = this.get('name');
210
+ details.name = this.get('name');
211
211
  }
212
212
 
213
213
  if (!this.get('statechartIsInitialized')) {
@@ -215,7 +215,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
215
215
  }
216
216
 
217
217
  details['current-states'] = [];
218
- this.get('currentStates').forEach(function(state) {
218
+ this.get('currentStates').forEach(function (state) {
219
219
  details['current-states'].push(state.get('fullPath'));
220
220
  });
221
221
 
@@ -227,12 +227,12 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
227
227
  if (this._gotoStateActions) {
228
228
  stateTransition['transition-sequence'] = [];
229
229
  var actions = this._gotoStateActions,
230
- actionToStr = function(action) {
230
+ actionToStr = function (action) {
231
231
  var actionName = action.action === SC.ENTER_STATE ? "enter" : "exit";
232
232
  return "%@ %@".fmt(actionName, action.state.get('fullPath'));
233
233
  };
234
234
 
235
- actions.forEach(function(action) {
235
+ actions.forEach(function (action) {
236
236
  stateTransition['transition-sequence'].push(actionToStr(action));
237
237
  });
238
238
 
@@ -265,7 +265,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
265
265
 
266
266
  @see #details
267
267
  */
268
- toStringWithDetails: function() {
268
+ toStringWithDetails: function () {
269
269
  var str = "",
270
270
  header = this.toString(),
271
271
  details = this.get('details');
@@ -277,7 +277,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
277
277
  },
278
278
 
279
279
  /** @private */
280
- _hashToString: function(hash, indent) {
280
+ _hashToString: function (hash, indent) {
281
281
  var str = "";
282
282
 
283
283
  for (var key in hash) {
@@ -298,14 +298,14 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
298
298
  },
299
299
 
300
300
  /** @private */
301
- _arrayToString: function(key, array, indent) {
301
+ _arrayToString: function (key, array, indent) {
302
302
  if (array.length === 0) {
303
303
  return "%@%@: []".fmt(' '.mult(indent), key);
304
304
  }
305
305
 
306
306
  var str = "%@%@: [\n".fmt(' '.mult(indent), key);
307
307
 
308
- array.forEach(function(item, idx) {
308
+ array.forEach(function (item, idx) {
309
309
  str += "%@%@\n".fmt(' '.mult(indent + 2), item);
310
310
  }, this);
311
311
 
@@ -362,7 +362,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
362
362
 
363
363
  NOTE: This is only available in debug mode!
364
364
  */
365
- statechartLogTrace: function(msg) {
365
+ statechartLogTrace: function (msg) {
366
366
  SC.Logger.info("%@: %@".fmt(this.get('statechartLogPrefix'), msg));
367
367
  },
368
368
 
@@ -498,18 +498,18 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
498
498
  @see SC.StatechartDelegate
499
499
  @see #delegate
500
500
  */
501
- statechartDelegate: function() {
501
+ statechartDelegate: function () {
502
502
  var del = this.get('delegate');
503
503
  return this.delegateFor('isStatechartDelegate', del);
504
504
  }.property('delegate'),
505
505
 
506
- initMixin: function() {
506
+ initMixin: function () {
507
507
  if (this.get('autoInitStatechart')) {
508
508
  this.initStatechart();
509
509
  }
510
510
  },
511
511
 
512
- destroyMixin: function() {
512
+ destroyMixin: function () {
513
513
  var root = this.get('rootState');
514
514
 
515
515
  //@if(debug)
@@ -527,7 +527,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
527
527
  Initializes the statechart. By initializing the statechart, it will create all the states and register
528
528
  them with the statechart. Once complete, the statechart can be used to go to states and send events to.
529
529
  */
530
- initStatechart: function() {
530
+ initStatechart: function () {
531
531
  if (this.get('statechartIsInitialized')) return;
532
532
 
533
533
  this._gotoStateLocked = NO;
@@ -599,7 +599,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
599
599
  /**
600
600
  Will create a root state for the statechart
601
601
  */
602
- createRootState: function(state, attrs) {
602
+ createRootState: function (state, attrs) {
603
603
  if (!attrs) attrs = {};
604
604
  state = state.create(attrs);
605
605
  return state;
@@ -610,7 +610,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
610
610
 
611
611
  @returns {Array} the current states
612
612
  */
613
- currentStates: function() {
613
+ currentStates: function () {
614
614
  return this.getPath('rootState.currentSubstates');
615
615
  }.property().cacheable(),
616
616
 
@@ -619,7 +619,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
619
619
 
620
620
  @return {SC.State}
621
621
  */
622
- firstCurrentState: function() {
622
+ firstCurrentState: function () {
623
623
  var cs = this.get('currentStates');
624
624
  return cs ? cs.objectAt(0) : null;
625
625
  }.property('currentStates').cacheable(),
@@ -629,7 +629,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
629
629
 
630
630
  @returns {Number} the count
631
631
  */
632
- currentStateCount: function() {
632
+ currentStateCount: function () {
633
633
  return this.getPath('currentStates.length');
634
634
  }.property('currentStates').cacheable(),
635
635
 
@@ -639,7 +639,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
639
639
  @param state {State|String} the state to check
640
640
  @returns {Boolean} true if the state is a current state, otherwise fals is returned
641
641
  */
642
- stateIsCurrentState: function(state) {
642
+ stateIsCurrentState: function (state) {
643
643
  return this.get('rootState').stateIsCurrentSubstate(state);
644
644
  },
645
645
 
@@ -649,7 +649,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
649
649
 
650
650
  @returns {Array} the currently entered states
651
651
  */
652
- enteredStates: function() {
652
+ enteredStates: function () {
653
653
  return this.getPath('rootState.enteredSubstates');
654
654
  }.property().cacheable(),
655
655
 
@@ -659,7 +659,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
659
659
  @param state {State|String} the state to check
660
660
  @returns {Boolean} true if the state is a currently entered state, otherwise false is returned
661
661
  */
662
- stateIsEntered: function(state) {
662
+ stateIsEntered: function (state) {
663
663
  return this.get('rootState').stateIsEnteredSubstate(state);
664
664
  },
665
665
 
@@ -669,7 +669,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
669
669
  @param value {State|String} either a state object or the name of a state
670
670
  @returns {Boolean} true if the state does belong ot the statechart, otherwise false is returned
671
671
  */
672
- doesContainState: function(value) {
672
+ doesContainState: function (value) {
673
673
  return !SC.none(this.getState(value));
674
674
  },
675
675
 
@@ -679,7 +679,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
679
679
  @param value {State|String} either a state object of the name of a state
680
680
  @returns {State} if a match then the matching state is returned, otherwise null is returned
681
681
  */
682
- getState: function(state) {
682
+ getState: function (state) {
683
683
  var root = this.get('rootState');
684
684
  return root === state ? root : root.getSubstate(state);
685
685
  },
@@ -727,7 +727,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
727
727
  @param useHistory {Boolean} Optional. Indicates whether to include using history states in the transition process
728
728
  @param context {Hash} Optional. A context object that will be passed to all exited and entered states
729
729
  */
730
- gotoState: function(state, fromCurrentState, useHistory, context) {
730
+ gotoState: function (state, fromCurrentState, useHistory, context) {
731
731
  if (!this.get('statechartIsInitialized')) {
732
732
  this.statechartLogError("can not go to state %@. statechart has not yet been initialized".fmt(state));
733
733
  return;
@@ -853,7 +853,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
853
853
  /**
854
854
  Indicates if the statechart is in an active goto state process
855
855
  */
856
- gotoStateActive: function() {
856
+ gotoStateActive: function () {
857
857
  return this._gotoStateLocked;
858
858
  }.property(),
859
859
 
@@ -861,14 +861,14 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
861
861
  Indicates if the statechart is in an active goto state process
862
862
  that has been suspended
863
863
  */
864
- gotoStateSuspended: function() {
864
+ gotoStateSuspended: function () {
865
865
  return this._gotoStateLocked && !!this._gotoStateSuspendedPoint;
866
866
  }.property(),
867
867
 
868
868
  /**
869
869
  Resumes an active goto state transition process that has been suspended.
870
870
  */
871
- resumeGotoState: function() {
871
+ resumeGotoState: function () {
872
872
  if (!this.get('gotoStateSuspended')) {
873
873
  this.statechartLogError("Can not resume goto state since it has not been suspended");
874
874
  return;
@@ -879,7 +879,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
879
879
  },
880
880
 
881
881
  /** @private */
882
- _executeGotoStateActions: function(gotoState, actions, marker, context) {
882
+ _executeGotoStateActions: function (gotoState, actions, marker, context) {
883
883
  var action = null,
884
884
  len = actions.length,
885
885
  actionResult = null;
@@ -889,13 +889,13 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
889
889
  for (; marker < len; marker += 1) {
890
890
  this._currentGotoStateAction = action = actions[marker];
891
891
  switch (action.action) {
892
- case SC.EXIT_STATE:
893
- actionResult = this._exitState(action.state, context);
894
- break;
892
+ case SC.EXIT_STATE:
893
+ actionResult = this._exitState(action.state, context);
894
+ break;
895
895
 
896
- case SC.ENTER_STATE:
897
- actionResult = this._enterState(action.state, action.currentState, context);
898
- break;
896
+ case SC.ENTER_STATE:
897
+ actionResult = this._enterState(action.state, action.currentState, context);
898
+ break;
899
899
  }
900
900
 
901
901
  //
@@ -935,16 +935,18 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
935
935
  },
936
936
 
937
937
  /** @private */
938
- _cleanupStateTransition: function() {
938
+ _cleanupStateTransition: function () {
939
939
  this._currentGotoStateAction = null;
940
940
  this._gotoStateSuspendedPoint = null;
941
941
  this._gotoStateActions = null;
942
942
  this._gotoStateLocked = NO;
943
943
  this._flushPendingStateTransition();
944
+ // Check the flags so we only flush if the events will actually get sent.
945
+ if (!this._sendEventLocked && !this._gotoStateLocked) { this._flushPendingSentEvents(); }
944
946
  },
945
947
 
946
948
  /** @private */
947
- _exitState: function(state, context) {
949
+ _exitState: function (state, context) {
948
950
  var parentState;
949
951
 
950
952
  if (state.get('currentSubstates').indexOf(state) >= 0) {
@@ -991,12 +993,12 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
991
993
  @param state {SC.State} the state whose enterState method is to be invoked
992
994
  @param context {Hash} a context hash object to provide the enterState method
993
995
  */
994
- exitState: function(state, context) {
996
+ exitState: function (state, context) {
995
997
  return state.exitState(context);
996
998
  },
997
999
 
998
1000
  /** @private */
999
- _enterState: function(state, current, context) {
1001
+ _enterState: function (state, current, context) {
1000
1002
  var parentState = state.get('parentState');
1001
1003
  if (parentState && !state.get('isConcurrentState')) parentState.set('historyState', state);
1002
1004
 
@@ -1044,7 +1046,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1044
1046
  @param state {SC.State} the state whose enterState method is to be invoked
1045
1047
  @param context {Hash} a context hash object to provide the enterState method
1046
1048
  */
1047
- enterState: function(state, context) {
1049
+ enterState: function (state, context) {
1048
1050
  if (state.enterStateByRoute && SC.kindOf(context, SC.StateRouteHandlerContext)) {
1049
1051
  return state.enterStateByRoute(context);
1050
1052
  } else {
@@ -1089,7 +1091,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1089
1091
  @param fromCurrentState {SC.State|String} Optional. the current state to start the state transition process from
1090
1092
  @param recursive {Boolean} Optional. whether to follow history states recursively.
1091
1093
  */
1092
- gotoHistoryState: function(state, fromCurrentState, recursive, context) {
1094
+ gotoHistoryState: function (state, fromCurrentState, recursive, context) {
1093
1095
  if (!this.get('statechartIsInitialized')) {
1094
1096
  this.statechartLogError("can not go to state %@'s history state. Statechart has not yet been initialized".fmt(state));
1095
1097
  return;
@@ -1140,7 +1142,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1140
1142
  @see #stateWillTryToHandleEvent
1141
1143
  @see #stateDidTryToHandleEvent
1142
1144
  */
1143
- sendEvent: function(event, arg1, arg2) {
1145
+ sendEvent: function (event, arg1, arg2) {
1144
1146
 
1145
1147
  if (this.get('isDestroyed')) {
1146
1148
  this.statechartLogError("can not send event %@. statechart is destroyed".fmt(event));
@@ -1148,6 +1150,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1148
1150
  }
1149
1151
 
1150
1152
  var statechartHandledEvent = NO,
1153
+ result = this,
1151
1154
  eventHandled = NO,
1152
1155
  currentStates = this.get('currentStates').slice(),
1153
1156
  checkedStates = {},
@@ -1155,7 +1158,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1155
1158
  i = 0,
1156
1159
  state = null;
1157
1160
 
1158
- if (this._sendEventLocked || this._goStateLocked) {
1161
+ if (this._sendEventLocked || this._gotoStateLocked) {
1159
1162
  // Want to prevent any actions from being processed by the states until
1160
1163
  // they have had a chance to handle the most immediate action or completed
1161
1164
  // a state transition
@@ -1184,8 +1187,8 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1184
1187
  if (!state.get('isCurrentState')) continue;
1185
1188
  while (!eventHandled && state) {
1186
1189
  if (!checkedStates[state.get('fullPath')]) {
1187
- eventHandled = state.tryToHandleEvent(event, arg1, arg2);
1188
- checkedStates[state.get('fullPath')] = YES;
1190
+ eventHandled = state.tryToHandleEvent(event, arg1, arg2);
1191
+ checkedStates[state.get('fullPath')] = YES;
1189
1192
  }
1190
1193
  if (!eventHandled) state = state.get('parentState');
1191
1194
  else statechartHandledEvent = YES;
@@ -1203,7 +1206,13 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1203
1206
  }
1204
1207
  //@endif
1205
1208
 
1206
- var result = this._flushPendingSentEvents();
1209
+ // Check if the flags are unlocked. These means any pending events
1210
+ // will successfully send, so go ahead and flush. Otherwise, events
1211
+ // would become out of order since the first event would get shifted,
1212
+ // then pushed.
1213
+ if (!this._sendEventLocked && !this._gotoStateLocked) {
1214
+ result = this._flushPendingSentEvents();
1215
+ }
1207
1216
 
1208
1217
  return statechartHandledEvent ? this : (result ? this : null);
1209
1218
  },
@@ -1216,7 +1225,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1216
1225
  @param {String} event the event the state will try to handle
1217
1226
  @param {String} handler the name of the method on the state that will try to handle the event
1218
1227
  */
1219
- stateWillTryToHandleEvent: function(state, event, handler) {
1228
+ stateWillTryToHandleEvent: function (state, event, handler) {
1220
1229
  this._stateHandleEventInfo = {
1221
1230
  state: state,
1222
1231
  event: event,
@@ -1233,7 +1242,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1233
1242
  @param {String} handler the name of the method on the state that did try to handle the event
1234
1243
  @param {Boolean} handled indicates if the handler was able to handle the event
1235
1244
  */
1236
- stateDidTryToHandleEvent: function(state, event, handler, handled) {
1245
+ stateDidTryToHandleEvent: function (state, event, handler, handled) {
1237
1246
  this._stateHandleEventInfo = null;
1238
1247
  },
1239
1248
 
@@ -1242,7 +1251,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1242
1251
  Creates a chain of states from the given state to the greatest ancestor state (the root state). Used
1243
1252
  when perform state transitions.
1244
1253
  */
1245
- _createStateChain: function(state) {
1254
+ _createStateChain: function (state) {
1246
1255
  var chain = [];
1247
1256
 
1248
1257
  while (state) {
@@ -1259,10 +1268,10 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1259
1268
  go from being exited to states being entered during the state transition process. The value
1260
1269
  returned is the fist matching state between the two given state chains.
1261
1270
  */
1262
- _findPivotState: function(stateChain1, stateChain2) {
1271
+ _findPivotState: function (stateChain1, stateChain2) {
1263
1272
  if (stateChain1.length === 0 || stateChain2.length === 0) return null;
1264
1273
 
1265
- var pivot = stateChain1.find(function(state, index) {
1274
+ var pivot = stateChain1.find(function (state, index) {
1266
1275
  if (stateChain2.indexOf(state) >= 0) return YES;
1267
1276
  });
1268
1277
 
@@ -1279,7 +1288,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1279
1288
  @param exitStatePath {Array} an array representing a path of states that are to be exited
1280
1289
  @param stopState {State} an explicit state in which to stop the exiting process
1281
1290
  */
1282
- _traverseStatesToExit: function(state, exitStatePath, stopState, gotoStateActions) {
1291
+ _traverseStatesToExit: function (state, exitStatePath, stopState, gotoStateActions) {
1283
1292
  if (!state || state === stopState) return;
1284
1293
 
1285
1294
  // This state has concurrent substates. Therefore we have to make sure we
@@ -1316,7 +1325,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1316
1325
  @param pivotState {State} The state pivoting when to go from exiting states to entering states
1317
1326
  @param useHistory {Boolean} indicates whether to recursively follow history states
1318
1327
  */
1319
- _traverseStatesToEnter: function(state, enterStatePath, pivotState, useHistory, gotoStateActions) {
1328
+ _traverseStatesToEnter: function (state, enterStatePath, pivotState, useHistory, gotoStateActions) {
1320
1329
  if (!state) return;
1321
1330
 
1322
1331
  // We do not want to enter states in the enter path until the pivot state has been reached. After
@@ -1387,7 +1396,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1387
1396
  @param event {String} the property name to check
1388
1397
  @returns {Boolean}
1389
1398
  */
1390
- respondsTo: function(event) {
1399
+ respondsTo: function (event) {
1391
1400
  // Fast path!
1392
1401
  if (this.get('isDestroyed')) {
1393
1402
  this.statechartLogError("can not respond to event %@. statechart is destroyed".fmt(event));
@@ -1421,7 +1430,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1421
1430
  @param arg2 {Object} Optional
1422
1431
  @returns {Boolean} YES if handled, NO if not handled
1423
1432
  */
1424
- tryToPerform: function(event, arg1, arg2) {
1433
+ tryToPerform: function (event, arg1, arg2) {
1425
1434
  if (!this.respondsTo(event)) return NO;
1426
1435
 
1427
1436
  if (SC.typeOf(this[event]) === SC.T_FUNCTION) {
@@ -1461,7 +1470,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1461
1470
  we want to call a calculate method on the current states where the method
1462
1471
  will return a value when invoked. We can handle the returned values like so:
1463
1472
 
1464
- invokeStateMethod('calculate', value, function(state, result) {
1473
+ invokeStateMethod('calculate', value, function (state, result) {
1465
1474
  // .. handle the result returned from calculate that was invoked
1466
1475
  // on the given state
1467
1476
  })
@@ -1483,7 +1492,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1483
1492
  is returned. The value is the result of the method that got invoked
1484
1493
  on a state.
1485
1494
  */
1486
- invokeStateMethod: function(methodName, args, func) {
1495
+ invokeStateMethod: function (methodName, args, func) {
1487
1496
  if (methodName === 'unknownEvent') {
1488
1497
  this.statechartLogError("can not invoke method unkownEvent");
1489
1498
  return;
@@ -1496,8 +1505,10 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1496
1505
  arg = len > 0 ? args[len - 1] : null,
1497
1506
  callback = SC.typeOf(arg) === SC.T_FUNCTION ? args.pop() : null,
1498
1507
  currentStates = this.get('currentStates'),
1499
- i = 0, state = null, checkedStates = {},
1500
- method, result = undefined, calledStates = 0;
1508
+ i = 0, state = null,
1509
+ checkedStates = {},
1510
+ method, result,
1511
+ calledStates = 0;
1501
1512
 
1502
1513
  len = currentStates.get('length');
1503
1514
 
@@ -1524,7 +1535,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1524
1535
 
1525
1536
  Iterate over all the given concurrent states and enter them
1526
1537
  */
1527
- _traverseConcurrentStatesToEnter: function(states, exclude, useHistory, gotoStateActions) {
1538
+ _traverseConcurrentStatesToEnter: function (states, exclude, useHistory, gotoStateActions) {
1528
1539
  var i = 0,
1529
1540
  len = states.length,
1530
1541
  state = null;
@@ -1540,7 +1551,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1540
1551
  Called by gotoState to flush a pending state transition at the front of the
1541
1552
  pending queue.
1542
1553
  */
1543
- _flushPendingStateTransition: function() {
1554
+ _flushPendingStateTransition: function () {
1544
1555
  if (!this._pendingStateTransitions) {
1545
1556
  this.statechartLogError("Unable to flush pending state transition. _pendingStateTransitions is invalid");
1546
1557
  return;
@@ -1555,7 +1566,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1555
1566
  Called by sendEvent to flush a pending actions at the front of the pending
1556
1567
  queue
1557
1568
  */
1558
- _flushPendingSentEvents: function() {
1569
+ _flushPendingSentEvents: function () {
1559
1570
  var pending = this._pendingSentEvents.shift();
1560
1571
  if (!pending) return null;
1561
1572
  return this.sendEvent(pending.event, pending.arg1, pending.arg2);
@@ -1563,7 +1574,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1563
1574
 
1564
1575
  /** @private */
1565
1576
  //@if(debug)
1566
- _monitorIsActiveDidChange: function() {
1577
+ _monitorIsActiveDidChange: function () {
1567
1578
  if (this.get('monitorIsActive') && SC.none(this.get('monitor'))) {
1568
1579
  this.set('monitor', SC.StatechartMonitor.create());
1569
1580
  }
@@ -1576,19 +1587,19 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1576
1587
  TODO: Come back to this and refactor the code. It works, but it
1577
1588
  could certainly be improved
1578
1589
  */
1579
- _processGotoStateArgs: function(args) {
1590
+ _processGotoStateArgs: function (args) {
1580
1591
  var processedArgs = {
1581
- state: null,
1582
- fromCurrentState: null,
1583
- useHistory: false,
1584
- context: null
1585
- },
1586
- len = null,
1587
- value = null;
1592
+ state: null,
1593
+ fromCurrentState: null,
1594
+ useHistory: false,
1595
+ context: null
1596
+ },
1597
+ len = null,
1598
+ value = null;
1588
1599
 
1589
1600
  args = SC.$A(args);
1590
- args = args.filter(function(item) {
1591
- return !(item === undefined);
1601
+ args = args.filter(function (item) {
1602
+ return item !== undefined;
1592
1603
  });
1593
1604
  len = args.length;
1594
1605
 
@@ -1647,7 +1658,7 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1647
1658
  - There must be one or more states that can be added to the root state
1648
1659
 
1649
1660
  */
1650
- _constructRootStateClass: function() {
1661
+ _constructRootStateClass: function () {
1651
1662
  var rsExampleKey = 'rootStateExample',
1652
1663
  rsExample = this.get(rsExampleKey),
1653
1664
  initialState = this.get('initialState'),
@@ -1700,27 +1711,27 @@ SC.StatechartManager = /** @scope SC.StatechartManager.prototype */{
1700
1711
  },
1701
1712
 
1702
1713
  /** @private */
1703
- _logStatechartCreationError: function(msg) {
1714
+ _logStatechartCreationError: function (msg) {
1704
1715
  SC.Logger.error("Unable to create statechart for %@: %@.".fmt(this, msg));
1705
1716
  },
1706
1717
 
1707
1718
  /**
1708
1719
  Used to log a statechart error message
1709
1720
  */
1710
- statechartLogError: function(msg) {
1721
+ statechartLogError: function (msg) {
1711
1722
  SC.Logger.error("ERROR %@: %@".fmt(this.get('statechartLogPrefix'), msg));
1712
1723
  },
1713
1724
 
1714
1725
  /**
1715
1726
  Used to log a statechart warning message
1716
1727
  */
1717
- statechartLogWarning: function(msg) {
1728
+ statechartLogWarning: function (msg) {
1718
1729
  if (this.get('suppressStatechartWarnings')) return;
1719
1730
  SC.Logger.warn("WARN %@: %@".fmt(this.get('statechartLogPrefix'), msg));
1720
1731
  },
1721
1732
 
1722
1733
  /** @property */
1723
- statechartLogPrefix: function() {
1734
+ statechartLogPrefix: function () {
1724
1735
  var className = SC._object_className(this.constructor),
1725
1736
  name = this.get('name'), prefix;
1726
1737