[IMP] owl: update to v1.0.0-beta3

This commit is contained in:
Géry Debongnie
2019-12-16 10:04:15 +01:00
parent d66f5baead
commit 94461320aa
2 changed files with 108 additions and 108 deletions
+106 -106
View File
@@ -837,7 +837,7 @@
};
// note that the space after typeof is relevant. It makes sure that the formatted
// expression has a space after typeof
const OPERATORS = ".,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>".split(",");
const OPERATORS = "...,.,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=,;".split(",");
let tokenizeString = function (expr) {
let s = expr[0];
let start = s;
@@ -1055,7 +1055,7 @@
this.currentKey = "";
this.rootContext = this;
this.templateName = name || "noname";
this.addLine("var h = this.h;");
this.addLine("let h = this.h;");
}
generateID() {
return CompilationContext.nextID++;
@@ -1068,9 +1068,12 @@
* Such a key is necessary when we need to associate an id to some element
* generated by a template (for example, a component)
*/
generateTemplateKey() {
generateTemplateKey(prefix = "") {
const id = this.generateID();
let locationExpr = `\`__${this.generateID()}__`;
if (this.loopNumber === 0 && !this.currentKey) {
return `'${prefix}__${id}__'`;
}
let locationExpr = `\`${prefix}__${id}__`;
for (let i = 0; i < this.loopNumber - 1; i++) {
locationExpr += `\${i${i + 1}}__`;
}
@@ -1185,7 +1188,7 @@
startProtectScope() {
const protectID = this.generateID();
this.rootContext.shouldDefineScope = true;
this.addLine(`const _origScope${protectID} = scope;`);
this.addLine(`let _origScope${protectID} = scope;`);
this.addLine(`scope = Object.assign(Object.create(context), scope);`);
return protectID;
}
@@ -1251,12 +1254,9 @@
if (typeof str === "number") {
return String(str);
}
return str
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&#x27;")
.replace(/`/g, "&#x60;");
const p = document.createElement("p");
p.textContent = str;
return p.innerHTML;
}
/**
* Returns a function, that, as long as it continues to be invoked, will not
@@ -1352,7 +1352,13 @@
return vnode.text;
}
})
.join();
.join("");
},
getComponent(obj) {
while (obj && !obj.hasOwnProperty("__owl__")) {
obj = obj.__proto__;
}
return obj;
}
};
function parseXML(xml) {
@@ -1537,8 +1543,17 @@
return vnode.text;
}
const node = document.createElement(vnode.sel);
const result = patch(node, vnode);
return result.elm.outerHTML;
const elem = patch(node, vnode).elm;
function escapeTextNodes(node) {
if (node.nodeType === 3) {
node.textContent = escape(node.textContent);
}
for (let n of node.childNodes) {
escapeTextNodes(n);
}
}
escapeTextNodes(elem);
return elem.outerHTML;
}
/**
* Force all widgets connected to this QWeb instance to rerender themselves.
@@ -1637,7 +1652,7 @@
// this is an unusual situation: this text node is the result of the
// template rendering.
let nodeID = ctx.generateID();
ctx.addLine(`var vn${nodeID} = {text: \`${text}\`};`);
ctx.addLine(`let vn${nodeID} = {text: \`${text}\`};`);
ctx.addLine(`result = vn${nodeID};`);
ctx.rootContext.rootNode = nodeID;
ctx.rootContext.parentTextNode = nodeID;
@@ -1822,7 +1837,7 @@
}
}
else {
ctx.addLine(`var _${attID} = '${value}';`);
ctx.addLine(`let _${attID} = '${value}';`);
if (!name.match(/^[a-zA-Z]+$/)) {
// attribute contains 'non letters' => we want to quote it
name = '"' + name + '"';
@@ -1858,12 +1873,12 @@
const attValue = node.getAttribute(attName);
if (attValue) {
const attValueID = ctx.generateID();
ctx.addLine(`var _${attValueID} = ${formattedValue};`);
ctx.addLine(`let _${attValueID} = ${formattedValue};`);
formattedValue = `'${attValue}' + (_${attValueID} ? ' ' + _${attValueID} : '')`;
const attrIndex = attrs.findIndex(att => att.startsWith(attName + ":"));
attrs.splice(attrIndex, 1);
}
ctx.addLine(`var _${attID} = ${formattedValue};`);
ctx.addLine(`let _${attID} = ${formattedValue};`);
attrs.push(`${attName}: _${attID}`);
handleBooleanProps(attName, attID);
}
@@ -1878,17 +1893,17 @@
const attID = ctx.generateID();
let staticVal = node.getAttribute(attName);
if (staticVal) {
ctx.addLine(`var _${attID} = '${staticVal} ' + ${formattedExpr};`);
ctx.addLine(`let _${attID} = '${staticVal} ' + ${formattedExpr};`);
}
else {
ctx.addLine(`var _${attID} = ${formattedExpr};`);
ctx.addLine(`let _${attID} = ${formattedExpr};`);
}
attrs.push(`${attName}: _${attID}`);
}
// t-att= attributes
if (name === "t-att") {
let id = ctx.generateID();
ctx.addLine(`var _${id} = ${ctx.formatExpression(value)};`);
ctx.addLine(`let _${id} = ${ctx.formatExpression(value)};`);
tattrs.push(id);
}
}
@@ -1919,7 +1934,7 @@
ctx.addLine(`}`);
ctx.closeIf();
}
ctx.addLine(`var vn${nodeID} = h('${node.nodeName}', p${nodeID}, c${nodeID});`);
ctx.addLine(`let vn${nodeID} = h('${node.nodeName}', p${nodeID}, c${nodeID});`);
if (ctx.parentNode) {
ctx.addLine(`c${ctx.parentNode}.push(vn${nodeID});`);
}
@@ -2009,12 +2024,12 @@
let exprID;
if (typeof value === "string") {
exprID = `_${ctx.generateID()}`;
ctx.addLine(`var ${exprID} = ${ctx.formatExpression(value)};`);
ctx.addLine(`let ${exprID} = ${ctx.formatExpression(value)};`);
}
else {
exprID = `scope.${value.id}`;
}
ctx.addIf(`${exprID} || ${exprID} === 0`);
ctx.addIf(`${exprID} != null`);
if (ctx.escaping) {
let protectID;
if (value.hasBody) {
@@ -2031,7 +2046,7 @@
let nodeID = ctx.generateID();
ctx.rootContext.rootNode = nodeID;
ctx.rootContext.parentTextNode = nodeID;
ctx.addLine(`var vn${nodeID} = {text: ${exprID}};`);
ctx.addLine(`let vn${nodeID} = {text: ${exprID}};`);
if (ctx.rootContext.shouldDefineResult) {
ctx.addLine(`result = vn${nodeID}`);
}
@@ -2103,7 +2118,7 @@
const tempParentNodeID = ctx.generateID();
const _parentNode = ctx.parentNode;
ctx.parentNode = tempParentNodeID;
ctx.addLine(`const c${tempParentNodeID} = new utils.VDomArray();`);
ctx.addLine(`let c${tempParentNodeID} = new utils.VDomArray();`);
const nodeCopy = node.cloneNode(true);
for (let attr of ["t-set", "t-value", "t-if", "t-else", "t-elif"]) {
nodeCopy.removeAttribute(attr);
@@ -2170,6 +2185,7 @@
// Step 1: sanity checks
// ------------------------------------------------
ctx.rootContext.shouldDefineScope = true;
ctx.rootContext.shouldDefineUtils = true;
if (node.nodeName !== "t") {
throw new Error("Invalid tag for t-call directive (should be 't')");
}
@@ -2195,7 +2211,9 @@
ctx.indent();
protectID = ctx.startProtectScope();
const nodeCopy = node.cloneNode(true);
nodeCopy.removeAttribute("t-call");
for (let attr of ["t-if", "t-else", "t-elif", "t-call"]) {
nodeCopy.removeAttribute(attr);
}
const parentNode = ctx.parentNode;
ctx.parentNode = "__0";
// this local scope is intended to trap c__0
@@ -2212,14 +2230,15 @@
// Step 4: add the appropriate function call to current component
// ------------------------------------------------
const callingScope = hasBody ? "scope" : "Object.assign(Object.create(context), scope)";
const parentComponent = `utils.getComponent(context)`;
if (ctx.parentNode) {
ctx.addLine(`this.subTemplates['${subTemplate}'].call(this, ${callingScope}, Object.assign({}, extra, {parentNode: c${ctx.parentNode}}));`);
ctx.addLine(`this.subTemplates['${subTemplate}'].call(this, ${callingScope}, Object.assign({}, extra, {parentNode: c${ctx.parentNode}, parent: ${parentComponent}}));`);
}
else {
// this is a t-call with no parentnode, we need to extract the result
ctx.rootContext.shouldDefineResult = true;
ctx.addLine(`result = []`);
ctx.addLine(`this.subTemplates['${subTemplate}'].call(this, ${callingScope}, Object.assign({}, extra, {parentNode: result}));`);
ctx.addLine(`this.subTemplates['${subTemplate}'].call(this, ${callingScope}, Object.assign({}, extra, {parentNode: result, parent: ${parentComponent}}));`);
ctx.addLine(`result = result[0]`);
}
// Step 5: restore previous scope
@@ -2245,16 +2264,16 @@
const elems = node.getAttribute("t-foreach");
const name = node.getAttribute("t-as");
let arrayID = ctx.generateID();
ctx.addLine(`var _${arrayID} = ${ctx.formatExpression(elems)};`);
ctx.addLine(`let _${arrayID} = ${ctx.formatExpression(elems)};`);
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};`);
ctx.addLine(`let _${keysID} = _${valuesID} = _${arrayID};`);
ctx.addIf(`!(_${arrayID} instanceof Array)`);
ctx.addLine(`_${keysID} = Object.keys(_${arrayID});`);
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
ctx.closeIf();
ctx.addLine(`var _length${keysID} = _${keysID}.length;`);
ctx.addLine(`let _length${keysID} = _${keysID}.length;`);
let varsID = ctx.startProtectScope();
const loopVar = `i${ctx.loopNumber}`;
ctx.addLine(`for (let ${loopVar} = 0; ${loopVar} < _length${keysID}; ${loopVar}++) {`);
@@ -2325,46 +2344,54 @@
self: "if (e.target !== this.elm) {return}",
stop: "e.stopPropagation();"
};
const FNAMEREGEXP = /^[$A-Z_][0-9A-Z_$]*$/i;
function makeHandlerCode(ctx, fullName, value, putInCache, modcodes = MODS_CODE) {
const [event, ...mods] = fullName.slice(5).split(".");
if (!event) {
throw new Error("Missing event name with t-on directive");
}
let code;
// check if it is a method with no args, a method with args or an expression
let args = "";
const name = value.replace(/\(.*\)/, function (_args) {
args = _args.slice(1, -1);
return "";
});
const isMethodCall = name.match(FNAMEREGEXP);
// then generate code
if (isMethodCall) {
ctx.rootContext.shouldDefineUtils = true;
const comp = `utils.getComponent(context)`;
if (args) {
let argId = ctx.generateID();
ctx.addLine(`let args${argId} = [${ctx.formatExpression(args)}];`);
code = `${comp}['${name}'](...args${argId}, e);`;
putInCache = false;
}
else {
code = `${comp}['${name}'](e);`;
}
}
else {
// if we get here, then it is an expression
putInCache = false;
code = ctx.formatExpression(value);
}
const modCode = mods.map(mod => modcodes[mod]).join("");
let handler = `function (e) {if (!context.__owl__.isMounted){return}${modCode}${code}}`;
if (putInCache) {
const key = ctx.generateTemplateKey(event);
ctx.addLine(`extra.handlers[${key}] = extra.handlers[${key}] || ${handler};`);
handler = `extra.handlers[${key}]`;
}
return { event, handler };
}
QWeb.addDirective({
name: "on",
priority: 90,
atNodeCreation({ ctx, fullName, value, nodeID }) {
const [eventName, ...mods] = fullName.slice(5).split(".");
if (!eventName) {
throw new Error("Missing event name with t-on directive");
}
let extraArgs;
let handlerName = value.replace(/\(.*\)/, function (args) {
extraArgs = args.slice(1, -1);
return "";
});
let params = extraArgs ? `context, ${ctx.formatExpression(extraArgs)}` : "context";
let handler = `function (e) {if (!context.__owl__.isMounted){return}`;
handler += mods
.map(function (mod) {
return MODS_CODE[mod];
})
.join("");
if (handlerName) {
if (!extraArgs) {
handler += `const fn = context['${handlerName}'];`;
handler += `if (fn) { fn.call(${params}, e); } else { context.${handlerName}; }`;
handler += `}`;
ctx.addLine(`extra.handlers['${eventName}' + ${nodeID}] = extra.handlers['${eventName}' + ${nodeID}] || ${handler};`);
ctx.addLine(`p${nodeID}.on['${eventName}'] = extra.handlers['${eventName}' + ${nodeID}];`);
}
else {
const handlerKey = `handler${ctx.generateID()}`;
ctx.addLine(`const ${handlerKey} = context['${handlerName}'] && context['${handlerName}'].bind(${params});`);
handler += `if (${handlerKey}) { ${handlerKey}(e); } else { context.${value}; }`;
handler += `}`;
ctx.addLine(`p${nodeID}.on['${eventName}'] = ${handler};`);
}
}
else {
handler += "}";
ctx.addLine(`p${nodeID}.on['${eventName}'] = ${handler};`);
}
const { event, handler } = makeHandlerCode(ctx, fullName, value, true);
ctx.addLine(`p${nodeID}.on['${event}'] = ${handler};`);
}
});
//------------------------------------------------------------------------------
@@ -2781,7 +2808,7 @@
extraNames: ["props"],
priority: 100,
atNodeEncounter({ ctx, value, node, qweb }) {
ctx.addLine("//COMPONENT");
ctx.addLine(`// Component '${value}'`);
ctx.rootContext.shouldDefineQWeb = true;
ctx.rootContext.shouldDefineParent = true;
ctx.rootContext.shouldDefineUtils = true;
@@ -2796,13 +2823,7 @@
const name = attributes[i].name;
const value = attributes[i].textContent;
if (name.startsWith("t-on-")) {
const [eventName, ...mods] = name.slice(5).split(".");
let extraArgs;
let handlerValue = value.replace(/\(.*\)/, function (args) {
extraArgs = args.slice(1, -1);
return "";
});
events.push([eventName, mods, handlerValue, extraArgs]);
events.push([name, value]);
}
else if (name === "t-transition") {
transition = value;
@@ -2875,33 +2896,9 @@
}
}
let eventsCode = events
.map(function ([eventName, mods, handlerValue, extraArgs]) {
let params = "context";
if (extraArgs) {
if (ctx.loopNumber) {
let argId = ctx.generateID();
// 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)};`);
params = `context, arg${argId}`;
}
else {
params = `context, ${ctx.formatExpression(extraArgs)}`;
}
}
let handler = `function (e) {if(!context.__owl__.isMounted){return}`;
handler += mods
.map(function (mod) {
return T_COMPONENT_MODS_CODE[mod];
})
.join("");
if (handlerValue) {
handler += `const fn = context['${handlerValue}'];`;
handler += `if (fn) { fn.call(${params}, e); } else { context.${handlerValue}; }`;
}
handler += `}`;
return `vn.elm.addEventListener('${eventName}', ${handler});`;
.map(function ([name, value]) {
const { event, handler } = makeHandlerCode(ctx, name, value, false, T_COMPONENT_MODS_CODE);
return `vn.elm.addEventListener('${event}', ${handler});`;
})
.join("");
const styleExpr = tattStyle || (styleAttr ? `'${styleAttr}'` : false);
@@ -4356,6 +4353,9 @@
},
set(target, k, v) {
throw new Error("Store state should only be modified through actions");
},
has(target, k) {
return k in result;
}
});
}
@@ -4864,9 +4864,9 @@
exports.useState = useState$1;
exports.utils = utils;
exports.__info__.version = '1.0.0-beta2';
exports.__info__.date = '2019-12-11T09:31:58.227Z';
exports.__info__.hash = '0762eeb';
exports.__info__.version = '1.0.0-beta3';
exports.__info__.date = '2019-12-16T08:57:32.773Z';
exports.__info__.hash = 'd9bf428';
exports.__info__.url = 'https://github.com/odoo/owl';
}(this.owl = this.owl || {}));
+2 -2
View File
@@ -1101,7 +1101,7 @@ const RESPONSIVE_XML = `<templates>
<t t-raw="maincontent"/>
</div>
</div>
<t t-else="1">
<t t-else="">
<t t-raw="maincontent"/>
</t>
</div>
@@ -1438,7 +1438,7 @@ const FORM_XML = `<templates>
<div>Text: <t t-esc="state.text"/></div>
<div>Other Text: <t t-esc="state.othertext"/></div>
<div>Number: <t t-esc="state.number"/></div>
<div>Boolean: <t t-if="state.bool">True</t><t t-else="1">False</t></div>
<div>Boolean: <t t-if="state.bool">True</t><t t-else="">False</t></div>
<div>Color: <t t-esc="state.color"/></div>
</div>
</templates>