|
| 1 | +/** |
| 2 | + * @name ColorIndicator |
| 3 | + * @author QuantumSoul |
| 4 | + * @description Highlights color codes in discord chats |
| 5 | + * @version 0.0.1 |
| 6 | + */ |
| 7 | + |
| 8 | +const CLASS_SCROLLER_INNER = BdApi.Webpack.getByKeys("navigationDescription", "scrollerInner")["scrollerInner"]; |
| 9 | +const CLASS_MESSAGE_LIST_ITEM = BdApi.Webpack.getByKeys("messageListItem")["messageListItem"]; |
| 10 | +const CLASS_MESSAGE_CONTENT = BdApi.Webpack.getByKeys("messageEditorCompact", "messageContent")["messageContent"]; |
| 11 | + |
| 12 | +module.exports = class Plugin { |
| 13 | + observer = null; |
| 14 | + |
| 15 | + start() { |
| 16 | + this.onSwitch(); |
| 17 | + } |
| 18 | + |
| 19 | + stop() { |
| 20 | + if (this.observer) this.observer.disconnect(); |
| 21 | + } |
| 22 | + |
| 23 | + onSwitch() { |
| 24 | + if (this.observer) this.observer.disconnect(); |
| 25 | + this.observer = new MutationObserver(this.handleMutations); |
| 26 | + |
| 27 | + //format existing messages and listen to new ones |
| 28 | + const channels = document.querySelector("." + CLASS_SCROLLER_INNER); |
| 29 | + if (channels) { |
| 30 | + //existing one |
| 31 | + channels.querySelectorAll("." + CLASS_MESSAGE_CONTENT).forEach(this.parseMessage); |
| 32 | + |
| 33 | + //new ones |
| 34 | + this.observer.observe(channels, { |
| 35 | + childList: true, |
| 36 | + subtree: true, |
| 37 | + characterData: true, |
| 38 | + }); |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + handleMutations = (mutationsList) => { |
| 43 | + let timeoutId = null; //prevents formatting before edition |
| 44 | + |
| 45 | + for (const mutation of mutationsList) { |
| 46 | + if (mutation.type === "childList") { |
| 47 | + for (const node of mutation.addedNodes) { |
| 48 | + if (node.classList && node.classList.contains(CLASS_MESSAGE_CONTENT)) { |
| 49 | + timeoutId = setTimeout(() => { |
| 50 | + //unedited message |
| 51 | + this.parseMessage(node); |
| 52 | + timeoutId = null; |
| 53 | + }, 500); |
| 54 | + } else if (node.classList && node.classList.contains(CLASS_MESSAGE_LIST_ITEM)) { |
| 55 | + //new message |
| 56 | + this.parseMessage(node.querySelector("." + CLASS_MESSAGE_CONTENT)); |
| 57 | + } |
| 58 | + } |
| 59 | + } else if (mutation.type === "characterData") { |
| 60 | + const messageContent = mutation.target.parentNode.closest("." + CLASS_MESSAGE_CONTENT); |
| 61 | + if (messageContent) { |
| 62 | + //edited message |
| 63 | + if (timeoutId !== null) { |
| 64 | + clearTimeout(timeoutId); |
| 65 | + timeoutId = null; |
| 66 | + } |
| 67 | + this.parseMessage(messageContent); |
| 68 | + } |
| 69 | + } |
| 70 | + } |
| 71 | + }; |
| 72 | + |
| 73 | + parseMessage = (messageContent) => { |
| 74 | + const colorCodeRegex = /#(?:[0-9a-fA-F]{3,6})\b/g; |
| 75 | + |
| 76 | + messageContent.querySelectorAll('span').forEach((span) => { |
| 77 | + if (span.classList.contains('changed-indicator')) { |
| 78 | + const textNode = document.createTextNode(span.textContent); |
| 79 | + try { |
| 80 | + span.parentNode.replaceChild(textNode, span); |
| 81 | + } catch (error) {} |
| 82 | + } |
| 83 | + }); |
| 84 | + |
| 85 | + messageContent.innerHTML = messageContent.innerHTML.replace(colorCodeRegex, (match) => { |
| 86 | + const textColor = this.isColorTooDark(match) ? 'white' : 'black'; |
| 87 | + return `<span class="changed-indicator inline" style="background-color:${match}; color:${textColor};">${match}</span>`; |
| 88 | + }); |
| 89 | + }; |
| 90 | + |
| 91 | + isColorTooDark = (hexColor) => { |
| 92 | + const bigint = parseInt(hexColor.slice(1), 16); |
| 93 | + const rgb = { r: (bigint >> 16) & 255, g: (bigint >> 8) & 255, b: bigint & 255 }; |
| 94 | + return 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b < 128; |
| 95 | + }; |
| 96 | +}; |
0 commit comments