Add per-forum stats to TW profiles
Fixed: twpowertools:102
Change-Id: Ie947c05346a5e430f08b3f3c4fbd13c2c8d744da
diff --git a/src/contentScripts/communityConsole/extraInfo.js b/src/contentScripts/communityConsole/extraInfo.js
index 35572da..af5ac7f 100644
--- a/src/contentScripts/communityConsole/extraInfo.js
+++ b/src/contentScripts/communityConsole/extraInfo.js
@@ -939,7 +939,8 @@
})
.then(profile => {
new PerForumStatsSection(
- chart?.parentNode, profile.body, this.displayLanguage);
+ chart?.parentNode, profile.body, this.displayLanguage,
+ /* isCommunityConsole = */ true);
})
.catch(err => {
console.error(
diff --git a/src/contentScripts/communityConsole/main.js b/src/contentScripts/communityConsole/main.js
index 8c67bb5..f43a25a 100644
--- a/src/contentScripts/communityConsole/main.js
+++ b/src/contentScripts/communityConsole/main.js
@@ -279,4 +279,5 @@
injectStylesheet(chrome.runtime.getURL('css/autorefresh_list.css'));
// Extra info
injectStylesheet(chrome.runtime.getURL('css/extrainfo.css'));
+ injectStylesheet(chrome.runtime.getURL('css/extrainfo_perforumstats.css'));
});
diff --git a/src/contentScripts/communityConsole/utils/PerForumStatsSection.js b/src/contentScripts/communityConsole/utils/PerForumStatsSection.js
index 153cfb1..7ca0f38 100644
--- a/src/contentScripts/communityConsole/utils/PerForumStatsSection.js
+++ b/src/contentScripts/communityConsole/utils/PerForumStatsSection.js
@@ -24,8 +24,9 @@
};
export default class PerForumStatsSection {
- constructor(existingChartSection, profile, locale) {
+ constructor(existingChartSection, profile, locale, isCommunityConsole) {
this.locale = locale;
+ this.isCommunityConsole = isCommunityConsole;
this.parseAndSetData(profile);
this.buildDOM(existingChartSection);
if (this.data.length) this.injectChart(this.data[0]?.id);
@@ -42,7 +43,7 @@
this.data = [];
for (const id of intersectionForumIDs) {
- const fui = forumUserInfos.find(ui => ui[1] === id)?.[2];
+ const fui = forumUserInfos.find(ui => ui?.[1] === id)?.[2];
const numMessages = kDataKeys.reduce((prevVal, key) => {
if (!fui?.[key[0]]) return prevVal;
return prevVal + fui[key[0]].reduce((prevVal, userActivity) => {
@@ -51,7 +52,7 @@
}, /* initialValue = */ 0);
this.data.push({
id,
- forumTitle: forumTitles.find(t => t[1] === id)?.[2],
+ forumTitle: forumTitles.find(t => t?.[1] === id)?.[2],
forumUserInfo: fui,
numMessages,
});
@@ -78,9 +79,23 @@
let title = document.createElement('h2');
title.classList.add('scTailwindSharedActivitycharttitle');
- const [badge, badgeTooltip] = createExtBadge();
+ let badge, badgeTooltip;
+ if (this.isCommunityConsole) {
+ [badge, badgeTooltip] = createExtBadge();
+ } else {
+ badge = document.createElement('span');
+ badge.classList.add('TWPT-badge');
+
+ var badgeImg = document.createElement('img');
+ badgeImg.src =
+ 'https://fonts.gstatic.com/s/i/materialicons/repeat/v6/24px.svg';
+
+ badge.appendChild(badgeImg);
+ }
+
let titleText = document.createElement('span');
- titleText.textContent = chrome.i18n.getMessage('inject_perforumstats_heading');
+ titleText.textContent =
+ chrome.i18n.getMessage('inject_perforumstats_heading');
title.append(badge, titleText);
@@ -93,7 +108,7 @@
root.append(title, selector, chartEl);
section.append(root);
existingChartSection.after(section);
- new MDCTooltip(badgeTooltip);
+ if (this.isCommunityConsole) new MDCTooltip(badgeTooltip);
}
getAplosData(forumId) {
@@ -101,10 +116,15 @@
for (const [key, name, color] of kDataKeys) {
let rawData = this.data.find(f => f.id === forumId)?.forumUserInfo?.[key];
let data;
- if (!rawData)
+ if (!rawData) {
data = [];
- else
- data = rawData.map(m => JSON.stringify(Object.values(m)));
+ } else {
+ // We're filtering empty strings since in the public forum there a lose
+ // conversion takes place and the first element of the array is always
+ // null, which breaks the Aplos graph rendering.
+ data =
+ rawData.map(m => JSON.stringify(Object.values(m))).filter(m => !!m);
+ }
aplosData.push({
color,
data,
diff --git a/src/contentScripts/profile.js b/src/contentScripts/profile.js
deleted file mode 100644
index 3f7a3fa..0000000
--- a/src/contentScripts/profile.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import {getOptions} from '../common/optionsUtils.js';
-
-import {injectPreviousPostsLinksUnifiedProfile} from './utilsCommon/unifiedProfiles.js';
-
-getOptions('history').then(options => {
- if (options?.history)
- injectPreviousPostsLinksUnifiedProfile(/* isCommunityConsole = */ false);
-});
diff --git a/src/contentScripts/publicProfile.js b/src/contentScripts/publicProfile.js
new file mode 100644
index 0000000..fec0c85
--- /dev/null
+++ b/src/contentScripts/publicProfile.js
@@ -0,0 +1,43 @@
+import {getOptions} from '../common/optionsUtils.js';
+
+import PerForumStatsSection from './communityConsole/utils/PerForumStatsSection.js';
+import {correctArrayKeys} from './utilsCommon/protojs.js';
+import {injectPreviousPostsLinksUnifiedProfile} from './utilsCommon/unifiedProfiles.js';
+
+const profileViewRegex = /var view ?= ?(.+\]);/;
+
+getOptions(['history', 'extrainfo']).then(options => {
+ if (options?.history)
+ injectPreviousPostsLinksUnifiedProfile(/* isCommunityConsole = */ false);
+
+ if (options?.extrainfo) {
+ try {
+ // Find chart
+ const chart = document.querySelector(
+ 'sc-tailwind-user_profile-user-profile ' +
+ '.scTailwindUser_profileUserprofilesection ' +
+ 'sc-tailwind-shared-activity-chart');
+ if (!chart) throw new Error('Couldn\'t find existing chart.');
+
+ // Extract profile JSON information
+ const scripts = document.querySelectorAll('script');
+ let profileView = null;
+ for (let i = 0; i < scripts.length; ++i) {
+ const matches = scripts[i].textContent.match(profileViewRegex);
+ if (matches?.[1]) {
+ profileView = JSON.parse(matches[1]);
+ break;
+ }
+ }
+ const profileViewC = {'1': correctArrayKeys(profileView)};
+ console.log(profileViewC);
+ if (!profileView) throw new Error('Could not find user view data.');
+ new PerForumStatsSection(
+ chart?.parentNode, profileViewC,
+ document.documentElement?.lang ?? 'en',
+ /* isCommunityConsole = */ false);
+ } catch (err) {
+ console.error('Error while injecting extra info: ', err);
+ }
+ }
+});
diff --git a/src/contentScripts/publicProfileStart.js b/src/contentScripts/publicProfileStart.js
new file mode 100644
index 0000000..f5a3a2f
--- /dev/null
+++ b/src/contentScripts/publicProfileStart.js
@@ -0,0 +1,7 @@
+import {injectScript} from '../common/contentScriptsUtils.js';
+import {getOptions} from '../common/optionsUtils.js';
+
+getOptions('extrainfo').then(options => {
+ if (options?.extrainfo)
+ injectScript(chrome.runtime.getURL('extraInfoInject.bundle.js'));
+});
diff --git a/src/contentScripts/utilsCommon/protojs.js b/src/contentScripts/utilsCommon/protojs.js
new file mode 100644
index 0000000..026559b
--- /dev/null
+++ b/src/contentScripts/utilsCommon/protojs.js
@@ -0,0 +1,13 @@
+// Function which converts a protobuf array into an array which can be accessed
+// as if it was a protobuf object (with the same keys). If the input is not an
+// array it returns itself (since it is called recursively).
+export function correctArrayKeys(input) {
+ if (!Array.isArray(input)) return input;
+
+ let object = [];
+ for (let i = 0; i < input.length; ++i) {
+ if (input[i] === null) continue;
+ object[i + 1] = correctArrayKeys(input[i]);
+ }
+ return object;
+}
diff --git a/src/static/_locales/en/messages.json b/src/static/_locales/en/messages.json
index 492ab4d..f6ac4be 100644
--- a/src/static/_locales/en/messages.json
+++ b/src/static/_locales/en/messages.json
@@ -156,7 +156,7 @@
"description": "Feature checkbox in the options page"
},
"options_perforumstats": {
- "message": "Show per-forum activity in profiles in the Community Console.",
+ "message": "Show per-forum activity in profiles.",
"description": "Feature checkbox in the options page"
},
"options_save": {
diff --git a/src/static/css/extrainfo.css b/src/static/css/extrainfo.css
index eeb8694..ae15f8d 100644
--- a/src/static/css/extrainfo.css
+++ b/src/static/css/extrainfo.css
@@ -126,28 +126,3 @@
--icon-size: 9.5px;
margin-right: 2px;
}
-
-
-/* Per-forum stats section */
-.TWPT-scTailwindSharedActivitychartroot .scTailwindSharedActivitychartchart {
- margin-top: 26px;
-}
-
-.TWPT-scTailwindSharedActivitychartroot .scTailwindSharedActivitycharttitle {
- display: flex;
- align-items: center;
-}
-
-.TWPT-scTailwindSharedActivitychartroot .scTailwindSharedActivitycharttitle .TWPT-badge {
- margin-inline-end: 6px;
-}
-
-.TWPT-scTailwindSharedActivitychartroot .TWPT-select-container {
- position: absolute;
- top: 56px;
- z-index: 2;
-}
-
-.TWPT-scTailwindSharedActivitychartroot .TWPT-select-container select {
- max-width: 300px;
-}
diff --git a/src/static/css/extrainfo_perforumstats.css b/src/static/css/extrainfo_perforumstats.css
new file mode 100644
index 0000000..ff73e98
--- /dev/null
+++ b/src/static/css/extrainfo_perforumstats.css
@@ -0,0 +1,23 @@
+/* Per-forum stats section */
+.TWPT-scTailwindSharedActivitychartroot .scTailwindSharedActivitychartchart {
+ margin-top: 26px;
+}
+
+.TWPT-scTailwindSharedActivitychartroot .scTailwindSharedActivitycharttitle {
+ display: flex;
+ align-items: center;
+}
+
+.TWPT-scTailwindSharedActivitychartroot .scTailwindSharedActivitycharttitle .TWPT-badge {
+ margin-inline-end: 6px;
+}
+
+.TWPT-scTailwindSharedActivitychartroot .TWPT-select-container {
+ position: absolute;
+ top: 56px;
+ z-index: 2;
+}
+
+.TWPT-scTailwindSharedActivitychartroot .TWPT-select-container select {
+ max-width: 300px;
+}
diff --git a/templates/manifest.gjson b/templates/manifest.gjson
index 2524612..b4f0281 100644
--- a/templates/manifest.gjson
+++ b/templates/manifest.gjson
@@ -44,8 +44,14 @@
{
"matches": ["https://support.google.com/*/profile/*", "https://support.google.com/profile/*"],
"all_frames": true,
- "js": ["profile.bundle.js", "mdcStyles.bundle.js"],
- "css": ["css/common/forum.css", "css/unifiedprofile.css"]
+ "js": ["publicProfileStart.bundle.js"],
+ "run_at": "document_start"
+ },
+ {
+ "matches": ["https://support.google.com/*/profile/*", "https://support.google.com/profile/*"],
+ "all_frames": true,
+ "js": ["publicProfile.bundle.js", "mdcStyles.bundle.js"],
+ "css": ["css/common/forum.css", "css/unifiedprofile.css", "css/extrainfo_perforumstats.css"]
}
],
"permissions": [
@@ -82,6 +88,7 @@
"css/autorefresh_list.css",
"css/image_max_height.css",
"css/extrainfo.css",
+ "css/extrainfo_perforumstats.css",
"communityConsoleMain.bundle.js.map",
"communityConsoleStart.bundle.js.map",
diff --git a/webpack.config.js b/webpack.config.js
index 6024eb4..9d28abb 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -43,7 +43,8 @@
communityConsoleStart: './src/contentScripts/communityConsole/start.js',
publicForum: './src/contentScripts/publicForum.js',
publicThread: './src/contentScripts/publicThread.js',
- profile: './src/contentScripts/profile.js',
+ publicProfile: './src/contentScripts/publicProfile.js',
+ publicProfileStart: './src/contentScripts/publicProfileStart.js',
profileIndicator: './src/contentScripts/profileIndicator.js',
// Injected JS