mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2042f2ec01 |
@@ -24,4 +24,4 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm install
|
||||
- run: npm run test
|
||||
- run: npm run check-formatting
|
||||
- run: npm run prettier
|
||||
|
||||
+3
-1
@@ -31,4 +31,6 @@ release-notes.md
|
||||
.rpt2_cache
|
||||
|
||||
# useful in some cases
|
||||
/temp
|
||||
/temp
|
||||
|
||||
coverage
|
||||
|
||||
@@ -124,7 +124,7 @@ npm install @odoo/owl
|
||||
|
||||
If you want to use a simple `<script>` tag, the last release can be downloaded here:
|
||||
|
||||
- [owl-1.4.9](https://github.com/odoo/owl/releases/tag/v1.4.9)
|
||||
- [owl-1.4.5](https://github.com/odoo/owl/releases/tag/v1.4.5)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -176,9 +176,9 @@ const uuid = generateUUID();
|
||||
class MyComponent extends Component {
|
||||
static template = xml`<div data-o-${uuid}="">...</div>`;
|
||||
static style = css`
|
||||
[data-o-${uuid}] {
|
||||
color: red;
|
||||
}
|
||||
`;
|
||||
[data-o-${uuid}] {
|
||||
color: red;
|
||||
}
|
||||
`;
|
||||
}
|
||||
```
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@odoo/owl",
|
||||
"version": "1.4.9",
|
||||
"version": "1.4.5",
|
||||
"description": "Odoo Web Library (OWL)",
|
||||
"main": "dist/owl.cjs.js",
|
||||
"browser": "dist/owl.iife.js",
|
||||
@@ -76,7 +76,9 @@
|
||||
"jsx",
|
||||
"json",
|
||||
"node"
|
||||
]
|
||||
],
|
||||
"collectCoverage": true,
|
||||
"coverageReporters": ["html"]
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# 🦉 OWL Roadmap 🦉
|
||||
|
||||
- Current version: 1.4.9
|
||||
- Current version: 1.4.5
|
||||
- Status: stable
|
||||
|
||||
This roadmap is only an attempt at predicting Owl's future. Everything may
|
||||
|
||||
@@ -400,7 +400,6 @@ export class Component<Props extends {} = any, T extends Env = Env> {
|
||||
if (currentFiber && !currentFiber.isRendered && !currentFiber.isCompleted) {
|
||||
return scheduler.addFiber(currentFiber.root);
|
||||
}
|
||||
|
||||
// if we aren't mounted at this point, it implies that there is a
|
||||
// currentFiber that is already rendered (isRendered is true), so we are
|
||||
// about to be mounted
|
||||
@@ -506,6 +505,7 @@ export class Component<Props extends {} = any, T extends Env = Env> {
|
||||
const __owl__ = this.__owl__;
|
||||
|
||||
__owl__.status = STATUS.MOUNTED;
|
||||
__owl__.currentFiber = null;
|
||||
this.mounted();
|
||||
if (__owl__.mountedCB) {
|
||||
__owl__.mountedCB();
|
||||
@@ -767,7 +767,7 @@ export async function mount<T extends Type<Component>>(
|
||||
const { env, props, target } = params;
|
||||
let origEnv = C.hasOwnProperty("env") ? (C as any).env : null;
|
||||
if (env) {
|
||||
(C as any as typeof Component).env = env;
|
||||
((C as any) as typeof Component).env = env;
|
||||
}
|
||||
const component: Component = new C(null, props);
|
||||
if (origEnv) {
|
||||
|
||||
@@ -234,11 +234,7 @@ QWeb.addDirective({
|
||||
} else if (!name.startsWith("t-")) {
|
||||
if (name !== "class" && name !== "style") {
|
||||
// this is a prop!
|
||||
if (value.includes("=>")) {
|
||||
props[name] = ctx.captureExpression(value);
|
||||
} else {
|
||||
props[name] = ctx.formatExpression(value) || "undefined";
|
||||
}
|
||||
props[name] = ctx.formatExpression(value) || "undefined";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,6 @@ export class Fiber {
|
||||
// build patchQueue
|
||||
const patchQueue: Fiber[] = [];
|
||||
const doWork: (Fiber) => Fiber | null = function (f) {
|
||||
f.component.__owl__.currentFiber = null;
|
||||
patchQueue.push(f);
|
||||
return f.child;
|
||||
};
|
||||
@@ -243,9 +242,8 @@ export class Fiber {
|
||||
}
|
||||
component.__patch(target!, fiber.vnode!);
|
||||
} else {
|
||||
const vnode = component.__owl__.vnode;
|
||||
if (fiber.shouldPatch && vnode) {
|
||||
component.__patch(vnode, fiber.vnode!);
|
||||
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
|
||||
@@ -257,6 +255,10 @@ export class Fiber {
|
||||
component.__owl__.pvnode!.elm = component.__owl__.vnode!.elm;
|
||||
}
|
||||
}
|
||||
const compOwl = component.__owl__;
|
||||
if (fiber === compOwl.currentFiber) {
|
||||
compOwl.currentFiber = null;
|
||||
}
|
||||
}
|
||||
|
||||
// insert into the DOM (mount case)
|
||||
|
||||
@@ -28,6 +28,8 @@ Object.defineProperty(config, "mode", {
|
||||
|
||||
This is not suitable for production use.
|
||||
See https://github.com/odoo/owl/blob/master/doc/reference/config.md#mode for more information.`);
|
||||
} else {
|
||||
console.log(`Owl is now running in 'prod' mode.`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -326,8 +326,7 @@ QWeb.addDirective({
|
||||
ctx.addLine(`if (!_${arrayID}) { throw new Error('QWeb error: Invalid loop expression')}`);
|
||||
let keysID = ctx.generateID();
|
||||
let valuesID = ctx.generateID();
|
||||
ctx.addLine(`let _${keysID} = _${arrayID};`);
|
||||
ctx.addLine(`let _${valuesID} = _${arrayID};`);
|
||||
ctx.addLine(`let _${keysID} = _${valuesID} = _${arrayID};`);
|
||||
ctx.addIf(`!(_${arrayID} instanceof Array)`);
|
||||
ctx.addLine(`_${keysID} = Object.keys(_${arrayID});`);
|
||||
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
|
||||
|
||||
@@ -163,18 +163,7 @@ export class CompilationContext {
|
||||
const done = new Set();
|
||||
return tokens
|
||||
.map((tok) => {
|
||||
// "this" in captured expressions should be the current component
|
||||
if (tok.value === "this") {
|
||||
if (!done.has("this")) {
|
||||
done.add("this");
|
||||
this.addLine(`const this_${argId} = utils.getComponent(context);`);
|
||||
}
|
||||
tok.value = `this_${argId}`;
|
||||
}
|
||||
// Variables that should be looked up in the scope. isLocal is for arrow
|
||||
// function arguments that should stay untouched (eg "ev => ev" should
|
||||
// not become "const ev_1 = scope['ev']; ev_1 => ev_1")
|
||||
if (tok.varName && !tok.isLocal) {
|
||||
if (tok.varName) {
|
||||
if (!done.has(tok.varName)) {
|
||||
done.add(tok.varName);
|
||||
this.addLine(`const ${tok.varName}_${argId} = ${tok.value};`);
|
||||
|
||||
@@ -25,10 +25,9 @@
|
||||
// Misc types, constants and helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const RESERVED_WORDS =
|
||||
"true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,eval,void,Math,RegExp,Array,Object,Date".split(
|
||||
","
|
||||
);
|
||||
const RESERVED_WORDS = "true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,eval,void,Math,RegExp,Array,Object,Date".split(
|
||||
","
|
||||
);
|
||||
|
||||
const WORD_REPLACEMENT = Object.assign(Object.create(null), {
|
||||
and: "&&",
|
||||
@@ -70,7 +69,6 @@ interface Token {
|
||||
size?: number;
|
||||
varName?: string;
|
||||
replace?: Function;
|
||||
isLocal?: boolean;
|
||||
}
|
||||
|
||||
const STATIC_TOKEN_MAP: { [key: string]: TKind } = Object.assign(Object.create(null), {
|
||||
@@ -255,7 +253,6 @@ const isRightSeparator = (token) =>
|
||||
* the list of variables so it does not get replaced by a lookup in the context
|
||||
*/
|
||||
export function compileExprToArray(expr: string, scope: { [key: string]: QWebVar }): Token[] {
|
||||
const localVars = new Set<string>();
|
||||
scope = Object.create(scope);
|
||||
const tokens = tokenize(expr);
|
||||
|
||||
@@ -310,13 +307,11 @@ export function compileExprToArray(expr: string, scope: { [key: string]: QWebVar
|
||||
if (tokens[j].type === "SYMBOL" && tokens[j].originalValue) {
|
||||
tokens[j].value = tokens[j].originalValue!;
|
||||
scope[tokens[j].value] = { id: tokens[j].value, expr: tokens[j].value };
|
||||
localVars.add(tokens[j].value);
|
||||
}
|
||||
j--;
|
||||
}
|
||||
} else {
|
||||
scope[token.value] = { id: token.value, expr: token.value };
|
||||
localVars.add(token.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,13 +326,6 @@ export function compileExprToArray(expr: string, scope: { [key: string]: QWebVar
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// Mark all variables that have been used locally.
|
||||
// This assumes the expression has only one scope (incorrect but "good enough for now")
|
||||
for (const token of tokens) {
|
||||
if (token.type === "SYMBOL" && localVars.has(token.value)) {
|
||||
token.isLocal = true;
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,7 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['state'].s;
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -69,8 +68,7 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
|
||||
let key1 = i1;
|
||||
let _6 = scope['section'].blips;
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _6;
|
||||
let _8 = _6;
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
@@ -311,8 +309,7 @@ exports[`composition sub components with some state rendered in a loop 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['state'].numbers;
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -600,8 +597,7 @@ exports[`other directives with t-component t-on expression captured in t-foreach
|
||||
scope.iter = 0;
|
||||
let _2 = scope['arr'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -643,8 +639,7 @@ exports[`other directives with t-component t-on expression in t-foreach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['state'].values;
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -696,8 +691,7 @@ exports[`other directives with t-component t-on expression in t-foreach with t-s
|
||||
scope.bossa = 'nova';
|
||||
let _2 = scope['state'].values;
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -750,8 +744,7 @@ exports[`other directives with t-component t-on method call in t-foreach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['state'].values;
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -1417,8 +1410,7 @@ exports[`other directives with t-component t-set outside modified in t-foreach 1
|
||||
scope.iter = 0;
|
||||
let _2 = scope['state'].values;
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -1454,350 +1446,6 @@ exports[`other directives with t-component t-set outside modified in t-foreach 1
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures component instance as 'this' 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Parent\\"
|
||||
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);
|
||||
// Component 'Child'
|
||||
const this_2 = utils.getComponent(context);
|
||||
let w3 = '__4__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__4__']] : false;
|
||||
let props3 = {callback:value=>this_2.setValue(value),value:scope['state'].val};
|
||||
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 = scope['Child'] || context.constructor.components[componentKey3] || QWeb.components[componentKey3];
|
||||
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[`props evaluation arrow function prop captures component instance as 'this' 2`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Child\\"
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c5 = [], p5 = {key:5};
|
||||
let vn5 = h('span', p5, c5);
|
||||
let _6 = scope['props'].value;
|
||||
if (_6 != null) {
|
||||
c5.push({text: _6});
|
||||
}
|
||||
return vn5;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures context component instance as 'this' inside slot 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Parent\\"
|
||||
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);
|
||||
// Component 'Wrapper'
|
||||
let w2 = '__3__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__3__']] : false;
|
||||
let props2 = {};
|
||||
if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) {
|
||||
w2.destroy();
|
||||
w2 = false;
|
||||
}
|
||||
if (w2) {
|
||||
w2.__updateProps(props2, extra.fiber, utils.combine(context, scope));
|
||||
let pvnode = w2.__owl__.pvnode;
|
||||
c1.push(pvnode);
|
||||
} else {
|
||||
let componentKey2 = \`Wrapper\`;
|
||||
let W2 = scope['Wrapper'] || context.constructor.components[componentKey2] || QWeb.components[componentKey2];
|
||||
if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')}
|
||||
w2 = new W2(parent, props2);
|
||||
parent.__owl__.cmap['__3__'] = w2.__owl__.id;
|
||||
w2.__owl__.slotId = 1;
|
||||
let fiber = w2.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
|
||||
let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}});
|
||||
c1.push(pvnode);
|
||||
w2.__owl__.pvnode = pvnode;
|
||||
}
|
||||
w2.__owl__.parentLastFiberId = extra.fiber.id;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures context component instance as 'this' inside slot 2`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Wrapper\\"
|
||||
let utils = this.constructor.utils;
|
||||
let result;
|
||||
let h = this.h;
|
||||
const slot8 = this.constructor.slots[context.__owl__.slotId + '_' + 'default'];
|
||||
if (slot8) {
|
||||
let children9= []
|
||||
result = {}
|
||||
slot8.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: children9, parent: extra.parent || context}));
|
||||
utils.defineProxy(result, children9[0]);
|
||||
}
|
||||
return result;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures context component instance as 'this' inside slot 3`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"slot_default_template\\"
|
||||
let utils = this.constructor.utils;
|
||||
let QWeb = this.constructor;
|
||||
let parent = extra.parent;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c4 = extra.parentNode;
|
||||
// Component 'Child'
|
||||
const this_5 = utils.getComponent(context);
|
||||
let w6 = '__7__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__7__']] : false;
|
||||
let props6 = {callback:value=>this_5.setValue(value),value:scope['state'].val};
|
||||
if (w6 && w6.__owl__.currentFiber && !w6.__owl__.vnode) {
|
||||
w6.destroy();
|
||||
w6 = false;
|
||||
}
|
||||
if (w6) {
|
||||
w6.__updateProps(props6, extra.fiber, undefined);
|
||||
let pvnode = w6.__owl__.pvnode;
|
||||
c4.push(pvnode);
|
||||
} else {
|
||||
let componentKey6 = \`Child\`;
|
||||
let W6 = scope['Child'] || context.constructor.components[componentKey6] || QWeb.components[componentKey6];
|
||||
if (!W6) {throw new Error('Cannot find the definition of component \\"' + componentKey6 + '\\"')}
|
||||
w6 = new W6(parent, props6);
|
||||
parent.__owl__.cmap['__7__'] = w6.__owl__.id;
|
||||
let fiber = w6.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
|
||||
let pvnode = h('dummy', {key: '__7__', hook: {remove() {},destroy(vn) {w6.destroy();}}});
|
||||
c4.push(pvnode);
|
||||
w6.__owl__.pvnode = pvnode;
|
||||
}
|
||||
w6.__owl__.parentLastFiberId = extra.fiber.id;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures context component instance as 'this' inside slot 4`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Child\\"
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c10 = [], p10 = {key:10};
|
||||
let vn10 = h('span', p10, c10);
|
||||
let _11 = scope['props'].value;
|
||||
if (_11 != null) {
|
||||
c10.push({text: _11});
|
||||
}
|
||||
return vn10;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures context component instance as 'this' inside slot default content 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Parent\\"
|
||||
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);
|
||||
// Component 'Wrapper'
|
||||
let w2 = '__3__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__3__']] : false;
|
||||
let props2 = {};
|
||||
if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) {
|
||||
w2.destroy();
|
||||
w2 = false;
|
||||
}
|
||||
if (w2) {
|
||||
w2.__updateProps(props2, extra.fiber, undefined);
|
||||
let pvnode = w2.__owl__.pvnode;
|
||||
c1.push(pvnode);
|
||||
} else {
|
||||
let componentKey2 = \`Wrapper\`;
|
||||
let W2 = scope['Wrapper'] || context.constructor.components[componentKey2] || QWeb.components[componentKey2];
|
||||
if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')}
|
||||
w2 = new W2(parent, props2);
|
||||
parent.__owl__.cmap['__3__'] = w2.__owl__.id;
|
||||
let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
|
||||
let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}});
|
||||
c1.push(pvnode);
|
||||
w2.__owl__.pvnode = pvnode;
|
||||
}
|
||||
w2.__owl__.parentLastFiberId = extra.fiber.id;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures context component instance as 'this' inside slot default content 2`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Wrapper\\"
|
||||
let utils = this.constructor.utils;
|
||||
let QWeb = this.constructor;
|
||||
let parent = context;
|
||||
let scope = Object.create(context);
|
||||
let result;
|
||||
let h = this.h;
|
||||
const slot4 = this.constructor.slots[context.__owl__.slotId + '_' + 'default'];
|
||||
if (slot4) {
|
||||
let children5= []
|
||||
result = {}
|
||||
slot4.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: children5, parent: extra.parent || context}));
|
||||
utils.defineProxy(result, children5[0]);
|
||||
} else {
|
||||
// Component 'Child'
|
||||
const this_6 = utils.getComponent(context);
|
||||
let w7 = '__8__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__8__']] : false;
|
||||
let vn9 = {};
|
||||
result = vn9;
|
||||
let props7 = {callback:value=>this_6.setValue(value),value:scope['state'].val};
|
||||
if (w7 && w7.__owl__.currentFiber && !w7.__owl__.vnode) {
|
||||
w7.destroy();
|
||||
w7 = false;
|
||||
}
|
||||
if (w7) {
|
||||
w7.__updateProps(props7, extra.fiber, undefined);
|
||||
let pvnode = w7.__owl__.pvnode;
|
||||
utils.defineProxy(vn9, pvnode);
|
||||
} else {
|
||||
let componentKey7 = \`Child\`;
|
||||
let W7 = scope['Child'] || context.constructor.components[componentKey7] || QWeb.components[componentKey7];
|
||||
if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
|
||||
w7 = new W7(parent, props7);
|
||||
parent.__owl__.cmap['__8__'] = w7.__owl__.id;
|
||||
let fiber = w7.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
|
||||
let pvnode = h('dummy', {key: '__8__', hook: {remove() {},destroy(vn) {w7.destroy();}}});
|
||||
utils.defineProxy(vn9, pvnode);
|
||||
w7.__owl__.pvnode = pvnode;
|
||||
}
|
||||
w7.__owl__.parentLastFiberId = extra.fiber.id;
|
||||
}
|
||||
return result;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures context component instance as 'this' inside slot default content 3`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Child\\"
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c10 = [], p10 = {key:10};
|
||||
let vn10 = h('span', p10, c10);
|
||||
let _11 = scope['props'].value;
|
||||
if (_11 != null) {
|
||||
c10.push({text: _11});
|
||||
}
|
||||
return vn10;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures loop variables 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Parent\\"
|
||||
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 _2 = [0,1];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _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.loopVar_first = i1 === 0
|
||||
scope.loopVar_last = i1 === _length3 - 1
|
||||
scope.loopVar_index = i1
|
||||
scope.loopVar = _3[i1]
|
||||
scope.loopVar_value = _4[i1]
|
||||
let key1 = scope['loopVar'];
|
||||
// Component 'Child'
|
||||
const this_6 = utils.getComponent(context);
|
||||
const loopVar_6 = scope['loopVar'];
|
||||
let k8 = \`__8__\${key1}__\`;
|
||||
let w7 = k8 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k8]] : false;
|
||||
let props7 = {callback:()=>this_6.setValue(loopVar_6),value:scope['state'].val};
|
||||
if (w7 && w7.__owl__.currentFiber && !w7.__owl__.vnode) {
|
||||
w7.destroy();
|
||||
w7 = false;
|
||||
}
|
||||
if (w7) {
|
||||
w7.__updateProps(props7, extra.fiber, undefined);
|
||||
let pvnode = w7.__owl__.pvnode;
|
||||
c1.push(pvnode);
|
||||
} else {
|
||||
let componentKey7 = \`Child\`;
|
||||
let W7 = scope['Child'] || context.constructor.components[componentKey7] || QWeb.components[componentKey7];
|
||||
if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
|
||||
w7 = new W7(parent, props7);
|
||||
parent.__owl__.cmap[k8] = w7.__owl__.id;
|
||||
let fiber = w7.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
|
||||
let pvnode = h('dummy', {key: k8, hook: {remove() {},destroy(vn) {w7.destroy();}}});
|
||||
c1.push(pvnode);
|
||||
w7.__owl__.pvnode = pvnode;
|
||||
}
|
||||
w7.__owl__.parentLastFiberId = extra.fiber.id;
|
||||
}
|
||||
scope = _origScope5;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation arrow function prop captures loop variables 2`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"Child\\"
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c9 = [], p9 = {key:9};
|
||||
let vn9 = h('span', p9, c9);
|
||||
let _10 = scope['props'].value;
|
||||
if (_10 != null) {
|
||||
c9.push({text: _10});
|
||||
}
|
||||
return vn9;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`props evaluation t-set with a body expression can be used as textual prop 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -1912,8 +1560,7 @@ exports[`random stuff/miscellaneous t-on with handler bound to dynamic argument
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['items'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -2191,8 +1838,7 @@ exports[`t-model directive in a t-foreach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['state'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -2232,8 +1878,7 @@ exports[`t-model directive in a t-foreach, part 2 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['state'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
|
||||
@@ -414,8 +414,7 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = `
|
||||
c1.push(vn2);
|
||||
let _3 = scope['state'].users;
|
||||
if (!_3) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _4 = _3;
|
||||
let _5 = _3;
|
||||
let _4 = _5 = _3;
|
||||
if (!(_3 instanceof Array)) {
|
||||
_4 = Object.keys(_3);
|
||||
_5 = Object.values(_3);
|
||||
@@ -513,8 +512,7 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = `
|
||||
c1.push(vn2);
|
||||
let _3 = scope['state'].users;
|
||||
if (!_3) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _4 = _3;
|
||||
let _5 = _3;
|
||||
let _4 = _5 = _3;
|
||||
if (!(_3 instanceof Array)) {
|
||||
_4 = Object.keys(_3);
|
||||
_5 = Object.values(_3);
|
||||
@@ -647,8 +645,7 @@ exports[`t-slot directive slots in t-foreach in t-foreach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['tree'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -675,8 +672,7 @@ exports[`t-slot directive slots in t-foreach in t-foreach 1`] = `
|
||||
c1.push(vn8);
|
||||
let _9 = scope['node1'].nodes;
|
||||
if (!_9) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _10 = _9;
|
||||
let _11 = _9;
|
||||
let _10 = _11 = _9;
|
||||
if (!(_9 instanceof Array)) {
|
||||
_10 = Object.keys(_9);
|
||||
_11 = Object.values(_9);
|
||||
|
||||
@@ -1388,62 +1388,6 @@ describe("async rendering", () => {
|
||||
expect(fixture.innerHTML).toBe("<span>4</span>");
|
||||
});
|
||||
|
||||
test("calling render in destroy", async () => {
|
||||
let a: any = null;
|
||||
let c: any = null;
|
||||
|
||||
class C extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<t t-esc="props.fromA"/>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
let flag = false;
|
||||
class B extends Component {
|
||||
static template = xml`<C fromA="props.fromA"/>`;
|
||||
static components = { C };
|
||||
|
||||
setup() {
|
||||
c = this;
|
||||
}
|
||||
|
||||
mounted() {
|
||||
if (flag) {
|
||||
this.render();
|
||||
} else {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
willUnmount() {
|
||||
c.render();
|
||||
}
|
||||
}
|
||||
|
||||
class A extends Component {
|
||||
static template = xml`<B t-key="key" fromA="state"/>`;
|
||||
static components = { B };
|
||||
state = "a";
|
||||
key = 1;
|
||||
|
||||
setup() {
|
||||
a = this;
|
||||
}
|
||||
}
|
||||
|
||||
const parent = new A();
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div>a</div>");
|
||||
|
||||
a.state = "A";
|
||||
a.key = 2;
|
||||
await a.render();
|
||||
// this nextTick is critical, otherwise jest may silently swallow errors
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div>A</div>");
|
||||
});
|
||||
|
||||
test("change state and call manually render: no unnecessary rendering", async () => {
|
||||
class Widget extends Component {
|
||||
static template = xml`<div><t t-esc="state.val"/></div>`;
|
||||
|
||||
@@ -265,8 +265,7 @@ describe("class and style attributes with t-component", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
expect(fixture.innerHTML).toBe("");
|
||||
});
|
||||
|
||||
@@ -1881,176 +1881,6 @@ describe("props evaluation ", () => {
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span><p>4343</p><p>43</p></span></div>");
|
||||
});
|
||||
|
||||
test("arrow function prop captures component instance as 'this'", async () => {
|
||||
expect.assertions(5);
|
||||
let child, parent;
|
||||
class Child extends Component {
|
||||
setup() {
|
||||
child = this;
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate("Child", `<span><t t-esc="props.value"/></span>`);
|
||||
|
||||
class Parent extends Component {
|
||||
static components = { Child };
|
||||
state = useState({ val: 42 });
|
||||
setup() {
|
||||
parent = this;
|
||||
}
|
||||
setValue(value) {
|
||||
expect(this).toBe(parent);
|
||||
this.state.val = value;
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div>
|
||||
<Child callback="value => this.setValue(value)" value="state.val"/>
|
||||
</div>`
|
||||
);
|
||||
|
||||
const widget = new Parent();
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span>42</span></div>");
|
||||
child.props.callback(123);
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>123</span></div>");
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(env.qweb.templates.Child.fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("arrow function prop captures context component instance as 'this' inside slot", async () => {
|
||||
expect.assertions(7);
|
||||
let child, parent;
|
||||
class Child extends Component {
|
||||
setup() {
|
||||
child = this;
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate("Child", `<span><t t-esc="props.value"/></span>`);
|
||||
|
||||
class Wrapper extends Component {}
|
||||
env.qweb.addTemplate("Wrapper", `<t t-slot="default"/>`);
|
||||
|
||||
class Parent extends Component {
|
||||
static components = { Child, Wrapper };
|
||||
state = useState({ val: 42 });
|
||||
setup() {
|
||||
parent = this;
|
||||
}
|
||||
setValue(value) {
|
||||
expect(this).toBe(parent);
|
||||
this.state.val = value;
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div>
|
||||
<Wrapper>
|
||||
<Child callback="value => this.setValue(value)" value="state.val"/>
|
||||
</Wrapper>
|
||||
</div>`
|
||||
);
|
||||
|
||||
const widget = new Parent();
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span>42</span></div>");
|
||||
child.props.callback(123);
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>123</span></div>");
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(env.qweb.templates.Wrapper.fn.toString()).toMatchSnapshot();
|
||||
expect(QWeb.slots["1_default"].toString()).toMatchSnapshot();
|
||||
expect(env.qweb.templates.Child.fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("arrow function prop captures context component instance as 'this' inside slot default content", async () => {
|
||||
expect.assertions(6);
|
||||
let child, wrapper;
|
||||
class Child extends Component {
|
||||
setup() {
|
||||
child = this;
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate("Child", `<span><t t-esc="props.value"/></span>`);
|
||||
|
||||
class Wrapper extends Component {
|
||||
static components = { Child };
|
||||
state = useState({ val: 42 });
|
||||
setup() {
|
||||
wrapper = this;
|
||||
}
|
||||
setValue(value) {
|
||||
expect(this).toBe(wrapper);
|
||||
this.state.val = value;
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate(
|
||||
"Wrapper",
|
||||
`<t t-slot="default">
|
||||
<Child callback="value => this.setValue(value)" value="state.val"/>
|
||||
</t>`
|
||||
);
|
||||
|
||||
class Parent extends Component {
|
||||
static components = { Wrapper };
|
||||
}
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div>
|
||||
<Wrapper/>
|
||||
</div>`
|
||||
);
|
||||
|
||||
const widget = new Parent();
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span>42</span></div>");
|
||||
child.props.callback(123);
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>123</span></div>");
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(env.qweb.templates.Wrapper.fn.toString()).toMatchSnapshot();
|
||||
expect(env.qweb.templates.Child.fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("arrow function prop captures loop variables", async () => {
|
||||
let children = [];
|
||||
class Child extends Component {
|
||||
setup() {
|
||||
children.push(this);
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate("Child", `<span><t t-esc="props.value"/></span>`);
|
||||
|
||||
class Parent extends Component {
|
||||
static components = { Child };
|
||||
state = useState({ val: 42 });
|
||||
setValue(value) {
|
||||
this.state.val = value;
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div>
|
||||
<t t-foreach="[0, 1]" t-as="loopVar" t-key="loopVar">
|
||||
<Child callback="() => this.setValue(loopVar)" value="state.val"/>
|
||||
</t>
|
||||
</div>`
|
||||
);
|
||||
|
||||
const widget = new Parent();
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span>42</span><span>42</span></div>");
|
||||
children[0].props.callback();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>0</span><span>0</span></div>");
|
||||
children[1].props.callback();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>1</span><span>1</span></div>");
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(env.qweb.templates.Child.fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("other directives with t-component", () => {
|
||||
|
||||
@@ -361,8 +361,7 @@ describe("component error handling (catchError)", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
|
||||
expect(console.error).toBeCalledTimes(0);
|
||||
@@ -473,8 +472,7 @@ describe("component error handling (catchError)", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
|
||||
expect(console.error).toBeCalledTimes(0);
|
||||
@@ -501,8 +499,7 @@ describe("component error handling (catchError)", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
|
||||
expect(console.error).toBeCalledTimes(0);
|
||||
@@ -526,8 +523,7 @@ describe("component error handling (catchError)", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'y'\)|Cannot read property 'y' of undefined/g;
|
||||
const regexp = /Cannot read properties of undefined \(reading 'y'\)|Cannot read property 'y' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
});
|
||||
|
||||
|
||||
@@ -546,8 +546,7 @@ describe("Portal: Basic use and DOM placement", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
});
|
||||
|
||||
|
||||
@@ -429,8 +429,7 @@ exports[`foreach does not pollute the rendering context 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = [1];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -465,8 +464,7 @@ exports[`foreach iterate on items (on a element node) 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = [1,2];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -504,8 +502,7 @@ exports[`foreach iterate on items 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = [3,2,1];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -552,8 +549,7 @@ exports[`foreach iterate, dict param 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['value'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -600,8 +596,7 @@ exports[`foreach iterate, position 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = Array(5);
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -646,8 +641,7 @@ exports[`foreach t-call with body in t-foreach in t-foreach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['numbers'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -664,8 +658,7 @@ exports[`foreach t-call with body in t-foreach in t-foreach 1`] = `
|
||||
let key1 = i1;
|
||||
let _6 = scope['letters'];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _6;
|
||||
let _8 = _6;
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
@@ -736,8 +729,7 @@ exports[`foreach t-call without body in t-foreach in t-foreach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['numbers'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -754,8 +746,7 @@ exports[`foreach t-call without body in t-foreach in t-foreach 1`] = `
|
||||
let key1 = i1;
|
||||
let _6 = scope['letters'];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _6;
|
||||
let _8 = _6;
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
@@ -820,8 +811,7 @@ exports[`foreach t-foreach in t-forach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['numbers'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -838,8 +828,7 @@ exports[`foreach t-foreach in t-forach 1`] = `
|
||||
let key1 = i1;
|
||||
let _6 = scope['letters'];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _6;
|
||||
let _8 = _6;
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
@@ -882,8 +871,7 @@ exports[`foreach warn if no key in some case 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = [1,2];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -952,8 +940,7 @@ exports[`misc global 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = [4,5,6];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -1679,8 +1666,7 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
|
||||
}
|
||||
let _6 = scope['node'].children||[];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _6;
|
||||
let _8 = _6;
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
@@ -1760,8 +1746,7 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
|
||||
}
|
||||
let _6 = scope['node'].children||[];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _6;
|
||||
let _8 = _6;
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
@@ -1847,8 +1832,7 @@ exports[`t-call (template calling recursive template, part 4: with t-set recursi
|
||||
}
|
||||
let _6 = scope['node'].children||[];
|
||||
if (!_6) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _7 = _6;
|
||||
let _8 = _6;
|
||||
let _7 = _8 = _6;
|
||||
if (!(_6 instanceof Array)) {
|
||||
_7 = Object.keys(_6);
|
||||
_8 = Object.values(_6);
|
||||
@@ -2014,8 +1998,7 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['list'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -2792,8 +2775,7 @@ exports[`t-key t-key directive in a list 1`] = `
|
||||
let vn1 = h('ul', p1, c1);
|
||||
let _2 = scope['beers'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -2897,8 +2879,7 @@ exports[`t-on can bind handlers with loop variable as argument 1`] = `
|
||||
let vn1 = h('ul', p1, c1);
|
||||
let _2 = ['someval'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -3180,8 +3161,7 @@ exports[`t-on t-on with prevent modifier in t-foreach 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['projects'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -3452,8 +3432,7 @@ exports[`t-ref refs in a loop 1`] = `
|
||||
let vn1 = h('div', p1, c1);
|
||||
let _2 = scope['items'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
@@ -3697,8 +3676,7 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
|
||||
scope.v = 1;
|
||||
let _2 = scope['list'];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _4 = _2;
|
||||
let _3 = _4 = _2;
|
||||
if (!(_2 instanceof Array)) {
|
||||
_3 = Object.keys(_2);
|
||||
_4 = Object.values(_2);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`memory t-foreach does not leak stuff in global scope 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('p', p1, c1);
|
||||
let _2 = [3,2,1];
|
||||
if (!_2) { throw new Error('QWeb error: Invalid loop expression')}
|
||||
let _3 = _2;
|
||||
let _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.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;
|
||||
}"
|
||||
`;
|
||||
@@ -1,14 +0,0 @@
|
||||
import { QWeb } from "../../src/qweb/index";
|
||||
import { renderToString } from "../helpers";
|
||||
|
||||
describe("memory", () => {
|
||||
test("t-foreach does not leak stuff in global scope", () => {
|
||||
let qweb = new QWeb();
|
||||
const initialNumberOfGlobals = Object.keys(window).length;
|
||||
qweb.addTemplate("test", `<p><t t-foreach="[3, 2, 1]" t-as="item"><t t-esc="item"/></t></p>`);
|
||||
const result = renderToString(qweb, "test");
|
||||
const expected = `<p>321</p>`;
|
||||
expect(result).toBe(expected);
|
||||
expect(Object.keys(window).length).toBe(initialNumberOfGlobals);
|
||||
});
|
||||
});
|
||||
+40
-1
@@ -62,6 +62,9 @@ async function startRelease() {
|
||||
}
|
||||
let shouldUploadPlayground = await ask(`Should this release be uploaded on the playground [y/n] ? (y)`);
|
||||
shouldUploadPlayground = shouldUploadPlayground.toLowerCase() !== 'n';
|
||||
|
||||
let shouldUploadPCoverageReport = await ask(`Should this release coverage report be published [y/n] ? (y)`);
|
||||
shouldUploadPCoverageReport = shouldUploadPCoverageReport.toLowerCase() !== 'n';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
log(`Step 2/${STEPS}: running tests...`);
|
||||
@@ -122,7 +125,7 @@ async function startRelease() {
|
||||
if (shouldUploadPlayground) {
|
||||
log(`Bonus step: publishing new release on playground...`);
|
||||
let owl_code = null;
|
||||
status = 0
|
||||
let status = 0
|
||||
|
||||
try {
|
||||
owl_code = await readFile("dist/owl.iife.js");
|
||||
@@ -153,6 +156,42 @@ async function startRelease() {
|
||||
logError("Something went wrong for the playground update.")
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldUploadPCoverageReport) {
|
||||
let status = 0
|
||||
log(`Bonus step: publishing new coverage report...`);
|
||||
|
||||
if (!fs.existsSync("./coverage")) {
|
||||
logError("Couldn't update coverage report, there is no coverage folder on master.")
|
||||
return;
|
||||
}
|
||||
|
||||
status += await execCommand("git stash push -a -- coverage");
|
||||
if (status !== 0) {
|
||||
logError("Couldn't stash coverage")
|
||||
return;
|
||||
}
|
||||
|
||||
status += await execCommand("git checkout gh-pages");
|
||||
if (status !== 0) {
|
||||
logError("Couldn't switch to gh-pages branch")
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
status += await execCommand("rm -rf coverage");
|
||||
status += await execCommand("git stash pop");
|
||||
status += await execCommand("git add coverage");
|
||||
status += await execCommand(`git commit -m "[IMP] update coverage report for owl v${next}"`);
|
||||
status += await execCommand(`git push origin gh-pages`);
|
||||
status += await execCommand("git checkout -");
|
||||
|
||||
if (status !== 0) {
|
||||
logError("Something went wrong for the coverage report update.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@
|
||||
// "compileOnSave": false, // Signals to the IDE to generate all files for a given tsconfig.json upon saving.
|
||||
"compilerOptions": {
|
||||
// Main options
|
||||
"target": "es2017", // Specify ECMAScript target version: 'es3' (default), 'es5', 'es2015', 'es2016', 'es2017','es2018' or 'esnext'.
|
||||
"module": "es6", // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
|
||||
"target": "esnext", // Specify ECMAScript target version: 'es3' (default), 'es5', 'es2015', 'es2016', 'es2017','es2018' or 'esnext'.
|
||||
"module": "esnext", // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
|
||||
// "lib": ["esnext", "dom"], // Specify library files to be included in the compilation.
|
||||
// "allowJs": false, // Allow javascript files to be compiled.
|
||||
// "checkJs": false, // Report errors in .js files.
|
||||
|
||||
Reference in New Issue
Block a user