mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[REL] v2.5.0
# v2.5.0 - [IMP] app: add global values at compile time - [IMP] parser: add support for custom directives - [FIX] runtime: properly handle error caused in mounted hook
This commit is contained in:
+64
-14
@@ -3227,6 +3227,9 @@ class TemplateSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.getRawTemplate = config.getTemplate;
|
this.getRawTemplate = config.getTemplate;
|
||||||
|
this.customDirectives = config.customDirectives || {};
|
||||||
|
this.runtimeUtils = { ...helpers, __globals__: config.globalValues || {} };
|
||||||
|
this.hasGlobalValues = Boolean(config.globalValues && Object.keys(config.globalValues).length);
|
||||||
}
|
}
|
||||||
static registerTemplate(name, fn) {
|
static registerTemplate(name, fn) {
|
||||||
globalTemplates[name] = fn;
|
globalTemplates[name] = fn;
|
||||||
@@ -3283,7 +3286,7 @@ class TemplateSet {
|
|||||||
this.templates[name] = function (context, parent) {
|
this.templates[name] = function (context, parent) {
|
||||||
return templates[name].call(this, context, parent);
|
return templates[name].call(this, context, parent);
|
||||||
};
|
};
|
||||||
const template = templateFn(this, bdom, helpers);
|
const template = templateFn(this, bdom, this.runtimeUtils);
|
||||||
this.templates[name] = template;
|
this.templates[name] = template;
|
||||||
}
|
}
|
||||||
return this.templates[name];
|
return this.templates[name];
|
||||||
@@ -3334,7 +3337,7 @@ TemplateSet.registerTemplate("__portal__", portalTemplate);
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Misc types, constants and helpers
|
// Misc types, constants and helpers
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
const RESERVED_WORDS = "true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date".split(",");
|
const RESERVED_WORDS = "true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date,__globals__".split(",");
|
||||||
const WORD_REPLACEMENT = Object.assign(Object.create(null), {
|
const WORD_REPLACEMENT = Object.assign(Object.create(null), {
|
||||||
and: "&&",
|
and: "&&",
|
||||||
or: "||",
|
or: "||",
|
||||||
@@ -3806,6 +3809,9 @@ class CodeGenerator {
|
|||||||
this.dev = options.dev || false;
|
this.dev = options.dev || false;
|
||||||
this.ast = ast;
|
this.ast = ast;
|
||||||
this.templateName = options.name;
|
this.templateName = options.name;
|
||||||
|
if (options.hasGlobalValues) {
|
||||||
|
this.helpers.add("__globals__");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
generateCode() {
|
generateCode() {
|
||||||
const ast = this.ast;
|
const ast = this.ast;
|
||||||
@@ -4844,29 +4850,33 @@ class CodeGenerator {
|
|||||||
// Parser
|
// Parser
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
const cache = new WeakMap();
|
const cache = new WeakMap();
|
||||||
function parse(xml) {
|
function parse(xml, customDir) {
|
||||||
|
const ctx = {
|
||||||
|
inPreTag: false,
|
||||||
|
customDirectives: customDir,
|
||||||
|
};
|
||||||
if (typeof xml === "string") {
|
if (typeof xml === "string") {
|
||||||
const elem = parseXML(`<t>${xml}</t>`).firstChild;
|
const elem = parseXML(`<t>${xml}</t>`).firstChild;
|
||||||
return _parse(elem);
|
return _parse(elem, ctx);
|
||||||
}
|
}
|
||||||
let ast = cache.get(xml);
|
let ast = cache.get(xml);
|
||||||
if (!ast) {
|
if (!ast) {
|
||||||
// we clone here the xml to prevent modifying it in place
|
// we clone here the xml to prevent modifying it in place
|
||||||
ast = _parse(xml.cloneNode(true));
|
ast = _parse(xml.cloneNode(true), ctx);
|
||||||
cache.set(xml, ast);
|
cache.set(xml, ast);
|
||||||
}
|
}
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
function _parse(xml) {
|
function _parse(xml, ctx) {
|
||||||
normalizeXML(xml);
|
normalizeXML(xml);
|
||||||
const ctx = { inPreTag: false };
|
|
||||||
return parseNode(xml, ctx) || { type: 0 /* Text */, value: "" };
|
return parseNode(xml, ctx) || { type: 0 /* Text */, value: "" };
|
||||||
}
|
}
|
||||||
function parseNode(node, ctx) {
|
function parseNode(node, ctx) {
|
||||||
if (!(node instanceof Element)) {
|
if (!(node instanceof Element)) {
|
||||||
return parseTextCommentNode(node, ctx);
|
return parseTextCommentNode(node, ctx);
|
||||||
}
|
}
|
||||||
return (parseTDebugLog(node, ctx) ||
|
return (parseTCustom(node, ctx) ||
|
||||||
|
parseTDebugLog(node, ctx) ||
|
||||||
parseTForEach(node, ctx) ||
|
parseTForEach(node, ctx) ||
|
||||||
parseTIf(node, ctx) ||
|
parseTIf(node, ctx) ||
|
||||||
parseTPortal(node, ctx) ||
|
parseTPortal(node, ctx) ||
|
||||||
@@ -4908,6 +4918,35 @@ function parseTextCommentNode(node, ctx) {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
function parseTCustom(node, ctx) {
|
||||||
|
if (!ctx.customDirectives) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const nodeAttrsNames = node.getAttributeNames();
|
||||||
|
for (let attr of nodeAttrsNames) {
|
||||||
|
if (attr === "t-custom" || attr === "t-custom-") {
|
||||||
|
throw new OwlError("Missing custom directive name with t-custom directive");
|
||||||
|
}
|
||||||
|
if (attr.startsWith("t-custom-")) {
|
||||||
|
const directiveName = attr.split(".")[0].slice(9);
|
||||||
|
const customDirective = ctx.customDirectives[directiveName];
|
||||||
|
if (!customDirective) {
|
||||||
|
throw new OwlError(`Custom directive "${directiveName}" is not defined`);
|
||||||
|
}
|
||||||
|
const value = node.getAttribute(attr);
|
||||||
|
const modifier = attr.split(".").length > 1 ? attr.split(".")[1] : undefined;
|
||||||
|
node.removeAttribute(attr);
|
||||||
|
try {
|
||||||
|
customDirective(node, value, modifier);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
throw new OwlError(`Custom directive "${directiveName}" throw the following error: ${error}`);
|
||||||
|
}
|
||||||
|
return parseNode(node, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// debugging
|
// debugging
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -5539,9 +5578,11 @@ function normalizeXML(el) {
|
|||||||
normalizeTEscTOut(el);
|
normalizeTEscTOut(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compile(template, options = {}) {
|
function compile(template, options = {
|
||||||
|
hasGlobalValues: false,
|
||||||
|
}) {
|
||||||
// parsing
|
// parsing
|
||||||
const ast = parse(template);
|
const ast = parse(template, options.customDirectives);
|
||||||
// some work
|
// some work
|
||||||
const hasSafeContext = template instanceof Node
|
const hasSafeContext = template instanceof Node
|
||||||
? !(template instanceof Element) || template.querySelector("[t-set], [t-call]") === null
|
? !(template instanceof Element) || template.querySelector("[t-set], [t-call]") === null
|
||||||
@@ -5563,7 +5604,7 @@ function compile(template, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do not modify manually. This file is generated by the release script.
|
// do not modify manually. This file is generated by the release script.
|
||||||
const version = "2.4.1";
|
const version = "2.5.0";
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Scheduler
|
// Scheduler
|
||||||
@@ -5642,7 +5683,14 @@ class Scheduler {
|
|||||||
if (!hasError) {
|
if (!hasError) {
|
||||||
fiber.complete();
|
fiber.complete();
|
||||||
}
|
}
|
||||||
this.tasks.delete(fiber);
|
// at this point, the fiber should have been applied to the DOM, so we can
|
||||||
|
// remove it from the task list. If it is not the case, it means that there
|
||||||
|
// was an error and an error handler triggered a new rendering that recycled
|
||||||
|
// the fiber, so in that case, we actually want to keep the fiber around,
|
||||||
|
// otherwise it will just be ignored.
|
||||||
|
if (fiber.appliedToDom) {
|
||||||
|
this.tasks.delete(fiber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6026,12 +6074,14 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
|
|||||||
dev: this.dev,
|
dev: this.dev,
|
||||||
translateFn: this.translateFn,
|
translateFn: this.translateFn,
|
||||||
translatableAttributes: this.translatableAttributes,
|
translatableAttributes: this.translatableAttributes,
|
||||||
|
customDirectives: this.customDirectives,
|
||||||
|
hasGlobalValues: this.hasGlobalValues,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export { App, Component, EventBus, OwlError, __info__, batched, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, validateType, whenReady, xml };
|
export { App, Component, EventBus, OwlError, __info__, batched, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, validateType, whenReady, xml };
|
||||||
|
|
||||||
|
|
||||||
__info__.date = '2024-10-31T09:42:30.824Z';
|
__info__.date = '2024-11-25T09:30:45.930Z';
|
||||||
__info__.hash = 'b8d09e5';
|
__info__.hash = '6b24864';
|
||||||
__info__.url = 'https://github.com/odoo/owl';
|
__info__.url = 'https://github.com/odoo/owl';
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@odoo/owl",
|
"name": "@odoo/owl",
|
||||||
"version": "2.4.1",
|
"version": "2.5.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@odoo/owl",
|
"name": "@odoo/owl",
|
||||||
"version": "2.4.1",
|
"version": "2.5.0",
|
||||||
"description": "Odoo Web Library (OWL)",
|
"description": "Odoo Web Library (OWL)",
|
||||||
"main": "dist/owl.cjs.js",
|
"main": "dist/owl.cjs.js",
|
||||||
"module": "dist/owl.es.js",
|
"module": "dist/owl.es.js",
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
// do not modify manually. This file is generated by the release script.
|
// do not modify manually. This file is generated by the release script.
|
||||||
export const version = "2.4.1";
|
export const version = "2.5.0";
|
||||||
|
|||||||
Reference in New Issue
Block a user