📄 template.js
字号:
/**
* TrimPath Template. Release 1.0.38.
* Copyright (C) 2004, 2005 Metaha.
*
* TrimPath Template is licensed under the GNU General Public License
* and the Apache License, Version 2.0, as follows:
*
* 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 2
* of the License, or (at your option) any later version.
*
* This program is distributed 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var TrimPath;
// TODO: Debugging mode vs stop-on-error mode - runtime flag.
// TODO: Handle || (or) characters and backslashes.
// TODO: Add more modifiers.
(function() { // Using a closure to keep global namespace clean.
if (TrimPath == null)
TrimPath = new Object();
if (TrimPath.evalEx == null)
TrimPath.evalEx = function(src) { return eval(src); };
var UNDEFINED;
if (Array.prototype.pop == null) // IE 5.x fix from Igor Poteryaev.
Array.prototype.pop = function() {
if (this.length === 0) {return UNDEFINED;}
return this[--this.length];
};
if (Array.prototype.push == null) // IE 5.x fix from Igor Poteryaev.
Array.prototype.push = function() {
for (var i = 0; i < arguments.length; ++i) {this[this.length] = arguments[i];}
return this.length;
};
TrimPath.parseTemplate = function(tmplContent, optTmplName, optEtc) {
if (optEtc == null)
optEtc = TrimPath.parseTemplate_etc;
var funcSrc = parse(tmplContent, optTmplName, optEtc);
var func = TrimPath.evalEx(funcSrc, optTmplName, 1);
if (func != null)
return new optEtc.Template(optTmplName, tmplContent, funcSrc, func, optEtc);
return null;
}
try {
String.prototype.process = function(context, optFlags) {
var template = TrimPath.parseTemplate(this, null);
if (template != null)
return template.process(context, optFlags);
return this;
}
} catch (e) { // Swallow exception, such as when String.prototype is sealed.
}
TrimPath.parseTemplate_etc = {}; // Exposed for extensibility.
TrimPath.parseTemplate_etc.statementTag = "forelse|for|if|elseif|else|var|macro";
TrimPath.parseTemplate_etc.statementDef = { // Lookup table for statement tags.
"if" : { delta: 1, prefix: "if (", suffix: ") {", paramMin: 1 },
"else" : { delta: 0, prefix: "} else {" },
"elseif" : { delta: 0, prefix: "} else if (", suffix: ") {", paramDefault: "true" },
"/if" : { delta: -1, prefix: "}" },
"for" : { delta: 1, paramMin: 3,
prefixFunc : function(stmtParts, state, tmplName, etc) {
if (stmtParts[2] != "in")
throw new etc.ParseError(tmplName, state.line, "bad for loop statement: " + stmtParts.join(' '));
var iterVar = stmtParts[1];
var listVar = "__LIST__" + iterVar;
return [ "var ", listVar, " = ", stmtParts[3], ";",
// Fix from Ross Shaull for hash looping, make sure that we have an array of loop lengths to treat like a stack.
"var __LENGTH_STACK__;",
"if (typeof(__LENGTH_STACK__) == 'undefined' || !__LENGTH_STACK__.length) __LENGTH_STACK__ = new Array();",
"__LENGTH_STACK__[__LENGTH_STACK__.length] = 0;", // Push a new for-loop onto the stack of loop lengths.
"if ((", listVar, ") != null) { ",
"var ", iterVar, "_ct = 0;", // iterVar_ct variable, added by B. Bittman
"for (var ", iterVar, "_index in ", listVar, ") { ",
iterVar, "_ct++;",
"if (typeof(", listVar, "[", iterVar, "_index]) == 'function') {continue;}", // IE 5.x fix from Igor Poteryaev.
"__LENGTH_STACK__[__LENGTH_STACK__.length - 1]++;",
"var ", iterVar, " = ", listVar, "[", iterVar, "_index];" ].join("");
} },
"forelse" : { delta: 0, prefix: "} } if (__LENGTH_STACK__[__LENGTH_STACK__.length - 1] == 0) { if (", suffix: ") {", paramDefault: "true" },
"/for" : { delta: -1, prefix: "} }; delete __LENGTH_STACK__[__LENGTH_STACK__.length - 1];" }, // Remove the just-finished for-loop from the stack of loop lengths.
"var" : { delta: 0, prefix: "var ", suffix: ";" },
"macro" : { delta: 1,
prefixFunc : function(stmtParts, state, tmplName, etc) {
var macroName = stmtParts[1].split('(')[0];
return [ "var ", macroName, " = function",
stmtParts.slice(1).join(' ').substring(macroName.length),
"{ var _OUT_arr = []; var _OUT = { write: function(m) { if (m) _OUT_arr.push(m); } }; " ].join('');
} },
"/macro" : { delta: -1, prefix: " return _OUT_arr.join(''); };" }
}
TrimPath.parseTemplate_etc.modifierDef = {
"eat" : function(v) { return ""; },
"escape" : function(s) { return String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); },
"capitalize" : function(s) { return String(s).toUpperCase(); },
"default" : function(s, d) { return s != null ? s : d; }
}
TrimPath.parseTemplate_etc.modifierDef.h = TrimPath.parseTemplate_etc.modifierDef.escape;
TrimPath.parseTemplate_etc.Template = function(tmplName, tmplContent, funcSrc, func, etc) {
this.process = function(context, flags) {
if (context == null)
context = {};
if (context._MODIFIERS == null)
context._MODIFIERS = {};
if (context.defined == null)
context.defined = function(str) { return (context[str] != undefined); };
for (var k in etc.modifierDef) {
if (context._MODIFIERS[k] == null)
context._MODIFIERS[k] = etc.modifierDef[k];
}
if (flags == null)
flags = {};
var resultArr = [];
var resultOut = { write: function(m) { resultArr.push(m); } };
try {
func(resultOut, context, flags);
} catch (e) {
if (flags.throwExceptions == true)
throw e;
var result = new String(resultArr.join("") + "[ERROR: " + e.toString() + (e.message ? '; ' + e.message : '') + "]");
result["exception"] = e;
return result;
}
return resultArr.join("");
}
this.name = tmplName;
this.source = tmplContent;
this.sourceFunc = funcSrc;
this.toString = function() { return "TrimPath.Template [" + tmplName + "]"; }
}
TrimPath.parseTemplate_etc.ParseError = function(name, line, message) {
this.name = name;
this.line = line;
this.message = message;
}
TrimPath.parseTemplate_etc.ParseError.prototype.toString = function() {
return ("TrimPath template ParseError in " + this.name + ": line " + this.line + ", " + this.message);
}
var parse = function(body, tmplName, etc) {
body = cleanWhiteSpace(body);
var funcText = [ "var TrimPath_Template_TEMP = function(_OUT, _CONTEXT, _FLAGS) { with (_CONTEXT) {" ];
var state = { stack: [], line: 1 }; // TODO: Fix line number counting.
var endStmtPrev = -1;
while (endStmtPrev + 1 < body.length) {
var begStmt = endStmtPrev;
// Scan until we find some statement markup.
begStmt = body.indexOf("{", begStmt + 1);
while (begStmt >= 0) {
var endStmt = body.indexOf('}', begStmt + 1);
var stmt = body.substring(begStmt, endStmt);
var blockrx = stmt.match(/^\{(cdata|minify|eval)/); // From B. Bittman, minify/eval/cdata implementation.
if (blockrx) {
var blockType = blockrx[1];
var blockMarkerBeg = begStmt + blockType.length + 1;
var blockMarkerEnd = body.indexOf('}', blockMarkerBeg);
if (blockMarkerEnd >= 0) {
var blockMarker;
if( blockMarkerEnd - blockMarkerBeg <= 0 ) {
blockMarker = "{/" + blockType + "}";
} else {
blockMarker = body.substring(blockMarkerBeg + 1, blockMarkerEnd);
}
var blockEnd = body.indexOf(blockMarker, blockMarkerEnd + 1);
if (blockEnd >= 0) {
emitSectionText(body.substring(endStmtPrev + 1, begStmt), funcText);
var blockText = body.substring(blockMarkerEnd + 1, blockEnd);
if (blockType == 'cdata') {
emitText(blockText, funcText);
} else if (blockType == 'minify') {
emitText(scrubWhiteSpace(blockText), funcText);
} else if (blockType == 'eval') {
if (blockText != null && blockText.length > 0) // From B. Bittman, eval should not execute until process().
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -