mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e73fb462c5 | |||
| 38c7ad9629 | |||
| d0c76c5854 | |||
| e032314739 | |||
| b2db7f21ed | |||
| 7b8ac13d3f | |||
| 06d852fcf9 | |||
| 7e4baf668a | |||
| fe34ba00a6 | |||
| e5e7790530 | |||
| 3bf91afc3f | |||
| 2529aa3ef2 | |||
| 8d25bddda4 | |||
| 81af21a025 | |||
| 9baea2c1cd | |||
| 8e03f9cd9c |
@@ -121,8 +121,8 @@ npm install @odoo/owl
|
||||
|
||||
If you want to use a simple `<script>` tag, the last release can be downloaded here:
|
||||
|
||||
- [owl-1.0.9.js](https://github.com/odoo/owl/releases/download/v1.0.9/owl.js)
|
||||
- [owl-1.0.9.min.js](https://github.com/odoo/owl/releases/download/v1.0.9/owl.min.js)
|
||||
- [owl-1.0.10.js](https://github.com/odoo/owl/releases/download/v1.0.10/owl.js)
|
||||
- [owl-1.0.10.min.js](https://github.com/odoo/owl/releases/download/v1.0.10/owl.min.js)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class ComponentB extends owl.Component {
|
||||
count: {type: Number},
|
||||
messages: {
|
||||
type: Array,
|
||||
element: {type: Object, shape: {id: Boolean, text: 'string' }
|
||||
element: {type: Object, shape: {id: Boolean, text: String }
|
||||
},
|
||||
date: Date,
|
||||
combinedVal: [Number, Boolean]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@odoo/owl",
|
||||
"version": "1.0.9",
|
||||
"version": "1.0.10",
|
||||
"description": "Odoo Web Library (OWL)",
|
||||
"main": "dist/owl.js",
|
||||
"types": "dist/types/index.d.ts",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# 🦉 OWL Roadmap 🦉
|
||||
|
||||
- Current version: 1.0.9
|
||||
- Current version: 1.0.10
|
||||
- Status: stable
|
||||
|
||||
This roadmap is only an attempt at predicting Owl's future. Everything may
|
||||
|
||||
@@ -496,9 +496,9 @@ export class Component<Props extends {} = any, T extends Env = Env> {
|
||||
}
|
||||
this.willUnmount();
|
||||
__owl__.isMounted = false;
|
||||
if (this.__owl__.currentFiber) {
|
||||
this.__owl__.currentFiber.isCompleted = true;
|
||||
this.__owl__.currentFiber.root.counter = 0;
|
||||
if (__owl__.currentFiber) {
|
||||
__owl__.currentFiber.isCompleted = true;
|
||||
__owl__.currentFiber.root.counter = 0;
|
||||
}
|
||||
const children = __owl__.children;
|
||||
for (let id in children) {
|
||||
@@ -656,9 +656,28 @@ export class Component<Props extends {} = any, T extends Env = Env> {
|
||||
// destroyed right now, because they are not in the DOM, and thus we won't
|
||||
// be notified later on (when patching), that they are removed from the DOM
|
||||
for (let childKey in __owl__.children) {
|
||||
let child = __owl__.children[childKey];
|
||||
if (!child.__owl__.isMounted && child.__owl__.parentLastFiberId < fiber.id) {
|
||||
child.destroy();
|
||||
const child = __owl__.children[childKey];
|
||||
const childOwl = child.__owl__;
|
||||
if (!childOwl.isMounted && childOwl.parentLastFiberId < fiber.id) {
|
||||
// we only do here a "soft" destroy, meaning that we leave the child
|
||||
// dom node alone, without removing it. Most of the time, it does not
|
||||
// matter, because the child component is already unmounted. However,
|
||||
// if some of its parent have been unmounted, the child could actually
|
||||
// still be attached to its parent, and this may be important if we
|
||||
// want to remount the parent, because the vdom need to match the
|
||||
// actual DOM
|
||||
child.__destroy(childOwl.parent);
|
||||
if (childOwl.pvnode) {
|
||||
// we remove the key here to make sure that the patching algorithm
|
||||
// is able to make the difference between this pvnode and an eventual
|
||||
// other instance of the same component
|
||||
delete childOwl.pvnode.key;
|
||||
// Since the component has been unmounted, we do not want to actually
|
||||
// call a remove hook. This is pretty important, since the t-component
|
||||
// directive actually disabled it, so the vdom algorithm will just
|
||||
// not remove the child elm if we don't remove the hook.
|
||||
delete childOwl.pvnode.data!.hook!.remove;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!vnode) {
|
||||
|
||||
@@ -238,12 +238,20 @@ export class Fiber {
|
||||
} else {
|
||||
if (fiber.shouldPatch) {
|
||||
component.__patch(component.__owl__.vnode!, fiber.vnode!);
|
||||
// When updating a Component's props (in directive),
|
||||
// the component has a pvnode AND should be patched.
|
||||
// However, its pvnode.elm may have changed if it is a High Order Component
|
||||
if (component.__owl__.pvnode) {
|
||||
component.__owl__.pvnode.elm = component.__owl__.vnode!.elm;
|
||||
}
|
||||
} else {
|
||||
component.__patch(document.createElement(fiber.vnode!.sel!), fiber.vnode!);
|
||||
component.__owl__.pvnode!.elm = component.__owl__.vnode!.elm;
|
||||
}
|
||||
}
|
||||
component.__owl__.currentFiber = null;
|
||||
if (fiber === component.__owl__.currentFiber) {
|
||||
component.__owl__.currentFiber = null;
|
||||
}
|
||||
}
|
||||
|
||||
// insert into the DOM (mount case)
|
||||
|
||||
@@ -37,7 +37,7 @@ QWeb.utils.validateProps = function (Widget, props: Object) {
|
||||
if (propsDef[propName] && !propsDef[propName].optional) {
|
||||
throw new Error(`Missing props '${propName}' (component '${Widget.name}')`);
|
||||
} else {
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let isValid;
|
||||
|
||||
@@ -25,7 +25,12 @@ export class Observer {
|
||||
notifyCB() {}
|
||||
|
||||
observe<T>(value: T, parent?: any): T {
|
||||
if (value === null || typeof value !== "object" || value instanceof Date) {
|
||||
if (
|
||||
value === null ||
|
||||
typeof value !== "object" ||
|
||||
value instanceof Date ||
|
||||
value instanceof Promise
|
||||
) {
|
||||
// fun fact: typeof null === 'object'
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -223,9 +223,6 @@ QWeb.addDirective({
|
||||
// ------------------------------------------------
|
||||
ctx.rootContext.shouldDefineScope = true;
|
||||
ctx.rootContext.shouldDefineUtils = true;
|
||||
if (node.nodeName !== "t") {
|
||||
throw new Error("Invalid tag for t-call directive (should be 't')");
|
||||
}
|
||||
const subTemplate = node.getAttribute("t-call")!;
|
||||
const nodeTemplate = qweb.templates[subTemplate];
|
||||
if (!nodeTemplate) {
|
||||
@@ -245,12 +242,11 @@ QWeb.addDirective({
|
||||
// Step 3: compile t-call body if necessary
|
||||
// ------------------------------------------------
|
||||
let hasBody = node.hasChildNodes();
|
||||
let protectID;
|
||||
const protectID = ctx.startProtectScope();
|
||||
if (hasBody) {
|
||||
// we add a sub scope to protect the ambient scope
|
||||
ctx.addLine(`{`);
|
||||
ctx.indent();
|
||||
protectID = ctx.startProtectScope();
|
||||
const nodeCopy = node.cloneNode(true) as Element;
|
||||
for (let attr of ["t-if", "t-else", "t-elif", "t-call"]) {
|
||||
nodeCopy.removeAttribute(attr);
|
||||
@@ -271,32 +267,27 @@ QWeb.addDirective({
|
||||
|
||||
// Step 4: add the appropriate function call to current component
|
||||
// ------------------------------------------------
|
||||
const callingScope = hasBody ? "scope" : "Object.assign(Object.create(context), scope)";
|
||||
const parentComponent = `utils.getComponent(context)`;
|
||||
const key = ctx.generateTemplateKey();
|
||||
const parentNode = ctx.parentNode ? `c${ctx.parentNode}` : "result";
|
||||
const extra = `Object.assign({}, extra, {parentNode: ${parentNode}, parent: ${parentComponent}, key: ${key}})`;
|
||||
if (ctx.parentNode) {
|
||||
ctx.addLine(
|
||||
`this.constructor.subTemplates['${subId}'].call(this, ${callingScope}, ${extra});`
|
||||
);
|
||||
ctx.addLine(`this.constructor.subTemplates['${subId}'].call(this, scope, ${extra});`);
|
||||
} else {
|
||||
// this is a t-call with no parentnode, we need to extract the result
|
||||
ctx.rootContext.shouldDefineResult = true;
|
||||
ctx.addLine(`result = []`);
|
||||
ctx.addLine(
|
||||
`this.constructor.subTemplates['${subId}'].call(this, ${callingScope}, ${extra});`
|
||||
);
|
||||
ctx.addLine(`this.constructor.subTemplates['${subId}'].call(this, scope, ${extra});`);
|
||||
ctx.addLine(`result = result[0]`);
|
||||
}
|
||||
|
||||
// Step 5: restore previous scope
|
||||
// ------------------------------------------------
|
||||
if (hasBody) {
|
||||
ctx.stopProtectScope(protectID);
|
||||
ctx.dedent();
|
||||
ctx.addLine(`}`);
|
||||
}
|
||||
ctx.stopProtectScope(protectID);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
+37
-8
@@ -262,6 +262,9 @@ QWeb.utils.toNumber = function (val: string): number | string {
|
||||
return isNaN(n) ? val : n;
|
||||
};
|
||||
|
||||
const hasDotAtTheEnd = /\.[\w_]+\s*$/;
|
||||
const hasBracketsAtTheEnd = /\[[^\[]+\]\s*$/;
|
||||
|
||||
QWeb.addDirective({
|
||||
name: "model",
|
||||
priority: 42,
|
||||
@@ -270,15 +273,41 @@ QWeb.addDirective({
|
||||
let handler;
|
||||
let event = fullName.includes(".lazy") ? "change" : "input";
|
||||
|
||||
// we keep here a reference to the "base expression" (if the expression
|
||||
// is `t-model="some.expr.value", then the base expression is "some.expr").
|
||||
// This is necessary so we can capture it in the handler closure.
|
||||
let expr = ctx.formatExpression(value);
|
||||
const index = expr.lastIndexOf(".");
|
||||
const baseExpr = expr.slice(0, index);
|
||||
ctx.addLine(`let expr${nodeID} = ${baseExpr};`);
|
||||
// First step: we need to understand the structure of the expression, and
|
||||
// from it, extract a base expression (that we can capture, which is
|
||||
// important because it will be used in a handler later) and a formatted
|
||||
// expression (which uses the captured base expression)
|
||||
//
|
||||
// Also, we support 2 kinds of values: some.expr.value or some.expr[value]
|
||||
// For the first one, we have:
|
||||
// - base expression = scope[some].expr
|
||||
// - expression = exprX.value (where exprX is the var that captures the base expr)
|
||||
// and for the expression with brackets:
|
||||
// - base expression = scope[some].expr
|
||||
// - expression = exprX[keyX] (where exprX is the var that captures the base expr
|
||||
// and keyX captures scope[value])
|
||||
let expr: string;
|
||||
let baseExpr: string;
|
||||
|
||||
if (hasDotAtTheEnd.test(value)) {
|
||||
// we manage the case where the expr has a dot: some.expr.value
|
||||
const index = value.lastIndexOf(".");
|
||||
baseExpr = value.slice(0, index);
|
||||
ctx.addLine(`let expr${nodeID} = ${ctx.formatExpression(baseExpr)};`);
|
||||
expr = `expr${nodeID}${value.slice(index)}`;
|
||||
} else if (hasBracketsAtTheEnd.test(value)) {
|
||||
// we manage here the case where the expr ends in a bracket expression:
|
||||
// some.expr[value]
|
||||
const index = value.lastIndexOf("[");
|
||||
baseExpr = value.slice(0, index);
|
||||
ctx.addLine(`let expr${nodeID} = ${ctx.formatExpression(baseExpr)};`);
|
||||
let exprKey = value.trimRight().slice(index + 1, -1);
|
||||
ctx.addLine(`let exprKey${nodeID} = ${ctx.formatExpression(exprKey)};`);
|
||||
expr = `expr${nodeID}[exprKey${nodeID}]`;
|
||||
} else {
|
||||
throw new Error(`Invalid t-model expression: "${value}" (it should be assignable)`);
|
||||
}
|
||||
|
||||
expr = `expr${nodeID}.${expr.slice(index + 1)}`;
|
||||
const key = ctx.generateTemplateKey();
|
||||
if (node.tagName === "select") {
|
||||
ctx.addLine(`p${nodeID}.props = {value: ${expr}};`);
|
||||
|
||||
+59
-37
@@ -66,8 +66,6 @@ interface QWebConfig {
|
||||
// Const/global stuff/helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DISABLED_TAGS = ["input", "textarea", "button", "select", "option", "optgroup"];
|
||||
|
||||
const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
|
||||
|
||||
const lineBreakRE = /[\r\n]/;
|
||||
@@ -86,10 +84,30 @@ interface Utils {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
function isComponent(obj) {
|
||||
function isComponent(obj): boolean {
|
||||
return obj && obj.hasOwnProperty("__owl__");
|
||||
}
|
||||
|
||||
class VDomArray extends Array {
|
||||
toString() {
|
||||
return vDomToString(this);
|
||||
}
|
||||
}
|
||||
|
||||
function vDomToString(vdom: VNode[]): string {
|
||||
return vdom
|
||||
.map((vnode) => {
|
||||
if (vnode.sel) {
|
||||
const node = document.createElement(vnode.sel);
|
||||
const result = patch(node, vnode);
|
||||
return (<HTMLElement>result.elm).outerHTML;
|
||||
} else {
|
||||
return vnode.text;
|
||||
}
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
const UTILS: Utils = {
|
||||
zero: Symbol("zero"),
|
||||
toObj(expr) {
|
||||
@@ -111,20 +129,8 @@ const UTILS: Utils = {
|
||||
addNameSpace(vnode) {
|
||||
addNS(vnode.data, vnode.children, vnode.sel);
|
||||
},
|
||||
VDomArray: class VDomArray extends Array {},
|
||||
vDomToString: function (vdom: VNode[]): string {
|
||||
return vdom
|
||||
.map((vnode) => {
|
||||
if (vnode.sel) {
|
||||
const node = document.createElement(vnode.sel);
|
||||
const result = patch(node, vnode);
|
||||
return (<HTMLElement>result.elm).outerHTML;
|
||||
} else {
|
||||
return vnode.text;
|
||||
}
|
||||
})
|
||||
.join("");
|
||||
},
|
||||
VDomArray,
|
||||
vDomToString,
|
||||
getComponent(obj) {
|
||||
while (obj && !isComponent(obj)) {
|
||||
obj = obj.__proto__;
|
||||
@@ -216,8 +222,8 @@ export class QWeb extends EventBus {
|
||||
// id, and a (global) mapping from an id to the compiled function. This is
|
||||
// necessary to ensure that global templates can be called with more than one
|
||||
// QWeb instance.
|
||||
subTemplates: {[key: string]: number} = {};
|
||||
static subTemplates: {[id: number]: Function} = {};
|
||||
subTemplates: { [key: string]: number } = {};
|
||||
static subTemplates: { [id: number]: Function } = {};
|
||||
|
||||
isUpdating: boolean = false;
|
||||
translateFn?: QWebConfig["translateFn"];
|
||||
@@ -509,10 +515,17 @@ export class QWeb extends EventBus {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.tagName !== "t" && node.hasAttribute("t-call")) {
|
||||
const tCallNode = document.createElement("t");
|
||||
tCallNode.setAttribute("t-call", node.getAttribute("t-call")!);
|
||||
node.removeAttribute("t-call");
|
||||
node.prepend(tCallNode);
|
||||
}
|
||||
|
||||
const firstLetter = node.tagName[0];
|
||||
if (firstLetter === firstLetter.toUpperCase()) {
|
||||
// this is a component, we modify in place the xml document to change
|
||||
// <SomeComponent ... /> to <t t-component="SomeComponent" ... />
|
||||
// <SomeComponent ... /> to <SomeComponent t-component="SomeComponent" ... />
|
||||
node.setAttribute("t-component", node.tagName);
|
||||
} else if (node.tagName !== "t" && node.hasAttribute("t-component")) {
|
||||
throw new Error(
|
||||
@@ -666,22 +679,31 @@ export class QWeb extends EventBus {
|
||||
const props: string[] = [];
|
||||
const tattrs: number[] = [];
|
||||
|
||||
function handleBooleanProps(key, val) {
|
||||
function handleProperties(key, val) {
|
||||
let isProp = false;
|
||||
if (node.nodeName === "input" && key === "checked") {
|
||||
let type = (<Element>node).getAttribute("type");
|
||||
if (type === "checkbox" || type === "radio") {
|
||||
isProp = true;
|
||||
}
|
||||
}
|
||||
if (node.nodeName === "option" && key === "selected") {
|
||||
isProp = true;
|
||||
}
|
||||
if (key === "disabled" && DISABLED_TAGS.indexOf(node.nodeName) > -1) {
|
||||
isProp = true;
|
||||
}
|
||||
if ((key === "readonly" && node.nodeName === "input") || node.nodeName === "textarea") {
|
||||
isProp = true;
|
||||
switch (node.nodeName) {
|
||||
case "input":
|
||||
let type = (<Element>node).getAttribute("type");
|
||||
if (type === "checkbox" || type === "radio") {
|
||||
if (key === "checked" || key === "indeterminate") {
|
||||
isProp = true;
|
||||
}
|
||||
}
|
||||
if (key === "value" || key === "readonly" || key === "disabled") {
|
||||
isProp = true;
|
||||
}
|
||||
break;
|
||||
case "option":
|
||||
isProp = key === "selected" || key === "disabled";
|
||||
break;
|
||||
case "textarea":
|
||||
isProp = key === "readonly" || key === "disabled";
|
||||
break;
|
||||
case "button":
|
||||
case "select":
|
||||
case "optgroup":
|
||||
isProp = key === "disabled";
|
||||
break;
|
||||
}
|
||||
if (isProp) {
|
||||
props.push(`${key}: _${val}`);
|
||||
@@ -720,7 +742,7 @@ export class QWeb extends EventBus {
|
||||
name = '"' + name + '"';
|
||||
}
|
||||
attrs.push(`${name}: _${attID}`);
|
||||
handleBooleanProps(name, attID);
|
||||
handleProperties(name, attID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -757,7 +779,7 @@ export class QWeb extends EventBus {
|
||||
}
|
||||
ctx.addLine(`let _${attID} = ${formattedValue};`);
|
||||
attrs.push(`${attName}: _${attID}`);
|
||||
handleBooleanProps(attName, attID);
|
||||
handleProperties(attName, attID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1253,12 +1253,16 @@ exports[`other directives with t-component t-set can't alter from within callee
|
||||
if (scope.iter != null) {
|
||||
c2.push({text: scope.iter});
|
||||
}
|
||||
this.constructor.subTemplates['2'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
let c5 = [], p5 = {key:5};
|
||||
let vn5 = h('p', p5, c5);
|
||||
c1.push(vn5);
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['2'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
scope = _origScope4;
|
||||
let c6 = [], p6 = {key:6};
|
||||
let vn6 = h('p', p6, c6);
|
||||
c1.push(vn6);
|
||||
if (scope.iter != null) {
|
||||
c5.push({text: scope.iter});
|
||||
c6.push({text: scope.iter});
|
||||
}
|
||||
return vn1;
|
||||
}"
|
||||
@@ -1280,18 +1284,18 @@ exports[`other directives with t-component t-set can't alter in t-call body 1`]
|
||||
if (scope.iter != null) {
|
||||
c2.push({text: scope.iter});
|
||||
}
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'iter').iter = 'inCall';
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['2'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
scope = _origScope4;
|
||||
}
|
||||
scope = _origScope4;
|
||||
let c6 = [], p6 = {key:6};
|
||||
let vn6 = h('p', p6, c6);
|
||||
c1.push(vn6);
|
||||
@@ -1401,6 +1405,47 @@ exports[`other directives with t-component t-set outside modified in t-foreach 1
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation t-set with a body expression can be used as textual prop 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"__template__2\\"
|
||||
let utils = this.constructor.utils;
|
||||
let QWeb = this.constructor;
|
||||
let parent = context;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let c2 = new utils.VDomArray();
|
||||
c2.push({text: \`42\`});
|
||||
scope.abc = c2
|
||||
// Component 'Child'
|
||||
let w3 = '__4__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__4__']] : false;
|
||||
let props3 = {val:scope.abc};
|
||||
if (w3 && w3.__owl__.currentFiber && !w3.__owl__.vnode) {
|
||||
w3.destroy();
|
||||
w3 = false;
|
||||
}
|
||||
if (w3) {
|
||||
w3.__updateProps(props3, extra.fiber, undefined);
|
||||
let pvnode = w3.__owl__.pvnode;
|
||||
c1.push(pvnode);
|
||||
} else {
|
||||
let componentKey3 = \`Child\`;
|
||||
let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| scope['Child'];
|
||||
if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')}
|
||||
w3 = new W3(parent, props3);
|
||||
parent.__owl__.cmap['__4__'] = w3.__owl__.id;
|
||||
let fiber = w3.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
|
||||
let pvnode = h('dummy', {key: '__4__', hook: {remove() {},destroy(vn) {w3.destroy();}}});
|
||||
c1.push(pvnode);
|
||||
w3.__owl__.pvnode = pvnode;
|
||||
}
|
||||
w3.__owl__.parentLastFiberId = extra.fiber.id;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`random stuff/miscellaneous can inject values in tagged templates 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -1410,7 +1455,11 @@ exports[`random stuff/miscellaneous can inject values in tagged templates 1`] =
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
this.constructor.subTemplates['3'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['3'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
scope = _origScope4;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1683,6 +1732,33 @@ exports[`t-model directive basic use, on an input 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-model directive basic use, on an input with bracket expression 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"__template__1\\"
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let c2 = [], p2 = {key:2,on:{}};
|
||||
let vn2 = h('input', p2, c2);
|
||||
c1.push(vn2);
|
||||
let expr2 = scope['state'];
|
||||
let exprKey2 = 'text';
|
||||
p2.props = {value: expr2[exprKey2]};
|
||||
extra.handlers['__3__'] = extra.handlers['__3__'] || ((ev) => {expr2[exprKey2] = ev.target.value});
|
||||
p2.on['input'] = extra.handlers['__3__'];
|
||||
let c4 = [], p4 = {key:4};
|
||||
let vn4 = h('span', p4, c4);
|
||||
c1.push(vn4);
|
||||
let _5 = scope['state'].text;
|
||||
if (_5 != null) {
|
||||
c4.push({text: _5});
|
||||
}
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-model directive basic use, on another key in component 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -1749,6 +1825,46 @@ exports[`t-model directive in a t-foreach 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-model directive in a t-foreach, part 2 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"__template__1\\"
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['state'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
}
|
||||
let _length3 = _3.length;
|
||||
let _origScope5 = scope;
|
||||
scope = Object.create(scope);
|
||||
for (let i1 = 0; i1 < _length3; i1++) {
|
||||
scope.thing_first = i1 === 0
|
||||
scope.thing_last = i1 === _length3 - 1
|
||||
scope.thing_index = i1
|
||||
scope.thing = _3[i1]
|
||||
scope.thing_value = _4[i1]
|
||||
let key1 = scope['thing_index'];
|
||||
let c6 = [], p6 = {key:\`\${key1}_6\`,on:{}};
|
||||
let vn6 = h('input', p6, c6);
|
||||
c1.push(vn6);
|
||||
let expr6 = scope['state'];
|
||||
let exprKey6 = scope['thing_index'];
|
||||
let k7 = \`__7__\${key1}__\`;
|
||||
p6.props = {value: expr6[exprKey6]};
|
||||
extra.handlers[k7] = extra.handlers[k7] || ((ev) => {expr6[exprKey6] = ev.target.value});
|
||||
p6.on['input'] = extra.handlers[k7];
|
||||
}
|
||||
scope = _origScope5;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-model directive on a select 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -1833,7 +1949,7 @@ exports[`t-model directive on an input type=radio 1`] = `
|
||||
let _2 = 'radio';
|
||||
let _3 = 'one';
|
||||
let _4 = 'One';
|
||||
let c5 = [], p5 = {key:5,attrs:{type: _2,id: _3,value: _4},on:{}};
|
||||
let c5 = [], p5 = {key:5,attrs:{type: _2,id: _3,value: _4},props:{value: _4},on:{}};
|
||||
let vn5 = h('input', p5, c5);
|
||||
c1.push(vn5);
|
||||
let expr5 = scope['state'];
|
||||
@@ -1843,7 +1959,7 @@ exports[`t-model directive on an input type=radio 1`] = `
|
||||
let _7 = 'radio';
|
||||
let _8 = 'two';
|
||||
let _9 = 'Two';
|
||||
let c10 = [], p10 = {key:10,attrs:{type: _7,id: _8,value: _9},on:{}};
|
||||
let c10 = [], p10 = {key:10,attrs:{type: _7,id: _8,value: _9},props:{value: _9},on:{}};
|
||||
let vn10 = h('input', p10, c10);
|
||||
c1.push(vn10);
|
||||
let expr10 = scope['state'];
|
||||
|
||||
@@ -1725,6 +1725,47 @@ describe("props evaluation ", () => {
|
||||
await widget.mount(fixture);
|
||||
expect(normalize(fixture.innerHTML)).toBe("<div><span>42</span></div>");
|
||||
});
|
||||
|
||||
test("t-set with a body expression can be used as textual prop", async () => {
|
||||
class Child extends Component {
|
||||
static template = xml`<span t-esc="props.val"/>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<t t-set="abc">42</t>
|
||||
<Child val="abc"/>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const widget = new Parent();
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span>42</span></div>");
|
||||
expect(env.qweb.templates[Parent.template].fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("t-set with a body expression can be passed in props, and then t-raw", async () => {
|
||||
class Child extends Component {
|
||||
static template = xml`
|
||||
<span>
|
||||
<t t-esc="props.val"/>
|
||||
<t t-raw="props.val"/>
|
||||
</span>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<t t-set="abc"><p>43</p></t>
|
||||
<Child val="abc"/>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const widget = new Parent();
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span><p>4343</p><p>43</p></span></div>");
|
||||
});
|
||||
});
|
||||
|
||||
describe("other directives with t-component", () => {
|
||||
@@ -3015,6 +3056,85 @@ describe("random stuff/miscellaneous", () => {
|
||||
expect(env.qweb.templates[Parent.template].fn.toString()).toMatchSnapshot();
|
||||
expect(fixture.innerHTML).toBe("<div><span>42</span></div>");
|
||||
});
|
||||
|
||||
test("update props of component without concrete own node", async () => {
|
||||
class Custom extends Component {
|
||||
static template = xml`
|
||||
<div class="widget-subkey">
|
||||
<t t-esc="props.key"/>__<t t-esc="props.subKey"/>
|
||||
</div>`;
|
||||
}
|
||||
class Child extends Component {
|
||||
static components = { Custom };
|
||||
static template = xml`
|
||||
<t t-component="Custom"
|
||||
t-key="props.subKey"
|
||||
key="props.key"
|
||||
subKey="props.subKey"/>`;
|
||||
}
|
||||
|
||||
class Parent extends Component {
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Child t-key="childProps.key" t-props="childProps"/>
|
||||
</div>`;
|
||||
childProps = {
|
||||
key: 1,
|
||||
subKey: 1,
|
||||
};
|
||||
}
|
||||
const parent = new Parent(null);
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.textContent!.trim()).toBe("1__1");
|
||||
|
||||
// First step: change the Custom's instance
|
||||
Object.assign(parent.childProps, {
|
||||
subKey: 2,
|
||||
});
|
||||
parent.render();
|
||||
await nextTick();
|
||||
expect(fixture.textContent!.trim()).toBe("1__2");
|
||||
|
||||
// Second step, change both Child's and Custom's instance
|
||||
Object.assign(parent.childProps, {
|
||||
key: 2,
|
||||
subKey: 3,
|
||||
});
|
||||
parent.render();
|
||||
await nextTick();
|
||||
expect(fixture.textContent!.trim()).toBe("2__3");
|
||||
});
|
||||
|
||||
test("two renderings initiated between willPatch and patched", async () => {
|
||||
let app;
|
||||
|
||||
class Panel extends Component {
|
||||
static template = xml`<abc><t t-esc="props.val"/></abc>`;
|
||||
mounted() {
|
||||
app.render();
|
||||
}
|
||||
willUnmount() {
|
||||
app.render();
|
||||
}
|
||||
}
|
||||
|
||||
// Main root component
|
||||
class App extends Component {
|
||||
static components = { Panel };
|
||||
static template = xml`<div><Panel t-key="'panel_' + state.panel" val="state.panel"/></div>`;
|
||||
|
||||
state = useState({ panel: "Panel1" });
|
||||
}
|
||||
|
||||
app = new App();
|
||||
await app.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div><abc>Panel1</abc></div>");
|
||||
app.state.panel = "Panel2";
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><abc>Panel2</abc></div>");
|
||||
});
|
||||
});
|
||||
|
||||
describe("widget and observable state", () => {
|
||||
@@ -3138,6 +3258,46 @@ describe("t-model directive", () => {
|
||||
expect(env.qweb.templates[SomeComponent.template].fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("basic use, on an input with bracket expression", async () => {
|
||||
class SomeComponent extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<input t-model="state['text']"/>
|
||||
<span><t t-esc="state.text"/></span>
|
||||
</div>`;
|
||||
state = useState({ text: "" });
|
||||
}
|
||||
const comp = new SomeComponent();
|
||||
await comp.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div><input><span></span></div>");
|
||||
|
||||
const input = fixture.querySelector("input")!;
|
||||
await editInput(input, "test");
|
||||
expect(comp.state.text).toBe("test");
|
||||
expect(fixture.innerHTML).toBe("<div><input><span>test</span></div>");
|
||||
expect(env.qweb.templates[SomeComponent.template].fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("throws if invalid expression", async () => {
|
||||
class SomeComponent extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<input t-model="state"/>
|
||||
</div>`;
|
||||
state = useState({ text: "" });
|
||||
}
|
||||
const comp = new SomeComponent();
|
||||
let error;
|
||||
try {
|
||||
await comp.mount(fixture);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
expect(error.message).toBe(`Invalid t-model expression: "state" (it should be assignable)`);
|
||||
});
|
||||
|
||||
test("basic use, on another key in component", async () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
@@ -3427,6 +3587,28 @@ describe("t-model directive", () => {
|
||||
expect(env.qweb.templates[SomeComponent.template].fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("in a t-foreach, part 2", async () => {
|
||||
class SomeComponent extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<t t-foreach="state" t-as="thing" t-key="thing_index" >
|
||||
<input t-model="state[thing_index]"/>
|
||||
</t>
|
||||
</div>
|
||||
`;
|
||||
state = useState(["zuko", "iroh"]);
|
||||
}
|
||||
const comp = new SomeComponent();
|
||||
await comp.mount(fixture);
|
||||
expect(comp.state).toEqual(["zuko", "iroh"]);
|
||||
|
||||
const input = fixture.querySelectorAll("input")[1]!;
|
||||
input.value = "uncle iroh";
|
||||
input.dispatchEvent(new Event("input"));
|
||||
expect(comp.state).toEqual(["zuko", "uncle iroh"]);
|
||||
expect(env.qweb.templates[SomeComponent.template].fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("two inputs in a div with a t-key", async () => {
|
||||
class SomeComponent extends Component {
|
||||
static template = xml`
|
||||
|
||||
@@ -786,6 +786,31 @@ describe("props validation", () => {
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><div>4</div></div>");
|
||||
});
|
||||
|
||||
test("mix of optional and mandatory", async () => {
|
||||
class Child extends Component {
|
||||
static props = {
|
||||
optional: { type: String, optional: true },
|
||||
mandatory: Number,
|
||||
};
|
||||
static template = xml` <div><t t-esc="props.mandatory"/></div>`;
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
static components = { Child };
|
||||
static template = xml`<div><Child/></div>`;
|
||||
}
|
||||
|
||||
const w = new App(undefined, {});
|
||||
let error;
|
||||
try {
|
||||
await w.mount(fixture);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
expect(error.message).toBe("Missing props 'mandatory' (component 'Child')");
|
||||
});
|
||||
});
|
||||
|
||||
describe("default props", () => {
|
||||
|
||||
@@ -929,4 +929,62 @@ describe("t-slot directive", () => {
|
||||
expect(fixture.innerHTML).toBe("<div><span>dash</span></div>");
|
||||
expect(env.qweb.templates[Dialog.template].fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("slot and t-esc", async () => {
|
||||
class Dialog extends Component {
|
||||
static template = xml`<span><t t-slot="default"/></span>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static template = xml`<div><Dialog><t t-esc="'toph'"/></Dialog></div>`;
|
||||
static components = { Dialog };
|
||||
}
|
||||
const parent = new Parent();
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div><span>toph</span></div>");
|
||||
});
|
||||
|
||||
test("slot and (inline) t-esc", async () => {
|
||||
class Dialog extends Component {
|
||||
static template = xml`<span><t t-slot="default"/></span>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static template = xml`<div><Dialog t-esc="'toph'"/></div>`;
|
||||
static components = { Dialog };
|
||||
}
|
||||
const parent = new Parent();
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div><span>toph</span></div>");
|
||||
});
|
||||
|
||||
test("slot and t-call", async () => {
|
||||
env.qweb.addTemplate("sokka", "<p>sokka</p>");
|
||||
class Dialog extends Component {
|
||||
static template = xml`<span><t t-slot="default"/></span>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static template = xml`<div><Dialog><t t-call="sokka"/></Dialog></div>`;
|
||||
static components = { Dialog };
|
||||
}
|
||||
const parent = new Parent();
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div><span><p>sokka</p></span></div>");
|
||||
});
|
||||
|
||||
test("slot and (inline) t-call", async () => {
|
||||
env.qweb.addTemplate("sokka", "<p>sokka</p>");
|
||||
class Dialog extends Component {
|
||||
static template = xml`<span><t t-slot="default"/></span>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static template = xml`<div><Dialog t-call="sokka"/></div>`;
|
||||
static components = { Dialog };
|
||||
}
|
||||
const parent = new Parent();
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div><span><p>sokka</p></span></div>");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -509,4 +509,103 @@ describe("unmounting and remounting", () => {
|
||||
expect(error).toBeDefined();
|
||||
expect(error.message).toBe("Cannot mount a destroyed component");
|
||||
});
|
||||
|
||||
test("destroying a sub-component cleans itself from parent's vnode", async () => {
|
||||
class C1 extends Component {
|
||||
static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
}
|
||||
class P extends Component {
|
||||
static components = { C1 };
|
||||
static template = xml`<div><div><C1 t-props="state" t-if="state.a"/></div></div>`;
|
||||
state = {
|
||||
a: "first",
|
||||
};
|
||||
}
|
||||
const parent = new P();
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.textContent).toBe("first");
|
||||
parent.unmount();
|
||||
parent.state.a = "";
|
||||
parent.mount(fixture);
|
||||
parent.state.a = "fixed";
|
||||
await parent.render();
|
||||
expect(fixture.textContent).toBe("fixed");
|
||||
});
|
||||
|
||||
test("destroying a sub-component cleans itself from parent's vnode, part 2", async () => {
|
||||
class C1 extends Component {
|
||||
static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
}
|
||||
class P extends Component {
|
||||
static components = { C1 };
|
||||
static template = xml`<div><div><C1 t-props="state" t-if="state.a"/>some text</div></div>`;
|
||||
state = {
|
||||
a: "first",
|
||||
};
|
||||
}
|
||||
const parent = new P();
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.textContent).toBe("firstsome text");
|
||||
parent.unmount();
|
||||
parent.state.a = "";
|
||||
parent.mount(fixture);
|
||||
parent.state.a = "fixed";
|
||||
await parent.render();
|
||||
expect(fixture.textContent).toBe("fixedsome text");
|
||||
});
|
||||
|
||||
test("destroying a sub-component cleans itself from parent's vnode, part 3", async () => {
|
||||
class C1 extends Component {
|
||||
static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
}
|
||||
|
||||
class C2 extends Component {
|
||||
static template = xml`<C1 a="props.a"/>`;
|
||||
static components = { C1 };
|
||||
}
|
||||
|
||||
class P extends Component {
|
||||
static components = { C2 };
|
||||
static template = xml`<div><div><C2 t-props="state" t-if="state.a"/></div></div>`;
|
||||
state = {
|
||||
a: "first",
|
||||
};
|
||||
}
|
||||
const parent = new P();
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.textContent).toBe("first");
|
||||
parent.unmount();
|
||||
parent.state.a = "";
|
||||
parent.mount(fixture);
|
||||
parent.state.a = "fixed";
|
||||
await parent.render();
|
||||
expect(fixture.textContent).toBe("fixed");
|
||||
});
|
||||
|
||||
test("destroying a sub-component cleans itself from parent's vnode, part 4", async () => {
|
||||
class C1 extends Component {
|
||||
static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
}
|
||||
|
||||
class C2 extends Component {
|
||||
static template = xml`<C1 a="props.a"/>`;
|
||||
static components = { C1 };
|
||||
}
|
||||
class P extends Component {
|
||||
static components = { C2 };
|
||||
static template = xml`<div><div><C2 t-props="state" t-if="state.a"/>some text</div></div>`;
|
||||
state = {
|
||||
a: "first",
|
||||
};
|
||||
}
|
||||
const parent = new P();
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.textContent).toBe("firstsome text");
|
||||
parent.unmount();
|
||||
parent.state.a = "";
|
||||
parent.mount(fixture);
|
||||
parent.state.a = "fixed";
|
||||
await parent.render();
|
||||
expect(fixture.textContent).toBe("fixedsome text");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -68,6 +68,23 @@ describe("observer", () => {
|
||||
expect(obj.date).not.toBe(date);
|
||||
});
|
||||
|
||||
test("properly handle promises (i.e.: treat them like primitive values", async () => {
|
||||
const observer = new Observer();
|
||||
let resolved = false;
|
||||
const prom = new Promise((r) => r());
|
||||
const obj: any = observer.observe({ prom });
|
||||
expect(obj.prom).toBeInstanceOf(Promise);
|
||||
|
||||
obj.prom.then(() => (resolved = true));
|
||||
|
||||
expect(observer.revNumber(obj)).toBe(1);
|
||||
|
||||
expect(resolved).toBe(false);
|
||||
await Promise.resolve();
|
||||
expect(resolved).toBe(true);
|
||||
expect(observer.revNumber(obj)).toBe(1);
|
||||
});
|
||||
|
||||
test("can change values in array", () => {
|
||||
const observer = new Observer();
|
||||
const obj: any = observer.observe({ arr: [1, 2] });
|
||||
|
||||
+2
-9
@@ -8,12 +8,6 @@ import "../src/qweb/extensions";
|
||||
import "../src/component/directive";
|
||||
import { browser } from "../src/browser";
|
||||
|
||||
// modifies scheduler to make it faster to test components
|
||||
scheduler.requestAnimationFrame = function (callback: FrameRequestCallback) {
|
||||
setTimeout(callback, 1);
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Some static cleanup
|
||||
let nextSlotId;
|
||||
let slots;
|
||||
@@ -43,9 +37,8 @@ export function nextMicroTick(): Promise<void> {
|
||||
}
|
||||
|
||||
export async function nextTick(): Promise<void> {
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(() => scheduler.requestAnimationFrame(() => resolve()));
|
||||
});
|
||||
await new Promise((resolve) => scheduler.requestAnimationFrame(resolve));
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
}
|
||||
|
||||
export function makeTestFixture() {
|
||||
|
||||
@@ -630,6 +630,177 @@ exports[`foreach iterate, position 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`foreach t-call with body in t-foreach in t-foreach 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"test\\"
|
||||
let utils = this.constructor.utils;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['numbers'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
}
|
||||
let _length3 = _3.length;
|
||||
let _origScope5 = scope;
|
||||
scope = Object.create(scope);
|
||||
for (let i1 = 0; i1 < _length3; i1++) {
|
||||
scope.a_first = i1 === 0
|
||||
scope.a_last = i1 === _length3 - 1
|
||||
scope.a_index = i1
|
||||
scope.a = _3[i1]
|
||||
scope.a_value = _4[i1]
|
||||
let key1 = i1;
|
||||
let _6 = scope['letters'];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
}
|
||||
let _length7 = _7.length;
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
for (let i2 = 0; i2 < _length7; i2++) {
|
||||
scope.b_first = i2 === 0
|
||||
scope.b_last = i2 === _length7 - 1
|
||||
scope.b_index = i2
|
||||
scope.b = _7[i2]
|
||||
scope.b_value = _8[i2]
|
||||
let key2 = i2;
|
||||
let _origScope13 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'c').c = 'x'+'_'+scope['a']+'_'+scope['b'];
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
let k14 = \`__14__\${key1}__\${key2}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: k14}));
|
||||
}
|
||||
scope = _origScope13;
|
||||
}
|
||||
scope = _origScope9;
|
||||
let c15 = [], p15 = {key:\`\${key1}_15\`};
|
||||
let vn15 = h('span', p15, c15);
|
||||
c1.push(vn15);
|
||||
if (scope.c != null) {
|
||||
c15.push({text: scope.c});
|
||||
}
|
||||
}
|
||||
scope = _origScope5;
|
||||
let c16 = [], p16 = {key:16};
|
||||
let vn16 = h('span', p16, c16);
|
||||
c1.push(vn16);
|
||||
c16.push({text: \`[\`});
|
||||
let _17 = scope['a'];
|
||||
if (_17 != null) {
|
||||
c16.push({text: _17});
|
||||
}
|
||||
c16.push({text: \`][\`});
|
||||
let _18 = scope['b'];
|
||||
if (_18 != null) {
|
||||
c16.push({text: _18});
|
||||
}
|
||||
c16.push({text: \`][\`});
|
||||
if (scope.c != null) {
|
||||
c16.push({text: scope.c});
|
||||
}
|
||||
c16.push({text: \`]\`});
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`foreach t-call without body in t-foreach in t-foreach 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"test\\"
|
||||
let utils = this.constructor.utils;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['numbers'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
}
|
||||
let _length3 = _3.length;
|
||||
let _origScope5 = scope;
|
||||
scope = Object.create(scope);
|
||||
for (let i1 = 0; i1 < _length3; i1++) {
|
||||
scope.a_first = i1 === 0
|
||||
scope.a_last = i1 === _length3 - 1
|
||||
scope.a_index = i1
|
||||
scope.a = _3[i1]
|
||||
scope.a_value = _4[i1]
|
||||
let key1 = i1;
|
||||
let _6 = scope['letters'];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
}
|
||||
let _length7 = _7.length;
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
for (let i2 = 0; i2 < _length7; i2++) {
|
||||
scope.b_first = i2 === 0
|
||||
scope.b_last = i2 === _length7 - 1
|
||||
scope.b_index = i2
|
||||
scope.b = _7[i2]
|
||||
scope.b_value = _8[i2]
|
||||
let key2 = i2;
|
||||
let _origScope12 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
let k13 = \`__13__\${key1}__\${key2}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: k13}));
|
||||
scope = _origScope12;
|
||||
}
|
||||
scope = _origScope9;
|
||||
let c14 = [], p14 = {key:\`\${key1}_14\`};
|
||||
let vn14 = h('span', p14, c14);
|
||||
c1.push(vn14);
|
||||
let _15 = scope['c'];
|
||||
if (_15 != null) {
|
||||
c14.push({text: _15});
|
||||
}
|
||||
}
|
||||
scope = _origScope5;
|
||||
let c16 = [], p16 = {key:16};
|
||||
let vn16 = h('span', p16, c16);
|
||||
c1.push(vn16);
|
||||
c16.push({text: \`[\`});
|
||||
let _17 = scope['a'];
|
||||
if (_17 != null) {
|
||||
c16.push({text: _17});
|
||||
}
|
||||
c16.push({text: \`][\`});
|
||||
let _18 = scope['b'];
|
||||
if (_18 != null) {
|
||||
c16.push({text: _18});
|
||||
}
|
||||
c16.push({text: \`][\`});
|
||||
let _19 = scope['c'];
|
||||
if (_19 != null) {
|
||||
c16.push({text: _19});
|
||||
}
|
||||
c16.push({text: \`]\`});
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`foreach t-foreach in t-forach 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -749,7 +920,11 @@ exports[`loading templates can load a few templates from a xml string 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('ul', p1, c1);
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
scope = _origScope4;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -787,16 +962,16 @@ exports[`misc global 1`] = `
|
||||
if (_7 != null) {
|
||||
c6.push({text: _7});
|
||||
}
|
||||
let _origScope10 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope10 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
let _origScope13 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope13 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'foo').foo = 'aaa';
|
||||
@@ -804,22 +979,34 @@ exports[`misc global 1`] = `
|
||||
}
|
||||
let k14 = \`__14__\${key1}__\`;
|
||||
this.constructor.subTemplates['2'].call(this, scope, Object.assign({}, extra, {parentNode: c__0, parent: utils.getComponent(context), key: k14}));
|
||||
scope = _origScope13;
|
||||
}
|
||||
let k15 = \`__15__\${key1}__\`;
|
||||
this.constructor.subTemplates['2'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c__0, parent: utils.getComponent(context), key: k15}));
|
||||
utils.getScope(scope, 'foo').foo = 'bbb';
|
||||
scope = _origScope13;
|
||||
let _origScope15 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
let k16 = \`__16__\${key1}__\`;
|
||||
this.constructor.subTemplates['2'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c__0, parent: utils.getComponent(context), key: k16}));
|
||||
this.constructor.subTemplates['2'].call(this, scope, Object.assign({}, extra, {parentNode: c__0, parent: utils.getComponent(context), key: k16}));
|
||||
scope = _origScope15;
|
||||
utils.getScope(scope, 'foo').foo = 'bbb';
|
||||
let _origScope17 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
let k18 = \`__18__\${key1}__\`;
|
||||
this.constructor.subTemplates['2'].call(this, scope, Object.assign({}, extra, {parentNode: c__0, parent: utils.getComponent(context), key: k18}));
|
||||
scope = _origScope17;
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
let k17 = \`__17__\${key1}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: k17}));
|
||||
scope = _origScope10;
|
||||
let k19 = \`__19__\${key1}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: k19}));
|
||||
}
|
||||
scope = _origScope10;
|
||||
}
|
||||
scope = _origScope5;
|
||||
this.constructor.subTemplates['3'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__20__'}));
|
||||
let _origScope22 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['3'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__23__'}));
|
||||
scope = _origScope22;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -872,7 +1059,7 @@ exports[`properly support svg add proper namespace to svg 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`special cases for some boolean html attributes/properties input type= checkbox, with t-att-checked 1`] = `
|
||||
exports[`special cases for some specific html attributes/properties input type= checkbox, with t-att-checked 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"test\\"
|
||||
@@ -886,7 +1073,7 @@ exports[`special cases for some boolean html attributes/properties input type= c
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`special cases for some boolean html attributes/properties various boolean html attributes 1`] = `
|
||||
exports[`special cases for some specific html attributes/properties various boolean html attributes 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"test\\"
|
||||
@@ -1108,7 +1295,11 @@ exports[`t-call (template calling basic caller 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1121,9 +1312,13 @@ exports[`t-call (template calling basic caller, no parent node 1`] = `
|
||||
let scope = Object.create(context);
|
||||
let result;
|
||||
let h = this.h;
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
result = []
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: result, parent: utils.getComponent(context), key: '__3__'}));
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: result, parent: utils.getComponent(context), key: '__4__'}));
|
||||
result = result[0]
|
||||
scope = _origScope3;
|
||||
return result;
|
||||
}"
|
||||
`;
|
||||
@@ -1137,10 +1332,10 @@ exports[`t-call (template calling call with several sub nodes on same line 1`] =
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
let c4 = [], p4 = {key:4};
|
||||
@@ -1155,8 +1350,8 @@ exports[`t-call (template calling call with several sub nodes on same line 1`] =
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__6__'}));
|
||||
scope = _origScope3;
|
||||
}
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1172,10 +1367,10 @@ exports[`t-call (template calling cascading t-call t-raw='0' 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope12 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope12 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
let c13 = [], p13 = {key:13};
|
||||
@@ -1190,8 +1385,8 @@ exports[`t-call (template calling cascading t-call t-raw='0' 1`] = `
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__15__'}));
|
||||
scope = _origScope12;
|
||||
}
|
||||
scope = _origScope12;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1206,7 +1401,11 @@ exports[`t-call (template calling inherit context 1`] = `
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
scope.foo = 1;
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__2__'}));
|
||||
let _origScope2 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
scope = _origScope2;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1225,7 +1424,11 @@ exports[`t-call (template calling recursive template, part 1 1`] = `
|
||||
c1.push(vn2);
|
||||
c2.push({text: \`hey\`});
|
||||
if (false) {
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__6__'}));
|
||||
let _origScope7 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__8__'}));
|
||||
scope = _origScope7;
|
||||
}
|
||||
return vn1;
|
||||
}"
|
||||
@@ -1248,8 +1451,12 @@ exports[`t-call (template calling recursive template, part 1 2`] = `
|
||||
c3.push(vn4);
|
||||
c4.push({text: \`hey\`});
|
||||
if (false) {
|
||||
let k5 = \`__5__\${key0}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c3, parent: utils.getComponent(context), key: k5}));
|
||||
let _origScope5 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
let k6 = \`__6__\${key0}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c3, parent: utils.getComponent(context), key: k6}));
|
||||
scope = _origScope5;
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -1263,18 +1470,18 @@ exports[`t-call (template calling recursive template, part 2 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope11 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope11 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'node').node = scope['root'];
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__12__'}));
|
||||
scope = _origScope11;
|
||||
}
|
||||
scope = _origScope11;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1315,10 +1522,10 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
|
||||
scope.subtree = _6[i1]
|
||||
scope.subtree_value = _7[i1]
|
||||
let key1 = i1;
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'node').node = scope['subtree'];
|
||||
@@ -1326,8 +1533,8 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
|
||||
}
|
||||
let k10 = \`__10__\${key0}__\${key1}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c2, parent: utils.getComponent(context), key: k10}));
|
||||
scope = _origScope9;
|
||||
}
|
||||
scope = _origScope9;
|
||||
}
|
||||
scope = _origScope8;
|
||||
}"
|
||||
@@ -1342,18 +1549,18 @@ exports[`t-call (template calling recursive template, part 3 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope11 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope11 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'node').node = scope['root'];
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__12__'}));
|
||||
scope = _origScope11;
|
||||
}
|
||||
scope = _origScope11;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1394,10 +1601,10 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
|
||||
scope.subtree = _6[i1]
|
||||
scope.subtree_value = _7[i1]
|
||||
let key1 = i1;
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'node').node = scope['subtree'];
|
||||
@@ -1405,8 +1612,8 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
|
||||
}
|
||||
let k10 = \`__10__\${key0}__\${key1}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c2, parent: utils.getComponent(context), key: k10}));
|
||||
scope = _origScope9;
|
||||
}
|
||||
scope = _origScope9;
|
||||
}
|
||||
scope = _origScope8;
|
||||
}"
|
||||
@@ -1421,10 +1628,10 @@ exports[`t-call (template calling recursive template, part 4: with t-set recursi
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope11 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope11 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'recursive_idx').recursive_idx = 1;
|
||||
@@ -1432,8 +1639,8 @@ exports[`t-call (template calling recursive template, part 4: with t-set recursi
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__12__'}));
|
||||
scope = _origScope11;
|
||||
}
|
||||
scope = _origScope11;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1479,10 +1686,10 @@ exports[`t-call (template calling recursive template, part 4: with t-set recursi
|
||||
scope.subtree = _6[i1]
|
||||
scope.subtree_value = _7[i1]
|
||||
let key1 = i1;
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope9 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'node').node = scope['subtree'];
|
||||
@@ -1490,8 +1697,8 @@ exports[`t-call (template calling recursive template, part 4: with t-set recursi
|
||||
}
|
||||
let k10 = \`__10__\${key0}__\${key1}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c2, parent: utils.getComponent(context), key: k10}));
|
||||
scope = _origScope9;
|
||||
}
|
||||
scope = _origScope9;
|
||||
}
|
||||
scope = _origScope8;
|
||||
}"
|
||||
@@ -1506,18 +1713,18 @@ exports[`t-call (template calling scoped parameters 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope2 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope2 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'foo').foo = 42;
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
scope = _origScope2;
|
||||
}
|
||||
scope = _origScope2;
|
||||
if (scope.foo != null) {
|
||||
c1.push({text: scope.foo});
|
||||
}
|
||||
@@ -1525,6 +1732,24 @@ exports[`t-call (template calling scoped parameters 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-call (template calling t-call allowed on a non t node 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"caller\\"
|
||||
let utils = this.constructor.utils;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-call (template calling t-call with t-if 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -1535,12 +1760,43 @@ exports[`t-call (template calling t-call with t-if 1`] = `
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
if (scope['flag']) {
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
}
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-call (template calling t-call with t-set inside and body text content 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"main\\"
|
||||
let utils = this.constructor.utils;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
{
|
||||
let c__0 = [];
|
||||
let c5 = new utils.VDomArray();
|
||||
c5.push({text: \`yip yip\`});
|
||||
scope.val = c5
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__6__'}));
|
||||
}
|
||||
scope = _origScope4;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -1568,10 +1824,10 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
|
||||
scope.v_value = _4[i1]
|
||||
let key1 = i1;
|
||||
utils.getScope(scope, 'val').val = scope['v'].val;
|
||||
let _origScope8 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope8 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'val3').val3 = scope.val*3;
|
||||
@@ -1579,8 +1835,8 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
|
||||
}
|
||||
let k9 = \`__9__\${key1}__\`;
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: k9}));
|
||||
scope = _origScope8;
|
||||
}
|
||||
scope = _origScope8;
|
||||
}
|
||||
scope = _origScope5;
|
||||
return vn1;
|
||||
@@ -1597,7 +1853,11 @@ exports[`t-call (template calling t-call with t-set inside and outside. 2 1`] =
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('p', p1, c1);
|
||||
scope.w = 'fromwrapper';
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__11__'}));
|
||||
let _origScope11 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__12__'}));
|
||||
scope = _origScope11;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1613,21 +1873,25 @@ exports[`t-call (template calling t-call, conditional and t-set in t-call body 1
|
||||
let vn1 = h('div', p1, c1);
|
||||
scope.v1 = 'elif';
|
||||
if (scope.v1==='if') {
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
}
|
||||
else if (scope.v1==='elif') {
|
||||
let _origScope7 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope6 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'v').v = 'success';
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['2'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__7__'}));
|
||||
scope = _origScope6;
|
||||
this.constructor.subTemplates['2'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__8__'}));
|
||||
}
|
||||
scope = _origScope7;
|
||||
}
|
||||
return vn1;
|
||||
}"
|
||||
@@ -1642,7 +1906,11 @@ exports[`t-call (template calling t-call, global templates 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1656,7 +1924,11 @@ exports[`t-call (template calling two different QWeb instances, and shared templ
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1670,7 +1942,11 @@ exports[`t-call (template calling two different QWeb instances, and shared templ
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__3__'}));
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1683,10 +1959,10 @@ exports[`t-call (template calling with unused body 1`] = `
|
||||
let scope = Object.create(context);
|
||||
let result;
|
||||
let h = this.h;
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
c__0.push({text: \`WHEEE\`});
|
||||
@@ -1695,8 +1971,8 @@ exports[`t-call (template calling with unused body 1`] = `
|
||||
result = []
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: result, parent: utils.getComponent(context), key: '__4__'}));
|
||||
result = result[0]
|
||||
scope = _origScope3;
|
||||
}
|
||||
scope = _origScope3;
|
||||
return result;
|
||||
}"
|
||||
`;
|
||||
@@ -1709,10 +1985,10 @@ exports[`t-call (template calling with unused setbody 1`] = `
|
||||
let scope = Object.create(context);
|
||||
let result;
|
||||
let h = this.h;
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'qux').qux = 3;
|
||||
@@ -1721,8 +1997,8 @@ exports[`t-call (template calling with unused setbody 1`] = `
|
||||
result = []
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: result, parent: utils.getComponent(context), key: '__4__'}));
|
||||
result = result[0]
|
||||
scope = _origScope3;
|
||||
}
|
||||
scope = _origScope3;
|
||||
return result;
|
||||
}"
|
||||
`;
|
||||
@@ -1735,10 +2011,10 @@ exports[`t-call (template calling with used body 1`] = `
|
||||
let scope = Object.create(context);
|
||||
let result;
|
||||
let h = this.h;
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
c__0.push({text: \`ok\`});
|
||||
@@ -1747,8 +2023,8 @@ exports[`t-call (template calling with used body 1`] = `
|
||||
result = []
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: result, parent: utils.getComponent(context), key: '__4__'}));
|
||||
result = result[0]
|
||||
scope = _origScope3;
|
||||
}
|
||||
scope = _origScope3;
|
||||
return result;
|
||||
}"
|
||||
`;
|
||||
@@ -1762,18 +2038,18 @@ exports[`t-call (template calling with used set body 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('span', p1, c1);
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
utils.getScope(scope, 'foo').foo = 'ok';
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
scope = _origScope3;
|
||||
}
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1921,7 +2197,11 @@ exports[`t-esc t-esc inside t-call, with t-set outside 1`] = `
|
||||
let c2 = new utils.VDomArray();
|
||||
c2.push({text: \`Hi\`});
|
||||
scope.v = c2
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
let _origScope5 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__6__'}));
|
||||
scope = _origScope5;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1978,10 +2258,10 @@ exports[`t-esc t-esc=0 is escaped 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let _origScope3 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
{
|
||||
let c__0 = [];
|
||||
let c4 = [], p4 = {key:4};
|
||||
@@ -1991,8 +2271,8 @@ exports[`t-esc t-esc=0 is escaped 1`] = `
|
||||
scope[utils.zero] = c__0;
|
||||
}
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
scope = _origScope3;
|
||||
}
|
||||
scope = _origScope3;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -2786,7 +3066,11 @@ exports[`t-on t-on with t-call 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
scope = _origScope4;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -2800,7 +3084,11 @@ exports[`t-on t-on, with arguments and t-call 1`] = `
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
this.constructor.subTemplates['1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__4__'}));
|
||||
let _origScope4 = scope;
|
||||
scope = Object.create(scope);
|
||||
scope.__access_mode__ = 'ro';
|
||||
this.constructor.subTemplates['1'].call(this, scope, Object.assign({}, extra, {parentNode: c1, parent: utils.getComponent(context), key: '__5__'}));
|
||||
scope = _origScope4;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
+104
-4
@@ -766,10 +766,11 @@ describe("t-call (template calling", () => {
|
||||
expect(qweb.subTemplates["sub"]).toBeTruthy();
|
||||
});
|
||||
|
||||
test("t-call not allowed on a non t node", () => {
|
||||
qweb.addTemplate("_basic-callee", "<t>ok</t>");
|
||||
test("t-call allowed on a non t node", () => {
|
||||
qweb.addTemplate("_basic-callee", "<span>ok</span>");
|
||||
qweb.addTemplate("caller", '<div t-call="_basic-callee"/>');
|
||||
expect(() => renderToString(qweb, "caller")).toThrow("Invalid tag");
|
||||
const expected = "<div><span>ok</span></div>";
|
||||
expect(renderToString(qweb, "caller")).toBe(expected);
|
||||
});
|
||||
|
||||
test("with unused body", () => {
|
||||
@@ -1072,6 +1073,21 @@ describe("t-call (template calling", () => {
|
||||
expect(renderToString(qweb1, "main")).toBe("<div><span>ok</span></div>");
|
||||
expect(renderToString(qweb2, "main")).toBe("<div><span>ok</span></div>");
|
||||
});
|
||||
|
||||
test("t-call with t-set inside and body text content", () => {
|
||||
qweb.addTemplate("sub", `<p><t t-esc="val"/></p>`);
|
||||
qweb.addTemplate(
|
||||
"main",
|
||||
`
|
||||
<div>
|
||||
<t t-call="sub">
|
||||
<t t-set="val">yip yip</t>
|
||||
</t>
|
||||
</div>`
|
||||
);
|
||||
const expected = "<div><p>yip yip</p></div>";
|
||||
expect(renderToString(qweb, "main")).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("foreach", () => {
|
||||
@@ -1162,6 +1178,63 @@ describe("foreach", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("t-call without body in t-foreach in t-foreach", () => {
|
||||
qweb.addTemplate(
|
||||
"test_called",
|
||||
`<t>
|
||||
<t t-set="c" t-value="'x' + '_' + a + '_'+ b" />
|
||||
[<t t-esc="a" />]
|
||||
[<t t-esc="b" />]
|
||||
[<t t-esc="c" />]
|
||||
</t>`
|
||||
);
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div>
|
||||
<t t-foreach="numbers" t-as="a">
|
||||
<t t-foreach="letters" t-as="b">
|
||||
<t t-call="test_called" />
|
||||
</t>
|
||||
<span t-esc="c"/>
|
||||
</t>
|
||||
<span>[<t t-esc="a" />][<t t-esc="b" />][<t t-esc="c" />]</span>
|
||||
</div>`
|
||||
);
|
||||
const context = { numbers: [1, 2, 3], letters: ["a", "b"] };
|
||||
expect(renderToString(qweb, "test", context)).toBe(
|
||||
"<div> [1] [a] [x_1_a] [1] [b] [x_1_b] <span></span> [2] [a] [x_2_a] [2] [b] [x_2_b] <span></span> [3] [a] [x_3_a] [3] [b] [x_3_b] <span></span><span>[][][]</span></div>"
|
||||
);
|
||||
});
|
||||
|
||||
test("t-call with body in t-foreach in t-foreach", () => {
|
||||
qweb.addTemplate(
|
||||
"test_called",
|
||||
`<t>
|
||||
[<t t-esc="a" />]
|
||||
[<t t-esc="b" />]
|
||||
[<t t-esc="c" />]
|
||||
</t>`
|
||||
);
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div>
|
||||
<t t-foreach="numbers" t-as="a">
|
||||
<t t-foreach="letters" t-as="b">
|
||||
<t t-call="test_called" >
|
||||
<t t-set="c" t-value="'x' + '_' + a + '_'+ b" />
|
||||
</t>
|
||||
</t>
|
||||
<span t-esc="c"/>
|
||||
</t>
|
||||
<span>[<t t-esc="a" />][<t t-esc="b" />][<t t-esc="c" />]</span>
|
||||
</div>`
|
||||
);
|
||||
const context = { numbers: [1, 2, 3], letters: ["a", "b"] };
|
||||
expect(renderToString(qweb, "test", context)).toBe(
|
||||
"<div> [1] [a] [x_1_a] [1] [b] [x_1_b] <span></span> [2] [a] [x_2_a] [2] [b] [x_2_b] <span></span> [3] [a] [x_3_a] [3] [b] [x_3_b] <span></span><span>[][][]</span></div>"
|
||||
);
|
||||
});
|
||||
|
||||
test("throws error if invalid loop expression", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
@@ -1777,7 +1850,7 @@ describe("loading templates", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("special cases for some boolean html attributes/properties", () => {
|
||||
describe("special cases for some specific html attributes/properties", () => {
|
||||
test("input type= checkbox, with t-att-checked", () => {
|
||||
qweb.addTemplate("test", `<input type="checkbox" t-att-checked="flag"/>`);
|
||||
const result = renderToString(qweb, "test", { flag: true });
|
||||
@@ -1804,6 +1877,33 @@ describe("special cases for some boolean html attributes/properties", () => {
|
||||
);
|
||||
renderToString(qweb, "test", { flag: true });
|
||||
});
|
||||
|
||||
test("input with t-att-value", () => {
|
||||
// render input with initial value
|
||||
qweb.addTemplate("test", `<input t-att-value="v"/>`);
|
||||
const vnode1 = qweb.render("test", { v: "zucchini" });
|
||||
const vnode2 = patch(document.createElement("input"), vnode1);
|
||||
let elm = vnode2.elm as HTMLInputElement;
|
||||
expect(elm.value).toBe("zucchini");
|
||||
|
||||
// change value manually in input, to simulate user input
|
||||
elm.value = "tomato";
|
||||
expect(elm.value).toBe("tomato");
|
||||
|
||||
// rerender with a different value, and patch actual dom, to check that
|
||||
// input value was properly reset by owl
|
||||
const vnode3 = qweb.render("test", { v: "potato" });
|
||||
patch(vnode2, vnode3);
|
||||
expect(elm.value).toBe("potato");
|
||||
});
|
||||
|
||||
test("input of type checkbox with t-att-indeterminate", () => {
|
||||
qweb.addTemplate("test", `<input type="checkbox" t-att-indeterminate="v"/>`);
|
||||
const vnode1 = qweb.render("test", { v: true });
|
||||
const vnode2 = patch(document.createElement("input"), vnode1);
|
||||
let elm = vnode2.elm as HTMLInputElement;
|
||||
expect(elm.indeterminate).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("whitespace handling", () => {
|
||||
|
||||
+4
-4
@@ -1107,9 +1107,9 @@ describe("html to vdom", function () {
|
||||
});
|
||||
|
||||
test("svg", function () {
|
||||
const nodeList = htmlToVDOM(`<svg></svg>`);
|
||||
expect(nodeList).toHaveLength(1);
|
||||
elm = patch(vnode0, nodeList[0]).elm;
|
||||
expect(elm).toBeInstanceOf(SVGSVGElement);
|
||||
const nodeList = htmlToVDOM(`<svg></svg>`);
|
||||
expect(nodeList).toHaveLength(1);
|
||||
elm = patch(vnode0, nodeList[0]).elm;
|
||||
expect(elm).toBeInstanceOf(SVGSVGElement);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user