Created
January 23, 2014 15:04
-
-
Save NullVoxPopuli/8579983 to your computer and use it in GitHub Desktop.
An attempt to make working with jQuery a little more object oriented
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
/* | |
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; | |
} | |
}; |
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
/* | |
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; | |
}; |
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
/* | |
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; | |
} | |
} | |
}); |
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
/* 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"); | |
}, | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Since the description doesn't do formatting:
This idea is a little half baked.
example usage:
$tb("body")
would inherit all theProposal
instance methods