Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototype for node selection & copying elis #233

Closed

Conversation

malte-laukoetter
Copy link
Member

@malte-laukoetter malte-laukoetter commented Apr 5, 2024

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 new content:click event on the RisPreview 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 after art_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 with eli: are moved to the end of the elements with the eli provided after eli:. 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 a computed defining both a get (load the data for the input from the xml) and a set (update the xml to include the change -> this then triggers a recomputation of the get).

Multi Select

Mutli select (with shift+click) is possible. When multiple akn:mods are selected their values are shown when they are the same otherwise mixed is used as a value. When editing them the data of all selected akn:mods is changed to the new value.

Overall

  1. No changes to the xslt
  2. The rendering is used to highlight stuff, provide a ui and to identify elements. Not as the source for the data.
  3. The actual changes to the data always happen directly on the XML
  4. The logic how to put the additional UI to the correct spot is completly encapsulated by RisPreview

Open Challenges

  • How to add the correct a11y roles to the rendering to mark e.g. all akn:mods as clickable. (as well as tabindex and keyboard events)
  • probably some more

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 with onClick:akn:. We should even be able to define the event on defineEmits using

[key: `click:akn:${string}`]

as the event name, but even with that vue still throws a warning about a non declared emit.

RISDEV-3681

@malte-laukoetter malte-laukoetter changed the title Prototype for node selection & copying elis [DO NOT MERGE] Prototype for node selection & copying elis Apr 5, 2024
@malte-laukoetter malte-laukoetter force-pushed the RISDEV-3714-prototype-for-node-selection branch 2 times, most recently from e2ec7b2 to 5d1a99f Compare April 5, 2024 11:38
malte-laukoetter and others added 4 commits April 8, 2024 18:09
Also support adding a selected class to elements with specified eids and
send click events when such elements are clicked.

RISDEV-0000
@andreasphil andreasphil force-pushed the RISDEV-3714-prototype-for-node-selection branch from 5d1a99f to a7c0abd Compare April 8, 2024 16:53
@andreasphil andreasphil added the do not merge For sharing prototypes or ideas that are not intended for merging label Apr 9, 2024
@andreasphil andreasphil changed the title [DO NOT MERGE] Prototype for node selection & copying elis Prototype for node selection & copying elis Apr 9, 2024
@malte-laukoetter
Copy link
Member Author

regarding the vue support for using teleport this way:

The teleport to target must be already in the DOM when the component is mounted. Ideally, this should be an element outside the entire Vue application. If targeting another element rendered by Vue, you need to make sure that element is mounted before the .

So it is indeed supported by vue just not the "ideal" use

@malte-laukoetter
Copy link
Member Author

Closed for now, we implemented parts already, the "Additional UI in the Preview" parts are still in discussion but we don't want to keep this pr open

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
do not merge For sharing prototypes or ideas that are not intended for merging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants