mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
@@ -60,5 +60,8 @@
|
||||
"json",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100
|
||||
}
|
||||
}
|
||||
|
||||
+8
-33
@@ -437,10 +437,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
__owl__.renderPromise = null;
|
||||
const target = __owl__.vnode || document.createElement(vnode.sel!);
|
||||
if (this.__owl__.classObj) {
|
||||
(<any>vnode).data.class = Object.assign(
|
||||
(<any>vnode).data.class || {},
|
||||
this.__owl__.classObj
|
||||
);
|
||||
(<any>vnode).data.class = Object.assign((<any>vnode).data.class || {}, this.__owl__.classObj);
|
||||
}
|
||||
__owl__.vnode = patch(target, vnode);
|
||||
}
|
||||
@@ -471,17 +468,11 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
if (template) {
|
||||
this.template = template;
|
||||
} else {
|
||||
while (
|
||||
(template = p.name) &&
|
||||
!(template in qweb.templates) &&
|
||||
p !== Component
|
||||
) {
|
||||
while ((template = p.name) && !(template in qweb.templates) && p !== Component) {
|
||||
p = p.__proto__;
|
||||
}
|
||||
if (p === Component) {
|
||||
throw new Error(
|
||||
`Could not find template for component "${this.constructor.name}"`
|
||||
);
|
||||
throw new Error(`Could not find template for component "${this.constructor.name}"`);
|
||||
} else {
|
||||
tmap[name] = template;
|
||||
this.template = template;
|
||||
@@ -493,10 +484,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
return this.__render();
|
||||
}
|
||||
|
||||
async __render(
|
||||
force: boolean = false,
|
||||
patchQueue: any[] = []
|
||||
): Promise<VNode> {
|
||||
async __render(force: boolean = false, patchQueue: any[] = []): Promise<VNode> {
|
||||
const __owl__ = this.__owl__;
|
||||
__owl__.renderId++;
|
||||
const promises: Promise<void>[] = [];
|
||||
@@ -536,10 +524,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
__mount(vnode: VNode, elm: HTMLElement): VNode {
|
||||
const __owl__ = this.__owl__;
|
||||
if (__owl__.classObj) {
|
||||
(<any>vnode).data.class = Object.assign(
|
||||
(<any>vnode).data.class || {},
|
||||
__owl__.classObj
|
||||
);
|
||||
(<any>vnode).data.class = Object.assign((<any>vnode).data.class || {}, __owl__.classObj);
|
||||
}
|
||||
__owl__.vnode = patch(elm, vnode);
|
||||
if (__owl__.parent!.__owl__.isMounted && !__owl__.isMounted) {
|
||||
@@ -619,11 +604,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
// list of strings (prop names)
|
||||
for (let i = 0, l = propsDef.length; i < l; i++) {
|
||||
if (!(propsDef[i] in props)) {
|
||||
throw new Error(
|
||||
`Missing props '${propsDef[i]}' (component '${
|
||||
this.constructor.name
|
||||
}')`
|
||||
);
|
||||
throw new Error(`Missing props '${propsDef[i]}' (component '${this.constructor.name}')`);
|
||||
}
|
||||
}
|
||||
} else if (propsDef) {
|
||||
@@ -631,11 +612,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
for (let propName in propsDef) {
|
||||
if (!(propName in props)) {
|
||||
if (propsDef[propName] && !propsDef[propName].optional) {
|
||||
throw new Error(
|
||||
`Missing props '${propName}' (component '${
|
||||
this.constructor.name
|
||||
}')`
|
||||
);
|
||||
throw new Error(`Missing props '${propName}' (component '${this.constructor.name}')`);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -643,9 +620,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
let isValid = isValidProp(props[propName], propsDef[propName]);
|
||||
if (!isValid) {
|
||||
throw new Error(
|
||||
`Props '${propName}' of invalid type in component '${
|
||||
this.constructor.name
|
||||
}'`
|
||||
`Props '${propName}' of invalid type in component '${this.constructor.name}'`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ Object.defineProperty(__info__, "mode", {
|
||||
`Owl is running in 'dev' mode. This is not suitable for production use. See ${url} for more information.`
|
||||
);
|
||||
} else {
|
||||
console.log(`Owl is now running in 'prod' mode.`)
|
||||
console.log(`Owl is now running in 'prod' mode.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+5
-22
@@ -21,15 +21,7 @@
|
||||
|
||||
// we define here a new modified Array prototype, which basically override all
|
||||
// Array methods that change some state to be able to track their changes
|
||||
const methodsToPatch = [
|
||||
"push",
|
||||
"pop",
|
||||
"shift",
|
||||
"unshift",
|
||||
"splice",
|
||||
"sort",
|
||||
"reverse"
|
||||
];
|
||||
const methodsToPatch = ["push", "pop", "shift", "unshift", "splice", "sort", "reverse"];
|
||||
const methodLen = methodsToPatch.length;
|
||||
|
||||
const ArrayProto = Array.prototype;
|
||||
@@ -78,18 +70,14 @@ export class Observer {
|
||||
|
||||
static set(target: any, key: number | string, value: any) {
|
||||
if (!target.__owl__) {
|
||||
throw Error(
|
||||
"`Observer.set()` can only be called with observed Objects or Arrays"
|
||||
);
|
||||
throw Error("`Observer.set()` can only be called with observed Objects or Arrays");
|
||||
}
|
||||
target.__owl__.observer.set(target, key, value);
|
||||
}
|
||||
|
||||
static delete(target: any, key: number | string) {
|
||||
if (!target.__owl__) {
|
||||
throw Error(
|
||||
"`Observer.delete()` can only be called with observed Objects"
|
||||
);
|
||||
throw Error("`Observer.delete()` can only be called with observed Objects");
|
||||
}
|
||||
target.__owl__.observer.delete(target, key);
|
||||
}
|
||||
@@ -127,8 +115,7 @@ export class Observer {
|
||||
|
||||
set(target: any, key: number | string, value: any) {
|
||||
let alreadyDefined =
|
||||
key in target &&
|
||||
Object.getOwnPropertyDescriptor(target, key)!.configurable === false;
|
||||
key in target && Object.getOwnPropertyDescriptor(target, key)!.configurable === false;
|
||||
if (alreadyDefined) {
|
||||
target[key] = value;
|
||||
} else {
|
||||
@@ -172,11 +159,7 @@ export class Observer {
|
||||
}
|
||||
}
|
||||
|
||||
_addProp<T extends { __owl__?: any }>(
|
||||
obj: T,
|
||||
key: string | number,
|
||||
value: any
|
||||
) {
|
||||
_addProp<T extends { __owl__?: any }>(obj: T, key: string | number, value: any) {
|
||||
var self = this;
|
||||
Object.defineProperty(obj, key, {
|
||||
configurable: true,
|
||||
|
||||
+11
-45
@@ -59,14 +59,7 @@ export interface Directive {
|
||||
// Const/global stuff/helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DISABLED_TAGS = [
|
||||
"input",
|
||||
"textarea",
|
||||
"button",
|
||||
"select",
|
||||
"option",
|
||||
"optgroup"
|
||||
];
|
||||
const DISABLED_TAGS = ["input", "textarea", "button", "select", "option", "optgroup"];
|
||||
|
||||
const lineBreakRE = /[\r\n]/;
|
||||
const whitespaceRE = /\s+/g;
|
||||
@@ -245,9 +238,7 @@ export class QWeb extends EventBus {
|
||||
return a + b;
|
||||
}) > 1
|
||||
) {
|
||||
throw new Error(
|
||||
"Only one conditional branching directive is allowed per node"
|
||||
);
|
||||
throw new Error("Only one conditional branching directive is allowed per node");
|
||||
}
|
||||
// All text nodes between branch nodes are removed
|
||||
let textNode;
|
||||
@@ -311,28 +302,20 @@ export class QWeb extends EventBus {
|
||||
}
|
||||
let template;
|
||||
try {
|
||||
template = new Function(
|
||||
"context",
|
||||
"extra",
|
||||
ctx.code.join("\n")
|
||||
) as CompiledTemplate;
|
||||
template = new Function("context", "extra", ctx.code.join("\n")) as CompiledTemplate;
|
||||
} catch (e) {
|
||||
const templateName = ctx.templateName.replace(/`/g, "'");
|
||||
console.groupCollapsed(`Invalid Code generated by ${templateName}`);
|
||||
console.warn(ctx.code.join("\n"));
|
||||
console.groupEnd();
|
||||
throw new Error(
|
||||
`Invalid generated code while compiling template '${templateName}': ${
|
||||
e.message
|
||||
}`
|
||||
`Invalid generated code while compiling template '${templateName}': ${e.message}`
|
||||
);
|
||||
}
|
||||
if (isDebug) {
|
||||
const tpl = this.templates[name];
|
||||
if (tpl) {
|
||||
const msg = `Template: ${
|
||||
tpl.elem.outerHTML
|
||||
}\nCompiled code:\n${template.toString()}`;
|
||||
const msg = `Template: ${tpl.elem.outerHTML}\nCompiled code:\n${template.toString()}`;
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
@@ -481,11 +464,7 @@ export class QWeb extends EventBus {
|
||||
}
|
||||
}
|
||||
|
||||
_compileGenericNode(
|
||||
node: ChildNode,
|
||||
ctx: Context,
|
||||
withHandlers: boolean = true
|
||||
): number {
|
||||
_compileGenericNode(node: ChildNode, ctx: Context, withHandlers: boolean = true): number {
|
||||
// nodeType 1 is generic tag
|
||||
if (node.nodeType !== 1) {
|
||||
throw new Error("unsupported node type");
|
||||
@@ -509,10 +488,7 @@ export class QWeb extends EventBus {
|
||||
if (key === "disabled" && DISABLED_TAGS.indexOf(node.nodeName) > -1) {
|
||||
isProp = true;
|
||||
}
|
||||
if (
|
||||
(key === "readonly" && node.nodeName === "input") ||
|
||||
node.nodeName === "textarea"
|
||||
) {
|
||||
if ((key === "readonly" && node.nodeName === "input") || node.nodeName === "textarea") {
|
||||
isProp = true;
|
||||
}
|
||||
if (isProp) {
|
||||
@@ -526,10 +502,7 @@ export class QWeb extends EventBus {
|
||||
const value = attributes[i].textContent!;
|
||||
|
||||
// regular attributes
|
||||
if (
|
||||
!name.startsWith("t-") &&
|
||||
!(<Element>node).getAttribute("t-attf-" + name)
|
||||
) {
|
||||
if (!name.startsWith("t-") && !(<Element>node).getAttribute("t-attf-" + name)) {
|
||||
const attID = ctx.generateID();
|
||||
if (name === "class") {
|
||||
let classDef = value
|
||||
@@ -577,9 +550,7 @@ export class QWeb extends EventBus {
|
||||
const attValueID = ctx.generateID();
|
||||
ctx.addLine(`var _${attValueID} = ${formattedValue};`);
|
||||
formattedValue = `'${attValue}' + (_${attValueID} ? ' ' + _${attValueID} : '')`;
|
||||
const attrIndex = attrs.findIndex(att =>
|
||||
att.startsWith(attName + ":")
|
||||
);
|
||||
const attrIndex = attrs.findIndex(att => att.startsWith(attName + ":"));
|
||||
attrs.splice(attrIndex, 1);
|
||||
}
|
||||
ctx.addLine(`var _${attID} = ${formattedValue};`);
|
||||
@@ -645,9 +616,7 @@ export class QWeb extends EventBus {
|
||||
ctx.addLine(`}`);
|
||||
ctx.closeIf();
|
||||
}
|
||||
ctx.addLine(
|
||||
`var vn${nodeID} = h('${node.nodeName}', p${nodeID}, c${nodeID});`
|
||||
);
|
||||
ctx.addLine(`var vn${nodeID} = h('${node.nodeName}', p${nodeID}, c${nodeID});`);
|
||||
if (ctx.parentNode) {
|
||||
ctx.addLine(`c${ctx.parentNode}.push(vn${nodeID});`);
|
||||
}
|
||||
@@ -776,10 +745,7 @@ export class Context {
|
||||
return `(${this.formatExpression(s.slice(2, -2))})`;
|
||||
}
|
||||
|
||||
let r = s.replace(
|
||||
/\{\{.*?\}\}/g,
|
||||
s => "${" + this.formatExpression(s.slice(2, -2)) + "}"
|
||||
);
|
||||
let r = s.replace(/\{\{.*?\}\}/g, s => "${" + this.formatExpression(s.slice(2, -2)) + "}");
|
||||
return "`" + r + "`";
|
||||
}
|
||||
}
|
||||
|
||||
+5
-14
@@ -60,9 +60,7 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Context) {
|
||||
ctx.addLine(`var frag${fragID} = this.utils.getFragment(${exprID})`);
|
||||
let tempNodeID = ctx.generateID();
|
||||
ctx.addLine(`var p${tempNodeID} = {hook: {`);
|
||||
ctx.addLine(
|
||||
` insert: n => n.elm.parentNode.replaceChild(frag${fragID}, n.elm),`
|
||||
);
|
||||
ctx.addLine(` insert: n => n.elm.parentNode.replaceChild(frag${fragID}, n.elm),`);
|
||||
ctx.addLine(`}};`);
|
||||
ctx.addLine(`var vn${tempNodeID} = h('div', p${tempNodeID})`);
|
||||
ctx.addLine(`c${ctx.parentNode}.push(vn${tempNodeID});`);
|
||||
@@ -116,9 +114,7 @@ QWeb.addDirective({
|
||||
if (value) {
|
||||
const formattedValue = ctx.formatExpression(value);
|
||||
if (ctx.variables.hasOwnProperty(variable)) {
|
||||
ctx.addLine(
|
||||
`${(<QWebExprVar>ctx.variables[variable]).id} = ${formattedValue}`
|
||||
);
|
||||
ctx.addLine(`${(<QWebExprVar>ctx.variables[variable]).id} = ${formattedValue}`);
|
||||
} else {
|
||||
const varName = `_${ctx.generateID()}`;
|
||||
ctx.addLine(`var ${varName} = ${formattedValue};`);
|
||||
@@ -220,9 +216,7 @@ QWeb.addDirective({
|
||||
}
|
||||
|
||||
// compile sub template
|
||||
const subCtx = ctx
|
||||
.subContext("caller", nodeCopy)
|
||||
.subContext("variables", Object.create(vars));
|
||||
const subCtx = ctx.subContext("caller", nodeCopy).subContext("variables", Object.create(vars));
|
||||
|
||||
qweb._compileNode(nodeTemplate.elem, subCtx);
|
||||
|
||||
@@ -250,9 +244,7 @@ QWeb.addDirective({
|
||||
const name = node.getAttribute("t-as")!;
|
||||
let arrayID = ctx.generateID();
|
||||
ctx.addLine(`var _${arrayID} = ${ctx.formatExpression(elems)};`);
|
||||
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 valuesID = ctx.generateID();
|
||||
ctx.addLine(`var _${keysID} = _${valuesID} = _${arrayID};`);
|
||||
@@ -269,8 +261,7 @@ QWeb.addDirective({
|
||||
ctx.addLine(`context.${name} = _${keysID}[i];`);
|
||||
ctx.addLine(`context.${name}_value = _${valuesID}[i];`);
|
||||
const nodeCopy = <Element>node.cloneNode(true);
|
||||
let shouldWarn =
|
||||
nodeCopy.tagName !== "t" && !nodeCopy.hasAttribute("t-key");
|
||||
let shouldWarn = nodeCopy.tagName !== "t" && !nodeCopy.hasAttribute("t-key");
|
||||
if (!shouldWarn && node.tagName === "t") {
|
||||
if (node.hasAttribute("t-component") && !node.hasAttribute("t-key")) {
|
||||
shouldWarn = true;
|
||||
|
||||
@@ -82,7 +82,7 @@ const STATIC_TOKEN_MAP: { [key: string]: TKind } = {
|
||||
")": "RIGHT_PAREN"
|
||||
};
|
||||
|
||||
const OPERATORS = ".,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%".split(',');
|
||||
const OPERATORS = ".,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%".split(",");
|
||||
|
||||
type Tokenizer = (expr: string) => Token | false;
|
||||
|
||||
@@ -231,10 +231,7 @@ export function tokenize(expr: string): Token[] {
|
||||
* - or if the previous token is a left brace or a comma, and the next token is
|
||||
* a colon (in that case, this is an object key: `{a: b}`)
|
||||
*/
|
||||
export function compileExpr(
|
||||
expr: string,
|
||||
vars: { [key: string]: QWebVar }
|
||||
): string {
|
||||
export function compileExpr(expr: string, vars: { [key: string]: QWebVar }): string {
|
||||
const tokens = tokenize(expr);
|
||||
let result = "";
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
@@ -246,10 +243,7 @@ export function compileExpr(
|
||||
if (prevToken) {
|
||||
if (prevToken.type === "OPERATOR" && prevToken.value === ".") {
|
||||
isVar = false;
|
||||
} else if (
|
||||
prevToken.type === "LEFT_BRACE" ||
|
||||
prevToken.type === "COMMA"
|
||||
) {
|
||||
} else if (prevToken.type === "LEFT_BRACE" || prevToken.type === "COMMA") {
|
||||
let nextToken = tokens[i + 1];
|
||||
if (nextToken && nextToken.type === "COLON") {
|
||||
isVar = false;
|
||||
|
||||
+19
-64
@@ -49,9 +49,7 @@ QWeb.addDirective({
|
||||
)}'\`)`
|
||||
);
|
||||
ctx.closeIf();
|
||||
let params = extraArgs
|
||||
? `owner, ${ctx.formatExpression(extraArgs)}`
|
||||
: "owner";
|
||||
let params = extraArgs ? `owner, ${ctx.formatExpression(extraArgs)}` : "owner";
|
||||
let handler;
|
||||
if (mods.length > 0) {
|
||||
handler = `function (e) {`;
|
||||
@@ -70,9 +68,7 @@ QWeb.addDirective({
|
||||
ctx.addLine(
|
||||
`extra.handlers['${eventName}' + ${nodeID}] = extra.handlers['${eventName}' + ${nodeID}] || ${handler};`
|
||||
);
|
||||
ctx.addLine(
|
||||
`p${nodeID}.on['${eventName}'] = extra.handlers['${eventName}' + ${nodeID}];`
|
||||
);
|
||||
ctx.addLine(`p${nodeID}.on['${eventName}'] = extra.handlers['${eventName}' + ${nodeID}];`);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -101,9 +97,7 @@ UTILS.transitionInsert = function(vn: VNode, name: string) {
|
||||
const elm = <HTMLElement>vn.elm;
|
||||
// remove potential duplicated vnode that is currently being removed, to
|
||||
// prevent from having twice the same node in the DOM during an animation
|
||||
const dup =
|
||||
elm.parentElement &&
|
||||
elm.parentElement!.querySelector(`*[data-owl-key='${vn.key}']`);
|
||||
const dup = elm.parentElement && elm.parentElement!.querySelector(`*[data-owl-key='${vn.key}']`);
|
||||
if (dup) {
|
||||
dup.remove();
|
||||
}
|
||||
@@ -164,9 +158,7 @@ function toMs(s: string): number {
|
||||
function whenTransitionEnd(elm: HTMLElement, cb) {
|
||||
const styles = window.getComputedStyle(elm);
|
||||
const delays: Array<string> = (styles.transitionDelay || "").split(", ");
|
||||
const durations: Array<string> = (styles.transitionDuration || "").split(
|
||||
", "
|
||||
);
|
||||
const durations: Array<string> = (styles.transitionDuration || "").split(", ");
|
||||
const timeout: number = getTimeout(delays, durations);
|
||||
if (timeout > 0) {
|
||||
elm.addEventListener("transitionend", cb, { once: true });
|
||||
@@ -425,9 +417,7 @@ QWeb.addDirective({
|
||||
// necessary to prevent collisions
|
||||
if (!key && ctx.inLoop) {
|
||||
let id = ctx.generateID();
|
||||
ctx.addLine(
|
||||
`let template${id} = "_slot_" + String(-${componentID} - i)`
|
||||
);
|
||||
ctx.addLine(`let template${id} = "_slot_" + String(-${componentID} - i)`);
|
||||
templateID = `template${id}`;
|
||||
} else {
|
||||
templateID = `"_slot_${templateID}"`;
|
||||
@@ -446,9 +436,7 @@ QWeb.addDirective({
|
||||
if (transition) {
|
||||
transitionsInsertCode = `utils.transitionInsert(vn, '${transition}');`;
|
||||
}
|
||||
let finalizeComponentCode = `w${componentID}.${
|
||||
keepAlive ? "unmount" : "destroy"
|
||||
}();`;
|
||||
let finalizeComponentCode = `w${componentID}.${keepAlive ? "unmount" : "destroy"}();`;
|
||||
if (ref && !keepAlive) {
|
||||
finalizeComponentCode += `delete context.refs[${refKey}];`;
|
||||
}
|
||||
@@ -501,9 +489,7 @@ QWeb.addDirective({
|
||||
// we need to evaluate the arguments now, because the handler will
|
||||
// be set asynchronously later when the widget is ready, and the
|
||||
// context might be different.
|
||||
ctx.addLine(
|
||||
`let arg${argId} = ${ctx.formatExpression(extraArgs)};`
|
||||
);
|
||||
ctx.addLine(`let arg${argId} = ${ctx.formatExpression(extraArgs)};`);
|
||||
params = `owner, arg${argId}`;
|
||||
} else {
|
||||
params = `owner, ${ctx.formatExpression(extraArgs)}`;
|
||||
@@ -536,9 +522,7 @@ QWeb.addDirective({
|
||||
if (async) {
|
||||
ctx.addLine(`const patchQueue${componentID} = [];`);
|
||||
ctx.addLine(
|
||||
`c${
|
||||
ctx.parentNode
|
||||
}.push(w${componentID} && w${componentID}.__owl__.pvnode || null);`
|
||||
`c${ctx.parentNode}.push(w${componentID} && w${componentID}.__owl__.pvnode || null);`
|
||||
);
|
||||
} else {
|
||||
ctx.addLine(`c${ctx.parentNode}.push(null);`);
|
||||
@@ -547,9 +531,7 @@ QWeb.addDirective({
|
||||
ctx.addIf(
|
||||
`w${componentID} && w${componentID}.__owl__.renderPromise && !w${componentID}.__owl__.vnode`
|
||||
);
|
||||
ctx.addIf(
|
||||
`utils.shallowEqual(props${componentID}, w${componentID}.__owl__.renderProps)`
|
||||
);
|
||||
ctx.addIf(`utils.shallowEqual(props${componentID}, w${componentID}.__owl__.renderProps)`);
|
||||
ctx.addLine(`def${defID} = w${componentID}.__owl__.renderPromise;`);
|
||||
ctx.addElse();
|
||||
ctx.addLine(`w${componentID}.destroy();`);
|
||||
@@ -568,12 +550,8 @@ QWeb.addDirective({
|
||||
ctx.addLine(
|
||||
`if (!W${componentID}) {throw new Error('Cannot find the definition of component "' + componentKey${componentID} + '"')}`
|
||||
);
|
||||
ctx.addLine(
|
||||
`w${componentID} = new W${componentID}(owner, props${componentID});`
|
||||
);
|
||||
ctx.addLine(
|
||||
`context.__owl__.cmap[${templateID}] = w${componentID}.__owl__.id;`
|
||||
);
|
||||
ctx.addLine(`w${componentID} = new W${componentID}(owner, props${componentID});`);
|
||||
ctx.addLine(`context.__owl__.cmap[${templateID}] = w${componentID}.__owl__.id;`);
|
||||
|
||||
// SLOTS
|
||||
if (node.childNodes.length) {
|
||||
@@ -587,11 +565,7 @@ QWeb.addDirective({
|
||||
slotNode.parentElement!.removeChild(slotNode);
|
||||
const key = slotNode.getAttribute("t-set")!;
|
||||
slotNode.removeAttribute("t-set");
|
||||
const slotFn = qweb._compile(
|
||||
`slot_${key}_template`,
|
||||
slotNode,
|
||||
ctx.parentNode!
|
||||
);
|
||||
const slotFn = qweb._compile(`slot_${key}_template`, slotNode, ctx.parentNode!);
|
||||
qweb.slots[`${slotId}_${key}`] = slotFn.bind(qweb);
|
||||
}
|
||||
}
|
||||
@@ -600,11 +574,7 @@ QWeb.addDirective({
|
||||
for (let child of Object.values(clone.childNodes)) {
|
||||
t.appendChild(child);
|
||||
}
|
||||
const slotFn = qweb._compile(
|
||||
`slot_default_template`,
|
||||
t,
|
||||
ctx.parentNode!
|
||||
);
|
||||
const slotFn = qweb._compile(`slot_default_template`, t, ctx.parentNode!);
|
||||
qweb.slots[`${slotId}_default`] = slotFn.bind(qweb);
|
||||
}
|
||||
}
|
||||
@@ -619,9 +589,7 @@ QWeb.addDirective({
|
||||
|
||||
ctx.addElse();
|
||||
// need to update component
|
||||
const patchQueueCode = async
|
||||
? `patchQueue${componentID}`
|
||||
: "extra.patchQueue";
|
||||
const patchQueueCode = async ? `patchQueue${componentID}` : "extra.patchQueue";
|
||||
ctx.addLine(
|
||||
`def${defID} = def${defID} || w${componentID}.__updateProps(props${componentID}, extra.forceUpdate, ${patchQueueCode});`
|
||||
);
|
||||
@@ -650,11 +618,7 @@ QWeb.addDirective({
|
||||
ctx.addLine(`extra.promises.push(def${defID});`);
|
||||
}
|
||||
|
||||
if (
|
||||
node.hasAttribute("t-if") ||
|
||||
node.hasAttribute("t-else") ||
|
||||
node.hasAttribute("t-elif")
|
||||
) {
|
||||
if (node.hasAttribute("t-if") || node.hasAttribute("t-else") || node.hasAttribute("t-elif")) {
|
||||
ctx.closeIf();
|
||||
}
|
||||
|
||||
@@ -694,10 +658,7 @@ QWeb.addDirective({
|
||||
`extra.mountedHandlers[${nodeID}] = extra.mountedHandlers[${nodeID}] || (context['${handler}'] || ${error}).bind(owner);`
|
||||
);
|
||||
}
|
||||
addNodeHook(
|
||||
"insert",
|
||||
`if (context.__owl__.isMounted) { extra.mountedHandlers[${nodeID}](); }`
|
||||
);
|
||||
addNodeHook("insert", `if (context.__owl__.isMounted) { extra.mountedHandlers[${nodeID}](); }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -709,9 +670,7 @@ QWeb.addDirective({
|
||||
priority: 80,
|
||||
atNodeEncounter({ ctx, value }): boolean {
|
||||
const slotKey = ctx.generateID();
|
||||
ctx.addLine(
|
||||
`const slot${slotKey} = this.slots[context.__owl__.slotId + '_' + '${value}'];`
|
||||
);
|
||||
ctx.addLine(`const slot${slotKey} = this.slots[context.__owl__.slotId + '_' + '${value}'];`);
|
||||
ctx.addIf(`slot${slotKey}`);
|
||||
ctx.addLine(
|
||||
`slot${slotKey}(context.__owl__.parent, Object.assign({}, extra, {parentNode: c${
|
||||
@@ -747,9 +706,7 @@ QWeb.addDirective({
|
||||
handler = `(ev) => {context.state['${value}'] = ev.target.checked}`;
|
||||
} else if (type === "radio") {
|
||||
const nodeValue = node.getAttribute("value")!;
|
||||
ctx.addLine(
|
||||
`p${nodeID}.props = {checked:context.state['${value}'] === '${nodeValue}'};`
|
||||
);
|
||||
ctx.addLine(`p${nodeID}.props = {checked:context.state['${value}'] === '${nodeValue}'};`);
|
||||
handler = `(ev) => {context.state['${value}'] = ev.target.value}`;
|
||||
event = "click";
|
||||
} else {
|
||||
@@ -765,8 +722,6 @@ QWeb.addDirective({
|
||||
ctx.addLine(
|
||||
`extra.handlers['${event}' + ${nodeID}] = extra.handlers['${event}' + ${nodeID}] || (${handler});`
|
||||
);
|
||||
ctx.addLine(
|
||||
`p${nodeID}.on['${event}'] = extra.handlers['${event}' + ${nodeID}];`
|
||||
);
|
||||
ctx.addLine(`p${nodeID}.on['${event}'] = extra.handlers['${event}' + ${nodeID}];`);
|
||||
}
|
||||
});
|
||||
|
||||
+1
-5
@@ -308,11 +308,7 @@ export function connect<E extends EnvWithStore, P, S>(
|
||||
);
|
||||
}
|
||||
__owl__.ownProps = nextProps;
|
||||
const mergedProps = Object.assign(
|
||||
{},
|
||||
nextProps,
|
||||
__owl__.currentStoreProps
|
||||
);
|
||||
const mergedProps = Object.assign({}, nextProps, __owl__.currentStoreProps);
|
||||
return super.__updateProps(mergedProps, forceUpdate, patchQueue);
|
||||
}
|
||||
};
|
||||
|
||||
+1
-5
@@ -76,11 +76,7 @@ export function escape(str: string | number | undefined): string {
|
||||
*
|
||||
* Inspired by https://davidwalsh.name/javascript-debounce-function
|
||||
*/
|
||||
export function debounce(
|
||||
func: Function,
|
||||
wait: number,
|
||||
immediate?: boolean
|
||||
): Function {
|
||||
export function debounce(func: Function, wait: number, immediate?: boolean): Function {
|
||||
let timeout;
|
||||
return function(this: any) {
|
||||
const context = this;
|
||||
|
||||
+25
-118
@@ -109,14 +109,7 @@ function createKeyToOldIdx(
|
||||
return map;
|
||||
}
|
||||
|
||||
const hooks: (keyof Module)[] = [
|
||||
"create",
|
||||
"update",
|
||||
"remove",
|
||||
"destroy",
|
||||
"pre",
|
||||
"post"
|
||||
];
|
||||
const hooks: (keyof Module)[] = ["create", "update", "remove", "destroy", "pre", "post"];
|
||||
|
||||
export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
let i: number,
|
||||
@@ -138,13 +131,7 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
function emptyNodeAt(elm: Element) {
|
||||
const id = elm.id ? "#" + elm.id : "";
|
||||
const c = elm.className ? "." + elm.className.split(" ").join(".") : "";
|
||||
return vnode(
|
||||
api.tagName(elm).toLowerCase() + id + c,
|
||||
{},
|
||||
[],
|
||||
undefined,
|
||||
elm
|
||||
);
|
||||
return vnode(api.tagName(elm).toLowerCase() + id + c, {}, [], undefined, elm);
|
||||
}
|
||||
|
||||
function createRmCb(childElm: Node, listeners: number) {
|
||||
@@ -179,19 +166,14 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
const dotIdx = sel.indexOf(".", hashIdx);
|
||||
const hash = hashIdx > 0 ? hashIdx : sel.length;
|
||||
const dot = dotIdx > 0 ? dotIdx : sel.length;
|
||||
const tag =
|
||||
hashIdx !== -1 || dotIdx !== -1
|
||||
? sel.slice(0, Math.min(hash, dot))
|
||||
: sel;
|
||||
const tag = hashIdx !== -1 || dotIdx !== -1 ? sel.slice(0, Math.min(hash, dot)) : sel;
|
||||
const elm = (vnode.elm =
|
||||
isDef(data) && isDef((i = (data as VNodeData).ns))
|
||||
? api.createElementNS(i, tag)
|
||||
: api.createElement(tag));
|
||||
if (hash < dot) elm.setAttribute("id", sel.slice(hash + 1, dot));
|
||||
if (dotIdx > 0)
|
||||
elm.setAttribute("class", sel.slice(dot + 1).replace(/\./g, " "));
|
||||
for (i = 0, iLen = cbs.create.length; i < iLen; ++i)
|
||||
cbs.create[i](emptyNode, vnode);
|
||||
if (dotIdx > 0) elm.setAttribute("class", sel.slice(dot + 1).replace(/\./g, " "));
|
||||
for (i = 0, iLen = cbs.create.length; i < iLen; ++i) cbs.create[i](emptyNode, vnode);
|
||||
if (array(children)) {
|
||||
for (i = 0, iLen = children.length; i < iLen; ++i) {
|
||||
const ch = children[i];
|
||||
@@ -237,8 +219,7 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
data = vnode.data;
|
||||
if (data !== undefined) {
|
||||
if (isDef((i = data.hook)) && isDef((i = i.destroy))) i(vnode);
|
||||
for (i = 0, iLen = cbs.destroy.length; i < iLen; ++i)
|
||||
cbs.destroy[i](vnode);
|
||||
for (i = 0, iLen = cbs.destroy.length; i < iLen; ++i) cbs.destroy[i](vnode);
|
||||
if (vnode.children !== undefined) {
|
||||
for (j = 0, jLen = vnode.children.length; j < jLen; ++j) {
|
||||
i = vnode.children[j];
|
||||
@@ -267,13 +248,8 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
invokeDestroyHook(ch);
|
||||
listeners = cbs.remove.length + 1;
|
||||
rm = createRmCb(ch.elm as Node, listeners);
|
||||
for (i = 0, iLen = cbs.remove.length; i < iLen; ++i)
|
||||
cbs.remove[i](ch, rm);
|
||||
if (
|
||||
isDef((i = ch.data)) &&
|
||||
isDef((i = i.hook)) &&
|
||||
isDef((i = i.remove))
|
||||
) {
|
||||
for (i = 0, iLen = cbs.remove.length; i < iLen; ++i) cbs.remove[i](ch, rm);
|
||||
if (isDef((i = ch.data)) && isDef((i = i.hook)) && isDef((i = i.remove))) {
|
||||
i(ch, rm);
|
||||
} else {
|
||||
rm();
|
||||
@@ -335,11 +311,7 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
} else if (sameVnode(oldEndVnode, newStartVnode)) {
|
||||
// Vnode moved left
|
||||
patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
|
||||
api.insertBefore(
|
||||
parentElm,
|
||||
oldEndVnode.elm as Node,
|
||||
oldStartVnode.elm as Node
|
||||
);
|
||||
api.insertBefore(parentElm, oldEndVnode.elm as Node, oldStartVnode.elm as Node);
|
||||
oldEndVnode = oldCh[--oldEndIdx];
|
||||
newStartVnode = newCh[++newStartIdx];
|
||||
} else {
|
||||
@@ -366,11 +338,7 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
} else {
|
||||
patchVnode(elmToMove, newStartVnode, insertedVnodeQueue);
|
||||
oldCh[idxInOld] = undefined as any;
|
||||
api.insertBefore(
|
||||
parentElm,
|
||||
elmToMove.elm as Node,
|
||||
oldStartVnode.elm as Node
|
||||
);
|
||||
api.insertBefore(parentElm, elmToMove.elm as Node, oldStartVnode.elm as Node);
|
||||
}
|
||||
newStartVnode = newCh[++newStartIdx];
|
||||
}
|
||||
@@ -379,31 +347,16 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
if (oldStartIdx <= oldEndIdx || newStartIdx <= newEndIdx) {
|
||||
if (oldStartIdx > oldEndIdx) {
|
||||
before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm;
|
||||
addVnodes(
|
||||
parentElm,
|
||||
before,
|
||||
newCh,
|
||||
newStartIdx,
|
||||
newEndIdx,
|
||||
insertedVnodeQueue
|
||||
);
|
||||
addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
|
||||
} else {
|
||||
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function patchVnode(
|
||||
oldVnode: VNode,
|
||||
vnode: VNode,
|
||||
insertedVnodeQueue: VNodeQueue
|
||||
) {
|
||||
function patchVnode(oldVnode: VNode, vnode: VNode, insertedVnodeQueue: VNodeQueue) {
|
||||
let i: any, iLen: number, hook: any;
|
||||
if (
|
||||
isDef((i = vnode.data)) &&
|
||||
isDef((hook = i.hook)) &&
|
||||
isDef((i = hook.prepatch))
|
||||
) {
|
||||
if (isDef((i = vnode.data)) && isDef((hook = i.hook)) && isDef((i = hook.prepatch))) {
|
||||
i(oldVnode, vnode);
|
||||
}
|
||||
const elm = (vnode.elm = oldVnode.elm as Node);
|
||||
@@ -411,20 +364,14 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
let ch = vnode.children;
|
||||
if (oldVnode === vnode) return;
|
||||
if (vnode.data !== undefined) {
|
||||
for (i = 0, iLen = cbs.update.length; i < iLen; ++i)
|
||||
cbs.update[i](oldVnode, vnode);
|
||||
for (i = 0, iLen = cbs.update.length; i < iLen; ++i) cbs.update[i](oldVnode, vnode);
|
||||
i = vnode.data.hook;
|
||||
if (isDef(i) && isDef((i = i.update))) i(oldVnode, vnode);
|
||||
}
|
||||
if (isUndef(vnode.text)) {
|
||||
if (isDef(oldCh) && isDef(ch)) {
|
||||
if (oldCh !== ch)
|
||||
updateChildren(
|
||||
elm,
|
||||
oldCh as Array<VNode>,
|
||||
ch as Array<VNode>,
|
||||
insertedVnodeQueue
|
||||
);
|
||||
updateChildren(elm, oldCh as Array<VNode>, ch as Array<VNode>, insertedVnodeQueue);
|
||||
} else if (isDef(ch)) {
|
||||
if (isDef(oldVnode.text)) api.setTextContent(elm, "");
|
||||
addVnodes(
|
||||
@@ -436,23 +383,13 @@ export function init(modules: Array<Partial<Module>>, domApi?: DOMAPI) {
|
||||
insertedVnodeQueue
|
||||
);
|
||||
} else if (isDef(oldCh)) {
|
||||
removeVnodes(
|
||||
elm,
|
||||
oldCh as Array<VNode>,
|
||||
0,
|
||||
(oldCh as Array<VNode>).length - 1
|
||||
);
|
||||
removeVnodes(elm, oldCh as Array<VNode>, 0, (oldCh as Array<VNode>).length - 1);
|
||||
} else if (isDef(oldVnode.text)) {
|
||||
api.setTextContent(elm, "");
|
||||
}
|
||||
} else if (oldVnode.text !== vnode.text) {
|
||||
if (isDef(oldCh)) {
|
||||
removeVnodes(
|
||||
elm,
|
||||
oldCh as Array<VNode>,
|
||||
0,
|
||||
(oldCh as Array<VNode>).length - 1
|
||||
);
|
||||
removeVnodes(elm, oldCh as Array<VNode>, 0, (oldCh as Array<VNode>).length - 1);
|
||||
}
|
||||
api.setTextContent(elm, vnode.text as string);
|
||||
}
|
||||
@@ -510,11 +447,7 @@ interface DOMAPI {
|
||||
createElementNS: (namespaceURI: string, qualifiedName: string) => Element;
|
||||
createTextNode: (text: string) => Text;
|
||||
createComment: (text: string) => Comment;
|
||||
insertBefore: (
|
||||
parentNode: Node,
|
||||
newNode: Node,
|
||||
referenceNode: Node | null
|
||||
) => void;
|
||||
insertBefore: (parentNode: Node, newNode: Node, referenceNode: Node | null) => void;
|
||||
removeChild: (node: Node, child: Node) => void;
|
||||
appendChild: (node: Node, child: Node) => void;
|
||||
parentNode: (node: Node) => Node;
|
||||
@@ -543,11 +476,7 @@ function createComment(text: string): Comment {
|
||||
return document.createComment(text);
|
||||
}
|
||||
|
||||
function insertBefore(
|
||||
parentNode: Node,
|
||||
newNode: Node,
|
||||
referenceNode: Node | null
|
||||
): void {
|
||||
function insertBefore(parentNode: Node, newNode: Node, referenceNode: Node | null): void {
|
||||
parentNode.insertBefore(newNode, referenceNode);
|
||||
}
|
||||
|
||||
@@ -644,21 +573,13 @@ type VNodeChildElement = VNode | string | number | undefined | null;
|
||||
type ArrayOrElement<T> = T | T[];
|
||||
type VNodeChildren = ArrayOrElement<VNodeChildElement>;
|
||||
|
||||
function addNS(
|
||||
data: any,
|
||||
children: VNodes | undefined,
|
||||
sel: string | undefined
|
||||
): void {
|
||||
function addNS(data: any, children: VNodes | undefined, sel: string | undefined): void {
|
||||
data.ns = "http://www.w3.org/2000/svg";
|
||||
if (sel !== "foreignObject" && children !== undefined) {
|
||||
for (let i = 0, iLen = children.length; i < iLen; ++i) {
|
||||
let childData = children[i].data;
|
||||
if (childData !== undefined) {
|
||||
addNS(
|
||||
childData,
|
||||
(children[i] as VNode).children as VNodes,
|
||||
children[i].sel
|
||||
);
|
||||
addNS(childData, (children[i] as VNode).children as VNodes, children[i].sel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -697,13 +618,7 @@ export function h(sel: any, b?: any, c?: any): VNode {
|
||||
if (children !== undefined) {
|
||||
for (i = 0, iLen = children.length; i < iLen; ++i) {
|
||||
if (primitive(children[i]))
|
||||
children[i] = vnode(
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
children[i],
|
||||
undefined
|
||||
);
|
||||
children[i] = vnode(undefined, undefined, undefined, children[i], undefined);
|
||||
}
|
||||
}
|
||||
if (
|
||||
@@ -769,9 +684,7 @@ interface Module {
|
||||
//------------------------------------------------------------------------------
|
||||
// module/eventlisteners.ts
|
||||
//------------------------------------------------------------------------------
|
||||
type On = {
|
||||
[N in keyof HTMLElementEventMap]?: (ev: HTMLElementEventMap[N]) => void
|
||||
} & {
|
||||
type On = { [N in keyof HTMLElementEventMap]?: (ev: HTMLElementEventMap[N]) => void } & {
|
||||
[event: string]: EventListener;
|
||||
};
|
||||
|
||||
@@ -850,8 +763,7 @@ function updateEventListeners(oldVnode: VNode, vnode?: VNode): void {
|
||||
// add new listeners which has not already attached
|
||||
if (on) {
|
||||
// reuse existing listener or create new
|
||||
var listener = ((vnode as any).listener =
|
||||
(oldVnode as any).listener || createListener());
|
||||
var listener = ((vnode as any).listener = (oldVnode as any).listener || createListener());
|
||||
// update vnode for listener
|
||||
listener.vnode = vnode;
|
||||
|
||||
@@ -973,9 +885,4 @@ const classModule = { create: updateClass, update: updateClass } as Module;
|
||||
//------------------------------------------------------------------------------
|
||||
// patch
|
||||
//------------------------------------------------------------------------------
|
||||
export const patch = init([
|
||||
eventListenersModule,
|
||||
attrsModule,
|
||||
propsModule,
|
||||
classModule
|
||||
]);
|
||||
export const patch = init([eventListenersModule, attrsModule, propsModule, classModule]);
|
||||
|
||||
@@ -173,10 +173,7 @@ describe("animations", () => {
|
||||
test("t-transition combined with component", async () => {
|
||||
expect.assertions(5);
|
||||
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div><Child t-transition="chimay"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("Parent", `<div><Child t-transition="chimay"/></div>`);
|
||||
env.qweb.addTemplate("Child", `<span>blue</span>`);
|
||||
class Parent extends Widget {
|
||||
components = { Child: Child };
|
||||
@@ -320,9 +317,7 @@ describe("animations", () => {
|
||||
expect(spans.length).toBe(1);
|
||||
expect(spans[0].className).toBe(`chimay-${phase} chimay-${phase}-active`);
|
||||
cb();
|
||||
expect(spans[0].className).toBe(
|
||||
`chimay-${phase}-active chimay-${phase}-to`
|
||||
);
|
||||
expect(spans[0].className).toBe(`chimay-${phase}-active chimay-${phase}-to`);
|
||||
def.resolve();
|
||||
});
|
||||
|
||||
@@ -330,9 +325,7 @@ describe("animations", () => {
|
||||
button!.click();
|
||||
await def; // wait for the mocked repaint to be done
|
||||
widget.el!.querySelector("span")!.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><button>Toggle</button><span class="">blue</span></div>'
|
||||
);
|
||||
expect(fixture.innerHTML).toBe('<div><button>Toggle</button><span class="">blue</span></div>');
|
||||
|
||||
// click to remove the span, and click again to re-add it before transitionend
|
||||
def = makeDeferred();
|
||||
@@ -346,9 +339,7 @@ describe("animations", () => {
|
||||
|
||||
await def; // wait for the mocked repaint to be done
|
||||
widget.el!.querySelector("span")!.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><button>Toggle</button><span class="">blue</span></div>'
|
||||
);
|
||||
expect(fixture.innerHTML).toBe('<div><button>Toggle</button><span class="">blue</span></div>');
|
||||
});
|
||||
|
||||
test("t-transition combined with t-component, remove and re-add before transitionend", async () => {
|
||||
@@ -386,9 +377,7 @@ describe("animations", () => {
|
||||
expect(spans.length).toBe(1);
|
||||
expect(spans[0].className).toBe(`chimay-${phase} chimay-${phase}-active`);
|
||||
cb();
|
||||
expect(spans[0].className).toBe(
|
||||
`chimay-${phase}-active chimay-${phase}-to`
|
||||
);
|
||||
expect(spans[0].className).toBe(`chimay-${phase}-active chimay-${phase}-to`);
|
||||
def.resolve();
|
||||
});
|
||||
|
||||
@@ -396,9 +385,7 @@ describe("animations", () => {
|
||||
button!.click();
|
||||
await def; // wait for the mocked repaint to be done
|
||||
widget.el!.querySelector("span")!.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><button>Toggle</button><span class="">blue</span></div>'
|
||||
);
|
||||
expect(fixture.innerHTML).toBe('<div><button>Toggle</button><span class="">blue</span></div>');
|
||||
|
||||
// click to remove the span, and click again to re-add it before transitionend
|
||||
def = makeDeferred();
|
||||
@@ -412,8 +399,6 @@ describe("animations", () => {
|
||||
|
||||
await def; // wait for the mocked repaint to be done
|
||||
widget.el!.querySelector("span")!.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><button>Toggle</button><span class="">blue</span></div>'
|
||||
);
|
||||
expect(fixture.innerHTML).toBe('<div><button>Toggle</button><span class="">blue</span></div>');
|
||||
});
|
||||
});
|
||||
|
||||
+60
-202
@@ -92,9 +92,7 @@ describe("basic widget properties", () => {
|
||||
try {
|
||||
await widget.mount(fixture);
|
||||
} catch (e) {
|
||||
expect(e.message).toBe(
|
||||
'Could not find template for component "SomeWidget"'
|
||||
);
|
||||
expect(e.message).toBe('Could not find template for component "SomeWidget"');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -128,9 +126,7 @@ describe("basic widget properties", () => {
|
||||
class StyledWidget extends Widget {}
|
||||
const widget = new StyledWidget(env);
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
`<div style="font-weight:bold;" class="some-class">world</div>`
|
||||
);
|
||||
expect(fixture.innerHTML).toBe(`<div style="font-weight:bold;" class="some-class">world</div>`);
|
||||
});
|
||||
|
||||
test("changing state before first render does not trigger a render", async () => {
|
||||
@@ -249,10 +245,7 @@ describe("lifecycle hooks", () => {
|
||||
"ParentWidget",
|
||||
`<div><t t-if="state.flag"><t t-component="child"/></t></div>`
|
||||
);
|
||||
env.qweb.addTemplate(
|
||||
"ChildWidget",
|
||||
`<div><t t-component="childchild"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ChildWidget", `<div><t t-component="childchild"/></div>`);
|
||||
|
||||
class ParentWidget extends Widget {
|
||||
components = { child: ChildWidget };
|
||||
@@ -300,10 +293,7 @@ describe("lifecycle hooks", () => {
|
||||
test("willPatch, patched hook are called on subsubcomponents, in proper order", async () => {
|
||||
const steps: any[] = [];
|
||||
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="child" n="state.n"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="child" n="state.n"/></div>`);
|
||||
class ParentWidget extends Widget {
|
||||
components = { child: ChildWidget };
|
||||
state = { n: 1 };
|
||||
@@ -314,10 +304,7 @@ describe("lifecycle hooks", () => {
|
||||
steps.push("parent:patched");
|
||||
}
|
||||
}
|
||||
env.qweb.addTemplate(
|
||||
"ChildWidget",
|
||||
`<div><t t-component="childchild" n="props.n"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ChildWidget", `<div><t t-component="childchild" n="props.n"/></div>`);
|
||||
class ChildWidget extends Widget {
|
||||
components = { childchild: ChildChildWidget };
|
||||
willPatch() {
|
||||
@@ -780,11 +767,7 @@ describe("lifecycle hooks", () => {
|
||||
expect(steps).toEqual(["child:mounted", "child:willUnmount"]);
|
||||
widget.state.flag = true;
|
||||
await nextTick();
|
||||
expect(steps).toEqual([
|
||||
"child:mounted",
|
||||
"child:willUnmount",
|
||||
"child:mounted"
|
||||
]);
|
||||
expect(steps).toEqual(["child:mounted", "child:willUnmount", "child:mounted"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -859,10 +842,7 @@ describe("composition", () => {
|
||||
|
||||
test("can use components from the global registry", async () => {
|
||||
QWeb.register("WidgetB", WidgetB);
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="WidgetB"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="WidgetB"/></div>`);
|
||||
class ParentWidget extends Widget {}
|
||||
const widget = new ParentWidget(env);
|
||||
await widget.mount(fixture);
|
||||
@@ -872,10 +852,7 @@ describe("composition", () => {
|
||||
|
||||
test("don't fallback to global registry if widget defined locally", async () => {
|
||||
QWeb.register("WidgetB", WidgetB); // should not use this widget
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="WidgetB"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="WidgetB"/></div>`);
|
||||
env.qweb.addTemplate("AnotherWidgetB", `<span>Belgium</span>`);
|
||||
class AnotherWidgetB extends Widget {}
|
||||
class ParentWidget extends Widget {
|
||||
@@ -912,17 +889,12 @@ describe("composition", () => {
|
||||
try {
|
||||
await parent.mount(fixture);
|
||||
} catch (e) {
|
||||
expect(e.message).toBe(
|
||||
'Cannot find the definition of component "SomeMispelledWidget"'
|
||||
);
|
||||
expect(e.message).toBe('Cannot find the definition of component "SomeMispelledWidget"');
|
||||
}
|
||||
});
|
||||
|
||||
test("t-refs on widget are components", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"WidgetC",
|
||||
`<div>Hello<t t-ref="mywidgetb" t-component="b"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("WidgetC", `<div>Hello<t t-ref="mywidgetb" t-component="b"/></div>`);
|
||||
class WidgetC extends Widget {
|
||||
components = { b: WidgetB };
|
||||
}
|
||||
@@ -1007,24 +979,17 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("modifying a sub widget", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="Counter"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="Counter"/></div>`);
|
||||
class ParentWidget extends Widget {
|
||||
components = { Counter };
|
||||
}
|
||||
const widget = new ParentWidget(env);
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>0<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>0<button>Inc</button></div></div>");
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>1<button>Inc</button></div></div>");
|
||||
});
|
||||
|
||||
test("refs in a loop", async () => {
|
||||
@@ -1066,10 +1031,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("rerendering a widget with a sub widget", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="Counter"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="Counter"/></div>`);
|
||||
class ParentWidget extends Widget {
|
||||
components = { Counter };
|
||||
}
|
||||
@@ -1078,20 +1040,13 @@ describe("composition", () => {
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>1<button>Inc</button></div></div>");
|
||||
await widget.render();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>1<button>Inc</button></div></div>");
|
||||
});
|
||||
|
||||
test("sub components are destroyed if no longer in dom, then recreated", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-if="state.ok"><Counter /></t></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-if="state.ok"><Counter /></t></div>`);
|
||||
class ParentWidget extends Widget {
|
||||
state = { ok: true };
|
||||
components = { Counter };
|
||||
@@ -1101,18 +1056,14 @@ describe("composition", () => {
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>1<button>Inc</button></div></div>");
|
||||
widget.state.ok = false;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div></div>");
|
||||
|
||||
widget.state.ok = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>0<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>0<button>Inc</button></div></div>");
|
||||
});
|
||||
|
||||
test("sub components with t-keepalive are not destroyed if no longer in dom", async () => {
|
||||
@@ -1129,9 +1080,7 @@ describe("composition", () => {
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>1<button>Inc</button></div></div>");
|
||||
const counter = children(widget)[0];
|
||||
expect(counter.__owl__.isMounted).toBe(true);
|
||||
|
||||
@@ -1143,9 +1092,7 @@ describe("composition", () => {
|
||||
widget.state.ok = true;
|
||||
await nextTick();
|
||||
expect(counter.__owl__.isMounted).toBe(true);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div>1<button>Inc</button></div></div>");
|
||||
});
|
||||
|
||||
test("sub components dom state with t-keepalive is preserved", async () => {
|
||||
@@ -1320,10 +1267,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("t-component with dynamic value", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="{{state.widget}}"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="{{state.widget}}"/></div>`);
|
||||
class ParentWidget extends Widget {
|
||||
components = { WidgetB };
|
||||
state = { widget: "WidgetB" };
|
||||
@@ -1335,10 +1279,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("t-component with dynamic value 2", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="Widget{{state.widget}}"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="Widget{{state.widget}}"/></div>`);
|
||||
class ParentWidget extends Widget {
|
||||
components = { WidgetB };
|
||||
state = { widget: "B" };
|
||||
@@ -1352,10 +1293,7 @@ describe("composition", () => {
|
||||
|
||||
describe("props evaluation ", () => {
|
||||
test("explicit object prop", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div><t t-component="child" value="state.val"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("Parent", `<div><t t-component="child" value="state.val"/></div>`);
|
||||
class Parent extends Widget {
|
||||
components = { child: Child };
|
||||
state = { val: 42 };
|
||||
@@ -1379,10 +1317,7 @@ describe("props evaluation ", () => {
|
||||
env.qweb.addTemplate("Child", `<span><t t-esc="props.greetings"/></span>`);
|
||||
class Child extends Widget {}
|
||||
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div><t t-component="child" greetings="greetings"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("Parent", `<div><t t-component="child" greetings="greetings"/></div>`);
|
||||
class Parent extends Widget {
|
||||
components = { child: Child };
|
||||
get greetings() {
|
||||
@@ -1600,9 +1535,7 @@ describe("class and style attributes with t-component", () => {
|
||||
}
|
||||
const widget = new ParentWidget(env);
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
`<div><div style="font-weight: bold;"></div></div>`
|
||||
);
|
||||
expect(fixture.innerHTML).toBe(`<div><div style="font-weight: bold;"></div></div>`);
|
||||
});
|
||||
|
||||
test("dynamic t-att-style is properly added and updated on widget root el", async () => {
|
||||
@@ -1622,16 +1555,12 @@ describe("class and style attributes with t-component", () => {
|
||||
|
||||
expect(env.qweb.templates.ParentWidget.fn.toString()).toMatchSnapshot();
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
`<div><div style="font-size: 20px;"></div></div>`
|
||||
);
|
||||
expect(fixture.innerHTML).toBe(`<div><div style="font-size: 20px;"></div></div>`);
|
||||
|
||||
widget.state.style = "font-size: 30px";
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
`<div><div style="font-size: 30px;"></div></div>`
|
||||
);
|
||||
expect(fixture.innerHTML).toBe(`<div><div style="font-size: 30px;"></div></div>`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1891,10 +1820,7 @@ describe("other directives with t-component", () => {
|
||||
});
|
||||
|
||||
test("t-if works with t-component", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"ParentWidget",
|
||||
`<div><t t-component="child" t-if="state.flag"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("ParentWidget", `<div><t t-component="child" t-if="state.flag"/></div>`);
|
||||
class ParentWidget extends Widget {
|
||||
components = { child: Child };
|
||||
state = { flag: true };
|
||||
@@ -2044,19 +1970,13 @@ describe("random stuff/miscellaneous", () => {
|
||||
// in this situation, we protect against a bug that occurred: because of the
|
||||
// interplay between components and vnodes, a sub widget vnode was patched
|
||||
// twice.
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div><t t-component="child" flag="state.flag"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("Parent", `<div><t t-component="child" flag="state.flag"/></div>`);
|
||||
class Parent extends Widget {
|
||||
components = { child: Child };
|
||||
state = { flag: false };
|
||||
}
|
||||
|
||||
env.qweb.addTemplate(
|
||||
"Child",
|
||||
`<span>abc<t t-if="props.flag">def</t></span>`
|
||||
);
|
||||
env.qweb.addTemplate("Child", `<span>abc<t t-if="props.flag">def</t></span>`);
|
||||
class Child extends Widget {}
|
||||
|
||||
const widget = new Parent(env);
|
||||
@@ -2077,10 +1997,7 @@ describe("random stuff/miscellaneous", () => {
|
||||
state = { flag: false };
|
||||
}
|
||||
|
||||
env.qweb.addTemplate(
|
||||
"Child",
|
||||
`<span>abc<t t-if="props.flag">def</t></span>`
|
||||
);
|
||||
env.qweb.addTemplate("Child", `<span>abc<t t-if="props.flag">def</t></span>`);
|
||||
class Child extends Widget {}
|
||||
|
||||
const widget = new Parent(env);
|
||||
@@ -2190,9 +2107,7 @@ describe("random stuff/miscellaneous", () => {
|
||||
|
||||
const a = new A(env);
|
||||
await a.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
`<div>A<div>B</div><div>C<div>D</div><div>E</div></div></div>`
|
||||
);
|
||||
expect(fixture.innerHTML).toBe(`<div>A<div>B</div><div>C<div>D</div><div>E</div></div></div>`);
|
||||
expect(steps).toEqual([
|
||||
"A:willStart",
|
||||
"A:render",
|
||||
@@ -2267,10 +2182,7 @@ describe("async rendering", () => {
|
||||
test("destroying/recreating a subwidget with different props (if start is not over)", async () => {
|
||||
let def = makeDeferred();
|
||||
let n = 0;
|
||||
env.qweb.addTemplate(
|
||||
"W",
|
||||
`<div><t t-if="state.val > 1"><Child val="state.val"/></t></div>`
|
||||
);
|
||||
env.qweb.addTemplate("W", `<div><t t-if="state.val > 1"><Child val="state.val"/></t></div>`);
|
||||
class W extends Widget {
|
||||
components = { Child };
|
||||
state = { val: 1 };
|
||||
@@ -2380,23 +2292,15 @@ describe("async rendering", () => {
|
||||
}
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
"<div><span>a1</span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div><span>a1</span></div>");
|
||||
parent.state.valA = 2;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
"<div><span>a1</span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div><span>a1</span></div>");
|
||||
parent.state.flagB = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
"<div><span>a1</span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div><span>a1</span></div>");
|
||||
defB.resolve();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
"<div><span>a1</span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div><span>a1</span></div>");
|
||||
defA.resolve();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
@@ -2569,25 +2473,19 @@ describe("async rendering", () => {
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>0</span><span>0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>0</span><span>0</span>");
|
||||
|
||||
// click on button to increment Parent counter
|
||||
def = makeDeferred();
|
||||
fixture.querySelector("button")!.click();
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>1</span><span>0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>1</span><span>0</span>");
|
||||
|
||||
def.resolve();
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>1</span><span>1</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>1</span><span>1</span>");
|
||||
});
|
||||
|
||||
test("fast component with t-asyncroot directive", async () => {
|
||||
@@ -2624,25 +2522,19 @@ describe("async rendering", () => {
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>0</span><span>0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>0</span><span>0</span>");
|
||||
|
||||
// click on button to increment Parent counter
|
||||
def = makeDeferred();
|
||||
fixture.querySelector("button")!.click();
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>1</span><span>0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>1</span><span>0</span>");
|
||||
|
||||
def.resolve();
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>1</span><span>1</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>1</span><span>1</span>");
|
||||
});
|
||||
|
||||
test("t-component with t-asyncroot directive: mixed re-renderings", async () => {
|
||||
@@ -2687,40 +2579,30 @@ describe("async rendering", () => {
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>0/0</span><span>0/0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>0/0</span><span>0/0</span>");
|
||||
|
||||
// click on button to increment Parent counter
|
||||
def = makeDeferred();
|
||||
fixture.querySelector("button")!.click();
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>0/1</span><span>0/0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>0/1</span><span>0/0</span>");
|
||||
|
||||
// click on each Child to increment their local counter
|
||||
const children = parent.el!.querySelectorAll("span");
|
||||
children[0]!.click();
|
||||
await nextTick();
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>1/1</span><span>0/0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>1/1</span><span>0/0</span>");
|
||||
|
||||
children[1]!.click();
|
||||
await nextTick();
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>1/1</span><span>1/0</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>1/1</span><span>1/0</span>");
|
||||
|
||||
// finalize first re-rendering (coming from the props update)
|
||||
def.resolve();
|
||||
await nextTick();
|
||||
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||
"<span>1/1</span><span>1/1</span>"
|
||||
);
|
||||
expect(fixture.querySelector(".children")!.innerHTML).toBe("<span>1/1</span><span>1/1</span>");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2860,9 +2742,7 @@ describe("widget and observable state", () => {
|
||||
try {
|
||||
await parent.mount(fixture);
|
||||
} catch (e) {
|
||||
expect(e.message).toBe(
|
||||
'Observed state cannot be changed here! (key: "coffee", val: "2")'
|
||||
);
|
||||
expect(e.message).toBe('Observed state cannot be changed here! (key: "coffee", val: "2")');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -2903,10 +2783,7 @@ describe("t-mounted directive", () => {
|
||||
});
|
||||
|
||||
test("combined with a t-if", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"TestWidget",
|
||||
`<div><input t-if="state.flag" t-mounted="f"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("TestWidget", `<div><input t-if="state.flag" t-mounted="f"/></div>`);
|
||||
class TestWidget extends Widget {
|
||||
state = { flag: false };
|
||||
f() {}
|
||||
@@ -2922,10 +2799,7 @@ describe("t-mounted directive", () => {
|
||||
});
|
||||
|
||||
test("combined with a t-ref", async () => {
|
||||
env.qweb.addTemplate(
|
||||
"TestWidget",
|
||||
`<div><input t-ref="input" t-mounted="f"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("TestWidget", `<div><input t-ref="input" t-mounted="f"/></div>`);
|
||||
class TestWidget extends Widget {
|
||||
f() {}
|
||||
}
|
||||
@@ -3099,9 +2973,7 @@ describe("t-slot directive", () => {
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>sts rocks</span></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div><span>sts rocks</span></div></div>");
|
||||
});
|
||||
|
||||
test("default slot work with text nodes", async () => {
|
||||
@@ -3144,9 +3016,7 @@ describe("t-slot directive", () => {
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>sts</span><span>rocks</span></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div><span>sts</span><span>rocks</span></div></div>");
|
||||
});
|
||||
|
||||
test("multiple roots are allowed in a default slot", async () => {
|
||||
@@ -3168,9 +3038,7 @@ describe("t-slot directive", () => {
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>sts</span><span>rocks</span></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div><span>sts</span><span>rocks</span></div></div>");
|
||||
});
|
||||
|
||||
test("missing slots are ignored", async () => {
|
||||
@@ -3193,9 +3061,7 @@ describe("t-slot directive", () => {
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><span><span>some content</span></span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><span><span>some content</span></span></div>");
|
||||
});
|
||||
|
||||
test("t-debug on a t-set (defining a slot)", async () => {
|
||||
@@ -3264,16 +3130,12 @@ describe("t-model directive", () => {
|
||||
const comp = new SomeComponent(env);
|
||||
await comp.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><input type="checkbox"><span>no</span></div>'
|
||||
);
|
||||
expect(fixture.innerHTML).toBe('<div><input type="checkbox"><span>no</span></div>');
|
||||
|
||||
let input = fixture.querySelector("input")!;
|
||||
input.click();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><input type="checkbox"><span>yes</span></div>'
|
||||
);
|
||||
expect(fixture.innerHTML).toBe('<div><input type="checkbox"><span>yes</span></div>');
|
||||
expect(comp.state.flag).toBe(true);
|
||||
expect(env.qweb.templates.SomeComponent.fn.toString()).toMatchSnapshot();
|
||||
|
||||
@@ -3296,16 +3158,12 @@ describe("t-model directive", () => {
|
||||
const comp = new SomeComponent(env);
|
||||
await comp.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><textarea></textarea><span></span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><textarea></textarea><span></span></div>");
|
||||
|
||||
const textarea = fixture.querySelector("textarea")!;
|
||||
await editInput(textarea, "test");
|
||||
expect(comp.state.text).toBe("test");
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><textarea></textarea><span>test</span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><textarea></textarea><span>test</span></div>");
|
||||
});
|
||||
|
||||
test("on an input type=radio", async () => {
|
||||
|
||||
@@ -52,14 +52,10 @@ interface FileData {
|
||||
sections: MarkDownSection[];
|
||||
}
|
||||
|
||||
function isLinkValid(
|
||||
link: MarkDownLink,
|
||||
current: FileData,
|
||||
files: FileData[]
|
||||
): boolean {
|
||||
function isLinkValid(link: MarkDownLink, current: FileData, files: FileData[]): boolean {
|
||||
const parts = link.link.split("#");
|
||||
const currentParts = current.name.split("/");
|
||||
const path = currentParts.length > 1 ? currentParts[0] + '/' : "";
|
||||
const path = currentParts.length > 1 ? currentParts[0] + "/" : "";
|
||||
const fullName = path + parts[0];
|
||||
if (parts.length === 1) {
|
||||
// no # in url
|
||||
@@ -70,8 +66,7 @@ function isLinkValid(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const file =
|
||||
parts[0] === "" ? current : files.find(f => f.name === fullName);
|
||||
const file = parts[0] === "" ? current : files.find(f => f.name === fullName);
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,7 @@ describe("event bus behaviour", () => {
|
||||
test("throw error if callback is undefined", () => {
|
||||
expect.assertions(1);
|
||||
const bus = new EventBus();
|
||||
expect(() => bus.on("event", {}, <any>undefined)).toThrow(
|
||||
`Missing callback`
|
||||
);
|
||||
expect(() => bus.on("event", {}, <any>undefined)).toThrow(`Missing callback`);
|
||||
});
|
||||
|
||||
test("can unsubscribe", () => {
|
||||
|
||||
+2
-9
@@ -68,11 +68,7 @@ export function renderToDOM(
|
||||
return result.elm as HTMLElement;
|
||||
}
|
||||
|
||||
export function renderToString(
|
||||
qweb: QWeb,
|
||||
t: string,
|
||||
context: EvalContext = {}
|
||||
): string {
|
||||
export function renderToString(qweb: QWeb, t: string, context: EvalContext = {}): string {
|
||||
const node = renderToDOM(qweb, t, context);
|
||||
return node instanceof Text ? node.textContent! : node.outerHTML;
|
||||
}
|
||||
@@ -92,10 +88,7 @@ export function unpatchNextFrame() {
|
||||
UTILS.nextFrame = nextFrame;
|
||||
}
|
||||
|
||||
export async function editInput(
|
||||
input: HTMLInputElement | HTMLTextAreaElement,
|
||||
value: string
|
||||
) {
|
||||
export async function editInput(input: HTMLInputElement | HTMLTextAreaElement, value: string) {
|
||||
input.value = value;
|
||||
input.dispatchEvent(new Event("input"));
|
||||
input.dispatchEvent(new Event("change"));
|
||||
|
||||
@@ -126,7 +126,6 @@ describe("props validation", () => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("can validate a prop with multiple types", async () => {
|
||||
let TestWidget = class extends Widget {
|
||||
static props = { p: [String, Boolean] };
|
||||
@@ -155,10 +154,8 @@ describe("props validation", () => {
|
||||
expect(() => {
|
||||
new TestWidget(env, { p: 1 });
|
||||
}).toThrow();
|
||||
|
||||
});
|
||||
|
||||
|
||||
test("can validate an array with given primitive type", async () => {
|
||||
let TestWidget = class extends Widget {
|
||||
static props = { p: { type: Array, element: String } };
|
||||
@@ -222,7 +219,7 @@ describe("props validation", () => {
|
||||
type: Object,
|
||||
shape: {
|
||||
id: Number,
|
||||
url: [Boolean, {type: Array, element: Number}],
|
||||
url: [Boolean, { type: Array, element: Number }]
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -236,15 +233,13 @@ describe("props validation", () => {
|
||||
expect(() => {
|
||||
new TestWidget(env, { p: { id: 1, url: [12, true] } });
|
||||
}).toThrow();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("default props", () => {
|
||||
test("can set default values", async () => {
|
||||
class TestWidget extends Widget {
|
||||
static defaultProps = {p: 4}
|
||||
static defaultProps = { p: 4 };
|
||||
}
|
||||
|
||||
const w = new TestWidget(env, {});
|
||||
@@ -253,7 +248,7 @@ describe("default props", () => {
|
||||
|
||||
test("default values are also set whenever component is updated", async () => {
|
||||
class TestWidget extends Widget {
|
||||
static defaultProps = {p: 4}
|
||||
static defaultProps = { p: 4 };
|
||||
}
|
||||
|
||||
const w = new TestWidget(env, { p: 1 });
|
||||
|
||||
+35
-111
@@ -26,9 +26,7 @@ describe("static templates", () => {
|
||||
|
||||
test("simple dynamic value", () => {
|
||||
qweb.addTemplate("test", '<t><t t-esc="text"/></t>');
|
||||
expect(renderToString(qweb, "test", { text: "hello vdom" })).toBe(
|
||||
"hello vdom"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { text: "hello vdom" })).toBe("hello vdom");
|
||||
});
|
||||
|
||||
test("simple string, with some dynamic value", () => {
|
||||
@@ -54,9 +52,7 @@ describe("static templates", () => {
|
||||
|
||||
describe("error handling", () => {
|
||||
test("invalid xml", () => {
|
||||
expect(() => qweb.addTemplate("test", "<div>")).toThrow(
|
||||
"Invalid XML in template"
|
||||
);
|
||||
expect(() => qweb.addTemplate("test", "<div>")).toThrow("Invalid XML in template");
|
||||
});
|
||||
|
||||
test("template with text node and tag", () => {
|
||||
@@ -73,9 +69,7 @@ describe("error handling", () => {
|
||||
|
||||
test("cannot add twice the same template", () => {
|
||||
qweb.addTemplate("test", `<t></t>`);
|
||||
expect(() => qweb.addTemplate("test", "<div/>", true)).not.toThrow(
|
||||
"already defined"
|
||||
);
|
||||
expect(() => qweb.addTemplate("test", "<div/>", true)).not.toThrow("already defined");
|
||||
expect(() => qweb.addTemplate("test", "<div/>")).toThrow("already defined");
|
||||
});
|
||||
|
||||
@@ -94,19 +88,14 @@ describe("error handling", () => {
|
||||
|
||||
test("nice error when t-on is evaluated with a missing event", () => {
|
||||
qweb.addTemplate("templatename", `<div t-on="somemethod"></div>`);
|
||||
expect(() =>
|
||||
qweb.render("templatename", { someMethod() {} }, { handlers: [] })
|
||||
).toThrow("Missing event name with t-on directive");
|
||||
expect(() => qweb.render("templatename", { someMethod() {} }, { handlers: [] })).toThrow(
|
||||
"Missing event name with t-on directive"
|
||||
);
|
||||
});
|
||||
|
||||
test("error when unknown directive", () => {
|
||||
qweb.addTemplate(
|
||||
"templatename",
|
||||
`<div t-best-beer="rochefort 10">test</div>`
|
||||
);
|
||||
expect(() => qweb.render("templatename")).toThrow(
|
||||
"Unknown QWeb directive: 't-best-beer'"
|
||||
);
|
||||
qweb.addTemplate("templatename", `<div t-best-beer="rochefort 10">test</div>`);
|
||||
expect(() => qweb.render("templatename")).toThrow("Unknown QWeb directive: 't-best-beer'");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,9 +112,7 @@ describe("t-esc", () => {
|
||||
|
||||
test.skip("escaping", () => {
|
||||
qweb.addTemplate("test", `<span><t t-esc="var"/></span>`);
|
||||
expect(renderToString(qweb, "test", { var: "<ok>" })).toBe(
|
||||
"<span><ok></span>"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { var: "<ok>" })).toBe("<span><ok></span>");
|
||||
});
|
||||
|
||||
test("escaping on a node", () => {
|
||||
@@ -157,9 +144,7 @@ describe("t-raw", () => {
|
||||
|
||||
test("not escaping", () => {
|
||||
qweb.addTemplate("test", `<div><t t-raw="var"/></div>`);
|
||||
expect(renderToString(qweb, "test", { var: "<ok></ok>" })).toBe(
|
||||
"<div><ok></ok></div>"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { var: "<ok></ok>" })).toBe("<div><ok></ok></div>");
|
||||
});
|
||||
|
||||
test("t-raw and another sibling node", () => {
|
||||
@@ -172,10 +157,7 @@ describe("t-raw", () => {
|
||||
|
||||
describe("t-set", () => {
|
||||
test("set from attribute literal", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div><t t-set="value" t-value="'ok'"/><t t-esc="value"/></div>`
|
||||
);
|
||||
qweb.addTemplate("test", `<div><t t-set="value" t-value="'ok'"/><t t-esc="value"/></div>`);
|
||||
expect(renderToString(qweb, "test")).toBe("<div>ok</div>");
|
||||
});
|
||||
|
||||
@@ -187,24 +169,16 @@ describe("t-set", () => {
|
||||
<t t-if="v === 'ok'">grimbergen</t>
|
||||
</div>`
|
||||
);
|
||||
expect(renderToString(qweb, "test", { value: "ok" })).toBe(
|
||||
"<div>grimbergen</div>"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { value: "ok" })).toBe("<div>grimbergen</div>");
|
||||
});
|
||||
|
||||
test("set from body literal", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<t><t t-set="value">ok</t><t t-esc="value"/></t>`
|
||||
);
|
||||
qweb.addTemplate("test", `<t><t t-set="value">ok</t><t t-esc="value"/></t>`);
|
||||
expect(renderToString(qweb, "test")).toBe("ok");
|
||||
});
|
||||
|
||||
test("set from attribute lookup", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div><t t-set="stuff" t-value="value"/><t t-esc="stuff"/></div>`
|
||||
);
|
||||
qweb.addTemplate("test", `<div><t t-set="stuff" t-value="value"/><t t-esc="stuff"/></div>`);
|
||||
expect(renderToString(qweb, "test", { value: "ok" })).toBe("<div>ok</div>");
|
||||
});
|
||||
|
||||
@@ -236,18 +210,12 @@ describe("t-set", () => {
|
||||
});
|
||||
|
||||
test("value priority", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div><t t-set="value" t-value="1">2</t><t t-esc="value"/></div>`
|
||||
);
|
||||
qweb.addTemplate("test", `<div><t t-set="value" t-value="1">2</t><t t-esc="value"/></div>`);
|
||||
expect(renderToString(qweb, "test")).toBe("<div>1</div>");
|
||||
});
|
||||
|
||||
test("evaluate value expression", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div><t t-set="value" t-value="1 + 2"/><t t-esc="value"/></div>`
|
||||
);
|
||||
qweb.addTemplate("test", `<div><t t-set="value" t-value="1 + 2"/><t t-esc="value"/></div>`);
|
||||
expect(renderToString(qweb, "test")).toBe("<div>3</div>");
|
||||
});
|
||||
|
||||
@@ -272,25 +240,19 @@ describe("t-set", () => {
|
||||
"test",
|
||||
`<div><t t-set="value" t-value="somevariable + 2"/><t t-esc="value"/></div>`
|
||||
);
|
||||
expect(renderToString(qweb, "test", { somevariable: 43 })).toBe(
|
||||
"<div>45</div>"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { somevariable: 43 })).toBe("<div>45</div>");
|
||||
});
|
||||
});
|
||||
|
||||
describe("t-if", () => {
|
||||
test("boolean value true condition", () => {
|
||||
qweb.addTemplate("test", `<div><t t-if="condition">ok</t></div>`);
|
||||
expect(renderToString(qweb, "test", { condition: true })).toBe(
|
||||
"<div>ok</div>"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { condition: true })).toBe("<div>ok</div>");
|
||||
});
|
||||
|
||||
test("boolean value false condition", () => {
|
||||
qweb.addTemplate("test", `<div><t t-if="condition">ok</t></div>`);
|
||||
expect(renderToString(qweb, "test", { condition: false })).toBe(
|
||||
"<div></div>"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { condition: false })).toBe("<div></div>");
|
||||
});
|
||||
|
||||
test("boolean value condition missing", () => {
|
||||
@@ -307,9 +269,7 @@ describe("t-if", () => {
|
||||
<t t-else="">beer</t></div>
|
||||
`
|
||||
);
|
||||
expect(renderToString(qweb, "test", { color: "red" })).toBe(
|
||||
"<div>red is dead</div>"
|
||||
);
|
||||
expect(renderToString(qweb, "test", { color: "red" })).toBe("<div>red is dead</div>");
|
||||
});
|
||||
|
||||
test("boolean value condition else", () => {
|
||||
@@ -335,9 +295,7 @@ describe("t-if", () => {
|
||||
`
|
||||
);
|
||||
const result = trim(renderToString(qweb, "test", { condition: false }));
|
||||
expect(result).toBe(
|
||||
"<div><span>begin</span>fail-else<span>end</span></div>"
|
||||
);
|
||||
expect(result).toBe("<div><span>begin</span>fail-else<span>end</span></div>");
|
||||
});
|
||||
|
||||
test("can use some boolean operators in expressions", () => {
|
||||
@@ -362,9 +320,7 @@ describe("t-if", () => {
|
||||
m: 5,
|
||||
n: 2
|
||||
};
|
||||
expect(normalize(renderToString(qweb, "test", context))).toBe(
|
||||
"<div>andormgtnlt</div>"
|
||||
);
|
||||
expect(normalize(renderToString(qweb, "test", context))).toBe("<div>andormgtnlt</div>");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -489,10 +445,7 @@ describe("attributes", () => {
|
||||
});
|
||||
|
||||
test("format multiple", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div t-attf-foo="a {{value1}} is {{value2}} of {{value3}} ]"/>`
|
||||
);
|
||||
qweb.addTemplate("test", `<div t-attf-foo="a {{value1}} is {{value2}} of {{value3}} ]"/>`);
|
||||
const result = renderToString(qweb, "test", {
|
||||
value1: 0,
|
||||
value2: 1,
|
||||
@@ -528,19 +481,13 @@ describe("attributes", () => {
|
||||
});
|
||||
|
||||
test("class and t-attf-class with ternary operation", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div class="hello" t-attf-class="{{value ? 'world' : ''}}"/>`
|
||||
);
|
||||
qweb.addTemplate("test", `<div class="hello" t-attf-class="{{value ? 'world' : ''}}"/>`);
|
||||
const result = renderToString(qweb, "test", { value: true });
|
||||
expect(result).toBe(`<div class="hello world"></div>`);
|
||||
});
|
||||
|
||||
test("t-att-class with object", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div class="static" t-att-class="{a: b, c: d, e: f}"/>`
|
||||
);
|
||||
qweb.addTemplate("test", `<div class="static" t-att-class="{a: b, c: d, e: f}"/>`);
|
||||
const result = renderToString(qweb, "test", { b: true, d: false, f: true });
|
||||
expect(result).toBe(`<div class="static a e"></div>`);
|
||||
});
|
||||
@@ -569,10 +516,7 @@ describe("t-call (template calling", () => {
|
||||
|
||||
test("with unused setbody", () => {
|
||||
qweb.addTemplate("_basic-callee", "<div>ok</div>");
|
||||
qweb.addTemplate(
|
||||
"caller",
|
||||
'<t t-call="_basic-callee"><t t-set="qux" t-value="3"/></t>'
|
||||
);
|
||||
qweb.addTemplate("caller", '<t t-call="_basic-callee"><t t-set="qux" t-value="3"/></t>');
|
||||
const expected = "<div>ok</div>";
|
||||
expect(renderToString(qweb, "caller")).toBe(expected);
|
||||
});
|
||||
@@ -678,9 +622,7 @@ describe("foreach", () => {
|
||||
</t>
|
||||
</div>`
|
||||
);
|
||||
const result = trim(
|
||||
renderToString(qweb, "test", { value: { a: 1, b: 2, c: 3 } })
|
||||
);
|
||||
const result = trim(renderToString(qweb, "test", { value: { a: 1, b: 2, c: 3 } }));
|
||||
const expected = `<div>[0:a1][1:b2][2:c3]</div>`;
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
@@ -727,14 +669,8 @@ describe("foreach", () => {
|
||||
describe("misc", () => {
|
||||
test("global", () => {
|
||||
qweb.addTemplate("_callee-asc", `<Año t-att-falló="'agüero'" t-raw="0"/>`);
|
||||
qweb.addTemplate(
|
||||
"_callee-uses-foo",
|
||||
`<span t-esc="foo">foo default</span>`
|
||||
);
|
||||
qweb.addTemplate(
|
||||
"_callee-asc-toto",
|
||||
`<div t-raw="toto">toto default</div>`
|
||||
);
|
||||
qweb.addTemplate("_callee-uses-foo", `<span t-esc="foo">foo default</span>`);
|
||||
qweb.addTemplate("_callee-asc-toto", `<div t-raw="toto">toto default</div>`);
|
||||
qweb.addTemplate(
|
||||
"caller",
|
||||
`
|
||||
@@ -847,10 +783,7 @@ describe("t-on", () => {
|
||||
});
|
||||
|
||||
test("can bind handlers with object arguments", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<button t-on-click="add({val: 5})">Click</button>`
|
||||
);
|
||||
qweb.addTemplate("test", `<button t-on-click="add({val: 5})">Click</button>`);
|
||||
let a = 1;
|
||||
const node = renderToDOM(
|
||||
qweb,
|
||||
@@ -868,10 +801,7 @@ describe("t-on", () => {
|
||||
|
||||
test("can bind handlers with empty object", () => {
|
||||
expect.assertions(2);
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<button t-on-click="doSomething({})">Click</button>`
|
||||
);
|
||||
qweb.addTemplate("test", `<button t-on-click="doSomething({})">Click</button>`);
|
||||
const node = renderToDOM(
|
||||
qweb,
|
||||
"test",
|
||||
@@ -887,10 +817,7 @@ describe("t-on", () => {
|
||||
|
||||
test("can bind handlers with empty object (with non empty inner string)", () => {
|
||||
expect.assertions(2);
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<button t-on-click="doSomething({ })">Click</button>`
|
||||
);
|
||||
qweb.addTemplate("test", `<button t-on-click="doSomething({ })">Click</button>`);
|
||||
const node = renderToDOM(
|
||||
qweb,
|
||||
"test",
|
||||
@@ -1190,13 +1117,10 @@ describe("whitespace handling", () => {
|
||||
|
||||
describe("t-key", () => {
|
||||
test("can use t-key directive on a node", () => {
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div t-key="beer.id"><t t-esc="beer.name"/></div>`
|
||||
qweb.addTemplate("test", `<div t-key="beer.id"><t t-esc="beer.name"/></div>`);
|
||||
expect(renderToString(qweb, "test", { beer: { id: 12, name: "Chimay Rouge" } })).toBe(
|
||||
"<div>Chimay Rouge</div>"
|
||||
);
|
||||
expect(
|
||||
renderToString(qweb, "test", { beer: { id: 12, name: "Chimay Rouge" } })
|
||||
).toBe("<div>Chimay Rouge</div>");
|
||||
});
|
||||
|
||||
test("t-key directive in a list", () => {
|
||||
|
||||
@@ -2,9 +2,7 @@ import { compileExpr, tokenize } from "../src/qweb_expressions";
|
||||
|
||||
describe("tokenizer", () => {
|
||||
test("simple tokens", () => {
|
||||
expect(tokenize("1.3")).toEqual([
|
||||
{ type: "VALUE", value: "1.3" }
|
||||
]);
|
||||
expect(tokenize("1.3")).toEqual([{ type: "VALUE", value: "1.3" }]);
|
||||
|
||||
expect(tokenize("{}")).toEqual([
|
||||
{ type: "LEFT_BRACE", value: "{" },
|
||||
@@ -29,10 +27,7 @@ describe("tokenizer", () => {
|
||||
{ type: "VALUE", value: "2" },
|
||||
{ type: "RIGHT_BRACE", value: "}" }
|
||||
]);
|
||||
expect(tokenize("a,")).toEqual([
|
||||
{ type: "SYMBOL", value: "a" },
|
||||
{ type: "COMMA", value: "," }
|
||||
]);
|
||||
expect(tokenize("a,")).toEqual([{ type: "SYMBOL", value: "a" }, { type: "COMMA", value: "," }]);
|
||||
expect(tokenize("][")).toEqual([
|
||||
{ type: "RIGHT_BRACKET", value: "]" },
|
||||
{ type: "LEFT_BRACKET", value: "[" }
|
||||
@@ -46,7 +41,7 @@ describe("tokenizer", () => {
|
||||
{ type: "OPERATOR", value: "<" },
|
||||
{ type: "OPERATOR", value: ">" },
|
||||
{ type: "OPERATOR", value: "!==" },
|
||||
{ type: "OPERATOR", value: "!=" },
|
||||
{ type: "OPERATOR", value: "!=" }
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -54,25 +49,17 @@ describe("tokenizer", () => {
|
||||
expect(() => tokenize("'")).toThrow("Invalid expression");
|
||||
expect(() => tokenize("'\\")).toThrow("Invalid expression");
|
||||
expect(() => tokenize("'\\'")).toThrow("Invalid expression");
|
||||
expect(tokenize("'hello ged'")).toEqual([
|
||||
{ type: "VALUE", value: "'hello ged'" }
|
||||
]);
|
||||
expect(tokenize("'hello \\'ged\\''")).toEqual([
|
||||
{ type: "VALUE", value: "'hello \\'ged\\''" }
|
||||
]);
|
||||
expect(tokenize("'hello ged'")).toEqual([{ type: "VALUE", value: "'hello ged'" }]);
|
||||
expect(tokenize("'hello \\'ged\\''")).toEqual([{ type: "VALUE", value: "'hello \\'ged\\''" }]);
|
||||
|
||||
expect(() => tokenize('"')).toThrow("Invalid expression");
|
||||
expect(() => tokenize('"\\"')).toThrow("Invalid expression");
|
||||
expect(tokenize('"hello ged"')).toEqual([
|
||||
{ type: "VALUE", value: '"hello ged"' }
|
||||
]);
|
||||
expect(tokenize('"hello ged"')).toEqual([{ type: "VALUE", value: '"hello ged"' }]);
|
||||
expect(tokenize('"hello ged"}')).toEqual([
|
||||
{ type: "VALUE", value: '"hello ged"' },
|
||||
{ type: "RIGHT_BRACE", value: "}" }
|
||||
]);
|
||||
expect(tokenize('"hello \\"ged\\""')).toEqual([
|
||||
{ type: "VALUE", value: '"hello \\"ged\\""' }
|
||||
]);
|
||||
expect(tokenize('"hello \\"ged\\""')).toEqual([{ type: "VALUE", value: '"hello \\"ged\\""' }]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -113,9 +100,7 @@ describe("expression evaluation", () => {
|
||||
test("arrays and objects", () => {
|
||||
expect(compileExpr("[{b:1}] ", {})).toBe("[{b:1}]");
|
||||
expect(compileExpr("{a: []} ", {})).toBe("{a:[]}");
|
||||
expect(compileExpr("[{b:1, c: [1, {d: {e: 3}} ]}] ", {})).toBe(
|
||||
"[{b:1,c:[1,{d:{e:3}}]}]"
|
||||
);
|
||||
expect(compileExpr("[{b:1, c: [1, {d: {e: 3}} ]}] ", {})).toBe("[{b:1,c:[1,{d:{e:3}}]}]");
|
||||
});
|
||||
|
||||
test("dot operator", () => {
|
||||
@@ -130,13 +115,9 @@ describe("expression evaluation", () => {
|
||||
});
|
||||
|
||||
test("various binary operators", () => {
|
||||
expect(compileExpr("color == 'black'", {})).toBe(
|
||||
"context['color']=='black'"
|
||||
);
|
||||
expect(compileExpr("color == 'black'", {})).toBe("context['color']=='black'");
|
||||
expect(compileExpr("a || b", {})).toBe("context['a']||context['b']");
|
||||
expect(compileExpr("color === 'black'", {})).toBe(
|
||||
"context['color']==='black'"
|
||||
);
|
||||
expect(compileExpr("color === 'black'", {})).toBe("context['color']==='black'");
|
||||
expect(compileExpr("'li_'+item", {})).toBe("'li_'+context['item']");
|
||||
expect(compileExpr("state.val > 1", {})).toBe("context['state'].val>1");
|
||||
});
|
||||
@@ -164,18 +145,14 @@ describe("expression evaluation", () => {
|
||||
expect(compileExpr("a()", {})).toBe("context['a']()");
|
||||
expect(compileExpr("a(1)", {})).toBe("context['a'](1)");
|
||||
expect(compileExpr("a(1,2)", {})).toBe("context['a'](1,2)");
|
||||
expect(compileExpr("a(1,2,{a:[a]})", {})).toBe(
|
||||
"context['a'](1,2,{a:[context['a']]})"
|
||||
);
|
||||
expect(compileExpr("a(1,2,{a:[a]})", {})).toBe("context['a'](1,2,{a:[context['a']]})");
|
||||
expect(compileExpr("'x'.toUpperCase()", {})).toBe("'x'.toUpperCase()");
|
||||
expect(compileExpr("'x'.toUpperCase({a: 3})", {})).toBe(
|
||||
"'x'.toUpperCase({a:3})"
|
||||
expect(compileExpr("'x'.toUpperCase({a: 3})", {})).toBe("'x'.toUpperCase({a:3})");
|
||||
expect(compileExpr("'x'.toUpperCase(a)", { a: { id: "_v5", expr: "" } })).toBe(
|
||||
"'x'.toUpperCase(_v5)"
|
||||
);
|
||||
expect(compileExpr("'x'.toUpperCase({b: a})", { a: { id: "_v5", expr: "" } })).toBe(
|
||||
"'x'.toUpperCase({b:_v5})"
|
||||
);
|
||||
expect(
|
||||
compileExpr("'x'.toUpperCase(a)", { a: { id: "_v5", expr: "" } })
|
||||
).toBe("'x'.toUpperCase(_v5)");
|
||||
expect(
|
||||
compileExpr("'x'.toUpperCase({b: a})", { a: { id: "_v5", expr: "" } })
|
||||
).toBe("'x'.toUpperCase({b:_v5})");
|
||||
});
|
||||
});
|
||||
|
||||
+6
-21
@@ -1,11 +1,6 @@
|
||||
import { Component, Env } from "../src/component";
|
||||
import { connect, Store } from "../src/store";
|
||||
import {
|
||||
makeTestFixture,
|
||||
makeTestEnv,
|
||||
nextMicroTick,
|
||||
nextTick
|
||||
} from "./helpers";
|
||||
import { makeTestFixture, makeTestEnv, nextMicroTick, nextTick } from "./helpers";
|
||||
import { Observer } from "../src";
|
||||
|
||||
describe("basic use", () => {
|
||||
@@ -794,9 +789,7 @@ describe("connecting a component to store", () => {
|
||||
|
||||
store.commit("addTodo", "hoegaarden");
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><span>jupiler</span><span>hoegaarden</span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><span>jupiler</span><span>hoegaarden</span></div>");
|
||||
});
|
||||
|
||||
test("connect receives store getters as third argument", async () => {
|
||||
@@ -930,9 +923,7 @@ describe("connecting a component to store", () => {
|
||||
|
||||
store.commit("addBeer", "kwak");
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><span>jupiler</span><span>kwak</span></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><span>jupiler</span><span>kwak</span></div>");
|
||||
});
|
||||
|
||||
test("connected component with undefined, null and string props", async () => {
|
||||
@@ -984,9 +975,7 @@ describe("connecting a component to store", () => {
|
||||
const app = new App(env);
|
||||
|
||||
await app.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>taster:aaron</span></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div><span>taster:aaron</span></div></div>");
|
||||
|
||||
app.state.beerId = 1;
|
||||
await nextTick();
|
||||
@@ -1062,9 +1051,7 @@ describe("connecting a component to store", () => {
|
||||
const app = new App(env);
|
||||
|
||||
await app.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>taster:aaron</span></div></div>"
|
||||
);
|
||||
expect(fixture.innerHTML).toBe("<div><div><span>taster:aaron</span></div></div>");
|
||||
|
||||
app.state.beerId = 1;
|
||||
await nextTick();
|
||||
@@ -1334,9 +1321,7 @@ describe("connecting a component to store", () => {
|
||||
await nextTick();
|
||||
expect(renderCount).toBe(1);
|
||||
expect(fCount).toBe(1);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div class="todoapp"></div>'
|
||||
);
|
||||
expect(fixture.innerHTML).toBe('<div class="todoapp"></div>');
|
||||
});
|
||||
|
||||
test("connected component willpatch/patch hooks are called on store updates", async () => {
|
||||
|
||||
+28
-143
@@ -59,9 +59,7 @@ describe("attributes", function() {
|
||||
test("are set correctly when namespaced", function() {
|
||||
const vnode1 = h("div", { attrs: { "xlink:href": "#foo" } });
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(elm.getAttributeNS("http://www.w3.org/1999/xlink", "href")).toBe(
|
||||
"#foo"
|
||||
);
|
||||
expect(elm.getAttributeNS("http://www.w3.org/1999/xlink", "href")).toBe("#foo");
|
||||
});
|
||||
|
||||
test("should not touch class nor id fields", function() {
|
||||
@@ -207,12 +205,8 @@ describe("snabbdom", function() {
|
||||
expect(elm.firstChild.namespaceURI).toBe(SVGNamespace);
|
||||
|
||||
// verify that svg tag automatically gets svg namespace
|
||||
elm = patch(
|
||||
vnode0,
|
||||
h("svg", [
|
||||
h("foreignObject", [h("div", ["I am HTML embedded in SVG"])])
|
||||
])
|
||||
).elm;
|
||||
elm = patch(vnode0, h("svg", [h("foreignObject", [h("div", ["I am HTML embedded in SVG"])])]))
|
||||
.elm;
|
||||
expect(elm.namespaceURI).toBe(SVGNamespace);
|
||||
expect(elm.firstChild.namespaceURI).toBe(SVGNamespace);
|
||||
expect(elm.firstChild.firstChild.namespaceURI).toBe(XHTMLNamespace);
|
||||
@@ -352,13 +346,7 @@ describe("snabbdom", function() {
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(elm.children.length).toBe(2);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["1", "2", "3", "4", "5"]);
|
||||
});
|
||||
|
||||
test("add elements in the middle", function() {
|
||||
@@ -368,13 +356,7 @@ describe("snabbdom", function() {
|
||||
expect(elm.children.length).toBe(4);
|
||||
expect(elm.children.length).toBe(4);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["1", "2", "3", "4", "5"]);
|
||||
});
|
||||
|
||||
test("add elements at beginning and end", function() {
|
||||
@@ -383,13 +365,7 @@ describe("snabbdom", function() {
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(elm.children.length).toBe(3);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["1", "2", "3", "4", "5"]);
|
||||
});
|
||||
|
||||
test("adds children to parent with no children", function() {
|
||||
@@ -588,35 +564,19 @@ describe("snabbdom", function() {
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(elm.children.length).toBe(6);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"4",
|
||||
"3",
|
||||
"2",
|
||||
"1",
|
||||
"5",
|
||||
"0"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["4", "3", "2", "1", "5", "0"]);
|
||||
});
|
||||
|
||||
test("supports null/undefined children", function() {
|
||||
const vnode1 = h("i", [0, 1, 2, 3, 4, 5].map(spanNum));
|
||||
const vnode2 = h(
|
||||
"i",
|
||||
[null, 2, undefined, null, 1, 0, null, 5, 4, null, 3, undefined].map(
|
||||
spanNum
|
||||
)
|
||||
[null, 2, undefined, null, 1, 0, null, 5, 4, null, 3, undefined].map(spanNum)
|
||||
);
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(elm.children.length).toBe(6);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"2",
|
||||
"1",
|
||||
"0",
|
||||
"5",
|
||||
"4",
|
||||
"3"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["2", "1", "0", "5", "4", "3"]);
|
||||
});
|
||||
|
||||
test("supports all null/undefined children", function() {
|
||||
@@ -627,14 +587,7 @@ describe("snabbdom", function() {
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(elm.children.length).toBe(0);
|
||||
elm = patch(vnode2, vnode3).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"5",
|
||||
"4",
|
||||
"3",
|
||||
"2",
|
||||
"1",
|
||||
"0"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["5", "4", "3", "2", "1", "0"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -714,18 +667,10 @@ describe("snabbdom", function() {
|
||||
});
|
||||
|
||||
test("removes elements", function() {
|
||||
const vnode1 = h("div", [
|
||||
h("span", "One"),
|
||||
h("span", "Two"),
|
||||
h("span", "Three")
|
||||
]);
|
||||
const vnode1 = h("div", [h("span", "One"), h("span", "Two"), h("span", "Three")]);
|
||||
const vnode2 = h("div", [h("span", "One"), h("span", "Three")]);
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"One",
|
||||
"Two",
|
||||
"Three"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["One", "Two", "Three"]);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["One", "Three"]);
|
||||
});
|
||||
@@ -760,49 +705,19 @@ describe("snabbdom", function() {
|
||||
});
|
||||
|
||||
test("reorders elements", function() {
|
||||
const vnode1 = h("div", [
|
||||
h("span", "One"),
|
||||
h("div", "Two"),
|
||||
h("b", "Three")
|
||||
]);
|
||||
const vnode2 = h("div", [
|
||||
h("b", "Three"),
|
||||
h("span", "One"),
|
||||
h("div", "Two")
|
||||
]);
|
||||
const vnode1 = h("div", [h("span", "One"), h("div", "Two"), h("b", "Three")]);
|
||||
const vnode2 = h("div", [h("b", "Three"), h("span", "One"), h("div", "Two")]);
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"One",
|
||||
"Two",
|
||||
"Three"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["One", "Two", "Three"]);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
expect(map(elm.children, c => c.tagName)).toEqual(["B", "SPAN", "DIV"]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual([
|
||||
"Three",
|
||||
"One",
|
||||
"Two"
|
||||
]);
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["Three", "One", "Two"]);
|
||||
});
|
||||
|
||||
test("supports null/undefined children", function() {
|
||||
const vnode1 = h("i", [null, h("i", "1"), h("i", "2"), null]);
|
||||
const vnode2 = h("i", [
|
||||
h("i", "2"),
|
||||
undefined,
|
||||
undefined,
|
||||
h("i", "1"),
|
||||
undefined
|
||||
]);
|
||||
const vnode3 = h("i", [
|
||||
null,
|
||||
h("i", "1"),
|
||||
undefined,
|
||||
null,
|
||||
h("i", "2"),
|
||||
undefined,
|
||||
null
|
||||
]);
|
||||
const vnode2 = h("i", [h("i", "2"), undefined, undefined, h("i", "1"), undefined]);
|
||||
const vnode3 = h("i", [null, h("i", "1"), undefined, null, h("i", "2"), undefined, null]);
|
||||
elm = patch(vnode0, vnode1).elm;
|
||||
expect(map(elm.children, c => c.innerHTML)).toEqual(["1", "2"]);
|
||||
elm = patch(vnode1, vnode2).elm;
|
||||
@@ -835,10 +750,7 @@ describe("snabbdom", function() {
|
||||
}
|
||||
const vnode1 = h("div", [
|
||||
h("span", "First sibling"),
|
||||
h("div", { hook: { create: cb } }, [
|
||||
h("span", "Child 1"),
|
||||
h("span", "Child 2")
|
||||
]),
|
||||
h("div", { hook: { create: cb } }, [h("span", "Child 1"), h("span", "Child 2")]),
|
||||
h("span", "Can't touch me")
|
||||
]);
|
||||
patch(vnode0, vnode1);
|
||||
@@ -855,10 +767,7 @@ describe("snabbdom", function() {
|
||||
}
|
||||
const vnode1 = h("div", [
|
||||
h("span", "First sibling"),
|
||||
h("div", { hook: { insert: cb } }, [
|
||||
h("span", "Child 1"),
|
||||
h("span", "Child 2")
|
||||
]),
|
||||
h("div", { hook: { insert: cb } }, [h("span", "Child 1"), h("span", "Child 2")]),
|
||||
h("span", "Can touch me")
|
||||
]);
|
||||
patch(vnode0, vnode1);
|
||||
@@ -874,17 +783,11 @@ describe("snabbdom", function() {
|
||||
}
|
||||
const vnode1 = h("div", [
|
||||
h("span", "First sibling"),
|
||||
h("div", { hook: { prepatch: cb } }, [
|
||||
h("span", "Child 1"),
|
||||
h("span", "Child 2")
|
||||
])
|
||||
h("div", { hook: { prepatch: cb } }, [h("span", "Child 1"), h("span", "Child 2")])
|
||||
]);
|
||||
const vnode2 = h("div", [
|
||||
h("span", "First sibling"),
|
||||
h("div", { hook: { prepatch: cb } }, [
|
||||
h("span", "Child 1"),
|
||||
h("span", "Child 2")
|
||||
])
|
||||
h("div", { hook: { prepatch: cb } }, [h("span", "Child 1"), h("span", "Child 2")])
|
||||
]);
|
||||
patch(vnode0, vnode1);
|
||||
patch(vnode1, vnode2);
|
||||
@@ -965,10 +868,7 @@ describe("snabbdom", function() {
|
||||
}
|
||||
const vnode1 = h("div", [
|
||||
h("span", "First sibling"),
|
||||
h("div", { hook: { remove: cb } }, [
|
||||
h("span", "Child 1"),
|
||||
h("span", "Child 2")
|
||||
])
|
||||
h("div", { hook: { remove: cb } }, [h("span", "Child 1"), h("span", "Child 2")])
|
||||
]);
|
||||
const vnode2 = h("div", [h("span", "First sibling")]);
|
||||
patch(vnode0, vnode1);
|
||||
@@ -981,9 +881,7 @@ describe("snabbdom", function() {
|
||||
function cb(vnode) {
|
||||
calls++;
|
||||
}
|
||||
const vnode1 = h("div", [
|
||||
h("div", { hook: { destroy: cb } }, [h("span", "Child 1")])
|
||||
]);
|
||||
const vnode1 = h("div", [h("div", { hook: { destroy: cb } }, [h("span", "Child 1")])]);
|
||||
const vnode2 = h("div", "Text node");
|
||||
patch(vnode0, vnode1);
|
||||
patch(vnode1, vnode2);
|
||||
@@ -1053,10 +951,7 @@ describe("snabbdom", function() {
|
||||
result.push(vnode);
|
||||
rm();
|
||||
}
|
||||
const vnode1 = h("div", { hook: { remove: cb } }, [
|
||||
h("b", "Child 1"),
|
||||
h("i", "Child 2")
|
||||
]);
|
||||
const vnode1 = h("div", { hook: { remove: cb } }, [h("b", "Child 1"), h("i", "Child 2")]);
|
||||
const vnode2 = h("span", [h("b", "Child 1"), h("i", "Child 2")]);
|
||||
patch(vnode0, vnode1);
|
||||
patch(vnode1, vnode2);
|
||||
@@ -1091,10 +986,7 @@ describe("snabbdom", function() {
|
||||
}
|
||||
const vnode1 = h("div", [
|
||||
h("span", "First sibling"),
|
||||
h("div", [
|
||||
h("span", { hook: { destroy: cb } }, "Child 1"),
|
||||
h("span", "Child 2")
|
||||
])
|
||||
h("div", [h("span", { hook: { destroy: cb } }, "Child 1"), h("span", "Child 2")])
|
||||
]);
|
||||
const vnode2 = h("div");
|
||||
patch(vnode0, vnode1);
|
||||
@@ -1150,11 +1042,7 @@ describe("snabbdom", function() {
|
||||
}
|
||||
}
|
||||
]);
|
||||
const vnode1 = h("div", [
|
||||
h("span", "First child"),
|
||||
"",
|
||||
h("span", "Third child")
|
||||
]);
|
||||
const vnode1 = h("div", [h("span", "First child"), "", h("span", "Third child")]);
|
||||
const vnode2 = h("div");
|
||||
patch(vnode0, vnode1);
|
||||
patch(vnode1, vnode2);
|
||||
@@ -1196,10 +1084,7 @@ describe("snabbdom", function() {
|
||||
function cb(vnode) {
|
||||
result.push(vnode);
|
||||
}
|
||||
const vnode1 = h("div", [
|
||||
h("span", { hook: { update: cb } }, "Hello"),
|
||||
h("span", "there")
|
||||
]);
|
||||
const vnode1 = h("div", [h("span", { hook: { update: cb } }, "Hello"), h("span", "there")]);
|
||||
patch(vnode0, vnode1);
|
||||
patch(vnode1, vnode1);
|
||||
expect(result).toHaveLength(0);
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
buildData,
|
||||
startMeasure,
|
||||
stopMeasure,
|
||||
formatNumber
|
||||
} from "../shared/utils.js";
|
||||
import { buildData, startMeasure, stopMeasure, formatNumber } from "../shared/utils.js";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Likes Counter Widget
|
||||
@@ -40,11 +35,7 @@ class App extends owl.Component {
|
||||
state = { messages: [], multipleFlag: false, clearAfterFlag: false };
|
||||
|
||||
mounted() {
|
||||
this.log(
|
||||
`Benchmarking Owl v${owl.__info__.version} (build date: ${
|
||||
owl.__info__.date
|
||||
})`
|
||||
);
|
||||
this.log(`Benchmarking Owl v${owl.__info__.version} (build date: ${owl.__info__.date})`);
|
||||
}
|
||||
|
||||
benchmark(message, fn, callback) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
buildData,
|
||||
startMeasure,
|
||||
stopMeasure,
|
||||
formatNumber
|
||||
} from "../shared/utils.js";
|
||||
import { buildData, startMeasure, stopMeasure, formatNumber } from "../shared/utils.js";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Likes Counter Widget
|
||||
@@ -40,11 +35,7 @@ class App extends owl.Component {
|
||||
state = { messages: [], multipleFlag: false, clearAfterFlag: false };
|
||||
|
||||
mounted() {
|
||||
this.log(
|
||||
`Benchmarking Owl v${owl.__info__.version} (build date: ${
|
||||
owl.__info__.date
|
||||
})`
|
||||
);
|
||||
this.log(`Benchmarking Owl v${owl.__info__.version} (build date: ${owl.__info__.date})`);
|
||||
}
|
||||
|
||||
benchmark(message, fn, callback) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
buildData,
|
||||
startMeasure,
|
||||
stopMeasure,
|
||||
formatNumber
|
||||
} from "../shared/utils.js";
|
||||
import { buildData, startMeasure, stopMeasure, formatNumber } from "../shared/utils.js";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Likes Counter Widget
|
||||
@@ -40,11 +35,7 @@ class App extends owl.Component {
|
||||
state = { messages: [], multipleFlag: false, clearAfterFlag: false };
|
||||
|
||||
mounted() {
|
||||
this.log(
|
||||
`Benchmarking Owl v${owl.__info__.version} (build date: ${
|
||||
owl.__info__.date
|
||||
})`
|
||||
);
|
||||
this.log(`Benchmarking Owl v${owl.__info__.version} (build date: ${owl.__info__.date})`);
|
||||
}
|
||||
|
||||
benchmark(message, fn, callback) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
buildData,
|
||||
startMeasure,
|
||||
stopMeasure,
|
||||
formatNumber
|
||||
} from "../shared/utils.js";
|
||||
import { buildData, startMeasure, stopMeasure, formatNumber } from "../shared/utils.js";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Likes Counter Widget
|
||||
@@ -40,11 +35,7 @@ class App extends owl.Component {
|
||||
state = { messages: [], multipleFlag: false, clearAfterFlag: false };
|
||||
|
||||
mounted() {
|
||||
this.log(
|
||||
`Benchmarking Owl v${owl.__info__.version} (build date: ${
|
||||
owl.__info__.date
|
||||
})`
|
||||
);
|
||||
this.log(`Benchmarking Owl v${owl.__info__.version} (build date: ${owl.__info__.date})`);
|
||||
}
|
||||
|
||||
benchmark(message, fn, callback) {
|
||||
@@ -128,9 +119,7 @@ class App extends owl.Component {
|
||||
|
||||
removeMessage(event) {
|
||||
this.benchmark("remove message", () => {
|
||||
const index = this.state.messages.findIndex(
|
||||
m => m.id === event.detail.id
|
||||
);
|
||||
const index = this.state.messages.findIndex(m => m.id === event.detail.id);
|
||||
this.state.messages.splice(index, 1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -97,10 +97,7 @@ function makeCodeIframe(js, css, xml, errorHandler) {
|
||||
setTimeout(function() {
|
||||
if (iframe.contentWindow) {
|
||||
iframe.contentWindow.removeEventListener("error", errorHandler);
|
||||
iframe.contentWindow.removeEventListener(
|
||||
"unhandledrejection",
|
||||
errorHandler
|
||||
);
|
||||
iframe.contentWindow.removeEventListener("unhandledrejection", errorHandler);
|
||||
}
|
||||
}, 200);
|
||||
doc.body.appendChild(script);
|
||||
|
||||
@@ -1351,7 +1351,7 @@ export const SAMPLES = [
|
||||
description: "Lifecycle demo",
|
||||
code: LIFECYCLE_DEMO,
|
||||
xml: LIFECYCLE_DEMO_XML,
|
||||
css: LIFECYCLE_CSS,
|
||||
css: LIFECYCLE_CSS
|
||||
},
|
||||
{
|
||||
description: "Todo List App (with store)",
|
||||
|
||||
Reference in New Issue
Block a user