Skip to content

Commit e676850

Browse files
committed
[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
1 parent 6b24864 commit e676850

File tree

4 files changed

+67
-17
lines changed

4 files changed

+67
-17
lines changed

docs/owl.js

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,6 +3227,9 @@ class TemplateSet {
32273227
}
32283228
}
32293229
this.getRawTemplate = config.getTemplate;
3230+
this.customDirectives = config.customDirectives || {};
3231+
this.runtimeUtils = { ...helpers, __globals__: config.globalValues || {} };
3232+
this.hasGlobalValues = Boolean(config.globalValues && Object.keys(config.globalValues).length);
32303233
}
32313234
static registerTemplate(name, fn) {
32323235
globalTemplates[name] = fn;
@@ -3283,7 +3286,7 @@ class TemplateSet {
32833286
this.templates[name] = function (context, parent) {
32843287
return templates[name].call(this, context, parent);
32853288
};
3286-
const template = templateFn(this, bdom, helpers);
3289+
const template = templateFn(this, bdom, this.runtimeUtils);
32873290
this.templates[name] = template;
32883291
}
32893292
return this.templates[name];
@@ -3334,7 +3337,7 @@ TemplateSet.registerTemplate("__portal__", portalTemplate);
33343337
//------------------------------------------------------------------------------
33353338
// Misc types, constants and helpers
33363339
//------------------------------------------------------------------------------
3337-
const RESERVED_WORDS = "true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date".split(",");
3340+
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(",");
33383341
const WORD_REPLACEMENT = Object.assign(Object.create(null), {
33393342
and: "&&",
33403343
or: "||",
@@ -3806,6 +3809,9 @@ class CodeGenerator {
38063809
this.dev = options.dev || false;
38073810
this.ast = ast;
38083811
this.templateName = options.name;
3812+
if (options.hasGlobalValues) {
3813+
this.helpers.add("__globals__");
3814+
}
38093815
}
38103816
generateCode() {
38113817
const ast = this.ast;
@@ -4844,29 +4850,33 @@ class CodeGenerator {
48444850
// Parser
48454851
// -----------------------------------------------------------------------------
48464852
const cache = new WeakMap();
4847-
function parse(xml) {
4853+
function parse(xml, customDir) {
4854+
const ctx = {
4855+
inPreTag: false,
4856+
customDirectives: customDir,
4857+
};
48484858
if (typeof xml === "string") {
48494859
const elem = parseXML(`<t>${xml}</t>`).firstChild;
4850-
return _parse(elem);
4860+
return _parse(elem, ctx);
48514861
}
48524862
let ast = cache.get(xml);
48534863
if (!ast) {
48544864
// we clone here the xml to prevent modifying it in place
4855-
ast = _parse(xml.cloneNode(true));
4865+
ast = _parse(xml.cloneNode(true), ctx);
48564866
cache.set(xml, ast);
48574867
}
48584868
return ast;
48594869
}
4860-
function _parse(xml) {
4870+
function _parse(xml, ctx) {
48614871
normalizeXML(xml);
4862-
const ctx = { inPreTag: false };
48634872
return parseNode(xml, ctx) || { type: 0 /* Text */, value: "" };
48644873
}
48654874
function parseNode(node, ctx) {
48664875
if (!(node instanceof Element)) {
48674876
return parseTextCommentNode(node, ctx);
48684877
}
4869-
return (parseTDebugLog(node, ctx) ||
4878+
return (parseTCustom(node, ctx) ||
4879+
parseTDebugLog(node, ctx) ||
48704880
parseTForEach(node, ctx) ||
48714881
parseTIf(node, ctx) ||
48724882
parseTPortal(node, ctx) ||
@@ -4908,6 +4918,35 @@ function parseTextCommentNode(node, ctx) {
49084918
}
49094919
return null;
49104920
}
4921+
function parseTCustom(node, ctx) {
4922+
if (!ctx.customDirectives) {
4923+
return null;
4924+
}
4925+
const nodeAttrsNames = node.getAttributeNames();
4926+
for (let attr of nodeAttrsNames) {
4927+
if (attr === "t-custom" || attr === "t-custom-") {
4928+
throw new OwlError("Missing custom directive name with t-custom directive");
4929+
}
4930+
if (attr.startsWith("t-custom-")) {
4931+
const directiveName = attr.split(".")[0].slice(9);
4932+
const customDirective = ctx.customDirectives[directiveName];
4933+
if (!customDirective) {
4934+
throw new OwlError(`Custom directive "${directiveName}" is not defined`);
4935+
}
4936+
const value = node.getAttribute(attr);
4937+
const modifier = attr.split(".").length > 1 ? attr.split(".")[1] : undefined;
4938+
node.removeAttribute(attr);
4939+
try {
4940+
customDirective(node, value, modifier);
4941+
}
4942+
catch (error) {
4943+
throw new OwlError(`Custom directive "${directiveName}" throw the following error: ${error}`);
4944+
}
4945+
return parseNode(node, ctx);
4946+
}
4947+
}
4948+
return null;
4949+
}
49114950
// -----------------------------------------------------------------------------
49124951
// debugging
49134952
// -----------------------------------------------------------------------------
@@ -5539,9 +5578,11 @@ function normalizeXML(el) {
55395578
normalizeTEscTOut(el);
55405579
}
55415580

5542-
function compile(template, options = {}) {
5581+
function compile(template, options = {
5582+
hasGlobalValues: false,
5583+
}) {
55435584
// parsing
5544-
const ast = parse(template);
5585+
const ast = parse(template, options.customDirectives);
55455586
// some work
55465587
const hasSafeContext = template instanceof Node
55475588
? !(template instanceof Element) || template.querySelector("[t-set], [t-call]") === null
@@ -5563,7 +5604,7 @@ function compile(template, options = {}) {
55635604
}
55645605

55655606
// do not modify manually. This file is generated by the release script.
5566-
const version = "2.4.1";
5607+
const version = "2.5.0";
55675608

55685609
// -----------------------------------------------------------------------------
55695610
// Scheduler
@@ -5642,7 +5683,14 @@ class Scheduler {
56425683
if (!hasError) {
56435684
fiber.complete();
56445685
}
5645-
this.tasks.delete(fiber);
5686+
// at this point, the fiber should have been applied to the DOM, so we can
5687+
// remove it from the task list. If it is not the case, it means that there
5688+
// was an error and an error handler triggered a new rendering that recycled
5689+
// the fiber, so in that case, we actually want to keep the fiber around,
5690+
// otherwise it will just be ignored.
5691+
if (fiber.appliedToDom) {
5692+
this.tasks.delete(fiber);
5693+
}
56465694
}
56475695
}
56485696
}
@@ -6026,12 +6074,14 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
60266074
dev: this.dev,
60276075
translateFn: this.translateFn,
60286076
translatableAttributes: this.translatableAttributes,
6077+
customDirectives: this.customDirectives,
6078+
hasGlobalValues: this.hasGlobalValues,
60296079
});
60306080
};
60316081

60326082
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 };
60336083

60346084

6035-
__info__.date = '2024-10-31T09:42:30.824Z';
6036-
__info__.hash = 'b8d09e5';
6085+
__info__.date = '2024-11-25T09:30:45.930Z';
6086+
__info__.hash = '6b24864';
60376087
__info__.url = 'https://github.com/odoo/owl';

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@odoo/owl",
3-
"version": "2.4.1",
3+
"version": "2.5.0",
44
"description": "Odoo Web Library (OWL)",
55
"main": "dist/owl.cjs.js",
66
"module": "dist/owl.es.js",

src/version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
// do not modify manually. This file is generated by the release script.
2-
export const version = "2.4.1";
2+
export const version = "2.5.0";

0 commit comments

Comments
 (0)