Created
September 16, 2013 17:15
-
-
Save tomconnors/6583595 to your computer and use it in GitHub Desktop.
an alternate api for the Meteor template lifecycle
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
//============================================================================== | |
// template utilities | |
// making Meteor's template api a bit less, well, awful | |
//============================================================================== | |
define([ | |
"lib/ext" | |
], | |
function(ext){ | |
"use strict"; | |
var | |
/* | |
* internal mappings of templateNames to callbacks | |
*/ | |
_createdFns = {}, | |
_destroyedFns = {}, | |
_renderedFns = {}, | |
_firstRenderFns = {}, | |
/* | |
* add a callback `fn` for `eventName` (created | rendered | destroyed) | |
* for the template Template[templateName] | |
*/ | |
addCallback = function(eventName, callbacks, templateName, fn){ | |
var callbacksFortemplateName = callbacks[templateName]; | |
if(callbacksFortemplateName){ | |
callbacks[templateName].push(fn); | |
} else { | |
callbacksFortemplateName = callbacks[templateName] = [fn]; | |
var oldCallback = Template[templateName][eventName]; | |
Template[templateName][eventName] = function(){ | |
var instance = this; | |
_.each(callbacks[templateName], function(callback){ | |
callback(instance); | |
}); | |
_.isFunction(oldCallback) && oldCallback.call(instance); | |
}; | |
} | |
}, | |
/* | |
* remove `fn` as a callback for some event for Template[templateName]. | |
* if fn isn't provided, remove all callbacks for that template + event. | |
*/ | |
removeCallback = function(callbacks, templateName, fn){ | |
var callbacksFortemplateName = callbacks[templateName]; | |
if(callbacksFortemplateName){ | |
if(fn){ | |
callbacksFortemplateName.splice(_.indexOf(fn), 1); | |
} else { | |
callbacks[templateName] = []; | |
} | |
} | |
}, | |
addCreatedCallback = _.partial(addCallback, "created", _createdFns), | |
addDestroyedCallback = _.partial(addCallback, "destroyed", _destroyedFns), | |
addRenderedCallback = _.partial(addCallback, "rendered", _renderedFns), | |
/* | |
* only call `fn` when the first `rendered` callback fires, per instance of Template[templateName] | |
*/ | |
addFirstRenderCallback = function(templateName, fn){ | |
var | |
callbacks = _firstRenderFns[templateName], | |
doCallback = false; | |
if(callbacks){ | |
_firstRenderFns[templateName].push(fn); | |
} else { | |
callbacks = _firstRenderFns[templateName] = [fn]; | |
addCreatedCallback(templateName, function(instance){ doCallback = true; }); | |
addRenderedCallback(templateName, function(instance){ | |
if(doCallback){ | |
doCallback = false; | |
_.each(_firstRenderFns[templateName], ext.invoke(instance)); | |
} | |
}); | |
} | |
}, | |
removeCreatedCallback = _.partial(removeCallback, _createdFns), | |
removeDestroyedCallback = _.partial(removeCallback, _destroyedFns), | |
removeRenderedCallback = _.partial(removeCallback, _renderedFns), | |
removeFirstRenderCallback = _.partial(removeCallback, _firstRenderFns), | |
/* | |
* add event listeners that are dependent upon the existence of an | |
* instance of Template[templateName], but which are not | |
* inside of that instance's DOM. | |
* @example | |
* addExternalEventListeners('popup', { "click .elsewhere": function(e, template){ closeThePopup(); } }); | |
*/ | |
addExternalEventListeners = function(templateName, eventMap){ | |
var handlers = {}; | |
addCreatedCallback(templateName, function(instance){ | |
_.each(eventMap, function(handler, name){ | |
var | |
splitKey = name.split(" "), | |
event = _.first(splitKey), | |
selector = splitKey.length === 1 ? null : _.rest(splitKey).join(" "), | |
$el = selector ? $(selector) : $(document.body); | |
handlers[name] = function(e){ | |
handler(e, instance); | |
}; | |
$el.on(event, handlers[name]); | |
}); | |
}); | |
addDestroyedCallback(templateName, function(instance){ | |
_.each(eventMap, function(handler, name){ | |
var | |
splitKey = name.split(" "), | |
event = _.first(splitKey), | |
selector = splitKey.length === 1 ? null : _.rest(splitKey).join(" "), | |
$el = selector ? $(selector) : $(document.body); | |
$el.off(event, handlers[name]); | |
delete handlers[name]; | |
}); | |
}); | |
}; | |
return { | |
addCreatedCallback: addCreatedCallback, | |
addDestroyedCallback: addDestroyedCallback, | |
addRenderedCallback: addRenderedCallback, | |
addFirstRenderCallback: addFirstRenderCallback, | |
removeCreatedCallback: removeCreatedCallback, | |
removeDestroyedCallback: removeDestroyedCallback, | |
removeRenderedCallback: removeRenderedCallback, | |
removeFirstRenderCallback: removeFirstRenderCallback, | |
addExternalEventListeners: addExternalEventListeners | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment