mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e3b7c74da | |||
| 98bb2842d8 | |||
| 6e185f987b | |||
| c0f495661d | |||
| 0f7a8289a6 | |||
| 1c3b04f6a8 | |||
| 64db7777dd | |||
| 37313c47a3 | |||
| 3f563de9c0 | |||
| 97564a7612 | |||
| f1abf7f2ea | |||
| 8464a1b04e | |||
| c0a62dfd05 | |||
| 600f1e35d4 | |||
| b3181f119d | |||
| 1e1e05350a | |||
| b242230e20 |
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [12.x, 14.x]
|
node-version: [12.x, 14.x, 16.x]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<h1 align="center">🦉 <a href="https://odoo.github.io/owl/">OWL Framework</a> 🦉</h1>
|
<h1 align="center">🦉 <a href="https://odoo.github.io/owl/">OWL Framework</a> 🦉</h1>
|
||||||
|
|
||||||
|
[](https://www.gnu.org/licenses/lgpl-3.0)
|
||||||
|
[](https://badge.fury.io/js/@odoo%2Fowl)
|
||||||
|
[](https://www.npmjs.com/package/@odoo/owl)
|
||||||
|
|
||||||
_Class based components with hooks, reactive state and concurrent mode_
|
_Class based components with hooks, reactive state and concurrent mode_
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
@@ -120,7 +124,7 @@ npm install @odoo/owl
|
|||||||
|
|
||||||
If you want to use a simple `<script>` tag, the last release can be downloaded here:
|
If you want to use a simple `<script>` tag, the last release can be downloaded here:
|
||||||
|
|
||||||
- [owl-1.4.3](https://github.com/odoo/owl/releases/tag/v1.4.3)
|
- [owl-1.4.7](https://github.com/odoo/owl/releases/tag/v1.4.7)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,9 @@ just put the following code:
|
|||||||
Note that we put everything inside an immediately executed function to avoid leaking
|
Note that we put everything inside an immediately executed function to avoid leaking
|
||||||
anything to the global scope.
|
anything to the global scope.
|
||||||
|
|
||||||
Finally, `owl.js` should be the last version downloaded from the Owl repository (you can use `owl.min.js` if you prefer).
|
Finally, `owl.js` should be the last version downloaded from the Owl repository (you can use `owl.min.js` if you prefer). Be aware that you should download the `owl.iife.js` or `owl.iife.min.js`, because these files
|
||||||
|
are built to run directly on the browser (other files such as `owl.cjs.js` are
|
||||||
|
built to be bundled by other tools).
|
||||||
|
|
||||||
Now, the project should be ready. Loading the `index.html` file into a browser
|
Now, the project should be ready. Loading the `index.html` file into a browser
|
||||||
should show an empty page, with the title `Owl Todo App`, and it should log a
|
should show an empty page, with the title `Owl Todo App`, and it should log a
|
||||||
|
|||||||
+8
-7
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@odoo/owl",
|
"name": "@odoo/owl",
|
||||||
"version": "1.4.3",
|
"version": "1.4.7",
|
||||||
"description": "Odoo Web Library (OWL)",
|
"description": "Odoo Web Library (OWL)",
|
||||||
"main": "dist/owl.cjs.js",
|
"main": "dist/owl.cjs.js",
|
||||||
"browser": "dist/owl.iife.js",
|
"browser": "dist/owl.iife.js",
|
||||||
@@ -37,28 +37,29 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/odoo/owl#readme",
|
"homepage": "https://github.com/odoo/owl#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^23.3.14",
|
"@types/jest": "^27.0.1",
|
||||||
"@types/node": "^14.11.8",
|
"@types/node": "^14.11.8",
|
||||||
"chalk": "^3.0.0",
|
"chalk": "^3.0.0",
|
||||||
"cpx": "^1.5.0",
|
"cpx": "^1.5.0",
|
||||||
"current-git-branch": "^1.1.0",
|
"current-git-branch": "^1.1.0",
|
||||||
"git-rev-sync": "^1.12.0",
|
"git-rev-sync": "^1.12.0",
|
||||||
"github-api": "^3.3.0",
|
"github-api": "^3.3.0",
|
||||||
"jest": "^23.6.0",
|
"jest": "^27.1.0",
|
||||||
"jest-environment-jsdom": "^24.7.1",
|
"jest-environment-jsdom": "^27.1.0",
|
||||||
"live-server": "^1.2.1",
|
"live-server": "^1.2.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^2.0.4",
|
"prettier": "^2.0.4",
|
||||||
"rollup": "^1.6.0",
|
"rollup": "^2.56.3",
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"rollup-plugin-typescript2": "^0.27.3",
|
"rollup-plugin-typescript2": "^0.30.0",
|
||||||
"sass": "^1.16.1",
|
"sass": "^1.16.1",
|
||||||
"source-map-support": "^0.5.10",
|
"source-map-support": "^0.5.10",
|
||||||
"ts-jest": "^23.10.5",
|
"ts-jest": "^27.0.5",
|
||||||
"typescript": "^3.7.2",
|
"typescript": "^3.7.2",
|
||||||
"uglify-es": "^3.3.9"
|
"uglify-es": "^3.3.9"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
|
"testEnvironment": "jsdom",
|
||||||
"roots": [
|
"roots": [
|
||||||
"<rootDir>/src",
|
"<rootDir>/src",
|
||||||
"<rootDir>/tests"
|
"<rootDir>/tests"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# 🦉 OWL Roadmap 🦉
|
# 🦉 OWL Roadmap 🦉
|
||||||
|
|
||||||
- Current version: 1.4.3
|
- Current version: 1.4.7
|
||||||
- Status: stable
|
- Status: stable
|
||||||
|
|
||||||
This roadmap is only an attempt at predicting Owl's future. Everything may
|
This roadmap is only an attempt at predicting Owl's future. Everything may
|
||||||
|
|||||||
@@ -400,6 +400,7 @@ export class Component<Props extends {} = any, T extends Env = Env> {
|
|||||||
if (currentFiber && !currentFiber.isRendered && !currentFiber.isCompleted) {
|
if (currentFiber && !currentFiber.isRendered && !currentFiber.isCompleted) {
|
||||||
return scheduler.addFiber(currentFiber.root);
|
return scheduler.addFiber(currentFiber.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we aren't mounted at this point, it implies that there is a
|
// 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
|
// currentFiber that is already rendered (isRendered is true), so we are
|
||||||
// about to be mounted
|
// about to be mounted
|
||||||
@@ -505,7 +506,6 @@ export class Component<Props extends {} = any, T extends Env = Env> {
|
|||||||
const __owl__ = this.__owl__;
|
const __owl__ = this.__owl__;
|
||||||
|
|
||||||
__owl__.status = STATUS.MOUNTED;
|
__owl__.status = STATUS.MOUNTED;
|
||||||
__owl__.currentFiber = null;
|
|
||||||
this.mounted();
|
this.mounted();
|
||||||
if (__owl__.mountedCB) {
|
if (__owl__.mountedCB) {
|
||||||
__owl__.mountedCB();
|
__owl__.mountedCB();
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ export class Fiber {
|
|||||||
// build patchQueue
|
// build patchQueue
|
||||||
const patchQueue: Fiber[] = [];
|
const patchQueue: Fiber[] = [];
|
||||||
const doWork: (Fiber) => Fiber | null = function (f) {
|
const doWork: (Fiber) => Fiber | null = function (f) {
|
||||||
|
f.component.__owl__.currentFiber = null;
|
||||||
patchQueue.push(f);
|
patchQueue.push(f);
|
||||||
return f.child;
|
return f.child;
|
||||||
};
|
};
|
||||||
@@ -255,10 +256,6 @@ export class Fiber {
|
|||||||
component.__owl__.pvnode!.elm = component.__owl__.vnode!.elm;
|
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)
|
// insert into the DOM (mount case)
|
||||||
|
|||||||
+5
-3
@@ -1,4 +1,5 @@
|
|||||||
import { QWeb } from "./qweb/index";
|
import { QWeb } from "./qweb/index";
|
||||||
|
import { TRANSLATABLE_ATTRS } from "./qweb/qweb";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file creates and exports the OWL 'config' object, with keys:
|
* This file creates and exports the OWL 'config' object, with keys:
|
||||||
@@ -9,9 +10,12 @@ import { QWeb } from "./qweb/index";
|
|||||||
interface Config {
|
interface Config {
|
||||||
mode: string;
|
mode: string;
|
||||||
enableTransitions: boolean;
|
enableTransitions: boolean;
|
||||||
|
translatableAttributes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const config = {} as Config;
|
export const config = {
|
||||||
|
translatableAttributes: TRANSLATABLE_ATTRS,
|
||||||
|
} as Config;
|
||||||
|
|
||||||
Object.defineProperty(config, "mode", {
|
Object.defineProperty(config, "mode", {
|
||||||
get() {
|
get() {
|
||||||
@@ -24,8 +28,6 @@ Object.defineProperty(config, "mode", {
|
|||||||
|
|
||||||
This is not suitable for production use.
|
This is not suitable for production use.
|
||||||
See https://github.com/odoo/owl/blob/master/doc/reference/config.md#mode for more information.`);
|
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,7 +326,8 @@ QWeb.addDirective({
|
|||||||
ctx.addLine(`if (!_${arrayID}) { throw new Error('QWeb error: Invalid loop expression')}`);
|
ctx.addLine(`if (!_${arrayID}) { throw new Error('QWeb error: Invalid loop expression')}`);
|
||||||
let keysID = ctx.generateID();
|
let keysID = ctx.generateID();
|
||||||
let valuesID = ctx.generateID();
|
let valuesID = ctx.generateID();
|
||||||
ctx.addLine(`let _${keysID} = _${valuesID} = _${arrayID};`);
|
ctx.addLine(`let _${keysID} = _${arrayID};`);
|
||||||
|
ctx.addLine(`let _${valuesID} = _${arrayID};`);
|
||||||
ctx.addIf(`!(_${arrayID} instanceof Array)`);
|
ctx.addIf(`!(_${arrayID} instanceof Array)`);
|
||||||
ctx.addLine(`_${keysID} = Object.keys(_${arrayID});`);
|
ctx.addLine(`_${keysID} = Object.keys(_${arrayID});`);
|
||||||
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
|
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
|
||||||
|
|||||||
+16
-5
@@ -66,7 +66,7 @@ interface QWebConfig {
|
|||||||
// Const/global stuff/helpers
|
// Const/global stuff/helpers
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
|
export const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
|
||||||
|
|
||||||
const lineBreakRE = /[\r\n]/;
|
const lineBreakRE = /[\r\n]/;
|
||||||
const whitespaceRE = /\s+/g;
|
const whitespaceRE = /\s+/g;
|
||||||
@@ -127,12 +127,12 @@ const UTILS: Utils = {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// this is already an object, but we may need to split keys:
|
// this is already an object, but we may need to split keys:
|
||||||
// {'a': true, 'b c': true} should become {a: true, b: true, c: true}
|
// {'a b': true, 'a c': false} should become {a: true, b: true, c: false}
|
||||||
for (let key in expr) {
|
for (let key in expr) {
|
||||||
const value = expr[key];
|
const value = expr[key];
|
||||||
const words = key.split(/\s+/);
|
const words = key.split(/\s+/);
|
||||||
for (let word of words) {
|
for (let word of words) {
|
||||||
result[word] = value;
|
result[word] = result[word] || value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -329,6 +329,9 @@ export class QWeb extends EventBus {
|
|||||||
* template, with the name given by the t-name attribute.
|
* template, with the name given by the t-name attribute.
|
||||||
*/
|
*/
|
||||||
addTemplates(xmlstr: string | Document) {
|
addTemplates(xmlstr: string | Document) {
|
||||||
|
if (!xmlstr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const doc = typeof xmlstr === "string" ? parseXML(xmlstr) : xmlstr;
|
const doc = typeof xmlstr === "string" ? parseXML(xmlstr) : xmlstr;
|
||||||
const templates = doc.getElementsByTagName("templates")[0];
|
const templates = doc.getElementsByTagName("templates")[0];
|
||||||
if (!templates) {
|
if (!templates) {
|
||||||
@@ -557,7 +560,11 @@ export class QWeb extends EventBus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (node.tagName !== "t" && node.hasAttribute("t-call")) {
|
if (node.tagName !== "t" && node.hasAttribute("t-call")) {
|
||||||
const tCallNode = document.createElement("t");
|
const tCallNode = document.implementation.createDocument(
|
||||||
|
"http://www.w3.org/1999/xhtml",
|
||||||
|
"t",
|
||||||
|
null
|
||||||
|
).documentElement;
|
||||||
tCallNode.setAttribute("t-call", node.getAttribute("t-call")!);
|
tCallNode.setAttribute("t-call", node.getAttribute("t-call")!);
|
||||||
node.removeAttribute("t-call");
|
node.removeAttribute("t-call");
|
||||||
node.prepend(tCallNode);
|
node.prepend(tCallNode);
|
||||||
@@ -593,7 +600,11 @@ export class QWeb extends EventBus {
|
|||||||
throw new Error(`Unknown QWeb directive: '${attrName}'`);
|
throw new Error(`Unknown QWeb directive: '${attrName}'`);
|
||||||
}
|
}
|
||||||
if (node.tagName !== "t" && (attrName === "t-esc" || attrName === "t-raw")) {
|
if (node.tagName !== "t" && (attrName === "t-esc" || attrName === "t-raw")) {
|
||||||
const tNode = document.createElement("t");
|
const tNode = document.implementation.createDocument(
|
||||||
|
"http://www.w3.org/1999/xhtml",
|
||||||
|
"t",
|
||||||
|
null
|
||||||
|
).documentElement;
|
||||||
tNode.setAttribute(attrName, node.getAttribute(attrName)!);
|
tNode.setAttribute(attrName, node.getAttribute(attrName)!);
|
||||||
for (let child of Array.from(node.childNodes)) {
|
for (let child of Array.from(node.childNodes)) {
|
||||||
tNode.appendChild(child);
|
tNode.appendChild(child);
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['state'].s;
|
let _2 = scope['state'].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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -68,7 +69,8 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
|
|||||||
let key1 = i1;
|
let key1 = i1;
|
||||||
let _6 = scope['section'].blips;
|
let _6 = scope['section'].blips;
|
||||||
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 = _6;
|
||||||
|
let _8 = _6;
|
||||||
if (!(_6 instanceof Array)) {
|
if (!(_6 instanceof Array)) {
|
||||||
_7 = Object.keys(_6);
|
_7 = Object.keys(_6);
|
||||||
_8 = Object.values(_6);
|
_8 = Object.values(_6);
|
||||||
@@ -309,7 +311,8 @@ exports[`composition sub components with some state rendered in a loop 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['state'].numbers;
|
let _2 = scope['state'].numbers;
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -597,7 +600,8 @@ exports[`other directives with t-component t-on expression captured in t-foreach
|
|||||||
scope.iter = 0;
|
scope.iter = 0;
|
||||||
let _2 = scope['arr'];
|
let _2 = scope['arr'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -639,7 +643,8 @@ exports[`other directives with t-component t-on expression in t-foreach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['state'].values;
|
let _2 = scope['state'].values;
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -691,7 +696,8 @@ exports[`other directives with t-component t-on expression in t-foreach with t-s
|
|||||||
scope.bossa = 'nova';
|
scope.bossa = 'nova';
|
||||||
let _2 = scope['state'].values;
|
let _2 = scope['state'].values;
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -744,7 +750,8 @@ exports[`other directives with t-component t-on method call in t-foreach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['state'].values;
|
let _2 = scope['state'].values;
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -1410,7 +1417,8 @@ exports[`other directives with t-component t-set outside modified in t-foreach 1
|
|||||||
scope.iter = 0;
|
scope.iter = 0;
|
||||||
let _2 = scope['state'].values;
|
let _2 = scope['state'].values;
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -1560,7 +1568,8 @@ exports[`random stuff/miscellaneous t-on with handler bound to dynamic argument
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['items'];
|
let _2 = scope['items'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -1838,7 +1847,8 @@ exports[`t-model directive in a t-foreach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['state'];
|
let _2 = scope['state'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -1878,7 +1888,8 @@ exports[`t-model directive in a t-foreach, part 2 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['state'];
|
let _2 = scope['state'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
|
|||||||
@@ -414,7 +414,8 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = `
|
|||||||
c1.push(vn2);
|
c1.push(vn2);
|
||||||
let _3 = scope['state'].users;
|
let _3 = scope['state'].users;
|
||||||
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 = _3;
|
||||||
|
let _5 = _3;
|
||||||
if (!(_3 instanceof Array)) {
|
if (!(_3 instanceof Array)) {
|
||||||
_4 = Object.keys(_3);
|
_4 = Object.keys(_3);
|
||||||
_5 = Object.values(_3);
|
_5 = Object.values(_3);
|
||||||
@@ -512,7 +513,8 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = `
|
|||||||
c1.push(vn2);
|
c1.push(vn2);
|
||||||
let _3 = scope['state'].users;
|
let _3 = scope['state'].users;
|
||||||
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 = _3;
|
||||||
|
let _5 = _3;
|
||||||
if (!(_3 instanceof Array)) {
|
if (!(_3 instanceof Array)) {
|
||||||
_4 = Object.keys(_3);
|
_4 = Object.keys(_3);
|
||||||
_5 = Object.values(_3);
|
_5 = Object.values(_3);
|
||||||
@@ -645,7 +647,8 @@ exports[`t-slot directive slots in t-foreach in t-foreach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['tree'];
|
let _2 = scope['tree'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -672,7 +675,8 @@ exports[`t-slot directive slots in t-foreach in t-foreach 1`] = `
|
|||||||
c1.push(vn8);
|
c1.push(vn8);
|
||||||
let _9 = scope['node1'].nodes;
|
let _9 = scope['node1'].nodes;
|
||||||
if (!_9) { throw new Error('QWeb error: Invalid loop expression')}
|
if (!_9) { throw new Error('QWeb error: Invalid loop expression')}
|
||||||
let _10 = _11 = _9;
|
let _10 = _9;
|
||||||
|
let _11 = _9;
|
||||||
if (!(_9 instanceof Array)) {
|
if (!(_9 instanceof Array)) {
|
||||||
_10 = Object.keys(_9);
|
_10 = Object.keys(_9);
|
||||||
_11 = Object.values(_9);
|
_11 = Object.values(_9);
|
||||||
|
|||||||
@@ -1388,6 +1388,62 @@ describe("async rendering", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<span>4</span>");
|
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 () => {
|
test("change state and call manually render: no unnecessary rendering", async () => {
|
||||||
class Widget extends Component {
|
class Widget extends Component {
|
||||||
static template = xml`<div><t t-esc="state.val"/></div>`;
|
static template = xml`<div><t t-esc="state.val"/></div>`;
|
||||||
|
|||||||
@@ -265,7 +265,8 @@ describe("class and style attributes with t-component", () => {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
expect(error.message).toBe("Cannot read property 'crash' of undefined");
|
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("");
|
expect(fixture.innerHTML).toBe("");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ describe("component error handling (catchError)", () => {
|
|||||||
try {
|
try {
|
||||||
await super.render();
|
await super.render();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toBe("Cannot read property 'this' of undefined");
|
expect(e.message).toMatch(
|
||||||
|
/Cannot read properties of undefined \(reading 'this'\)|Cannot read property 'this' of undefined/
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,7 +361,8 @@ describe("component error handling (catchError)", () => {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
expect(error.message).toBe("Cannot read property 'crash' of undefined");
|
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);
|
expect(console.error).toBeCalledTimes(0);
|
||||||
console.error = consoleError;
|
console.error = consoleError;
|
||||||
@@ -469,7 +472,8 @@ describe("component error handling (catchError)", () => {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
expect(error.message).toBe("Cannot read property 'crash' of undefined");
|
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);
|
expect(console.error).toBeCalledTimes(0);
|
||||||
console.error = consoleError;
|
console.error = consoleError;
|
||||||
@@ -495,7 +499,8 @@ describe("component error handling (catchError)", () => {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
expect(error.message).toBe("Cannot read property 'crash' of undefined");
|
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);
|
expect(console.error).toBeCalledTimes(0);
|
||||||
console.error = consoleError;
|
console.error = consoleError;
|
||||||
@@ -518,7 +523,8 @@ describe("component error handling (catchError)", () => {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
expect(error.message).toBe("Cannot read property 'y' of undefined");
|
const regexp = /Cannot read properties of undefined \(reading 'y'\)|Cannot read property 'y' of undefined/g;
|
||||||
|
expect(error.message).toMatch(regexp);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("simple catchError", async () => {
|
test("simple catchError", async () => {
|
||||||
|
|||||||
@@ -75,8 +75,6 @@ describe("hooks", () => {
|
|||||||
}
|
}
|
||||||
const component = new MyComponent();
|
const component = new MyComponent();
|
||||||
await component.mount(fixture);
|
await component.mount(fixture);
|
||||||
expect(component).not.toHaveProperty("mounted");
|
|
||||||
expect(component).not.toHaveProperty("willUnmount");
|
|
||||||
expect(fixture.innerHTML).toBe("<div>hey</div>");
|
expect(fixture.innerHTML).toBe("<div>hey</div>");
|
||||||
expect(steps).toEqual(["mounted"]);
|
expect(steps).toEqual(["mounted"]);
|
||||||
component.unmount();
|
component.unmount();
|
||||||
@@ -383,8 +381,6 @@ describe("hooks", () => {
|
|||||||
|
|
||||||
const component = new MyComponent();
|
const component = new MyComponent();
|
||||||
await component.mount(fixture);
|
await component.mount(fixture);
|
||||||
expect(component).not.toHaveProperty("patched");
|
|
||||||
expect(component).not.toHaveProperty("willPatch");
|
|
||||||
expect(steps).toEqual([]);
|
expect(steps).toEqual([]);
|
||||||
|
|
||||||
expect(fixture.innerHTML).toBe("<div>hey</div>");
|
expect(fixture.innerHTML).toBe("<div>hey</div>");
|
||||||
@@ -630,8 +626,6 @@ describe("hooks", () => {
|
|||||||
|
|
||||||
const app = new App();
|
const app = new App();
|
||||||
await app.mount(fixture);
|
await app.mount(fixture);
|
||||||
expect(app).not.toHaveProperty("willStart");
|
|
||||||
expect(app).not.toHaveProperty("willUpdateProps");
|
|
||||||
expect(fixture.innerHTML).toBe("<div><span>1</span></div>");
|
expect(fixture.innerHTML).toBe("<div><span>1</span></div>");
|
||||||
|
|
||||||
// NOTE: 'on2ndStart' appears first in the list even though
|
// NOTE: 'on2ndStart' appears first in the list even though
|
||||||
|
|||||||
@@ -546,7 +546,8 @@ describe("Portal: Basic use and DOM placement", () => {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
expect(error.message).toBe("Cannot read property 'crash' of undefined");
|
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||||
|
expect(error.message).toMatch(regexp);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("portal manual unmount", async () => {
|
test("portal manual unmount", async () => {
|
||||||
|
|||||||
@@ -429,7 +429,8 @@ exports[`foreach does not pollute the rendering context 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = [1];
|
let _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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -464,7 +465,8 @@ exports[`foreach iterate on items (on a element node) 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = [1,2];
|
let _2 = [1,2];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -502,7 +504,8 @@ exports[`foreach iterate on items 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = [3,2,1];
|
let _2 = [3,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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -549,7 +552,8 @@ exports[`foreach iterate, dict param 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['value'];
|
let _2 = scope['value'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -596,7 +600,8 @@ exports[`foreach iterate, position 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = Array(5);
|
let _2 = Array(5);
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -641,7 +646,8 @@ exports[`foreach t-call with body in t-foreach in t-foreach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['numbers'];
|
let _2 = scope['numbers'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -658,7 +664,8 @@ exports[`foreach t-call with body in t-foreach in t-foreach 1`] = `
|
|||||||
let key1 = i1;
|
let key1 = i1;
|
||||||
let _6 = scope['letters'];
|
let _6 = scope['letters'];
|
||||||
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 = _6;
|
||||||
|
let _8 = _6;
|
||||||
if (!(_6 instanceof Array)) {
|
if (!(_6 instanceof Array)) {
|
||||||
_7 = Object.keys(_6);
|
_7 = Object.keys(_6);
|
||||||
_8 = Object.values(_6);
|
_8 = Object.values(_6);
|
||||||
@@ -729,7 +736,8 @@ exports[`foreach t-call without body in t-foreach in t-foreach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['numbers'];
|
let _2 = scope['numbers'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -746,7 +754,8 @@ exports[`foreach t-call without body in t-foreach in t-foreach 1`] = `
|
|||||||
let key1 = i1;
|
let key1 = i1;
|
||||||
let _6 = scope['letters'];
|
let _6 = scope['letters'];
|
||||||
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 = _6;
|
||||||
|
let _8 = _6;
|
||||||
if (!(_6 instanceof Array)) {
|
if (!(_6 instanceof Array)) {
|
||||||
_7 = Object.keys(_6);
|
_7 = Object.keys(_6);
|
||||||
_8 = Object.values(_6);
|
_8 = Object.values(_6);
|
||||||
@@ -811,7 +820,8 @@ exports[`foreach t-foreach in t-forach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['numbers'];
|
let _2 = scope['numbers'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -828,7 +838,8 @@ exports[`foreach t-foreach in t-forach 1`] = `
|
|||||||
let key1 = i1;
|
let key1 = i1;
|
||||||
let _6 = scope['letters'];
|
let _6 = scope['letters'];
|
||||||
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 = _6;
|
||||||
|
let _8 = _6;
|
||||||
if (!(_6 instanceof Array)) {
|
if (!(_6 instanceof Array)) {
|
||||||
_7 = Object.keys(_6);
|
_7 = Object.keys(_6);
|
||||||
_8 = Object.values(_6);
|
_8 = Object.values(_6);
|
||||||
@@ -871,7 +882,8 @@ exports[`foreach warn if no key in some case 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = [1,2];
|
let _2 = [1,2];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -940,7 +952,8 @@ exports[`misc global 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = [4,5,6];
|
let _2 = [4,5,6];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -1666,7 +1679,8 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
|
|||||||
}
|
}
|
||||||
let _6 = scope['node'].children||[];
|
let _6 = scope['node'].children||[];
|
||||||
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 = _6;
|
||||||
|
let _8 = _6;
|
||||||
if (!(_6 instanceof Array)) {
|
if (!(_6 instanceof Array)) {
|
||||||
_7 = Object.keys(_6);
|
_7 = Object.keys(_6);
|
||||||
_8 = Object.values(_6);
|
_8 = Object.values(_6);
|
||||||
@@ -1746,7 +1760,8 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
|
|||||||
}
|
}
|
||||||
let _6 = scope['node'].children||[];
|
let _6 = scope['node'].children||[];
|
||||||
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 = _6;
|
||||||
|
let _8 = _6;
|
||||||
if (!(_6 instanceof Array)) {
|
if (!(_6 instanceof Array)) {
|
||||||
_7 = Object.keys(_6);
|
_7 = Object.keys(_6);
|
||||||
_8 = Object.values(_6);
|
_8 = Object.values(_6);
|
||||||
@@ -1832,7 +1847,8 @@ exports[`t-call (template calling recursive template, part 4: with t-set recursi
|
|||||||
}
|
}
|
||||||
let _6 = scope['node'].children||[];
|
let _6 = scope['node'].children||[];
|
||||||
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 = _6;
|
||||||
|
let _8 = _6;
|
||||||
if (!(_6 instanceof Array)) {
|
if (!(_6 instanceof Array)) {
|
||||||
_7 = Object.keys(_6);
|
_7 = Object.keys(_6);
|
||||||
_8 = Object.values(_6);
|
_8 = Object.values(_6);
|
||||||
@@ -1998,7 +2014,8 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['list'];
|
let _2 = scope['list'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -2775,7 +2792,8 @@ exports[`t-key t-key directive in a list 1`] = `
|
|||||||
let vn1 = h('ul', p1, c1);
|
let vn1 = h('ul', p1, c1);
|
||||||
let _2 = scope['beers'];
|
let _2 = scope['beers'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -2879,7 +2897,8 @@ exports[`t-on can bind handlers with loop variable as argument 1`] = `
|
|||||||
let vn1 = h('ul', p1, c1);
|
let vn1 = h('ul', p1, c1);
|
||||||
let _2 = ['someval'];
|
let _2 = ['someval'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -3161,7 +3180,8 @@ exports[`t-on t-on with prevent modifier in t-foreach 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['projects'];
|
let _2 = scope['projects'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -3432,7 +3452,8 @@ exports[`t-ref refs in a loop 1`] = `
|
|||||||
let vn1 = h('div', p1, c1);
|
let vn1 = h('div', p1, c1);
|
||||||
let _2 = scope['items'];
|
let _2 = scope['items'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -3676,7 +3697,8 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
|
|||||||
scope.v = 1;
|
scope.v = 1;
|
||||||
let _2 = scope['list'];
|
let _2 = scope['list'];
|
||||||
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 = _2;
|
||||||
|
let _4 = _2;
|
||||||
if (!(_2 instanceof Array)) {
|
if (!(_2 instanceof Array)) {
|
||||||
_3 = Object.keys(_2);
|
_3 = Object.keys(_2);
|
||||||
_4 = Object.values(_2);
|
_4 = Object.values(_2);
|
||||||
@@ -3943,6 +3965,20 @@ exports[`t-set value priority 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`translation support can add additional attributes to the list of translatable attributes 1`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"test\\"
|
||||||
|
let h = this.h;
|
||||||
|
let _1 = 'word';
|
||||||
|
let _2 = 'mot';
|
||||||
|
let c3 = [], p3 = {key:3,attrs:{tomato: _1,potato: _2}};
|
||||||
|
let vn3 = h('div', p3, c3);
|
||||||
|
c3.push({text: \`text\`});
|
||||||
|
return vn3;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`translation support can translate node content 1`] = `
|
exports[`translation support can translate node content 1`] = `
|
||||||
"function anonymous(context, extra
|
"function anonymous(context, extra
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// 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;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
@@ -27,3 +27,31 @@ exports[`qweb t-att t-att-class with multiple classes 2`] = `
|
|||||||
return vn4;
|
return vn4;
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`qweb t-att t-att-class with multiple classes, some of which are duplicate 1`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"test\\"
|
||||||
|
let utils = this.constructor.utils;
|
||||||
|
let scope = Object.create(context);
|
||||||
|
let h = this.h;
|
||||||
|
let _1 = utils.toClassObj({'a b c':scope['value'],'a b d':!scope['value']});
|
||||||
|
let c2 = [], p2 = {key:2,class:_1};
|
||||||
|
let vn2 = h('div', p2, c2);
|
||||||
|
return vn2;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`qweb t-att t-att-class with multiple classes, some of which are duplicate 2`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"test\\"
|
||||||
|
let utils = this.constructor.utils;
|
||||||
|
let scope = Object.create(context);
|
||||||
|
let h = this.h;
|
||||||
|
let _3 = utils.toClassObj({'a b c':scope['value'],'a b d':!scope['value']});
|
||||||
|
let c4 = [], p4 = {key:4,class:_3};
|
||||||
|
let vn4 = h('div', p4, c4);
|
||||||
|
return vn4;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|||||||
+15
-4
@@ -1,4 +1,5 @@
|
|||||||
import { QWeb } from "../../src/qweb/index";
|
import { QWeb } from "../../src/qweb/index";
|
||||||
|
import { config } from "../../src/index";
|
||||||
import { nextTick, normalize, renderToDOM, renderToString, trim } from "../helpers";
|
import { nextTick, normalize, renderToDOM, renderToString, trim } from "../helpers";
|
||||||
import { patch } from "../../src/vdom";
|
import { patch } from "../../src/vdom";
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ let qweb: QWeb;
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
QWeb.TEMPLATES = {};
|
QWeb.TEMPLATES = {};
|
||||||
|
QWeb.nextId = 1;
|
||||||
qweb = new QWeb();
|
qweb = new QWeb();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1862,8 +1864,7 @@ describe("t-ref", () => {
|
|||||||
|
|
||||||
describe("loading templates", () => {
|
describe("loading templates", () => {
|
||||||
test("can initialize qweb with a string", () => {
|
test("can initialize qweb with a string", () => {
|
||||||
const templates = `
|
const templates = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<templates id="template" xml:space="preserve">
|
<templates id="template" xml:space="preserve">
|
||||||
<div t-name="hey">jupiler</div>
|
<div t-name="hey">jupiler</div>
|
||||||
</templates>`;
|
</templates>`;
|
||||||
@@ -1872,8 +1873,7 @@ describe("loading templates", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("can load a few templates from a xml string", () => {
|
test("can load a few templates from a xml string", () => {
|
||||||
const data = `
|
const data = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<templates id="template" xml:space="preserve">
|
<templates id="template" xml:space="preserve">
|
||||||
|
|
||||||
<t t-name="items"><li>ok</li><li>foo</li></t>
|
<t t-name="items"><li>ok</li><li>foo</li></t>
|
||||||
@@ -2213,6 +2213,17 @@ describe("translation support", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("can add additional attributes to the list of translatable attributes", () => {
|
||||||
|
const translations = {
|
||||||
|
word: "mot",
|
||||||
|
};
|
||||||
|
const translateFn = (expr) => translations[expr] || expr;
|
||||||
|
const qweb = new QWeb({ translateFn });
|
||||||
|
config.translatableAttributes.push("potato");
|
||||||
|
qweb.addTemplate("test", `<div tomato="word" potato="word">text</div>`);
|
||||||
|
expect(renderToString(qweb, "test")).toBe('<div tomato="word" potato="mot">text</div>');
|
||||||
|
});
|
||||||
|
|
||||||
test("translation is done on the trimmed text, with extra spaces readded after", () => {
|
test("translation is done on the trimmed text, with extra spaces readded after", () => {
|
||||||
const translations = {
|
const translations = {
|
||||||
word: "mot",
|
word: "mot",
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -24,4 +24,13 @@ describe("qweb t-att", () => {
|
|||||||
'<div class="a b c"></div>'
|
'<div class="a b c"></div>'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("t-att-class with multiple classes, some of which are duplicate", () => {
|
||||||
|
expect(render(`<div t-att-class="{'a b c': value, 'a b d': !value}" />`, { value: true })).toBe(
|
||||||
|
'<div class="a b c"></div>'
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
render(`<div t-att-class="{'a b c': value, 'a b d': !value}" />`, { value: false })
|
||||||
|
).toBe('<div class="a b d"></div>');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ describe("Link component", () => {
|
|||||||
await app.mount(fixture);
|
await app.mount(fixture);
|
||||||
|
|
||||||
expect(window.location.pathname).toBe("/users");
|
expect(window.location.pathname).toBe("/users");
|
||||||
var evt = new MouseEvent("click", {
|
var evt = new MouseEvent("contextmenu", {
|
||||||
button: 1,
|
button: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -13,8 +13,8 @@
|
|||||||
// "compileOnSave": false, // Signals to the IDE to generate all files for a given tsconfig.json upon saving.
|
// "compileOnSave": false, // Signals to the IDE to generate all files for a given tsconfig.json upon saving.
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// Main options
|
// Main options
|
||||||
"target": "esnext", // Specify ECMAScript target version: 'es3' (default), 'es5', 'es2015', 'es2016', 'es2017','es2018' or 'esnext'.
|
"target": "es2017", // 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'.
|
"module": "es6", // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
|
||||||
// "lib": ["esnext", "dom"], // Specify library files to be included in the compilation.
|
// "lib": ["esnext", "dom"], // Specify library files to be included in the compilation.
|
||||||
// "allowJs": false, // Allow javascript files to be compiled.
|
// "allowJs": false, // Allow javascript files to be compiled.
|
||||||
// "checkJs": false, // Report errors in .js files.
|
// "checkJs": false, // Report errors in .js files.
|
||||||
|
|||||||
Reference in New Issue
Block a user