Inject additional information to message payloads
This additional information will be used to inject an element inside
messages quoting their parent message.
Bug: twpowertools:153
Change-Id: I502f9f9d0377ad5cb9be9c2a96cec416609e790f
diff --git a/src/contentScripts/communityConsole/flattenThreads/flattenThreads.js b/src/contentScripts/communityConsole/flattenThreads/flattenThreads.js
new file mode 100644
index 0000000..91bcfbb
--- /dev/null
+++ b/src/contentScripts/communityConsole/flattenThreads/flattenThreads.js
@@ -0,0 +1,55 @@
+export const kAdditionalInfoPrefix = '__TWPT_FLATTENTHREADS_ADDITIONALINFO__';
+export const kAdditionalInfoRegex =
+ /^__TWPT_FLATTENTHREADS_ADDITIONALINFO__(.*)/;
+
+export const kReplyPayloadSelector =
+ '.scTailwindThreadMessageMessagecardcontent:not(.scTailwindThreadMessageMessagecardpromoted) .scTailwindThreadPostcontentroot html-blob';
+
+export default class FlattenThreads {
+ construct() {}
+
+ getExtraInfo(node) {
+ let rawExtraInfo = null;
+ const possibleExtraInfoNodes =
+ node.querySelectorAll('span[style*=\'display\'][style*=\'none\']');
+ for (const candidate of possibleExtraInfoNodes) {
+ const content = candidate.textContent;
+ const matches = content.match(kAdditionalInfoRegex);
+ if (matches) {
+ rawExtraInfo = matches?.[1] ?? null;
+ break;
+ }
+ }
+ if (!rawExtraInfo) return null;
+ return JSON.parse(rawExtraInfo);
+ }
+
+ injectId(node, extraInfo) {
+ const root = node.closest('.scTailwindThreadMessageMessagecardcontent');
+ if (!root) return false;
+ root.setAttribute('data-twpt-message-id', extraInfo.id);
+ return true;
+ }
+
+ injectQuote(node, extraInfo) {
+ const content = node.closest('.scTailwindThreadPostcontentroot');
+ // @TODO: Change this by the actual quote component
+ const quote = document.createElement('div');
+ quote.textContent = 'QUOTE(' + extraInfo.parentMessage.id + ')';
+ content.prepend(quote);
+ }
+
+ injectIfApplicable(node) {
+ // If we injected the additional information, it means the flatten threads
+ // feature is enabled and in actual use, so we should inject the quote.
+ const extraInfo = this.getExtraInfo(node);
+ if (!extraInfo) return;
+
+ this.injectId(node, extraInfo);
+ if (extraInfo.isComment) this.injectQuote(node, extraInfo);
+ }
+
+ shouldInject(node) {
+ return node.matches(kReplyPayloadSelector);
+ }
+}
diff --git a/src/contentScripts/communityConsole/main.js b/src/contentScripts/communityConsole/main.js
index 1edb466..a3b1bb7 100644
--- a/src/contentScripts/communityConsole/main.js
+++ b/src/contentScripts/communityConsole/main.js
@@ -8,6 +8,7 @@
// #!if ['chromium', 'chromium_mv3'].includes(browser_target)
import {applyDragAndDropFixIfEnabled} from './dragAndDropFix.js';
// #!endif
+import {default as FlattenThreads, kReplyPayloadSelector} from './flattenThreads/flattenThreads.js';
import InfiniteScroll from './infiniteScroll.js';
import {kRepliesSectionSelector} from './threadToolbar/constants.js';
import ThreadToolbar from './threadToolbar/threadToolbar.js';
@@ -15,7 +16,7 @@
import Workflows from './workflows/workflows.js';
var mutationObserver, options, avatars, infiniteScroll, workflows,
- threadToolbar;
+ threadToolbar, flattenThreads;
const watchedNodesSelectors = [
// App container (used to set up the intersection observer and inject the dark
@@ -76,6 +77,9 @@
// Thread page reply section (for the thread page toolbar)
kRepliesSectionSelector,
+
+ // Reply payload (for the flatten threads UI)
+ kReplyPayloadSelector,
];
function handleCandidateNode(node) {
@@ -214,6 +218,11 @@
if (threadToolbar.shouldInject(node)) {
threadToolbar.injectIfApplicable(node);
}
+
+ // Inject parent reply quote
+ if (flattenThreads.shouldInject(node)) {
+ flattenThreads.injectIfApplicable(node);
+ }
}
}
@@ -251,6 +260,7 @@
infiniteScroll = new InfiniteScroll();
workflows = new Workflows();
threadToolbar = new ThreadToolbar();
+ flattenThreads = new FlattenThreads();
// autoRefresh, extraInfo, threadPageDesignWarning and workflowsImport are
// initialized in start.js