From 2b6880e12e2ecd901f3bf14edf85292ee6e2f5f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 21 Oct 2025 17:31:22 +0200 Subject: [PATCH] Use mouse events instead of drag/drop events to resize column On drag/drop events some browsers automatically scroll the container to make the dragged element visible. Closes #14306 --- sao/src/view/tree.js | 103 ++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 70 deletions(-) diff --git a/sao/src/view/tree.js b/sao/src/view/tree.js index d55b64dc4f..d8494a40df 100644 --- a/sao/src/view/tree.js +++ b/sao/src/view/tree.js @@ -15,36 +15,6 @@ }); } - // circumvent https://bugzilla.mozilla.org/show_bug.cgi?id=505521 - // Use page position to not depend on the monitor. - let dragoverFixAdded = false; - let lastWindowDragEvent = null; - const fillEventPagePosition = (e) => { - e.pagePosition = { - x: e.pageX, - y: e.pageY, - }; - - if (!navigator.userAgent.search("Firefox")) { - return; - } - - if (!dragoverFixAdded) { - window.addEventListener('dragover', (e) => { - lastWindowDragEvent = e; - }); - dragoverFixAdded = true; - } - - if (lastWindowDragEvent && - (e.timeStamp - lastWindowDragEvent.timeStamp) < 100) { - e.pagePosition = { - x: lastWindowDragEvent.pageX, - y: lastWindowDragEvent.pageY, - }; - } - } - Sao.View.TreeXMLViewParser = Sao.class_(Sao.View.XMLViewParser, { _parse_tree: function(node, attributes) { for (const child of node.childNodes) { @@ -157,9 +127,6 @@ this.treeview = jQuery('
', { 'class': 'treeview responsive' }).appendTo(this.el); - this.dragged_image= jQuery('', { - 'class': 'tree-dragged-image', - }).html(' ').appendTo(this.el); // Synchronize both scrollbars this.treeview.scroll(() => { @@ -265,7 +232,13 @@ }); label.append(arrow); column.arrow = arrow; - th.click(column, this.sort_model.bind(this)); + th.click(column, (e) => { + if (is_resizing) { + e.stopImmediatePropagation(); + return; + } + this.sort_model(e); + }); label.addClass('sortable'); } tr.append(th.append(label)); @@ -273,7 +246,9 @@ 'class': 'resizer', 'draggable': true, }).appendTo(th); - resizer.on('dragstart', (event) => { + let is_resizing = false; + resizer.on('mousedown', (event) => { + is_resizing = true; let th = event.target.parentNode; let headers = th.parentNode.childNodes; let cols = this.colgroup[0].childNodes; @@ -287,32 +262,31 @@ col.style.width = `${header.offsetWidth}px`; } } - th.dataset.startPosition = event.pageX; - th.dataset.originalWidth = th.offsetWidth; + + let startX = event.pageX; + let originalWidth = th.offsetWidth; + + function on_mouse_move(e) { + let col = cols[th.dataset.column]; + let width_offset = e.pageX - startX; + if (Sao.i18n.rtl) { + width_offset *= -1; + } + let width = Number(originalWidth) + width_offset; + col.style.width = `${width}px`; + } + + function on_mouse_up() { + document.removeEventListener('mousemove', on_mouse_move); + document.removeEventListener('mouseup', on_mouse_up); + setTimeout(() => is_resizing = false, 0); + } + + document.addEventListener('mousemove', on_mouse_move); + document.addEventListener('mouseup', on_mouse_up); this.table.addClass('table-bordered'); - event.originalEvent.dataTransfer.setDragImage( - this.dragged_image.get(0), 0, 0); - }); - // column_widths is used as a global for the callback of the - // drag event so that when the setTimeout callback is triggered - // the latest value of the width is used - let column_widths = {}; - resizer.on('drag', (event) => { - fillEventPagePosition(event); - let resized_th = event.target.parentNode; - let col = this.colgroup[0].childNodes[resized_th.dataset.column]; - let width_offset = (event.pagePosition.x - - resized_th.dataset.startPosition); - if (Sao.i18n.rtl) { - width_offset *= -1; - } - let width = Number(resized_th.dataset.originalWidth) + width_offset; - column_widths[resized_th] = width; - setTimeout(() => { - let width = column_widths[resized_th]; - col.style.width = `${width}px`; - }); + event.preventDefault(); }); column.header = th; @@ -335,17 +309,6 @@ idx += 1; } - this.table.on('dragover', (event) => { - // This is necessary so that the 'drop' event is processed - event.preventDefault(); - }); - this.table.on('drop', (event) => { - event.preventDefault(); - if (!this.editable) { - this.table.removeClass('table-bordered'); - } - }); - this.tbody = jQuery(''); this.table.append(this.tbody);