mProjectsCode / obsidian-meta-bind-plugin

A plugin for Obsidian to make your notes interactive with inline input fields, metadata displays, and buttons.
https://www.moritzjung.dev/obsidian-meta-bind-plugin-docs/
GNU General Public License v3.0
534 stars 42 forks source link

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

Open LynetteCullens opened 3 months ago

LynetteCullens commented 3 months ago

Please fill out these Check-boxes

Plugin Version

1.1.3

This Issue Occurs on

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 commented 3 months ago

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");
    };
})();
mProjectsCode commented 2 months ago

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

LynetteCullens commented 1 month ago

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?

mProjectsCode commented 1 month ago

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.

LynetteCullens commented 1 month ago

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");
    };
})();
bpannier commented 1 week ago

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

mProjectsCode commented 1 week ago

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 commented 1 week ago

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.

LynetteCullens commented 5 days ago

@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.