soma.js
Version:
soma.js is a javascript framework created to build scalable and maintainable applications.
246 lines (231 loc) • 6.77 kB
JavaScript
// plugins
var plugins = [];
soma.plugins = soma.plugins || {};
soma.plugins.add = function(plugin) {
plugins.push(plugin);
};
soma.plugins.remove = function(plugin) {
for (var i = plugins.length-1, l = 0; i >= l; i--) {
if (plugin === plugins[i]) {
plugins.splice(i, 1);
}
}
};
// framework
soma.Application = soma.extend({
constructor: function() {
var self = this;
function setup() {
// injector
self.injector = new infuse.Injector(self.dispatcher);
// dispatcher
self.dispatcher = new soma.EventDispatcher();
// mapping
self.injector.mapValue('injector', self.injector);
self.injector.mapValue('instance', self);
self.injector.mapValue('dispatcher', self.dispatcher);
// mediator
self.injector.mapClass('mediators', Mediators, true);
self.mediators = self.injector.getValue('mediators');
// commands
self.injector.mapClass('commands', Commands, true);
self.commands = self.injector.getValue('commands');
// plugins
for (var i = 0, l = plugins.length; i < l; i++) {
self.createPlugin(plugins[i]);
}
}
setup.bind(this)();
this.init();
this.start();
},
createPlugin: function() {
if (arguments.length === 0 || !arguments[0]) {
throw new Error('Error creating a plugin, plugin class is missing.');
}
var params = infuse.getDependencies(arguments[0]);
// add plugin function
var args = [arguments[0]];
// add injection mappings
for (var i=0, l=params.length; i < l; i++) {
if (this.injector.hasMapping(params[i]) || this.injector.hasInheritedMapping(params[i])) {
args.push(this.injector.getValue(params[i]));
}
else {
args.push(undefined);
}
}
// trim array
for (var a = args.length-1, b = args.length; a >= 0; a--) {
if (typeof args[a] === 'undefined') {
args.splice(a, 1);
}
else {
break;
}
}
// add arguments
for (var j=1, k=arguments.length; j < k; j++) {
args.push(arguments[j]);
}
return this.injector.createInstance.apply(this.injector, args);
},
init: function() {
},
start: function() {
},
dispose: function() {
// mapping
if (this.injector) {
this.injector.removeMapping('injector');
this.injector.removeMapping('dispatcher');
this.injector.removeMapping('mediators');
this.injector.removeMapping('commands');
this.injector.removeMapping('instance');
}
// variables
if (this.injector) {
this.injector.dispose();
}
if (this.dispatcher) {
this.dispatcher.dispose();
}
if (this.mediators) {
this.mediators.dispose();
}
if (this.commands) {
this.commands.dispose();
}
this.injector = undefined;
this.dispatcher = undefined;
this.mediators = undefined;
this.commands = undefined;
this.instance = undefined;
}
});
var Mediators = soma.extend({
constructor: function() {
this.injector = null;
this.dispatcher = null;
},
create: function(cl, target) {
if (!cl || typeof cl !== 'function') {
throw new Error('Error creating a mediator, the first parameter must be a function.');
}
if (target === undefined || target === null) {
throw new Error('Error creating a mediator, the second parameter cannot be undefined or null.');
}
var targets = [];
var meds = [];
var targetToString = Object.prototype.toString.call(target);
if ((targetToString === '[object Array]' || targetToString === '[object NodeList]') && target.length > 0) {
targets = [].concat(target);
}
else {
targets.push(target);
}
for (var i= 0, l=targets.length; i<l; i++) {
var injector = this.injector.createChild();
injector.mapValue('target', targets[i]);
var mediator = injector.createInstance(cl);
if (targets.length === 1) {
return mediator;
}
meds.push(mediator);
}
return meds;
},
dispose: function() {
this.injector = undefined;
this.dispatcher = undefined;
}
});
var Commands = soma.extend({
constructor: function() {
this.boundHandler = this.handler.bind(this);
this.dispatcher = null;
this.injector = null;
this.list = {};
},
has: function(commandName) {
return this.list[commandName] !== null && this.list[commandName] !== undefined;
},
get: function(commandName) {
if (this.has(commandName)) {
return this.list[commandName];
}
return undefined;
},
getAll: function() {
var copy = {};
for (var cmd in this.list) {
if (this.list.hasOwnProperty(cmd)) {
copy[cmd] = this.list[cmd];
}
}
return copy;
},
add: function(commandName, command) {
if (typeof commandName !== 'string') {
throw new Error('Error adding a command, the first parameter must be a string.');
}
if (typeof command !== 'function') {
throw new Error('Error adding a command with the name "' + command + '", the second parameter must be a function, and must contain an "execute" public method.');
}
if (this.has(commandName)) {
throw new Error('Error adding a command with the name: "' + commandName + '", already registered.');
}
this.list[ commandName ] = command;
this.addInterceptor(commandName);
},
remove: function(commandName) {
if (!this.has(commandName)) {
return;
}
this.list[commandName] = undefined;
delete this.list[commandName];
this.removeInterceptor(commandName);
},
addInterceptor: function(commandName) {
this.dispatcher.addEventListener(commandName, this.boundHandler, -Number.MAX_VALUE);
},
removeInterceptor: function(commandName) {
this.dispatcher.removeEventListener(commandName, this.boundHandler);
},
handler: function(event) {
if (event.isDefaultPrevented && !event.isDefaultPrevented()) {
this.executeCommand(event);
}
},
executeCommand: function(event) {
var commandName = event.type;
if (this.has(commandName)) {
var command = this.injector.createInstance(this.list[commandName]);
if (!command.hasOwnProperty('execute') && command['execute'] === 'function') {
throw new Error('Error in ' + this + ' Command ' + command + ' must contain an execute public method.');
}
command.execute(event);
}
},
dispose: function() {
for (var cmd in this.list) {
if (this.list.hasOwnProperty(cmd)) {
this.remove(cmd);
}
}
this.boundHandler = undefined;
this.dispatcher = undefined;
this.injector = undefined;
this.list = undefined;
}
});
// event extend utils
soma.EventDispatcher.extend = function (obj) {
return soma.inherit(soma.EventDispatcher, obj);
};
soma.Event.extend = function (obj) {
return soma.inherit(soma.Event, obj);
};
infuse.Injector.extend = function(obj) {
return soma.inherit(infuse.Injector, obj);
};