Commit Graph

94 Commits

Author SHA1 Message Date
Géry Debongnie 6465665550 [FIX] qweb/component: handle nested t-foreach and components
The way keys were handled in QWeb was mostly ok, but a little naive. It
is fine when we deal with a list of dom nodes, since the reconciliation
algorithm need only to be able to differentiate/reconcile nodes in that
list, but it is an issue with components, which needs to globally be
able to find themselves in their parent's children map.

Because of the way this was handled, there were situations were Owl
internal virtual dom would crash, since components wrongly assumed that
they were already rendered in a different place.

To fix this, we generalize the way keys are generated, by concatenating
all sub keys coming from each iteration loops.

closes #584
2019-12-17 15:23:24 +01:00
Géry Debongnie 9216c5c24b [FIX] qweb: t-call properly transfer key to sub components
Since t-call is now a function call, we need to properly handle the
internal key used to find previous components.  If a t-call is inside a
t-foreach, then we need to transfer the key to the sub template.
Otherwise, each component in the subtemplate will be associated to the
same key, which means that it will lead to big issues: components are
destroyed and reused...

closes #581
2019-12-16 20:30:34 +01:00
Géry Debongnie ef6fd457f8 [FIX] qweb: add support for spread operator
closes #575
2019-12-13 22:35:26 +01:00
Lucas Perais (lpe) 5e7f1d5e6d [FIX] qweb: t-call must pass extra parent
Before this commit, when template was t-call'ed and defined
t-component directive within it, there was a crash because extra.parent was never defined

After this commit, this use case works
2019-12-13 20:28:49 +01:00
Géry Debongnie 29a80d0b28 [FIX] qweb: properly display falsy values
While it is not tested, nor documented, the reference QWeb
implementation display the `false` value as "false". So, we have to
adapt the Owl implementation to match that behaviour.

At the same time, this commit uses 'let' instead of 'var' in various places,
to make the compiled code more consistant.
2019-12-13 14:48:19 +01:00
Géry Debongnie 0931a4dc5b [FIX] qweb: bind handlers to component
Before this commit, the handlers were bound to the current context,
which is often the component but not necessarily.  In some cases, a sub
scope can be created (with t-foreach, or slots, or t-call), and the
context is actually an object with the actual component instance it its
prototype chain, but not the component.
2019-12-12 14:32:43 +01:00
Géry Debongnie 4e22dbcad6 [FIX] qweb: accept assignations in qweb expressions
closes #560
closes #569
2019-12-12 14:32:43 +01:00
Géry Debongnie 97d8b3ed8c [REF] tests: remove Widget common class
Bad name, and bad practice to use it. It makes tests less standalone.
2019-12-11 12:25:05 +01:00
Géry Debongnie 9921ae07b1 [REF] tests: move slots tests out of main component file 2019-12-11 12:25:05 +01:00
Géry Debongnie 41cb5f1abd [FIX] *: remove useless values to t-else and t-debug
The actual value does not matter, only the fact that it is present.

closes #564
2019-12-11 12:25:05 +01:00
Géry Debongnie bc455be720 [IMP] components: slots can now define default content
closes #554
2019-12-11 10:11:47 +01:00
Géry Debongnie ce9c2f8613 [FIX] qweb/component: refactoring of scoping/variables/slots
This commit is a significant refactoring of the internal of QWeb. It
simplifies the way variables/scoping and slots interact together.  The
main idea is that we use a simple scope object instead of a
context/var/scope object.

This commit also implement the actual correct QWeb semantic for the
t-call directive with a sub body.  Before, we simply extracted the
variables from the body and injected them at the top of the sub
template.  We now simply compile the body before the sub template.

This is a joint work with Lucas (lpe).

closes #541
closes #544
closes #545

closes #557
closes #556
2019-12-11 10:07:41 +01:00
Géry Debongnie 7ec05ff8cf [IMP] component: add position option to mount method
A component can now be mounted in different positions: either 'before' (at
the start), 'after' (at the end), or 'attach' (take possession of a target
element)

closes #539
2019-12-06 10:53:01 +01:00
Géry Debongnie a0bfbf6dd0 [FIX] qweb/component: do not call handlers for unmounted components
Unmounted components should be considered inactive, at least from the
perspective of Owl itself.

closes #543
2019-12-06 09:58:12 +01:00
Géry Debongnie b67cb71048 [FIX] slots: propagate vars to correct function
closes #529
2019-12-06 09:53:48 +01:00
Géry Debongnie f12d3373c9 [FIX] qweb: properly handle empty class attribute
The classList.add method actually crashes when given an empty string (or
a string with just white spaces).

