From 6258447e3fea3d934d4cfb173b70be725d1d140a Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Wed, 8 Feb 2017 18:52:35 +0100
Subject: [PATCH] [BUGFIX] PageTree: Re-introduce queueing

With the removal of the ExtJS state providers, the polyfill
`TYPO3ExtJSStateProviderBridge` with a limited functional subset was
introduced. Previously, changes were queued to reduce the amount of
requests, which got lost since then. This was a complex workaround in
first place and the real issue that the same data is sent *per node*
lies somewhere deep in ExtJS and was never fixed.

As we aim to get rid of the last pieces of ExtJS sooner than later, the
queueing mechanism is added again keep the load low and to worship our
servers.

Resolves: #79693
Related: #79227
Releases: master
Change-Id: Ibcccd9be183437192027cbfab634515f710728c6
Reviewed-on: https://review.typo3.org/51591
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Thomas Hohn <thomas@hohn.dk>
Tested-by: Thomas Hohn <thomas@hohn.dk>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Reviewed-by: Markus Sommer <markussom@posteo.de>
Tested-by: Markus Sommer <markussom@posteo.de>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
---
 .../Classes/Controller/BackendController.php  | 70 ++++++++++++++++++-
 1 file changed, 68 insertions(+), 2 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Controller/BackendController.php b/typo3/sysext/backend/Classes/Controller/BackendController.php
index a8570b0bc22d..4960865914a0 100644
--- a/typo3/sysext/backend/Classes/Controller/BackendController.php
+++ b/typo3/sysext/backend/Classes/Controller/BackendController.php
@@ -293,10 +293,31 @@ class BackendController
         $this->pageRenderer->addJsInlineCode('BackendInlineJavascript', $this->js, false);
         $this->loadResourcesForRegisteredNavigationComponents();
         // @todo: remove this when ExtJS is removed
+        $states = $this->getBackendUser()->uc['BackendComponents']['States'];
         $this->pageRenderer->addExtOnReadyCode('
             var TYPO3ExtJSStateProviderBridge = function() {};
             Ext.extend(TYPO3ExtJSStateProviderBridge, Ext.state.Provider, {
+                state: {},
+                queue: [],
+                dirty: false,
                 prefix: "BackendComponents.States.",
+                initState: function(state) {
+                    if (Ext.isArray(state)) {
+                        Ext.each(state, function(item) {
+                            this.state[item.name] = item.value;
+                        }, this);
+                    } else if (Ext.isObject(state)) {
+                        Ext.iterate(state, function(key, value) {
+                            this.state[key] = value;
+                        }, this);
+                    } else {
+                        this.state = {};
+                    }
+                    var me = this;
+                    window.setInterval(function() {
+                        me.submitState(me)
+                    }, 750);
+                },
                 get: function(name, defaultValue) {
                     return TYPO3.Storage.Persistent.isset(this.prefix + name) ? TYPO3.Storage.Persistent.get(this.prefix + name) : defaultValue;
                 },
@@ -304,11 +325,56 @@ class BackendController
                     TYPO3.Storage.Persistent.unset(this.prefix + name);
                 },
                 set: function(name, value) {
-                    TYPO3.Storage.Persistent.set(this.prefix + name, value);
+                    if (!name) {
+                        return;
+                    }
+                    this.queueChange(name, value);
+                },
+                queueChange: function(name, value) {
+                    var o = {};
+                    var i;
+                    var found = false;
+
+                    var lastValue = this.state[name];
+                    for (i = 0; i < this.queue.length; i++) {
+                        if (this.queue[i].name === name) {
+                            lastValue = this.queue[i].value;
+                        }
+                    }
+                    var changed = undefined === lastValue || lastValue !== value;
+
+                    if (changed) {
+                        o.name = name;
+                        o.value = value;
+                        for (i = 0; i < this.queue.length; i++) {
+                            if (this.queue[i].name === o.name) {
+                                this.queue[i] = o;
+                                found = true;
+                            }
+                        }
+                        if (false === found) {
+                            this.queue.push(o);
+                        }
+                        this.dirty = true;
+                    }
+                },
+                submitState: function(context) {
+                    if (!context.dirty) {
+                        return;
+                    }
+                    for (var i = 0; i < context.queue.length; ++i) {
+                        TYPO3.Storage.Persistent.set(context.prefix + context.queue[i].name, context.queue[i].value).done(function() {
+                            if (!context.dirty) {
+                                context.queue = [];
+                            }
+                        });
+                    }
+                    context.dirty = false;
                 }
             });
             Ext.state.Manager.setProvider(new TYPO3ExtJSStateProviderBridge());
-	        ');
+            Ext.state.Manager.getProvider().initState(' . (!empty($states) ? json_encode($states) : []) . ');
+            ');
         // Set document title:
         $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [TYPO3 CMS ' . TYPO3_version . ']' : 'TYPO3 CMS ' . TYPO3_version;
         // Renders the module page
-- 
GitLab