Skip to content

Instantly share code, notes, and snippets.

@gre
Created Feb 3, 2012
Embed
What would you like to do?
SelectorTemplating is a simple CSS-selector-based JavaScript templating.

SelectorTemplating is a simple CSS-selector-based JavaScript templating.

Whereas most templates use inherence, this one is based on "mixin", You can easily mix template fragment each others with the power of CSS selector (like in a CSS file).

It is made for highly modular and loosely coupled JS libraries or applications.

Hence, It perfectly fits the Scalable JavaScript Application Architecture

More infos

http://blog.greweb.fr/2012/02/css-selector-based-templating-example-with-javascript/

License

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
(function ($) {
/**
* SelectorTemplating.js
* License: GPL v3
* Author: gaetanrenaudeau.fr - 2012
* Link: https://gist.github.com/gists/1731611
*/
this.SelectorTemplating = function (container, onTemplated) {
var self = this,
rootTemplate, // type of Arguments
fragments = []; // Array of { selector: ".container", tmpl: function(i){ return "html"; } }
self.add = function (containerSelector, template, callback, priority) {
fragments.push({
tmpl: template,
cb: callback,
selector: containerSelector,
priority: priority || 0
});
return self;
}
self.remove = function (template) {
var i = $.indexOf($.map(fragments, function (t) { return t.tmpl }), template);
if (i >= 0) fragments.splice(i, 1);
return self;
}
self.refresh = function (template) {
self.compile();
}
// Template the whole thing
self.compile = function () {
var cbs = [],
i = 0,
waitList, el, nodes, created,
somethingChangedThisLoop;
// empty the container
self.destroy();
// all fragments goes to a waitlist, we need to append them all.
// When a selector matches nodes, we append the template in nodes and remove from the waitlist.
waitList = [].concat(fragments);
waitList.sort(function (a, b) {
return (a.priority != b.priority) ?
(b.priority - a.priority) : // higher priority first
(a.selector < b.selector ? -1 : 1); // try to put root selector first (guess)
});
while (waitList.length) {
el = waitList[i];
// Try to find the container
nodes = !el.selector ? [container] : $.find(container, el.selector);
if (nodes.length) {
somethingChangedThisLoop = true;
// template into each containers.
created = $.map(nodes, function(node, i) {
return $.append(node, el.tmpl(i));
});
el.nodes = created;
// remove from the waitlist
waitList.splice(i, 1);
i = 0;
}
else {
// continue the loop if we have waitList and something has changed the last loop.
if (++i >= waitList.length) {
i = 0;
if(!somethingChangedThisLoop) break;
somethingChangedThisLoop = false;
}
}
}
$.each(fragments, function (template) {
template.cb && template.cb(template.nodes, container);
});
onTemplated && onTemplated();
return self;
}
// Clean the template
self.destroy = function () {
$.html(container, '');
$.each(fragments, function (template) {
template.nodes = [];
});
return self;
}
}
}(sliderjs.util));
// SOME UTILS YOU HAVE TO DEFINE SOMEWHERE (or use jQuery and adapt the code)
var $ = {
html: function (element, html) { if(element) element.innerHTML = html; },
append: function (element, html) { // add only the first node of html in element and return this node.
var div = document.createElement("div");
div.innerHTML = html;
return element.appendChild(div.firstChild);
},
find: function (element, css) {
if(!element) return [];
return element.querySelectorAll(css);
},
each: function (a,f){
if(a.forEach) a.forEach(f); else for(var i=0; i<a.length; ++i) f(a[i], i, a);
},
map: function (a,f){
var t=[]; $.each(a, function (v,i,l){ t[i]=f(v,i,l); }); return t;
},
indexOf: function (t, a) {
if (t.indexOf) return t.indexOf(a);
for(var i=0; i<t.length; i++)
if(t[i]==a)
return i;
return -1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment