diff --git a/templates/contest/edit.html b/templates/contest/edit.html
index 469eef10e..5cfed9731 100644
--- a/templates/contest/edit.html
+++ b/templates/contest/edit.html
@@ -142,6 +142,7 @@
});
var oldSortIndex;
+ var dragCursorOffset;
$('#form_set').sortable({
handle: 'td.order-column',
placeholder: 'placeholder',
@@ -150,8 +151,35 @@
start: function(event, ui) {
ui.placeholder.empty();
oldSortIndex = ui.item.index();
+ // .table has backdrop-filter (table.scss), which makes the table a CSS
+ // containing block for fixed/absolute descendants in Chrome (but not
+ // consistently in Firefox/Safari), throwing off the dragged row's
+ // on-screen position. Suspend it for the drag and drive the helper with
+ // raw viewport coordinates so it never depends on any ancestor's offset.
+ $('#problem-table').css('backdrop-filter', 'none');
+ // Read the true on-screen rect BEFORE switching position, then set
+ // fixed + matching top/left atomically. Otherwise jQuery UI's old
+ // absolute-relative top/left gets reinterpreted under fixed semantics
+ // and the helper jumps far off its actual position.
+ var rect = ui.helper[0].getBoundingClientRect();
+ dragCursorOffset = {
+ top: event.clientY - rect.top,
+ left: event.clientX - rect.left,
+ };
+ ui.helper.css({
+ position: 'fixed',
+ top: rect.top,
+ left: rect.left,
+ });
+ },
+ sort: function(event, ui) {
+ ui.helper.css({
+ top: event.clientY - dragCursorOffset.top,
+ left: event.clientX - dragCursorOffset.left,
+ });
},
stop: function(event, ui) {
+ $('#problem-table').css('backdrop-filter', '');
_renumberOrders();
},
});
diff --git a/templates/problem/data.html b/templates/problem/data.html
index e1d683ed4..92456e0c3 100644
--- a/templates/problem/data.html
+++ b/templates/problem/data.html
@@ -534,14 +534,42 @@
};
var oldIndex;
+ var dragCursorOffset;
$table.find('tbody:first').sortable({
handle: 'i.fa-ellipsis-v',
placeholder: 'placeholder',
start: function (event, ui) {
ui.placeholder.empty();
oldIndex = ui.item.index();
+ // .table has backdrop-filter (table.scss), which makes the table a CSS
+ // containing block for fixed/absolute descendants in Chrome (but not
+ // consistently in Firefox/Safari), throwing off the dragged row's
+ // on-screen position. Suspend it for the drag and drive the helper with
+ // raw viewport coordinates so it never depends on any ancestor's offset.
+ $table.css('backdrop-filter', 'none');
+ // Read the true on-screen rect BEFORE switching position, then set
+ // fixed + matching top/left atomically. Otherwise jQuery UI's old
+ // absolute-relative top/left gets reinterpreted under fixed semantics
+ // and the helper jumps far off its actual position.
+ var rect = ui.helper[0].getBoundingClientRect();
+ dragCursorOffset = {
+ top: event.clientY - rect.top,
+ left: event.clientX - rect.left,
+ };
+ ui.helper.css({
+ position: 'fixed',
+ top: rect.top,
+ left: rect.left,
+ });
+ },
+ sort: function (event, ui) {
+ ui.helper.css({
+ top: event.clientY - dragCursorOffset.top,
+ left: event.clientX - dragCursorOffset.left,
+ });
},
stop: function (event, ui) {
+ $table.css('backdrop-filter', '');
var newIndex = ui.item.index();
reordering_row(oldIndex, newIndex, ui.item);
}