closes #530
2019-12-03 16:19:09 +01:00
Géry Debongnie ed4ab51c17 [FIX] component: tricky concurrency issue
This is a really interesting problem: there was a situation where a
component would not have an event handler properly bound. The reason was
that we were in a situation where the scheduler task queue was flushed
at an unfortunate timing:

- parent component template is rendered
- subcomponent is prepared:
   - sub component is willStarted
   - it is rendered (so, fiber counter is set to 0)
- scheduler task queue is flushed => we patch the DOM
- the code registered in the __prepare.then(handler) is executed, which
  add the createHook to the vnode (but after the dom is patched)

Usually, the last two steps happen in a different order, but in an
environment with connected components, we sometimes flush the task queue
at various moments, so some code could be executed between the end of
__prepare and the registered handler.

The fix is interesting: we give a callback to the __prepare function
instead of registering a .then handler to the deferred.  This callback
is then guaranteed to be called at exactly the proper timing.

Thanks seb for the hard work of finding the root cause of this issue

closes #520
2019-12-03 08:23:10 +01:00
Géry Debongnie 06a6d890d7 [DOC] move some component doc in sub pages
closes #354
2019-12-02 08:55:12 +01:00
Géry Debongnie 8c17bb0411 [FIX] component: reorganize fiber update algorithm
Closes #473
Closes #484
Closes #489
Closes #492
Closes #512

Co-authored-by: Aaron Bohy <aab@odoo.com>
2019-11-29 15:13:37 +01:00
Aaron Bohy 6e5d6aa226 [FIX] slots: use correct scope and vars at update
Part of #473
2019-11-28 14:42:46 +01:00
Aaron Bohy 85d4393242 [FIX] t-slot: correct parented relationship with nested slots
Closes #506
2019-11-28 10:15:57 +01:00
Aaron Bohy 6c8b401092 [FIX] component: slots: multiple slots with components
Closes #508
2019-11-27 15:47:55 +01:00
Géry Debongnie 6c753bb49f [FIX] qweb: scope t-key directive to node and subnodes
not to siblings

closes #503
2019-11-27 13:31:40 +01:00
Géry Debongnie 8fb35ed969 [FIX] owl: add prettier to devDependencies
also, run prettier on codebase

closes #498
2019-11-27 08:06:17 +01:00
Géry Debongnie 14db513f3b [FIX] component: allow fragments in method mount
It is now possible to mount components in fragments

closes #494
2019-11-22 15:00:37 +01:00
Géry Debongnie 48744cfa87 [DOC] add hooks explanation, and testing/debug page
closes #372
closes #419
2019-11-22 13:41:44 +01:00
Aaron Bohy 7e6b1a28a0 [IMP] qweb: throw error if t-component not used on a node t
Before this rev, using t-component on a div (for example) node
would silently ignore the div and replace it by the root node of
the component. A way to improve this was to create an extra div
node and to put the component inside it. However, it raised
questions: what do we do with other attributes set on this tag?
Do we apply them on the div, or on the component? In addition,
some of them only make sense on the component (e.g. props), so we
have to detect them. Whatever we would have decided, it wouldn't
have been obvious from the user point of view, so we chose not to
support it, and we thus now raise an error in this case.

Closes #487.
2019-11-21 17:06:35 +01:00
Aaron Bohy 58f6724194 [FIX] component: reset isRendered when reusing fiber
It is important to reset the isRendered flag to false to ensure
that other (subsequent) simultaneous calls to render will be
skipped, as the currentFiber is actually no yet (re-)rendered.

Closes #483
2019-11-21 15:35:30 +01:00
Géry Debongnie 27b4eece66 [FIX] component: display correct error in some case
It could happen that a component would crash. But then, the __render
code tried to copy the class properties into the vnode, which does not
exist, creating a new error.

So, the solution is to process the classObj only in the successful part
of the render call, which then will not crash, so the normal error
handling will occur.
2019-11-20 14:35:25 +01:00
Aaron Bohy 2e3e8cd603 [FIX] component: destroy not yet mounted components (2)
Following 2922cee6ea

Previous commit was not correct: used children with a cancelled
fiber (for instance, with a new currentFiber) could be destroyed.
This commit fixes the issue differently, by directly detecting
children that are not used anymore (and not mounted), and destroy
them directly (no need to wait for willStart promise to be resolved
anymore).
2019-11-20 14:31:03 +01:00
Aaron Bohy 2922cee6ea [FIX] component: can destroy not yet mounted components
Sub-issue of #476
2019-11-20 11:43:14 +01:00
Géry Debongnie 7749fd3b96 [FIX] component: remove stale fiber in scheduler
Owl takes care of not rendering a component that will be unmounted
immediately after, and it works.  However, it also should clean
up the newly added fiber.
2019-11-20 11:24:32 +01:00
Géry Debongnie f44b9a38ae [IMP] component: better coordination for errors in rendering
part of #410
2019-11-20 11:24:32 +01:00
Géry Debongnie c7773bfd2a [FIX] qweb/component: fix scoping issue with t-model and t-foreach
Without this fix, the handler set by t-model did not capture properly
the expression that needs to be updated.

