obsidian-meta-bind-plugin icon indicating copy to clipboard operation
obsidian-meta-bind-plugin copied to clipboard

Unable to click on meta-bind fields when inside a callout

Open LynetteCullens opened this issue 1 year ago • 16 comments

Please fill out these Check-boxes

  • [X] I checked for existing similar issues
  • [X] I checked that the plugin is up to date
  • [X] The issue persist with all other plugins and themes disabled

Plugin Version

1.1.3

This Issue Occurs on

  • [X] Windows
  • [ ] Linux
  • [ ] macOS
  • [ ] Android
  • [ ] iOS

Debug Info

SYSTEM INFO:
	Obsidian version: v1.6.7
	Installer version: v1.5.3
	Operating system: Windows 10 Home 10.0.19045
	Login status: logged in
	Catalyst license: none
	Insider build toggle: off
	Live preview: on
	Base theme: adapt to system
	Community theme: none
	Snippets enabled: 0
	Restricted mode: off
	Plugins installed: 1
	Plugins enabled: 1
		1: Meta Bind v1.1.3

RECOMMENDATIONS:
	Community plugins: for bugs, please first try updating all your plugins to latest. If still not fixed, please try to make the issue happen in the Sandbox Vault or disable community plugins.

Describe the Issue

Can't interact with input fields when they're placed inside of callouts in Live Preview mode.

Steps to Reproduce

  1. Place an input field inside of a callout.
  2. Try to interact with said field while in Live Preview Mode.

Expected Behavior

I used to be able to interact with the field in Live Preview Mode. So, I expected the field to be interactable without having to switch to Reading View.

Reference: #291

LynetteCullens avatar Aug 19 '24 20:08 LynetteCullens

https://github.com/mProjectsCode/obsidian-meta-bind-plugin/issues/291#issuecomment-2251944924

Work Around Script that is Referenced in the above comment for anyone who is interested. Should Be Set to Run on Note Open Modified 8/22/24 To ONLY Work in Callout Elements

(() => {
    console.log("Meta Bind Input in Live Preview script for callouts is running");

    function setupListeners() {
        function handleClick(e) {
            if (e.target instanceof HTMLElement) {
                let parent = e.target;
                // Check if the clicked element is inside a callout
                const callout = parent.closest('[data-callout]');
                
                if (!callout) {
                    return; // Exit if not in a callout
                }

                while (parent !== null) {
                    if (parent.classList.contains('mb-input') || parent.classList.contains('editor-input')) {
                        e.stopPropagation();
                        e.preventDefault();
                        
                        const editorInput = parent.closest('.editor-input');
                        if (editorInput) {
                            const textarea = editorInput.querySelector('textarea');
                            const displayDiv = editorInput.querySelector('div.svelte-1tfnqy0');
                            
                            if (textarea && displayDiv) {
                                // Get the original Markdown content from the textarea
                                const originalContent = textarea.value;
                                
                                // Hide the display div and show the textarea
                                displayDiv.style.display = 'none';
                                textarea.style.display = 'block';
                                textarea.value = originalContent;
                                textarea.focus();

                                // Set up events to handle the editing
                                textarea.onblur = () => {
                                    textarea.style.display = 'none';
                                    displayDiv.style.display = 'block';
                                };
                            }
                        }
                        break;
                    }
                    parent = parent.parentElement;
                }
            }
        }

        function handleKeydown(e) {
            if (e.target instanceof HTMLElement && e.target.tagName === 'TEXTAREA') {
                // Check if the textarea is inside a callout
                const callout = e.target.closest('[data-callout]');
                
                if (!callout) {
                    return; // Exit if not in a callout
                }

                let parent = e.target;
                while (parent !== null) {
                    if (parent.classList.contains('mb-input') || parent.classList.contains('editor-input')) {
                        e.stopPropagation();
                        break;
                    }
                    parent = parent.parentElement;
                }
            }
        }

        document.addEventListener('click', handleClick, true);
        document.addEventListener('keydown', handleKeydown, true);

        console.log("Event listeners for callouts attached");
    }

    // Delay setup slightly to ensure DOM is ready
    setTimeout(setupListeners, 2000);

    // Return a cleanup function
    return () => {
        document.removeEventListener('click', handleClick, true);
        document.removeEventListener('keydown', handleKeydown, true);
        console.log("Event listeners for callouts removed");
    };
})();

