mProjectsCode / obsidian-js-engine-plugin

https://www.moritzjung.dev/obsidian-js-engine-plugin-docs/
GNU General Public License v3.0
85 stars 5 forks source link

Event handlers placed through plugin don't work in live preview mode #14

Closed martyn0ff closed 2 months ago

martyn0ff commented 6 months ago

In live preview mode, all event handlers that were put on elements by means of JS Engine don't work. The reason for this is that for some reason Obsidian duplicates elements - one is created for editor mode, and another for preview mode.

Steps to reproduce

  1. Create brand new vault
  2. Install JS Engine plugin
  3. Create a note with following content (replace escaped backticks`):
    
    <div class="container" style="width:200px; height:200px; background-color: lightgrey">
    Hover over me!
    </div>

```js-engine const ctr = document.getElementsByClassName("container")[0]; ctr.onmouseover = () => alert("boo"); ```

4. Try hover over your mouse over the grey square in edit mode and observe successful JS execution.
5. Enter preview mode.
6. Try hover over your mouse over the grey square in live preview mode and observe no popup window.

(Go to developer console in Obsidian and try looking for this div on `app.workspace.activeLeaf.containerEl`, and you will see that there are two of them after changing view mode once)

**Solution**
The solution is to replace the second element with the first by means of js. Something among the lines of
```javascript
const containers = document.getElementByClassName("container")
if (containers.length == 2) {
  const containerParent = container[1].parentElement;
  containerParent.replaceChild(containers[0],containers1]);
}
mProjectsCode commented 6 months ago

How about adding the event listeners to all results of the query selector and not just the first one in your first example?

martyn0ff commented 6 months ago

Oh, you're totally right! I don't work with JS much and I forgot that onXXX properties only ever hold single event handler. However things would be different when we're dealing with addEventListener - it would add the same event handler to the element in either of the modes once we switch to different mode (because JS Engine fires up once per mode) which would not be desirable.

I thought that there is a way for your plugin to detect adding event listeners to elements and ensuring that both modes will receive those handlers, but now that I think of it, is it even possible at all? Maybe it's at least worthwhile to warn about this event handling gotcha in JS Engine docs. Took me some time to figure out why my event handlers did not fire. :-)