Plato on Github
Report Home
module.js
Maintainability
71.78
Lines of code
201
Difficulty
30.43
Estimated Errors
1.04
Function weight
By Complexity
By SLOC
// Module // ------ // A simple module system, used to create privacy and encapsulation in // Marionette applications Marionette.Module = function(moduleName, app){ this.moduleName = moduleName; // store sub-modules this.submodules = {}; this._setupInitializersAndFinalizers(); // store the configuration for this module this.app = app; this.startWithParent = true; this.triggerMethod = Marionette.triggerMethod; }; // Extend the Module prototype with events / listenTo, so that the module // can be used as an event aggregator or pub/sub. _.extend(Marionette.Module.prototype, Backbone.Events, { // Initializer for a specific module. Initializers are run when the // module's `start` method is called. addInitializer: function(callback){ this._initializerCallbacks.add(callback); }, // Finalizers are run when a module is stopped. They are used to teardown // and finalize any variables, references, events and other code that the // module had set up. addFinalizer: function(callback){ this._finalizerCallbacks.add(callback); }, // Start the module, and run all of its initializers start: function(options){ // Prevent re-starting a module that is already started if (this._isInitialized){ return; } // start the sub-modules (depth-first hierarchy) _.each(this.submodules, function(mod){ // check to see if we should start the sub-module with this parent if (mod.startWithParent){ mod.start(options); } }); // run the callbacks to "start" the current module this.triggerMethod("before:start", options); this._initializerCallbacks.run(options, this); this._isInitialized = true; this.triggerMethod("start", options); }, // Stop this module by running its finalizers and then stop all of // the sub-modules for this module stop: function(){ // if we are not initialized, don't bother finalizing if (!this._isInitialized){ return; } this._isInitialized = false; Marionette.triggerMethod.call(this, "before:stop"); // stop the sub-modules; depth-first, to make sure the // sub-modules are stopped / finalized before parents _.each(this.submodules, function(mod){ mod.stop(); }); // run the finalizers this._finalizerCallbacks.run(undefined,this); // reset the initializers and finalizers this._initializerCallbacks.reset(); this._finalizerCallbacks.reset(); Marionette.triggerMethod.call(this, "stop"); }, // Configure the module with a definition function and any custom args // that are to be passed in to the definition function addDefinition: function(moduleDefinition, customArgs){ this._runModuleDefinition(moduleDefinition, customArgs); }, // Internal method: run the module definition function with the correct // arguments _runModuleDefinition: function(definition, customArgs){ if (!definition){ return; } // build the correct list of arguments for the module definition var args = _.flatten([ this, this.app, Backbone, Marionette, Marionette.$, _, customArgs ]); definition.apply(this, args); }, // Internal method: set up new copies of initializers and finalizers. // Calling this method will wipe out all existing initializers and // finalizers. _setupInitializersAndFinalizers: function(){ this._initializerCallbacks = new Marionette.Callbacks(); this._finalizerCallbacks = new Marionette.Callbacks(); } }); // Type methods to create modules _.extend(Marionette.Module, { // Create a module, hanging off the app parameter as the parent object. create: function(app, moduleNames, moduleDefinition){ var module = app; // get the custom args passed in after the module definition and // get rid of the module name and definition function var customArgs = slice(arguments); customArgs.splice(0, 3); // split the module names and get the length moduleNames = moduleNames.split("."); var length = moduleNames.length; // store the module definition for the last module in the chain var moduleDefinitions = []; moduleDefinitions[length-1] = moduleDefinition; // Loop through all the parts of the module definition _.each(moduleNames, function(moduleName, i){ var parentModule = module; module = this._getModule(parentModule, moduleName, app); this._addModuleDefinition(parentModule, module, moduleDefinitions[i], customArgs); }, this); // Return the last module in the definition chain return module; }, _getModule: function(parentModule, moduleName, app, def, args){ // Get an existing module of this name if we have one var module = parentModule[moduleName]; if (!module){ // Create a new module if we don't have one module = new Marionette.Module(moduleName, app); parentModule[moduleName] = module; // store the module on the parent parentModule.submodules[moduleName] = module; } return module; }, _addModuleDefinition: function(parentModule, module, def, args){ var fn; var startWithParent; if (_.isFunction(def)){ // if a function is supplied for the module definition fn = def; startWithParent = true; } else if (_.isObject(def)){ // if an object is supplied fn = def.define; startWithParent = def.startWithParent; } else { // if nothing is supplied startWithParent = true; } // add module definition if needed if (fn){ module.addDefinition(fn, args); } // `and` the two together, ensuring a single `false` will prevent it // from starting with the parent module.startWithParent = module.startWithParent && startWithParent; // setup auto-start if needed if (module.startWithParent && !module.startWithParentIsConfigured){ // only configure this once module.startWithParentIsConfigured = true; // add the module initializer config parentModule.addInitializer(function(options){ if (module.startWithParent){ module.start(options); } }); } } });