From 310c34620f57fdfc70acbf9eb6ca998b789c7d90 Mon Sep 17 00:00:00 2001
From: Ruben Carlo Benante
Date: Mon, 6 Jul 2026 22:27:33 -0300
Subject: [PATCH] OrganonTweaks: swallow post-drag click so a held press
(>100ms) never opens the card; v1.2
---
Asset/js/click-guard.js | 35 +++++++++++++++++++++++++++++++++
Controller/ConfigController.php | 3 +++
Plugin.php | 10 +++++++++-
README.md | 12 +++++++++++
Template/config/show.php | 7 +++++++
VERSION | 2 +-
6 files changed, 67 insertions(+), 2 deletions(-)
create mode 100644 Asset/js/click-guard.js
diff --git a/Asset/js/click-guard.js b/Asset/js/click-guard.js
new file mode 100644
index 0000000..2fe3fa0
--- /dev/null
+++ b/Asset/js/click-guard.js
@@ -0,0 +1,35 @@
+/*
+ * OrganonTweaks -- only open a card on a quick click.
+ *
+ * A real click is a quick press-release; a drag is a press, some movement, and a release
+ * much later. When you drop a card, jQuery UI can leak a trailing "click" on it, and
+ * Kanboard opens the card -- an unwanted side effect of the drag.
+ *
+ * We simply time the press on a card: record the moment of mousedown / touchstart, and on
+ * the click that follows, if more than THRESHOLD ms elapsed the press was a drag (held),
+ * not a click, so we swallow the click in the capture phase before Kanboard's open handler
+ * runs. A normal click is well under the threshold and opens the card as usual.
+ */
+(function () {
+ "use strict";
+
+ var THRESHOLD = 100; // ms; a press on a card held longer than this is a drag, not a click
+ var pressStart = 0;
+
+ function onDown(e) {
+ pressStart = (e.target && e.target.closest && e.target.closest(".task-board")) ? Date.now() : 0;
+ }
+
+ document.addEventListener("mousedown", onDown, true);
+ document.addEventListener("touchstart", onDown, true);
+
+ document.addEventListener("click", function (e) {
+ if (pressStart &&
+ e.target && e.target.closest && e.target.closest(".task-board") &&
+ (Date.now() - pressStart) > THRESHOLD) {
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ }
+ pressStart = 0;
+ }, true);
+})();
diff --git a/Controller/ConfigController.php b/Controller/ConfigController.php
index 42d5e20..ddc7f1a 100644
--- a/Controller/ConfigController.php
+++ b/Controller/ConfigController.php
@@ -16,6 +16,7 @@ class ConfigController extends BaseController
'values' => array(
'organon_tweaks_always_comment_icon' => (int) $this->configModel->get('organon_tweaks_always_comment_icon', 1),
'organon_tweaks_keep_scroll' => (int) $this->configModel->get('organon_tweaks_keep_scroll', 1),
+ 'organon_tweaks_quick_click_only' => (int) $this->configModel->get('organon_tweaks_quick_click_only', 1),
),
'errors' => array(),
)));
@@ -27,10 +28,12 @@ class ConfigController extends BaseController
$alwaysCommentIcon = isset($values['organon_tweaks_always_comment_icon']) ? 1 : 0;
$keepScroll = isset($values['organon_tweaks_keep_scroll']) ? 1 : 0;
+ $quickClickOnly = isset($values['organon_tweaks_quick_click_only']) ? 1 : 0;
if ($this->configModel->save(array(
'organon_tweaks_always_comment_icon' => $alwaysCommentIcon,
'organon_tweaks_keep_scroll' => $keepScroll,
+ 'organon_tweaks_quick_click_only' => $quickClickOnly,
))) {
$this->flash->success(t('Settings saved successfully.'));
} else {
diff --git a/Plugin.php b/Plugin.php
index 395f2db..d4a33c1 100644
--- a/Plugin.php
+++ b/Plugin.php
@@ -34,6 +34,14 @@ class Plugin extends Base
'template' => 'plugins/OrganonTweaks/Asset/js/keep-scroll.js',
));
}
+
+ // Tweak: only open a card on a quick click (a press held > 100ms is a drag, so the
+ // trailing click is swallowed and the card does not open).
+ if ((int) $this->configModel->get('organon_tweaks_quick_click_only', 1) === 1) {
+ $this->hook->on('template:layout:js', array(
+ 'template' => 'plugins/OrganonTweaks/Asset/js/click-guard.js',
+ ));
+ }
}
public function getHelpers()
@@ -60,7 +68,7 @@ class Plugin extends Base
public function getPluginVersion()
{
- return '1.1.0';
+ return '1.2.0';
}
public function getPluginHomepage()
diff --git a/README.md b/README.md
index 18a636b..5ed4efb 100644
--- a/README.md
+++ b/README.md
@@ -47,12 +47,24 @@ board stays where you were.
itself is replaced), reads/writes `scrollLeft` on whichever `#board-container` is current.
- **On by default.** Toggle it under "Settings -> Organon Tweaks".
+### Open a card only on a quick click
+
+Dropping a card sometimes leaks a trailing "click" that opens the card -- an unwanted side
+effect of the drag. A real click is a quick press-release; a drag is a press held much
+longer. So `Asset/js/click-guard.js` times the press on a card (`mousedown`/`touchstart` to
+the following `click`) and, if it was held longer than **100 ms**, swallows the click in the
+capture phase before Kanboard's open handler -- so a drag never opens the card. Normal
+clicks (well under 100 ms) still open cards as usual. The 100 ms threshold is fixed.
+
+- **On by default.** Toggle it under "Settings -> Organon Tweaks".
+
## Settings
Global (per Kanboard instance) and admin-only, under "Settings -> Organon Tweaks":
- **Always show the comment icon on board cards** -- default on.
- **Keep the board scroll position across refreshes** -- default on.
+- **Open a card only on a quick click** -- default on.
## Requirements
diff --git a/Template/config/show.php b/Template/config/show.php
index 781e219..efd272b 100644
--- a/Template/config/show.php
+++ b/Template/config/show.php
@@ -19,6 +19,13 @@