mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] owl: update to v1.0.0
This commit is contained in:
@@ -837,7 +837,7 @@
|
|||||||
};
|
};
|
||||||
// note that the space after typeof is relevant. It makes sure that the formatted
|
// note that the space after typeof is relevant. It makes sure that the formatted
|
||||||
// expression has a space after typeof
|
// expression has a space after typeof
|
||||||
const OPERATORS = "...,.,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=,;".split(",");
|
const OPERATORS = "...,.,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=,;,in ".split(",");
|
||||||
let tokenizeString = function (expr) {
|
let tokenizeString = function (expr) {
|
||||||
let s = expr[0];
|
let s = expr[0];
|
||||||
let start = s;
|
let start = s;
|
||||||
@@ -981,7 +981,7 @@
|
|||||||
* the arrow operator, then we add the current (or some previous tokens) token to
|
* the arrow operator, then we add the current (or some previous tokens) token to
|
||||||
* the list of variables so it does not get replaced by a lookup in the context
|
* the list of variables so it does not get replaced by a lookup in the context
|
||||||
*/
|
*/
|
||||||
function compileExpr(expr, scope) {
|
function compileExprToArray(expr, scope) {
|
||||||
scope = Object.create(scope);
|
scope = Object.create(scope);
|
||||||
const tokens = tokenize(expr);
|
const tokens = tokenize(expr);
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
@@ -1017,6 +1017,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isVar) {
|
if (isVar) {
|
||||||
|
token.varName = token.value;
|
||||||
if (token.value in scope && "id" in scope[token.value]) {
|
if (token.value in scope && "id" in scope[token.value]) {
|
||||||
token.value = scope[token.value].expr;
|
token.value = scope[token.value].expr;
|
||||||
}
|
}
|
||||||
@@ -1026,7 +1027,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tokens.map(t => t.value).join("");
|
return tokens;
|
||||||
|
}
|
||||||
|
function compileExpr(expr, scope) {
|
||||||
|
return compileExprToArray(expr, scope)
|
||||||
|
.map(t => t.value)
|
||||||
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
const INTERP_REGEXP = /\{\{.*?\}\}/g;
|
const INTERP_REGEXP = /\{\{.*?\}\}/g;
|
||||||
@@ -1044,6 +1050,7 @@
|
|||||||
this.indentLevel = 0;
|
this.indentLevel = 0;
|
||||||
this.shouldDefineParent = false;
|
this.shouldDefineParent = false;
|
||||||
this.shouldDefineScope = false;
|
this.shouldDefineScope = false;
|
||||||
|
this.protectedScopeNumber = 0;
|
||||||
this.shouldDefineQWeb = false;
|
this.shouldDefineQWeb = false;
|
||||||
this.shouldDefineUtils = false;
|
this.shouldDefineUtils = false;
|
||||||
this.shouldDefineRefs = false;
|
this.shouldDefineRefs = false;
|
||||||
@@ -1164,6 +1171,24 @@
|
|||||||
this.rootContext.shouldDefineScope = true;
|
this.rootContext.shouldDefineScope = true;
|
||||||
return compileExpr(expr, this.variables);
|
return compileExpr(expr, this.variables);
|
||||||
}
|
}
|
||||||
|
captureExpression(expr) {
|
||||||
|
this.rootContext.shouldDefineScope = true;
|
||||||
|
const argId = this.generateID();
|
||||||
|
const tokens = compileExprToArray(expr, this.variables);
|
||||||
|
const done = new Set();
|
||||||
|
return tokens
|
||||||
|
.map(tok => {
|
||||||
|
if (tok.varName) {
|
||||||
|
if (!done.has(tok.varName)) {
|
||||||
|
done.add(tok.varName);
|
||||||
|
this.addLine(`const ${tok.varName}_${argId} = ${tok.value};`);
|
||||||
|
}
|
||||||
|
tok.value = `${tok.varName}_${argId}`;
|
||||||
|
}
|
||||||
|
return tok.value;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Perform string interpolation on the given string. Note that if the whole
|
* Perform string interpolation on the given string. Note that if the whole
|
||||||
* string is an expression, it simply returns it (formatted and enclosed in
|
* string is an expression, it simply returns it (formatted and enclosed in
|
||||||
@@ -1180,14 +1205,19 @@
|
|||||||
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 + "`";
|
return "`" + r + "`";
|
||||||
}
|
}
|
||||||
startProtectScope() {
|
startProtectScope(codeBlock) {
|
||||||
const protectID = this.generateID();
|
const protectID = this.generateID();
|
||||||
|
this.rootContext.protectedScopeNumber++;
|
||||||
this.rootContext.shouldDefineScope = true;
|
this.rootContext.shouldDefineScope = true;
|
||||||
|
const scopeExpr = codeBlock
|
||||||
|
? `Object.create(scope);`
|
||||||
|
: `Object.assign(Object.create(context), scope);`;
|
||||||
this.addLine(`let _origScope${protectID} = scope;`);
|
this.addLine(`let _origScope${protectID} = scope;`);
|
||||||
this.addLine(`scope = Object.assign(Object.create(context), scope);`);
|
this.addLine(`scope = ${scopeExpr}`);
|
||||||
return protectID;
|
return protectID;
|
||||||
}
|
}
|
||||||
stopProtectScope(protectID) {
|
stopProtectScope(protectID) {
|
||||||
|
this.rootContext.protectedScopeNumber--;
|
||||||
this.addLine(`scope = _origScope${protectID};`);
|
this.addLine(`scope = _origScope${protectID};`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1312,6 +1342,9 @@
|
|||||||
remove: "(vn, rm)",
|
remove: "(vn, rm)",
|
||||||
destroy: "()"
|
destroy: "()"
|
||||||
};
|
};
|
||||||
|
function isComponent(obj) {
|
||||||
|
return obj && obj.hasOwnProperty("__owl__");
|
||||||
|
}
|
||||||
const UTILS = {
|
const UTILS = {
|
||||||
zero: Symbol("zero"),
|
zero: Symbol("zero"),
|
||||||
toObj(expr) {
|
toObj(expr) {
|
||||||
@@ -1350,10 +1383,21 @@
|
|||||||
.join("");
|
.join("");
|
||||||
},
|
},
|
||||||
getComponent(obj) {
|
getComponent(obj) {
|
||||||
while (obj && !obj.hasOwnProperty("__owl__")) {
|
while (obj && !isComponent(obj)) {
|
||||||
obj = obj.__proto__;
|
obj = obj.__proto__;
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
},
|
||||||
|
getScope(obj, property) {
|
||||||
|
const obj0 = obj;
|
||||||
|
while (obj && !obj.hasOwnProperty(property)) {
|
||||||
|
const newObj = obj.__proto__;
|
||||||
|
if (!newObj || isComponent(newObj)) {
|
||||||
|
return obj0;
|
||||||
|
}
|
||||||
|
obj = newObj;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function parseXML(xml) {
|
function parseXML(xml) {
|
||||||
@@ -2107,7 +2151,12 @@
|
|||||||
qwebvar.expr = `scope.${variable}`;
|
qwebvar.expr = `scope.${variable}`;
|
||||||
if (value) {
|
if (value) {
|
||||||
const formattedValue = ctx.formatExpression(value);
|
const formattedValue = ctx.formatExpression(value);
|
||||||
ctx.addLine(`${qwebvar.expr} = ${formattedValue};`);
|
let scopeExpr = `scope`;
|
||||||
|
if (ctx.protectedScopeNumber) {
|
||||||
|
ctx.rootContext.shouldDefineUtils = true;
|
||||||
|
scopeExpr = `utils.getScope(scope, '${variable}')`;
|
||||||
|
}
|
||||||
|
ctx.addLine(`${scopeExpr}.${variable} = ${formattedValue};`);
|
||||||
qwebvar.value = formattedValue;
|
qwebvar.value = formattedValue;
|
||||||
}
|
}
|
||||||
if (hasBody) {
|
if (hasBody) {
|
||||||
@@ -2231,9 +2280,9 @@
|
|||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
const callingScope = hasBody ? "scope" : "Object.assign(Object.create(context), scope)";
|
const callingScope = hasBody ? "scope" : "Object.assign(Object.create(context), scope)";
|
||||||
const parentComponent = `utils.getComponent(context)`;
|
const parentComponent = `utils.getComponent(context)`;
|
||||||
const keyCode = ctx.loopNumber || ctx.hasKey0 ? `, key: ${ctx.generateTemplateKey()}` : "";
|
const key = ctx.generateTemplateKey();
|
||||||
const parentNode = ctx.parentNode ? `c${ctx.parentNode}` : "result";
|
const parentNode = ctx.parentNode ? `c${ctx.parentNode}` : "result";
|
||||||
const extra = `Object.assign({}, extra, {parentNode: ${parentNode}, parent: ${parentComponent}${keyCode}})`;
|
const extra = `Object.assign({}, extra, {parentNode: ${parentNode}, parent: ${parentComponent}, key: ${key}})`;
|
||||||
if (ctx.parentNode) {
|
if (ctx.parentNode) {
|
||||||
ctx.addLine(`this.subTemplates['${subTemplate}'].call(this, ${callingScope}, ${extra});`);
|
ctx.addLine(`this.subTemplates['${subTemplate}'].call(this, ${callingScope}, ${extra});`);
|
||||||
}
|
}
|
||||||
@@ -2277,7 +2326,7 @@
|
|||||||
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
|
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
|
||||||
ctx.closeIf();
|
ctx.closeIf();
|
||||||
ctx.addLine(`let _length${keysID} = _${keysID}.length;`);
|
ctx.addLine(`let _length${keysID} = _${keysID}.length;`);
|
||||||
let varsID = ctx.startProtectScope();
|
let varsID = ctx.startProtectScope(true);
|
||||||
const loopVar = `i${ctx.loopNumber}`;
|
const loopVar = `i${ctx.loopNumber}`;
|
||||||
ctx.addLine(`for (let ${loopVar} = 0; ${loopVar} < _length${keysID}; ${loopVar}++) {`);
|
ctx.addLine(`for (let ${loopVar} = 0; ${loopVar} < _length${keysID}; ${loopVar}++) {`);
|
||||||
ctx.indent();
|
ctx.indent();
|
||||||
@@ -2374,7 +2423,7 @@
|
|||||||
ctx.rootContext.shouldDefineUtils = true;
|
ctx.rootContext.shouldDefineUtils = true;
|
||||||
const comp = `utils.getComponent(context)`;
|
const comp = `utils.getComponent(context)`;
|
||||||
if (args) {
|
if (args) {
|
||||||
let argId = ctx.generateID();
|
const argId = ctx.generateID();
|
||||||
ctx.addLine(`let args${argId} = [${ctx.formatExpression(args)}];`);
|
ctx.addLine(`let args${argId} = [${ctx.formatExpression(args)}];`);
|
||||||
code = `${comp}['${name}'](...args${argId}, e);`;
|
code = `${comp}['${name}'](...args${argId}, e);`;
|
||||||
putInCache = false;
|
putInCache = false;
|
||||||
@@ -2385,8 +2434,9 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// if we get here, then it is an expression
|
// if we get here, then it is an expression
|
||||||
|
// we need to capture every variable in it
|
||||||
putInCache = false;
|
putInCache = false;
|
||||||
code = ctx.formatExpression(value);
|
code = ctx.captureExpression(value);
|
||||||
}
|
}
|
||||||
const modCode = mods.map(mod => modcodes[mod]).join("");
|
const modCode = mods.map(mod => modcodes[mod]).join("");
|
||||||
let handler = `function (e) {if (!context.__owl__.isMounted){return}${modCode}${code}}`;
|
let handler = `function (e) {if (!context.__owl__.isMounted){return}${modCode}${code}}`;
|
||||||
@@ -3484,9 +3534,23 @@
|
|||||||
const selectorStack = [];
|
const selectorStack = [];
|
||||||
const parts = [];
|
const parts = [];
|
||||||
let rules = [];
|
let rules = [];
|
||||||
|
function generateSelector(stackIndex, parentSelector) {
|
||||||
|
const parts = [];
|
||||||
|
for (const selector of selectorStack[stackIndex]) {
|
||||||
|
let part = (parentSelector && parentSelector + " " + selector) || selector;
|
||||||
|
if (part.includes("&")) {
|
||||||
|
part = selector.replace(/&/g, parentSelector || "");
|
||||||
|
}
|
||||||
|
if (stackIndex < selectorStack.length - 1) {
|
||||||
|
part = generateSelector(stackIndex + 1, part);
|
||||||
|
}
|
||||||
|
parts.push(part);
|
||||||
|
}
|
||||||
|
return parts.join(", ");
|
||||||
|
}
|
||||||
function generateRules() {
|
function generateRules() {
|
||||||
if (rules.length) {
|
if (rules.length) {
|
||||||
parts.push(selectorStack.join(" ") + " {");
|
parts.push(generateSelector(0) + " {");
|
||||||
parts.push(...rules);
|
parts.push(...rules);
|
||||||
parts.push("}");
|
parts.push("}");
|
||||||
rules = [];
|
rules = [];
|
||||||
@@ -3501,7 +3565,7 @@
|
|||||||
else {
|
else {
|
||||||
if (tokens[0] === "{") {
|
if (tokens[0] === "{") {
|
||||||
generateRules();
|
generateRules();
|
||||||
selectorStack.push(token);
|
selectorStack.push(token.split(/\s*,\s*/));
|
||||||
tokens.shift();
|
tokens.shift();
|
||||||
}
|
}
|
||||||
if (tokens[0] === ";") {
|
if (tokens[0] === ";") {
|
||||||
@@ -4344,6 +4408,27 @@
|
|||||||
const component = Component.current;
|
const component = Component.current;
|
||||||
component.env = Object.assign(Object.create(component.env), nextEnv);
|
component.env = Object.assign(Object.create(component.env), nextEnv);
|
||||||
}
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// useExternalListener
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* When a component needs to listen to DOM Events on element(s) that are not
|
||||||
|
* part of his hierarchy, we can use the `useExternalListener` hook.
|
||||||
|
* It will correctly add and remove the event listener, whenever the
|
||||||
|
* component is mounted and unmounted.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* a menu needs to listen to the click on window to be closed automatically
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* in the constructor of the OWL component that needs to be notified,
|
||||||
|
* `useExternalListener(window, 'click', this._doSomething);`
|
||||||
|
* */
|
||||||
|
function useExternalListener(target, eventName, handler, eventParams) {
|
||||||
|
const boundHandler = handler.bind(Component.current);
|
||||||
|
onMounted(() => target.addEventListener(eventName, boundHandler, eventParams));
|
||||||
|
onWillUnmount(() => target.removeEventListener(eventName, boundHandler, eventParams));
|
||||||
|
}
|
||||||
|
|
||||||
var _hooks = /*#__PURE__*/Object.freeze({
|
var _hooks = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
__proto__: null,
|
||||||
@@ -4355,7 +4440,8 @@
|
|||||||
onWillStart: onWillStart,
|
onWillStart: onWillStart,
|
||||||
onWillUpdateProps: onWillUpdateProps,
|
onWillUpdateProps: onWillUpdateProps,
|
||||||
useRef: useRef,
|
useRef: useRef,
|
||||||
useSubEnv: useSubEnv
|
useSubEnv: useSubEnv,
|
||||||
|
useExternalListener: useExternalListener
|
||||||
});
|
});
|
||||||
|
|
||||||
class Store extends Context {
|
class Store extends Context {
|
||||||
@@ -4972,9 +5058,9 @@
|
|||||||
exports.useState = useState$1;
|
exports.useState = useState$1;
|
||||||
exports.utils = utils;
|
exports.utils = utils;
|
||||||
|
|
||||||
exports.__info__.version = '1.0.0-beta5';
|
exports.__info__.version = '1.0.0';
|
||||||
exports.__info__.date = '2019-12-20T10:27:22.467Z';
|
exports.__info__.date = '2020-01-09T13:45:31.837Z';
|
||||||
exports.__info__.hash = 'b63cd4c';
|
exports.__info__.hash = '3d0f046';
|
||||||
exports.__info__.url = 'https://github.com/odoo/owl';
|
exports.__info__.url = 'https://github.com/odoo/owl';
|
||||||
|
|
||||||
}(this.owl = this.owl || {}));
|
}(this.owl = this.owl || {}));
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ const actions = {
|
|||||||
todo.completed = !todo.completed;
|
todo.completed = !todo.completed;
|
||||||
},
|
},
|
||||||
clearCompleted({ state, dispatch }) {
|
clearCompleted({ state, dispatch }) {
|
||||||
for (let todo of state.todos) {
|
for (let todo of state.todos.slice()) {
|
||||||
if (todo.completed) {
|
if (todo.completed) {
|
||||||
dispatch("removeTodo", todo.id);
|
dispatch("removeTodo", todo.id);
|
||||||
}
|
}
|
||||||
@@ -1089,20 +1089,20 @@ const RESPONSIVE_XML = `<templates>
|
|||||||
<button>Button!</button>
|
<button>Button!</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<t t-name="maincontent">
|
||||||
|
<FormView />
|
||||||
|
<Chatter />
|
||||||
|
</t>
|
||||||
<div t-name="App" class="app" t-att-class="{mobile: env.isMobile, desktop: !env.isMobile}">
|
<div t-name="App" class="app" t-att-class="{mobile: env.isMobile, desktop: !env.isMobile}">
|
||||||
<t t-set="maincontent">
|
|
||||||
<FormView />
|
|
||||||
<Chatter />
|
|
||||||
</t>
|
|
||||||
<Navbar/>
|
<Navbar/>
|
||||||
<ControlPanel/>
|
<ControlPanel/>
|
||||||
<div class="content-wrapper" t-if="!env.isMobile">
|
<div class="content-wrapper" t-if="!env.isMobile">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<t t-raw="maincontent"/>
|
<t t-call="maincontent"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<t t-else="">
|
<t t-else="">
|
||||||
<t t-raw="maincontent"/>
|
<t t-call="maincontent"/>
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
</templates>
|
</templates>
|
||||||
|
|||||||
Reference in New Issue
Block a user