Prototype for node selection & copying elis #233
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
DO NOT MERGE - This is just a prototype and has neither tests nor documentation and includes changes that are just there to demonstrate the abilities of it. If we want to use (some of) this approach we should copy the needed parts to a new PR and add tests, docs, ...
Ideas tested in this prototype
Clicking on Nodes
For node selections a click handler on the preview-div is used that reacts to all clicks inside the preview. The clicked element is then identified based on its
data-eId
attribute. This creates a newcontent:click
event on theRisPreview
component that can then be used by the view to handle what exactly should happen.To handle clicks on specific elements (e.g. only articles) and identify these correctly for e.g. the selected nodes the handler of
content:click
might need to shorten the eli to the length needed (e.g. removing everything afterart_x
to identify articles)Highlighting selected Nodes
The currently selected elements are identified by their eid. These are handled by the parent component and provided to
RisPreview
via a prop. These elements then get the additional class.selected
applied to them. This class is used to change the styles applied to the selected elements.Additional UI in the Preview
Named slots of
RisPreview
that start witheli:
are moved to the end of the elements with the eli provided aftereli:
. This is done by using<Teleport>
.It is not possible to move something in front of an existing element of the rendering in the HTML (visually it can be moved there using CSS).
Loading Data for Inputs
For the inputs the data is loaded directly from the xml. For this the xml string is parsed to a Document. And then xPath expressions are used to find the data in the xml using the eli of e.g. the
akn:mod
.Saving Data from the Inputs
Saving is handled in almost the same way as loading: By identifying the node of the xml that needs to be changed using a xPath and then updating that nodes value. The xml then needs to be converted back to a string and is stored in
currentArticleXml
. -> The xml-editor is the source of truth and the inputs just modify its content in a convenient way.The inputs are synced by using
v-model
with acomputed
defining both aget
(load the data for the input from the xml) and aset
(update the xml to include the change -> this then triggers a recomputation of theget
).Multi Select
Mutli select (with shift+click) is possible. When multiple
akn:mod
s are selected their values are shown when they are the same otherwisemixed
is used as a value. When editing them the data of all selectedakn:mod
s is changed to the new value.Overall
Open Challenges
akn:mod
s as clickable. (as well as tabindex and keyboard events)My feelings / thoughts
Clicking on Nodes
works but with the a11y challenges I'm quite unsure if this is the best way to handle it or if registering event handlers on the individual elements at the same time as e.g. a tabindex would be simpler / less likely to lead to forgetting something. It could also remove the need to shorten the elis to the expected parts
Highlighting selected Nodes
Seems to work quite well, even though it is a bit annoying that the classes need to be readded with every change of the html (but I don't see a way around it).
Styling the nodes once this class was added was quite straight forward.
Additional UI in the Preview
Quite nice to use from the outside. Has some limits in regards to what can be achieved and is not 100% the way vue recommends using
<Teleport />
Loading & Saving Data (Inputs)
I really like that this handles the data in its source format and no big parsing/mapping step is necessary.
The methods for using xPaths in JS are quite old and not that nice to use but wrapping them in our own functions should alleviate most of the pain from that. And while using
document.querySelector
would imo sometimes lead to nicer queries using xPath would allow us to use the same query language for both the backend and the frontend. Also xPath supports querying attributes so no extra step is needed for that.The usage of the computed with setters together with v-model was surprisingly simple. I also like that it places the loading and modifying logic close together. I am almost wondering why vue isn't recommending that for most usages of v-model with more complex data structures in the background.
Conclusion
I really like the teleport+slot solution, using xml as directly as possible as well as the computed-vModel suff. I'm still a bit unsure of the usage of xPath over something like
querySelector
but with a tendency towards xPath.I'm not at all sure if this one global click handler is a good way and would really like to try out / see some other ideas for this
Further idea
Maybe a similar approach to the slots could be used for more specific event handlers, but I haven't tested how well vue works with dynamic event listener names:
Sketch: listener created like
<RisPreview @click:akn:mod="handler" />
and then the RisPreview component somehow automatically adds event listeners (tabindexes, etc...) to the elements of that type.Edit: quick test of the idea
this should be doable with the help of
useAttrs
and then filtering the keys of that object for starting withonClick:akn:
. We should even be able to define the event ondefineEmits
usingas the event name, but even with that vue still throws a warning about a non declared emit.
RISDEV-3681