alpinejs/alpine

File Manager with Context Menu

JesusChrist69 opened this issue · 1 comments

Discussed in #3832

I feel like I should create issue from discussion as I discovered there is some kind of error

Originally posted by JesusChrist69 October 28, 2023
Hi, I've came across alpinejs recently and fell in love with it. However, I am currently stuck on a little problem with displaying my contextmenu. To give you a little bit more idea what am I trying to achieve: I am trying to make file manager where you would be able to right click anywhere and be able to do some actions (for example upload new files, create new folder, etc., I am sure you get the idea). This part works perfectly fine.

Problem begins when I try to display different items in my contextmenu when user right clicks on some folder (menu displays perfectly fine with "Open Folder" option and disappears as it should when I right click anywhere else or when I left click on the same item), but once I left click anywhere else then only one item from contextmenu disappears (the "Open Folder" option disappears and everything else just flash and reappear). Its almost like if my variable "showContextMenu" switched back to "true" once I left click inside of the div that holds my x-data.

Does anyone have any idea how to fix that? I've tried to put x-on:click.away x-on:click x-on:contextmenu x-on:contextmenu.away on every single element and force showContextMenu to be false but nothing helped to resolve my issue. I've also tried to find some alpinejs examples but I was not successfull with that as everything that pops up when you search for contextmenu problem is just some simple contextmenu.

<div>
    <form wire:submit.prevent="saveFiles" class="hidden">
        <input wire:model="uploads" type="file" multiple id="fileUpload">
        <x-button type="submit" wire:loading.attr="disabled"></x-button>
    </form>

    <div x-data="{ showContextMenu: false, contextMenuX: '0', contextMenuY: '0', folderClicked: false }"
         class="flex items-start container mx-auto p-16 w-screen h-screen"
         x-on:contextmenu.away="showContextMenu = false; folderClicked = false"
         x-on:click.away="showContextMenu = false; folderClicked = false;"
         x-on:click.prevent="showContextMenu = false; folderClicked = false;"
         x-on:contextmenu="
         $event.preventDefault();
         showContextMenu = true;
         contextMenuX = $event.clientX + 'px';
         contextMenuY = $event.clientY + 'px';">

        <div x-on:contextmenu="$event.preventDefault(); folderClicked = true"
             x-on:click="folderClicked = false"
             x-on:click.away="folderClicked = false" x-on:contextmenu.away="folderClicked = false"
             class="flex flex-col me-8 items-center transition-all font-semibold outline-none focus:outline-none cursor-pointer">
            <i class="fa-solid fa-folder text-6xl text-center"></i>
            <span class="text-center text-sm break-all">Test Folder</span>
        </div>

        <div class="absolute">
            <div class="absolute mt-12 min-w-full w-48 z-30"
                 :style="'top: calc(' + contextMenuY + ' - 11rem); left: calc(' + contextMenuX + ' - 16rem)'"
                 x-show="showContextMenu">
                <span
                    class="absolute top-0 left-0 w-2 h-2 bg-white transform rotate-45 -mt-1 ml-3 border-gray-300 border-l border-t z-20"></span>
                <div
                    class="bg-white overflow-auto rounded-lg shadow-md w-full relative z-10 py-2 border border-gray-300 text-gray-800 text-xs">
                    <ul class="list-reset">
                        <li>
                            <a x-show="folderClicked" href=""
                               class="px-4 py-1 font-bold flex hover:bg-gray-100 no-underline hover:no-underline"
                               x-on:click.away="showContextMenu = false">
                                Open Folder
                            </a>
                            <a href=""
                               class="px-4 py-1 font-bold flex hover:bg-gray-100 no-underline hover:no-underline"
                               x-on:click.away="showContextMenu = false">
                                <i class="fa-solid fa-folder-plus mr-2"></i>
                                New Folder
                            </a>
                            <a href="" onclick="document.querySelector('#fileUpload').click()"
                               class="px-4 py-1 font-bold flex hover:bg-gray-100 no-underline hover:no-underline"
                               x-on:click.away="showContextMenu = false">
                                <i class="fa-solid fa-file-arrow-up mr-2"></i>
                                Upload Files
                            </a>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</div>

I hope that I just did not oversee some basic fact in docs and now look like a complete fool..

Thanks in advance for any ideas.

  • David
Originally posted by **JesusChrist69** October 28, 2023 [https://imgur.com/9lTuixy](Preview of what is happening) - quality dropped a lot (sorry about that) when I uploaded it on imgur but you can see at least a little bit of what is happening.
Originally posted by **JesusChrist69** October 28, 2023 I just noticed that I had hidden errors in console... and the clicking triggers error: `Uncaught (in promise) TypeError: u is not a function at alpinejs-3.13.1.js:5:7954` which refers to this: `queueMicrotask(()=>{ let s = br(e); s ? (s._x_hideChildren || (s._x_hideChildren = []), s._x_hideChildren.push(e)) : i(()=>{ let a = c=>{ let l = Promise.all([c._x_hidePromise, ...(c._x_hideChildren || []).map(a)]).then(([u])=>u()); return delete c._x_hidePromise, delete c._x_hideChildren, l } ; a(e).catch(c=>{ if (!c.isFromCancelledTransition) throw c } ) } ) } )` Error is exactly this line: `let l = Promise.all([c._x_hidePromise, ...(c._x_hideChildren || []).map(a)]).then(([u])=>u());`

So I guess that might be the issue as it refers to hiding children. I tried to import it via cdn (https://cdn.jsdelivr.net/npm/alpinejs@3.13.1/dist/cdn.min.js) and (//unpkg.com/alpinejs) but had same results on both of them, I checked issues for this and found that it might be due to missing defer on <script> tag but I do have defer on my <script>, downloading it locally did not help either. I also tried to use .outside instead of .away but had same results. Can it have something to do with livewire? I came across docs in alpine that stated there might be some problems with livewire but it was not related to clicking (I believe).

This issue has been closed as we are now using discussions to track bugs and ideas, and as there is already a discussion open we will continue investigating in that discussion.
See this announcement for more details #1423