LynetteCullens avatar Aug 19 '24 22:08 LynetteCullens

I had a fix for this a while back, but that broke interaction with some input fields on android in LP.

mProjectsCode avatar Sep 14 '24 10:09 mProjectsCode

I had a fix for this a while back, but that broke interaction with some input fields on android in LP.

I would like for them to be segregated, and have their own fork. Just android, not ios?

LynetteCullens avatar Oct 04 '24 19:10 LynetteCullens

No, I am absolutely not interested in maintaining a fork for mobile. The major reasons are:

  1. Extra time investment
  2. There is no way to distribute a plugin as mobile-only

However since this plugin is open source under the GPL-3.0 license, you are free to fork it and do whatever you want.

Regarding the other issue, I only got reports for Android and none for iOS.

mProjectsCode avatar Oct 04 '24 19:10 mProjectsCode

Updated Script that will work with 1.2.1

(() => {
    console.log("Meta Bind Input in Live Preview script for callouts is running");

    function setupListeners() {
        function handleClick(e) {
            if (e.target instanceof HTMLElement) {
                let parent = e.target;
                // Check if the clicked element is inside a callout
                const callout = parent.closest('[data-callout]');

                if (!callout) {
                    return; // Exit if not in a callout
                }

                while (parent !== null) {
                    if (parent.classList.contains('mb-input') || parent.classList.contains('editor-input')) {
                        e.preventDefault(); // Avoid triggering unwanted events
                        
                        // Manually trigger focusIn() on the editor input field if it's clicked
                        const editorComponent = parent.closest('.mb-editor-input');
                        
                        if (editorComponent) {
                            // Access the Svelte component and trigger focusIn
                            const focusInFn = editorComponent.__svelte__?.focusIn;
                            if (focusInFn) {
                                focusInFn();
                            }
                        }
                        break;
                    }
                    parent = parent.parentElement;
                }
            }
        }

        function handleKeydown(e) {
            if (e.target instanceof HTMLElement && e.target.tagName === 'TEXTAREA') {
                // Check if the textarea is inside a callout
                const callout = e.target.closest('[data-callout]');

                if (!callout) {
                    return; // Exit if not in a callout
                }

                let parent = e.target;
                while (parent !== null) {
                    if (parent.classList.contains('mb-input') || parent.classList.contains('editor-input')) {
                        e.stopPropagation();
                        break;
                    }
                    parent = parent.parentElement;
                }
            }
        }

        document.addEventListener('click', handleClick, true);
        document.addEventListener('keydown', handleKeydown, true);

        console.log("Event listeners for callouts attached");
    }

    // Delay setup slightly to ensure DOM is ready
    setTimeout(setupListeners, 2000);

    // Return a cleanup function
    return () => {
        document.removeEventListener('click', handleClick, true);
        document.removeEventListener('keydown', handleKeydown, true);
        console.log("Event listeners for callouts removed");
    };
})();

LynetteCullens avatar Oct 06 '24 19:10 LynetteCullens

@LynetteCullens thanks for providing a fix, I am struggling to understand how to use your script. Is this a patch for the plugin??

bpannier avatar Nov 10 '24 11:11 bpannier

I tested around a bit more. preventDefault on the click event will prevent the callout from going into "edit" mode, but it also breaks some input fields like the date and time inputs.

mProjectsCode avatar Nov 10 '24 12:11 mProjectsCode

I don't know how to prevent the callout from going into edit mode without breaking some input fields. I am open to suggestions and PRs if someone has an idea.

mProjectsCode avatar Nov 10 '24 12:11 mProjectsCode

@LynetteCullens thanks for providing a fix, I am struggling to understand how to use your script. Is this a patch for the plugin??

