/** * jQuery Templates * * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. * * Written by: Stan Lemon <stanlemon@mac.com> * * Based off of the Ext.Template library, available at: * http://www.extjs.com * * This library provides basic templating functionality, allowing for macro-based * templates within jQuery. * * Basic Usage: * * var t = $.template('<div id="foo">Hello ${name}, how are you ${question}?  I am ${me:substr(0,10)}</div>'); * * $(selector).append( t , { *     name: 'Stan', *     question: 'feeling', *     me: 'doing quite well myself, thank you very much!' * }); * * Requires: jQuery 1.2+ * * * @todo    Add callbacks to the DOM manipulation methods, so that events can be bound *          to template nodes after creation. */(function($){		/**	 * Create a New Template	 */	$.template = function(html, options) {		return new $.template.instance(html, options);	};	/**	 * Template constructor - Creates a new template instance.	 *	 * @param 	html 	The string of HTML to be used for the template.	 * @param 	options An object of configurable options.  Currently	 * 			you can toggle compile as a boolean value and set a custom	 *          template regular expression on the property regx by	 *          specifying the key of the regx to use from the regx object.	 */	$.template.instance = function(html, options) {        // If a custom regular expression has been set, grab it from the regx object        if ( options && options['regx'] ) options.regx = this.regx[ options.regx ];		this.options = $.extend({			compile: 		false,			regx:           this.regx.standard		}, options || {});		this.html = html;		if (this.options.compile) {			this.compile();   		}		this.isTemplate = true;	};	/**	 * Regular Expression for Finding Variables	 *	 * The default pattern looks for variables in JSP style, the form of: ${variable}	 * There are also regular expressions available for ext-style variables and	 * jTemplate style variables.	 *	 * You can add your own regular expressions for variable ussage by doing.	 * $.extend({ $.template.re , {	 *     myvartype: /...../g	 * }	 *	 * Then when creating a template do:	 * var t = $.template("<div>...</div>", { regx: 'myvartype' });	 */	$.template.regx = $.template.instance.prototype.regx = {	    jsp:        /\$\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,        ext:        /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,        jtemplates: /\{\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}\}/g	};		/**	 * Set the standard regular expression to be used.	 */	$.template.regx.standard = $.template.regx.jsp;		/**	 * Variable Helper Methods	 *	 * This is a collection of methods which can be used within the variable syntax, ie:	 * ${variable:substr(0,30)} Which would only print a substring, 30 characters in length	 * begining at the first character for the variable named "variable".	 *	 * A basic substring helper is provided as an example of how you can define helpers.	 * To add more helpers simply do:	 * $.extend( $.template.helpers , {	 *	 sampleHelper: function() { ... }		 * });	 */	$.template.helpers = $.template.instance.prototype.helpers = {		substr : function(value, start, length){			return String(value).substr(start, length);		}	};	/**	 * Template Instance Methods	 */	$.extend( $.template.instance.prototype, {				/**		 * Apply Values to a Template		 *		 * This is the macro-work horse of the library, it receives an object		 * and the properties of that objects are assigned to the template, where		 * the variables in the template represent keys within the object itself.		 *		 * @param 	values 	An object of properties mapped to template variables		 */		apply: function(values) {			if (this.options.compile) {				return this.compiled(values);			} else {				var tpl = this;				var fm = this.helpers;				var fn = function(m, name, format, args) {					if (format) {						if (format.substr(0, 5) == "this."){							return tpl.call(format.substr(5), values[name], values);						} else {							if (args) {								// quoted values are required for strings in compiled templates, 								// but for non compiled we need to strip them								// quoted reversed for jsmin								var re = /^\s*['"](.*)["']\s*$/;								args = args.split(',');								for(var i = 0, len = args.length; i < len; i++) {									args[i] = args[i].replace(re, "$1");								}								args = [values[name]].concat(args);							} else {								args = [values[name]];							}							return fm[format].apply(fm, args);						}					} else {						return values[name] !== undefined ? values[name] : "";					}				};				return this.html.replace(this.options.regx, fn);			}		},		/**		 * Compile a template for speedier usage		 */		compile: function() {			var sep = $.browser.mozilla ? "+" : ",";			var fm = this.helpers;			var fn = function(m, name, format, args){				if (format) {					args = args ? ',' + args : "";					if (format.substr(0, 5) != "this.") {						format = "fm." + format + '(';					} else {						format = 'this.call("'+ format.substr(5) + '", ';						args = ", values";					}				} else {					args= ''; format = "(values['" + name + "'] == undefined ? '' : ";				}				return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";			};			var body;			if ($.browser.mozilla) {				body = "this.compiled = function(values){ return '" +					   this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.options.regx, fn) +						"';};";			} else {				body = ["this.compiled = function(values){ return ['"];				body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.options.regx, fn));				body.push("'].join('');};");				body = body.join('');			}			eval(body);			return this;		}	});	/**	 * Save a reference in this local scope to the original methods which we're 	 * going to overload.	 **/	var $_old = {	    domManip: $.fn.domManip,	    text: $.fn.text,	    html: $.fn.html	};	/**	 * Overwrite the domManip method so that we can use things like append() by passing a 	 * template object and macro parameters.	 */	$.fn.domManip = function( args, table, reverse, callback ) {		if (args[0].isTemplate) {			// Apply the template and it's arguments...			args[0] = args[0].apply( args[1] );			// Get rid of the arguements, we don't want to pass them on			delete args[1];		}		// Call the original method		var r = $_old.domManip.apply(this, arguments);		return r;	};    /**     * Overwrite the html() method     */	$.fn.html = function( value , o ) {	    if (value && value.isTemplate) var value = value.apply( o );		var r = $_old.html.apply(this, [value]);		return r;	};		/**	 * Overwrite the text() method	 */	$.fn.text = function( value , o ) {	    if (value && value.isTemplate) var value = value.apply( o );		var r = $_old.text.apply(this, [value]);		return r;	};})(jQuery);
