refactor: migrate extra info feature to the new architecture
Bug: twpowertools:176
Change-Id: I379216066b973fe76f000ab9581053c1f0da569e
diff --git a/src/common/architecture/dependenciesProvider/DependenciesProvider.ts b/src/common/architecture/dependenciesProvider/DependenciesProvider.ts
index 132a67c..b6af2a1 100644
--- a/src/common/architecture/dependenciesProvider/DependenciesProvider.ts
+++ b/src/common/architecture/dependenciesProvider/DependenciesProvider.ts
@@ -1,16 +1,23 @@
+import ExtraInfo from '../../../features/extraInfo/core';
import AutoRefresh from '../../../features/autoRefresh/core/autoRefresh';
export const AutoRefreshDependency = 'autoRefresh';
+export const ExtraInfoDependency = 'extraInfo';
export const DependenciesToClass = {
[AutoRefreshDependency]: AutoRefresh,
+ [ExtraInfoDependency]: ExtraInfo,
};
interface OurWindow extends Window {
TWPTDependencies?: Dependencies;
}
+export type ClassFromDependency<T extends Dependency> = InstanceType<
+ (typeof DependenciesToClass)[T]
+>;
+
type Dependencies = {
- [K in Dependency]?: InstanceType<(typeof DependenciesToClass)[K]>;
+ [K in Dependency]?: ClassFromDependency<K>;
};
export type Dependency = keyof typeof DependenciesToClass;
@@ -26,14 +33,22 @@
this.dependencies = ourWindow.TWPTDependencies;
}
- getDependency(dependency: Dependency) {
+ /**
+ * Gets an instance of a dependency, and creates it beforehand if it doesn't exist yet.
+ */
+ getDependency<T extends Dependency>(dependency: T): ClassFromDependency<T> {
this.setUpDependency(dependency);
- return this.dependencies[dependency];
+ const dep = this.dependencies[dependency];
+ if (!dep) {
+ throw new Error(`Dependency ${dependency} not found.`);
+ }
+ return dep;
}
- setUpDependency(dependency: Dependency): void {
+ setUpDependency<T extends Dependency>(dependency: T): void {
if (!this.dependencies[dependency]) {
- this.dependencies[dependency] = new DependenciesToClass[dependency]();
+ const dependencyClass = DependenciesToClass[dependency];
+ this.dependencies[dependency] = new dependencyClass() as Dependencies[T];
}
}
}
diff --git a/src/contentScripts/communityConsole/main.js b/src/contentScripts/communityConsole/main.js
index 6b5c7f7..637e061 100644
--- a/src/contentScripts/communityConsole/main.js
+++ b/src/contentScripts/communityConsole/main.js
@@ -46,12 +46,9 @@
'ec-bulk-actions material-button[debugid="mark-read-button"]',
'ec-bulk-actions material-button[debugid="mark-unread-button"]',
- // Thread list items (used to inject the avatars and extra info)
+ // Thread list items (used to inject the avatars)
'li',
- // Thread list item toolbelt (used for the extra info feature)
- 'ec-thread-summary .main .toolbelt',
-
// Thread list (used for the autorefresh feature)
'ec-thread-list',
@@ -61,19 +58,6 @@
// Canned response tags (for the "import CR" popup for the workflows feature)
'ec-canned-response-row .tags',
- // Question state chips container (for the extra info feature)
- 'sc-tailwind-thread-question-question-card sc-tailwind-thread-question-state-chips',
-
- // Replies (for the extra info feature)
- 'sc-tailwind-thread-message-message-list sc-tailwind-thread-message-message-card',
-
- // Comments (for the extra info feature)
- 'sc-tailwind-thread-message-message-list sc-tailwind-thread-message-comment-card',
-
- // User activity chart (for the per-forum stats feature)
- 'ec-unified-user .scTailwindUser_profileUserprofilesection ' +
- 'sc-tailwind-shared-activity-chart',
-
// Thread page main content
'ec-thread > .page > .material-content > div[role="list"]',
@@ -97,11 +81,6 @@
}
}
- // Show additional details in the profile view.
- if (node.matches('ec-unified-user .scTailwindUser_profileUsercardmain')) {
- window.TWPTExtraInfo.injectAbuseChipsAtProfileIfEnabled(node);
- }
-
// Show the "previous posts" links if the option is currently enabled.
// Here we're selecting the 'ec-user > div' element (unique child)
if (node.matches(
@@ -141,17 +120,9 @@
// Inject avatar links to threads in the thread list. injectIfEnabled is
// responsible of determining whether it should run or not depending on its
// current setting.
- //
- // Also, inject extra info in the thread list.
if (('tagName' in node) && (node.tagName == 'LI') &&
node.querySelector('ec-thread-summary') !== null) {
avatars.injectIfEnabled(node);
- window.TWPTExtraInfo.injectAtThreadListIfEnabled(node);
- }
-
- // Inject extra info in the toolbelt of an expanded thread list item.
- if (node.matches('ec-thread-summary .main .toolbelt')) {
- window.TWPTExtraInfo.injectAtExpandedThreadListIfEnabled(node);
}
if (node.tagName == 'IFRAME') {
@@ -170,28 +141,6 @@
window.TWPTWorkflowsImport.addButtonIfEnabled(node);
}
- // Show additional details in the thread view.
- if (node.matches(
- 'sc-tailwind-thread-question-question-card sc-tailwind-thread-question-state-chips')) {
- window.TWPTExtraInfo.injectAtQuestionIfEnabled(node);
- }
- if (node.matches(
- 'sc-tailwind-thread-message-message-list sc-tailwind-thread-message-message-card')) {
- window.TWPTExtraInfo.injectAtReplyIfEnabled(node);
- }
-
- if (node.matches(
- 'sc-tailwind-thread-message-message-list sc-tailwind-thread-message-comment-card')) {
- window.TWPTExtraInfo.injectAtCommentIfEnabled(node);
- }
-
- // Inject per-forum stats section in the user profile
- if (node.matches(
- 'ec-unified-user .scTailwindUser_profileUserprofilesection ' +
- 'sc-tailwind-shared-activity-chart')) {
- window.TWPTExtraInfo.injectPerForumStatsIfEnabled(node);
- }
-
// Inject old thread page design warning if applicable
if (node.matches(
'ec-thread > .page > .material-content > div[role="list"]')) {
@@ -259,7 +208,7 @@
flattenThreads = new FlattenThreads();
reportDialogColorThemeFix = new ReportDialogColorThemeFix(options);
- // extraInfo, threadPageDesignWarning and workflowsImport are
+ // threadPageDesignWarning and workflowsImport are
// initialized in start.js
// Before starting the mutation Observer, check whether we missed any
@@ -313,9 +262,6 @@
injectStylesheet(chrome.runtime.getURL('css/batchlock_inject.css'));
// Thread list avatars
injectStylesheet(chrome.runtime.getURL('css/thread_list_avatars.css'));
- // Extra info
- injectStylesheet(chrome.runtime.getURL('css/extrainfo.css'));
- injectStylesheet(chrome.runtime.getURL('css/extrainfo_perforumstats.css'));
// Workflows, Thread toolbar
injectScript(chrome.runtime.getURL('litComponentsInject.bundle.js'));
// Thread toolbar
diff --git a/src/contentScripts/communityConsole/start.js b/src/contentScripts/communityConsole/start.js
index 33d2039..a0640ba 100644
--- a/src/contentScripts/communityConsole/start.js
+++ b/src/contentScripts/communityConsole/start.js
@@ -1,7 +1,6 @@
-import {injectScript, injectStylesheet} from '../../common/contentScriptsUtils.js';
+import {injectStylesheet} from '../../common/contentScriptsUtils.js';
import {getOptions} from '../../common/optionsUtils.js';
-import ExtraInfo from './extraInfo/index.js';
import FlattenThreadsReplyActionHandler from './flattenThreads/replyActionHandler.js';
import ThreadPageDesignWarning from './threadPageDesignWarning.js';
import WorkflowsImport from './workflows/import.js';
@@ -9,8 +8,6 @@
const SMEI_NESTED_REPLIES = 15;
const SMEI_RCE_THREAD_INTEROP = 22;
-injectScript(chrome.runtime.getURL('extraInfoInject.bundle.js'));
-
getOptions(null).then(options => {
/* IMPORTANT NOTE: Remember to change this when changing the "ifs" below!! */
if (options.loaddrafts || options.interopthreadpage ||
@@ -47,7 +44,6 @@
// Initialized here instead of in main.js so the first event is received if it
// happens when the page loads.
- window.TWPTExtraInfo = new ExtraInfo();
window.TWPTThreadPageDesignWarning = new ThreadPageDesignWarning();
window.TWPTWorkflowsImport = new WorkflowsImport();
@@ -71,6 +67,7 @@
injectStylesheet(chrome.runtime.getURL('css/ui_spacing/console.css'));
}
- const flattenThreadsReplyActionHandler = new FlattenThreadsReplyActionHandler(options);
+ const flattenThreadsReplyActionHandler =
+ new FlattenThreadsReplyActionHandler(options);
flattenThreadsReplyActionHandler.handleIfApplicable();
});
diff --git a/src/features/Features.ts b/src/features/Features.ts
index 6eab170..41e6b5d 100644
--- a/src/features/Features.ts
+++ b/src/features/Features.ts
@@ -2,12 +2,14 @@
import AutoRefreshFeature from './autoRefresh/autoRefresh.feature';
import InfiniteScrollFeature from './infiniteScroll/infiniteScroll.feature';
import ScriptFilterListProvider from '../common/architecture/scripts/ScriptFilterListProvider';
+import ExtraInfoFeature from './extraInfo/extraInfo.feature';
export type ConcreteFeatureClass = { new (): Feature };
export default class Features extends ScriptFilterListProvider {
private features: ConcreteFeatureClass[] = [
AutoRefreshFeature,
+ ExtraInfoFeature,
InfiniteScrollFeature,
];
private initializedFeatures: Feature[];
diff --git a/src/contentScripts/communityConsole/extraInfo/consts.js b/src/features/extraInfo/core/consts.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/consts.js
rename to src/features/extraInfo/core/consts.js
diff --git a/src/contentScripts/communityConsole/extraInfo/index.js b/src/features/extraInfo/core/index.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/index.js
rename to src/features/extraInfo/core/index.js
diff --git a/src/contentScripts/communityConsole/extraInfo/infoHandlers/base.js b/src/features/extraInfo/core/infoHandlers/base.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/infoHandlers/base.js
rename to src/features/extraInfo/core/infoHandlers/base.js
diff --git a/src/contentScripts/communityConsole/extraInfo/infoHandlers/basedOnResponseEvent.js b/src/features/extraInfo/core/infoHandlers/basedOnResponseEvent.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/infoHandlers/basedOnResponseEvent.js
rename to src/features/extraInfo/core/infoHandlers/basedOnResponseEvent.js
diff --git a/src/contentScripts/communityConsole/extraInfo/infoHandlers/profile.js b/src/features/extraInfo/core/infoHandlers/profile.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/infoHandlers/profile.js
rename to src/features/extraInfo/core/infoHandlers/profile.js
diff --git a/src/contentScripts/communityConsole/extraInfo/infoHandlers/thread.js b/src/features/extraInfo/core/infoHandlers/thread.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/infoHandlers/thread.js
rename to src/features/extraInfo/core/infoHandlers/thread.js
diff --git a/src/contentScripts/communityConsole/extraInfo/infoHandlers/threadList.js b/src/features/extraInfo/core/infoHandlers/threadList.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/infoHandlers/threadList.js
rename to src/features/extraInfo/core/infoHandlers/threadList.js
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/base.js b/src/features/extraInfo/core/injections/base.js
similarity index 96%
rename from src/contentScripts/communityConsole/extraInfo/injections/base.js
rename to src/features/extraInfo/core/injections/base.js
index 78ded47..66c024e 100644
--- a/src/contentScripts/communityConsole/extraInfo/injections/base.js
+++ b/src/features/extraInfo/core/injections/base.js
@@ -1,7 +1,7 @@
import {MDCTooltip} from '@material/tooltip';
import {shouldImplement} from '../../../../common/commonUtils.js';
-import {createExtBadge} from '../../utils/common.js';
+import {createExtBadge} from '../../../../contentScripts/communityConsole/utils/common.js';
export default class BaseExtraInfoInjection {
constructor(infoHandler, optionsWatcher) {
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/baseThreadMessage.js b/src/features/extraInfo/core/injections/baseThreadMessage.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/injections/baseThreadMessage.js
rename to src/features/extraInfo/core/injections/baseThreadMessage.js
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/expandedThreadList.js b/src/features/extraInfo/core/injections/expandedThreadList.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/injections/expandedThreadList.js
rename to src/features/extraInfo/core/injections/expandedThreadList.js
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/profileAbuse.js b/src/features/extraInfo/core/injections/profileAbuse.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/injections/profileAbuse.js
rename to src/features/extraInfo/core/injections/profileAbuse.js
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/profilePerForumStats.js b/src/features/extraInfo/core/injections/profilePerForumStats.js
similarity index 73%
rename from src/contentScripts/communityConsole/extraInfo/injections/profilePerForumStats.js
rename to src/features/extraInfo/core/injections/profilePerForumStats.js
index 57278ee..83de9db 100644
--- a/src/contentScripts/communityConsole/extraInfo/injections/profilePerForumStats.js
+++ b/src/features/extraInfo/core/injections/profilePerForumStats.js
@@ -1,5 +1,5 @@
-import {getDisplayLanguage} from '../../utils/common.js';
-import PerForumStatsSection from '../../utils/PerForumStatsSection.js';
+import {getDisplayLanguage} from '../../../../contentScripts/communityConsole/utils/common.js';
+import PerForumStatsSection from '../../../../contentScripts/communityConsole/utils/PerForumStatsSection.js';
import BaseExtraInfoInjection from './base.js';
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/threadComment.js b/src/features/extraInfo/core/injections/threadComment.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/injections/threadComment.js
rename to src/features/extraInfo/core/injections/threadComment.js
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/threadList.js b/src/features/extraInfo/core/injections/threadList.js
similarity index 95%
rename from src/contentScripts/communityConsole/extraInfo/injections/threadList.js
rename to src/features/extraInfo/core/injections/threadList.js
index 6a78ea3..e35fbe0 100644
--- a/src/contentScripts/communityConsole/extraInfo/injections/threadList.js
+++ b/src/features/extraInfo/core/injections/threadList.js
@@ -1,7 +1,7 @@
import {MDCTooltip} from '@material/tooltip';
import {parseUrl} from '../../../../common/commonUtils.js';
-import {createExtBadge} from '../../utils/common.js';
+import {createExtBadge} from '../../../../contentScripts/communityConsole/utils/common.js';
import {kItemMetadataState, kItemMetadataStateI18n} from '../consts.js';
import ThreadExtraInfoService from '../services/thread.js';
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/threadQuestion.js b/src/features/extraInfo/core/injections/threadQuestion.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/injections/threadQuestion.js
rename to src/features/extraInfo/core/injections/threadQuestion.js
diff --git a/src/contentScripts/communityConsole/extraInfo/injections/threadReply.js b/src/features/extraInfo/core/injections/threadReply.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/injections/threadReply.js
rename to src/features/extraInfo/core/injections/threadReply.js
diff --git a/src/contentScripts/communityConsole/extraInfo/services/message.js b/src/features/extraInfo/core/services/message.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/services/message.js
rename to src/features/extraInfo/core/services/message.js
diff --git a/src/contentScripts/communityConsole/extraInfo/services/states.js b/src/features/extraInfo/core/services/states.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/services/states.js
rename to src/features/extraInfo/core/services/states.js
diff --git a/src/contentScripts/communityConsole/extraInfo/services/thread.js b/src/features/extraInfo/core/services/thread.js
similarity index 100%
rename from src/contentScripts/communityConsole/extraInfo/services/thread.js
rename to src/features/extraInfo/core/services/thread.js
diff --git a/src/features/extraInfo/extraInfo.feature.ts b/src/features/extraInfo/extraInfo.feature.ts
new file mode 100644
index 0000000..f7f9f66
--- /dev/null
+++ b/src/features/extraInfo/extraInfo.feature.ts
@@ -0,0 +1,18 @@
+import Feature from '../../common/architecture/features/Feature';
+import { ConcreteScript } from '../../common/architecture/scripts/Script';
+import CCExtraInfoDependencySetUpScript from './scripts/ccExtraInfoDependencySetUp.script';
+import CCExtraInfoInjectScript from './scripts/ccExtraInfoInject.script';
+import CCExtraInfoMainScript from './scripts/ccExtraInfoMain.script';
+import CCExtraInfoStylesScript from './scripts/ccExtraInfoStyles.script';
+
+export default class ExtraInfoFeature extends Feature {
+ public readonly scripts: ConcreteScript[] = [
+ CCExtraInfoDependencySetUpScript,
+ CCExtraInfoInjectScript,
+ CCExtraInfoMainScript,
+ CCExtraInfoStylesScript,
+ ];
+
+ readonly codename = 'extraInfo';
+ readonly relatedOptions: string[] = [];
+}
diff --git a/src/features/extraInfo/nodeWatcherHandlers/profile/ccExtraInfoProfileAbuseChips.handler.ts b/src/features/extraInfo/nodeWatcherHandlers/profile/ccExtraInfoProfileAbuseChips.handler.ts
new file mode 100644
index 0000000..7cc895a
--- /dev/null
+++ b/src/features/extraInfo/nodeWatcherHandlers/profile/ccExtraInfoProfileAbuseChips.handler.ts
@@ -0,0 +1,11 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCExtraInfoMainOptions } from '../../scripts/ccExtraInfoMain.script';
+
+export default class CCExtraInfoProfileAbuseChipsHandler extends CssSelectorNodeWatcherScriptHandler<CCExtraInfoMainOptions> {
+ cssSelector = 'ec-unified-user .scTailwindUser_profileUsercardmain';
+
+ onMutatedNode({ node }: NodeMutation) {
+ this.options.extraInfo.injectAbuseChipsAtProfileIfEnabled(node);
+ }
+}
diff --git a/src/features/extraInfo/nodeWatcherHandlers/profile/ccExtraInfoProfilePerForumStats.handler.ts b/src/features/extraInfo/nodeWatcherHandlers/profile/ccExtraInfoProfilePerForumStats.handler.ts
new file mode 100644
index 0000000..d08db21
--- /dev/null
+++ b/src/features/extraInfo/nodeWatcherHandlers/profile/ccExtraInfoProfilePerForumStats.handler.ts
@@ -0,0 +1,12 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCExtraInfoMainOptions } from '../../scripts/ccExtraInfoMain.script';
+
+export default class CCExtraInfoProfilePerForumStatsHandler extends CssSelectorNodeWatcherScriptHandler<CCExtraInfoMainOptions> {
+ cssSelector =
+ 'ec-unified-user .scTailwindUser_profileUserprofilesection sc-tailwind-shared-activity-chart';
+
+ onMutatedNode({ node }: NodeMutation) {
+ this.options.extraInfo.injectPerForumStatsIfEnabled(node);
+ }
+}
diff --git a/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadComment.handler.ts b/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadComment.handler.ts
new file mode 100644
index 0000000..802dc51
--- /dev/null
+++ b/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadComment.handler.ts
@@ -0,0 +1,14 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCExtraInfoMainOptions } from '../../scripts/ccExtraInfoMain.script';
+
+/**
+ * Inject extra info to threads in the thread list.
+ */
+export default class CCExtraInfoThreadCommentHandler extends CssSelectorNodeWatcherScriptHandler<CCExtraInfoMainOptions> {
+ cssSelector = 'sc-tailwind-thread-message-message-list sc-tailwind-thread-message-comment-card';
+
+ onMutatedNode({ node }: NodeMutation) {
+ this.options.extraInfo.injectAtCommentIfEnabled(node);
+ }
+}
diff --git a/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadQuestion.handler.ts b/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadQuestion.handler.ts
new file mode 100644
index 0000000..0d16772
--- /dev/null
+++ b/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadQuestion.handler.ts
@@ -0,0 +1,14 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCExtraInfoMainOptions } from '../../scripts/ccExtraInfoMain.script';
+
+/**
+ * Inject extra info to threads in the thread list.
+ */
+export default class CCExtraInfoThreadQuestionHandler extends CssSelectorNodeWatcherScriptHandler<CCExtraInfoMainOptions> {
+ cssSelector = 'sc-tailwind-thread-question-question-card sc-tailwind-thread-question-state-chips';
+
+ onMutatedNode({ node }: NodeMutation) {
+ this.options.extraInfo.injectAtQuestionIfEnabled(node);
+ }
+}
diff --git a/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadReply.handler.ts b/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadReply.handler.ts
new file mode 100644
index 0000000..543ddb0
--- /dev/null
+++ b/src/features/extraInfo/nodeWatcherHandlers/thread/ccExtraInfoThreadReply.handler.ts
@@ -0,0 +1,14 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCExtraInfoMainOptions } from '../../scripts/ccExtraInfoMain.script';
+
+/**
+ * Inject extra info to threads in the thread list.
+ */
+export default class CCExtraInfoThreadReplyHandler extends CssSelectorNodeWatcherScriptHandler<CCExtraInfoMainOptions> {
+ cssSelector = 'sc-tailwind-thread-message-message-list sc-tailwind-thread-message-message-card';
+
+ onMutatedNode({ node }: NodeMutation) {
+ this.options.extraInfo.injectAtReplyIfEnabled(node);
+ }
+}
diff --git a/src/features/extraInfo/nodeWatcherHandlers/threadList/ccExtraInfoThreadList.handler.ts b/src/features/extraInfo/nodeWatcherHandlers/threadList/ccExtraInfoThreadList.handler.ts
new file mode 100644
index 0000000..5d26037
--- /dev/null
+++ b/src/features/extraInfo/nodeWatcherHandlers/threadList/ccExtraInfoThreadList.handler.ts
@@ -0,0 +1,14 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCExtraInfoMainOptions } from '../../scripts/ccExtraInfoMain.script';
+
+/**
+ * Inject extra info to threads in the thread list.
+ */
+export default class CCExtraInfoThreadListHandler extends CssSelectorNodeWatcherScriptHandler<CCExtraInfoMainOptions> {
+ cssSelector = 'li:has(ec-thread-summary)';
+
+ onMutatedNode({ node }: NodeMutation) {
+ this.options.extraInfo.injectAtThreadListIfEnabled(node);
+ }
+}
diff --git a/src/features/extraInfo/nodeWatcherHandlers/threadList/ccExtraInfoThreadListToolbelt.handler.ts b/src/features/extraInfo/nodeWatcherHandlers/threadList/ccExtraInfoThreadListToolbelt.handler.ts
new file mode 100644
index 0000000..b6ef4dc
--- /dev/null
+++ b/src/features/extraInfo/nodeWatcherHandlers/threadList/ccExtraInfoThreadListToolbelt.handler.ts
@@ -0,0 +1,14 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCExtraInfoMainOptions } from '../../scripts/ccExtraInfoMain.script';
+
+/**
+ * Inject extra info in the toolbelt of an expanded thread list item.
+ */
+export default class CCExtraInfoThreadListToolbeltHandler extends CssSelectorNodeWatcherScriptHandler<CCExtraInfoMainOptions> {
+ cssSelector = 'ec-thread-summary .main .toolbelt';
+
+ onMutatedNode({ node }: NodeMutation) {
+ this.options.extraInfo.injectAtExpandedThreadListIfEnabled(node);
+ }
+}
diff --git a/src/features/extraInfo/scripts/ccExtraInfoDependencySetUp.script.ts b/src/features/extraInfo/scripts/ccExtraInfoDependencySetUp.script.ts
new file mode 100644
index 0000000..cd595c5
--- /dev/null
+++ b/src/features/extraInfo/scripts/ccExtraInfoDependencySetUp.script.ts
@@ -0,0 +1,15 @@
+import { Dependency, ExtraInfoDependency } from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
+import {
+ ScriptEnvironment,
+ ScriptPage,
+ ScriptRunPhase,
+} from '../../../common/architecture/scripts/Script';
+import SetUpDependenciesScript from '../../../common/architecture/scripts/setUpDependencies/SetUpDependenciesScript';
+
+export default class CCExtraInfoDependencySetUpScript extends SetUpDependenciesScript {
+ public priority = 101;
+ public page = ScriptPage.CommunityConsole;
+ public environment = ScriptEnvironment.ContentScript;
+ public runPhase = ScriptRunPhase.Start;
+ public dependencies: Dependency[] = [ExtraInfoDependency];
+}
diff --git a/src/features/extraInfo/scripts/ccExtraInfoInject.script.ts b/src/features/extraInfo/scripts/ccExtraInfoInject.script.ts
new file mode 100644
index 0000000..2bd6364
--- /dev/null
+++ b/src/features/extraInfo/scripts/ccExtraInfoInject.script.ts
@@ -0,0 +1,14 @@
+import Script, { ScriptEnvironment, ScriptPage, ScriptRunPhase } from "../../../common/architecture/scripts/Script";
+import { injectScript } from "../../../common/contentScriptsUtils";
+
+export default class CCExtraInfoInjectScript extends Script {
+ priority = 11;
+
+ page = ScriptPage.CommunityConsole;
+ environment = ScriptEnvironment.ContentScript;
+ runPhase = ScriptRunPhase.Start;
+
+ execute() {
+ injectScript(chrome.runtime.getURL('extraInfoInject.bundle.js'));
+ }
+}
diff --git a/src/features/extraInfo/scripts/ccExtraInfoMain.script.ts b/src/features/extraInfo/scripts/ccExtraInfoMain.script.ts
new file mode 100644
index 0000000..80fbfbf
--- /dev/null
+++ b/src/features/extraInfo/scripts/ccExtraInfoMain.script.ts
@@ -0,0 +1,43 @@
+import DependenciesProviderSingleton, {
+ ExtraInfoDependency,
+} from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
+import {
+ ScriptEnvironment,
+ ScriptPage,
+ ScriptRunPhase,
+} from '../../../common/architecture/scripts/Script';
+import NodeWatcherScript from '../../../common/architecture/scripts/nodeWatcher/NodeWatcherScript';
+import ExtraInfo from '../core';
+import CCExtraInfoProfileAbuseChipsHandler from '../nodeWatcherHandlers/profile/ccExtraInfoProfileAbuseChips.handler';
+import CCExtraInfoProfilePerForumStatsHandler from '../nodeWatcherHandlers/profile/ccExtraInfoProfilePerForumStats.handler';
+import CCExtraInfoThreadCommentHandler from '../nodeWatcherHandlers/thread/ccExtraInfoThreadComment.handler';
+import CCExtraInfoThreadListHandler from '../nodeWatcherHandlers/threadList/ccExtraInfoThreadList.handler';
+import CCExtraInfoThreadListToolbeltHandler from '../nodeWatcherHandlers/threadList/ccExtraInfoThreadListToolbelt.handler';
+import CCExtraInfoThreadQuestionHandler from '../nodeWatcherHandlers/thread/ccExtraInfoThreadQuestion.handler';
+import CCExtraInfoThreadReplyHandler from '../nodeWatcherHandlers/thread/ccExtraInfoThreadReply.handler';
+
+export interface CCExtraInfoMainOptions {
+ extraInfo: ExtraInfo;
+}
+
+export default class CCExtraInfoMainScript extends NodeWatcherScript<CCExtraInfoMainOptions> {
+ page = ScriptPage.CommunityConsole;
+ environment = ScriptEnvironment.ContentScript;
+ runPhase = ScriptRunPhase.Main;
+ handlers = new Map([
+ ['ccExtraInfoProfile', CCExtraInfoProfileAbuseChipsHandler],
+ ['ccExtraInfoProfilePerForumStats', CCExtraInfoProfilePerForumStatsHandler],
+ ['ccExtraInfoThreadComment', CCExtraInfoThreadCommentHandler],
+ ['ccExtraInfoThreadList', CCExtraInfoThreadListHandler],
+ ['ccExtraInfoThreadListToolbelt', CCExtraInfoThreadListToolbeltHandler],
+ ['ccExtraInfoThreadQuestion', CCExtraInfoThreadQuestionHandler],
+ ['ccExtraInfoThreadReply', CCExtraInfoThreadReplyHandler],
+ ]);
+
+ protected optionsFactory(): CCExtraInfoMainOptions {
+ const dependenciesProvider = DependenciesProviderSingleton.getInstance();
+ return {
+ extraInfo: dependenciesProvider.getDependency(ExtraInfoDependency),
+ };
+ }
+}
diff --git a/src/features/extraInfo/scripts/ccExtraInfoStyles.script.ts b/src/features/extraInfo/scripts/ccExtraInfoStyles.script.ts
new file mode 100644
index 0000000..4d806f6
--- /dev/null
+++ b/src/features/extraInfo/scripts/ccExtraInfoStyles.script.ts
@@ -0,0 +1,17 @@
+import Script, {
+ ScriptEnvironment,
+ ScriptPage,
+ ScriptRunPhase,
+} from '../../../common/architecture/scripts/Script';
+import { injectStylesheet } from '../../../common/contentScriptsUtils';
+
+export default class CCExtraInfoStylesScript extends Script {
+ page = ScriptPage.CommunityConsole;
+ environment = ScriptEnvironment.ContentScript;
+ runPhase = ScriptRunPhase.Main;
+
+ execute() {
+ injectStylesheet(chrome.runtime.getURL('css/extrainfo.css'));
+ injectStylesheet(chrome.runtime.getURL('css/extrainfo_perforumstats.css'));
+ }
+}