You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
436 lines
11 KiB
JavaScript
436 lines
11 KiB
JavaScript
10 years ago
|
// Backbone.Wreqr (Backbone.Marionette)
|
||
|
// ----------------------------------
|
||
|
// v1.3.2
|
||
|
//
|
||
|
// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
|
||
|
// Distributed under MIT license
|
||
|
//
|
||
|
// http://github.com/marionettejs/backbone.wreqr
|
||
|
|
||
|
|
||
|
(function(root, factory) {
|
||
|
|
||
|
if (typeof define === 'function' && define.amd) {
|
||
|
define(['backbone', 'underscore'], function(Backbone, _) {
|
||
|
return factory(Backbone, _);
|
||
|
});
|
||
|
} else if (typeof exports !== 'undefined') {
|
||
|
var Backbone = require('backbone');
|
||
|
var _ = require('underscore');
|
||
|
module.exports = factory(Backbone, _);
|
||
|
} else {
|
||
|
factory(root.Backbone, root._);
|
||
|
}
|
||
|
|
||
|
}(this, function(Backbone, _) {
|
||
|
"use strict";
|
||
|
|
||
|
var previousWreqr = Backbone.Wreqr;
|
||
|
|
||
|
var Wreqr = Backbone.Wreqr = {};
|
||
|
|
||
|
Backbone.Wreqr.VERSION = '1.3.2';
|
||
|
|
||
|
Backbone.Wreqr.noConflict = function () {
|
||
|
Backbone.Wreqr = previousWreqr;
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
// 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){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
return function(){
|
||
|
return config.callback.apply(config.context, arguments);
|
||
|
};
|
||
|
},
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
Wreqr.Handlers.prototype.constructor.apply(this, arguments);
|
||
|
},
|
||
|
|
||
|
// Execute a named command with the supplied args
|
||
|
execute: function(name){
|
||
|
name = arguments[0];
|
||
|
var args = _.rest(arguments);
|
||
|
|
||
|
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(name){
|
||
|
if (this.hasHandler(name)) {
|
||
|
return this.getHandler(name).apply(this, _.rest(arguments));
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
})(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, _);
|
||
|
|
||
|
// Wreqr.Channel
|
||
|
// --------------
|
||
|
//
|
||
|
// An object that wraps the three messaging systems:
|
||
|
// EventAggregator, RequestResponse, Commands
|
||
|
Wreqr.Channel = (function(Wreqr){
|
||
|
"use strict";
|
||
|
|
||
|
var Channel = function(channelName) {
|
||
|
this.vent = new Backbone.Wreqr.EventAggregator();
|
||
|
this.reqres = new Backbone.Wreqr.RequestResponse();
|
||
|
this.commands = new Backbone.Wreqr.Commands();
|
||
|
this.channelName = channelName;
|
||
|
};
|
||
|
|
||
|
_.extend(Channel.prototype, {
|
||
|
|
||
|
// Remove all handlers from the messaging systems of this channel
|
||
|
reset: function() {
|
||
|
this.vent.off();
|
||
|
this.vent.stopListening();
|
||
|
this.reqres.removeAllHandlers();
|
||
|
this.commands.removeAllHandlers();
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
// Connect a hash of events; one for each messaging system
|
||
|
connectEvents: function(hash, context) {
|
||
|
this._connect('vent', hash, context);
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
connectCommands: function(hash, context) {
|
||
|
this._connect('commands', hash, context);
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
connectRequests: function(hash, context) {
|
||
|
this._connect('reqres', hash, context);
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
// Attach the handlers to a given message system `type`
|
||
|
_connect: function(type, hash, context) {
|
||
|
if (!hash) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
context = context || this;
|
||
|
var method = (type === 'vent') ? 'on' : 'setHandler';
|
||
|
|
||
|
_.each(hash, function(fn, eventName) {
|
||
|
this[type][method](eventName, _.bind(fn, context));
|
||
|
}, this);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
|
||
|
return Channel;
|
||
|
})(Wreqr);
|
||
|
|
||
|
// Wreqr.Radio
|
||
|
// --------------
|
||
|
//
|
||
|
// An object that lets you communicate with many channels.
|
||
|
Wreqr.radio = (function(Wreqr, _){
|
||
|
"use strict";
|
||
|
|
||
|
var Radio = function() {
|
||
|
this._channels = {};
|
||
|
this.vent = {};
|
||
|
this.commands = {};
|
||
|
this.reqres = {};
|
||
|
this._proxyMethods();
|
||
|
};
|
||
|
|
||
|
_.extend(Radio.prototype, {
|
||
|
|
||
|
channel: function(channelName) {
|
||
|
if (!channelName) {
|
||
|
throw new Error('Channel must receive a name');
|
||
|
}
|
||
|
|
||
|
return this._getChannel( channelName );
|
||
|
},
|
||
|
|
||
|
_getChannel: function(channelName) {
|
||
|
var channel = this._channels[channelName];
|
||
|
|
||
|
if(!channel) {
|
||
|
channel = new Wreqr.Channel(channelName);
|
||
|
this._channels[channelName] = channel;
|
||
|
}
|
||
|
|
||
|
return channel;
|
||
|
},
|
||
|
|
||
|
_proxyMethods: function() {
|
||
|
_.each(['vent', 'commands', 'reqres'], function(system) {
|
||
|
_.each( messageSystems[system], function(method) {
|
||
|
this[system][method] = proxyMethod(this, system, method);
|
||
|
}, this);
|
||
|
}, this);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
|
||
|
var messageSystems = {
|
||
|
vent: [
|
||
|
'on',
|
||
|
'off',
|
||
|
'trigger',
|
||
|
'once',
|
||
|
'stopListening',
|
||
|
'listenTo',
|
||
|
'listenToOnce'
|
||
|
],
|
||
|
|
||
|
commands: [
|
||
|
'execute',
|
||
|
'setHandler',
|
||
|
'setHandlers',
|
||
|
'removeHandler',
|
||
|
'removeAllHandlers'
|
||
|
],
|
||
|
|
||
|
reqres: [
|
||
|
'request',
|
||
|
'setHandler',
|
||
|
'setHandlers',
|
||
|
'removeHandler',
|
||
|
'removeAllHandlers'
|
||
|
]
|
||
|
};
|
||
|
|
||
|
var proxyMethod = function(radio, system, method) {
|
||
|
return function(channelName) {
|
||
|
var messageSystem = radio._getChannel(channelName)[system];
|
||
|
|
||
|
return messageSystem[method].apply(messageSystem, _.rest(arguments));
|
||
|
};
|
||
|
};
|
||
|
|
||
|
return new Radio();
|
||
|
|
||
|
})(Wreqr, _);
|
||
|
|
||
|
|
||
|
return Backbone.Wreqr;
|
||
|
|
||
|
}));
|