[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)
- [Example](#example)
- [Templates](#templates)
- [Composition](#composition)
- [Reference](#reference)
- [Properties](#properties)
- [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
change to it will cause a rerendering.
## Templates
## Composition
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:
@@ -73,18 +73,39 @@ templates are standard [QWeb](qweb.md) templates, but with an extra directive:
widgets:
```xml
<div>
<span>some text</span>
<t t-widget="MyWidget" t-props="{info: 13}">
</div>
<div t-name="parent">
<span>some text</span>
<t t-widget="MyWidget" t-props="{info: 13}">
</div>
```
In this example, the template create a widget MyWidget just after the span. See
the [QWeb](qweb.md) documentation for more information on the `t-widget` directive.
```js
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
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
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}]`;
}
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(
`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
}[_${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", () => {
test("t-on works as expected", async () => {
let n = 0;