Controller = { views: {}, // views hash map models: {}, // models hash map collections: {}, // collections hash map // Set of methods to get existing view, get view constructor and create new view using constuctor getView: function() {}, getViewConstructor: function() {}, createView: function() {}, // Set of methods to get existing model, get model constructor and create new model using constuctor getModel: function() {}, getModelConstructor: function() {}, createModel: function() {}, // Set of methods to get existing collection, // get collection constructor and create new collectionusing constuctor getCollection: function() {}, getCollectionConstructor: function() {}, createCollection: function() {}, // This method will subscribe controller instance to view events addListeners: function() {} }
Application
- a basic constructor that will merge controllers into a single application - comes to the rescue. Application = { //Method that will initialize all controllers upon applicaiton launch initializeControllers: function() {}, // Set of methods to get existing model, get model constructor and create new model using constuctor getModel: function() {}, getModelConstructor: function() {}, createModel: function() {}, // Set of methods to get existing collection, get collectionconstructor and create new collectionusing constuctor getCollection: function() {}, getCollectionConstructor: function() {}, createCollection: function() {}, }
// Create collection instances upon application start Application.buildCollections() // Initialize all application controllers Application.initializeControllers()
EventBus = { // Function to add event listeners addListeners: function() {}, // Function to fire event listneres fireEvent: function() {} }
Application
. The base class is implemented in the same way as the backbone does. var Application = function(options) { _.extend(this, options || {}); // Create a new instance of EventBus and pass the reference to out application this.eventbus = new EventBus({application: this}); // Run application initialization if needed this.initialize.apply(this, arguments); // Create documentReady callback to lauch the application $($.proxy(this.onReady, this)); };
_.extend
, we extend the prototype: _.extend(Application.prototype, { // Hash maps to store models, collections and controllers models: {}, collections: {}, controllers: {}, /** * Abstract fuction that will be called during application instance creation */ initialize: function(options) { return this; }, /** * Called on documentReady, defined in constructor */ onReady: function() { // initialize controllers this.initializeControllers(this.controllers || {}); // call to controller.onLauch callback this.launchControllers(); // call application.lauch callback this.launch.call(this); }, /** * Function that will convert string identifier into the instance reference */ parseClasses: function(classes) { var hashMap = {}; _.each(classes, function(cls) { var classReference = resolveNamespace(cls), id = cls.split('.').pop(); hashMap[id] = classReference; }, this); return hashMap; }, /** * Abstract fuction that will be called during application lauch */ launch: function() {}, /** * Getter to retreive link to the particular controller instance */ getController: function(id) { return this.controllers[id]; }, /** * Function that will loop throught the list of collection constructors and create instances */ buildCollections: function() { _.each(this.collections, function(collection, alias) { this.getCollection(alias); }, this); } });
Application.initializeControllers
will create instances and subtract sets of collections and models to store the links directly in the application itself. And Application.launchControllers
will go through already created controllers and execute Controller.onLaunch
callback. _.extend(Application.prototype, { ... /** * Fuction that will loop through all application conrollers and create their instances * Additionaly, read the list of models and collections from each controller * and save the reference within application */ initializeControllers: function(controllers) { this.controllers = {}; _.each(controllers, function(ctrl) { var classReference = resolveNamespace(ctrl), id = ctrl.split('.').pop(); // create new Controller instance and pass reference to the application var controller = new classReference({ id: id, application: this }); controller.views = this.parseClasses(controller.views || []); _.extend(this.models, this.parseClasses(controller.models || [])); _.extend(this.collections, this.parseClasses(controller.collections || {})); this.buildCollections(); this.controllers[id] = controller; }, this); }, /** * Launch all controllers using onLauch callback */ launchControllers: function() { _.each(this.controllers, function(ctrl, id) { ctrl.onLaunch(this); }, this); } ... });
Application.addListeners
method, which delegates work to our EventBus: _.extend(Application.prototype, { ... /** * Abstract fuction that will be called during application lauch */ addListeners: function(listeners, controller) { this.eventbus.addListeners(listeners, controller) } ... });
_.extend(Application.prototype, { ... /** * Getter to retreive link to the particular model instance * If model instance isn't created, create it */ getModel: function(name) { this._modelsCache = this._modelsCache || {}; var model = this._modelsCache[name], modelClass = this.getModelConstructor(name); if(!model && modelClass) { model = this.createModel(name); this._modelsCache[name] = model; } return model || null; }, /** * Getter to retreive link to the particular model consturctor */ getModelConstructor: function(name) { return this.models[name]; }, /** * Function to create new model instance */ createModel: function(name, options) { var modelClass = this.getModelConstructor(name), options = _.extend(options || {}); var model = new modelClass(options); return model; }, /** * Getter to retreive link to the particular collection instance * If collection instance isn't created, create it */ getCollection: function(name) { ... }, /** * Getter to retreive link to the particular collection consturctor */ getCollectionConstructor: function(name) { ... }, /** * Function to create new collection instance */ createCollection: function(name, options) { ... }, ... });
Application.parseClasses
method should be mentioned. The fact is that I decided to transfer lists of controllers, models, collections and view as an array of strings. Getting at the entrance [ 'myApplication.controller.UserManager', 'myApplication.controller.FormBuilder' ]
{ 'UserManager': myApplication.controller.UserManager, 'FormBuilder': myApplication.controller.FormBuilder }
Application
. To start the announcement: var Controller = function(options) { _.extend(this, options || {}); this.initialize.apply(this, arguments); };
_.extend(Controller.prototype, { views: {}, models: {}, collections: {}, initialize: function(options) { }, /** * Add new listener to the application event bus */ addListeners: function(listeners) { this.getApplication().addListeners(listeners, this); }, /** * Abstract fuction that will be called during application lauch */ onLaunch: function(application) { }, /** * Getter that will return the reference to the application instance */ getApplication: function() { return this.application; } });
_.extend(Controller.prototype, { ... /** * Getter that will return the reference to the view constructor */ getViewConstructor: function(name) { return this.views[name]; }, /** * Function to create a new view instance * All views are cached within _viewsCache hash map */ createView: function(name, options) { var view = this.getViewConstructor(name), options = _.extend(options || {}, { alias: name }); return new view(options); } ... });
Application
_.extend(Controller.prototype, { ... /** * Delegate method to get model instance reference */ getModel: function(name) { return this.application.getModel(name); }, /** * Delegate method to get model constructor reference */ getModelConstructor: function(name) { return this.application.getModelConstructor(name); }, /** * Delegate method to create model instance */ createModel: function(name, options) { return this.application.createModel(name) }, /** * Delegate method to get collection instance reference */ getCollection: function(name) { return this.application.getCollection(name); }, /** * Delegate method to get collection constructor reference */ getCollectionConstructor: function(name) { return this.application.getCollectionConstructor(name); }, /** * Delegate method to create collection instance */ createCollection: function(name, options) { return this.application.createCollection(name); } ... });
Application.EventBus
_.extend(Controller.prototype, { ... /** * Delegate method to fire event */ fireEvent: function(selector, event, args) { this.application.eventbus.fireEvent(selector, event, args); } ... });
Backbone.View
prototype. The fact is that we need a certain selector by which events will be tracked. To do this, we introduce the alias
property, which will automatically be assigned when the component is created. And add the fireEvent
method, which will call the “native” View.trigger()
and EventBus
about the new event. var EventBus = function(options) { var me = this; _.extend(this, options || {}); // Extend Backbone.View.prototype _.extend(Backbone.View.prototype, { alias: null, /* * Getter that wll return alias */ getAlias: function() { return this.options.alias; }, /* * Instead of calling View.trigger lets use custom function * It will notify the EventBus about new event */ fireEvent: function(event, args) { this.trigger.apply(this, arguments); me.fireEvent(this.getAlias(), event, args); } }); };
EventBus.addListeners
to subscribe to new events, and EventBus.fireEvent
wears the necessary handler and executes it. _.extend(EventBus.prototype, { // Hash Map that will contains references to the all reginstered event listeners pool: {}, /** * Function to register new event listener */ addListeners: function(selectors, controller) { this.pool[controller.id] = this.pool[controller.id] || {}; var pool = this.pool[controller.id]; if(_.isArray(selectors)) { _.each(selectors, function(selector) { this.control(selector, controller); }, this) } else if(_.isObject(selectors)) { _.each(selectors, function(listeners, selector) { _.each(listeners, function(listener, event) { pool[selector] = pool[selector] || {}; pool[selector][event] = pool[selector][event] || []; pool[selector][event].push(listener); }, this); }, this) } }, /** * Function to execute event listener */ fireEvent: function(selector, event, args) { var application = this.getApplication(); _.each(this.pool, function(eventsPoolByAlias, controllerId) { var events = eventsPoolByAlias[selector]; if(events) { var listeners = events[event] controller = application.getController(controllerId); _.each(listeners, function(fn) { fn.apply(controller, args); }); } }, this); }, /** * Getter to receive the application reference */ getApplication: function() { return this.options['application']; } });
Application.extend = Backbone.Model.extend; Controller.extend = Backbone.Model.extend;
extend
function.Source: https://habr.com/ru/post/149626/
All Articles