Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Ejs, Haml, Pure, Tmpl

  • Loading branch information...
commit e03cb05958c81b57bdfbffed8b5bb30fdb7660a4 1 parent b433f52
@quirkey quirkey authored
View
4 .gitignore
@@ -1,7 +1,7 @@
-tmp*
+tmp/*
.lock
.bundle
.rvmrc
_layouts
_site
-.DS_Store
+.DS_Store
View
679 lib/plugins/sammy.ejs.js
@@ -1,677 +1,12 @@
(function($) {
- // Embeddedjs is property of http://embeddedjs.com/
- // Sammy ejs plugin written Codeofficer @ http://www.codeofficer.com/
-
- var rsplit = function(string, regex) {
- var result = regex.exec(string),
- retArr = new Array(),
- first_idx, last_idx, first_bit;
- while (result != null) {
- first_idx = result.index;
- last_idx = regex.lastIndex;
- if ((first_idx) != 0) {
- first_bit = string.substring(0, first_idx);
- retArr.push(string.substring(0, first_idx));
- string = string.slice(first_idx);
- };
- retArr.push(result[0]);
- string = string.slice(result[0].length);
- result = regex.exec(string);
- };
- if (! string == '') {
- retArr.push(string);
- };
- return retArr;
- };
-
- var chop = function(string) {
- return string.substr(0, string.length - 1);
- };
-
- var extend = function(d, s) {
- for (var n in s) {
- if(s.hasOwnProperty(n)) d[n] = s[n];
- };
- };
-
- /* @Constructor*/
- EJS = function(options) {
- options = (typeof(options) == "string") ? {view: options} : options;
- this.set_options(options);
- if (options.precompiled) {
- this.template = {};
- this.template.process = options.precompiled;
- EJS.update(this.name, this);
- return;
- };
- if (options.element) {
- if (typeof(options.element) == 'string') {
- var name = options.element;
- options.element = document.getElementById(options.element);
- if (options.element == null) throw name + 'does not exist!';
- };
- if (options.element.value) {
- this.text = options.element.value;
- } else {
- this.text = options.element.innerHTML;
- };
- this.name = options.element.id;
- this.type = '[';
- } else if (options.url) {
- options.url = EJS.endExt(options.url, this.extMatch);
- this.name = this.name ? this.name : options.url;
- var url = options.url;
- //options.view = options.absolute_url || options.view || options.;
- var template = EJS.get(this.name /*url*/, this.cache);
- if (template) return template;
- if (template == EJS.INVALID_PATH) return null;
- try {
- this.text = EJS.request( url + (this.cache ? '' : '?' + Math.random() ));
- } catch(e) {};
- if (this.text == null) {
- throw( {type: 'EJS', message: 'There is no template at '+url} );
- };
- //this.name = url;
- };
- var template = new EJS.Compiler(this.text, this.type);
- template.compile(options, this.name);
- EJS.update(this.name, this);
- this.template = template;
- };
-
- /* @Prototype*/
- EJS.prototype = {
- /**
- * Renders an object with extra view helpers attached to the view.
- * @param {Object} object data to be rendered
- * @param {Object} extra_helpers an object with additonal view helpers
- * @return {String} returns the result of the string
- */
- render : function(object, extra_helpers) {
- object = object || {};
- this._extra_helpers = extra_helpers;
- var v = new EJS.Helpers(object, extra_helpers || {});
- return this.template.process.call(object, object,v);
- },
-
- update : function(element, options) {
- if (typeof(element) == 'string') {
- element = document.getElementById(element);
- };
- if (options == null) {
- _template = this;
- return function(object) {
- EJS.prototype.update.call(_template, element, object);
- };
- };
- if (typeof(options) == 'string') {
- params = {};
- params.url = options;
- _template = this;
- params.onComplete = function(request) {
- var object = eval(request.responseText);
- EJS.prototype.update.call(_template, element, object);
- };
- EJS.ajax_request(params);
- } else {
- element.innerHTML = this.render(options);
- };
- },
-
- out : function() {
- return this.template.out;
- },
-
- /**
- * Sets options on this view to be rendered with.
- * @param {Object} options
- */
- set_options : function(options){
- this.type = options.type || EJS.type;
- this.cache = (options.cache != null) ? options.cache : EJS.cache;
- this.text = options.text || null;
- this.name = options.name || null;
- this.ext = options.ext || EJS.ext;
- this.extMatch = new RegExp(this.ext.replace(/\./, '\.'));
- }
- };
-
- EJS.endExt = function(path, match) {
- if (!path) return null;
- match.lastIndex = 0;
- return path + (match.test(path) ? '' : this.ext);
- };
-
- /* @Static*/
- EJS.Scanner = function(source, left, right) {
- extend(this, {
- left_delimiter: left +'%',
- right_delimiter: '%'+right,
- double_left: left+'%%',
- double_right: '%%'+right,
- left_equal: left+'%=',
- left_comment: left+'%#'
- });
- this.SplitRegexp = (left == '[') ? /(\[%%)|(%%\])|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/ : new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)');
- this.source = source;
- this.stag = null;
- this.lines = 0;
- };
-
- EJS.Scanner.to_text = function(input) {
- if (input == null || input === undefined) return '';
- if(input instanceof Date) return input.toDateString();
- if(input.toString) return input.toString();
- return '';
- };
-
- EJS.Scanner.prototype = {
- scan: function(block) {
- scanline = this.scanline;
- regex = this.SplitRegexp;
- if (! this.source == '') {
- var source_split = rsplit(this.source, /\n/);
- for (var i=0; i<source_split.length; i++) {
- var item = source_split[i];
- this.scanline(item, regex, block);
- };
- };
- },
-
- scanline: function(line, regex, block) {
- this.lines++;
- var line_split = rsplit(line, regex);
- for (var i=0; i<line_split.length; i++) {
- var token = line_split[i];
- if (token != null) {
- try {
- block(token, this);
- } catch(e) {
- throw {type: 'EJS.Scanner', line: this.lines};
- };
- };
- };
- }
- };
-
- EJS.Buffer = function(pre_cmd, post_cmd) {
- this.line = new Array();
- this.script = "";
- this.pre_cmd = pre_cmd;
- this.post_cmd = post_cmd;
- for (var i=0; i<this.pre_cmd.length; i++) {
- this.push(pre_cmd[i]);
- };
- };
-
- EJS.Buffer.prototype = {
- push: function(cmd) {
- this.line.push(cmd);
- },
-
- cr: function() {
- this.script = this.script + this.line.join('; ');
- this.line = new Array();
- this.script = this.script + "\n";
- },
-
- close: function() {
- if (this.line.length > 0) {
- for (var i=0; i<this.post_cmd.length; i++){
- this.push(pre_cmd[i]);
- };
- this.script = this.script + this.line.join('; ');
- line = null;
- };
- }
- };
-
- EJS.Compiler = function(source, left) {
- this.pre_cmd = ['var ___ViewO = [];'];
- this.post_cmd = new Array();
- this.source = ' ';
- if (source != null) {
- if (typeof(source) == 'string') {
- source = source.replace(/\r\n/g, "\n");
- source = source.replace(/\r/g, "\n");
- this.source = source;
- } else if (source.innerHTML) {
- this.source = source.innerHTML;
- };
- if (typeof this.source != 'string') {
- this.source = "";
- };
- };
- left = left || '<';
- var right = '>';
- switch(left) {
- case '[':
- right = ']';
- break;
- case '<':
- break;
- default:
- throw left+' is not a supported deliminator';
- break;
- };
- this.scanner = new EJS.Scanner(this.source, left, right);
- this.out = '';
- };
-
- EJS.Compiler.prototype = {
- compile: function(options, name) {
- options = options || {};
- this.out = '';
- var put_cmd = "___ViewO.push(";
- var insert_cmd = put_cmd;
- var buff = new EJS.Buffer(this.pre_cmd, this.post_cmd);
- var content = '';
- var clean = function(content) {
- content = content.replace(/\\/g, '\\\\');
- content = content.replace(/\n/g, '\\n');
- content = content.replace(/"/g, '\\"');
- return content;
- };
- this.scanner.scan(function(token, scanner) {
- if (scanner.stag == null) {
- switch(token) {
- case '\n':
- content = content + "\n";
- buff.push(put_cmd + '"' + clean(content) + '");');
- buff.cr();
- content = '';
- break;
- case scanner.left_delimiter:
- case scanner.left_equal:
- case scanner.left_comment:
- scanner.stag = token;
- if (content.length > 0) {
- buff.push(put_cmd + '"' + clean(content) + '")');
- };
- content = '';
- break;
- case scanner.double_left:
- content = content + scanner.left_delimiter;
- break;
- default:
- content = content + token;
- break;
- };
- } else {
- switch(token) {
- case scanner.right_delimiter:
- switch(scanner.stag) {
- case scanner.left_delimiter:
- if (content[content.length - 1] == '\n') {
- content = chop(content);
- buff.push(content);
- buff.cr();
- } else {
- buff.push(content);
- };
- break;
- case scanner.left_equal:
- buff.push(insert_cmd + "(EJS.Scanner.to_text(" + content + ")))");
- break;
- };
- scanner.stag = null;
- content = '';
- break;
- case scanner.double_right:
- content = content + scanner.right_delimiter;
- break;
- default:
- content = content + token;
- break;
- };
- };
- });
- if (content.length > 0) {
- // Chould be content.dump in Ruby
- buff.push(put_cmd + '"' + clean(content) + '")');
- };
- buff.close();
- this.out = buff.script + ";";
- var to_be_evaled = '/*' + name + '*/this.process = function(_CONTEXT,_VIEW) { try { with(_VIEW) { with (_CONTEXT) {' + this.out + " return ___ViewO.join('');}}}catch(e){e.lineNumber=null;throw e;}};";
- try {
- eval(to_be_evaled);
- } catch(e) {
- if (typeof JSLINT != 'undefined') {
- JSLINT(this.out);
- for (var i = 0; i < JSLINT.errors.length; i++) {
- var error = JSLINT.errors[i];
- if (error.reason != "Unnecessary semicolon.") {
- error.line++;
- var e = new Error();
- e.lineNumber = error.line;
- e.message = error.reason;
- if (options.view) e.fileName = options.view;
- throw e;
- };
- };
- } else {
- throw e;
- };
- };
- }
- };
-
- //type, cache, folder
- /**
- * Sets default options for all views
- * @param {Object} options Set view with the following options
- * <table class="options">
- <tbody><tr><th>Option</th><th>Default</th><th>Description</th></tr>
- <tr>
- <td>type</td>
- <td>'<'</td>
- <td>type of magic tags. Options are '&lt;' or '['
- </td>
- </tr>
- <tr>
- <td>cache</td>
- <td>true in production mode, false in other modes</td>
- <td>true to cache template.
- </td>
- </tr>
- </tbody></table>
- *
- */
- EJS.config = function(options){
- EJS.cache = (options.cache != null) ? options.cache : EJS.cache;
- EJS.type = (options.type != null) ? options.type : EJS.type;
- EJS.ext = (options.ext != null) ? options.ext : EJS.ext;
- var templates_directory = EJS.templates_directory || {}; //nice and private container
- EJS.templates_directory = templates_directory;
- EJS.get = function(path, cache) {
- if(cache == false) return null;
- if(templates_directory[path]) return templates_directory[path];
- return null;
- };
- EJS.update = function(path, template) {
- if (path == null) return;
- templates_directory[path] = template ;
- };
- EJS.INVALID_PATH = -1;
- };
- EJS.config( {cache: true, type: '<', ext: '.ejs' } );
-
- /**
- * @constructor
- * By adding functions to EJS.Helpers.prototype, those functions will be available in the
- * views.
- * @init Creates a view helper. This function is called internally. You should never call it.
- * @param {Object} data The data passed to the view. Helpers have access to it through this._data
- */
- EJS.Helpers = function(data, extras){
- this._data = data;
- this._extras = extras;
- extend(this, extras);
- };
-
- /* @prototype*/
- EJS.Helpers.prototype = {
- /**
- * Renders a new view. If data is passed in, uses that to render the view.
- * @param {Object} options standard options passed to a new view.
- * @param {optional:Object} data
- * @return {String}
- */
- view: function(options, data, helpers) {
- if (!helpers) helpers = this._extras;
- if (!data) data = this._data;
- return new EJS(options).render(data, helpers);
- },
- /**
- * For a given value, tries to create a human representation.
- * @param {Object} input the value being converted.
- * @param {Object} null_text what text should be present if input == null or undefined, defaults to ''
- * @return {String}
- */
- to_text: function(input, null_text) {
- if (input == null || input === undefined) return null_text || '';
- if (input instanceof(Date)) return input.toDateString();
- if (input.toString) return input.toString().replace(/\n/g, '<br />').replace(/''/g, "'");
- return '';
- }
- };
-
- EJS.newRequest = function() {
- var factories = [function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }];
- for(var i = 0; i < factories.length; i++) {
- try {
- var request = factories[i]();
- if (request != null) return request;
- } catch(e) { continue; }
- };
- };
-
- EJS.request = function(path) {
- var request = new EJS.newRequest();
- request.open("GET", path, false);
- try {
- request.send(null);
- } catch(e){
- return null;
- };
- if ( request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) return null;
- return request.responseText;
- };
-
- EJS.ajax_request = function(params) {
- params.method = ( params.method ? params.method : 'GET');
- var request = new EJS.newRequest();
- request.onreadystatechange = function() {
- if (request.readyState == 4) {
- if (request.status == 200) {
- params.onComplete(request);
- } else {
- params.onComplete(request);
- };
- };
- };
- request.open(params.method, params.url);
- request.send(null);
- };
-
- EJS.Helpers.prototype.date_tag = function(name, value , html_options) {
- if(!(value instanceof(Date))) value = new Date();
- var month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
- var years = [], months = [], days =[];
- var year = value.getFullYear();
- var month = value.getMonth();
- var day = value.getDate();
- for (var y = year - 15; y < year+15 ; y++) {
- years.push({value: y, text: y});
- };
- for (var m = 0; m < 12; m++) {
- months.push({value: (m), text: month_names[m]});
- };
- for (var d = 0; d < 31; d++) {
- days.push({value: (d+1), text: (d+1)});
- };
- var year_select = this.select_tag(name+'[year]', year, years, {id: name+'[year]'} );
- var month_select = this.select_tag(name+'[month]', month, months, {id: name+'[month]'});
- var day_select = this.select_tag(name+'[day]', day, days, {id: name+'[day]'});
- return year_select+month_select+day_select;
- };
-
- EJS.Helpers.prototype.form_tag = function(action, html_options) {
- html_options = html_options || {};
- html_options.action = action;
- if(html_options.multipart == true) {
- html_options.method = 'post';
- html_options.enctype = 'multipart/form-data';
- };
- return this.start_tag_for('form', html_options);
- };
-
- EJS.Helpers.prototype.form_tag_end = function() {
- return this.tag_end('form');
- };
-
- EJS.Helpers.prototype.hidden_field_tag = function(name, value, html_options) {
- return this.input_field_tag(name, value, 'hidden', html_options);
- };
-
- EJS.Helpers.prototype.input_field_tag = function(name, value , inputType, html_options) {
- html_options = html_options || {};
- html_options.id = html_options.id || name;
- html_options.value = value || '';
- html_options.type = inputType || 'text';
- html_options.name = name;
- return this.single_tag_for('input', html_options);
- };
-
- EJS.Helpers.prototype.is_current_page = function(url) {
- return (window.location.href == url || window.location.pathname == url ? true : false);
- };
-
- EJS.Helpers.prototype.link_to = function(name, url, html_options) {
- if(!name) var name = 'null';
- if(!html_options) var html_options = {};
- if(html_options.confirm){
- html_options.onclick = " var ret_confirm = confirm(\""+html_options.confirm+"\"); if(!ret_confirm){ return false;} ";
- html_options.confirm = null;
- };
- html_options.href = url;
- return this.start_tag_for('a', html_options)+name+ this.tag_end('a');
- };
-
- EJS.Helpers.prototype.submit_link_to = function(name, url, html_options) {
- if(!name) var name = 'null';
- if(!html_options) var html_options = {};
- html_options.onclick = html_options.onclick || '';
- if(html_options.confirm){
- html_options.onclick = " var ret_confirm = confirm(\""+html_options.confirm+"\"); if(!ret_confirm){ return false;} ";
- html_options.confirm = null;
- };
- html_options.value = name;
- html_options.type = 'submit';
- html_options.onclick = html_options.onclick + (url ? this.url_for(url) : '')+'return false;';
- return this.start_tag_for('input', html_options);
- };
-
- EJS.Helpers.prototype.link_to_if = function(condition, name, url, html_options, post, block) {
- return this.link_to_unless((condition == false), name, url, html_options, post, block);
- };
-
- EJS.Helpers.prototype.link_to_unless = function(condition, name, url, html_options, block) {
- html_options = html_options || {};
- if(condition) {
- if(block && typeof(block) == 'function') {
- return block(name, url, html_options, block);
- } else {
- return name;
- };
- } else {
- return this.link_to(name, url, html_options);
- };
- };
-
- EJS.Helpers.prototype.link_to_unless_current = function(name, url, html_options, block) {
- html_options = html_options || {};
- return this.link_to_unless(this.is_current_page(url), name, url, html_options, block);
- };
-
-
- EJS.Helpers.prototype.password_field_tag = function(name, value, html_options) {
- return this.input_field_tag(name, value, 'password', html_options);
- };
-
- EJS.Helpers.prototype.select_tag = function(name, value, choices, html_options) {
- html_options = html_options || {};
- html_options.id = html_options.id || name;
- html_options.value = value;
- html_options.name = name;
- var txt = '';
- txt += this.start_tag_for('select', html_options);
- for(var i = 0; i < choices.length; i++) {
- var choice = choices[i];
- var optionOptions = {value: choice.value};
- if(choice.value == value) optionOptions.selected ='selected';
- txt += this.start_tag_for('option', optionOptions )+choice.text+this.tag_end('option');
- };
- txt += this.tag_end('select');
- return txt;
- };
-
- EJS.Helpers.prototype.single_tag_for = function(tag, html_options) {
- return this.tag(tag, html_options, '/>');
- };
-
- EJS.Helpers.prototype.start_tag_for = function(tag, html_options) {
- return this.tag(tag, html_options);
- };
-
- EJS.Helpers.prototype.submit_tag = function(name, html_options) {
- html_options = html_options || {};
- html_options.type = html_options.type || 'submit';
- html_options.value = name || 'Submit';
- return this.single_tag_for('input', html_options);
- };
-
- EJS.Helpers.prototype.tag = function(tag, html_options, end) {
- if(!end) var end = '>';
- var txt = ' ';
- for(var attr in html_options) {
- if(html_options[attr] != null) {
- var value = html_options[attr].toString();
- } else {
- var value='';
- };
- // special case because "class" is a reserved word in IE
- if(attr == "Class") attr = "class";
- if( value.indexOf("'") != -1 ) {
- txt += attr+'=\"'+value+'\" ';
- } else {
- txt += attr+"='"+value+"' ";
- };
- };
- return '<' + tag + txt + end;
- };
-
- EJS.Helpers.prototype.tag_end = function(tag) {
- return '</'+tag+'>';
- };
-
- EJS.Helpers.prototype.text_area_tag = function(name, value, html_options) {
- html_options = html_options || {};
- html_options.id = html_options.id || name;
- html_options.name = html_options.name || name;
- value = value || '';
- if(html_options.size) {
- html_options.cols = html_options.size.split('x')[0];
- html_options.rows = html_options.size.split('x')[1];
- delete html_options.size;
- };
- html_options.cols = html_options.cols || 50;
- html_options.rows = html_options.rows || 4;
- return this.start_tag_for('textarea', html_options)+value+this.tag_end('textarea');
- };
-
- EJS.Helpers.prototype.text_tag = EJS.Helpers.prototype.text_area_tag;
-
- EJS.Helpers.prototype.text_field_tag = function(name, value, html_options) {
- return this.input_field_tag(name, value, 'text', html_options);
- };
-
- EJS.Helpers.prototype.url_for = function(url) {
- return 'window.location="' + url + '";';
- };
-
- EJS.Helpers.prototype.img_tag = function(image_location, alt, options){
- options = options || {};
- options.src = image_location;
- options.alt = alt;
- return this.single_tag_for('img', options);
- };
-
- // -------------------------------------------------------------
-
Sammy = Sammy || {};
+ // `Sammy.EJS` is a thin wrapper around the EJS templating engine which can be donwloaded
+ // at http://embeddedjs.com/
+ //
+ // Note: As of Sammy 0.7, Sammy.EJS does not include the actual templating engine in the source.
+ // Include ejs.js before including sammy.ejs.js
Sammy.EJS = function(app, method_alias) {
// *Helper:* Uses simple templating to parse ERB like templates.
@@ -685,12 +20,12 @@
//
var template = function(template, data, name) {
// use name for caching
- if (typeof name == 'undefined') name = template;
+ if (typeof name == 'undefined') { name = template; }
return new EJS({text: template, name: name}).render(data);
};
// set the default method name/extension
- if (!method_alias) method_alias = 'ejs';
+ if (!method_alias) { method_alias = 'ejs'; }
// create the helper at the method alias
app.helper(method_alias, template);
View
515 lib/plugins/sammy.haml.js
@@ -1,514 +1,19 @@
(function($) {
- /*
- port of http://github.com/creationix/haml-js
- version v0.2.6pre - 2010-10-01
- by Tim Caswell <tim@creationix.com>
- */
-
- var matchers, self_close_tags, embedder, forceXML;
-
- function html_escape(text) {
- return (text + "").
- replace(/&/g, "&amp;").
- replace(/</g, "&lt;").
- replace(/>/g, "&gt;").
- replace(/\"/g, "&quot;");
- }
-
- function render_attribs(attribs) {
- var key, value, result = [];
- for (key in attribs) {
- if (key !== '_content' && attribs.hasOwnProperty(key)) {
- switch (attribs[key]) {
- case 'undefined':
- case 'false':
- case 'null':
- case '""':
- break;
- default:
- try {
- value = JSON.parse("[" + attribs[key] +"]")[0];
- if (value === true) {
- value = key;
- } else if (typeof value === 'string' && embedder.test(value)) {
- value = '" +\n' + parse_interpol(html_escape(value)) + ' +\n"';
- } else {
- value = html_escape(value);
- }
- result.push(" " + key + '=\\"' + value + '\\"');
- } catch (e) {
- result.push(" " + key + '=\\"" + html_escape(' + attribs[key] + ') + "\\"');
- }
- }
- }
- }
- return result.join("");
- }
-
- // Parse the attribute block using a state machine
- function parse_attribs(line) {
- var attributes = {},
- l = line.length,
- i, c,
- count = 1,
- quote = false,
- skip = false,
- open, close, joiner, seperator,
- pair = {
- start: 1,
- middle: null,
- end: null
- };
-
- if (!(l > 0 && (line.charAt(0) === '{' || line.charAt(0) === '('))) {
- return {
- _content: line[0] === ' ' ? line.substr(1, l) : line
- };
- }
- open = line.charAt(0);
- close = (open === '{') ? '}' : ')';
- joiner = (open === '{') ? ':' : '=';
- seperator = (open === '{') ? ',' : ' ';
-
- function process_pair() {
- if (typeof pair.start === 'number' &&
- typeof pair.middle === 'number' &&
- typeof pair.end === 'number') {
- var key = line.substr(pair.start, pair.middle - pair.start).trim(),
- value = line.substr(pair.middle + 1, pair.end - pair.middle - 1).trim();
- attributes[key] = value;
- }
- pair = {
- start: null,
- middle: null,
- end: null
- };
- }
-
- for (i = 1; count > 0; i += 1) {
-
- // If we reach the end of the line, then there is a problem
- if (i > l) {
- throw "Malformed attribute block";
- }
-
- c = line.charAt(i);
- if (skip) {
- skip = false;
- } else {
- if (quote) {
- if (c === '\\') {
- skip = true;
- }
- if (c === quote) {
- quote = false;
- }
- } else {
- if (c === '"' || c === "'") {
- quote = c;
- }
-
- if (count === 1) {
- if (c === joiner) {
- pair.middle = i;
- }
- if (c === seperator || c === close) {
- pair.end = i;
- process_pair();
- if (c === seperator) {
- pair.start = i + 1;
- }
- }
- }
-
- if (c === open || c === "(") {
- count += 1;
- }
- if (c === close || (count > 1 && c === ")")) {
- count -= 1;
- }
- }
- }
- }
- attributes._content = line.substr(i, line.length);
- return attributes;
- }
-
- // Split interpolated strings into an array of literals and code fragments.
- function parse_interpol(value) {
- var items = [],
- pos = 0,
- next = 0,
- match;
- while (true) {
- // Match up to embedded string
- next = value.substr(pos).search(embedder);
- if (next < 0) {
- if (pos < value.length) {
- items.push(JSON.stringify(value.substr(pos)));
- }
- break;
- }
- items.push(JSON.stringify(value.substr(pos, next)));
- pos += next;
-
- // Match embedded string
- match = value.substr(pos).match(embedder);
- next = match[0].length;
- if (next < 0) { break; }
- items.push(match[1] || match[2]);
- pos += next;
- }
- return items.filter(function (part) { return part && part.length > 0}).join(" +\n");
- }
-
- // Used to find embedded code in interpolated strings.
- embedder = /\#\{([^}]*)\}/;
-
- self_close_tags = ["meta", "img", "link", "br", "hr", "input", "area", "base"];
-
- // All matchers' regexps should capture leading whitespace in first capture
- // and trailing content in last capture
- matchers = [
- // html tags
- {
- regexp: /^(\s*)((?:[.#%][a-z_\-][a-z0-9_:\-]*)+)(.*)$/i,
- process: function () {
- var tag, classes, ids, attribs, content;
- tag = this.matches[2];
- classes = tag.match(/\.([a-z_\-][a-z0-9_\-]*)/gi);
- ids = tag.match(/\#([a-z_\-][a-z0-9_\-]*)/gi);
- tag = tag.match(/\%([a-z_\-][a-z0-9_:\-]*)/gi);
-
- // Default to <div> tag
- tag = tag ? tag[0].substr(1, tag[0].length) : 'div';
-
- attribs = this.matches[3];
- if (attribs) {
- attribs = parse_attribs(attribs);
- if (attribs._content) {
- this.contents.unshift(attribs._content.trim());
- delete(attribs._content);
- }
- } else {
- attribs = {};
- }
-
- if (classes) {
- classes = classes.map(function (klass) {
- return klass.substr(1, klass.length);
- }).join(' ');
- if (attribs['class']) {
- try {
- attribs['class'] = JSON.stringify(classes + " " + JSON.parse(attribs['class']));
- } catch (e) {
- attribs['class'] = JSON.stringify(classes + " ") + " + " + attribs['class'];
- }
- } else {
- attribs['class'] = JSON.stringify(classes);
- }
- }
- if (ids) {
- ids = ids.map(function (id) {
- return id.substr(1, id.length);
- }).join(' ');
- if (attribs.id) {
- attribs.id = JSON.stringify(ids + " ") + attribs.id;
- } else {
- attribs.id = JSON.stringify(ids);
- }
- }
-
- attribs = render_attribs(attribs);
-
- content = this.render_contents();
- if (content === '""') {
- content = '';
- }
-
- if (forceXML ? content.length > 0 : self_close_tags.indexOf(tag) == -1) {
- return '"<' + tag + attribs + '>"' +
- (content.length > 0 ? ' + \n' + content : "") +
- ' + \n"</' + tag + '>"';
- } else {
- return '"<' + tag + attribs + ' />"';
- }
- }
- },
-
- // each loops
- {
- regexp: /^(\s*)(?::for|:each)\s+(?:([a-z_][a-z_\-]*),\s*)?([a-z_][a-z_\-]*)\s+in\s+(.*)(\s*)$/i,
- process: function () {
- var ivar = this.matches[2] || '__key__', // index
- vvar = this.matches[3], // value
- avar = this.matches[4], // array
- rvar = '__result__'; // results
-
- if (this.matches[5]) {
- this.contents.unshift(this.matches[5]);
- }
- return '(function () { ' +
- 'var ' + rvar + ' = [], ' + ivar + ', ' + vvar + '; ' +
- 'for (' + ivar + ' in ' + avar + ') { ' +
- 'if (' + avar + '.hasOwnProperty(' + ivar + ')) { ' +
- vvar + ' = ' + avar + '[' + ivar + ']; ' +
- rvar + '.push(\n' + (this.render_contents() || "''") + '\n); ' +
- '} } return ' + rvar + '.join(""); }).call(this)';
- }
- },
-
- // if statements
- {
- regexp: /^(\s*):if\s+(.*)\s*$/i,
- process: function () {
- var condition = this.matches[2];
- return '(function () { ' +
- 'if (' + condition + ') { ' +
- 'return (\n' + (this.render_contents() || '') + '\n);' +
- '} else { return ""; } }).call(this)';
- }
- },
-
- // declarations
- {
- regexp: /^()!!!(?:\s*(.*))\s*$/,
- process: function () {
- var line = '';
- switch ((this.matches[2] || '').toLowerCase()) {
- case '':
- // XHTML 1.0 Transitional
- line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
- break;
- case 'strict':
- case '1.0':
- // XHTML 1.0 Strict
- line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
- break;
- case 'frameset':
- // XHTML 1.0 Frameset
- line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';
- break;
- case '5':
- // XHTML 5
- line = '<!DOCTYPE html>';
- break;
- case '1.1':
- // XHTML 1.1
- line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
- break;
- case 'basic':
- // XHTML Basic 1.1
- line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">';
- break;
- case 'mobile':
- // XHTML Mobile 1.2
- line = '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">';
- break;
- case 'xml':
- // XML
- line = "<?xml version='1.0' encoding='utf-8' ?>";
- break;
- case 'xml iso-8859-1':
- // XML iso-8859-1
- line = "<?xml version='1.0' encoding='iso-8859-1' ?>";
- break;
- }
- return JSON.stringify(line + "\n");
- }
- },
-
- // Embedded markdown. Needs to be added to exports externally.
- {
- regexp: /^(\s*):markdown\s*$/i,
- process: function () {
- return parse_interpol(exports.Markdown.encode(this.contents.join("\n")));
- }
- },
-
- // script blocks
- {
- regexp: /^(\s*):(?:java)?script\s*$/,
- process: function () {
- return parse_interpol('\n<script type="text/javascript">\n' +
- '//<![CDATA[\n' +
- this.contents.join("\n") +
- "\n//]]>\n</script>\n");
- }
- },
-
- // css blocks
- {
- regexp: /^(\s*):css\s*$/,
- process: function () {
- return JSON.stringify('\n<style type="text/css">\n' +
- this.contents.join("\n") +
- "\n</style>\n");
- }
- },
-
- ];
-
- function compile(lines) {
- var block = false,
- output = [];
-
- // If lines is a string, turn it into an array
- if (typeof lines === 'string') {
- lines = lines.trim().replace(/\n\r|\r/g, '\n').split('\n');
- }
-
- lines.forEach(function(line) {
- var match, found = false;
-
- // Collect all text as raw until outdent
- if (block) {
- match = block.check_indent(line);
- if (match) {
- block.contents.push(match[1] || "");
- return;
- } else {
- output.push(block.process());
- block = false;
- }
- }
-
- matchers.forEach(function (matcher) {
- if (!found) {
- match = matcher.regexp(line);
- if (match) {
- block = {
- contents: [],
- matches: match,
- check_indent: new RegExp("^(?:\\s*|" + match[1] + " (.*))$"),
- process: matcher.process,
- render_contents: function () {
- return compile(this. contents);
- }
- };
- found = true;
- }
- }
- });
-
- // Match plain text
- if (!found) {
- output.push(function () {
- // Escaped plain text
- if (line[0] === '\\') {
- return parse_interpol(line.substr(1, line.length));
- }
-
- // Plain variable data
- if (line[0] === '=') {
- line = line.substr(1, line.length).trim();
- try {
- return parse_interpol(JSON.parse(line));
- } catch (e) {
- return line;
- }
- }
-
- // HTML escape variable data
- if (line.substr(0, 2) === "&=") {
- line = line.substr(2, line.length).trim();
- try {
- return JSON.stringify(html_escape(JSON.parse(line)));
- } catch (e2) {
- return 'html_escape(' + line + ')';
- }
- }
-
- // Plain text
- return parse_interpol(line);
- }());
- }
-
- });
- if (block) {
- output.push(block.process());
- }
- return output.filter(function (part) { return part && part.length > 0}).join(" +\n");
- };
-
- function optimize(js) {
- var new_js = [], buffer = [], part, end;
-
- function flush() {
- if (buffer.length > 0) {
- new_js.push(JSON.stringify(buffer.join("")) + end);
- buffer = [];
- }
- }
- js.replace(/\n\r|\r/g, '\n').split('\n').forEach(function (line) {
- part = line.match(/^(\".*\")(\s*\+\s*)?$/);
- if (!part) {
- flush();
- new_js.push(line);
- return;
- }
- end = part[2] || "";
- part = part[1];
- try {
- buffer.push(JSON.parse(part));
- } catch (e) {
- flush();
- new_js.push(line);
- }
- });
- flush();
- return new_js.join("\n");
- };
-
- function render(text, options) {
- options = options || {};
- text = text || "";
- var js = compile(text);
- if (options.optimize) {
- js = Haml.optimize(js);
- }
- return execute(js, options.context || Haml, options.locals);
- };
-
- function execute(js, self, locals) {
- return (function () {
- with(locals || {}) {
- try {
- return eval("(" + js + ")");
- } catch (e) {
- return "\n<pre class='error'>" + html_escape(e.stack) + "</pre>\n";
- }
-
- }
- }).call(self);
- };
-
- Haml = function Haml(haml, xml) {
- forceXML = xml;
- var js = optimize(compile(haml));
- return new Function("locals",
- html_escape + "\n" +
- "with(locals || {}) {\n" +
- " try {\n" +
- " return (" + js + ");\n" +
- " } catch (e) {\n" +
- " return \"\\n<pre class='error'>\" + html_escape(e.stack) + \"</pre>\\n\";\n" +
- " }\n" +
- "}");
- }
-
Sammy = Sammy || {};
- // <tt>Sammy.Haml</tt> provides a quick way of using haml style templates in your app.
- // The plugin itself includes the haml-js library created by Tim Caswell at
+ // `Sammy.Haml` provides a quick way of using haml style templates in your app.
+ // The plugin wraps haml-js library created by Tim Caswell at
// at http://github.com/creationix/haml-js
//
+ // Note: As of Sammy 0.7, Sammy.Haml does not include the actual templating engine in the source.
+ // Include haml.js before including sammy.haml.js
+ //
// Haml is an alternative HTML syntax that is really great for describing
// the structure of HTML documents.
//
// By default using Sammy.Haml in your app adds the <tt>haml()</tt> method to the EventContext
- // prototype. However, just like <tt>Sammy.Template</tt> you can change the default name of the method
+ // prototype. However, just like `Sammy.Template` you can change the default name of the method
// by passing a second argument (e.g. you could use the hml() as the method alias so that all the template
// files could be in the form file.hml instead of file.haml)
//
@@ -536,7 +41,7 @@
//
// });
//
- // If I go to `#/hello/AQ` in the browser, Sammy will render this to the <tt>body</tt>:
+ // If I go to `#/hello/AQ` in the browser, Sammy will render this to the `body`:
//
// <h1>Hello!</h1>
//
@@ -546,8 +51,6 @@
// includes the full source.
//
Sammy.Haml = function(app, method_alias) {
- app.use(Sammy.JSON);
-
var haml_cache = {};
// *Helper* Uses haml-js to parse a template and interpolate and work with the passed data
//
@@ -559,7 +62,7 @@
//
var haml = function(template, data, name) {
// use name for caching
- if (typeof name == 'undefined') name = template;
+ if (typeof name == 'undefined') { name = template; }
var fn = haml_cache[name];
if (!fn) {
fn = haml_cache[name] = Haml(template);
@@ -568,7 +71,7 @@
};
// set the default method name/extension
- if (!method_alias) method_alias = 'haml';
+ if (!method_alias) { method_alias = 'haml'; }
app.helper(method_alias, haml);
};
View
739 lib/plugins/sammy.pure.js
@@ -1,745 +1,12 @@
(function($) {
-/*!
- PURE Unobtrusive Rendering Engine for HTML
-
- Licensed under the MIT licenses.
- More information at: http://www.opensource.org
-
- Copyright (c) 2010 Michael Cvilic - BeeBole.com
-
- Thanks to Rog Peppe for the functional JS jump
- revision: 2.47
-*/
-
-var $p, pure = $p = function(){
- var sel = arguments[0],
- ctxt = false;
-
- if(typeof sel === 'string'){
- ctxt = arguments[1] || false;
- }
- return $p.core(sel, ctxt);
-};
-
-$p.core = function(sel, ctxt, plugins){
- //get an instance of the plugins
- var plugins = getPlugins(),
- templates = [];
-
- //search for the template node(s)
- switch(typeof sel){
- case 'string':
- templates = plugins.find(ctxt || document, sel);
- if(templates.length === 0) {
- error('The template "' + sel + '" was not found');
- }
- break;
- case 'undefined':
- error('The template root is undefined, check your selector');
- break;
- default:
- templates = [sel];
- }
-
- for(var i = 0, ii = templates.length; i < ii; i++){
- plugins[i] = templates[i];
- }
- plugins.length = ii;
-
- // set the signature string that will be replaced at render time
- var Sig = '_s' + Math.floor( Math.random() * 1000000 ) + '_',
- // another signature to prepend to attributes and avoid checks: style, height, on[events]...
- attPfx = '_a' + Math.floor( Math.random() * 1000000 ) + '_',
- // rx to parse selectors, e.g. "+tr.foo[class]"
- selRx = /^(\+)?([^\@\+]+)?\@?([^\+]+)?(\+)?$/,
- // set automatically attributes for some tags
- autoAttr = {
- IMG:'src',
- INPUT:'value'
- },
- // check if the argument is an array - thanks salty-horse (Ori Avtalion)
- isArray = Array.isArray ?
- function(o) {
- return Array.isArray(o);
- } :
- function(o) {
- return Object.prototype.toString.call(o) === "[object Array]";
- };
-
- return plugins;
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * *
- core functions
- * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
- // error utility
- function error(e){
- if(typeof console !== 'undefined'){
- console.log(e);
- }else{ alert(e); }
- throw('pure error: ' + e);
- }
-
- //return a new instance of plugins
- function getPlugins(){
- var plugins = $p.plugins,
- f = function(){};
- f.prototype = plugins;
-
- // do not overwrite functions if external definition
- f.prototype.compile = plugins.compile || compile;
- f.prototype.render = plugins.render || render;
- f.prototype.autoRender = plugins.autoRender || autoRender;
- f.prototype.find = plugins.find || find;
-
- // give the compiler and the error handling to the plugin context
- f.prototype._compiler = compiler;
- f.prototype._error = error;
-
- return new f();
- }
-
- // returns the outer HTML of a node
- function outerHTML(node){
- // if IE take the internal method otherwise build one
- return node.outerHTML || (
- function(n){
- var div = document.createElement('div'), h;
- div.appendChild( n.cloneNode(true) );
- h = div.innerHTML;
- div = null;
- return h;
- })(node);
- }
-
- // returns the string generator function
- function wrapquote(qfn, f){
- return function(ctxt){
- return qfn('' + f.call(ctxt.context, ctxt));
- };
- }
-
- // default find using querySelector when available on the browser
- function find(n, sel){
- if(typeof n === 'string'){
- sel = n;
- n = false;
- }
- if(typeof document.querySelectorAll !== 'undefined'){
- return (n||document).querySelectorAll( sel );
- }else{
- error('You can test PURE standalone with: iPhone, FF3.5+, Safari4+ and IE8+\n\nTo run PURE on your browser, you need a JS library/framework with a CSS selector engine');
- }
- }
-
- // create a function that concatenates constant string
- // sections (given in parts) and the results of called
- // functions to fill in the gaps between parts (fns).
- // fns[n] fills in the gap between parts[n-1] and parts[n];
- // fns[0] is unused.
- // this is the inner template evaluation loop.
- function concatenator(parts, fns){
- return function(ctxt){
- var strs = [ parts[ 0 ] ],
- n = parts.length,
- fnVal, pVal, attLine, pos;
-
- for(var i = 1; i < n; i++){
- fnVal = fns[i]( ctxt );
- pVal = parts[i];
-
- // if the value is empty and attribute, remove it
- if(fnVal === ''){
- attLine = strs[ strs.length - 1 ];
- if( ( pos = attLine.search( /[\w]+=\"?$/ ) ) > -1){
- strs[ strs.length - 1 ] = attLine.substring( 0, pos );
- pVal = pVal.substr( 1 );
- }
- }
-
- strs[ strs.length ] = fnVal;
- strs[ strs.length ] = pVal;
- }
- return strs.join('');
- };
- }
-
- // parse and check the loop directive
- function parseloopspec(p){
- var m = p.match( /^(\w+)\s*<-\s*(\S+)?$/ );
- if(m === null){
- error('bad loop spec: "' + p + '"');
- }
- if(m[1] === 'item'){
- error('"item<-..." is a reserved word for the current running iteration.\n\nPlease choose another name for your loop.');
- }
- if( !m[2] || (m[2] && (/context/i).test(m[2]))){ //undefined or space(IE)
- m[2] = function(ctxt){return ctxt.context;};
- }
- return {name: m[1], sel: m[2]};
- }
-
- // parse a data selector and return a function that
- // can traverse the data accordingly, given a context.
- function dataselectfn(sel){
- if(typeof(sel) === 'function'){
- return sel;
- }
- //check for a valid js variable name with hyphen(for properties only), $, _ and :
- var m = sel.match(/^[a-zA-Z\$_\@][\w\$:-]*(\.[\w\$:-]*[^\.])*$/);
- if(m === null){
- var found = false, s = sel, parts = [], pfns = [], i = 0, retStr;
- // check if literal
- if(/\'|\"/.test( s.charAt(0) )){
- if(/\'|\"/.test( s.charAt(s.length-1) )){
- retStr = s.substring(1, s.length-1);
- return function(){ return retStr; };
- }
- }else{
- // check if literal + #{var}
- while((m = s.match(/#\{([^{}]+)\}/)) !== null){
- found = true;
- parts[i++] = s.slice(0, m.index);
- pfns[i] = dataselectfn(m[1]);
- s = s.slice(m.index + m[0].length, s.length);
- }
- }
- if(!found){
- error('bad data selector syntax: ' + sel);
- }
- parts[i] = s;
- return concatenator(parts, pfns);
- }
- m = sel.split('.');
- return function(ctxt){
- var data = ctxt.context;
- if(!data){
- return '';
- }
- var v = ctxt[m[0]],
- i = 0;
- if(v && v.item){
- data = v.item;
- i += 1;
- }
- var n = m.length;
- for(; i < n; i++){
- if(!data){break;}
- data = data[m[i]];
- }
- return (!data && data !== 0) ? '':data;
- };
- }
-
- // wrap in an object the target node/attr and their properties
- function gettarget(dom, sel, isloop){
- var osel, prepend, selector, attr, append, target = [];
- if( typeof sel === 'string' ){
- osel = sel;
- var m = sel.match(selRx);
- if( !m ){
- error( 'bad selector syntax: ' + sel );
- }
-
- prepend = m[1];
- selector = m[2];
- attr = m[3];
- append = m[4];
-
- if(selector === '.' || ( !selector && attr ) ){
- target[0] = dom;
- }else{
- target = plugins.find(dom, selector);
- }
- if(!target || target.length === 0){
- return error('The node "' + sel + '" was not found in the template');
- }
- }else{
- // autoRender node
- prepend = sel.prepend;
- attr = sel.attr;
- append = sel.append;
- target = [dom];
- }
-
- if( prepend || append ){
- if( prepend && append ){
- error('append/prepend cannot take place at the same time');
- }else if( isloop ){
- error('no append/prepend/replace modifiers allowed for loop target');
- }else if( append && isloop ){
- error('cannot append with loop (sel: ' + osel + ')');
- }
- }
- var setstr, getstr, quotefn, isStyle, isClass, attName, setfn;
- if(attr){
- isStyle = (/^style$/i).test(attr);
- isClass = (/^class$/i).test(attr);
- attName = isClass ? 'className' : attr;
- setstr = function(node, s) {
- node.setAttribute(attPfx + attr, s);
- if (attName in node && !isStyle) {
- node[attName] = '';
- }
- if (node.nodeType === 1) {
- node.removeAttribute(attr);
- isClass && node.removeAttribute(attName);
- }
- };
- if (isStyle || isClass) {//IE no quotes special care
- if(isStyle){
- getstr = function(n){ return n.style.cssText; };
- }else{
- getstr = function(n){ return n.className; };
- }
- quotefn = function(s){ return s.replace(/\"/g, '&quot;'); };
- }else {
- getstr = function(n){ return n.getAttribute(attr); };
- quotefn = function(s){ return s.replace(/\"/g, '&quot;').replace(/\s/g, '&nbsp;'); };
- }
- if(prepend){
- setfn = function(node, s){ setstr( node, s + getstr( node )); };
- }else if(append){
- setfn = function(node, s){ setstr( node, getstr( node ) + s); };
- }else{
- setfn = function(node, s){ setstr( node, s ); };
- }
- }else{
- if (isloop) {
- setfn = function(node, s) {
- var pn = node.parentNode;
- if (pn) {
- //replace node with s
- pn.insertBefore(document.createTextNode(s), node.nextSibling);
- pn.removeChild(node);
- }
- };
- } else {
- if (prepend) {
- setfn = function(node, s) { node.insertBefore(document.createTextNode(s), node.firstChild); };
- } else if (append) {
- setfn = function(node, s) { node.appendChild(document.createTextNode(s));};
- } else {
- setfn = function(node, s) {
- while (node.firstChild) { node.removeChild(node.firstChild); }
- node.appendChild(document.createTextNode(s));
- };
- }
- }
- quotefn = function(s) { return s; };
- }
- return { attr: attr, nodes: target, set: setfn, sel: osel, quotefn: quotefn };
- }
-
- function setsig(target, n){
- var sig = Sig + n + ':';
- for(var i = 0; i < target.nodes.length; i++){
- // could check for overlapping targets here.
- target.set( target.nodes[i], sig );
- }
- }
-
- // read de loop data, and pass it to the inner rendering function
- function loopfn(name, dselect, inner, sorter, filter){
- return function(ctxt){
- var a = dselect(ctxt),
- old = ctxt[name],
- temp = { items : a },
- filtered = 0,
- length,
- strs = [],
- buildArg = function(idx, temp, ftr, len){
- ctxt.pos = temp.pos = idx;
- ctxt.item = temp.item = a[ idx ];
- ctxt.items = a;
- //if array, set a length property - filtered items
- typeof len !== 'undefined' && (ctxt.length = len);
- //if filter directive
- if(typeof ftr === 'function' && ftr(ctxt) === false){
- filtered++;
- return;
- }
- strs.push( inner.call(temp, ctxt ) );
- };
- ctxt[name] = temp;
- if( isArray(a) ){
- length = a.length || 0;
- // if sort directive
- if(typeof sorter === 'function'){
- a.sort(sorter);
- }
- //loop on array
- for(var i = 0, ii = length; i < ii; i++){
- buildArg(i, temp, filter, length - filtered);
- }
- }else{
- if(a && typeof sorter !== 'undefined'){
- error('sort is only available on arrays, not objects');
- }
- //loop on collections
- for(var prop in a){
- a.hasOwnProperty( prop ) && buildArg(prop, temp, filter);
- }
- }
-
- typeof old !== 'undefined' ? ctxt[name] = old : delete ctxt[name];
- return strs.join('');
- };
- }
- // generate the template for a loop node
- function loopgen(dom, sel, loop, fns){
- var already = false, ls, sorter, filter, prop;
- for(prop in loop){
- if(loop.hasOwnProperty(prop)){
- if(prop === 'sort'){
- sorter = loop.sort;
- continue;
- }else if(prop === 'filter'){
- filter = loop.filter;
- continue;
- }
- if(already){
- error('cannot have more than one loop on a target');
- }
- ls = prop;
- already = true;
- }
- }
- if(!ls){
- error('Error in the selector: ' + sel + '\nA directive action must be a string, a function or a loop(<-)');
- }
- var dsel = loop[ls];
- // if it's a simple data selector then we default to contents, not replacement.
- if(typeof(dsel) === 'string' || typeof(dsel) === 'function'){
- loop = {};
- loop[ls] = {root: dsel};
- return loopgen(dom, sel, loop, fns);
- }
- var spec = parseloopspec(ls),
- itersel = dataselectfn(spec.sel),
- target = gettarget(dom, sel, true),
- nodes = target.nodes;
-
- for(i = 0; i < nodes.length; i++){
- var node = nodes[i],
- inner = compiler(node, dsel);
- fns[fns.length] = wrapquote(target.quotefn, loopfn(spec.name, itersel, inner, sorter, filter));
- target.nodes = [node]; // N.B. side effect on target.
- setsig(target, fns.length - 1);
- }
- }
-
- function getAutoNodes(n, data){
- var ns = n.getElementsByTagName('*'),
- an = [],
- openLoops = {a:[],l:{}},
- cspec,
- isNodeValue,
- i, ii, j, jj, ni, cs, cj;
- //for each node found in the template
- for(i = -1, ii = ns.length; i < ii; i++){
- ni = i > -1 ?ns[i]:n;
- if(ni.nodeType === 1 && ni.className !== ''){
- //when a className is found
- cs = ni.className.split(' ');
- // for each className
- for(j = 0, jj=cs.length;j<jj;j++){
- cj = cs[j];
- // check if it is related to a context property
- cspec = checkClass(cj, ni.tagName);
- // if so, store the node, plus the type of data
- if(cspec !== false){
- isNodeValue = (/nodevalue/i).test(cspec.attr);
- if(cspec.sel.indexOf('@') > -1 || isNodeValue){
- ni.className = ni.className.replace('@'+cspec.attr, '');
- if(isNodeValue){
- cspec.attr = false;
- }
- }
- an.push({n:ni, cspec:cspec});
- }
- }
- }
- }
- return an;
-
- function checkClass(c, tagName){
- // read the class
- var ca = c.match(selRx),
- attr = ca[3] || autoAttr[tagName],
- cspec = {prepend:!!ca[1], prop:ca[2], attr:attr, append:!!ca[4], sel:c},
- i, ii, loopi, loopil, val;
- // check in existing open loops
- for(i = openLoops.a.length-1; i >= 0; i--){
- loopi = openLoops.a[i];
- loopil = loopi.l[0];
- val = loopil && loopil[cspec.prop];
- if(typeof val !== 'undefined'){
- cspec.prop = loopi.p + '.' + cspec.prop;
- if(openLoops.l[cspec.prop] === true){
- val = val[0];
- }
- break;
- }
- }
- // not found check first level of data
- if(typeof val === 'undefined'){
- val = isArray(data) ? data[0][cspec.prop] : data[cspec.prop];
- // nothing found return
- if(typeof val === 'undefined'){
- return false;
- }
- }
- // set the spec for autoNode
- if(isArray(val)){
- openLoops.a.push( {l:val, p:cspec.prop} );
- openLoops.l[cspec.prop] = true;
- cspec.t = 'loop';
- }else{
- cspec.t = 'str';
- }
- return cspec;
- }
- }
-
- // returns a function that, given a context argument,
- // will render the template defined by dom and directive.
- function compiler(dom, directive, data, ans){
- var fns = [];
- // autoRendering nodes parsing -> auto-nodes
- ans = ans || data && getAutoNodes(dom, data);
- if(data){
- var j, jj, cspec, n, target, nodes, itersel, node, inner;
- // for each auto-nodes
- while(ans.length > 0){
- cspec = ans[0].cspec;
- n = ans[0].n;
- ans.splice(0, 1);
- if(cspec.t === 'str'){
- // if the target is a value
- target = gettarget(n, cspec, false);
- setsig(target, fns.length);
- fns[fns.length] = wrapquote(target.quotefn, dataselectfn(cspec.prop));
- }else{
- // if the target is a loop
- itersel = dataselectfn(cspec.sel);
- target = gettarget(n, cspec, true);
- nodes = target.nodes;
- for(j = 0, jj = nodes.length; j < jj; j++){
- node = nodes[j];
- inner = compiler(node, false, data, ans);
- fns[fns.length] = wrapquote(target.quotefn, loopfn(cspec.sel, itersel, inner));
- target.nodes = [node];
- setsig(target, fns.length - 1);
- }
- }
- }
- }
- // read directives
- var target, dsel;
- for(var sel in directive){
- if(directive.hasOwnProperty(sel)){
- dsel = directive[sel];
- if(typeof(dsel) === 'function' || typeof(dsel) === 'string'){
- // set the value for the node/attr
- target = gettarget(dom, sel, false);
- setsig(target, fns.length);
- fns[fns.length] = wrapquote(target.quotefn, dataselectfn(dsel));
- }else{
- // loop on node
- loopgen(dom, sel, dsel, fns);
- }
- }
- }
- // convert node to a string
- var h = outerHTML(dom), pfns = [];
- // IE adds an unremovable "selected, value" attribute
- // hard replace while waiting for a better solution
- h = h.replace(/<([^>]+)\s(value\=""|selected)\s?([^>]*)>/ig, "<$1 $3>");
-
- // remove attribute prefix
- h = h.split(attPfx).join('');
-
- // slice the html string at "Sig"
- var parts = h.split( Sig ), p;
- // for each slice add the return string of
- for(var i = 1; i < parts.length; i++){
- p = parts[i];
- // part is of the form "fn-number:..." as placed there by setsig.
- pfns[i] = fns[ parseInt(p, 10) ];
- parts[i] = p.substring( p.indexOf(':') + 1 );
- }
- return concatenator(parts, pfns);
- }
- // compile the template with directive
- // if a context is passed, the autoRendering is triggered automatically
- // return a function waiting the data as argument
- function compile(directive, ctxt, template){
- var rfn = compiler( ( template || this[0] ).cloneNode(true), directive, ctxt);
- return function(context){
- return rfn({context:context});
- };
- }
- //compile with the directive as argument
- // run the template function on the context argument
- // return an HTML string
- // should replace the template and return this
- function render(ctxt, directive){
- var fn = typeof directive === 'function' ? directive : plugins.compile( directive, false, this[0] );
- for(var i = 0, ii = this.length; i < ii; i++){
- this[i] = replaceWith( this[i], fn( ctxt, false ));
- }
- context = null;
- return this;
- }
-
- // compile the template with autoRender
- // run the template function on the context argument
- // return an HTML string
- function autoRender(ctxt, directive){
- var fn = plugins.compile( directive, ctxt, this[0] );
- for(var i = 0, ii = this.length; i < ii; i++){
- this[i] = replaceWith( this[i], fn( ctxt, false));
- }
- context = null;
- return this;
- }
-
- function replaceWith(elm, html) {
- var ne,
- ep = elm.parentNode,
- depth = 0;
- switch (elm.tagName) {
- case 'TBODY': case 'THEAD': case 'TFOOT':
- html = '<TABLE>' + html + '</TABLE>';
- depth = 1;
- break;
- case 'TR':
- html = '<TABLE><TBODY>' + html + '</TBODY></TABLE>';
- depth = 2;
- break;
- case 'TD': case 'TH':
- html = '<TABLE><TBODY><TR>' + html + '</TR></TBODY></TABLE>';
- depth = 3;
- break;
- }
- tmp = document.createElement('SPAN');
- tmp.style.display = 'none';
- document.body.appendChild(tmp);
- tmp.innerHTML = html;
- ne = tmp.firstChild;
- while (depth--) {
- ne = ne.firstChild;
- }
- ep.insertBefore(ne, elm);
- ep.removeChild(elm);
- document.body.removeChild(tmp);
- elm = ne;
-
- ne = ep = null;
- return elm;
- }
-};
-
-$p.plugins = {};
-
-$p.libs = {
- dojo:function(){
- if(typeof document.querySelector === 'undefined'){
- $p.plugins.find = function(n, sel){
- return dojo.query(sel, n);
- };
- }
- },
- domassistant:function(){
- if(typeof document.querySelector === 'undefined'){
- $p.plugins.find = function(n, sel){
- return $(n).cssSelect(sel);
- };
- }
- DOMAssistant.attach({
- publicMethods : [ 'compile', 'render', 'autoRender'],
- compile:function(directive, ctxt){ return $p(this).compile(directive, ctxt); },
- render:function(ctxt, directive){ return $( $p(this).render(ctxt, directive) )[0]; },
- autoRender:function(ctxt, directive){ return $( $p(this).autoRender(ctxt, directive) )[0]; }
- });
- },
- jquery:function(){
- if(typeof document.querySelector === 'undefined'){
- $p.plugins.find = function(n, sel){
- return jQuery(n).find(sel);
- };
- }
- jQuery.fn.extend({
- compile:function(directive, ctxt){ return $p(this[0]).compile(directive, ctxt); },
- render:function(ctxt, directive){ return jQuery( $p( this[0] ).render( ctxt, directive ) ); },
- autoRender:function(ctxt, directive){ return jQuery( $p( this[0] ).autoRender( ctxt, directive ) ); }
- });
- },
- mootools:function(){
- if(typeof document.querySelector === 'undefined'){
- $p.plugins.find = function(n, sel){
- return $(n).getElements(sel);
- };
- }
- Element.implement({
- compile:function(directive, ctxt){ return $p(this).compile(directive, ctxt); },
- render:function(ctxt, directive){ return $p(this).render(ctxt, directive); },
- autoRender:function(ctxt, directive){ return $p(this).autoRender(ctxt, directive); }
- });
- },
- prototype:function(){
- if(typeof document.querySelector === 'undefined'){
- $p.plugins.find = function(n, sel){
- n = n === document ? n.body : n;
- return typeof n === 'string' ? $$(n) : $(n).select(sel);
- };
- }
- Element.addMethods({
- compile:function(element, directive, ctxt){ return $p(element).compile(directive, ctxt); },
- render:function(element, ctxt, directive){ return $p(element).render(ctxt, directive); },
- autoRender:function(element, ctxt, directive){ return $p(element).autoRender(ctxt, directive); }
- });
- },
- sizzle:function(){
- if(typeof document.querySelector === 'undefined'){
- $p.plugins.find = function(n, sel){
- return Sizzle(sel, n);
- };
- }
- },
- sly:function(){
- if(typeof document.querySelector === 'undefined'){
- $p.plugins.find = function(n, sel){
- return Sly(sel, n);
- };
- }
- }
-};
-
-// get lib specifics if available
-(function(){
- var libkey =
- typeof dojo !== 'undefined' && 'dojo' ||
- typeof DOMAssistant !== 'undefined' && 'domassistant' ||
- typeof jQuery !== 'undefined' && 'jquery' ||
- typeof MooTools !== 'undefined' && 'mootools' ||
- typeof Prototype !== 'undefined' && 'prototype' ||
- typeof Sizzle !== 'undefined' && 'sizzle' ||
- typeof Sly !== 'undefined' && 'sly';
-
- libkey && $p.libs[libkey]();
-})();
-
-
Sammy = Sammy || {};
// `Sammy.Pure` is a simple wrapper around the pure.js templating engine for
// use in Sammy apps.
//
+ // Note: You must include the pure.js source before including sammy.pure.js.
+ //
// See http://beebole.com/pure/ for detailed documentation.
Sammy.Pure = function(app, method_alias) {
@@ -748,7 +15,7 @@ $p.libs = {
};
// set the default method name/extension
- if (!method_alias) method_alias = 'pure';
+ if (!method_alias) { method_alias = 'pure'; }
app.helper(method_alias, pure);
};
View
501 lib/plugins/sammy.tmpl.js
@@ -1,494 +1,13 @@
-(function( jQuery, undefined ){
-
- /*
- * a port of the...
- * jQuery Templating Plugin
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- */
-
- var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,
- newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = [];
-
- function newTmplItem( options, parentItem, fn, data ) {
- // Returns a template item data structure for a new rendered instance of a template (a 'template item').
- // The content field is a hierarchical array of strings and nested items (to be
- // removed and replaced by nodes field of dom elements, once inserted in DOM).
- var newItem = {
- data: data || (parentItem ? parentItem.data : {}),
- _wrap: parentItem ? parentItem._wrap : null,
- tmpl: null,
- parent: parentItem || null,
- nodes: [],
- calls: tiCalls,
- nest: tiNest,
- wrap: tiWrap,
- html: tiHtml,
- update: tiUpdate
- };
- if ( options ) {
- jQuery.extend( newItem, options, { nodes: [], parent: parentItem } );
- }
- if ( fn ) {
- // Build the hierarchical content to be used during insertion into DOM
- newItem.tmpl = fn;
- newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem );
- newItem.key = ++itemKey;
- // Keep track of new template item, until it is stored as jQuery Data on DOM element
- (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem;
- }
- return newItem;
- }
-
- // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core).
- jQuery.each({
- appendTo: "append",
- prependTo: "prepend",
- insertBefore: "before",
- insertAfter: "after",
- replaceAll: "replaceWith"
- }, function( name, original ) {
- jQuery.fn[ name ] = function( selector ) {
- var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems,
- parent = this.length === 1 && this[0].parentNode;
-
- appendToTmplItems = newTmplItems || {};
- if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
- insert[ original ]( this[0] );
- ret = this;
- } else {
- for ( i = 0, l = insert.length; i < l; i++ ) {
- cloneIndex = i;
- elems = (i > 0 ? this.clone(true) : this).get();
- jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
- ret = ret.concat( elems );
- }
- cloneIndex = 0;
- ret = this.pushStack( ret, name, insert.selector );
- }
- tmplItems = appendToTmplItems;
- appendToTmplItems = null;
- jQuery.tmpl.complete( tmplItems );
- return ret;
- };
- });
-
- jQuery.fn.extend({
- // Use first wrapped element as template markup.
- // Return wrapped set of template items, obtained by rendering template against data.
- tmpl: function( data, options, parentItem ) {
- return jQuery.tmpl( this[0], data, options, parentItem );
- },
-
- // Find which rendered template item the first wrapped DOM element belongs to
- tmplItem: function() {
- return jQuery.tmplItem( this[0] );
- },
-
- // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template.
- template: function( name ) {
- return jQuery.template( name, this[0] );
- },
-
- domManip: function( args, table, callback, options ) {
- // This appears to be a bug in the appendTo, etc. implementation
- // it should be doing .call() instead of .apply(). See #6227
- if ( args[0] && args[0].nodeType ) {
- var dmArgs = jQuery.makeArray( arguments ), argsLength = args.length, i = 0, tmplItem;
- while ( i < argsLength && !(tmplItem = jQuery.data( args[i++], "tmplItem" ))) {}
- if ( argsLength > 1 ) {
- dmArgs[0] = [jQuery.makeArray( args )];
- }
- if ( tmplItem && cloneIndex ) {
- dmArgs[2] = function( fragClone ) {
- // Handler called by oldManip when rendered template has been inserted into DOM.
- jQuery.tmpl.afterManip( this, fragClone, callback );
- };
- }
- oldManip.apply( this, dmArgs );
- } else {
- oldManip.apply( this, arguments );
- }
- cloneIndex = 0;
- if ( !appendToTmplItems ) {
- jQuery.tmpl.complete( newTmplItems );
- }
- return this;
- }
- });
-
- jQuery.extend({
- // Return wrapped set of template items, obtained by rendering template against data.
- tmpl: function( tmpl, data, options, parentItem ) {
- var ret, topLevel = !parentItem;
- if ( topLevel ) {
- // This is a top-level tmpl call (not from a nested template using {{tmpl}})
- parentItem = topTmplItem;
- tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl );
- wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level
- } else if ( !tmpl ) {
- // The template item is already associated with DOM - this is a refresh.
- // Re-evaluate rendered template for the parentItem
- tmpl = parentItem.tmpl;
- newTmplItems[parentItem.key] = parentItem;
- parentItem.nodes = [];
- if ( parentItem.wrapped ) {
- updateWrapped( parentItem, parentItem.wrapped );
- }
- // Rebuild, without creating a new template item
- return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) ));
- }
- if ( !tmpl ) {
- return []; // Could throw...
- }
- if ( typeof data === "function" ) {
- data = data.call( parentItem || {} );
- }
- if ( options && options.wrapped ) {
- updateWrapped( options, options.wrapped );
- }
- ret = jQuery.isArray( data ) ?
- jQuery.map( data, function( dataItem ) {
- return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null;
- }) :
- [ newTmplItem( options, parentItem, tmpl, data ) ];
- return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret;
- },
-
- // Return rendered template item for an element.
- tmplItem: function( elem ) {
- var tmplItem;
- if ( elem instanceof jQuery ) {
- elem = elem[0];
- }
- while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {}
- return tmplItem || topTmplItem;
- },
-
- // Set:
- // Use $.template( name, tmpl ) to cache a named template,
- // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc.
- // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration.
-
- // Get:
- // Use $.template( name ) to access a cached template.
- // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString )
- // will return the compiled template, without adding a name reference.
- // If templateString includes at least one HTML tag, $.template( templateString ) is equivalent
- // to $.template( null, templateString )
- template: function( name, tmpl ) {
- if (tmpl) {
- // Compile template and associate with name
- if ( typeof tmpl === "string" ) {
- // This is an HTML string being passed directly in.
- tmpl = buildTmplFn( tmpl )
- } else if ( tmpl instanceof jQuery ) {
- tmpl = tmpl[0] || {};
- }
- if ( tmpl.nodeType ) {
- // If this is a template block, use cached copy, or generate tmpl function and cache.
- tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML ));
- }
- return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl;
- }
- // Return named compiled template
- return name ? (typeof name !== "string" ? jQuery.template( null, name ):
- (jQuery.template[name] ||
- // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec)
- jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null;
- },
-
- encode: function( text ) {
- // Do HTML encoding replacing < > & and ' and " by corresponding entities.
- return ("" + text).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;");
- }
- });
-
- jQuery.extend( jQuery.tmpl, {
- tag: {
- "tmpl": {
- _default: { $2: "null" },
- open: "if($notnull_1){___$$$___=___$$$___.concat($item.nest($1,$2));}"
- // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions)
- // This means that {{tmpl foo}} treats foo as a template (which IS a function).
- // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}.
- },
- "wrap": {
- _default: { $2: "null" },
- open: "$item.calls(_,$1,$2);_=[];",
- close: "call=$item.calls();___$$$___=call.___$$$___.concat($item.wrap(call,___$$$___));"
- },
- "each": {
- _default: { $2: "$index, $value" },
- open: "if($notnull_1){$.each($1a,function($2){with(this){",
- close: "}});}"
- },
- "if": {
- open: "if(($notnull_1) && $1a){",
- close: "}"
- },
- "else": {
- _default: { $1: "true" },
- open: "}else if(($notnull_1) && $1a){"
- },
- "html": {
- // Unecoded expression evaluation.
- open: "if($notnull_1){___$$$___.push($1a);}"
- },
- "=": {
- // Encoded expression evaluation. Abbreviated form is ${}.
- _default: { $1: "$data" },
- open: "if($notnull_1){___$$$___.push($.encode($1a));}"
- },
- "!": {
- // Comment tag. Skipped by parser
- open: ""
- }
- },
-
- // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events
- complete: function( items ) {
- newTmplItems = {};
- },
-
- // Call this from code which overrides domManip, or equivalent
- // Manage cloning/storing template items etc.
- afterManip: function afterManip( elem, fragClone, callback ) {
- // Provides cloned fragment ready for fixup prior to and after insertion into DOM
- var content = fragClone.nodeType === 11 ?
- jQuery.makeArray(fragClone.childNodes) :
- fragClone.nodeType === 1 ? [fragClone] : [];
-
- // Return fragment to original caller (e.g. append) for DOM insertion
- callback.call( elem, fragClone );
-
- // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data.
- storeTmplItems( content );
- cloneIndex++;
- }
- });
-
- //========================== Private helper functions, used by code above ==========================
-
- function build( tmplItem, nested, content ) {
- // Convert hierarchical content into flat string array
- // and finally return array of fragments ready for DOM insertion
- var frag, ret = content ? jQuery.map( content, function( item ) {
- return (typeof item ===