In response to https://gist.github.com/AdrianRossouw/0d6d49702a64e22b7541
Backbone = require 'backbone'
state = require 'state'
Router = require './router'
module.exports = class Application
constructor: ->
@router = null
state this, require './state-machine'{ pathToUrl, urlToPath } = require './util'
module.exports = state
methods:
getUrl: -> pathToUrl @state().path()
setUrl: -> @router.navigate @getUrl(), trigger: no
urlState: (url) -> @state().go urlToPath url
events:
noSuchMethod: (name) ->
# Just for fun let’s be strict about invalid method calls.
throw new Error "No such method '#{name}' in state '#{@state()}'"Instead of the awkward bit in router.js where we rig up listenForArrive to each state, I’ll just delegate the arrive event once at the root.
The event delegation feature is still only on
master… I’ve notnpm version’d in quite awhile 😐 … and I forget what I was waiting on … probably oughtta just bump it as-is.
'***:arrive': -> do @setUrl; do @showHere I have a special, sort-of-hidden exit-only initial state in which to contain the start method. This makes start impossible to call more than once by definition.
_incipient: state 'initial',
admit: no
start: ->Instead of '$state' I’m keying this (instance of Application) to 'app'.
@router = new Router app: thisInstead of an explicit this.show() call here, I do an initial this.state().go('...') call. This leads to the delegated arrive handler above, which performs the initial this.show() call for us.
@state().go 'home' # or wherever the “real” start state should be
do Backbone.History.start
returnDo we want to accommodate the / route? Then we should probably leave the root state concrete (i.e. as-is, not abstract) and implement a show method for the root.
show: -> # renderOr do we want the root to redirect to home? If so then we should make the root state abstract, and make the home state default.
home: state 'default',
show: -> # render
about: state
show: ->
team: state
show: ->
# etc.module.exports = class Router extends Backbone.RouterAwkwardness begone! … all that remains of initialize is the Application instance.
initialize: (opts) ->
@app = opts.appMaybe there’s a cleaner way to deal with this routing table stuff too … hmm …
routes:
'*state': 'goState'
goState: (stateName) -> @app.urlState stateName… might it help to override Backbone.Router.prototype.route?
I wonder also how evil it'd be to pull a state( Backbone.Router.prototype, {} ) or similar … since, really, the app’s “navigational state machine” is the router itself.
Yeah, this is cool!
Let's take a quick look at what features we needed for this.