From 5cdffd834538f1ca37b141c5c8750099e0682c9e Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Mon, 2 Mar 2020 15:10:06 +0100
Subject: [PATCH] [BUGFIX] Fix binding to `this` in event API

This patch ensures `this` is correctly bound to the triggering element
which is mandatory for event delegation.

Resolves: #90618
Releases: master
Change-Id: Icddcce55bbd62c452ac419d120ef9550b91cb306
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63526
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../Public/TypeScript/Event/DebounceEvent.ts  | 20 ++++++++-----------
 .../Public/TypeScript/Event/ThrottleEvent.ts  |  9 ++++++---
 .../Public/JavaScript/Event/DebounceEvent.js  |  2 +-
 .../Public/JavaScript/Event/ThrottleEvent.js  |  2 +-
 4 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/DebounceEvent.ts b/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/DebounceEvent.ts
index de01e7913608..ae91ef0b949b 100644
--- a/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/DebounceEvent.ts
+++ b/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/DebounceEvent.ts
@@ -27,24 +27,20 @@ class DebounceEvent extends RegularEvent {
   private debounce(callback: Listener, wait: number, immediate: boolean): Listener {
     let timeout: number = null;
 
-    return () => {
-      const context: any = this;
-      const args = arguments;
-      const later = function() {
-        timeout = null;
-        if (!immediate) {
-          callback.apply(context, args);
-        }
-      };
-
+    return function (this: Node, ...args: any[]): void {
       const callNow = immediate && !timeout;
 
       // Reset timeout handler to make sure the callback is executed once
       clearTimeout(timeout);
       if (callNow) {
-        callback.apply(context, args);
+        callback.apply(this, args);
       } else {
-        timeout = setTimeout(later, wait);
+        timeout = setTimeout((): void => {
+          timeout = null;
+          if (!immediate) {
+            callback.apply(this, args);
+          }
+        }, wait);
       }
     };
   }
diff --git a/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/ThrottleEvent.ts b/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/ThrottleEvent.ts
index cbfc6a3f3134..fdedc3796813 100644
--- a/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/ThrottleEvent.ts
+++ b/Build/Sources/TypeScript/core/Resources/Public/TypeScript/Event/ThrottleEvent.ts
@@ -26,16 +26,19 @@ class ThrottleEvent extends RegularEvent {
   private throttle(callback: Listener, limit: number): Listener {
     let wait: boolean = false;
 
-    return () => {
+    return function (this: Node, ...args: any[]): void {
       if (wait) {
         return;
       }
 
-      callback.apply(null, arguments);
+      callback.apply(this, args);
       wait = true;
 
-      setTimeout(function () {
+      setTimeout((): void => {
         wait = false;
+
+        // Wait time is over, execute callback again to have final state
+        callback.apply(this, args);
       }, limit);
     };
   }
diff --git a/typo3/sysext/core/Resources/Public/JavaScript/Event/DebounceEvent.js b/typo3/sysext/core/Resources/Public/JavaScript/Event/DebounceEvent.js
index 31f30023fe42..df1c43b099f5 100644
--- a/typo3/sysext/core/Resources/Public/JavaScript/Event/DebounceEvent.js
+++ b/typo3/sysext/core/Resources/Public/JavaScript/Event/DebounceEvent.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","./RegularEvent"],(function(e,t,n){"use strict";return class extends n{constructor(e,t,n=250,u=!1){super(e,t),this.callback=this.debounce(this.callback,n,u)}debounce(e,t,n){let u=null;return()=>{const c=this,l=arguments,s=function(){u=null,n||e.apply(c,l)},r=n&&!u;clearTimeout(u),r?e.apply(c,l):u=setTimeout(s,t)}}}}));
\ No newline at end of file
+define(["require","exports","./RegularEvent"],(function(e,t,n){"use strict";return class extends n{constructor(e,t,n=250,s=!1){super(e,t),this.callback=this.debounce(this.callback,n,s)}debounce(e,t,n){let s=null;return function(...u){const c=n&&!s;clearTimeout(s),c?e.apply(this,u):s=setTimeout(()=>{s=null,n||e.apply(this,u)},t)}}}}));
\ No newline at end of file
diff --git a/typo3/sysext/core/Resources/Public/JavaScript/Event/ThrottleEvent.js b/typo3/sysext/core/Resources/Public/JavaScript/Event/ThrottleEvent.js
index 82c64f14800c..3cb4e7424f5d 100644
--- a/typo3/sysext/core/Resources/Public/JavaScript/Event/ThrottleEvent.js
+++ b/typo3/sysext/core/Resources/Public/JavaScript/Event/ThrottleEvent.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","./RegularEvent"],(function(t,e,r){"use strict";return class extends r{constructor(t,e,r){super(t,e),this.callback=this.throttle(e,r)}throttle(t,e){let r=!1;return()=>{r||(t.apply(null,arguments),r=!0,setTimeout((function(){r=!1}),e))}}}}));
\ No newline at end of file
+define(["require","exports","./RegularEvent"],(function(t,e,r){"use strict";return class extends r{constructor(t,e,r){super(t,e),this.callback=this.throttle(e,r)}throttle(t,e){let r=!1;return function(...s){r||(t.apply(this,s),r=!0,setTimeout(()=>{r=!1,t.apply(this,s)},e))}}}}));
\ No newline at end of file
-- 
GitLab