;(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(factory);
} else if (typeof module === "object" && typeof module.exports === "object") {
module.exports = factory();
} else {
global.TPL = factory();
}
})(this, function () {
// Usage:
// console.log(new TPL.Template("<div>Total: {{= value }}<div>", {delimiters: ["{{", "}}"]}).render({value: "<span>15</span>"}));
// Options:
// delimiters - characters to use for open and close delimiters
// rmWhitespace - remove whitespace between HTML-tags
// Tags:
// <% - scriptlet tag for control-flow, no output
// <%% - outputs raw template part
// <%- - outputs the raw unescaped value into the template
// <%= - outputs the HTML escaped value into the template
// <%# - comment tag, no execution, no output
// %> - plain ending tag
function Template (templateString, newSettingsObject) {
var settingsObject = {
delimiters: ["<%", "%>"]
, rmWhitespace: false // removeWhitespace
};
if (newSettingsObject) {setNewSettings(settingsObject, newSettingsObject);}
var renderFunction = createRenderFunction(templateString, settingsObject); // console.log(renderFunction.toString());
return {render: function (dataObject) {return renderFunction(dataObject, settingsObject, escapeHtmlFunction, trim);}};
}
function setNewSettings (settingsObject, newSettingsObject) {
for (var key in newSettingsObject) {
if (newSettingsObject.hasOwnProperty(key)) {
settingsObject[key] = newSettingsObject[key];
}
}
}
function trim (text) {
return text == null ? "" : ("" + text).replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); // Trim space: \s, BOM: \uFEFF, NBSP: \xA0.
}
function createRenderFunction (templateString, settingsObject) {
var matchRegExp = createMatchRegExp(settingsObject)
, renderFunction;
try {
renderFunction = new Function ("dataObject", "_settingsObject_", "_escapeHtmlFunction_", "_trim_" // ) {
, "if (!dataObject) {dataObject = {};}" + "\n"
+ "var _parsedTemplateString_ = '';" + "\n"
+ "with (dataObject) {" + "\n"
+ "_parsedTemplateString_ += '" + (function(){
var resultString = ""
, index = 0;
templateString.replace(matchRegExp, function (match, prerenderCodeString, rawInterpolateCodeString, interpolateAndEscapeCodeString, commentCodeString, evaluateCodeString, offset) {
resultString += escapeString(templateString.slice(index, offset));
index = offset + match.length;
if (prerenderCodeString !== undefined) {
resultString += "' + '" + settingsObject.delimiters[0] + prerenderCodeString + settingsObject.delimiters[1] + "' + '";
} else if (rawInterpolateCodeString !== undefined) {
resultString += "'" + "\n"
+ "+ (function(){" + "\n"
+ "var _value_ = " + rawInterpolateCodeString + ";" + "\n"
+ "if (_value_ === undefined || _value_ === null) {return '';} else {return _value_;}" + "\n"
+ "})()" + "\n"
+ "+ '";
} else if (interpolateAndEscapeCodeString !== undefined) {
resultString += "'" + "\n"
+ "+ (function(){" + "\n"
+ "var _value_ = " + interpolateAndEscapeCodeString + ";" + "\n"
+ "if (_value_ === undefined || _value_ === null) {return '';} else {return _escapeHtmlFunction_(_value_);}" + "\n"
+ "})()" + "\n"
+ "+ '";
} else if (commentCodeString !== undefined) {
// Do nothing
} else if (evaluateCodeString !== undefined) {
resultString += "';" + "\n"
+ evaluateCodeString + "\n"
+ "_parsedTemplateString_ += '";
}
return match;
});
return resultString;
})()
+ "';" + "\n"
+ "}" + "\n"
+ "if (_settingsObject_.rmWhitespace) {_parsedTemplateString_ = _trim_(_parsedTemplateString_.replace(/\\\\r/g, ''));}" + "\n"
+ "return _parsedTemplateString_;"
// }
);
} catch (error) {
if (error instanceof SyntaxError) {error.message += " while compiling template: " + templateString;}
throw error;
}
return renderFunction;
}
function createMatchRegExp (settingsObject) {
var openDelimiter = settingsObject.delimiters[0] // <%
, closeDelimiter = settingsObject.delimiters[1] // %>
, stringInsideDelimiters = "([\\s\\S]+?)" // some string
, tags = {
prerender: openDelimiter + "%" + stringInsideDelimiters + closeDelimiter // <%% some string %>
, rawInterpolate: openDelimiter + "-" + stringInsideDelimiters + closeDelimiter // <%= some string %>
, interpolateAndEscape: openDelimiter + "=" + stringInsideDelimiters + closeDelimiter // <%- some string %>
, comment: openDelimiter + "#" + stringInsideDelimiters + closeDelimiter // <%# some string %>
, evaluate: openDelimiter + stringInsideDelimiters + closeDelimiter // <% some string %>
}
, matchRegExp = new RegExp([
tags.prerender // Important!!! Must be first!
, tags.rawInterpolate
, tags.interpolateAndEscape
, tags.comment
, tags.evaluate // Important!!! Must be last!
].join("|") + "|$", "g"); // /<%%([\s\S]+?)%>|<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%#([\s\S]+?)%>|<%([\s\S]+?)%>|$/g
return matchRegExp;
}
function escapeString (string) {
return string.replace(/\\|'|\r|\n|\u2028|\u2029/g, function (match) {
var escapeCharacters = {
"'": "\\'"
, "\\": "\\\\"
, "\r": "\\r"
, "\n": "\\n"
, "\u2028": "\\u2028"
, "\u2029": "\\u2029"
};
return escapeCharacters[match];
});
}
function escapeHtmlFunction (string) {
string = "" + string;
var pattern = "(?:&|<|>|\"|'|`)"
, testRegExp = new RegExp(pattern)
, replaceRegExp = new RegExp(pattern, "g");
if (testRegExp.test(string)) {
return string.replace(replaceRegExp, function (match) {
var escapeCharacters = {
"&": "&"
, "<": "<"
, ">": ">"
, "\"": """
, "'": "'"
, "`": "`"
};
return escapeCharacters[match];
});
} else {
return string;
}
}
return {
Template: Template
, compile: function (templateString, newSettingsObject) {return new Template(templateString, newSettingsObject);}
, render: function (templateString, dataObject, newSettingsObject) {return new Template(templateString, newSettingsObject).render(dataObject);}
};
});
// Тесты
//console.log(new TPL.Template(" \r \r Total: <% if (true) { %>1<% } %> Total: <%= value %> Total: <%- value %> Total: <%# comment %> Total: <%%- value %> ", {rmWhitespace: true}).render({value: "<div>15</div>"}));
Комментариев нет:
Отправить комментарий