Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use jsTree's state plugin to persist object tree state
... instead of a poor custom reimplementation of the same. This change fixes several bugs of the existing implementation and improves the overall user experience when interacting with the object tree: 1. It fixes one annoying bug I've encountered many times: if you had expanded a certain node in the tree and then changed the .ksy spec so that a node under the same path still existed in the tree but was no longer openable (in our case, only non-empty arrays and user type objects are openable, so either it has become empty or its type has changed to a primitive type, for example), then our naive code would still try to open it and asynchronously wait for it to be opened, which wouldn't happen. In that case, the code was stuck on an unfulfilled promise at every reparsing (because the promise fulfillment happened only after all required nodes were opened), which in practice had several implications: - selecting a node in the object tree didn't highlight the corresponding interval in the hex dump, - opening or closing nodes in the tree was abrupt (without a smooth transition as usual), - changes to the set of opened nodes weren't persisted to the local storage, - an open "Errors" pane didn't disappear, even if the error has been already fixed. So this change also fixes #61 - this is an issue which reported this exact problem, but was closed because nobody knew how to reproduce it. The remark in #61 (comment) by @DarkShadow44 confirms my suspicions that it is the same thing: > After I cleared the local storage data, I can't reproduce it > either. Basically the only way I know to resolve the promise was to open a few random nodes in the tree (or pick one and repeatedly close and open it again). The opening code would (mis)interpret these events as if the nodes it requested to open were finally opened, and then resolve the promise. But you had to do this after every reparsing, which was annoying. 2. Thanks to the default behavior of the jsTree's state plugin, the scroll position and the selected node are now persisted as well. Previously, only the set of opened nodes and the selection range in the hex viewer was preserved (the saved hex viewer selection sometimes resulted to selecting the right node and scrolling to it, but this indirect approach is not as good as actually saving the scroll offset and the selected node). Currently, the events that trigger the saving of the tree state are left at default `changed.jstree open_node.jstree close_node.jstree` (see https://www.jstree.com/api/#/?f=$.jstree.defaults.state.events), meaning that the state is only saved when opening, closing or selecting a node. This means that if you only scroll in the jsTree and don't interact with the tree after that, the new scroll position won't be persisted - but this is just a minor inconvenience. We can further improve this in the future. 3. A tree node is now selected as soon as it's focused. This in practice means that a node is selected upon "mousedown" (i.e. when the button is pressed, but not necessarily released yet), not only after a full cycle of pressing and releasing the mouse button. Likewise, when navigating in the tree using the keyboard (for example using the arrow keys), a new node is selected already on "keydown", not "keyup". 4. Both the first time after page load (after restoring the selected node from local storage) and after clicking on an interval in the hex dump, the jsTree's stored "active node" is updated to the selected node. This ensures that when the object tree pane regains focus (and no node has been moused over since the event that changed the selected node), jsTree will focus the selected node. A notable difference in state persistence is that the old version kept paths of all nodes ever opened in the local storage, whereas the jsTree's state plugin always rewrites the local storage with the *current* state. This means that if you have some nodes open and switch to a different spec, the information about the open nodes from the original spec is lost unless the open nodes' paths also exist in the new spec. In the previous version, all open nodes would survive switching between specs like that. This might not be ideal, but it can be fixed in the future simply by storing states for different specs under different keys (see https://www.jstree.com/api/#/?f=$.jstree.defaults.state.key).
- Loading branch information