- added VTepL => is not WIP but works better then Template.js and will replace 90% of all templates with one do the for feature
This commit is contained in:
parent
4c4afe3bdf
commit
170a6cc716
5 changed files with 365 additions and 1 deletions
|
@ -1,3 +1,4 @@
|
|||
/** @deprecated use VTepL instead! */
|
||||
class Template {
|
||||
constructor() {
|
||||
this.tpl = {};
|
||||
|
|
34
raw/javascript/templateLang/VTepLCore.js
Normal file
34
raw/javascript/templateLang/VTepLCore.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
'use strict';
|
||||
|
||||
class VTpeLCore {
|
||||
constructor(options = {}) {
|
||||
this.templates = {};
|
||||
this.dir = options.path || '/tpl/';
|
||||
this.suffix = options.suffix || 'tpl';
|
||||
this.path = options.template || `${this.dir}%s.${this.suffix}`;
|
||||
this.cache = options.cache === undefined ? true : options.cache;
|
||||
}
|
||||
|
||||
async loadTemplate(name) {
|
||||
let rawData = await fetch(this.path.replace('%s', name));
|
||||
if (rawData.ok) {
|
||||
let data = await rawData.text();
|
||||
this.addTpl(name, data);
|
||||
}
|
||||
}
|
||||
|
||||
async loadArray(names) {
|
||||
for (let name of names) {
|
||||
await this.loadTemplate(name);
|
||||
}
|
||||
}
|
||||
|
||||
addTpl(name, content) {
|
||||
let temp = this.templates[name] = new VTpeLTemplate(name, content)
|
||||
temp.parseContent(this.cache);
|
||||
}
|
||||
|
||||
renderOn(name, data) {
|
||||
return this.templates[name].render(data);
|
||||
}
|
||||
}
|
133
raw/javascript/templateLang/VTepLInterpreter.js
Normal file
133
raw/javascript/templateLang/VTepLInterpreter.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
'use strict';
|
||||
|
||||
class VTepLInterpreter {
|
||||
constructor(parser) {
|
||||
this.parser = parser;
|
||||
this.data = [];
|
||||
this.content = '';
|
||||
}
|
||||
|
||||
render(data) {
|
||||
let self = this;
|
||||
self.data = data;
|
||||
let newData = self.interpreter(self.parser.parsed);
|
||||
self.data = [];
|
||||
return newData[0];
|
||||
}
|
||||
|
||||
interpreter(parsed, index = 0) {
|
||||
let self = this;
|
||||
let types = VParserTypes;
|
||||
let tplCont = '';
|
||||
for (let i = index; i < parsed.length; i++) {
|
||||
let item = parsed[i],
|
||||
content = item.content;
|
||||
switch (item.type) {
|
||||
case types.content:
|
||||
tplCont += content;
|
||||
break;
|
||||
case types.variable:
|
||||
tplCont += self.getVariable(content)
|
||||
break;
|
||||
case types.assign:
|
||||
let data = content.split("="),
|
||||
key = data.shift();
|
||||
self.setVariable(data.join("=").trim(), key.trim());
|
||||
break;
|
||||
case types.forEach:
|
||||
let d = this.handleForEach(item, parsed, i);
|
||||
i = d[0];
|
||||
tplCont += d[1];
|
||||
break;
|
||||
case types.for:
|
||||
let fd = this.handleFor(item, parsed, i);
|
||||
i = fd[0];
|
||||
tplCont += fd[1];
|
||||
break;
|
||||
case types.if:
|
||||
let id = this.handleIf(item, parsed, i);
|
||||
i = id[0];
|
||||
tplCont += id[1];
|
||||
break;
|
||||
case types.ifEnd:
|
||||
tplCont += content;
|
||||
return [tplCont, i];
|
||||
case types.forEnd:
|
||||
tplCont += content;
|
||||
return [tplCont, i];
|
||||
default:
|
||||
console.warn("Invalid Type found");
|
||||
break;
|
||||
}
|
||||
}
|
||||
//this.content = tplCont;
|
||||
return [tplCont, parsed.length];
|
||||
}
|
||||
|
||||
getVariable(variable) {
|
||||
if (this.data[variable]) {
|
||||
return this.data[variable];
|
||||
}
|
||||
let split = variable.split("."),
|
||||
prevVar = this.data;
|
||||
for (let i = 0; i < split.length; i++) {
|
||||
prevVar = prevVar[split[i]] || prevVar;
|
||||
}
|
||||
if (typeof prevVar === 'string') {
|
||||
return prevVar;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
setVariable(value, variable) {
|
||||
let c = this.getVariable(value);
|
||||
if (c !== '') {
|
||||
value = c;
|
||||
}
|
||||
this.data[variable] = value;
|
||||
}
|
||||
|
||||
handleForEach(item, parsed, i) {
|
||||
let content = item.content.split(" as ");
|
||||
let root = this.getVariable(content[0].trim());
|
||||
let addTo = 0,
|
||||
isInvalid = false;
|
||||
if (root === '') {
|
||||
isInvalid = true;
|
||||
root = [];
|
||||
}
|
||||
let d = Object.keys(root),
|
||||
raw = '';
|
||||
for (let x of d) {
|
||||
this.setVariable(root[x], content[1].trim());
|
||||
let data = this.interpreter(parsed, i + 1);
|
||||
addTo = data[1];
|
||||
raw += data[0];
|
||||
}
|
||||
if (isInvalid) {
|
||||
raw = '';
|
||||
}
|
||||
return [addTo, raw];
|
||||
}
|
||||
|
||||
handleFor(item, parsed, ind) {
|
||||
let content = item.content.split(" as "),
|
||||
addTo = 0,
|
||||
count = content[0].trim().split(".."),
|
||||
max = parseInt(count[1]),
|
||||
min = parseInt(count[0]),
|
||||
newContent = '';
|
||||
for (let i = min; i < max; i++) {
|
||||
this.setVariable(i.toString(), content[1]);
|
||||
let data = this.interpreter(parsed, ind + 1);
|
||||
addTo = data[1];
|
||||
newContent += data[0];
|
||||
}
|
||||
return [addTo, newContent];
|
||||
}
|
||||
|
||||
handleIf(item, parsed, i) {
|
||||
let data = this.interpreter(parsed, i + 1);
|
||||
return [data[1], data[0]];
|
||||
}
|
||||
}
|
178
raw/javascript/templateLang/VTepLParser.js
Normal file
178
raw/javascript/templateLang/VTepLParser.js
Normal file
|
@ -0,0 +1,178 @@
|
|||
'use strict';
|
||||
|
||||
const VParserTypes = {
|
||||
content: 0,
|
||||
variable: 1,
|
||||
for: 2,
|
||||
forEach: 3,
|
||||
forContent: 4,
|
||||
forEnd: 5,
|
||||
if: 6,
|
||||
ifContent: 7,
|
||||
ifEnd: 8,
|
||||
assign: 9,
|
||||
none: -1,
|
||||
|
||||
// operators
|
||||
'!=': 100,
|
||||
'==': 101,
|
||||
'&&': 102,
|
||||
'||': 103,
|
||||
'>=': 104,
|
||||
'<=': 105,
|
||||
'>': 106,
|
||||
'<': 107,
|
||||
'+': 108,
|
||||
'-': 109,
|
||||
'*': 110,
|
||||
'/': 111,
|
||||
'%': 112
|
||||
};
|
||||
|
||||
|
||||
class VTpeLParser {
|
||||
constructor(name, content) {
|
||||
let self = this;
|
||||
self.name = name;
|
||||
self.legex = content;
|
||||
self.index = 0;
|
||||
self.content = '';
|
||||
self.parsed = [];
|
||||
self.contexts = [0];
|
||||
self.allowedOperators = ['!=', '==', '&&', '||', '>=', '<=', '>', '<', '+', '-', '*', '/', '%']
|
||||
}
|
||||
|
||||
tokenize() {
|
||||
let self = this;
|
||||
for (self.index = 0; self.index < self.legex.length; self.index++) {
|
||||
let i = self.index,
|
||||
char = self.legex.charAt(i);
|
||||
if (self.nextContains('/*', i, true)) {
|
||||
self.extract('*/', VParserTypes.none)
|
||||
} else if (self.nextContains('//', i, true)) {
|
||||
self.extract('\n', VParserTypes.none);
|
||||
} else if (self.nextContains('<!--', i, true)) {
|
||||
self.extract('-->', VParserTypes.none);
|
||||
} else if (self.nextContains('{for(', i, true)) {
|
||||
self.extract(')}', VParserTypes.for);
|
||||
self.contexts.push(VParserTypes.for);
|
||||
} else if (self.nextContains('{foreach(', i, true)) {
|
||||
self.extract(')}', VParserTypes.forEach);
|
||||
self.contexts.push(VParserTypes.forEach);
|
||||
} else if (self.nextContains('{/for}', i, true)) {
|
||||
self.addType(VParserTypes.forEnd);
|
||||
self.contexts.pop();
|
||||
} else if (self.nextContains('{if(', i, true)) {
|
||||
self.extract(')}', VParserTypes.if);
|
||||
self.contexts.push(VParserTypes.if);
|
||||
} else if (self.nextContains('{/if}', i, true)) {
|
||||
self.addType(VParserTypes.ifEnd);
|
||||
self.contexts.pop();
|
||||
} else if (self.nextContains('$${', i, true)) {
|
||||
self.extract('}', VParserTypes.assign);
|
||||
} else if (self.nextContains('${', i, true)) {
|
||||
self.extract('}', VParserTypes.variable);
|
||||
} else {
|
||||
self.content += char;
|
||||
}
|
||||
}
|
||||
self.addType(VParserTypes.content);
|
||||
return self.parsed;
|
||||
}
|
||||
|
||||
addType(type) {
|
||||
let self = this;
|
||||
let content = self.content.trim(),
|
||||
instructions = self.findInstructions(type);
|
||||
self.content = '';
|
||||
if (type !== VParserTypes.none) {
|
||||
if (type === VParserTypes.content && content === '') {
|
||||
return null;
|
||||
}
|
||||
return self.parsed.push({
|
||||
content: content,
|
||||
type: type,
|
||||
context: self.contexts[self.contexts.length - 1],
|
||||
instructions: instructions
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
nextContains(find, index, add = false) {
|
||||
let count = this.nextContainsRaw(this.legex, find, index);
|
||||
if (add && count > 0) {
|
||||
this.index += count;
|
||||
}
|
||||
return count > 0 || count === -1;
|
||||
}
|
||||
|
||||
nextContainsRaw(raw, find, index) {
|
||||
if (typeof find === "string") {
|
||||
find = find.split("");
|
||||
}
|
||||
let count = find.length;
|
||||
if (count < 1) {
|
||||
return -1;
|
||||
}
|
||||
for (let i = 0; i < count; i++) {
|
||||
let nc = raw.charAt(index + i);
|
||||
if ((find[i] === '\n' && nc === undefined)) {
|
||||
return count;
|
||||
}
|
||||
if (find[i] !== nc) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
extract(findUntil = '}', type = 1) {
|
||||
let self = this;
|
||||
self.addType(0);
|
||||
findUntil = findUntil.split("")
|
||||
let content = '',
|
||||
index = self.index,
|
||||
legex = self.legex,
|
||||
firstFind = findUntil.shift();
|
||||
for (let i = self.index; i < legex.length; i++) {
|
||||
let char = legex.charAt(i);
|
||||
if (char === firstFind && self.nextContains(findUntil, i + 1)) {
|
||||
console.debug(`[Parser][${index} > ${i}] >> ${content}`);
|
||||
self.index = i + findUntil.length;
|
||||
self.content = content;
|
||||
self.addType(type);
|
||||
return;
|
||||
}
|
||||
content += char;
|
||||
}
|
||||
throw 'Template variable at Position: ' + index + ' not closed!';
|
||||
}
|
||||
|
||||
// @todo implement split... is needed for if statements and math stuff or get it stupid!
|
||||
getOperator(string) {
|
||||
let operators = [];
|
||||
for (let i = 0; i < string.length; i++) {
|
||||
if (this.nextContainsRaw(string, "(", i)) {
|
||||
let innerCon = '';
|
||||
for (let x = 0; x < string.length; x++) {
|
||||
let char = string.charAt(i + x);
|
||||
if (char === ')') {
|
||||
break;
|
||||
}
|
||||
innerCon += char;
|
||||
}
|
||||
operators = [...operators, this.getOperator(innerCon)];
|
||||
} else {
|
||||
}
|
||||
}
|
||||
return operators;
|
||||
}
|
||||
|
||||
findInstructions(type) {
|
||||
if (type === VParserTypes.if) {
|
||||
return this.getOperator(this.content);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
18
raw/javascript/templateLang/VTepLTemplate.js
Normal file
18
raw/javascript/templateLang/VTepLTemplate.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
class VTpeLTemplate {
|
||||
constructor(name, content) {
|
||||
this.name = name;
|
||||
this.tpl = content;
|
||||
this.parser = new VTpeLParser(name, content);
|
||||
this.interpreter = new VTepLInterpreter(this.parser);
|
||||
}
|
||||
|
||||
render(data = {}) {
|
||||
return this.interpreter.render(data);
|
||||
}
|
||||
|
||||
parseContent() {
|
||||
this.parser.tokenize();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue