frozencanuck / ki Goto Github PK
View Code? Open in Web Editor NEWA Statechart Framework for SproutCore
Home Page: http://frozencanuck.wordpress.com
License: Other
A Statechart Framework for SproutCore
Home Page: http://frozencanuck.wordpress.com
License: Other
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
+});
This works:
valueBinding: SC.Binding.transform(function() {
return "State: " + App.statechart.get('currentStates').map(function(state) { return state.get('fullPath'); }).join(', ');
}).from('App.statechart.firstCurrentState')
This does not:
valueBinding: SC.Binding.transform(function(currentStates) {
return "State: " + currentStates.map(function(state) { return state.get('fullPath'); }).join(', ');
}).from('App.statechart.currentStates')
I would expect currentStates
to be observable for changes the same way that firstCurrentState
is.
Will there be a more solid documentation soon on how to use it.
Would be great to read some tutorials and create some example apps.
Hi
I am using ExtJS and really miss the Ki framework.
Is there any change Ki could be used with ExtJS if I include the Sproutcore js files into the frontend?
/Johnny
How do I share a variable between enterState() and exitState() because when entered I want to create an object that is destroyed on exit.
Is there a way or do I have to use a global variable?
render() should be state-aware when Ki.StatechartManager is used in views.
A default render() implementation would dispatch to the view's statechart. (It can easily be overridden by simply implementing render() in the view.)
There are two approaches to dispatching render(). The first (and simplest) is to treat render() like any other actions, and have the deepest state that responds to render() handle it.
The second approach is to walk the hierarchy from root to leaf, in order, giving each state a chance to "render", and then walk it backwards (tags need to be closed). This is more consistent with how states are actually used to render(), and would promote code reuse.
(It would also be nice if, following a state transition, if the state implements render(), if this.displayDidChange() were called automatically.)
Feel free to discuss this further; I'm still working things out (though a solution is necessary).
Why can't I have a parent state that happens to have substates but is also itself a full fledged state?
Currently it's like this:
* SHOW_CONTACTS
* CREATE_CONTACT - Create contact pane pops up
* EDIT_CONTACT - Edit contact pane pops up
When I really just want this:
* CREATE_CONTACT - Create contact pane pops up
* EDIT_CONTACT - Edit contact pane pops up
According to the API I can send arguments to an event:
mainStatechart.sendEvent("showView", sender, context)
But is it possible to send arguments to a state?
this.gotoState("SHOWING_VIEW", fromCurrentState, useHistory)
/Johnny
Are there philosophical objections to sending along a context with gotoState that enterState could use? E.g.:
gotoState: function(state, fromCurrentState, useHistory) {
Becomes:
gotoState: function(state, fromCurrentState, context, useHistory) {
Then:
enterState: function (context) {
This would help us simplify a lot of things.
Line #837 in Statechart.js needs this safety check when creating a statechart on the fly....
I've read your wiki page about history states.
It seems that one state can hold one history state (the substate that was last entered) right?
Is it possible to "log" all states that were entered so it would be like a browser's BACK and FORWARD button, jumping through all states you have been in?
Because now it seems that I can only jump back ONE state.
When I goto a state with gotoState() I get:
ERROR Ki.Statechart: Can not go to state Ki.State<sessionState.checkingUserSession.route1, sc704>. Pivot state Ki.State<ROOT_STATE, sc695> has concurrent substates.
Is there a way to work around this?
With the latest Ki I must still notifyPropertyChange('isCurrentState') on my state's enterState/exitState to notify things bound to isCurrentState. It appears isCurrentState is still a .property() that doesn't observe anything:
isCurrentState: function() {
return this.stateIsCurrentSubstate(this);
}.property()
But the inverse (moving from a parent state to a substate invoking exitState) isn't true. This wreaks havoc if you're doing complimentary things in those methods.
I have set some variables in one state and when i goto another state I want the new state to be able to access the previous set variables.
Is it possible to pass arguments to events and states?
If I goto a parent state that has sub states, does the enterState() of the parent state get fired first and then the sub states enterState() or do they fire asynchronously?
It seems that it's only possible to pass a hash {} as second argument in gotoState().
If I pass a string or a SC object it says:
"ERROR Ki.Statechart: Can not to goto state Ki.State<session.checkingIfUserIsSignedInAtYi, sc862>. Main.Ki.StateResponse:sc889 is not a recognized current state in statechart"
Is this a bug? It would be good to be able to pass strings, number, arrays but mostly I want to pass a SC object.
Thanks.
I've got a mixin that I use that allows easy additions of observers in the statechart to fire state events when observed value changes.
https://gist.github.com/4cdb482c27eb896e632d
This can be used like:
https://gist.github.com/63c790db4883498578ca
This would be a neat addition. One question would be, should it be using sendEvent
or invokeStateMethod
in the addStatechartObserver method?
I think the developer does not have to choose between gotoState() or gotoHistoryState(). It is up to the statechart manager to handle that.
Adding two booleans to Ki.state could avoid the use of the method gotoHistoryState() :
A: Ki.State.design({
initialSubstate: 'A1',
/** PROPOSAL **/
history: YES,
historyRecursive: NO,
A1: Ki.State.design({
}),
A2: Ki.State.design({
}),
}),
Hi, I set a state to have 2 current sub states. When an event happen but is handled by the parent state (not by the sub states), it receive the event 2 times. It would be nice to have an option to deactivate the event forward to the parent state. Let's say a new property named "isFowardingEvent" is NO on a state, it handle the event but do not forward it if the handler method is missing.
In my example, only one of my sub state should have isFowardingEvent set to NO. The other will still forward the event to make sure the parent event receive the event.
Does it make any sense ?
Hi, how is Ki working with the new Sproutcore-Handlebars?
Now when you can have states in the view's im wondering when you would want to have them in the views instead of in the statechart.
Eg. I have a TabView with 4 page views ... when I switch page I want to enter that page's state. Is it possible/correct to put those states in the page views instead of the statechart?
This would be kinda like a better approach in my mind, because now my statechart is actually only mirroring the structure of the views and as the application grows it becomes easily unmanageable and I have to play detective and keep the mapping between the statechart and the views hierarchy updated.
It's kinda radical but if I move the whole statechart structure out to the views, this mapping problem seems to be solved. But I would like to know if this is one of the way I should use the new states in the views API for.
The specification does not require an initial substate (you can been in a parent state without being in any substate) and a number of widely used statechart patterns require this behavior.
Ki should allow a state with substates to not define initialSubstate. Currently, it throws an error.
Right now I can't make a binding to isCurrentState because it's not re-fired once the state does become the current state since it's just a .property().
I'm using Ki with sproutcore where I'm having a lot of independent modules with their own states.
I wonder how I could dynamically add one module's states in the current statechart?
Thanks.
While following the documentation in the state chart manager class upon firing up a brand new SC app this is the exception thrown in the console..
While using Master (f410bde) today, we ran into a bug where calling .currentStates() would always return an array of length 1, and the only state being the deepest (not any of the parent states)
Is this expected behaviour? if so, is there a way to get a list of the state tree leading upto the current state? or do I just need to loop through state = state.parentState
until I find the one I want?
I wonder, from the view of the GUI/Statechart, what are the differences between initialSubstate and substatesAreConcurrent?
/Johnny
Is it possible to split the statechart into different files?
Eg one for each state.
Thanks.
I have these states:
I always enter either SHOWING_PAGE_ONE or SHOWING_PAGE_TWO.
When I enter SHOWING_MENU_PANE and then close it I want to go back to previous state. How do I tell Ki which one of SHOWING_PAGE_ONE and SHOWING_PAGE_TWO was the previous state?
I could of course use currentStates each time I'm in a state and push it to an array to save the information.
But I wonder if there is another way of doing this with Ki? Has this to do with History states?
/Johnny
I have a simple statechart used for authentication. It has one root state, with multiple substates such as 'loggedIn'.
If the statechart is currently in state 'loggedIn' and i call gotoState('loggedIn'), it runs exitState() and enterState() for the 'loggedIn' state, which seems like the wrong behaviour: if the statechart is already in that state it shouldn't run any state transitions!
This means that in our code, we always have to check that the current state isnt equal to the one we are transitioning to, in order not to run any superfluous transitions.
I wonder if Ki works with Node.js?
If it does, how do I include it?
Thanks.
This won't remove any functionality, but it will allow us to use the Ki.Statechart name where it is most likely to be used: as a mixin on an existing class (especially, views or the main app object in core.js).
The existing Ki.Statechart class behavior can easily be restored with SC.Object.create(Ki.Statechart, {
});
P.s. I'd especially like to see this change made in SproutCore 1.5.
HI!
statechart.sendEvent is silently handling all exceptions.
} catch (ex) { /** Gobal the exception and move on */ }
Shouldn't this exceptions be thrown and available for: SC.ExceptionHandler.handleException() to process?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.