FrozenCanuck / Ki

A Statechart Framework for SproutCore
http://frozencanuck.wordpress.com
Other
105 stars 7 forks source link

Statecharts and SC.routes #29

Open netom opened 13 years ago

netom commented 13 years ago

I've made a patch to ki to enable adding a "route" hash property to State objects. Based on this property the State init() does SC.routes.add, so the router can trigger gotoState or sendEvent (based on this "route" property).

I've added a setLocation('optional location string') to make easy to set browser location based on the state's "route" property.

Example: ... rootState: Ki.State.design({

initialSubstate: 'routing',

routing: Ki.State.design({
  // Router will generate the events necessary to go on from here.
}),

// Transient state, determine login status
start: Ki.State.design({
  // Default route
  route: {
    match: ''
  },

  enterState: function() {
    // Set the location to reflect the route to this state
    this.setLocation();
    this.gotoState('loginS');
  }
}),
...

Patch:

diff --git a/frameworks/foundation/system/state.js b/frameworks/foundation/system/state.js
index 927fd5a..5103fab 100644
--- a/frameworks/foundation/system/state.js
+++ b/frameworks/foundation/system/state.js
@@ -92,6 +92,24 @@ Ki.State = SC.Object.extend({
   */
   currentSubstates: null,

+  
+  /**
+    An object that identifies the route belongs to this state.
+   
+    Example:
+    {
+      match: 'users',
+      event: 'showUsers',
+      order: 3
+    }
+    
+    If event is not given, then router will use gotoState
+    instead of sendEvent on the statechart.
+    
+    Lower order routes matched first.
+   */
+  route: null,
+  
   /** 
     Indicates if this state should trace actions. Useful for debugging
     purposes. Managed by the statechart.
@@ -121,6 +139,35 @@ Ki.State = SC.Object.extend({
     return owner ? owner : sc;
   }.property().cacheable(),

+  /**
+    Callback for SC.routes
+    
+    This function gets called if a route that was assigned to this event
+    matches the hash url part.
+   */
+  _handleRoute: function() {
+    var sc = this.get('statechart')
+    if (this.route.event) {
+      sc.sendEvent(this.route.event);
+    } else {
+      sc.gotoState(this.name);
+    }
+  },
+
+  /**
+    Sets browser location
+   
+    Sets the browser location hash part based on the given argument
+    or  - if it's not given - the route propery of the state.
+   */
+  setLocation: function(location) {
+    if (!location) {
+      SC.routes.set('location', this.route.match);
+    } else {
+      SC.routes.set('location', location);
+    }
+  },
   init: function() {
     sc_super();

@@ -138,6 +185,10 @@ Ki.State = SC.Object.extend({
       sc.addObserver(ownerKey, this, '_statechartOwnerDidChange');
       sc.addObserver(traceKey, this, '_statechartTraceDidChange');
     }
+    
+    if (this.route) {
+      SC.routes.add(this.route.match, this, '_handleRoute');
+    }
   },

   destroy: function() {
@@ -1060,4 +1111,4 @@ Ki.EmptyState = Ki.State.extend({
     this.stateLogWarning("No initial substate was defined for state %@. Entering default empty state".fmt(this.get('parentState')));
   }

-});
\ No newline at end of file
+});
FrozenCanuck commented 13 years ago

Awesome :-). Could you also include unit tests for this. Thanks.

netom commented 13 years ago

I have to admit that I having hard time writing proper for this functionality. My problem is that routing is sooo deep inside SC that I can't imagine writing a unit test without writing a dummy-router. My problem with this is that it'd make the unit test so complicated and closely coupled with the SC routing, that it'd lose its purpose.

Any thoughts on this?

On 28 March 2011 18:58, FrozenCanuck reply@reply.github.com wrote:

Awesome :-). Could you also include unit tests for this. Thanks.

Reply to this email directly or view it on GitHub: https://github.com/FrozenCanuck/Ki/issues/29#comment_926955