mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] app: add global values at compile time
This commit, add a new configuration on the App: globalValues.
It's a global object of elements available at compilations.
For instance:
```js
const app = new App(SomeComponent, {
globalValues: {
plop: (string: any) => {
steps.push(string);
},
},
});
```
The plop function will be available at the compilation, so it can be
used on the templates :
```xml
<div t-on-click="() => __globals__.plop('click')" class="my-div"/>
```
This commit is contained in:
committed by
Géry Debongnie
parent
7e687234bf
commit
6b2486473f
@@ -68,6 +68,7 @@ The `config` object is an object with some of the following keys:
|
|||||||
whenever it encounters a component that does not provide a [static props description](props.md#props-validation).
|
whenever it encounters a component that does not provide a [static props description](props.md#props-validation).
|
||||||
- **`customDirectives (object)`**: if given, the corresponding function on the object will be called
|
- **`customDirectives (object)`**: if given, the corresponding function on the object will be called
|
||||||
on the template custom directives: `t-custom-*` (see [Custom Directives](templates.md#custom-directives)).
|
on the template custom directives: `t-custom-*` (see [Custom Directives](templates.md#custom-directives)).
|
||||||
|
- **`globalValues (object)`**: Global object of elements available at compilations.
|
||||||
|
|
||||||
## `mount` helper
|
## `mount` helper
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export interface Config {
|
|||||||
export interface CodeGenOptions extends Config {
|
export interface CodeGenOptions extends Config {
|
||||||
hasSafeContext?: boolean;
|
hasSafeContext?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
hasGlobalValues: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// using a non-html document so that <inner/outer>HTML serializes as XML instead
|
// using a non-html document so that <inner/outer>HTML serializes as XML instead
|
||||||
@@ -286,6 +287,9 @@ export 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(): string {
|
generateCode(): string {
|
||||||
|
|||||||
@@ -12,10 +12,13 @@ export type TemplateFunction = (app: TemplateSet, bdom: any, helpers: any) => Te
|
|||||||
interface CompileOptions extends Config {
|
interface CompileOptions extends Config {
|
||||||
name?: string;
|
name?: string;
|
||||||
customDirectives?: customDirectives;
|
customDirectives?: customDirectives;
|
||||||
|
hasGlobalValues: boolean;
|
||||||
}
|
}
|
||||||
export function compile(
|
export function compile(
|
||||||
template: string | Element,
|
template: string | Element,
|
||||||
options: CompileOptions = {}
|
options: CompileOptions = {
|
||||||
|
hasGlobalValues: false,
|
||||||
|
}
|
||||||
): TemplateFunction {
|
): TemplateFunction {
|
||||||
// parsing
|
// parsing
|
||||||
const ast = parse(template, options.customDirectives);
|
const ast = parse(template, options.customDirectives);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { OwlError } from "../common/owl_error";
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const RESERVED_WORDS =
|
const RESERVED_WORDS =
|
||||||
"true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date".split(
|
"true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date,__globals__".split(
|
||||||
","
|
","
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(
|
|||||||
translateFn: this.translateFn,
|
translateFn: this.translateFn,
|
||||||
translatableAttributes: this.translatableAttributes,
|
translatableAttributes: this.translatableAttributes,
|
||||||
customDirectives: this.customDirectives,
|
customDirectives: this.customDirectives,
|
||||||
|
hasGlobalValues: this.hasGlobalValues,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface TemplateSetConfig {
|
|||||||
templates?: string | Document | Record<string, string>;
|
templates?: string | Document | Record<string, string>;
|
||||||
getTemplate?: (s: string) => Element | Function | string | void;
|
getTemplate?: (s: string) => Element | Function | string | void;
|
||||||
customDirectives?: customDirectives;
|
customDirectives?: customDirectives;
|
||||||
|
globalValues?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TemplateSet {
|
export class TemplateSet {
|
||||||
@@ -30,6 +31,8 @@ export class TemplateSet {
|
|||||||
translatableAttributes?: string[];
|
translatableAttributes?: string[];
|
||||||
Portal = Portal;
|
Portal = Portal;
|
||||||
customDirectives: customDirectives;
|
customDirectives: customDirectives;
|
||||||
|
runtimeUtils: object;
|
||||||
|
hasGlobalValues: boolean;
|
||||||
|
|
||||||
constructor(config: TemplateSetConfig = {}) {
|
constructor(config: TemplateSetConfig = {}) {
|
||||||
this.dev = config.dev || false;
|
this.dev = config.dev || false;
|
||||||
@@ -46,6 +49,8 @@ export class TemplateSet {
|
|||||||
}
|
}
|
||||||
this.getRawTemplate = config.getTemplate;
|
this.getRawTemplate = config.getTemplate;
|
||||||
this.customDirectives = config.customDirectives || {};
|
this.customDirectives = config.customDirectives || {};
|
||||||
|
this.runtimeUtils = { ...helpers, __globals__: config.globalValues || {} };
|
||||||
|
this.hasGlobalValues = Boolean(config.globalValues && Object.keys(config.globalValues).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTemplate(name: string, template: string | Element) {
|
addTemplate(name: string, template: string | Element) {
|
||||||
@@ -101,7 +106,7 @@ export 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];
|
||||||
|
|||||||
@@ -43,6 +43,21 @@ exports[`app app: clear scheduler tasks and destroy cancelled nodes immediately
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`app can add functions to the bdom 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
let { __globals__ } = helpers;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<div class=\\"my-div\\" block-handler-0=\\"click\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let hdlr1 = [()=>__globals__.plop('click'), ctx];
|
||||||
|
return block1([hdlr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`app can call processTask twice in a row without crashing 1`] = `
|
exports[`app can call processTask twice in a row without crashing 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -201,4 +201,22 @@ describe("app", () => {
|
|||||||
await app.mount(fixture);
|
await app.mount(fixture);
|
||||||
expect(fixture.innerHTML).toBe("parent<div></div>");
|
expect(fixture.innerHTML).toBe("parent<div></div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("can add functions to the bdom", async () => {
|
||||||
|
const steps: string[] = [];
|
||||||
|
class SomeComponent extends Component {
|
||||||
|
static template = xml`<div t-on-click="() => __globals__.plop('click')" class="my-div"/>`;
|
||||||
|
}
|
||||||
|
const app = new App(SomeComponent, {
|
||||||
|
globalValues: {
|
||||||
|
plop: (string: any) => {
|
||||||
|
steps.push(string);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await app.mount(fixture);
|
||||||
|
expect(fixture.innerHTML).toBe(`<div class="my-div"></div>`);
|
||||||
|
fixture.querySelector("div")!.click();
|
||||||
|
expect(steps).toEqual(["click"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user