'use strict''use strict'Third-party libraries.
_ = require 'underscore'
Backbone = require 'backbone'JavaScript classes which are instantiated with new
Dispatcher = require 'chaplin/dispatcher'
Layout = require 'chaplin/views/layout'
Composer = require 'chaplin/composer'
Router = require 'chaplin/lib/router'A mix-in that should be mixed to class.
EventBroker = require 'chaplin/lib/event_broker'Independent global event bus that is used by itself, so lowercased.
mediator = require 'chaplin/mediator'The bootstrapper is the entry point for Chaplin apps.
module.exports = class ApplicationBorrow the extend method from a dear friend.
@extend = Backbone.Model.extendMixin an EventBroker for publish/subscribe functionality.
_.extend @prototype, EventBrokerSite-wide title that is mapped to HTML title tag.
title: ''The application instantiates three core modules:
dispatcher: null
layout: null
router: null
composer: null
started: false
constructor: (options = {}) ->
@initialize options
initialize: (options = {}) ->Check if app is already started.
if @started
throw new Error 'Application#initialize: App was already started'Register all routes. You might pass Router/History options as the second parameter. Chaplin enables pushState per default and Backbone uses / as the root per default. You might change that in the options if necessary: @initRouter routes, pushState: false, root: '/subdir/'
@initRouter options.routes, optionsDispatcher listens for routing events and initialises controllers.
@initDispatcher optionsLayout listens for click events & delegates internal links to router.
@initLayout optionsComposer grants the ability for views and stuff to be persisted.
@initComposer optionsMediator is a global message broker which implements pub / sub pattern.
@initMediator()Start the application.
@start()Chaplin.Dispatcher sits between the router and controllers to listen for routing events. When they occur, Chaplin.Dispatcher loads the target controller module and instantiates it before invoking the target action. Any previously active controller is automatically disposed.
initDispatcher: (options) ->
@dispatcher = new Dispatcher optionsChaplin.Layout is the top-level application view. It does not inherit from Chaplin.View but borrows some of its functionalities. It is tied to the document dom element and registers application-wide events, such as internal links. And mainly, when a new controller is activated, Chaplin.Layout is responsible for changing the main view to the view of the new controller.
initLayout: (options = {}) ->
options.title ?= @title
@layout = new Layout options
initComposer: (options = {}) ->
@composer = new Composer optionsChaplin.mediator is a singleton that serves as the sole communication channel for all parts of the application. It should be sealed so that its misuse as a kitchen sink is prohibited. If you do want to give modules access to some shared resource, however, add it here before sealing the mediator.
initMediator: ->
mediator.seal()Chaplin.Router is responsible for observing URL changes. The router is a replacement for Backbone.Router and does not inherit from it directly. It's a different implementation with several advantages over the standard router provided by Backbone. The router is typically initialized by passing the function returned by routes.coffee.
initRouter: (routes, options) ->Save the reference for testing introspection only. Modules should communicate with each other via publish/subscribe.
@router = new Router optionsRegister any provided routes.
routes? @router.matchCan be customized when overridden.
start: ->After registering the routes, start Backbone.history.
@router.startHistory()Mark app as initialized.
@started = trueFreeze the application instance to prevent further changes.
Object.freeze? this disposed: false
dispose: ->Am I already disposed?
return if @disposed
properties = ['dispatcher', 'layout', 'router', 'composer']
for prop in properties when this[prop]?
this[prop].dispose()
@disposed = trueYou're frozen when your heart's not open.
Object.freeze? this