'use strict'
_ = require 'underscore'
Backbone = require 'backbone'
mediator = require 'chaplin/mediator'
utils = require 'chaplin/lib/utils'
EventBroker = require 'chaplin/lib/event_broker'
module.exports = class Dispatcher'use strict'
_ = require 'underscore'
Backbone = require 'backbone'
mediator = require 'chaplin/mediator'
utils = require 'chaplin/lib/utils'
EventBroker = require 'chaplin/lib/event_broker'
module.exports = class DispatcherBorrow the static extend method from Backbone.
@extend = Backbone.Model.extendMixin an EventBroker.
_.extend @prototype, EventBrokerThe previous route information. This object contains the controller name, action, path, and name (if any).
previousRoute: nullThe current controller, route information, and parameters. The current route object contains the same information as previous.
currentController: null
currentRoute: null
currentParams: null
currentQuery: null
constructor: ->
@initialize arguments...
initialize: (options = {}) ->Merge the options.
@settings = _.defaults options,
controllerPath: 'controllers/'
controllerSuffix: '_controller'Listen to global events.
@subscribeEvent 'router:match', @dispatchThe standard flow is:
dispatch: (route, params, options) ->Clone params and options so the original objects remain untouched.
params = if params then _.extend {}, params else {}
options = if options then _.extend {}, options else {}null or undefined query parameters are equivalent to an empty hash
options.query = {} if not options.query?Whether to force the controller startup even if current and new controllers and params match Default to false unless explicitly set to true.
options.forceStartup = false unless options.forceStartup is trueStop if the desired controller/action is already active with the same params.
return if not options.forceStartup and
@currentRoute?.controller is route.controller and
@currentRoute?.action is route.action and
_.isEqual(@currentParams, params) and
_.isEqual(@currentQuery, options.query)Fetch the new controller, then go on.
@loadController route.controller, (Controller) =>
@controllerLoaded route, params, options, ControllerLoad the constructor for a given controller name. The default implementation uses require() from a AMD module loader like RequireJS to fetch the constructor.
loadController: (name, handler) ->
fileName = name + @settings.controllerSuffix
moduleName = @settings.controllerPath + fileName
if define?.amd
require [moduleName], handler
else
setTimeout =>
handler require moduleName
, 0Handler for the controller lazy-loading.
controllerLoaded: (route, params, options, Controller) ->
if @nextPreviousRoute = @currentRoute
previous = _.extend {}, @nextPreviousRoute
previous.params = @currentParams if @currentParams?
delete previous.previous if previous.previous
prev = {previous}
@nextCurrentRoute = _.extend {}, route, prev
controller = new Controller params, @nextCurrentRoute, options
@executeBeforeAction controller, @nextCurrentRoute, params, optionsExecutes controller action.
executeAction: (controller, route, params, options) ->Dispose the previous controller.
if @currentControllerNotify the rest of the world beforehand.
@publishEvent 'beforeControllerDispose', @currentControllerPassing new parameters that the action method will receive.
@currentController.dispose params, route, optionsSave the new controller and its parameters.
@currentController = controller
@currentParams = params
@currentQuery = options.queryCall the controller action with params and options.
controller[route.action] params, route, optionsStop if the action triggered a redirect.
return if controller.redirectedWe're done! Spread the word!
@publishEvent 'dispatcher:dispatch', @currentController,
params, route, optionsExecutes before action filterer.
executeBeforeAction: (controller, route, params, options) ->
before = controller.beforeAction
executeAction = =>
if controller.redirected or @currentRoute and route is @currentRoute
@nextPreviousRoute = @nextCurrentRoute = null
controller.dispose()
return
@previousRoute = @nextPreviousRoute
@currentRoute = @nextCurrentRoute
@nextPreviousRoute = @nextCurrentRoute = null
@executeAction controller, route, params, options
unless before
executeAction()
returnThrow deprecation warning.
if typeof before isnt 'function'
throw new TypeError 'Controller#beforeAction: function expected. ' +
'Old object-like form is not supported.'Execute action in controller context.
promise = controller.beforeAction params, route, options
if promise and promise.then
promise.then executeAction
else
executeAction() disposed: false
dispose: ->
return if @disposed
@unsubscribeAllEvents()
@disposed = trueYou’re frozen when your heart’s not open.
Object.freeze? this