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.customDirectives = config.customDirectives || {};
|
||||
this.runtimeUtils = { ...helpers, __globals__: config.globalValues || {} };
|
||||
this.hasGlobalValues = Boolean(config.globalValues && Object.keys(config.globalValues).length);
|
||||
}
|
||||
static registerTemplate(name, fn) {
|
||||
globalTemplates[name] = fn;
|
||||
@@ -3283,7 +3286,7 @@ class TemplateSet {
|
||||
this.templates[name] = function (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;
|
||||
}
|
||||
return this.templates[name];
|
||||
@@ -3334,7 +3337,7 @@ TemplateSet.registerTemplate("__portal__", portalTemplate);
|
||||
//------------------------------------------------------------------------------
|
||||
// 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), {
|
||||
and: "&&",
|
||||
or: "||",
|
||||
@@ -3806,6 +3809,9 @@ class CodeGenerator {
|
||||
this.dev = options.dev || false;
|
||||
this.ast = ast;
|
||||
this.templateName = options.name;
|
||||
if (options.hasGlobalValues) {
|
||||
this.helpers.add("__globals__");
|
||||
}
|
||||
}
|
||||
generateCode() {
|
||||
const ast = this.ast;
|
||||
@@ -4844,29 +4850,33 @@ class CodeGenerator {
|
||||
// Parser
|
||||
// -----------------------------------------------------------------------------
|
||||
const cache = new WeakMap();
|
||||
function parse(xml) {
|
||||
function parse(xml, customDir) {
|
||||
const ctx = {
|
||||
inPreTag: false,
|
||||
customDirectives: customDir,
|
||||
};
|
||||
if (typeof xml === "string") {
|
||||
const elem = parseXML(`<t>${xml}</t>`).firstChild;
|
||||
return _parse(elem);
|
||||
return _parse(elem, ctx);
|
||||
}
|
||||
let ast = cache.get(xml);
|
||||
if (!ast) {
|
||||
// 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);
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
function _parse(xml) {
|
||||
function _parse(xml, ctx) {
|
||||
normalizeXML(xml);
|
||||
const ctx = { inPreTag: false };
|
||||
return parseNode(xml, ctx) || { type: 0 /* Text */, value: "" };
|
||||
}
|
||||
function parseNode(node, ctx) {
|
||||
if (!(node instanceof Element)) {
|
||||
return parseTextCommentNode(node, ctx);
|
||||
}
|
||||
return (parseTDebugLog(node, ctx) ||
|
||||
return (parseTCustom(node, ctx) ||
|
||||
parseTDebugLog(node, ctx) ||
|
||||
parseTForEach(node, ctx) ||
|
||||
parseTIf(node, ctx) ||
|
||||
parseTPortal(node, ctx) ||
|
||||
@@ -4908,6 +4918,35 @@ function parseTextCommentNode(node, ctx) {
|
||||
}
|
||||
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
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -5539,9 +5578,11 @@ function normalizeXML(el) {
|
||||
normalizeTEscTOut(el);
|
||||
}
|
||||
|
||||
function compile(template, options = {}) {
|
||||
function compile(template, options = {
|
||||
hasGlobalValues: false,
|
||||
}) {
|
||||
// parsing
|
||||
const ast = parse(template);
|
||||
const ast = parse(template, options.customDirectives);
|
||||
// some work
|
||||
const hasSafeContext = template instanceof Node
|
||||
? !(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.
|
||||
const version = "2.4.1";
|
||||
const version = "2.5.0";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Scheduler
|
||||
@@ -5642,7 +5683,14 @@ class Scheduler {
|
||||
if (!hasError) {
|
||||
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,
|
||||
translateFn: this.translateFn,
|
||||
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 };
|
||||
|
||||
|
||||
__info__.date = '2024-10-31T09:42:30.824Z';
|
||||
__info__.hash = 'b8d09e5';
|
||||
__info__.date = '2024-11-25T09:30:45.930Z';
|
||||
__info__.hash = '6b24864';
|
||||
__info__.url = 'https://github.com/odoo/owl';
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@odoo/owl",
|
||||
"version": "2.4.1",
|
||||
"version": "2.5.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@odoo/owl",
|
||||
"version": "2.4.1",
|
||||
"version": "2.5.0",
|
||||
"description": "Odoo Web Library (OWL)",
|
||||
"main": "dist/owl.cjs.js",
|
||||
"module": "dist/owl.es.js",
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
// 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