From 82ab18ad837ff15705275c0d3393a185bc9d752c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 11 Oct 2021 14:00:56 +0200 Subject: [PATCH] wip --- src/utils.ts | 68 ++++++++++++++++++++++++++++++++++++++++- tests/qweb/qweb.test.ts | 3 +- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 53ddcbc9..3f222623 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -15,7 +15,7 @@ import { browser } from "./browser"; export function whenReady(fn?: any) { return new Promise(function (resolve) { if (document.readyState !== "loading") { - resolve(); + (resolve as any)(); } else { document.addEventListener("DOMContentLoaded", resolve, false); } @@ -101,3 +101,69 @@ export function shallowEqual(p1, p2): boolean { } return true; } + +const escapeMethod = Symbol('html') + +// notable issues: +// * objects can't be negative in JS, so !!"" -> false but +// !!(new String) -> true, likewise markup +// TODO (?) +// * Markup.join / Markup#join => escapes items and returns a Markup +// * Markup#replace => automatically escapes the replacements (difficult impl) +class _Markup extends String { + [escapeMethod]() { + return this; + } +} + +/** +* Returns a markup object, which acts like a String but is considered safe by +* `_.escape`, and will therefore be injected as-is (without additional +* escaping) in templates. Can be used to inject dynamic HTML in templates +* (where the template itself can't), see first example. +* +* Can also be used as a *template tag*, in which case the literal content +* won't be escaped but the substitutions which are not already markup objects +* will be. +* +* ## WARNINGS: +* * A markup object is a `String` (boxed) but not a `string` (primitive), they +* typecheck differently which can be relevant. +* * To strip out the "markupness", just call `String(markup)`. +* * Most string operations (e.g. concatenation, `String#replace`, ...) will +* also strip out markupness +* * If the input is empty, returns a regular string (that way boolean tests +* work as expected). +* +* @returns a markup object +* +* @example regular function +* let h; +* if (someTest) { +* h = Markup(_t("This is a success")); +* } else { +* h = Markup(_t("Things did not work out")); +* } +* qweb.render("some_template", { message: h }); +* +* @example template tag +* const escaped = " text"; +* const asis = Markup`some text`; +* const h = Markup`Regular strings get ${escaped} but markup is injected ${asis}`; +*/ +export function Markup(v, ...exprs) { + if (!(v instanceof Array)) { + return v ? new _Markup(v) : ''; + } + const elements = []; + let i = 0; + for(; i < exprs.length; ++i) { + elements.push(v[i], escape(exprs[i])); + } + elements.push(v[i]); + + const s = elements.join(''); + if (!s) { return '' } + return new _Markup(s); +} + diff --git a/tests/qweb/qweb.test.ts b/tests/qweb/qweb.test.ts index 84a9e1a4..8cc5b5f5 100644 --- a/tests/qweb/qweb.test.ts +++ b/tests/qweb/qweb.test.ts @@ -2,6 +2,7 @@ import { QWeb } from "../../src/qweb/index"; import { config } from "../../src/index"; import { nextTick, normalize, renderToDOM, renderToString, trim } from "../helpers"; import { patch } from "../../src/vdom"; +import { Markup } from "../../src/utils"; //------------------------------------------------------------------------------ // Setup and helpers @@ -246,7 +247,7 @@ describe("t-out (formerly t-raw tests)", () => { test("not escaping", () => { qweb.addTemplate("test", `
`); - expect(renderToString(qweb, "test", { var: "" })).toBe("
"); + expect(renderToString(qweb, "test", { var: Markup`` })).toBe("
"); }); test("t-raw and another sibling node", () => {