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).
|
||||
- **`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)).
|
||||
- **`globalValues (object)`**: Global object of elements available at compilations.
|
||||
|
||||
## `mount` helper
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ export interface Config {
|
||||
export interface CodeGenOptions extends Config {
|
||||
hasSafeContext?: boolean;
|
||||
name?: string;
|
||||
hasGlobalValues: boolean;
|
||||
}
|
||||
|
||||
// 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.ast = ast;
|
||||
this.templateName = options.name;
|
||||
if (options.hasGlobalValues) {
|
||||
this.helpers.add("__globals__");
|
||||
}
|
||||
}
|
||||
|
||||
generateCode(): string {
|
||||
|
||||
@@ -12,10 +12,13 @@ export type TemplateFunction = (app: TemplateSet, bdom: any, helpers: any) => Te
|
||||
interface CompileOptions extends Config {
|
||||
name?: string;
|
||||
customDirectives?: customDirectives;
|
||||
hasGlobalValues: boolean;
|
||||
}
|
||||
export function compile(
|
||||
template: string | Element,
|
||||
options: CompileOptions = {}
|
||||
options: CompileOptions = {
|
||||
hasGlobalValues: false,
|
||||
}
|
||||
): TemplateFunction {
|
||||
// parsing
|
||||
const ast = parse(template, options.customDirectives);
|
||||
|
||||
@@ -28,7 +28,7 @@ import { OwlError } from "../common/owl_error";
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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,
|
||||
translatableAttributes: this.translatableAttributes,
|
||||
customDirectives: this.customDirectives,
|
||||
hasGlobalValues: this.hasGlobalValues,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface TemplateSetConfig {
|
||||
templates?: string | Document | Record<string, string>;
|
||||
getTemplate?: (s: string) => Element | Function | string | void;
|
||||
customDirectives?: customDirectives;
|
||||
globalValues?: object;
|
||||
}
|
||||
|
||||
export class TemplateSet {
|
||||
@@ -30,6 +31,8 @@ export class TemplateSet {
|
||||
translatableAttributes?: string[];
|
||||
Portal = Portal;
|
||||
customDirectives: customDirectives;
|
||||
runtimeUtils: object;
|
||||
hasGlobalValues: boolean;
|
||||
|
||||
constructor(config: TemplateSetConfig = {}) {
|
||||
this.dev = config.dev || false;
|
||||
@@ -46,6 +49,8 @@ export 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);
|
||||
}
|
||||
|
||||
addTemplate(name: string, template: string | Element) {
|
||||
@@ -101,7 +106,7 @@ export 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];
|
||||
|
||||
@@ -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`] = `
|
||||
"function anonymous(app, bdom, helpers
|
||||
) {
|
||||
|
||||
@@ -201,4 +201,22 @@ describe("app", () => {
|
||||
await app.mount(fixture);
|
||||
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