Skip to content

Statecharts and SC.routes #29

@netom

Description

@netom

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
+});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions