Skip to content

Instantly share code, notes, and snippets.

@ptejada
Last active October 2, 2015 15:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ptejada/2269151 to your computer and use it in GitHub Desktop.
Save ptejada/2269151 to your computer and use it in GitHub Desktop.
JSmodule is a simple JavaScript object for stacking data and hookable functions as methods.
/**
* A JavaScript module constructor
*
* Methods
* - get( name ) get the value the named internal variable
* - set( name , value ) set named internal variable a value
* - extend( methodName , function ) add a method to the module
*
* @param ModuleID
* @returns {Function}
* @constructor
*/
function JSmodule(ModuleID){
//save scope
var scope = this;
//debug function
function log(data, extra){
if(!options.debug) return {};
if(!!extra){
console.log("["+options.app+"] >> ",data, extra);
}else{
console.log("["+options.app+"] >> ",data);
}
return this;
}
/*
* Object constructor
*/
function constructor(methodOrOptions, /**Array=*/args){
if(methods[methodOrOptions]){
//execute function before method || Cancel execution if returned false
if(constructor.runBeforeCallbacks(methodOrOptions, args) === false) return false;
//Execute method
var returnVal = methods[ methodOrOptions ].apply( this, args);
//Smart return value
if(typeof returnVal != 'undefined')
return returnVal;
return this;
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
// Default to "init"
if(constructor.runBeforeCallbacks("init", methodOrOptions) === false);
return methods.init.apply( this, arguments );
} else {
throw new Error('['+options.app+'] >> Method `' + methodOrOptions + '` does not exists' );
}
};
//Global hidden options
var options = {};
//Global hidden callbacks
var callbacks = {};
//Global hidden data
var data = {};
//Default methods
var methods = {
init: function(newOptions, callback){
if(newOptions && typeof(newOptions) == 'object'){
options = MergeObject( options, newOptions );
}
if(typeof callback == 'function'){
callback.apply(this, [newOptions]);
}
//Call callbacks
constructor.runAfterCallbacks("init", newOptions);
}
}
//Private functions
function applyCallback(name, args){
if(typeof args == 'undefined'){
args = [];
}
//exit if no callback
if(!callbacks[name]){
log("No [" + name + "] callbacks");
}else{
log("Running ["+name+"] callback stack with arguments: ", args);
var cont;
//Apply function
for(var i in callbacks[name]){
cont = callbacks[name][i].apply(this,args);
log("Callback "+name+"["+i+"]() returned: ", cont);
if(cont === false) return false; //Return false to cancel further execution when running afterCallback
}
}
return true;
}
//Add debugging function to constructor
constructor.log = log;
/**
* Adds a callback function to the given stack
* @param name
* @param callback
*/
constructor.addCallback = function(name, callback){
if(!callbacks[name])
callbacks[name] = [];
callbacks[name].push(callback);
}
/**
* Adds a after callback function to the given stack
*
* @param name The name of the stack
* @param callback The callback function
*/
constructor.addAfterCallback = function( name, callback){
constructor.addCallback( name + ".after", callback)
}
/**
* Adds a before callback function to the given stack
*
* @param name The name of the stack
* @param callback The callback function
*/
constructor.addBeforeCallback = function( name, callback){
constructor.addCallback( name + ".before", callback)
}
/**
* Deletes callback stack
*
* @param name The name of the stack
*/
constructor.removeCallback = function( name ){
log("Clearing ["+name+"] callbacks");
if(name in callbacks){
delete callbacks[name];
}
}
/**
* Execute the before callback stack passing the given arguments
*
* @param name The name of the stack to run the callbacks
* @param args The arguments to pass to each function
* @returns {*}
*/
constructor.runBeforeCallbacks = function( name, /**Array=*/args ){
if(typeof args == 'undefined'){
args = [];
}
name = name + ".before";
return applyCallback.call(this, name, args);
}
/**
* Execute the after callback stack passing the given arguments
*
* @param name The name of the stack to run the callbacks
* @param args The arguments to pass to each function
* @returns {*}
*/
constructor.runAfterCallbacks = function( name, /**Array=*/args ){
if(typeof args == 'undefined'){
args = [];
}
name = name + ".after";
return applyCallback.call(this, name, args);
}
/**
* Execute a stack of functions passing the given arguments
*
* @param name The name of the callback stack
* @returns {*}
*/
constructor.runCallbacks = function(){
return applyCallback.apply(this, arguments);
}
/**
* Adds a method to the module
* @param name The method name
* @param func The method function
*/
constructor.extend = function(name, func){
if(typeof name == 'object'){
methods = MergeObject( methods, name );
}else{
methods[name] = func;
}
}
/**
* Gets value of a stored variable
*
* @param name The name of the stored variable
* @returns {*}
*/
constructor.get = function( name ){
if(name in data){
return data[name];
}else{
return null;
}
}
/**
* Stores a value in the module
*
* @param name The variable name to hold the value
* @param value The value to store in the variable
*/
constructor.set = function(name, value){
data[name] = value;
}
/**
* Get an internal option
*
* @param name The name of the internal option
* @returns {*}
*/
constructor.getOption = function( name ){
if(name in options){
return options[name]
}else{
return null
}
}
/**
* Set an internal option
*
* @param name The name of the option
* @param value The value to set the option
* @returns {*}
*/
constructor.setOption = function( name, value ){
return options[name] = value;
}
//Default options
options = {
app: ModuleID || "Obj",
debug: false
}
/*
* Required object merger function
*/
function MergeObject(obj1, obj2, callback){
var obj3 = {};
for(var i in obj1){
obj3[i] = obj1[i];
}
for(var n in obj2){
obj3[n] = obj2[n];
}
if(typeof callback == 'function')
callback();
return obj3;
}
return constructor;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment