twibiral / obsidian-execute-code

Obsidian Plugin to execute code in a note.
MIT License
994 stars 61 forks source link

[BUG] Parsing issue with new lines in @html command [javascript interaction with created HTML elements] #351

Open sergeBoisse opened 2 months ago

sergeBoisse commented 2 months ago

Describe the bug

In javascript, using the magic command @html(...) you can create html elements on the fly that would appear just below the code text. this is great ! for instance I can create a button with the following js block :

@html('<button>Add to favorites</button>');

And that is fine : clicking the run button in display mode (I do not use preview mode) and a button is created below the code.

But when I tried to trigger events with that button, weird things happen, for instance with

function coucou() {console.log("hello");}
@html(`
<button onclick='coucou();'>Add to favorites</button>
`);

When I run this block, the plugin prints ");'>Add to favorites</button> and no button is created. Furthermore, with the following code:

texte = `<button onclick="coucou">Clique !</button>`;
function coucou() { 
    console.log("hello");
}
@html(texte);

This time, the button is created, but nothing happens when you click on it.

Software Version OS:, windows 10 Plugin Version: 1.11.1 , Obsidian Version: 1.5.12

To Reproduce Steps to reproduce the behavior:

Write a js block in edit mode that use the @html() magic command to create some interractive html element like <input> , and insert into it a reference to a fonction to call when input is triggered

Expected behavior I would expect that when you create an input-type html element using @html(...) that has a "onclick" or "oninput" feature, then you could interact with it and use the event into a user-defined javascript function

Additional context By the way it would be great if you could get a reference to the html element that was created, or simply to the window element, or any other way to attach an event callback, but this is another topic.

twibiral commented 1 month ago

Hi! I think the problem with the second block is some parsing issue. We only use a simple regex to find the magic commands like @html. The problem with the second code is, that you try to call a function that is only defined within the code block. We run the javascript code on a separate node.js instance and not as part of the obsidian application. That means you cannot access javascript or typescript code/classes/functions/variables that are part of the obsidian app. Reversely, obsidian cannot access code of our runtime. While you run your js code, it cannot access obsidian variables, but in the moment the @html command embeds something in the node, this becomes part of the obsidian environment and it cannot access your own code anymore.

You can only call the functions that are part of your html, like this:

texte = `<button onclick="console.log('hello')">Clique !</button>`;
@html(texte);

You need to embed all code you want to execute in the html string.

sergeBoisse commented 1 month ago

Hello Tim, Thank you for your reply. I understand your explanation.

There are things that are still "illogical", according to me:

You can create html elements, and even svg, that will be displayed right at the bottom of the code block. Great ! For instance the following code

console.log("hello"); 

will display "hello" just below the clode block.

But this code :

texte = `
<button onclick="console.log('Hello')">Clique !</button>
`;
@html(texte);

will display the button, but clicking on it will print "hello"... in the console, not in the code block.

You said that we need to embed all code we want to execute in the html string. OK, then I tried this :

texte = `
<script>
function coucou() {
    console.log("coucou");
}
</script>
<button onclick="coucou()">Clique !</button>
`;
@html(texte);

run, click on the button... Nothing happens but there is an error in the console: 'index.html:1 Uncaught ReferenceError: coucou is not defined'

So the script was not copied into the html code.

Furthermore, Not only obsidian, but also document and window are not accessible from within the js code.

So it seems impossible to build truly interactive javascript applications using your plugin, which I find a bit paradoxical.

I thought that, even though you can't access obsidian features, using the @html tag would somehow allow to display and run html code the same way you would do to when creating an html page "from scratch". This is not the case. Thank you again for your support and undesrtanding.