fix: menu contextuel en DOM natif (bypass Alpine)
Alpine ne détecte pas les changements sur ctxMenu (objet imbriqué hors du scope _wsInitData dans le DOM). Le :style et x-show restent bloqués sur les valeurs initiales. Solution radicale: manipulation DOM directe - onContextMenu: menu.style.display='block' + position left/top - ctxMenuOpen*/Rename/Duplicate/Delete: menu.style.display='none' - @click.outside/@keydown.escape: DOM direct aussi - ctx-menu HTML: style="display:none" initial
This commit is contained in:
@@ -744,43 +744,36 @@ window._wsInitData = (function() {
|
||||
|
||||
// ── Context menu ──
|
||||
onContextMenu(ev) {
|
||||
console.log('onContextMenu fired', ev.clientX, ev.clientY);
|
||||
var el = ev.target.closest('[data-ws-id]');
|
||||
if (!el) { this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}; return; }
|
||||
var menu = document.querySelector('.ctx-menu');
|
||||
if (!el || !menu) { if (menu) menu.style.display = 'none'; return; }
|
||||
var id = parseInt(el.getAttribute('data-ws-id'));
|
||||
if (!id) { this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}; return; }
|
||||
if (!id) { menu.style.display = 'none'; return; }
|
||||
var node = this._findNodeById(this.displayTree, id);
|
||||
if (!node) { this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}; return; }
|
||||
// Reassign whole object for Alpine reactivity
|
||||
this.ctxMenu = {
|
||||
visible: true,
|
||||
x: ev.clientX,
|
||||
y: ev.clientY,
|
||||
node: node,
|
||||
tags: [...(node.tags||[])]
|
||||
};
|
||||
if (!node) { menu.style.display = 'none'; return; }
|
||||
// Store in Alpine data for menu actions (ctxMenuOpenPage, etc.)
|
||||
this.ctxMenu = {visible:true, x:ev.clientX, y:ev.clientY, node:node, tags:[...(node.tags||[])]};
|
||||
this.ctxTagAdding = false;
|
||||
this.ctxTagExistingOpen = false;
|
||||
this.ctxNewTagColor = '#787774';
|
||||
// Load available tags
|
||||
this.ctxAvailTags = (this.workspaceTags || []).filter(function(t) {
|
||||
return !(node.tags||[]).some(function(nt) { return nt.id === t.id; });
|
||||
});
|
||||
// Reposition after DOM update
|
||||
var self = this;
|
||||
self.$nextTick(function() {
|
||||
var menu = self.$el.querySelector('.ctx-menu');
|
||||
if (!menu) return;
|
||||
var rect = menu.getBoundingClientRect();
|
||||
var x = self.ctxMenu.x;
|
||||
var y = self.ctxMenu.y;
|
||||
if (x + rect.width > window.innerWidth - 4) x = window.innerWidth - rect.width - 4;
|
||||
if (y + rect.height > window.innerHeight - 4) y = window.innerHeight - rect.height - 4;
|
||||
if (x < 4) x = 4;
|
||||
if (y < 4) y = 4;
|
||||
// Reassign for reactivity
|
||||
self.ctxMenu = {visible:true, x:x, y:y, node:self.ctxMenu.node, tags:self.ctxMenu.tags};
|
||||
});
|
||||
// DOM manipulation (bypasses Alpine reactivity issues)
|
||||
menu.style.display = 'block';
|
||||
menu.style.left = ev.clientX + 'px';
|
||||
menu.style.top = ev.clientY + 'px';
|
||||
// Reposition if offscreen
|
||||
var rect = menu.getBoundingClientRect();
|
||||
var x = ev.clientX, y = ev.clientY;
|
||||
if (x + rect.width > window.innerWidth - 4) x = window.innerWidth - rect.width - 4;
|
||||
if (y + rect.height > window.innerHeight - 4) y = window.innerHeight - rect.height - 4;
|
||||
if (x < 4) x = 4;
|
||||
if (y < 4) y = 4;
|
||||
menu.style.left = x + 'px';
|
||||
menu.style.top = y + 'px';
|
||||
this.ctxMenu.x = x;
|
||||
this.ctxMenu.y = y;
|
||||
},
|
||||
|
||||
// ── Long-press (mobile context menu) ──
|
||||
@@ -829,24 +822,24 @@ window._wsInitData = (function() {
|
||||
|
||||
ctxMenuOpenPage() {
|
||||
if (this.ctxMenu.node) this.openPage(this.ctxMenu.node.id);
|
||||
this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]};
|
||||
document.querySelector('.ctx-menu').style.display = 'none';
|
||||
},
|
||||
|
||||
ctxMenuOpenFolder() {
|
||||
if (this.ctxMenu.node) this.navigateToFolder(this.ctxMenu.node.id);
|
||||
this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]};
|
||||
document.querySelector('.ctx-menu').style.display = 'none';
|
||||
},
|
||||
|
||||
ctxMenuRename() {
|
||||
if (this.ctxMenu.node) { this.startRename(this.ctxMenu.node); this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}; }
|
||||
if (this.ctxMenu.node) { this.startRename(this.ctxMenu.node); document.querySelector('.ctx-menu').style.display = 'none'; }
|
||||
},
|
||||
|
||||
ctxMenuDuplicate() {
|
||||
if (this.ctxMenu.node) { this.duplicateItem(this.ctxMenu.node); this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}; }
|
||||
if (this.ctxMenu.node) { this.duplicateItem(this.ctxMenu.node); document.querySelector('.ctx-menu').style.display = 'none'; }
|
||||
},
|
||||
|
||||
ctxMenuDelete() {
|
||||
if (this.ctxMenu.node) { this.deleteWithUndo(this.ctxMenu.node); this.ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}; }
|
||||
if (this.ctxMenu.node) { this.deleteWithUndo(this.ctxMenu.node); document.querySelector('.ctx-menu').style.display = 'none'; }
|
||||
},
|
||||
|
||||
ctxRemoveTag(tagId) {
|
||||
@@ -1928,7 +1921,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<script>console.log('FLOWDECK v2.4.6 — ws-split about to render, _wsInitData exists:', typeof window._wsInitData !== 'undefined');</script>
|
||||
|
||||
<div class="ws-split"
|
||||
@contextmenu.prevent="_wsInitData.onContextMenu($event); ctxMenu = _wsInitData.ctxMenu"
|
||||
@contextmenu.prevent="_wsInitData.onContextMenu($event)"
|
||||
@click.self="ctxMenu.visible = false"
|
||||
@touchstart="onTouchStart($event)"
|
||||
@touchend="onTouchEnd($event)"
|
||||
@@ -2357,10 +2350,9 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
</div><!-- /ws-main -->
|
||||
|
||||
<!-- Context menu -->
|
||||
<div class="ctx-menu"
|
||||
:style="{ left: ctxMenu.x + 'px', top: ctxMenu.y + 'px', display: ctxMenu.visible ? 'block' : 'none' }"
|
||||
@click.outside="ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}"
|
||||
@keydown.escape="ctxMenu = {visible:false,x:0,y:0,node:null,tags:[]}"
|
||||
<div class="ctx-menu" style="display:none"
|
||||
@click.outside="document.querySelector('.ctx-menu').style.display='none'"
|
||||
@keydown.escape="document.querySelector('.ctx-menu').style.display='none'"
|
||||
x-transition>
|
||||
<div class="ctx-item" @click="ctxMenuOpenPage()">📄 Open</div>
|
||||
<div class="ctx-item" x-show="ctxMenu.node && ctxMenu.node.is_folder" @click="ctxMenuOpenFolder()">📂 Open folder</div>
|
||||
|
||||
Reference in New Issue
Block a user