# v2.2.10
- [IMP] runtime: allow using any class as a type in props validation
- Update reactivity.md
- [IMP] owl-vision: Better snippets
- [FIX] docs: code in example cannot run
Previously, we had a fixed whitelist for types that were allowed during
props validation. The implementation however supports using arbitrary
classes, and in practice it's desirable to do so, and already done when
not using typescript (when using typescript, it will error if the class
is not whitelisted), eg in Odoo, we use "Element" for the arch in the
standard view props, but this causes all view controllers to fail type
checking because it's not whitelisted.
This commit simply replaces existing constructors by a generic
constructor type, and adds a test with a validation success and a test
with a validation failure.
While Sets have better lookup complexity than arrays, because of the
large constant factors, small arrays can perform better than small sets
when checking for inclusion.
In practice, replacing both of the raw types sets with arrays can
improve performance of reactive-heavy workloads by as much as 30%.
Considering the reactivity code is very hot when rendering data-heavy
components, and the low impact on readability of the fix, the
cost-benefit analysis is clearly in favour of making the fix.
A template set can now obtain a template by calling the function
getTemplate (if any) received in the initial config.
The returned value can be an Element instance, a template string, a
function (i.e. a compiled template), or null. In the last case, owl will
look into the template set rawTemplates object.
Before to this commit, the .trim modifier did not work correctly. The value
in the model is always trim at each input event but not the visual value
in the input. This difference between the visual and the model value cause
few strange bug.
After reflection, we think that we always want to be in .lazy when we use .trim.
Because we want to trim the final value during the onchange event and not
at each input event. If we do it at each input event, we can't write more then
one word easily.
So this commit change the behavior of the .trim modifier to always be in .lazy
For some reason the code of parseXML was duplicated, despite being
exactly the same except for some whitespace. Move it out into a common
utils file.
closes#1569
# v2.2.7
- [IMP] types: correctly support `Function` type for props-validation
- [IMP] app: allow to instantiate templates lazily
- [FIX] compiler: compile named slot in t-component in named slot
- [IMP] devtools: update the devtools documentation
- [IMP] owl-vision: syntax scripts, single quotes attributes and slot props highlight and switch below command
- [IMP] doc: improve documentation of useExternalListener
- [FIX] devtools: remove highlights when out of devtools
- [IMP] devtools: highlight component on select
- [ADD] owl-vision: vscode extension initial commit
Previously, having a Function as a type in the static props description
of a component would only work if the component was not the root
component, as the static props description on Component was "any",
whereas the static props description on ComponentConstructor was
"Schema". This meant that static props description on non-root
components was not type-checked, and on root components it was
type-checked only on the mount call.
This commit makes it so that static type description is of type "Schema"
on Component, now causing static props description to be type-checked,
and adds `typeof Function` to the `BaseType` union, which allows
declaring that a component expects a function as a prop.
Closes#1448
With this commit, the templates that are given while instantiating the
App class can be an object with templates not yet parsed (i.e. string,
not Document). This allow to instantiate the App class with templates
that are not yet parsed, and these templates will be parsed only when
needed.
Part of task-id 3601257
Previously, if a t-set-slot was inside a t-component itself inside a
t-set-slot the parser would crash, because the slot is removed from the
template before compiling its content, causing a further check's
assumption to be broken (the t-set-slot remains connected to the
component's xml node)
`useEffect` type is not compatible with later versions of Typescript.
(I tried with Typescript 5.2, I didn't check which specific
version had the breaking change)
This prevents other projects using owl (such as o-spreadsheet) to
upgrade their own version of Typescript.
`<T extends [...T]>` raises the two following errors:
`Type parameter 'T' has a circular constraint.ts(2313)`
`A rest element type must be an array type.`
# v2.2.6
- [IMP] devtools: add svg elements detection
- [FIX] reactivity: do not notify for NOOPs on collections
- [IMP] app: export apps set as static property
- [IMP] runtime: do not check template equality outside dev mode
- [FIX] runtime: properly support t-foreach on strings
Previously, if a reactive was observing the presence of an item in a
set that was originally not present, it would get notified when that
item was "deleted" from the set (even though there was nothing to delete
and the set did not change). The same applied to the key already being
present and then being "added". The same thing occured with Map, both
for presence but also for values (setting a key to the value it was
already set to would notify).
This commit fixes that.
Before this commit, Owl would export the list of apps in a global object
`__OWL_DEVTOOLS__`. However, it is sometimes useful to be able to
access that set, even outside of the devtools (for example, to register
templates in all active apps).
closes#1515
When defining a template with a name that the template set already
contains, we currently always check whether the template is the same and
throw an error when it's not. This is potentially expensive as it can
involve serializing a pretty large XML document. This check is only
supposed to help during development so this commit disables this check
outside dev mode.
Previously, support for iterables was added to t-foreach. The idea was
that anything that you can spread or on which you can use for..of would
be supported. Due to an implementation mistakes, strings, which are
iterable were not supported because we checked that the typeof the
iterable was 'object'.
To fix this, we coerce the iterable to an object and check whether that
coerced value has a Symbol.iterator property, which is what happens
behind the scenes when using for..of or spreading a primitive.
Closes: odoo/owl#1503
Firefox will not serialize the xmlns attributes of node inside
XMLDocuments, see https://bugzilla.mozilla.org/show_bug.cgi?id=175946
it will only output an xmlns attribute if the node being serialized has
a non-null namespaceURI.
When compiling templates, we currently use a special attribute,
"block-ns" to keep track of the namespace, but we do not make use of the
namespace to create the elements that will be serialized to the compiled
block string. This causes a difference in behaviour between Chrome and
Firefox: since we end up with an Element with two attributes: the
block-ns attribute and the xmlns attribute. Chrome will serialize both,
but Firefox will only serialize the block-ns because the Element does
not have a namespaceURI.
To fix this issue, we get rid of the block-ns magic attribute
completely, and use xmlns instead. We also use the namespace when
creating intermediate elements that will be used to create the
serialized block string: the namespace is only used to create the
elements but *not* set as an attribute, as this would cause chrome to
serialize it twice, causing a duplicate attribute error when parsing it
further down the line.
When creating the template element for the block at runtime, the xmlns
attribute is used both as the namespace with which to create the
element, and set as an attribute, this doesn't cause issues when
serializing later because the namespaceURI is never serialized as an
attribute when serializing an HTML document[1], so we avoid the
double-serialization in Chrome, and when doing HTML serialization,
Firefox will correctly serialize the attribute.
It's desirable that the xmlns is set as an attribute to allow users to
use owl to render SVG, and then use the HTML serialization of it as a
SVG even outside the context of an HTML document (eg to generate an SVG
file or an SVG data URL).
[1]: https://w3c.github.io/DOM-Parsing/#xml-serialization
Because the default content of a t-call is compiled before the block of
the t-call is created, the default content can sometimes incorrectly be
treated as though it is at the root of the template. This causes various
issues, in the case of a t-if, the default content will just replace the
t-call entirely when truthy, and when falsy the template will not return
anything, leading to a crash. Similar things occur with t-foreach and
t-out with a default content.
This commit fixes that by moving the block creation for the t-call ahead
of the compilation of the default content. In doing so, it makes the
context attribute "preventRoot" obsolete: the purpose of this attribute
is to somehow make the code aware that the root of the template will be
defined later, but because it wasn't propagated everywhere properly it
caused this issue. Now that the root already exists before we compile
the default content, we don't need it anymore.
In odoo/owl#1352 we added support for using t-foreach on Map objects,
maps should behave the same as objects where keys are available under
the name specified in t-as and values under that same name with the
suffix `_value`. Unfortunately, because the code for objects was written
in a confusing way (values were stored in a variable named `keys` and
vice versa), the implementation for Map was incorrect and keys and
values were swapped.
This commit fixes that and rewrites the code to be less confusing: keys
are extracted from the variables `k_block` and values from `v_block`,
which swaps the behaviour, and the code to prepare a list from an object
now extracts the keys in `keys` and the values in `values`
Previously, when a template failed to compile because of a syntax error
(typically because we don't do any syntax checking when compiling
expression, allowing invalid expressions to be transpiled successfully),
the error reporting was very minimal: you would only get the error
message itself (eg: "Unexpected token") with the stack information of
the error pointing to the call to `new Function` in owl, which is not
very useful.
This commit catches the compilation error and completes it with
information about the template name when available, and also adds the
generated code to the error message, allowing the user to just
copy/paste it in their web console or code editor to get a more precise
location for the error.
Before this commit, the App destroy method would not destroy everything
synchronously. The code scheduled a flush, which is asynchronous, to
finally clean up the task lists, and destroy the cancelled nodes. But
this is not really good for tests: we need a stronger guarantee that
nothing will happen after the destroy.
With this commit, we simply call the processTask method immediately
after destroying the root component, so all cancelled nodes will be
destroyed immediately.
Before this commit, the template parser would allow using t-esc on a
component tag (<MyComponent t-esc="expr"/>) but would incorrectly ignore
the component when parsing a t-out: <MyComponent t-out="expr"/> would be
parsed as <t t-out="expr"/>
This commit solves the issue, and also, moves the `t-out` parsing code
next to `t-esc` so they have the same priority relatively to other
directives.
closes#1483
# v2.2
- [IMP] runtime: add support for Map and other iterables in t-foreach
- [IMP] runtime: only destroy component in raf callback
- [REF] runtime: simplify implementation of batched
- [FIX] compiler: allow t-model.number to work with select
- [FIX] devtools: Fix crash when no root node
- [FIX] devtools: fix/imp env display
- [FIX] devtools: fix symbols handling and display
Before this commit, most of the time, components are destroyed when the
virtual dom is patched and a component node is removed. However, since
Owl is asynchronous and a component may take some time to get ready
(with onWillStart), it can happen that a component is created, then
before it is ready, it is recreated. In that case, the initial instance
has to be destroyed.
Before this commit, the destroy operation was done immediately, when we
cancel the current fibers. However, this means that we cannot have a
guarantee between micro task ticks that a component has not been
destroyed in the meantime.
For example, in Odoo, it is common to use the rpc service, which will
throw an error if called by a destroyed component. But because of the
possible destruction of a component at any time, the following code is
unsafe:
async loadSomeData() {
// guaranteed to be called when component is alive
await Promise.resolve();
// however here, component may have been destroyed
this.rpc(...)
}
So, to prevent this issue, we can slightly delay the destroy operation.
It is not entirely trivial, since we need to find a way to neutralize
the component in the meantime. But it seems like performing all that
kind of operation at the "commit" phase (so, the request animation frame
callback) makes sense to me.
So, this commit modifies the code to add a new component status
(cancelled) and use it to cancel components that are waiting to be
destroyed. These components will then be destroyed as soon as the
requestanimation frame starts, before all other dom operations.
Currently the implementation of batched is quite complicated and
difficult to read. This is because this approach tried to block all
calls at the same point and then only let the first one go through, but
an alternative approach is to simply throw away the calls that are made
after the first one has been scheduled. This change makes the
implementation much simpler to understand.
Co-authored-by: Aaron Bohy <aab@odoo.com>
Before this commit, owl parser would ignore the `.number` suffix on
<select> options. I do not see a good reason for that, and it prevents
some legitimate usecases.
closes#1444
Class attributes are managed in a specific way in owl: they are merged
with existing class attributes, and also, they can be defined in
multiple ways (t-att-class, t-attf-class, t-att=['class', ...] and each
of these can be combined together.
Before this commit, the `t-att` syntax was handled as a normal
attribute, and therefore, would not combine as required with existing
classes.
closes#1453
Before this commit, the `t-on` directive assumed that the next character
would be a -, and ignored it, so if someone would write `t-onclick` by
mistake, Owl would then add an event handler on the `lick` event,
instead of `click`.
With this commit, we improve the parser to make it stricter and fail if
there is no dash.
closes#1441
This commit adapts the behavior of the devtools global hook to get
the toRaw and reactive functions from the __OWL_DEVTOOLS__ variable
instead of the global owl when it is missing. Also adds the functions
to the __OWL_DEVTOOLS__ variable for the former to work.
This allows the devtools to work in environments where owl is loaded
through ES modules.
Also quickly fixes iframes detection update on page reload.
Before this commit, the translate function was not applied to text
content inside the body of a t-set (unless that content was itself
inside some html). This is not clearly not intended.
To fix it, we just need to call the translate function at the
appropriate moment.
closes#1434
Before this commit, when using a dynamic t-call, it was possible to have
a collision between subcomponent keys. This would cause hard to
understand owl crash, because owl would incorrectly use the same
component instance for two different template location. From
owl point of view, one of these component has to be destroyed and the
other one should be mounted, so a crash would occur.
The fix is to simply properly key sub components.
# v2.1.2
- [FIX] t-out: does not crash when outputting null
- [FIX] playground: fix name of playground component
- [FIX] playground: use ES owl version instead of iife
- [IMP] playground: give a name so it is more explicit in devtools
- [REF] github page: move page to docs folder on master branch
- [IMP/FIX] playground: fix and improve various things
Before this commit, doing `t-out="null"` would crash, since the
safeOutput function would assume that it is a block, thanks to the fact
that `typeof null === 'object'`.
We handle here the null value just as if it was undefined: it outputs an
empty string.
# v2.1.1
- [FIX] components: solve missing update (concurrency issue)
- [DOC] remove old references to comp for useRef hook
- [FIX] devtools: Fix build commands for windows users
- [FIX] devtools: Fix devtools in detached window
- [IMP] devtools: Add a button to navigate to the doc
- [IMP] devtools: Add devtools documentation
- [IMP] Allow app to be mounted in shadow DOM
- [IMP] playground: allow sharing playground links
- [IMP] runtime: allow validating object values using a type description
- [FIX] devtools: Increase vertical padding of the search bar
- [FIX] devtools: Hide the collapse all button
- [FIX] devtools: Fix bad computation of highlight boxes on the page
- [FIX] package: Auto-update package-lock.json
Before this commit, in some specific situations, owl could skip updating
the DOM, even though it should. Here is what could happen:
- we have a parent component (A) and a child component (B)
- B depends on some reactive props from A
- we update some state that results in A being rendered, and B updated
- before this render is applied to the dom, we update some state again,
which causes A to be rendered again
- however, this new render is such that the B props are now identical,
so it will skip rendering B
- it will then apply the result of the render to the DOM => only A is
updated but B should also be updated!
The problem comes from the fact that Owl committed the props to the
component right after the rendering, to the new props were used in the
props comparison method to decide if B should be updated. This is
incorrect, we should always use the current props to decide what to do,
and only commit them to the component after it has been patched.