Compare commits

...

2 Commits

Author SHA1 Message Date
Simon Genin (ges) de805d0d80 [FIX/IMP]: t-foreach can interpret any iterable.
t-foreach accepted only arrays and object.
Now, iterables and objects are accepted.

Closes #720
2020-10-13 15:37:24 +02:00
Géry Debongnie cb38d795f9 [FIX] slots: properly handle named t-slots inside named t-slots
Previous code naively handled nested t-set-slots: if a second named
slots was found, it overrode the first.

In this commit, we use a set to make sure that we only use the first
found t-set-slot node. Also, we ignore set-slots defined in a sub
components, because these slots are only relevant to the sub component
itself.

Note that it works as expected because document.querySelectorAll
performs a search depth first, so we will always use the named slots
closer to the parent element, in term of depth.

closes #682
2020-10-09 15:01:25 +02:00
7 changed files with 502 additions and 83 deletions
+29 -13
View File
@@ -400,7 +400,6 @@ QWeb.addDirective({
if (hasSlots) { if (hasSlots) {
const clone = <Element>node.cloneNode(true); const clone = <Element>node.cloneNode(true);
const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
// The next code is a fallback for compatibility reason. It accepts t-set // The next code is a fallback for compatibility reason. It accepts t-set
// elements that are direct children with a non empty body as nodes defining // elements that are direct children with a non empty body as nodes defining
@@ -410,26 +409,43 @@ QWeb.addDirective({
// code using slots. This will be removed in v2.0 someday. Meanwhile, // code using slots. This will be removed in v2.0 someday. Meanwhile,
// please use t-set-slot everywhere you need to set the content of a // please use t-set-slot everywhere you need to set the content of a
// slot. // slot.
for (let el of clone.children) { for (let node of clone.children) {
if (el.getAttribute("t-set") && el.hasChildNodes()) { if (node.hasAttribute("t-set") && node.hasChildNodes()) {
slotNodes.push(el); node.setAttribute("t-set-slot", node.getAttribute("t-set")!);
node.removeAttribute("t-set");
} }
} }
const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
const slotNames = new Set<string>();
const slotId = QWeb.nextSlotId++; const slotId = QWeb.nextSlotId++;
ctx.addLine(`w${componentID}.__owl__.slotId = ${slotId};`); ctx.addLine(`w${componentID}.__owl__.slotId = ${slotId};`);
if (slotNodes.length) { if (slotNodes.length) {
for (let i = 0, length = slotNodes.length; i < length; i++) { for (let i = 0, length = slotNodes.length; i < length; i++) {
const slotNode = slotNodes[i]; const slotNode = slotNodes[i];
slotNode.parentElement!.removeChild(slotNode); // check if this is defined in a sub component (in which case it should
let key = slotNode.getAttribute("t-set-slot")!; // be ignored)
slotNode.removeAttribute("t-set-slot"); let el = slotNode.parentElement;
let isInSubComponent = false;
// here again, this code should be removed when we stop supporting while (el !== clone) {
// using t-set to define the content of named slots. if (
if (!key) { el!.hasAttribute("t-component") ||
key = slotNode.getAttribute("t-set")!; el!.tagName[0] === el!.tagName[0].toUpperCase()
slotNode.removeAttribute("t-set"); ) {
isInSubComponent = true;
break;
}
} }
if (isInSubComponent) {
continue;
}
let key = slotNode.getAttribute("t-set-slot")!;
if (slotNames.has(key)) {
continue;
}
slotNames.add(key);
slotNode.removeAttribute("t-set-slot");
slotNode.parentElement!.removeChild(slotNode);
const slotFn = qweb._compile(`slot_${key}_template`, slotNode, ctx); const slotFn = qweb._compile(`slot_${key}_template`, slotNode, ctx);
QWeb.slots[`${slotId}_${key}`] = slotFn; QWeb.slots[`${slotId}_${key}`] = slotFn;
} }
+4
View File
@@ -312,9 +312,13 @@ QWeb.addDirective({
let valuesID = ctx.generateID(); let valuesID = ctx.generateID();
ctx.addLine(`let _${keysID} = _${valuesID} = _${arrayID};`); ctx.addLine(`let _${keysID} = _${valuesID} = _${arrayID};`);
ctx.addIf(`!(_${arrayID} instanceof Array)`); ctx.addIf(`!(_${arrayID} instanceof Array)`);
ctx.addIf(`typeof _${arrayID}[Symbol.iterator] === 'function'`);
ctx.addLine(`_${keysID} = [..._${arrayID}];`)
ctx.addElse();
ctx.addLine(`_${keysID} = Object.keys(_${arrayID});`); ctx.addLine(`_${keysID} = Object.keys(_${arrayID});`);
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`); ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
ctx.closeIf(); ctx.closeIf();
ctx.closeIf();
ctx.addLine(`let _length${keysID} = _${keysID}.length;`); ctx.addLine(`let _length${keysID} = _${keysID}.length;`);
let varsID = ctx.startProtectScope(true); let varsID = ctx.startProtectScope(true);
const loopVar = `i${ctx.loopNumber}`; const loopVar = `i${ctx.loopNumber}`;
@@ -53,8 +53,12 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -70,8 +74,12 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
if (!_6) { throw new Error('QWeb error: Invalid loop expression')} if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
let _7 = _8 = _6; let _7 = _8 = _6;
if (!(_6 instanceof Array)) { if (!(_6 instanceof Array)) {
_7 = Object.keys(_6); if (typeof _6[Symbol.iterator] === 'function') {
_8 = Object.values(_6); _7 = [..._6];
} else {
_7 = Object.keys(_6);
_8 = Object.values(_6);
}
} }
let _length7 = _7.length; let _length7 = _7.length;
let _origScope9 = scope; let _origScope9 = scope;
@@ -272,8 +280,12 @@ exports[`composition sub components with some state rendered in a loop 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -558,8 +570,12 @@ exports[`other directives with t-component t-on expression captured in t-foreach
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -600,8 +616,12 @@ exports[`other directives with t-component t-on expression in t-foreach 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -652,8 +672,12 @@ exports[`other directives with t-component t-on expression in t-foreach with t-s
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -705,8 +729,12 @@ exports[`other directives with t-component t-on method call in t-foreach 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -1371,8 +1399,12 @@ exports[`other directives with t-component t-set outside modified in t-foreach 1
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -1521,8 +1553,12 @@ exports[`random stuff/miscellaneous t-on with handler bound to dynamic argument
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -1797,8 +1833,12 @@ exports[`t-model directive in a t-foreach 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -1837,8 +1877,12 @@ exports[`t-model directive in a t-foreach, part 2 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -348,8 +348,12 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = `
if (!_3) { throw new Error('QWeb error: Invalid loop expression')} if (!_3) { throw new Error('QWeb error: Invalid loop expression')}
let _4 = _5 = _3; let _4 = _5 = _3;
if (!(_3 instanceof Array)) { if (!(_3 instanceof Array)) {
_4 = Object.keys(_3); if (typeof _3[Symbol.iterator] === 'function') {
_5 = Object.values(_3); _4 = [..._3];
} else {
_4 = Object.keys(_3);
_5 = Object.values(_3);
}
} }
let _length4 = _4.length; let _length4 = _4.length;
let _origScope6 = scope; let _origScope6 = scope;
@@ -445,8 +449,12 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = `
if (!_3) { throw new Error('QWeb error: Invalid loop expression')} if (!_3) { throw new Error('QWeb error: Invalid loop expression')}
let _4 = _5 = _3; let _4 = _5 = _3;
if (!(_3 instanceof Array)) { if (!(_3 instanceof Array)) {
_4 = Object.keys(_3); if (typeof _3[Symbol.iterator] === 'function') {
_5 = Object.values(_3); _4 = [..._3];
} else {
_4 = Object.keys(_3);
_5 = Object.values(_3);
}
} }
let _length4 = _4.length; let _length4 = _4.length;
let _origScope6 = scope; let _origScope6 = scope;
+65
View File
@@ -987,4 +987,69 @@ describe("t-slot directive", () => {
expect(fixture.innerHTML).toBe("<div><span><p>sokka</p></span></div>"); expect(fixture.innerHTML).toBe("<div><span><p>sokka</p></span></div>");
}); });
test("named slot inside slot", async () => {
class Child extends Component {
static template = xml`
<div>
<t t-slot="brol"/>
<t t-slot="default"/>
</div>`;
}
class Parent extends Component {
static template = xml`
<div>
<Child>
<t t-set-slot="brol">
<p>A<t t-esc="value"/></p>
</t>
<Child>
<t t-set-slot="brol">
<p>B<t t-esc="value"/></p>
</t>
</Child>
</Child>
</div>`;
static components = { Child };
value = "blip";
}
const parent = new Parent();
await parent.mount(fixture);
expect(fixture.innerHTML).toBe("<div><div><p>Ablip</p><div><p>Bblip</p></div></div></div>");
});
test("named slots inside slot, again", async () => {
class Child extends Component {
static template = xml`
<child>
<t t-slot="brol1">default1</t>
<t t-slot="brol2">default2</t>
<t t-slot="default"/>
</child>`;
}
class Parent extends Component {
static template = xml`
<div>
<Child>
<t t-set-slot="brol1">
<p>A<t t-esc="value"/></p>
</t>
<Child>
<t t-set-slot="brol2">
<p>B<t t-esc="value"/></p>
</t>
</Child>
</Child>
</div>`;
static components = { Child };
value = "blip";
}
const parent = new Parent();
await parent.mount(fixture);
expect(fixture.innerHTML).toBe(
"<div><child><p>Ablip</p>default2<child>default1<p>Bblip</p></child></child></div>"
);
});
}); });
+288 -44
View File
@@ -431,8 +431,12 @@ exports[`foreach does not pollute the rendering context 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -466,8 +470,12 @@ exports[`foreach iterate on items (on a element node) 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -504,8 +512,12 @@ exports[`foreach iterate on items 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -551,8 +563,12 @@ exports[`foreach iterate, dict param 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -598,8 +614,12 @@ exports[`foreach iterate, position 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -643,8 +663,12 @@ exports[`foreach t-call with body in t-foreach in t-foreach 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -660,8 +684,12 @@ exports[`foreach t-call with body in t-foreach in t-foreach 1`] = `
if (!_6) { throw new Error('QWeb error: Invalid loop expression')} if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
let _7 = _8 = _6; let _7 = _8 = _6;
if (!(_6 instanceof Array)) { if (!(_6 instanceof Array)) {
_7 = Object.keys(_6); if (typeof _6[Symbol.iterator] === 'function') {
_8 = Object.values(_6); _7 = [..._6];
} else {
_7 = Object.keys(_6);
_8 = Object.values(_6);
}
} }
let _length7 = _7.length; let _length7 = _7.length;
let _origScope9 = scope; let _origScope9 = scope;
@@ -731,8 +759,12 @@ exports[`foreach t-call without body in t-foreach in t-foreach 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -748,8 +780,12 @@ exports[`foreach t-call without body in t-foreach in t-foreach 1`] = `
if (!_6) { throw new Error('QWeb error: Invalid loop expression')} if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
let _7 = _8 = _6; let _7 = _8 = _6;
if (!(_6 instanceof Array)) { if (!(_6 instanceof Array)) {
_7 = Object.keys(_6); if (typeof _6[Symbol.iterator] === 'function') {
_8 = Object.values(_6); _7 = [..._6];
} else {
_7 = Object.keys(_6);
_8 = Object.values(_6);
}
} }
let _length7 = _7.length; let _length7 = _7.length;
let _origScope9 = scope; let _origScope9 = scope;
@@ -813,8 +849,12 @@ exports[`foreach t-foreach in t-forach 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -830,8 +870,12 @@ exports[`foreach t-foreach in t-forach 1`] = `
if (!_6) { throw new Error('QWeb error: Invalid loop expression')} if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
let _7 = _8 = _6; let _7 = _8 = _6;
if (!(_6 instanceof Array)) { if (!(_6 instanceof Array)) {
_7 = Object.keys(_6); if (typeof _6[Symbol.iterator] === 'function') {
_8 = Object.values(_6); _7 = [..._6];
} else {
_7 = Object.keys(_6);
_8 = Object.values(_6);
}
} }
let _length7 = _7.length; let _length7 = _7.length;
let _origScope9 = scope; let _origScope9 = scope;
@@ -861,6 +905,162 @@ exports[`foreach t-foreach in t-forach 1`] = `
}" }"
`; `;
exports[`foreach t-foreach supports custom iterators 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let scope = Object.create(context);
let h = this.h;
let c1 = [], p1 = {key:1};
let vn1 = h('div', p1, c1);
let _2 = scope['iterator'];
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2;
if (!(_2 instanceof Array)) {
if (typeof _2[Symbol.iterator] === 'function') {
_3 = [..._2];
} else {
_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.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
scope.item_index = i1
scope.item = _3[i1]
scope.item_value = _4[i1]
let key1 = i1;
let _6 = scope['item'];
if (_6 != null) {
c1.push({text: _6});
}
}
scope = _origScope5;
return vn1;
}"
`;
exports[`foreach t-foreach supports custom iterators 2`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let scope = Object.create(context);
let h = this.h;
let c1 = [], p1 = {key:1};
let vn1 = h('div', p1, c1);
let _2 = scope['iterator'];
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2;
if (!(_2 instanceof Array)) {
if (typeof _2[Symbol.iterator] === 'function') {
_3 = [..._2];
} else {
_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.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
scope.item_index = i1
scope.item = _3[i1]
scope.item_value = _4[i1]
let key1 = i1;
let _6 = scope['item'];
if (_6 != null) {
c1.push({text: _6});
}
}
scope = _origScope5;
return vn1;
}"
`;
exports[`foreach t-foreach supports custom iterators 3`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let scope = Object.create(context);
let h = this.h;
let c1 = [], p1 = {key:1};
let vn1 = h('div', p1, c1);
let _2 = scope['iterator'];
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2;
if (!(_2 instanceof Array)) {
if (typeof _2[Symbol.iterator] === 'function') {
_3 = [..._2];
} else {
_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.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
scope.item_index = i1
scope.item = _3[i1]
scope.item_value = _4[i1]
let key1 = i1;
let _6 = scope['item'];
if (_6 != null) {
c1.push({text: _6});
}
}
scope = _origScope5;
return vn1;
}"
`;
exports[`foreach t-foreach supports custom iterators 4`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let scope = Object.create(context);
let h = this.h;
let c1 = [], p1 = {key:1};
let vn1 = h('div', p1, c1);
let _2 = scope['iterator'];
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2;
if (!(_2 instanceof Array)) {
if (typeof _2[Symbol.iterator] === 'function') {
_3 = [..._2];
} else {
_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.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
scope.item_index = i1
scope.item = _3[i1]
scope.item_value = _4[i1]
let key1 = i1;
let _6 = scope['item'];
if (_6 != null) {
c1.push({text: _6});
}
}
scope = _origScope5;
return vn1;
}"
`;
exports[`foreach warn if no key in some case 1`] = ` exports[`foreach warn if no key in some case 1`] = `
"function anonymous(context, extra "function anonymous(context, extra
) { ) {
@@ -873,8 +1073,12 @@ exports[`foreach warn if no key in some case 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -942,8 +1146,12 @@ exports[`misc global 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -1509,8 +1717,12 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
if (!_5) { throw new Error('QWeb error: Invalid loop expression')} if (!_5) { throw new Error('QWeb error: Invalid loop expression')}
let _6 = _7 = _5; let _6 = _7 = _5;
if (!(_5 instanceof Array)) { if (!(_5 instanceof Array)) {
_6 = Object.keys(_5); if (typeof _5[Symbol.iterator] === 'function') {
_7 = Object.values(_5); _6 = [..._5];
} else {
_6 = Object.keys(_5);
_7 = Object.values(_5);
}
} }
let _length6 = _6.length; let _length6 = _6.length;
let _origScope8 = scope; let _origScope8 = scope;
@@ -1588,8 +1800,12 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
if (!_5) { throw new Error('QWeb error: Invalid loop expression')} if (!_5) { throw new Error('QWeb error: Invalid loop expression')}
let _6 = _7 = _5; let _6 = _7 = _5;
if (!(_5 instanceof Array)) { if (!(_5 instanceof Array)) {
_6 = Object.keys(_5); if (typeof _5[Symbol.iterator] === 'function') {
_7 = Object.values(_5); _6 = [..._5];
} else {
_6 = Object.keys(_5);
_7 = Object.values(_5);
}
} }
let _length6 = _6.length; let _length6 = _6.length;
let _origScope8 = scope; let _origScope8 = scope;
@@ -1673,8 +1889,12 @@ exports[`t-call (template calling recursive template, part 4: with t-set recursi
if (!_5) { throw new Error('QWeb error: Invalid loop expression')} if (!_5) { throw new Error('QWeb error: Invalid loop expression')}
let _6 = _7 = _5; let _6 = _7 = _5;
if (!(_5 instanceof Array)) { if (!(_5 instanceof Array)) {
_6 = Object.keys(_5); if (typeof _5[Symbol.iterator] === 'function') {
_7 = Object.values(_5); _6 = [..._5];
} else {
_6 = Object.keys(_5);
_7 = Object.values(_5);
}
} }
let _length6 = _6.length; let _length6 = _6.length;
let _origScope8 = scope; let _origScope8 = scope;
@@ -1810,8 +2030,12 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -2587,8 +2811,12 @@ exports[`t-key t-key directive in a list 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -2691,8 +2919,12 @@ exports[`t-on can bind handlers with loop variable as argument 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -2973,8 +3205,12 @@ exports[`t-on t-on with prevent modifier in t-foreach 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -3227,8 +3463,12 @@ exports[`t-ref refs in a loop 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
@@ -3471,8 +3711,12 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
if (!_2) { throw new Error('QWeb error: Invalid loop expression')} if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
let _3 = _4 = _2; let _3 = _4 = _2;
if (!(_2 instanceof Array)) { if (!(_2 instanceof Array)) {
_3 = Object.keys(_2); if (typeof _2[Symbol.iterator] === 'function') {
_4 = Object.values(_2); _3 = [..._2];
} else {
_3 = Object.keys(_2);
_4 = Object.values(_2);
}
} }
let _length3 = _3.length; let _length3 = _3.length;
let _origScope5 = scope; let _origScope5 = scope;
+38
View File
@@ -1263,6 +1263,44 @@ describe("foreach", () => {
); );
console.warn = consoleWarn; console.warn = consoleWarn;
}); });
test('t-foreach supports custom iterators', () => {
qweb.addTemplate(
"test",
`
<div>
<t t-foreach="iterator" t-as="item">
<t t-esc="item"/>
</t>
</div>`
);
let iterator: any = [1, 2, 3];
let result = trim(renderToString(qweb, "test", { iterator } ));
let expected = `<div>123</div>`;
expect(result).toBe(expected);
iterator = { 1: 1, 2: 2, 3:3 };
result = trim(renderToString(qweb, "test", { iterator } ));
expected = `<div>123</div>`;
expect(result).toBe(expected);
iterator = new Set([1, 2, 3]);
result = trim(renderToString(qweb, "test", { iterator } ));
expected = `<div>123</div>`;
expect(result).toBe(expected);
iterator = {}
iterator[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
}
result = trim(renderToString(qweb, "test", { iterator } ));
expected = `<div>123</div>`;
expect(result).toBe(expected);
});
}); });
describe("misc", () => { describe("misc", () => {