DEV: Use `@bind` instead of repeated `.bind(this)` (#14931)

DEV: Use @bind instead of repeated .bind(this) (#14931)

Fixes some cases where event listeners weren’t correctly removed. Also fixes a dependency tracking bug in user-private-messages

diff --git a/app/assets/javascripts/discourse/app/components/bookmark.js b/app/assets/javascripts/discourse/app/components/bookmark.js
index 9008d4e..deadd61 100644
--- a/app/assets/javascripts/discourse/app/components/bookmark.js
+++ b/app/assets/javascripts/discourse/app/components/bookmark.js
@@ -17,7 +17,7 @@ import { TIME_SHORTCUT_TYPES } from "discourse/lib/time-shortcut";
 import { action } from "@ember/object";
 import { ajax } from "discourse/lib/ajax";
 import bootbox from "bootbox";
-import discourseComputed, { on } from "discourse-common/utils/decorators";
+import discourseComputed, { bind, on } from "discourse-common/utils/decorators";
 import { formattedReminderTime } from "discourse/lib/bookmark";
 import { and, notEmpty } from "@ember/object/computed";
 import { popupAjaxError } from "discourse/lib/ajax-error";
@@ -65,7 +65,7 @@ export default Component.extend({
       _itsatrap: new ItsATrap(),
     });
 
-    this.registerOnCloseHandler(this._onModalClose.bind(this));
+    this.registerOnCloseHandler(this._onModalClose);
 
     this._loadBookmarkOptions();
     this._bindKeyboardShortcuts();
@@ -239,6 +239,7 @@ export default Component.extend({
     }
   },
 
+  @bind
   _onModalClose(closeOpts) {
     // we want to close without saving if the user already saved
     // manually or deleted the bookmark, as well as when the modal
diff --git a/app/assets/javascripts/discourse/app/components/d-editor.js b/app/assets/javascripts/discourse/app/components/d-editor.js
index 2766547..2c64f01 100644
--- a/app/assets/javascripts/discourse/app/components/d-editor.js
+++ b/app/assets/javascripts/discourse/app/components/d-editor.js
@@ -319,7 +319,7 @@ export default Component.extend(TextareaTextManipulation, {
     }
 
     if (isTesting()) {
-      this.element.addEventListener("paste", this.paste.bind(this));
+      this.element.addEventListener("paste", this.paste);
     }
   },
 
diff --git a/app/assets/javascripts/discourse/app/components/reviewable-item.js b/app/assets/javascripts/discourse/app/components/reviewable-item.js
index d7173eb..30eeff4 100644
--- a/app/assets/javascripts/discourse/app/components/reviewable-item.js
+++ b/app/assets/javascripts/discourse/app/components/reviewable-item.js
@@ -4,7 +4,7 @@ import I18n from "I18n";
 import { ajax } from "discourse/lib/ajax";
 import bootbox from "bootbox";
 import { dasherize } from "@ember/string";
-import discourseComputed from "discourse-common/utils/decorators";
+import discourseComputed, { bind } from "discourse-common/utils/decorators";
 import optionalService from "discourse/lib/optional-service";
 import { popupAjaxError } from "discourse/lib/ajax-error";
 import { set } from "@ember/object";
@@ -113,6 +113,7 @@ export default Component.extend({
     return _components[type];
   },
 
+  @bind
   _performConfirmed(action) {
     let reviewable = this.reviewable;
 
@@ -264,7 +265,7 @@ export default Component.extend({
           title: "review.reject_reason.title",
           model: this.reviewable,
         }).setProperties({
-          performConfirmed: this._performConfirmed.bind(this),
+          performConfirmed: this._performConfirmed,
           action,
         });
       } else if (customModal) {
@@ -272,7 +273,7 @@ export default Component.extend({
           title: `review.${customModal}.title`,
           model: this.reviewable,
         }).setProperties({
-          performConfirmed: this._performConfirmed.bind(this),
+          performConfirmed: this._performConfirmed,
           action,
         });
       } else {
diff --git a/app/assets/javascripts/discourse/app/controllers/user-private-messages.js b/app/assets/javascripts/discourse/app/controllers/user-private-messages.js
index 780e0e0..e0ec47b 100644
--- a/app/assets/javascripts/discourse/app/controllers/user-private-messages.js
+++ b/app/assets/javascripts/discourse/app/controllers/user-private-messages.js
@@ -27,12 +27,20 @@ export default Controller.extend({
     return pmView === VIEW_NAME_WARNINGS && !viewingSelf && !isAdmin;
   },
 
-  @discourseComputed("pmTopicTrackingState.newIncoming.[]", "group")
+  @discourseComputed(
+    "pmTopicTrackingState.newIncoming.[]",
+    "pmTopicTrackingState.statesModificationCounter",
+    "group"
+  )
   newLinkText() {
     return this._linkText("new");
   },
 
-  @discourseComputed("pmTopicTrackingState.newIncoming.[]", "group")
+  @discourseComputed(
+    "pmTopicTrackingState.newIncoming.[]",
+    "pmTopicTrackingState.statesModificationCounter",
+    "group"
+  )
   unreadLinkText() {
     return this._linkText("unread");
   },
diff --git a/app/assets/javascripts/discourse/app/lib/uppy-checksum-plugin.js b/app/assets/javascripts/discourse/app/lib/uppy-checksum-plugin.js
index 977a016..0b54cf8 100644
--- a/app/assets/javascripts/discourse/app/lib/uppy-checksum-plugin.js
+++ b/app/assets/javascripts/discourse/app/lib/uppy-checksum-plugin.js
@@ -1,6 +1,7 @@
 import { UploadPreProcessorPlugin } from "discourse/lib/uppy-plugin-base";
 import { Promise } from "rsvp";
 import { HUGE_FILE_THRESHOLD_BYTES } from "discourse/mixins/uppy-upload";
+import { bind } from "discourse-common/utils/decorators";
 
 export default class UppyChecksum extends UploadPreProcessorPlugin {
   static pluginId = "uppy-checksum";
@@ -33,6 +34,7 @@ export default class UppyChecksum extends UploadPreProcessorPlugin {
     return true;
   }
 
+  @bind
   _generateChecksum(fileIds) {
     if (!this._canUseSubtleCrypto()) {
       return this._skipAll(fileIds, true);
@@ -85,14 +87,14 @@ export default class UppyChecksum extends UploadPreProcessorPlugin {
   }
 
   _hasCryptoCipher() {
-    return window.crypto && window.crypto.subtle && window.crypto.subtle.digest;
+    return window.crypto?.subtle?.digest;
   }
 
   install() {
-    this._install(this._generateChecksum.bind(this));
+    this._install(this._generateChecksum);
   }
 
   uninstall() {
-    this._uninstall(this._generateChecksum.bind(this));
+    this._uninstall(this._generateChecksum);
   }
 }
diff --git a/app/assets/javascripts/discourse/app/lib/uppy-media-optimization-plugin.js b/app/assets/javascripts/discourse/app/lib/uppy-media-optimization-plugin.js
index 15ba5aa..b8e037f 100644
--- a/app/assets/javascripts/discourse/app/lib/uppy-media-optimization-plugin.js
+++ b/app/assets/javascripts/discourse/app/lib/uppy-media-optimization-plugin.js
@@ -1,5 +1,6 @@
 import { UploadPreProcessorPlugin } from "discourse/lib/uppy-plugin-base";
 import { Promise } from "rsvp";
+import { bind } from "discourse-common/utils/decorators";
 
 export default class UppyMediaOptimization extends UploadPreProcessorPlugin {
   static pluginId = "uppy-media-optimization";
@@ -15,6 +16,7 @@ export default class UppyMediaOptimization extends UploadPreProcessorPlugin {
     this.runParallel = opts.runParallel || false;
   }
 
+  @bind
   _optimizeFile(fileId) {
     let file = this._getFile(fileId);
 
@@ -42,13 +44,15 @@ export default class UppyMediaOptimization extends UploadPreProcessorPlugin {
       });
   }
 
+  @bind
   _optimizeParallel(fileIds) {
-    return Promise.all(fileIds.map(this._optimizeFile.bind(this)));
+    return Promise.all(fileIds.map(this._optimizeFile));
   }
 
+  @bind
   async _optimizeSerial(fileIds) {
     let optimizeTasks = fileIds.map((fileId) => () =>
-      this._optimizeFile.call(this, fileId)
+      this._optimizeFile(fileId)
     );
 
     for (const task of optimizeTasks) {
@@ -58,17 +62,17 @@ export default class UppyMediaOptimization extends UploadPreProcessorPlugin {
 
   install() {
     if (this.runParallel) {
-      this._install(this._optimizeParallel.bind(this));
+      this._install(this._optimizeParallel);
     } else {
-      this._install(this._optimizeSerial.bind(this));
+      this._install(this._optimizeSerial);
     }
   }
 
   uninstall() {
     if (this.runParallel) {
-      this._uninstall(this._optimizeParallel.bind(this));
+      this._uninstall(this._optimizeParallel);
     } else {

[... diff too long, it was truncated ...]

GitHub sha: f0d963faad0e3e848ac06ba045223ae5ad4cbb13

This commit appears in #14931 which was approved by jjaffeux. It was merged by CvX.