Skip to content

Instantly share code, notes, and snippets.

@TSMMark
Created October 7, 2014 16:48
Show Gist options
  • Save TSMMark/2addf47a9f4365468a03 to your computer and use it in GitHub Desktop.
Save TSMMark/2addf47a9f4365468a03 to your computer and use it in GitHub Desktop.
Demplate
var $ = require("jQuery")
, Delegator
;
Delegator = function () {
this.$el = $("<p/>");
}
// Add a function to the object that delegates to a property on the same object.
//
// @param obj [Object] - the object to add the function to.
// @param functionName [String] - the name of the function to delegate.
// @param delegateToPropName [String] - the name of the property on the object to delegate to.
//
// @return objFunction [Function] - the function that was created.
Delegator.delegate = function (obj, functionName, delegateToPropName) {
var objFunction = function () {
var delegateTo = this[delegateToPropName];
return delegateTo[functionName].apply(delegateTo, arguments);
}
return obj[functionName] = objFunction;
}
// Add basic event functions to an object.
// functions added: `on` `off` `trigger`
//
// @param obj [Object] - the object to add the functions to.
// @param delegateToPropName [String] - the name of the property on the object to delegate to.
//
// Example use:
// Delegator.extendEventDelegation(MyClass.prototype, "delegator");
Delegator.extendEventDelegation = function (obj, delegateToPropName) {
// Listen for an event.
Delegator.delegate(obj, "on", delegateToPropName);
// Stop listening for an event.
Delegator.delegate(obj, "off", delegateToPropName);
// Trigger an event.
Delegator.delegate(obj, "trigger", delegateToPropName);
}
// Delegate event functions to $el.
Delegator.extendEventDelegation(Delegator.prototype, "$el");
module.exports = Delegator;
var $ = require("jQuery")
, template = require("../template")
, Delegator = require("../Delegator")
, Model = require("./Model")
, Demplate
;
// Demplate: Data-Dependent Template
// @param el [Selector] - the element to render the template into
// @param templateID [String] - the ID of the script element with the template data
// @param options [Object] - key/value object of options
// @option data [Object] - the data to pass to the model
// @option model [Model] - the demplate Model
Demplate = function (el, templateID, options) {
options = (options || {});
this.$el = $(el);
this.templateID = templateID;
this.options = options;
this.model = (options.model || new Model(options.data || {}));
this.currentContent = undefined;
this.bindings = [];
this.bindListeners();
}
// Listen for key events.
// Events:
// render - triggered after new content is rendered.
// teardown - triggered before render if any rendered content already existed.
Delegator.delegate(Demplate.prototype, "on", "$el");
// Set the value of a key from the model and trigger a render.
Delegator.delegate(Demplate.prototype, "set", "model");
// Get the value of a key from the model.
Delegator.delegate(Demplate.prototype, "get", "model");
// Register an event which will be bound to matching elements after content is rendered.
// Events will be automatically unbound on tearddown to avoid rogue listeners.
//
// @param selector [String]
// @param eventName [String]
// @param fn [callback]
Demplate.prototype.bind = function (selector, eventName, fn) {
this.bindings.push([selector, eventName, fn]);
}
Demplate.prototype.render = function () {
var content = template(this.templateID, this.model.data);
this.setContent(content);
}
Demplate.prototype.clear = function () {
this.setContent("");
}
Demplate.prototype.setContent = function (content) {
if (this.currentContent) {
this._onTeardown();
this.$el.trigger("teardown", [this.$el]);
}
this.currentContent = content;
this.$el.html(content);
this._onRender();
this.$el.trigger("render", [this.$el]);
}
// For each binding, setup a listener.
Demplate.prototype._onRender = function () {
var self = this
, $el, eventName, fn;
$.each(self.bindings, function (_, data) {
$el = self.$el.find(data[0]);
eventName = data[1];
fn = data[2];
$el.on(eventName, fn);
});
}
// Remove each binding listener.
Demplate.prototype._onTeardown = function () {
var self = this
, $el, eventName, fn;
$.each(self.bindings, function (_, data) {
$el = self.$el.find(data[0]);
eventName = data[1];
fn = data[2];
$el.off(eventName, fn);
});
}
Demplate.prototype.bindListeners = function () {
var self = this;
self.model.on("change", function (event, key, value) {
self.render();
});
}
module.exports = Demplate;
var $ = require("jQuery")
, Delegator = require("../Delegator")
, Model
;
// TODO: Store default so that it may be reset
Model = function (data) {
this.data = (data || {});
this.delegator = new Delegator();
}
// Set a single attribute or multiple attributes and trigger the "change" event.
Model.prototype.set = function () {
var attributes, key, value;
if (arguments.length == 1) {
attributes = arguments[0];
this._setMultiple(attributes);
}
else {
key = arguments[0];
value = arguments[1];
this._setSingle(key, value);
}
this.delegator.trigger("change", [key, value]);
}
Model.prototype.get = function (key) {
return this.data[key];
}
Model.prototype._setSingle = function (key, value) {
this.data[key] = value;
}
Model.prototype._setMultiple = function (attributes) {
var self = this;
$.each(attributes, function (key, value) {
self._setSingle(key, value);
});
}
Delegator.extendEventDelegation(Model.prototype, "delegator");
module.exports = Model;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment