[IMP] component: add static css support for sub components

part of issue #80
This commit is contained in:
Géry Debongnie
2019-05-04 22:26:51 +02:00
parent ec0bafaa8e
commit 51320204f9
3 changed files with 74 additions and 9 deletions
+29 -8
View File
@@ -4,7 +4,7 @@
- [Overview](#overview) - [Overview](#overview)
- [Example](#example) - [Example](#example)
- [Templates](#templates) - [Composition](#composition)
- [Reference](#reference) - [Reference](#reference)
- [Properties](#properties) - [Properties](#properties)
- [Methods](#methods) - [Methods](#methods)
@@ -65,7 +65,7 @@ a state object is defined. It is not mandatory to use the state object, but it
is certainly encouraged. The state object is [observed](observer.md), and any is certainly encouraged. The state object is [observed](observer.md), and any
change to it will cause a rerendering. change to it will cause a rerendering.
## Templates ## Composition
The example above shows a QWeb template with a `t-on-click` directive. Widget The example above shows a QWeb template with a `t-on-click` directive. Widget
templates are standard [QWeb](qweb.md) templates, but with an extra directive: templates are standard [QWeb](qweb.md) templates, but with an extra directive:
@@ -73,18 +73,39 @@ templates are standard [QWeb](qweb.md) templates, but with an extra directive:
widgets: widgets:
```xml ```xml
<div> <div t-name="parent">
<span>some text</span> <span>some text</span>
<t t-widget="MyWidget" t-props="{info: 13}"> <t t-widget="MyWidget" t-props="{info: 13}">
</div> </div>
``` ```
In this example, the template create a widget MyWidget just after the span. See ```js
the [QWeb](qweb.md) documentation for more information on the `t-widget` directive. class ParentWidget extends owl.Component {
template = 'parent';
widgets = { MyWidget: MyWidget};
...
}
```
In this example, the `ParentWidget`'s template creates a widget `MyWidget` just
after the span. See the [QWeb](qweb.md) documentation for more information on the
`t-widget` directive.
Note that the rendering context for the template is the widget itself. This means Note that the rendering context for the template is the widget itself. This means
that the template can access `state`, `props`, `env`, or any methods defined in the widget. that the template can access `state`, `props`, `env`, or any methods defined in the widget.
**CSS and style:** there is some specific support to allow the parent to declare
additional css classes or style for the sub widget: css declared in `class`, `style`, `t-att-class` or `t-att-style` will be added to the
root widget element.
```xml
<div t-name="parent">
<t t-widget="MyWidget" class="someClass" style="font-weight:bold;" t-props="{info: 13}">
</div>
```
## Reference ## Reference
An Owl component is a small class which represent a widget or some UI element. An Owl component is a small class which represent a widget or some UI element.
+14 -1
View File
@@ -1212,8 +1212,21 @@ const widgetDirective: Directive = {
finalizeWidgetCode += `;delete context.refs[${refKey}]`; finalizeWidgetCode += `;delete context.refs[${refKey}]`;
} }
ctx.addIf(`isNew${widgetID}`); ctx.addIf(`isNew${widgetID}`);
let createHook = "";
let classAttr = node.getAttribute("class");
let styleAttr = node.getAttribute("style");
if (classAttr || styleAttr) {
const classCode = classAttr
? classAttr
.split(" ")
.map(c => `vn.elm.classList.add('${c}')`)
.join(";") + ";"
: "";
const styleCode = styleAttr ? `vn.elm.style = '${styleAttr}'` : "";
createHook = `vnode.data.hook = {create(_, vn){${classCode}${styleCode}}};`;
}
ctx.addLine( ctx.addLine(
`def${defID} = def${defID}.then(vnode=>{let pvnode=h(vnode.sel, {key: ${templateID}});c${ `def${defID} = def${defID}.then(vnode=>{${createHook}let pvnode=h(vnode.sel, {key: ${templateID}});c${
ctx.parentNode ctx.parentNode
}[_${dummyID}_index]=pvnode;pvnode.data.hook = {insert(vn){let nvn=w${widgetID}._mount(vnode, vn.elm);pvnode.elm=nvn.elm;${refExpr}},remove(){${finalizeWidgetCode}},destroy(){${finalizeWidgetCode}}}; w${widgetID}.__owl__.pvnode = pvnode;});` }[_${dummyID}_index]=pvnode;pvnode.data.hook = {insert(vn){let nvn=w${widgetID}._mount(vnode, vn.elm);pvnode.elm=nvn.elm;${refExpr}},remove(){${finalizeWidgetCode}},destroy(){${finalizeWidgetCode}}}; w${widgetID}.__owl__.pvnode = pvnode;});`
); );
+31
View File
@@ -1224,6 +1224,37 @@ describe("props evaluation (with t-props directive)", () => {
}); });
}); });
describe("class and style attributes with t-widget", () => {
test("class is properly added on widget root el", async () => {
class ParentWidget extends Widget {
inlineTemplate = `
<div>
<t t-widget="child" class="a b"/>
</div>`;
widgets = { child: Child };
}
class Child extends Widget {
inlineTemplate = `<div class="c"/>`
}
const widget = new ParentWidget(env);
await widget.mount(fixture);
expect(fixture.innerHTML).toBe(`<div><div class="c a b"></div></div>`);
});
test("style is properly added on widget root el", async () => {
class ParentWidget extends Widget {
inlineTemplate = `
<div>
<t t-widget="child" style="font-weight: bold;"/>
</div>`;
widgets = { child: Widget };
}
const widget = new ParentWidget(env);
await widget.mount(fixture);
expect(fixture.innerHTML).toBe(`<div><div style="font-weight: bold;"></div></div>`);
});
});
describe("other directives with t-widget", () => { describe("other directives with t-widget", () => {
test("t-on works as expected", async () => { test("t-on works as expected", async () => {
let n = 0; let n = 0;