This is a tricky commit. The key point is that the Fiber.complete
method, which commits a rendering to the DOM works like this: it
traverses the component tree, patch the corresponding DOM for each
component, calls the mounted/destroy hooks, and reset the currentfiber
of components to null, all synchronously.
However, this means that it is possible for components to initiate a
rendering (which create a new currentFiber) before the currentFiber is
reset to null, so the internal state of owl is corrupted. This can
occurs in a crash, as in the test that accompanies this commit.
To fix this, we take care of resetting the currentFiber first, while we
walk the component tree. Then, the internal state is always consistent
(i.e. a currentFiber to null means that there is no pending rendering)
closes#904
Updating my node version to v16, I noticed many tests breaking, because
the way errors are formatted did change. This commit ensures that the
test suite keeps working for all node versions.
If we want to upgrade Typescript to version >4 (in this repo or another using
owl), we also need jest >25. Jest <26 do not support Typescript >4.
However, jest >26 has a few breaking changes that completely breaks owl in
tests.
This commit updates jest to the current latest version (27) and adapts the
code accordingly.
A few words on what changed
---------------------------
1. the default test environment is no longer `jsdom`. It is now manually
configured to restore the previous env.
2. the jsdom version has been upgraded. This brings a few breaking changes,
detailed later.
3. there's a bug in jsdom >16.4. Manually created `<t/>` (by qweb compilation)
are recognized as "T" and not "t". Qweb thinks it's a component (since the
first letter is capitalized), but it's not a component: boom, everything
breaks.
A fix has been proposed here jsdom/jsdom#3240. But it's not likely to land
in jest in the short term (jest would need to update its dependency to the
next major jsdom version). This commit works around the problem for now by
creating `<t/>` slighty differently such that they are in an XML document
from the start (and not HTML document).
4. the xml parser implementation changed to increase the strictness and
correctness of XML parsing, according to specifications. A few tests needed
to be adapted.
https://github.com/jsdom/jsdom/commit/c96decf837ece54bdc550dfb7dca7e5d6c97bc2d
5. jest matcher `toHaveProperty` now check inherited properties. This breaks a
few tests. Since the breaking assertions didn't bring a lot of value from a
behavior point of view (it was more "white box" technical tests), they are
removed in this commit
https://github.com/facebook/jest/commit/1256f76a5a83034b51c7524142b60b099f69a7ab
6. jsdom now implements the behavior of links (`<a/>`). One test was `click`ing
on such a link, with the right click. Jsdom now tries to navigate to the
pointed URl...but crashes because navigation is not implemented :(
It turns out the test is probably not a valid/realistic scenario. On every
tested browser (chrome - chromium - brave - edge -firefox - safari), a
right click with the mouse triggers a `contextmenu` event and no `click`
event.
https://github.com/jsdom/jsdom/commit/cc95abc576f596ff7f3eaf8245f376e1f21aa485
Previously, if two attributes in t-att-class shared some classes, their
presence would be determined by the last attribute declared, instead of
being present if any attribute containing it evaluates to true. This
commit fixes that.
The previous changes in the combine method (used to copy all the
variables defined in the current scope for use in a slot) had the effect
of squashing the prototype chain: instead of `Component -> Obj1 ->
Obj2 -> Obj3`, the combined scope had: `Component -> Obj1'`.
This has an unfortunate interaction with the way t-call is implemented,
which uses the fact that we are in a subscope to add a own
__access_mode__. It depends specifially on the prototype chain, and that
the parent scope may have a different value for that property. But with
the way combine was implemented, we lost all that subtlety since
everything is squashed.
In this commit, we reimplement that function in a way to make sure we
keep the prototype chain structure
Before this commit, Owl inline expressions with a list with multiple
elements such as [a,b,c] was transformed into
[scope['a'], b: scope['b'], scope['c']]
instead of
[scope['a'], scope['b'], scope['c']]
This is due to a previous commit adding support for short object
descriptions such as {a,b}.
To fix this means that we have to keep track of the current group type
for the expression, which is done by using a stack.
# 1.4.1
This release brings in two small fixes:
- vdom: a performance improvement to reduce number of calls to classList.remove
- slots: fix subtle issue with wrong context used in event handlers when
multiple slots are involved
In some situations (a slot inside a slot), the combine method was
wrongly copying all properties of the scope into the context, which
caused the event handling system to wrongly use a subobject as component
(since it detects the fact that __owl__ is a own property_).
Consequently, we could have very subtle issue with some properties being
shadowed by a sub object.
# v1.4.0
This release is larger than usual: lot of small fixes, and a few improvements as
well.
- config: change debug mode warning to info
- fix: add support for callable expression in event handler (for example, `t-on-click="some.function"`)
- fix: allow specific props to override generic props (in `t-props`)
- fix: add support for short object description in inline expressions: `{ hey }`
- fix: add support for t-att-value on `<textarea/>` and `<select/>`
- fix: slots: issue with scoping in nested loops
- fix: slots: default slot is not lost in some cases
- fix: do not shadow an error in case the finalizing code fails
- imp: qweb: allow multiple class in class attribute object notation: `t-att-class="{'a b': value}"`
- imp: better detection for dynamic component change (less need for `t-key`)
- fix: router: allow querystrings in path
- fix: qweb: add support for template strings
- fix: qweb: make sure nodes with t-transition are removed in all cases
There is a possibility that the transitionend event of an element/component
with t-transition directive won't trigger. Though this situation is
difficult to assert, it was observe in odoo runbot for the pos ui.
When the transitionend event is not fired, the callback that removes
the element from the dom won't be called, resulting to a corrupted view.
An example of which is the following:
```html
<div t-if="show" t-transition="fade">Hello</div>
```
If `show` is set to false by some ui action and by any chance the
transitionend event is not fired (perhaps because the transition didn't
actually start or because of completely unknown reason), the div element
will remain in the view -- and this is not desirable.
This commit patches this situation such that if after 50ms that the
transitionend event is supposed to be fired but the event isn't fired, we
force the callback using a setTimeout. This guarantees the call of the
callback that is suppose to remove the element from the view.
Before this commit, Owl could not detect that the underlying component
in a template such as <t t-component="{{state.child}}"/> was changing,
if the two components have the same tag as root element.
This is because the reconciliation is done at the vdom level, which does
not know about components. To solve this, one could use a t-key to make
sure owl can make the difference.
With this commit, we can simply use our knowledge of the fact that we are
dealing with a dynamic component and autogenerate a suitable key.
closes#623
the low level method htmlelement.classList.add does not accept multiple
classes in one string, which is why, in owl, the expression
`<div t-att-class="{'a b c': value}" />`
did not work as one might expect. It is however very convenient in real
life templates, so this commit improve owl by adding support for this
feature.
closes#813
Before this commit, the error handling code simply destroyed the
application whenever an unhandled error occured in the owl rendering
process. This is perfectly fine, except that since the application is
potentially corrupted, the destroy code may crash as well. We simply
catch those errors to avoid shadowing the main issue.
closes#866
Before this commit, owl was erroneously defining default slots in most
cases, even though they are empty. The problem occurs when the content
of a component slots is a t-set-slot, and we remove that, then use the
rest as default slots, even though it is only reduced to a set of text
nodes.
With this commit, we only consider the content as default content if it
is not only a sequence of text nodes containing only spaces.
closes#882
The templates contained in a slot have to be rendered with the current
scope, but during the rendering of the sub component, which happens
later (after the willStart for the sub component). Therefore, we need to
save the scope that should be used for the slots, so we can access the
proper variables. This was done using an Object.assign() statement,
which is actually only a shallowclone for the own properties.
In this commit, we properly copy all the properties for the current
scope, even those contained in the prototype.
closes#855
Before this commit, it was not possible to set the value of a select tag
by using the t-att-value attribute.
Doing so is not actually trivial because of the way the vdom works: it
processes the node attributes before its children are created, which
means that the vdom code tries to set the initial value of the select
before its children are created, which means that it is ignored. To make
it work, I added a node create hook which is called after the children
are completely processed.
closes#873
Before this commit, using an expression such as "{machin}" was compiled
in qweb into "{scope['machin']}" which is not valid.
With this commit, we instead transform it into "{machin:
scope['machin']}".
closes#885
Before this commit, props and t-props were computed like
`Object.assign(props, t_props)`.
Now, it computes like `Object.assign(t_props, props)` so props will
override t-props.
closes https://github.com/odoo/owl/issues/886
Backport of odoo/odoo@e4834fce69
There's no way to easily disable / silence this warning, because
multiple tours explicitly opt into debug mode (with good reasons). So
it's not enough to bypass the `mode` setter in the test setup helpers
and set `QWeb.dev` directly (which works for test_main in POS and
main_tests in web), there would also need to be special workarounds in
the 4 modules which set `owl.config.mode` based on the session's debug
mode.
I'm not sure how useful this warning is: it defaults to `false` so the
only situation in which this would be relevant would be for a
third-party to use Owl *and* explicitly enable the debug mode
in-source *and* forget to remove it when deploying to production *and*
look at their console.
Before this commit, the error handling process was too naive: once an
error occurs in a rendering, owl catches it, looks for a component that
implements the catchError method, then calls it.
However, in real life, we sometimes need to rethrow that error (or
another one) to propagate the error to some parent handler. This error
needs to be handled by the closest parent component that implements
catchError.
This is what this commit implements: it wraps the catchError call in a
try/catch, then in case of errors, try to handle it by a parent.
Have a t-call within a t-set-slot of a component.
The called template has a t-component directive.
It should be like:
```xml
<t t-name="Zero">
<Slotted>
<t t-call="someTemplate" />
</Slotted>
</t>
<t t-name="someTemplate">
<SomeComponent />
</t>
```
Before this commit, the parent of SomeComponent was the Zero component
After this commit, the parent of SomeComponent is the Slotted Component as it should be
closes#862
Before this commit, params in paths had to be be between slashes and
comprise the entirety of the contents between those slashes (eg:
`/books/{{id}}/{{name}}`)
This is unnecessarily restrictive. This commit removes this restriction,
which allows for paths such as:
- `/books/{{id}}-{{name}}`
- `#books&id={{id}}&name={{name}}`
among others
closes#858