Created
May 26, 2014 13:17
-
-
Save kharandziuk/91422a185d53c32e81bf to your computer and use it in GitHub Desktop.
wreqr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Backbone.Wreqr (Backbone.Marionette) | |
// ---------------------------------- | |
// v1.3.1 | |
// | |
// 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.1'; | |
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(){ | |
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); | |
if (this.hasHandler(name)) { | |
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, _); | |
// 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]; | |
var args = Array.prototype.slice.call(arguments, 1); | |
return messageSystem[method].apply(messageSystem, args); | |
}; | |
}; | |
return new Radio(); | |
})(Wreqr); | |
return Backbone.Wreqr; | |
})); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment