'use strict' define 'aura/extensions/states', ['states'], (states) -> (application) -> {core, logger} = application {dom, mediator} = core state = current: 'initialization' list: [] previous: null change: (transition) -> unless transition.to == transition.from # The application transition consists in simply store the # old state and updating the current one state.previous = state.current state.current = transition.to mediator.emit 'state.changed', transition else mediator.emit 'state.errored', to: transition.to, message: 'Application already in this state!' changed: (transition) -> dom.find('html').addClass(transition.to).removeClass(transition.from) # Set default intial state dom.find('html').addClass state.current # Application flow control # TODO think of a more specific name, like a machine! flow = changed: (transition) -> {domain} = application unormalized_widget_options = states[transition.to] # TODO update aura and use native start method # TODO move domain flow logic to a domain extension # domain_flow = domain?[transition.to] # TODO cache rendered widgets! if unormalized_widget_options widgets_options = @normalize_widget_options unormalized_widget_options, transition injection = core.inject(widgets_options).fail flow.failed # TODO let this code more legible domain_flow?.ready ||= injection.then((widgets...) -> # TODO use es6-shim promises $.Deferred().resolveWith domain_flow, widgets ).done # To prevent reinstation upon changing to this state for the # second time, delete stored configuration for this state delete states[transition.to] if domain_flow and not domain_flow.ready # TODO use es6-shim promises domain_flow.ready = $.Deferred().resolveWith(domain_flow, []).done normalize_widget_options: (unormalized_widget_options, transition_widgets_options) -> widgets = [] for name, options of unormalized_widget_options widget_name = options.name || name options.resource ||= name unless name == widget_name # To allow user controlling the application change the # widget configuration at runtime, we check the transition # for widget options widgets.push name: widget_name options: core.util.extend transition_widgets_options[widget_name], options # TODO document why we delete this? delete options.name widgets failed: (exception) -> logger.error "states.flow.failed: Failed autostarting widget! \n Message: #{exception.message}", exception version: '0.2.4' initialize: (application) -> mediator.on 'state.change' , state.change mediator.on 'state.changed', state.changed # TODO load widgets before state.changed, load on state.change # TODO use function hanlder mediator.on 'state.changed', -> flow.changed arguments... # TODO better integration with router to remove initial states widgets mediator.on 'states.list', -> @emit 'states.listed', states # TODO store meta information about application states # application.states = Object.keys states Object.defineProperty core, 'state', set: (to) -> console.warn 'Changing state through the core object is no longer supported. Use application.state = \"other_state\" instead.' application.state = to get: -> console.warn 'Getting state through the core object is no longer supported. Use application.state instead.' application.state # TODO ask aura to use Object.create when instantiating a new # application and stop accessing the global object Object.defineProperty window.app, 'state', set: (to) -> # To use a unified internal api, transform the setter call # into the transition api # app.state = name: 'new_state', ... unless $.type(to) == 'string' transition = to: to.name delete to.name # app.state = 'new_state' else transition = to: to # app.state = 'previous' transition.to = if transition.to == 'previous' then state.previous else transition.to # To change the application state, must invoke the change # function with the apropriated transition object transition.from = state.current state.change transition get: -> state.current afterAppStart: (application) -> # TODO Change the application to default state in flows extension if (application.startOptions.widgets) application.state = "default" else application.core.metabolize = -> # If any initialized flow changed the application state # before the widgets initialization, store its state pass # through the default state and go back to the old state # created by the flows # # TODO initialize the first flow in flows extension current_state = application.state if application.state != 'initialization' application.startOptions.widgets = arguments[0] application.state = "default" startup = application.core.start arguments... # TODO move to domain extension # TODO let this code more legible domain_flow = application.domain.default domain_flow?.ready ||= injection.then((widgets...) -> # TODO use es6-shim promises $.Deferred().resolveWith domain_flow, widgets ).done application.state = current_state if current_state? startup