closes #474
2019-11-19 13:15:34 +01:00
Géry Debongnie bd39797f17 [FIX] component: propagate errors to caller
Errors from mounted/willPatch/patched should be returned to caller
(either mount or render functions)

part of #410
2019-11-18 14:29:54 +01:00
Géry Debongnie 54e1734f2f [IMP] component: display better error message if render is empty
closes #446
2019-11-14 16:40:07 +01:00
Géry Debongnie 56087b95cd [REF] observer: notify subscribers directly
This rev. moves the logic of batching the notifications of changes
occurring in the same microtask tick, from the observer, to the
listeners (the context, and the render function of components).
By doing so in render, we ensure that similar renderings are
batched in a single one, wherever they come from (state change,
store change, direct call...).
2019-11-14 15:12:31 +01:00
Aaron Bohy e5940b4b6b [FIX] component: concurrent calls to mount and render
Closes #450
2019-11-14 15:12:31 +01:00
Géry Debongnie f2b3ebd1ec [FIX] component: properly set currentFiber to null in all cases
Whenever a rendering is completed, we need to reset the currentFiber
to null to make sure all subsequent renderings will not be
confused.

However, the way it was done before this commit was wrong in a
specific situation: we resetted the currentFiber to null in the
patch method.  The idea was that this method was called every time
the component completes a rendering. But this is not true: it
can happen that a component is unmounted and remounted without
changes.  Then the component will be patched, but if there is no
change, it will not call recursively the patched methods of its
children.

So, we need to choose a better place to reset it to null.

closes #454
2019-11-14 11:56:13 +01:00
Aaron Bohy e47f604449 [FIX] component: concurrent rendering issue
Resolved rendering with cancelled fiber for (not yet) destroyed
component -> Cannot read property 'sel' of null

Closes #421
2019-11-12 10:01:12 +01:00
Aaron Bohy 7e721a96b5 [IMP] hooks: useRef on component: set el anyway
Closes #437
2019-11-06 17:06:37 +01:00
Aaron Bohy af4f372506 [REF] component: mount: remove renderBeforeRemount option
Re-render the component all the time before remounting it, which
seems safer anyway.

In the test, we had to add a nextTick to wait for the changes to
be notified (before, we waited thanks to the additional call to
mount). If we don't do the nextTick, mount is called, and render
is called right after (before the promise returned by mount is
resolved). This scenario doesn't work right now (see #441).

Closes #381
2019-11-06 16:26:12 +01:00
Géry Debongnie 8d1dd06340 [IMP] component: error when mounted on invalid target 2019-11-04 08:41:29 +01:00
Géry Debongnie d74b5a03db [IMP] component: add props on root components
This is a partial revert of commit 7d249d6f09.

The reason is that this changes made it much harder to unit test
components.  Before, we could simply instantiate a component
like this:
const my|Comp = new MyComponent(null, props);

and then simply test it.  This commit reestablish that possibility.
2019-11-01 09:03:27 +01:00
Aaron Bohy 05a678c039 [IMP] component: get env from constructor
closes #430
2019-11-01 08:39:35 +01:00
Géry Debongnie ba483b6e2c [FIX] component tests: make them work on windows
For an unknown reason, it looks like the way ticks, micro task ticks or other subtle scheduling issues are different on a windows machine (it may be because of other difference, such as a specific version of nodejs).

Anyway, I could not find the cause of the issue, but
simply waiting an extra microtask tick seems to work.
2019-10-31 12:32:26 +01:00
Aaron Bohy 08cb83149e [REM] component: remove t-keepalive directive
We don't see any usecase for it, it makes the code more complex,
and there were still potential unresolved concurrency issues with
it.

Part of task #295
2019-10-30 16:35:45 +01:00
Aaron Bohy 7d249d6f09 [IMP] component: do not set props in root components
Also remove props from Fiber, as it was not useful anymore.
2019-10-30 15:09:10 +01:00
Aaron Bohy 9106c19066 [IMP] component: simplify constructor API
It now takes two arguments: parent (optional, only for non-root
components) and props (optional). In the case of the root component,
the env is taken from the config (config.defaultEnv). If it doesn't
exists, the default env is created on the fly.

Closes #306
2019-10-30 15:09:10 +01:00
Aaron Bohy 9e37b968e8 [FIX] component: error handling: rendering with sub components
Closes #425
2019-10-30 13:27:48 +01:00