Skip to content

Instantly share code, notes, and snippets.

@pospi
Created September 24, 2013 01:05
Show Gist options
  • Save pospi/6679084 to your computer and use it in GitHub Desktop.
Save pospi/6679084 to your computer and use it in GitHub Desktop.
Boilerplate code for wrapping up a JavaScript object / class into a jQuery plugin
/**
* A jquery plugin wrapper for a pure JavaScript class
*
* This will automatically give us the following:
*
* - a constructor for our class using $('my.selector').myClass()
* - automatic method access to the class's instance functions via syntax
* $('my.selector').myClass('funcName', arg1, arg2, ...argN);
* - automatic property access of all the class's internal properties. Both this
* and the above can assist greatly with third-party code integration
* - neater memory usage due to use of prototype functions and proper OO rather
* than closures recreating functions in memory each time
* - portability (if desired) of our class' internal code away from
* framework-dependant code, to allow quick porting to other libraries
*
* Just replace all instances of 'CHANGEME' to use
*
* @author Sam Pospischil <[email protected]>
*/
$.fn.CHANGEME = function(func) {
var t = this;
var classStorageKey = 'CHANGEME';
var myObject = t.data(classStorageKey);
// constructor to create an object and bind it to our elements
var init = function (options) {
t.data(classStorageKey, new CHANGEME(t, options));
};
// Run the appropriate behaviour
if (func != undefined && myObject != undefined) {
if (typeof myObject[func] == 'function') {
// object function call
return myObject[func].apply( myObject, Array.prototype.slice.call( arguments, 1 ));
} else {
// intance variable request
return myObject[func];
}
} else if (typeof func === 'object' || !func ) {
// create a new object, optionally passing options map
init.apply( t, arguments );
return t;
} else {
$.error( 'Method ' + func + ' does not exist in CHANGEME' );
}
};
/**
* And here we go again, but this time with the addition that it
* works when run on a jquery object matching multiple elements.
* - Constructors are run on all elements in the set
* - When run on a single element, works exactly as above
* - Property access returns an array in the order of the jQuery set
* - Method access either chains when no results are returned, or returns
* an array of return values when the method in question has a return value
*/
$.fn.CHANGEME = function(func) {
var args = arguments;
var classStorageKey = 'CHANGEME';
// constructor to create an object and bind it to our elements
var init = function (options) {
this.data(classStorageKey, new CHANGEME(this, options));
};
var fnCall = false, // function calls can either chain when no results are returned or return arrays of results
results = [],
args = arguments;
this.each(function() {
var t = $(this);
var myObject = t.data(classStorageKey);
// Run the appropriate behaviour
if (func != undefined && myObject != undefined) {
if (typeof myObject[func] == 'function') {
// object function call
fnCall = true;
results.push(myObject[func].apply( myObject, Array.prototype.slice.call( args, 1 )));
return true;
} else {
// intance variable request
results.push(myObject[func]);
return true;
}
} else if (typeof func === 'object' || !func ) {
// create a new object, optionally passing options map
init.apply( t, args );
return true; // continue creating for each matched element
} else {
$.error( 'Method ' + func + ' does not exist in CHANGEME' );
}
});
// if the results from all function calls are undefined, there are no results!
if (fnCall) {
var allUndef = true;
for (var i = 0; i < results.length; i++) {
if (typeof results[i] != 'undefined') {
allUndef = false;
break;
}
}
if (allUndef) {
results = [];
}
}
return results.length ? (results.length == 1 ? results[0] : results) : this;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment