/* * TweakDrag -- auto-scroll the board while dragging a card near a screen edge. * * Kanboard drags cards with jQuery UI sortable. The board does not scroll during a drag * (jQuery UI's autoscroll is unreliable horizontally, and on touch the bundled Touch Punch * shim suppresses native scrolling while a card is held), so you can only drop onto columns * already on screen. This scrolls #board-container while a card drag is active and the * pointer nears the left/right edge, with a smooth continuous speed that grows toward the * edge -- so you can drag a card to the edge and roll the board to a far column. * * It only acts during an active card drag near an edge, so it is harmless when idle. Works * on desktop (mouse) and mobile (touch, via Touch Punch). No core changes. */ (function () { "use strict"; var EDGE_ZONE = 50; // px from the board edge where auto-scroll begins var MAX_SPEED = 22; // px per animation frame at the very edge var EASE = 1; // 1 = linear ramp, 2 = gentle-then-fast var jq = window.jQuery; if (!jq) { return; } var container = null; var dragging = false; var rafId = 0; var lastX = 0; var lastY = 0; function onMove(e) { if (e.touches && e.touches.length) { lastX = e.touches[0].clientX; lastY = e.touches[0].clientY; } else { lastX = e.clientX; lastY = e.clientY; } } // Distance is px from the edge; returns 0 at the zone border up to MAX_SPEED at the edge. function speedFor(distance) { var p = (EDGE_ZONE - distance) / EDGE_ZONE; if (p <= 0) { return 0; } if (p > 1) { p = 1; } if (EASE !== 1) { p = Math.pow(p, EASE); } return MAX_SPEED * p; } function step() { if (!dragging || !container) { return; } var rect = container.getBoundingClientRect(); var dLeft = lastX - rect.left; var dRight = rect.right - lastX; var speed = 0; if (dLeft < EDGE_ZONE) { speed = -speedFor(dLeft); } else if (dRight < EDGE_ZONE) { speed = speedFor(dRight); } if (speed !== 0) { var before = container.scrollLeft; container.scrollLeft = before + speed; // Only when the board actually moved: nudge jQuery UI to recompute drop // positions so the placeholder follows onto the newly revealed column. if (container.scrollLeft !== before) { document.dispatchEvent(new MouseEvent("mousemove", { clientX: lastX, clientY: lastY, bubbles: true })); } } rafId = window.requestAnimationFrame(step); } function startLoop() { container = document.getElementById("board-container"); if (!container) { return; } dragging = true; if (!rafId) { rafId = window.requestAnimationFrame(step); } } function stopLoop() { dragging = false; if (rafId) { window.cancelAnimationFrame(rafId); rafId = 0; } } // Track the pointer at all times (cheap; only used while dragging). document.addEventListener("mousemove", onMove, true); document.addEventListener("touchmove", onMove, true); document.addEventListener("pointermove", onMove, true); // A card drag started / stopped. jQuery UI sortable fires these (on touch too, via // Touch Punch); delegated on the document so board redraws need no rebinding. jq(document).on("sortstart", startLoop); jq(document).on("sortstop", stopLoop); })();