Make nested replies warning in old UI smarter

The warning shown in the old thread UI when the nested replies feature
is enabled in a thread has been improved. Before, it only worked by
checking whether the thread was posted in one of the few forums we knew
nested replies were enabled there. These forums were manually hardcoded
into the extension.

However, now the extension detects whether the thread shown is using
nested replies by inspecting the ViewThread response, just like TW does.

Bug: twpowertools:139
Change-Id: I3470eb600f743f14ca565151c19f333f741c544e
diff --git a/src/contentScripts/communityConsole/threadPageDesignWarning.js b/src/contentScripts/communityConsole/threadPageDesignWarning.js
index ae26938..f58112e 100644
--- a/src/contentScripts/communityConsole/threadPageDesignWarning.js
+++ b/src/contentScripts/communityConsole/threadPageDesignWarning.js
@@ -8,11 +8,18 @@
 
 import {createExtBadge} from './utils/common.js';
 
-// Forums where Nested Replies have been enabled
-const NRS_ENABLED_FORUM_IDS = [51488989];
+const kSMEINestedReplies = 15;
+const kViewThreadResponse = 'TWPT_ViewThreadResponse';
 
 export default class ThreadPageDesignWarning {
   constructor() {
+    this.lastThread = {
+      body: {},
+      id: -1,
+      timestamp: 0,
+    };
+    this.setUpHandler();
+
     // We have to save whether the old UI was enabled at startup, since that's
     // the moment when it takes effect. If the option changes while the tab is
     // open, it won't take effect.
@@ -25,8 +32,39 @@
       if (this.shouldShowWarning) {
         injectStylesheet(
             chrome.runtime.getURL('css/thread_page_design_warning.css'));
+      } else {
+        this.removeHandler();
       }
     });
+
+    this.isExperimentEnabled = this.isNestedRepliesExperimentEnabled();
+  }
+
+  isNestedRepliesExperimentEnabled() {
+    if (!document.documentElement.hasAttribute('data-startup')) return false;
+
+    let startup =
+        JSON.parse(document.documentElement.getAttribute('data-startup'));
+    return startup?.[1]?.[6]?.includes?.(kSMEINestedReplies);
+  }
+
+  eventHandler(e) {
+    if (e.detail.id < this.lastThread.id) return;
+
+    this.lastThread = {
+      body: e.detail.body,
+      id: e.detail.id,
+      timestamp: Date.now(),
+    };
+  }
+
+  setUpHandler() {
+    window.addEventListener(kViewThreadResponse, this.eventHandler.bind(this));
+  }
+
+  removeHandler() {
+    window.removeEventListener(
+        kViewThreadResponse, this.eventHandler.bind(this));
   }
 
   injectWarning(content) {
@@ -76,21 +114,44 @@
                    return Promise.reject(
                        new Error('shouldShowWarning is not defined.'));
 
-                 return Promise.resolve(this.shouldShowWarning);
+                 return Promise.resolve({result: this.shouldShowWarning});
                },
                {
                  interval: 500,
                  timeout: 10 * 1000,
                })
+        .then(preShouldShowWarning => {
+          if (!preShouldShowWarning.result) return;
+
+          // If the global SMEI experiment is enabled, all threads use nested
+          // replies, so we'll skip the per-thread check and always show the
+          // warning banner.
+          if (this.isExperimentEnabled) return Promise.resolve(true);
+
+          let currentThread = parseUrl(location.href);
+          if (currentThread === false)
+            throw new Error('current thread id cannot be parsed.');
+
+          return waitFor(() => {
+            let now = Date.now();
+            let lastThreadInfo = this.lastThread.body['1']?.['2']?.['1'];
+            if (now - this.lastThread.timestamp > 30 * 1000 ||
+                lastThreadInfo?.['1'] != currentThread.thread ||
+                lastThreadInfo?.['3'] != currentThread.forum)
+              throw new Error(
+                  'cannot obtain information about current thread.');
+
+            // If the messageOrGap field contains any items, the thread is using
+            // nested replies. Otherwise, it probably isn't using them.
+            return Promise.resolve(
+                {result: this.lastThread.body['1']?.['40']?.length > 0});
+          }, {
+            interval: 500,
+            timeout: 10 * 1000,
+          });
+        })
         .then(shouldShowWarning => {
-          if (!shouldShowWarning) return;
-
-          let thread = parseUrl(location.href);
-          if (thread === false)
-            throw new Error('current thread cannot be parsed.');
-
-          if (NRS_ENABLED_FORUM_IDS.includes(parseInt(thread.forum)))
-            this.injectWarning(content);
+          if (shouldShowWarning.result) this.injectWarning(content);
         })
         .catch(err => {
           console.error(