|
let listHeaderTargets; |
|
let lists; |
|
|
|
const classesBySelector = { |
|
"list-card": "[data-testid='list-card']", |
|
"trello-card": ["[data-testid='trello-card']", "ui-droppable"], |
|
"list-card-composer-textarea": "[data-testid='list-card-composer-textarea']", |
|
"list-cards": "[data-testid='list-cards']", |
|
"list-wrapper": "[data-testid='list-wrapper']", |
|
"list": "[data-testid='list']", |
|
"list-header": "[data-testid='list-header']", |
|
"list-name-textarea": "[data-testid='list-name-textarea']", |
|
"list-footer": "[data-testid='list-footer']", |
|
"list-name": "[data-testid='list-name']", |
|
}; |
|
const classes = {}; |
|
let lastMissing = Infinity; |
|
let stylesheet; |
|
let css; |
|
function update() { |
|
let missing = []; |
|
let newClasses = []; |
|
for (let [unobfuscatedClassName, selector] of Object.entries(classesBySelector)) { |
|
if (!classes[unobfuscatedClassName]) { |
|
let ignoredClasses = []; |
|
if (Array.isArray(selector)) |
|
ignoredClasses = selector.slice(1), selector = selector[0]; |
|
|
|
let found = false; |
|
for (const element of document.querySelectorAll(selector)) { |
|
const classList = [...element.classList].filter(cls => !ignoredClasses.includes(cls)); |
|
const className = classList.length === 1 ? classList[0] : undefined; |
|
if (className) { |
|
classes[unobfuscatedClassName] = className; |
|
newClasses.push([unobfuscatedClassName, className]); |
|
console.log(unobfuscatedClassName, className); |
|
found = true; |
|
break; |
|
} |
|
} |
|
|
|
if (!found) |
|
missing.push(unobfuscatedClassName); |
|
} |
|
} |
|
|
|
if (missing.length !== lastMissing) { |
|
lastMissing = missing.length; |
|
if (missing.length) |
|
console.log("Missing classes:", missing); |
|
else |
|
console.log("No missing classes", classes); |
|
|
|
stylesheet ??= document.querySelector("style[data-source='User JavaScript and CSS extension']"); |
|
if (!stylesheet) |
|
return console.warn("Couldn't find user stylesheet to update"); |
|
|
|
css ??= stylesheet.textContent; |
|
console.log(newClasses); |
|
for (const [unobfuscatedClassName, className] of newClasses) { |
|
console.log("Replacing", unobfuscatedClassName, "with", className); |
|
css = css.replaceAll(new RegExp(`(?<=\\.)${unobfuscatedClassName}(?![\\w-])`, "g"), className); |
|
} |
|
|
|
// console.log(css); |
|
stylesheet.textContent = css; |
|
|
|
if (classes["list-wrapper"]) |
|
lists ??= document.getElementsByClassName(classes["list-wrapper"]); |
|
if (classes["list-header"]) |
|
listHeaderTargets ??= document.getElementsByClassName(classes["list-header"]); |
|
} |
|
|
|
for (const target of listHeaderTargets ?? []) { |
|
if (!target.classList.contains("chiri-listening")) { |
|
target.addEventListener("contextmenu", onRightClickList); |
|
} |
|
} |
|
|
|
updateListStates(); |
|
} |
|
|
|
setInterval(update, 100); |
|
|
|
function onRightClickList (event) { |
|
toggleVisible(getListName(event.target)); |
|
event.preventDefault(); |
|
} |
|
|
|
function toggleVisible (listName) { |
|
const id = `chiri-list-hidden.${listName}`; |
|
const hidden = !localStorage.getItem(id); |
|
if (hidden) |
|
localStorage.setItem(id, hidden); |
|
else |
|
localStorage.removeItem(id); |
|
|
|
updateListStates(); |
|
} |
|
|
|
function updateListStates() { |
|
for (const list of lists ?? []) { |
|
const listName = getListName(list); |
|
const listFilterCardsCount = getListFilterCardsCount(list); |
|
const shouldHide = listFilterCardsCount === undefined ? !!localStorage.getItem(`chiri-list-hidden.${listName}`) : !listFilterCardsCount; |
|
list.classList.toggle("chiri-list-filtered", listFilterCardsCount === 0); |
|
list.classList.toggle("chiri-list-hidden", shouldHide); |
|
} |
|
} |
|
|
|
function getListName (element) { |
|
const listElement = classes["list-wrapper"] |
|
&& element?.closest?.(`.${classes["list-wrapper"]}`); |
|
|
|
return classes["list-name-textarea"] && |
|
listElement?.querySelector(`.${classes["list-name-textarea"]}`)?.getAttribute("aria-label"); |
|
} |
|
|
|
function getListFilterCardsCount (element) { |
|
const paragraphs = classes["list-wrapper"] |
|
&& element?.closest?.(`.${classes["list-wrapper"]}`)?.querySelectorAll("p"); |
|
|
|
if (!paragraphs) |
|
return undefined; |
|
|
|
for (const p of paragraphs) { |
|
if (!p.textContent.endsWith(" filters")) |
|
continue; |
|
|
|
const count = parseInt(p.textContent); |
|
return count; |
|
} |
|
} |
|
|