Skip to content

Instantly share code, notes, and snippets.

@NullVoxPopuli
Created January 23, 2014 15:04
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 NullVoxPopuli/8579983 to your computer and use it in GitHub Desktop.
Save NullVoxPopuli/8579983 to your computer and use it in GitHub Desktop.
An attempt to make working with jQuery a little more object oriented
/*
Builds a set of actions that are specific to each document type
= require_self
= require_tree ./models
*/
window.TB = window.TB || {};
TB.Object = jQuery.subclass();
$.extend(TB.Object, {
/* static */
selector: "",
className: "Object",
find: function() {
return $tb(this.selector);
}
});
$.extend(TB.Object.fn, {
/* instance */
});
/*
add helper method to the TB namespace such that we can
register classes to it
*/
$.extend(TB, {
/*
When we create a model, we need to register it here
in order to use it with the $ (jQuery) helper function
"Proposal",
"Template",
etc
probable others:
- scrollable
- rfp
- presentation
examples:
TB.registerModel("Proposal");
TB.registerModel("TableOfContents", {
namespace: TB.Proposal,
instanceMethods: {
}
});
*/
/*
creates a model in the TB namespace
name - the name of the model
options -
- static - functions available without an instance of the class
- instance - functions only available on a jQuery element
- namespace - which namespace to add this class to
*/
registerModel: function(name, options) {
/*
stuff to be included with every class
*/
var defaults = {
staticMethods: {},
instanceMethods: {},
namespace: null
}
var options = $.extend({}, defaults, options);
/*
determine which namespace to add to
*/
var parent = !!options.namespace ? options.namespace : this;
var parentSelector = !!options.namespace ? parent.selector : "";
/*
build and add the class
when we nest namespaces, we need to concat the child's
selector with the parent's selector, so that we minimize DOM
searching
*/
parent[name] = TB.Object.subclass();
$.extend(parent[name], options.staticMethods, {
selector: parentSelector + " " + options.staticMethods.selector,
className: name
});
$.extend(parent[name].fn, options.instanceMethods, {
/*
so instance methods have an easier time accessing this
*/
selector: parent[name].selector,
class: parent[name]
});
}
});
/*
we need a way to use a simple $-like helper, and have
the elements automatically take on one of our defined
subclasses
overriding $.fn.init would be ideal, but doesn't have
a straight forward implementation.
but because we want to dynamically use the correct
subclass, instead of writing a giant if-then block,
each element that is going to be designated as an instante
of one our subclasses / models is going to need a
data-class attribute, matching the name of the intended model
unfortunately, that requires us to make two searches
through the DOM
- once to find the element, so we can check for a data-class
- again to re-generate the element so it can be that class
- as often as possible, we should scope our use of $tb and .find()
in order to shorten the search time
other thought of implementations:
1. iterate through all the registered class names, and see if
the passed selector matches the one defined for that class
- results in only one DOM search
- requires that the selector include the class name... which
is exactly what we want to avaid, because subclassing
should be automatic in order to be the most flexible for
the js coder
2. somehow dynamically add an if-clause to $tb when
registering a class
- same benifits / drawbacks as #1
*/
window.$tb = function(selector, context) {
var jQueryInstance = $(selector, context);
if ( !! (klass = jQueryInstance.attr("data-class"))) {
/*
class found, re-instantiate as subclass
*/
return TB[klass](selector, context);
} else {
/*
otherwise default to standard jQuery
*/
return jQueryInstance;
}
};
/*
http://stackoverflow.com/questions/5280631/subclassing-a-jquery-object
- We can easily build custom widgets without cluttering the jQuery namespace.
- We can provide our own implementations of jQuery methods
- We can make use of jQuery's power with methods like trigger and bind already part of the class
*/
jQuery.subclass = function() {
function jQuerySubclass(selector, context) {
return new jQuerySubclass.fn.init(selector, context);
}
jQuery.extend(true, jQuerySubclass, this);
jQuerySubclass.superclass = this;
jQuerySubclass.fn = jQuerySubclass.prototype = this();
jQuerySubclass.fn.constructor = jQuerySubclass;
jQuerySubclass.fn.init = function init(selector, context) {
if (context && context instanceof jQuery && !(context instanceof jQuerySubclass)) {
context = jQuerySubclass(context);
}
return jQuery.fn.init.call(this, selector, context, rootjQuerySubclass);
};
jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;
var rootjQuerySubclass = jQuerySubclass(document);
return jQuerySubclass;
};
/*
accessing navigation, and other helpers
*/
TB.registerModel("Proposal", {
staticMethods: {
/*
help with selecting proposals explicitly
$tb(TB.Proposal.selector);
*/
selector: "[data-class=Proposal]",
Section: {
},
Page: {
},
Attachment: {
}
},
instanceMethods: {
/*
Proposals don't display sections
*/
sections: function() {
return [];
},
/*
collection of the content/page bodies
*/
pages: function() {
return $(".document-content");
},
tableOfContents: function() {
var toc = TB.Proposal.TableOfContents(TB.Proposal.TableOfContents.selector);
toc.proposal = this;
toc.self = toc;
return toc;
}
}
});
/* example. assumes TB.Proposal already exists */
TB.registerModel("TableOfContents", {
namespace: TB.Proposal,
staticMethods: {
selector: "[data-class=TableOfContents]",
Section: [],
Page: [],
Attachment: []
},
instanceMethods: {
proposal: [],
init: function(){
},
/*
has to be set be the instantiator
- would be cool if this could be set automatically
when TableOfContents is init'd
*/
proposal: function() {
return proposal;
},
sections: function() {
return $(this.selector + ".sections");
},
pages: function() {
return $(this.selector + " .pages");
},
}
});
@NullVoxPopuli
Copy link
Author

Since the description doesn't do formatting:

This idea is a little half baked.

  • This needs the ability to instantiate subclasses based on the element that is selected, to reduce DOM search time.
  • If the selected element doesn't have bindings for that subclass, they need to be added.
  • how do I use a parent namespace's element to help scope finding of children elements?
  • What is the best way to init the elements on page load?
  • If everything is object oriented, like in a backend language, when / how does initting happen?

example usage:

$tb("body") would inherit all the Proposal instance methods

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment