[IMP] qweb: implement t-key with a directive

closes #331
This commit is contained in:
Géry Debongnie
2019-10-27 11:23:09 +01:00
committed by aab-odoo
parent 5d57a7bf13
commit 5614c85b04
8 changed files with 267 additions and 247 deletions
+2 -13
View File
@@ -223,30 +223,19 @@ QWeb.addDirective({
}
}
let key = node.getAttribute("t-key");
if (key) {
key = ctx.formatExpression(key);
}
// computing the props string representing the props object
let propStr = Object.keys(props)
.map(k => k + ":" + props[k])
.join(",");
let defID = ctx.generateID();
let componentID = ctx.generateID();
let keyID = key && ctx.generateID();
if (key) {
// we bind a variable to the key (could be a complex expression, so we
// want to evaluate it only once)
ctx.addLine(`let key${keyID} = 'key' + ${key};`);
}
let locationExpr = `\`__${ctx.generateID()}__`;
for (let i = 0; i < ctx.loopNumber - 1; i++) {
locationExpr += `\${i${i + 1}}__`;
}
if (key || ctx.currentKey) {
const k = key ? `key${keyID}` : ctx.currentKey;
if (ctx.lastNodeKey || ctx.currentKey) {
const k = ctx.lastNodeKey || ctx.currentKey;
ctx.addLine(`let templateId${componentID} = ${locationExpr}\` + ${k};`);
} else {
locationExpr += ctx.loopNumber ? `\${i${ctx.loopNumber}}__\`` : "`";
+6 -14
View File
@@ -294,25 +294,17 @@ QWeb.addDirective({
ctx.addToScope(name, `_${keysID}[${loopVar}]`);
ctx.addToScope(name + "_value", `_${valuesID}[${loopVar}]`);
const nodeCopy = <Element>node.cloneNode(true);
let shouldWarn = nodeCopy.tagName !== "t" && !nodeCopy.hasAttribute("t-key");
if (!shouldWarn && node.tagName === "t") {
if (node.hasAttribute("t-component") && !node.hasAttribute("t-key")) {
shouldWarn = true;
}
if (
!shouldWarn &&
node.children.length === 1 &&
node.children[0].tagName !== "t" &&
!node.children[0].hasAttribute("t-key")
) {
shouldWarn = true;
}
}
let shouldWarn =
!nodeCopy.hasAttribute("t-key") &&
node.children.length === 1 &&
node.children[0].tagName !== "t" &&
!node.children[0].hasAttribute("t-key");
if (shouldWarn) {
console.warn(
`Directive t-foreach should always be used with a t-key! (in template: '${ctx.templateName}')`
);
}
nodeCopy.removeAttribute("t-foreach");
qweb._compileNode(nodeCopy, ctx);
ctx.dedent();
+13
View File
@@ -261,3 +261,16 @@ QWeb.addDirective({
ctx.addLine(`p${nodeID}.on['${event}'] = extra.handlers['${event}' + ${nodeID}];`);
}
});
//------------------------------------------------------------------------------
// t-key
//------------------------------------------------------------------------------
QWeb.addDirective({
name: "key",
priority: 45,
atNodeEncounter({ ctx, value }) {
let id = ctx.generateID();
ctx.addLine(`const nodeKey${id} = ${ctx.formatExpression(value)};`);
ctx.lastNodeKey = `nodeKey${id}`;
}
});
+1 -9
View File
@@ -151,7 +151,6 @@ export class QWeb extends EventBus {
name: 1,
att: 1,
attf: 1,
key: 1,
translation: 1
};
static DIRECTIVES: Directive[] = [];
@@ -725,14 +724,7 @@ export class QWeb extends EventBus {
}
}
let nodeID = ctx.generateID();
let nodeKey: any = (<Element>node).getAttribute("t-key");
if (nodeKey) {
ctx.addLine(`const nodeKey${nodeID} = ${ctx.formatExpression(nodeKey)}`);
nodeKey = `nodeKey${nodeID}`;
ctx.lastNodeKey = nodeKey;
} else {
nodeKey = nodeID;
}
let nodeKey = ctx.lastNodeKey || nodeID;
const parts = [`key:${nodeKey}`];
if (attrs.length + tattrs.length > 0) {
parts.push(`attrs:{${attrs.join(",")}}`);
@@ -305,33 +305,33 @@ exports[`composition sub components with some state rendered in a loop 1`] = `
context.number_index = i1;
context.number = _3[i1];
context.number_value = _4[i1];
const nodeKey5 = context['number'];
//COMPONENT
let key7 = 'key' + context['number'];
let templateId6 = \`__8__\` + key7;
let w6 = templateId6 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId6]] : false;
let props6 = {};
if (w6 && w6.__owl__.currentFiber && !w6.__owl__.vnode) {
w6.destroy();
w6 = false;
let templateId7 = \`__8__\` + nodeKey5;
let w7 = templateId7 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId7]] : false;
let props7 = {};
if (w7 && w7.__owl__.currentFiber && !w7.__owl__.vnode) {
w7.destroy();
w7 = false;
}
if (w6) {
w6.__updateProps(props6, extra.fiber, undefined, undefined, sibling);
let pvnode = w6.__owl__.pvnode;
if (w7) {
w7.__updateProps(props7, extra.fiber, undefined, undefined, sibling);
let pvnode = w7.__owl__.pvnode;
c1.push(pvnode);
} else {
let componentKey6 = \`ChildWidget\`;
let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| context['ChildWidget'];
if (!W6) {throw new Error('Cannot find the definition of component \\"' + componentKey6 + '\\"')}
w6 = new W6(parent, props6);
parent.__owl__.cmap[templateId6] = w6.__owl__.id;
let def5 = w6.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId6, hook: {insert(vn) { let nvn=w6.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w6.destroy();}}});
const fiber = w6.__owl__.currentFiber;
def5.then(function () {if (w6.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
let componentKey7 = \`ChildWidget\`;
let W7 = context.constructor.components[componentKey7] || QWeb.components[componentKey7]|| context['ChildWidget'];
if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
w7 = new W7(parent, props7);
parent.__owl__.cmap[templateId7] = w7.__owl__.id;
let def6 = w7.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId7, hook: {insert(vn) { let nvn=w7.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w7.destroy();}}});
const fiber = w7.__owl__.currentFiber;
def6.then(function () {if (w7.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
c1.push(pvnode);
w6.__owl__.pvnode = pvnode;
w7.__owl__.pvnode = pvnode;
}
sibling = w6.__owl__.currentFiber || sibling;
sibling = w7.__owl__.currentFiber || sibling;
}
return vn1;
}"
@@ -993,33 +993,33 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
const nodeKey2 = 'somestring';
//COMPONENT
let key4 = 'key' + 'somestring';
let templateId3 = \`__5__\` + key4;
let w3 = templateId3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId3]] : false;
let props3 = {flag:context['state'].flag};
if (w3 && w3.__owl__.currentFiber && !w3.__owl__.vnode) {
w3.destroy();
w3 = false;
let templateId4 = \`__5__\` + nodeKey2;
let w4 = templateId4 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId4]] : false;
let props4 = {flag:context['state'].flag};
if (w4 && w4.__owl__.currentFiber && !w4.__owl__.vnode) {
w4.destroy();
w4 = false;
}
if (w3) {
w3.__updateProps(props3, extra.fiber, undefined, undefined, sibling);
let pvnode = w3.__owl__.pvnode;
if (w4) {
w4.__updateProps(props4, extra.fiber, undefined, undefined, sibling);
let pvnode = w4.__owl__.pvnode;
c1.push(pvnode);
} else {
let componentKey3 = \`child\`;
let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| context['child'];
if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')}
w3 = new W3(parent, props3);
parent.__owl__.cmap[templateId3] = w3.__owl__.id;
let def2 = w3.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId3, hook: {insert(vn) { let nvn=w3.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w3.destroy();}}});
const fiber = w3.__owl__.currentFiber;
def2.then(function () {if (w3.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
let componentKey4 = \`child\`;
let W4 = context.constructor.components[componentKey4] || QWeb.components[componentKey4]|| context['child'];
if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(parent, props4);
parent.__owl__.cmap[templateId4] = w4.__owl__.id;
let def3 = w4.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId4, hook: {insert(vn) { let nvn=w4.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w4.destroy();}}});
const fiber = w4.__owl__.currentFiber;
def3.then(function () {if (w4.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
c1.push(pvnode);
w3.__owl__.pvnode = pvnode;
w4.__owl__.pvnode = pvnode;
}
sibling = w3.__owl__.currentFiber || sibling;
sibling = w4.__owl__.currentFiber || sibling;
return vn1;
}"
`;
@@ -1050,34 +1050,34 @@ exports[`random stuff/miscellaneous t-on with handler bound to dynamic argument
context.item_index = i1;
context.item = _3[i1];
context.item_value = _4[i1];
const nodeKey5 = context['item'];
//COMPONENT
let key7 = 'key' + context['item'];
let templateId6 = \`__8__\` + key7;
let templateId7 = \`__8__\` + nodeKey5;
let arg9 = context['item'];
let w6 = templateId6 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId6]] : false;
let props6 = {};
if (w6 && w6.__owl__.currentFiber && !w6.__owl__.vnode) {
w6.destroy();
w6 = false;
let w7 = templateId7 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId7]] : false;
let props7 = {};
if (w7 && w7.__owl__.currentFiber && !w7.__owl__.vnode) {
w7.destroy();
w7 = false;
}
if (w6) {
w6.__updateProps(props6, extra.fiber, undefined, undefined, sibling);
let pvnode = w6.__owl__.pvnode;
if (w7) {
w7.__updateProps(props7, extra.fiber, undefined, undefined, sibling);
let pvnode = w7.__owl__.pvnode;
c1.push(pvnode);
} else {
let componentKey6 = \`Child\`;
let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| context['Child'];
if (!W6) {throw new Error('Cannot find the definition of component \\"' + componentKey6 + '\\"')}
w6 = new W6(parent, props6);
parent.__owl__.cmap[templateId6] = w6.__owl__.id;
let def5 = w6.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId6, hook: {insert(vn) { let nvn=w6.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w6.destroy();}}});
const fiber = w6.__owl__.currentFiber;
def5.then(function () {if (w6.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {const fn = owner['onEv'];if (fn) { fn.call(owner, arg9, e); } else { owner.onEv; }});}};});
let componentKey7 = \`Child\`;
let W7 = context.constructor.components[componentKey7] || QWeb.components[componentKey7]|| context['Child'];
if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
w7 = new W7(parent, props7);
parent.__owl__.cmap[templateId7] = w7.__owl__.id;
let def6 = w7.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId7, hook: {insert(vn) { let nvn=w7.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w7.destroy();}}});
const fiber = w7.__owl__.currentFiber;
def6.then(function () {if (w7.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {const fn = owner['onEv'];if (fn) { fn.call(owner, arg9, e); } else { owner.onEv; }});}};});
c1.push(pvnode);
w6.__owl__.pvnode = pvnode;
w7.__owl__.pvnode = pvnode;
}
sibling = w6.__owl__.currentFiber || sibling;
sibling = w7.__owl__.currentFiber || sibling;
}
return vn1;
}"
@@ -1541,37 +1541,37 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = `
scope.user = context.user;
context.user_value = _5[i1];
scope.user_value = context.user_value;
const nodeKey6 = context['user'].id
let c6 = [], p6 = {key:nodeKey6};
var vn6 = h('li', p6, c6);
c2.push(vn6);
const nodeKey6 = context['user'].id;
let c7 = [], p7 = {key:nodeKey6};
var vn7 = h('li', p7, c7);
c2.push(vn7);
//COMPONENT
let templateId8 = \`__9__\` + nodeKey6;
let w8 = templateId8 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId8]] : false;
let props8 = {to:'/user/'+context['user'].id};
if (w8 && w8.__owl__.currentFiber && !w8.__owl__.vnode) {
w8.destroy();
w8 = false;
let templateId9 = \`__10__\` + nodeKey6;
let w9 = templateId9 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId9]] : false;
let props9 = {to:'/user/'+context['user'].id};
if (w9 && w9.__owl__.currentFiber && !w9.__owl__.vnode) {
w9.destroy();
w9 = false;
}
if (w8) {
w8.__updateProps(props8, extra.fiber, Object.assign({}, scope), undefined, sibling);
let pvnode = w8.__owl__.pvnode;
c6.push(pvnode);
if (w9) {
w9.__updateProps(props9, extra.fiber, Object.assign({}, scope), undefined, sibling);
let pvnode = w9.__owl__.pvnode;
c7.push(pvnode);
} else {
let componentKey8 = \`Link\`;
let W8 = context.constructor.components[componentKey8] || QWeb.components[componentKey8]|| context['Link'];
if (!W8) {throw new Error('Cannot find the definition of component \\"' + componentKey8 + '\\"')}
w8 = new W8(parent, props8);
parent.__owl__.cmap[templateId8] = w8.__owl__.id;
w8.__owl__.slotId = 1;
let def7 = w8.__prepare(extra.fiber, Object.assign({}, scope), undefined, sibling);
let pvnode = h('dummy', {key: templateId8, hook: {insert(vn) { let nvn=w8.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w8.destroy();}}});
const fiber = w8.__owl__.currentFiber;
def7.then(function () {if (w8.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
c6.push(pvnode);
w8.__owl__.pvnode = pvnode;
let componentKey9 = \`Link\`;
let W9 = context.constructor.components[componentKey9] || QWeb.components[componentKey9]|| context['Link'];
if (!W9) {throw new Error('Cannot find the definition of component \\"' + componentKey9 + '\\"')}
w9 = new W9(parent, props9);
parent.__owl__.cmap[templateId9] = w9.__owl__.id;
w9.__owl__.slotId = 1;
let def8 = w9.__prepare(extra.fiber, Object.assign({}, scope), undefined, sibling);
let pvnode = h('dummy', {key: templateId9, hook: {insert(vn) { let nvn=w9.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w9.destroy();}}});
const fiber = w9.__owl__.currentFiber;
def8.then(function () {if (w9.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
c7.push(pvnode);
w9.__owl__.pvnode = pvnode;
}
sibling = w8.__owl__.currentFiber || sibling;
sibling = w9.__owl__.currentFiber || sibling;
}
return vn1;
}"
@@ -1582,12 +1582,12 @@ exports[`t-slot directive slots are rendered with proper context, part 2 3`] = `
) {
let sibling = null;
var h = this.h;
let c6 = extra.parentNode;
let c7 = extra.parentNode;
Object.assign(context, extra.fiber.scope);
c6.push({text: \`User \`});
var _11 = context['user'].name;
if (_11 || _11 === 0) {
c6.push({text: _11});
c7.push({text: \`User \`});
var _12 = context['user'].name;
if (_12 || _12 === 0) {
c7.push({text: _12});
}
}"
`;
@@ -1644,38 +1644,38 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = `
scope.user = context.user;
context.user_value = _5[i1];
scope.user_value = context.user_value;
const nodeKey6 = context['user'].id
let c6 = [], p6 = {key:nodeKey6};
var vn6 = h('li', p6, c6);
c2.push(vn6);
var _7 = 'User '+context['user'].name;
const nodeKey6 = context['user'].id;
let c7 = [], p7 = {key:nodeKey6};
var vn7 = h('li', p7, c7);
c2.push(vn7);
var _8 = 'User '+context['user'].name;
//COMPONENT
let templateId9 = \`__10__\` + nodeKey6;
let w9 = templateId9 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId9]] : false;
let props9 = {to:'/user/'+context['user'].id};
if (w9 && w9.__owl__.currentFiber && !w9.__owl__.vnode) {
w9.destroy();
w9 = false;
let templateId10 = \`__11__\` + nodeKey6;
let w10 = templateId10 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId10]] : false;
let props10 = {to:'/user/'+context['user'].id};
if (w10 && w10.__owl__.currentFiber && !w10.__owl__.vnode) {
w10.destroy();
w10 = false;
}
if (w9) {
w9.__updateProps(props9, extra.fiber, Object.assign({}, scope), {_7}, sibling);
let pvnode = w9.__owl__.pvnode;
c6.push(pvnode);
if (w10) {
w10.__updateProps(props10, extra.fiber, Object.assign({}, scope), {_8}, sibling);
let pvnode = w10.__owl__.pvnode;
c7.push(pvnode);
} else {
let componentKey9 = \`Link\`;
let W9 = context.constructor.components[componentKey9] || QWeb.components[componentKey9]|| context['Link'];
if (!W9) {throw new Error('Cannot find the definition of component \\"' + componentKey9 + '\\"')}
w9 = new W9(parent, props9);
parent.__owl__.cmap[templateId9] = w9.__owl__.id;
w9.__owl__.slotId = 1;
let def8 = w9.__prepare(extra.fiber, Object.assign({}, scope), {_7}, sibling);
let pvnode = h('dummy', {key: templateId9, hook: {insert(vn) { let nvn=w9.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w9.destroy();}}});
const fiber = w9.__owl__.currentFiber;
def8.then(function () {if (w9.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
c6.push(pvnode);
w9.__owl__.pvnode = pvnode;
let componentKey10 = \`Link\`;
let W10 = context.constructor.components[componentKey10] || QWeb.components[componentKey10]|| context['Link'];
if (!W10) {throw new Error('Cannot find the definition of component \\"' + componentKey10 + '\\"')}
w10 = new W10(parent, props10);
parent.__owl__.cmap[templateId10] = w10.__owl__.id;
w10.__owl__.slotId = 1;
let def9 = w10.__prepare(extra.fiber, Object.assign({}, scope), {_8}, sibling);
let pvnode = h('dummy', {key: templateId10, hook: {insert(vn) { let nvn=w10.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w10.destroy();}}});
const fiber = w10.__owl__.currentFiber;
def9.then(function () {if (w10.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
c7.push(pvnode);
w10.__owl__.pvnode = pvnode;
}
sibling = w9.__owl__.currentFiber || sibling;
sibling = w10.__owl__.currentFiber || sibling;
}
return vn1;
}"
@@ -1686,11 +1686,11 @@ exports[`t-slot directive slots are rendered with proper context, part 3 3`] = `
) {
let sibling = null;
var h = this.h;
let c6 = extra.parentNode;
let _7 = extra.fiber.vars._7
let c7 = extra.parentNode;
let _8 = extra.fiber.vars._8
Object.assign(context, extra.fiber.scope);
if (_7 || _7 === 0) {
c6.push({text: _7});
if (_8 || _8 === 0) {
c7.push({text: _8});
}
}"
`;
+62 -62
View File
@@ -387,13 +387,13 @@ exports[`foreach iterate on items (on a element node) 1`] = `
context.item_index = i1;
context.item = _3[i1];
context.item_value = _4[i1];
const nodeKey5 = context['item']
let c5 = [], p5 = {key:nodeKey5};
var vn5 = h('span', p5, c5);
c1.push(vn5);
var _6 = context['item'];
if (_6 || _6 === 0) {
c5.push({text: _6});
const nodeKey5 = context['item'];
let c6 = [], p6 = {key:nodeKey5};
var vn6 = h('span', p6, c6);
c1.push(vn6);
var _7 = context['item'];
if (_7 || _7 === 0) {
c6.push({text: _7});
}
}
return vn1;
@@ -1643,14 +1643,14 @@ exports[`t-key can use t-key directive on a node 1`] = `
) {
let sibling = null;
var h = this.h;
const nodeKey1 = context['beer'].id
let c1 = [], p1 = {key:nodeKey1};
var vn1 = h('div', p1, c1);
var _2 = context['beer'].name;
if (_2 || _2 === 0) {
c1.push({text: _2});
const nodeKey1 = context['beer'].id;
let c2 = [], p2 = {key:nodeKey1};
var vn2 = h('div', p2, c2);
var _3 = context['beer'].name;
if (_3 || _3 === 0) {
c2.push({text: _3});
}
return vn1;
return vn2;
}"
`;
@@ -1676,13 +1676,13 @@ exports[`t-key t-key directive in a list 1`] = `
context.beer_index = i1;
context.beer = _3[i1];
context.beer_value = _4[i1];
const nodeKey5 = context['beer'].id
let c5 = [], p5 = {key:nodeKey5};
var vn5 = h('li', p5, c5);
c1.push(vn5);
var _6 = context['beer'].name;
if (_6 || _6 === 0) {
c5.push({text: _6});
const nodeKey5 = context['beer'].id;
let c6 = [], p6 = {key:nodeKey5};
var vn6 = h('li', p6, c6);
c1.push(vn6);
var _7 = context['beer'].name;
if (_7 || _7 === 0) {
c6.push({text: _7});
}
}
return vn1;
@@ -1774,16 +1774,16 @@ exports[`t-on can bind handlers with loop variable as argument 1`] = `
context.action_index = i1;
context.action = _3[i1];
context.action_value = _4[i1];
const nodeKey5 = context['action_index']
let c5 = [], p5 = {key:nodeKey5};
var vn5 = h('li', p5, c5);
c1.push(vn5);
let c6 = [], p6 = {key:6,on:{}};
var vn6 = h('a', p6, c6);
c5.push(vn6);
const handler7 = context['activate'] && context['activate'].bind(owner, context['action']);
p6.on['click'] = function (e) {if (handler7) { handler7(e); } else { context.activate(action); }};
c6.push({text: \`link\`});
const nodeKey5 = context['action_index'];
let c6 = [], p6 = {key:nodeKey5};
var vn6 = h('li', p6, c6);
c1.push(vn6);
let c7 = [], p7 = {key:nodeKey5,on:{}};
var vn7 = h('a', p7, c7);
c6.push(vn7);
const handler8 = context['activate'] && context['activate'].bind(owner, context['action']);
p7.on['click'] = function (e) {if (handler8) { handler8(e); } else { context.activate(action); }};
c7.push({text: \`link\`});
}
return vn1;
}"
@@ -2000,17 +2000,17 @@ exports[`t-on t-on with prevent modifier in t-foreach 1`] = `
context.project_index = i1;
context.project = _3[i1];
context.project_value = _4[i1];
var _5 = '#';
const nodeKey6 = context['project']
let c6 = [], p6 = {key:nodeKey6,attrs:{href: _5},on:{}};
var vn6 = h('a', p6, c6);
c1.push(vn6);
const handler7 = context['onEdit'] && context['onEdit'].bind(owner, context['project'].id);
p6.on['click'] = function (e) {e.preventDefault();if (handler7) { handler7(e); } else { context.onEdit(project.id); }};
c6.push({text: \` Edit \`});
var _8 = context['project'].name;
if (_8 || _8 === 0) {
c6.push({text: _8});
const nodeKey5 = context['project'];
var _6 = '#';
let c7 = [], p7 = {key:nodeKey5,attrs:{href: _6},on:{}};
var vn7 = h('a', p7, c7);
c1.push(vn7);
const handler8 = context['onEdit'] && context['onEdit'].bind(owner, context['project'].id);
p7.on['click'] = function (e) {e.preventDefault();if (handler8) { handler8(e); } else { context.onEdit(project.id); }};
c7.push({text: \` Edit \`});
var _9 = context['project'].name;
if (_9 || _9 === 0) {
c7.push({text: _9});
}
}
return vn1;
@@ -2207,22 +2207,22 @@ exports[`t-ref refs in a loop 1`] = `
context.item_index = i1;
context.item = _3[i1];
context.item_value = _4[i1];
const nodeKey5 = context['item']
let c5 = [], p5 = {key:nodeKey5};
var vn5 = h('div', p5, c5);
c1.push(vn5);
const ref6 = (context['item']);
p5.hook = {
const nodeKey5 = context['item'];
let c6 = [], p6 = {key:nodeKey5};
var vn6 = h('div', p6, c6);
c1.push(vn6);
const ref7 = (context['item']);
p6.hook = {
create: (_, n) => {
context.__owl__.refs[ref6] = n.elm;
context.__owl__.refs[ref7] = n.elm;
},
destroy: () => {
delete context.__owl__.refs[ref6];
delete context.__owl__.refs[ref7];
},
};
var _7 = context['item'];
if (_7 || _7 === 0) {
c5.push({text: _7});
var _8 = context['item'];
if (_8 || _8 === 0) {
c6.push({text: _8});
}
}
return vn1;
@@ -2383,16 +2383,16 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
context.elem_index = i1;
context.elem = _4[i1];
context.elem_value = _5[i1];
const nodeKey6 = context['elem_index']
let c6 = [], p6 = {key:nodeKey6};
var vn6 = h('div', p6, c6);
c1.push(vn6);
let c7 = [], p7 = {key:7};
var vn7 = h('span', p7, c7);
c6.push(vn7);
c7.push({text: \`v\`});
const nodeKey6 = context['elem_index'];
let c7 = [], p7 = {key:nodeKey6};
var vn7 = h('div', p7, c7);
c1.push(vn7);
let c8 = [], p8 = {key:nodeKey6};
var vn8 = h('span', p8, c8);
c7.push(vn8);
c8.push({text: \`v\`});
if (_2 || _2 === 0) {
c7.push({text: _2});
c8.push({text: _2});
}
_2 = context['elem']
}
+35 -1
View File
@@ -1,5 +1,6 @@
import { QWeb } from "../../src/qweb/index";
import { normalize, renderToDOM, renderToString, trim, nextTick } from "../helpers";
import { nextTick, normalize, renderToDOM, renderToString, trim } from "../helpers";
import { patch } from "../../src/vdom";
//------------------------------------------------------------------------------
// Setup and helpers
@@ -837,6 +838,9 @@ describe("foreach", () => {
);
renderToString(qweb, "test");
expect(console.warn).toHaveBeenCalledTimes(1);
expect(console.warn).toHaveBeenCalledWith(
"Directive t-foreach should always be used with a t-key! (in template: 'test')"
);
console.warn = consoleWarn;
});
});
@@ -1570,3 +1574,33 @@ describe("translation support", () => {
);
});
});
describe("t-key tests", () => {
test("t-key on t-foreach", async () => {
qweb.addTemplate(
"test",
`
<div>
<t t-foreach="things" t-as="thing" t-key="thing">
<span/>
</t>
</div>`
);
let vnode = qweb.render("test", { things: [1, 2] });
vnode = patch(document.createElement("div"), vnode);
let elm = vnode.elm as HTMLElement;
expect(elm.outerHTML).toBe("<div><span></span><span></span></div>");
const first = elm.querySelectorAll("span")[0];
const second = elm.querySelectorAll("span")[1];
patch(vnode, qweb.render("test", { things: [2, 1] }));
expect(elm.outerHTML).toBe("<div><span></span><span></span></div>");
expect(first).toBe(elm.querySelectorAll("span")[1]);
expect(second).toBe(elm.querySelectorAll("span")[0]);
});
});
@@ -11,35 +11,35 @@ exports[`RouteComponent can render simple cases 1`] = `
let result;
var h = this.h;
if (context['routeComponent']) {
const nodeKey1 = context['env'].router.currentRouteName;
//COMPONENT
let key3 = 'key' + context['env'].router.currentRouteName;
let templateId2 = \`__4__\` + key3;
let w2 = templateId2 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId2]] : false;
let templateId3 = \`__4__\` + nodeKey1;
let w3 = templateId3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[templateId3]] : false;
let vn5 = {};
result = vn5;
let props2 = Object.assign({}, context['env'].router.currentParams);
if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) {
w2.destroy();
w2 = false;
let props3 = Object.assign({}, context['env'].router.currentParams);
if (w3 && w3.__owl__.currentFiber && !w3.__owl__.vnode) {
w3.destroy();
w3 = false;
}
if (w2) {
w2.__updateProps(props2, extra.fiber, undefined, undefined, sibling);
let pvnode = w2.__owl__.pvnode;
if (w3) {
w3.__updateProps(props3, extra.fiber, undefined, undefined, sibling);
let pvnode = w3.__owl__.pvnode;
utils.defineProxy(vn5, pvnode);
} else {
let componentKey2 = \`routeComponent\`;
let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['routeComponent'];
if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')}
w2 = new W2(parent, props2);
parent.__owl__.cmap[templateId2] = w2.__owl__.id;
let def1 = w2.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId2, hook: {insert(vn) { let nvn=w2.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w2.destroy();}}});
const fiber = w2.__owl__.currentFiber;
def1.then(function () {if (w2.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
let componentKey3 = \`routeComponent\`;
let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| context['routeComponent'];
if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')}
w3 = new W3(parent, props3);
parent.__owl__.cmap[templateId3] = w3.__owl__.id;
let def2 = w3.__prepare(extra.fiber, undefined, undefined, sibling);
let pvnode = h('dummy', {key: templateId3, hook: {insert(vn) { let nvn=w3.__mount(fiber, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w3.destroy();}}});
const fiber = w3.__owl__.currentFiber;
def2.then(function () {if (w3.__owl__.isDestroyed) {return;} const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
utils.defineProxy(vn5, pvnode);
w2.__owl__.pvnode = pvnode;
w3.__owl__.pvnode = pvnode;
}
sibling = w2.__owl__.currentFiber || sibling;
sibling = w3.__owl__.currentFiber || sibling;
}
return result;
}"