1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | 1 132 132 132 132 132 132 1 96 14 125 97 33 29 97 97 97 97 16 14 14 14 14 14 14 14 81 81 81 81 132 132 1 140 140 140 140 140 140 140 140 193 193 193 140 193 193 132 132 132 193 193 193 193 76 76 117 6 6 111 193 81 193 193 118 118 47 45 | // 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){ Iif (!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); } }); } } }); |