308 lines
9.7 KiB
JavaScript
308 lines
9.7 KiB
JavaScript
//------------------------------------------------------------------------------
|
|
// Template-Engine
|
|
//------------------------------------------------------------------------------
|
|
// depends-on:
|
|
// inheritance
|
|
//------------------------------------------------------------------------------
|
|
|
|
// String-Methoden ergänzen
|
|
|
|
APPCO = {};
|
|
|
|
APPCO.apply = function(o, c, defaults){
|
|
// no "this" reference for friendly out of scope calls
|
|
if (defaults) {
|
|
APPCO.apply(o, defaults);
|
|
}
|
|
if (o && c && typeof c == 'object') {
|
|
for (var p in c) {
|
|
o[p] = c[p];
|
|
}
|
|
}
|
|
return o;
|
|
};
|
|
|
|
// quick and dirty! Manche Autoren lehnen solche Erweiterungen ab
|
|
|
|
APPCO.apply(String.prototype, {
|
|
include: function (pattern) {
|
|
return this.indexOf(pattern) > -1;
|
|
},
|
|
startsWith: function (pattern) {
|
|
return this.lastIndexOf(pattern, 0) === 0;
|
|
},
|
|
endsWith: function (pattern) {
|
|
var d = this.length - pattern.length;
|
|
return d >= 0 && this.indexOf(pattern, d) === d;
|
|
}
|
|
});
|
|
|
|
APPCO.apply(String, {
|
|
interpret: function(value) {
|
|
return value == null ? '' : String(value);
|
|
}
|
|
});
|
|
|
|
// Namensraum
|
|
|
|
var TELIB = {};
|
|
|
|
TELIB.Generator_cl = Class.create({
|
|
initialize: function () {
|
|
this.reset_px();
|
|
},
|
|
reset_px: function () {
|
|
this.code_a = ['var result_a = [];\n'];
|
|
},
|
|
write_px: function (text_spl) {
|
|
// Escape-Zeichen bei Strings ergänzen
|
|
var text_s = text_spl.replace(/"/g, '\\"');
|
|
text_s = text_s.replace(/'/g, "\\'");
|
|
this.code_a.push('result_a.push("' + text_s + '");\n');
|
|
},
|
|
code_px: function (code_spl) {
|
|
if (code_spl.startsWith('if')) {
|
|
this.code_a.push('if (' + code_spl.substr(2) + ') {\n');
|
|
} else if (code_spl.startsWith('else')) {
|
|
this.code_a.push('} else {\n');
|
|
} else if (code_spl.startsWith('endif')) {
|
|
this.code_a.push('}\n');
|
|
} else if (code_spl.startsWith('for')) {
|
|
this.code_a.push('for (' + code_spl.substr(3) + ') {\n');
|
|
} else if (code_spl.startsWith('endfor')) {
|
|
this.code_a.push('}\n');
|
|
} else {
|
|
this.code_a.push(code_spl + '\n');
|
|
}
|
|
},
|
|
substitute_px: function (subst_spl) {
|
|
this.code_a.push('result_a.push(' + String.interpret(subst_spl) + ');\n');
|
|
},
|
|
generate_px: function () {
|
|
var result_s = this.code_a.join('') + ' return result_a.join("");';
|
|
var f_o = new Function ('context', result_s);
|
|
return f_o;
|
|
}
|
|
});
|
|
|
|
TELIB.TemplateCompiler_cl = Class.create({
|
|
initialize: function () {
|
|
this.gen_o = new TELIB.Generator_cl();
|
|
this.reset_px();
|
|
},
|
|
reset_px: function () {
|
|
this.gen_o.reset_px();
|
|
this.preservePreWS_b = false;
|
|
this.preservePostWS_b = false;
|
|
},
|
|
setPreWS_px: function (on_bpl) {
|
|
if ((on_bpl == undefined) || (on_bpl == false)) {
|
|
this.preservePreWS_b = false;
|
|
} else {
|
|
this.preservePreWS_b = true;
|
|
}
|
|
},
|
|
setPostWS_px: function (on_bpl) {
|
|
if ((on_bpl == undefined) || (on_bpl == false)) {
|
|
this.preservePostWS_b = false;
|
|
} else {
|
|
this.preservePostWS_b = true;
|
|
}
|
|
},
|
|
compile_px: function (source_spl) {
|
|
var state_i = 0;
|
|
var pos_i = 0;
|
|
var len_i = source_spl.length;
|
|
var text_s = '';
|
|
var code_s = '';
|
|
var subst_s = '';
|
|
this.gen_o.reset_px();
|
|
|
|
var doubletest_f = function (char_spl) {
|
|
var status_b = false;
|
|
if ((pos_i + 1) < len_i) {
|
|
if ((source_spl[pos_i] == char_spl) && (source_spl[pos_i+1] == char_spl)) {
|
|
status_b = true;
|
|
}
|
|
}
|
|
return status_b;
|
|
}
|
|
|
|
while (pos_i < len_i) {
|
|
switch (state_i) {
|
|
case 0:
|
|
// outside
|
|
if (source_spl[pos_i] == '@') { // ECMA 5!
|
|
if (doubletest_f('@') == false) {
|
|
state_i = 2;
|
|
code_s = '';
|
|
} else {
|
|
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
|
state_i = 1;
|
|
text_s = '@';
|
|
pos_i++;
|
|
}
|
|
} else if (source_spl[pos_i] == '#') {
|
|
if (doubletest_f('#') == false) {
|
|
state_i = 3;
|
|
subst_s = '';
|
|
} else {
|
|
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
|
state_i = 1;
|
|
text_s = '#';
|
|
pos_i++;
|
|
}
|
|
} else if ((source_spl[pos_i] == ' ') || (source_spl[pos_i] == '\t')) {
|
|
state_i = 4;
|
|
text_s = '';
|
|
pos_i--; // Zeichen erneut verarbeiten
|
|
} else {
|
|
state_i = 1;
|
|
text_s = '';
|
|
pos_i--; // Zeichen erneut verarbeiten
|
|
}
|
|
break;
|
|
case 1:
|
|
// inText
|
|
if (source_spl[pos_i] == '@') {
|
|
if (doubletest_f('@') == false) {
|
|
// Textende, neuer Code
|
|
state_i = 0;
|
|
this.gen_o.write_px(text_s);
|
|
pos_i--; // Zeichen erneut verarbeiten
|
|
} else {
|
|
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
|
text_s += '@';
|
|
pos_i++;
|
|
}
|
|
} else if (source_spl[pos_i] == '#') {
|
|
if (doubletest_f('#') == false) {
|
|
// Textende, neue Substitution
|
|
state_i = 0;
|
|
this.gen_o.write_px(text_s);
|
|
pos_i--; // Zeichen erneut verarbeiten
|
|
// Textende, neuer Code
|
|
} else {
|
|
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
|
text_s += '#';
|
|
pos_i++;
|
|
}
|
|
} else if ((source_spl[pos_i] == ' ') || (source_spl[pos_i] == '\t')) {
|
|
// Textende
|
|
state_i = 0;
|
|
this.gen_o.write_px(text_s);
|
|
pos_i--; // Zeichen erneut verarbeiten
|
|
} else {
|
|
// sammeln
|
|
if ((source_spl[pos_i] != '\n') && (source_spl[pos_i] != '\r')) {
|
|
text_s += source_spl[pos_i];
|
|
} else if (source_spl[pos_i] == '\n') {
|
|
text_s += '\\n';
|
|
} else {
|
|
text_s += '\\r';
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
// inCode
|
|
if (source_spl[pos_i] == '@') {
|
|
if (doubletest_f('@') == false) {
|
|
// zu Ende, erzeugen
|
|
this.gen_o.code_px(code_s);
|
|
state_i = 5; //0
|
|
} else {
|
|
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
|
code_s += '@';
|
|
pos_i++;
|
|
}
|
|
} else {
|
|
// sammeln
|
|
code_s += source_spl[pos_i];
|
|
}
|
|
break;
|
|
case 3:
|
|
// inSubst
|
|
// Verdopplung # hier nicht zulässig!
|
|
if (source_spl[pos_i] == '#') {
|
|
// zu Ende, erzeugen
|
|
this.gen_o.substitute_px(subst_s);
|
|
state_i = 0;
|
|
} else {
|
|
// sammeln
|
|
subst_s += source_spl[pos_i];
|
|
}
|
|
break;
|
|
case 4:
|
|
// pre-code-whitespace
|
|
switch (source_spl[pos_i]) {
|
|
case ' ':
|
|
case '\t':
|
|
// sammeln
|
|
text_s += source_spl[pos_i];
|
|
break;
|
|
default:
|
|
state_i = 0;
|
|
if (source_spl[pos_i] != '@') {
|
|
this.gen_o.write_px(text_s);
|
|
} else {
|
|
if (doubletest_f('@') == false) {
|
|
// Whitespace vor Code-Beginn erkannt
|
|
if (this.preservePreWS_b == true) {
|
|
// trotzdem ausgeben
|
|
this.gen_o.write_px(text_s);
|
|
}
|
|
} // ansonsten wie normales Zeichen behandeln
|
|
}
|
|
pos_i--; // Zeichen erneut verarbeiten
|
|
}
|
|
break;
|
|
case 5:
|
|
// post-code-whitespace
|
|
switch (source_spl[pos_i]) {
|
|
case '\n':
|
|
text_s += '\\n';
|
|
state_i = 0;
|
|
break;
|
|
case '\r':
|
|
text_s += '\\r';
|
|
state_i = 0;
|
|
break;
|
|
case ' ':
|
|
case '\t':
|
|
// ggf. sammeln
|
|
text_s += source_spl[pos_i];
|
|
break;
|
|
default:
|
|
// Whitespace nach Code erkannt
|
|
if (this.preservePostWS_b == true) {
|
|
// trotzdem ausgeben
|
|
this.gen_o.write_px(text_s);
|
|
}
|
|
state_i = 0;
|
|
pos_i--; // Zeichen erneut verarbeiten
|
|
}
|
|
break;
|
|
}
|
|
pos_i++;
|
|
}
|
|
// welcher Zustand liegt abschließend vor?
|
|
if (state_i == 1) {
|
|
this.gen_o.write_px(text_s);
|
|
} else if (state_i == 2) {
|
|
this.gen_o.code_px(code_s);
|
|
} else if (state_i == 3) {
|
|
this.gen_o.substitute_px(subst_s);
|
|
} else if (state_i == 4) {
|
|
if (this.preservePreWS_b == true) {
|
|
this.gen_o.write_px(text_s);
|
|
}
|
|
} else if (state_i == 5) {
|
|
if (this.preservePostWS_b == true) {
|
|
this.gen_o.write_px(text_s);
|
|
}
|
|
}
|
|
|
|
return this.gen_o.generate_px();
|
|
}
|
|
});
|
|
// EOF
|