[IMP] app: add templates in app config

Also, improve the parsing code
This commit is contained in:
Géry Debongnie
2021-11-22 10:34:14 +01:00
committed by Aaron Bohy
parent eb2c41aa91
commit db9658c140
3 changed files with 45 additions and 7 deletions
+4
View File
@@ -15,6 +15,7 @@ export interface AppConfig {
env?: Env;
translatableAttributes?: string[];
translateFn?: (s: string) => string;
templates?: string | Document;
}
export const DEV_MSG = `Owl is running in 'dev' mode.
@@ -49,6 +50,9 @@ export class App<T extends typeof Component = any> extends TemplateSet {
if (config.translatableAttributes) {
this.translatableAttributes = config.translatableAttributes;
}
if (config.templates) {
this.addTemplates(config.templates);
}
return this;
}
+35 -1
View File
@@ -7,6 +7,36 @@ const bdom = { text, createBlock, list, multi, html, toggler, component };
export const globalTemplates: { [key: string]: string | Node } = {};
function parseXML(xml: string): Document {
const parser = new DOMParser();
const doc = parser.parseFromString(xml, "text/xml");
if (doc.getElementsByTagName("parsererror").length) {
let msg = "Invalid XML in template.";
const parsererrorText = doc.getElementsByTagName("parsererror")[0].textContent;
if (parsererrorText) {
msg += "\nThe parser has produced the following error message:\n" + parsererrorText;
const re = /\d+/g;
const firstMatch = re.exec(parsererrorText);
if (firstMatch) {
const lineNumber = Number(firstMatch[0]);
const line = xml.split("\n")[lineNumber - 1];
const secondMatch = re.exec(parsererrorText);
if (line && secondMatch) {
const columnIndex = Number(secondMatch[0]) - 1;
if (line[columnIndex]) {
msg +=
`\nThe error might be located at xml line ${lineNumber} column ${columnIndex}\n` +
`${line}\n${"-".repeat(columnIndex - 1)}^`;
}
}
}
}
throw new Error(msg);
}
return doc;
}
export class TemplateSet {
rawTemplates: typeof globalTemplates = Object.create(globalTemplates);
templates: { [name: string]: Template } = {};
@@ -33,7 +63,11 @@ export class TemplateSet {
}
addTemplates(xml: string | Document, options: { allowDuplicate?: boolean } = {}) {
xml = xml instanceof Document ? xml : new DOMParser().parseFromString(xml, "text/xml");
if (!xml) {
// empty string
return;
}
xml = xml instanceof Document ? xml : parseXML(xml);
for (const template of xml.querySelectorAll("[t-name]")) {
const name = template.getAttribute("t-name")!;
template.removeAttribute("t-name");
+6 -6
View File
@@ -21,12 +21,12 @@ describe("error handling", () => {
expect(() => context.addTemplate("test", "<div/>")).toThrow("already defined");
});
// test("addTemplates throw if parser error", () => {
// const context = new TestContext();
// expect(() => {
// context.addTemplates("<templates><abc>></templates>");
// }).toThrow("Invalid XML in template");
// });
test("addTemplates throw if parser error", () => {
const context = new TestContext();
expect(() => {
context.addTemplates("<templates><abc>></templates>");
}).toThrow("Invalid XML in template");
});
test("nice error when t-on is evaluated with a missing event", () => {
expect(() => renderToString(`<div t-on="somemethod"></div>`)).toThrow(