diff --git a/mustache.js b/mustache.js
index e2b52c8..8a883c8 100644
--- a/mustache.js
+++ b/mustache.js
@@ -29,8 +29,104 @@ var Mustache = function() {
}
this.pragmas = {};
+
+ // Fix up the stupidness that is IE's split implementation
+ this._compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group
+ var hasCapturingSplit = '{{hi}}'.split(/(hi)/).length === 3;
+ if (!hasCapturingSplit) {
+ this.splitFunc = this.capturingSplit;
+ } else {
+ this.splitFunc = String.prototype.split;
+ }
};
Renderer.prototype = {
+ capturingSplit: function(separator) {
+ // fix up the stupidness that is IE's broken String.split implementation
+ // originally by Steven Levithan
+ /* Cross-Browser Split 1.0.1
+ (c) Steven Levithan ; MIT License
+ An ECMA-compliant, uniform cross-browser split method */
+ var str = this;
+ var limit = undefined;
+
+ // if `separator` is not a regex, use the native `split`
+ if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
+ return String.prototype.split.call(str, separator, limit);
+ }
+
+ var output = [],
+ lastLastIndex = 0,
+ flags = (separator.ignoreCase ? "i" : "") +
+ (separator.multiline ? "m" : "") +
+ (separator.sticky ? "y" : ""),
+ separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy
+ separator2, match, lastIndex, lastLength;
+
+ str = str + ""; // type conversion
+ if (!this._compliantExecNpcg) {
+ separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt
+ }
+
+ /* behavior for `limit`: if it's...
+ - `undefined`: no limit.
+ - `NaN` or zero: return an empty array.
+ - a positive number: use `Math.floor(limit)`.
+ - a negative number: no limit.
+ - other: type-convert, then use the above rules. */
+ if (limit === undefined || +limit < 0) {
+ limit = Infinity;
+ } else {
+ limit = Math.floor(+limit);
+ if (!limit) {
+ return [];
+ }
+ }
+
+ while (match = separator.exec(str)) {
+ lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser
+
+ if (lastIndex > lastLastIndex) {
+ output.push(str.slice(lastLastIndex, match.index));
+
+ // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
+ if (!this._compliantExecNpcg && match.length > 1) {
+ match[0].replace(separator2, function () {
+ for (var i = 1; i < arguments.length - 2; i++) {
+ if (arguments[i] === undefined) {
+ match[i] = undefined;
+ }
+ }
+ });
+ }
+
+ if (match.length > 1 && match.index < str.length) {
+ Array.prototype.push.apply(output, match.slice(1));
+ }
+
+ lastLength = match[0].length;
+ lastLastIndex = lastIndex;
+
+ if (output.length >= limit) {
+ break;
+ }
+ }
+
+ if (separator.lastIndex === match.index) {
+ separator.lastIndex++; // avoid an infinite loop
+ }
+ }
+
+ if (lastLastIndex === str.length) {
+ if (lastLength || !separator.test("")) {
+ output.push("");
+ }
+ } else {
+ output.push(str.slice(lastLastIndex));
+ }
+
+ return output.length > limit ? output.slice(0, limit) : output;
+ },
+
render: function(template, context, partials) {
template = this.parse_pragmas(template, '{{', '}}');
@@ -71,7 +167,7 @@ var Mustache = function() {
var regex = new RegExp('(' + delimiters.join('|') + ')');
- var tokens = template.split(regex);
+ var tokens = this.splitFunc.call(template, regex);
var cleaned_tokens = [];
for (var i = 0, n = tokens.length; iThe list is empty.
',
- '{{/empty}}',
+ '{{/empty}}'
].join('\n');
var view = {
@@ -574,22 +574,22 @@ test("Performance", function() {
var template = '{{#count}}{{name}}\n{{/count}}';
- start = Date.now();
+ start = new Date();
for (var j=0;j<1000;++j) {
this._oldToHtml(template, view, {});
}
- end = Date.now();
+ end = new Date();
- var interpreter_time = end - start;
+ var interpreter_time = end.getTime() - start.getTime();
- start = Date.now();
+ start = new Date();
var compiler = Mustache.compile(template, {});
for (var k=0;k<1000;++k) {
compiler(view);
}
- end = Date.now();
+ end = new Date();
- var compiler_time = end - start;
+ var compiler_time = end.getTime() - start.getTime();
ok(compiler_timeThe list is empty.',
- '{{/empty}}',
+ '{{/empty}}'
].join('\n');
var view = {