2026-07-04 10:09:55 -03:00
|
|
|
/*
|
2026-07-06 07:28:06 -03:00
|
|
|
* OrganonTweaks -- move plugin-injected DOM bits into their native positions on the board.
|
2026-07-04 10:09:55 -03:00
|
|
|
*
|
2026-07-06 07:28:06 -03:00
|
|
|
* Both fixes are needed because Kanboard's relevant hooks render at the END of their
|
|
|
|
|
* container, not where the item belongs:
|
|
|
|
|
*
|
|
|
|
|
* 1. "Remove this Column": the template:board:column:dropdown hook renders AFTER the column
|
|
|
|
|
* menu <ul> (and the dropdown JS clones only that <ul>), so we move the hidden <li> into
|
|
|
|
|
* the column's real <ul>.
|
|
|
|
|
* 2. "Always show comment icon": the template:board:task:icons hook renders at the end of
|
|
|
|
|
* the card icons row, so the "+" bubble lands after priority instead of in the native
|
|
|
|
|
* comment slot. We move it just before the description icon (where the native comment
|
|
|
|
|
* icon sits), so the order matches whether or not the card has comments.
|
|
|
|
|
*
|
|
|
|
|
* Both re-run when the board is redrawn (AJAX polling / drag-and-drop refresh).
|
2026-07-04 10:09:55 -03:00
|
|
|
*/
|
|
|
|
|
(function () {
|
|
|
|
|
"use strict";
|
|
|
|
|
|
2026-07-06 07:28:06 -03:00
|
|
|
function relocateColumnMenuItems() {
|
2026-07-04 10:09:55 -03:00
|
|
|
var items = document.querySelectorAll(".organontweaks-remove-column-item");
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < items.length; i++) {
|
|
|
|
|
var li = items[i];
|
|
|
|
|
|
|
|
|
|
// Already moved into a menu list: just make sure it is visible.
|
|
|
|
|
if (li.closest("ul")) {
|
|
|
|
|
li.style.display = "";
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The hook renders the item as a child of the column's dropdown wrapper;
|
|
|
|
|
// its first <ul> is the native menu.
|
|
|
|
|
var menu = li.parentNode ? li.parentNode.querySelector("ul") : null;
|
|
|
|
|
|
|
|
|
|
if (menu) {
|
|
|
|
|
menu.appendChild(li);
|
|
|
|
|
li.style.display = "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 07:28:06 -03:00
|
|
|
function repositionCommentIcons() {
|
|
|
|
|
var items = document.querySelectorAll(".organontweaks-comment-add");
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < items.length; i++) {
|
|
|
|
|
var item = items[i];
|
|
|
|
|
var row = item.parentNode;
|
|
|
|
|
|
|
|
|
|
if (!row) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Native comment icon sits just before the description icon; if there is no
|
|
|
|
|
// description, before the age / closed block. That is the slot we move into.
|
2026-07-07 09:19:50 -03:00
|
|
|
// NB: the description icon is wrapped in <span class="tooltip"> (Kanboard's
|
|
|
|
|
// tooltipLink), not an <a>, so we walk up to whatever is the row's direct child.
|
|
|
|
|
var anchor = row.querySelector("i.fa-file-text-o") ||
|
|
|
|
|
row.querySelector(".task-icon-age") ||
|
|
|
|
|
row.querySelector(".task-board-closed");
|
2026-07-06 07:28:06 -03:00
|
|
|
|
2026-07-07 09:19:50 -03:00
|
|
|
while (anchor && anchor.parentNode !== row) {
|
|
|
|
|
anchor = anchor.parentNode;
|
2026-07-06 07:28:06 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Move only if needed (keeps the MutationObserver from looping).
|
2026-07-07 09:19:50 -03:00
|
|
|
if (anchor && anchor !== item && item.nextElementSibling !== anchor) {
|
2026-07-06 07:28:06 -03:00
|
|
|
row.insertBefore(item, anchor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-13 10:25:28 -03:00
|
|
|
function hideNativeSort() {
|
|
|
|
|
// Only when our persistent-sort control is present (the tweak is on); otherwise leave the
|
|
|
|
|
// native fa-sort menu alone.
|
|
|
|
|
if (!document.querySelector(".organontweaks-sort")) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sorts = document.querySelectorAll("#board .fa-sort");
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < sorts.length; i++) {
|
|
|
|
|
var dd = sorts[i].closest(".dropdown");
|
|
|
|
|
|
|
|
|
|
// Skip our own control (its OFF-state icon is also fa-sort).
|
|
|
|
|
if (dd && !dd.classList.contains("organontweaks-sort")) {
|
|
|
|
|
dd.style.display = "none";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 07:28:06 -03:00
|
|
|
function apply() {
|
|
|
|
|
relocateColumnMenuItems();
|
|
|
|
|
repositionCommentIcons();
|
2026-07-13 10:25:28 -03:00
|
|
|
hideNativeSort();
|
2026-07-06 07:28:06 -03:00
|
|
|
}
|
|
|
|
|
|
2026-07-04 10:09:55 -03:00
|
|
|
function init() {
|
2026-07-06 21:19:06 -03:00
|
|
|
var container = document.getElementById("board-container");
|
|
|
|
|
if (!container) {
|
2026-07-04 10:09:55 -03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 07:28:06 -03:00
|
|
|
apply();
|
2026-07-04 10:09:55 -03:00
|
|
|
|
2026-07-06 21:19:06 -03:00
|
|
|
// Observe the STABLE parent, not #board-container: Kanboard replaces the container
|
|
|
|
|
// on every card drop / AJAX poll (BoardDragAndDrop.refresh), which would kill an
|
|
|
|
|
// observer bound to the container itself and leave the items un-relocated after a
|
|
|
|
|
// move. The parent survives, so apply() keeps running on every rebuild.
|
|
|
|
|
var parent = container.parentNode;
|
2026-07-04 10:09:55 -03:00
|
|
|
|
2026-07-06 21:19:06 -03:00
|
|
|
if (parent && window.MutationObserver) {
|
|
|
|
|
new MutationObserver(apply).observe(parent, { childList: true, subtree: true });
|
2026-07-04 10:09:55 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (document.readyState === "loading") {
|
|
|
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
|
|
|
} else {
|
|
|
|
|
init();
|
|
|
|
|
}
|
|
|
|
|
})();
|