No, it is just a javascript code that runs every time I open a new note using RunJs plugin. I haven't tested it since 1.2.1 though. I've been working in iOS Obsidian since 1.2.1 so that I will be less inclined to pitchfork them.

LynetteCullens avatar Nov 17 '24 21:11 LynetteCullens

I am not in a great place to test things out myself right now but you can try event.stopPropagation(). It stops the event from propogating upwards (bubbling up) to the elements higher in the tree that can handle the same event. This might prevent the callout from taking the input while not breaking other behaviours that event.preventDefault() would break.

xhudaman avatar Mar 08 '25 03:03 xhudaman

That, sadly, does not work. It was one of the first things I tried, but event.preventDefault() is needed to stop the callout from unfolding. event.stopPropagation() and event.stopImmediatePropagation() are not enough.

mProjectsCode avatar Mar 08 '25 10:03 mProjectsCode

Fair enough, I'll try to dig into it once I'm done with my move.

xhudaman avatar Mar 08 '25 20:03 xhudaman

I am finding this behavior with input controls inside of tables as well.

sslatz11 avatar Mar 13 '25 16:03 sslatz11

I'd really like to see this fixed for tables as well. Should that be a separate issue?

adsilcott avatar Mar 24 '25 15:03 adsilcott

No. It's the same underlying issue.

mProjectsCode avatar Mar 24 '25 15:03 mProjectsCode

Running into the same problem. A fix would be quite nice!

ghdoca avatar Apr 04 '25 19:04 ghdoca

My "solution" is to stuff it inside of an embed, this way it works fine (PC, Windows). But I have done no real testing.

Mistmage avatar Jul 18 '25 22:07 Mistmage

My "solution" is to stuff it inside of an embed, this way it works fine (PC, Windows). But I have done no real testing.

I've tried doing that in version 1.1.3, and it did not work for me. I will try again using the newer update.

LynetteCullens avatar Jul 19 '25 06:07 LynetteCullens

My "solution" is to stuff it inside of an embed, this way it works fine (PC, Windows). But I have done no real testing.

I've tried doing that in version 1.1.3, and it did not work for me. I will try again using the newer update.

You are using Meta-bind-embed, right?

Mistmage avatar Jul 19 '25 15:07 Mistmage

My "solution" is to stuff it inside of an embed, this way it works fine (PC, Windows).

Doesn't fix it for me.

I tested this on obsidian 1.8.10, (also Windows PC), still behaves the same. Trying to click an interactive element opens the callouts edit mode instead of interacting with it.

Cube707 avatar Jul 20 '25 12:07 Cube707

My "solution" is to stuff it inside of an embed, this way it works fine (PC, Windows).

Doesn't fix it for me.

I tested this on obsidian 1.8.10, (also Windows PC), still behaves the same. Trying to click an interactive element opens the callouts edit mode instead of interacting with it.

mmm, you need to embed full callout, rather then embed the meta-bind. i am using 1.4.2 meta-bind, windows and 1.8.10.

You creates a meta-bind inside a callout, then embed it in another note using special meta-bind-embed. Unless there multiple similar problems it worked for me.

Mistmage avatar Jul 20 '25 12:07 Mistmage

you need to embed full callout, rather then embed the meta-bind.

That does indeed work. Interesting.

But it also mostly defeats the purpose as I specifically want (potentially multiple levels of) callouts to groups stuff...

Cube707 avatar Jul 20 '25 13:07 Cube707

you need to embed full callout, rather then embed the meta-bind.

That does indeed work. Interesting.

But it also mostly defeats the purpose as I specifically want (potentially multiple levels of) callouts to groups stuff...

You can have any number of callouts, in any configuration of levels inside another note. It just that they all have to be there.

I personally using it with TabSidian and that is a lot of callouts.

So unless you want to frequently change the content outside of the meta-bind inputs, there doesn't seem to be a limit.

And even then, if you need a changeable text field you technically can use editor INPUT for that.

(Also as meta-bind-embed works, you can embed same data structure into any number of notes and populate using properties)

