Skip to content

Instantly share code, notes, and snippets.

@Tronix117
Last active December 31, 2015 01:59
Show Gist options
  • Save Tronix117/7917925 to your computer and use it in GitHub Desktop.
Save Tronix117/7917925 to your computer and use it in GitHub Desktop.
Chaplin Smart Navigation. smartNavigate will automatically select and trigger the best route using only given route parameters
# Chaplin Smart Navigation
#
# Chaplin.mediator.smartNavigate params, options
#
# Add a smartNavigate method to Chaplin.mediator, it will automaticaly select
# the best route using only route params in first argument.
#
# Keep automaticaly current route params, except if they are explicitely set to
# null or if `reset: true` is passed as second argument.
#
# Exemple:
#
# First, don't forget to require this file before Application is initialized.
#
# Then, simply add an option `smart: true` on each route that should benefit
# from smart navigation.
#
# `routes.coffee` exemple:
# ...
# match '/posts' , 'posts#show', smart: true
# match '/posts/:postId' , 'posts#show', smart: true
# match '/users/:userId/posts' , 'user#show' , smart: true
# match '/users/:userId/posts/:postId', 'posts#show', smart: true
# ...
#
# Now you can call Chaplin.mediator.smartNavigate wherever you want:
# # Following methods are called in this specific order
#
# Chaplin.mediator.smartNavigate userId: 12
# # -> will trigger '/users/12/posts'
#
# Chaplin.mediator.smartNavigate postId: 23
# # -> will trigger '/users/12/posts/23'
#
# Chaplin.mediator.smartNavigate userId: null
# # -> will trigger '/posts/23'
#
# Chaplin.mediator.smartNavigate()
# # -> will trigger '/posts/23' again
#
# Chaplin.mediator.smartNavigate null, reset: true
# # -> will trigger '/posts'
#
# Magic! Just make sure two routes doesn't have the same set of params.
#
# @author Jeremy Trufier <[email protected]> (https://github.com/Tronix117)
# @license MIT
# -------------------------------------
mediator = module.exports = Chaplin.mediator
# Will keep an history of last know route parameters
mediator.lastRouteParams = {}
# Register smart route using sorted paramNames as key, format of key is:
# `paramsName0|paramsNameA|paramsNameB|paramsNameC`
mediator._smartRoutes = {}
# Subscribe to the global event that match routes, before controller get called
mediator.subscribe 'router:match', (route, actionParams, options)->
mediator.lastRouteParams = actionParams
# Override match method of the Router to get routes as they are created
Chaplin.Router.prototype._match = Chaplin.Router.prototype.match
Chaplin.Router.prototype.match = ->
# Call the former method, which will create the route
route = Chaplin.Router.prototype._match.apply @, arguments
# if the route as the `smart` option, then we can use it
if route.options.smart
# Format the route as _smartRoutes expects
sortedParams = route.paramNames.slice().sort().join('|')
# Make sure no two routes use same params to avoid development mistakes
if mediator._smartRoutes[sortedParams]
throw new Error "router#match: smart routes must have unique params set. \
Route <#{route.name}> and <#{mediator._smartRoutes[sortedParams].name}> have \
the same params set"
# Finaly save this route for smart use
mediator._smartRoutes[sortedParams] = route
# Finaly return the route like former method does
route
# Keep last known parameters when navigate, eventually add new ones, remove
# `null` ones and select the best route for those parameters.
#
# `options` may contain following:
# reset: if true only new parameters will be kept, old ones will be removed
mediator.smartNavigate = (params = {}, options = {})->
# Add lastRouteParams to params unless reset option is true
params = _.extend {}, mediator.lastRouteParams, params unless options.reset
# Get list of params key for params that contain a value and format it as
# _smartRoutes expects
keys = _.compact((key if val) for key, val of params).sort().join('|')
# Retrieve the best route using params
unless route = mediator._smartRoutes[keys]
throw new Error 'mediator#smartNavigate: request was not smart routed'
# Finaly trigger the route
mediator.execute 'router:route', route.name, params
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment