(function (root, factory) { if (typeof exports === 'object') { var underscore = require('underscore'); var backbone = require('backbone'); module.exports = factory(underscore, backbone); } else if (typeof define === 'function' && define.amd) { define(['underscore', 'backbone'], factory); } }(this, function (_, Backbone) { 'use strict'; Backbone.Wreqr = (function(Backbone, Marionette, _){ 'use strict'; var Wreqr = {}; // Handlers // -------- // A registry of functions to call, given a name Wreqr.Handlers = (function(Backbone, _){ 'use strict'; // Constructor // ----------- var Handlers = function(options){ this.options = options; this._wreqrHandlers = {}; if (_.isFunction(this.initialize)){ this.initialize(options); } }; Handlers.extend = Backbone.Model.extend; // Instance Members // ---------------- _.extend(Handlers.prototype, Backbone.Events, { // Add multiple handlers using an object literal configuration setHandlers: function(handlers){ _.each(handlers, function(handler, name){ var context = null; if (_.isObject(handler) && !_.isFunction(handler)){ context = handler.context; handler = handler.callback; } this.setHandler(name, handler, context); }, this); }, // Add a handler for the given name, with an // optional context to run the handler within setHandler: function(name, handler, context){ var config = { callback: handler, context: context }; this._wreqrHandlers[name] = config; this.trigger("handler:add", name, handler, context); }, // Determine whether or not a handler is registered hasHandler: function(name){ return !! this._wreqrHandlers[name]; }, // Get the currently registered handler for // the specified name. Throws an exception if // no handler is found. getHandler: function(name){ var config = this._wreqrHandlers[name]; if (!config){ throw new Error("Handler not found for '" + name + "'"); } return function(){ var args = Array.prototype.slice.apply(arguments); return config.callback.apply(config.context, args); }; }, // Remove a handler for the specified name removeHandler: function(name){ delete this._wreqrHandlers[name]; }, // Remove all handlers from this registry removeAllHandlers: function(){ this._wreqrHandlers = {}; } }); return Handlers; })(Backbone, _); // Wreqr.CommandStorage // -------------------- // // Store and retrieve commands for execution. Wreqr.CommandStorage = (function(){ 'use strict'; // Constructor function var CommandStorage = function(options){ this.options = options; this._commands = {}; if (_.isFunction(this.initialize)){ this.initialize(options); } }; // Instance methods _.extend(CommandStorage.prototype, Backbone.Events, { // Get an object literal by command name, that contains // the `commandName` and the `instances` of all commands // represented as an array of arguments to process getCommands: function(commandName){ var commands = this._commands[commandName]; // we don't have it, so add it if (!commands){ // build the configuration commands = { command: commandName, instances: [] }; // store it this._commands[commandName] = commands; } return commands; }, // Add a command by name, to the storage and store the // args for the command addCommand: function(commandName, args){ var command = this.getCommands(commandName); command.instances.push(args); }, // Clear all commands for the given `commandName` clearCommands: function(commandName){ var command = this.getCommands(commandName); command.instances = []; } }); return CommandStorage; })(); // Wreqr.Commands // -------------- // // A simple command pattern implementation. Register a command // handler and execute it. Wreqr.Commands = (function(Wreqr){ 'use strict'; return Wreqr.Handlers.extend({ // default storage type storageType: Wreqr.CommandStorage, constructor: function(options){ this.options = options || {}; this._initializeStorage(this.options); this.on("handler:add", this._executeCommands, this); var args = Array.prototype.slice.call(arguments); Wreqr.Handlers.prototype.constructor.apply(this, args); }, // Execute a named command with the supplied args execute: function(name, args){ name = arguments[0]; args = Array.prototype.slice.call(arguments, 1); if (this.hasHandler(name)){ this.getHandler(name).apply(this, args); } else { this.storage.addCommand(name, args); } }, // Internal method to handle bulk execution of stored commands _executeCommands: function(name, handler, context){ var command = this.storage.getCommands(name); // loop through and execute all the stored command instances _.each(command.instances, function(args){ handler.apply(context, args); }); this.storage.clearCommands(name); }, // Internal method to initialize storage either from the type's // `storageType` or the instance `options.storageType`. _initializeStorage: function(options){ var storage; var StorageType = options.storageType || this.storageType; if (_.isFunction(StorageType)){ storage = new StorageType(); } else { storage = StorageType; } this.storage = storage; } }); })(Wreqr); // Wreqr.RequestResponse // --------------------- // // A simple request/response implementation. Register a // request handler, and return a response from it Wreqr.RequestResponse = (function(Wreqr){ 'use strict'; return Wreqr.Handlers.extend({ request: function(){ var name = arguments[0]; var args = Array.prototype.slice.call(arguments, 1); return this.getHandler(name).apply(this, args); } }); })(Wreqr); // Event Aggregator // ---------------- // A pub-sub object that can be used to decouple various parts // of an application through event-driven architecture. Wreqr.EventAggregator = (function(Backbone, _){ 'use strict'; var EA = function(){}; // Copy the `extend` function used by Backbone's classes EA.extend = Backbone.Model.extend; // Copy the basic Backbone.Events on to the event aggregator _.extend(EA.prototype, Backbone.Events); return EA; })(Backbone, _); return Wreqr; })(Backbone, Backbone.Marionette, _); return Backbone.Wreqr; }));