I suspect the reason it dose work, is because meta-bind-embed dose not have any reaction on left click as it is a code block.

Mistmage avatar Jul 21 '25 16:07 Mistmage

I suspect the reason it dose work, is because meta-bind-embed dose not have any reaction on left click as it is a code block

see https://github.com/mProjectsCode/obsidian-meta-bind-plugin/issues/403#issuecomment-2466710482

The problem is that plugins cannot properly stop the event propagation and obsidian will always get the event, even if a meta-bind component is the closes object and declares its handling it. So the "unfolding" of the callout always triggers

Cube707 avatar Jul 21 '25 17:07 Cube707

My "solution" is to stuff it inside of an embed, this way it works fine (PC, Windows).

Doesn't fix it for me. I tested this on obsidian 1.8.10, (also Windows PC), still behaves the same. Trying to click an interactive element opens the callouts edit mode instead of interacting with it.

mmm, you need to embed full callout, rather then embed the meta-bind. i am using 1.4.2 meta-bind, windows and 1.8.10.

You creates a meta-bind inside a callout, then embed it in another note using special meta-bind-embed. Unless there multiple similar problems it worked for me.

My issue is that I can't get a specific callout to embed. I can only get the entire page. Are you working with page embeds instead of callout embeds? Do you have one callout per page? I also could not get more than one callout to display when embedding an entire page. It just duplicates the first callout for every callout.

LynetteCullens avatar Jul 21 '25 20:07 LynetteCullens

My "solution" is to stuff it inside of an embed, this way it works fine (PC, Windows).

Doesn't fix it for me. I tested this on obsidian 1.8.10, (also Windows PC), still behaves the same. Trying to click an interactive element opens the callouts edit mode instead of interacting with it.

mmm, you need to embed full callout, rather then embed the meta-bind. i am using 1.4.2 meta-bind, windows and 1.8.10. You creates a meta-bind inside a callout, then embed it in another note using special meta-bind-embed. Unless there multiple similar problems it worked for me.

My issue is that I can't get a specific callout to embed. I can only get the entire page. Are you working with page embeds instead of callout embeds? Do you have one callout per page? I also could not get more than one callout to display when embedding an entire page. It just duplicates the first callout for every callout.

It is correct that meta-bind-embed only supports page embeds, there is an open feature request to change that. Still, page embeds do work correctly, so I honestly have no idea, why it repeats the same callout for you.

I do indeed use "one callout per page", relatively speaking.

If you want some help, feel free to contact me on discord I am - mistmage

Mistmage avatar Jul 23 '25 00:07 Mistmage

Found a fix. We can simply add an interactive-child class to the input field, and Obsidian's click handler will ignore clicks within the element with the class. Not sure if this is new in Obsidian 1.9.0 with bases or has existed in earlier versions.

I will implement the fix properly and make a new release within the next few days.

mProjectsCode avatar Aug 18 '25 22:08 mProjectsCode

Found a fix. We can simply add an interactive-child class to the input field, and Obsidian's click handler will ignore clicks within the element with the class. Not sure if this is new in Obsidian 1.9.0 with bases or has existed in earlier versions.

I will implement the fix properly and make a new release within the next few days.

Yayyyy!!!! I will be celebrating. Whew.....My dopamine levels have increased....WOW

LynetteCullens avatar Aug 21 '25 19:08 LynetteCullens

I just realized that the fix isn't release jet, but most of the inline elements are actually already working fine for me in Obsidian v1.9.12:

Image
> [!note] working inputs:
> number: `INPUT[number:exampleNumProperty]`
> text: `INPUT[text:exampleTextProperty]`
> inlineSelect: `INPUT[inlineSelect(option(apple), option(banana), option(lemon)):exampleOptionProperty]`
> slider: `INPUT[slider(addLabels):exampleSliderProperty]`
> inlineList: `INPUT[inlineList:exampleListProperty]`
> toggle: `INPUT[toggle:exampleBoolProperty]`

What still isn't working are buttons and inputs like date-picker which open a modal (probably also buttons...)

Cube707 avatar Sep 04 '25 15:09 Cube707