[BUGFIX] JS: Fix FormEngine initialization 80/52180/7
authorMarkus Klein <markus.klein@typo3.org>
Mon, 27 Mar 2017 13:51:07 +0000 (15:51 +0200)
committerFrank Naegler <frank.naegler@typo3.org>
Wed, 29 Mar 2017 11:14:49 +0000 (13:14 +0200)
The FormEngine initialization process needs to be very careful
when the DOM is accessed.
This patch separates the routines and encapsulates those in
a DOMready handler, which are critical.

This solves a possible race condition when JS is executed faster
than DOM is built.

Releases: master, 7.6
Resolves: #80481
Resolves: #80366
Change-Id: I205aebc9f87a25f06942f923497f7f535fdb0c8f
Reviewed-on: https://review.typo3.org/52180
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Reviewed-by: Thomas Maroschik <tmaroschik@dfau.de>
Tested-by: Thomas Maroschik <tmaroschik@dfau.de>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
typo3/sysext/backend/Classes/Form/FormResultCompiler.php
typo3/sysext/backend/Resources/Private/TypeScript/FormEngineReview.ts
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js
typo3/sysext/backend/Resources/Public/JavaScript/FormEngineReview.js
typo3/sysext/backend/Resources/Public/JavaScript/FormEngineValidation.js

index 97d70bc..1b6da7e 100644 (file)
@@ -214,9 +214,10 @@ class FormResultCompiler
         $pageRenderer->addJsFile('EXT:backend/Resources/Public/JavaScript/md5.js');
         // load the main module for FormEngine with all important JS functions
         $this->requireJsModules['TYPO3/CMS/Backend/FormEngine'] = 'function(FormEngine) {
-                       FormEngine.setBrowserUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('wizard_element_browser')) . ');
-                       FormEngine.Validation.setUsMode(' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0') . ');
-                       FormEngine.Validation.registerReady();
+                       FormEngine.initialize(
+                               ' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('wizard_element_browser')) . ',
+                               ' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0') . '
+                       );
                }';
         $this->requireJsModules['TYPO3/CMS/Backend/FormEngineReview'] = null;
 
index 284b4a6..b20651c 100644 (file)
 
 /// <amd-dependency path="bootstrap">
 
-// todo: once FormEngineValidation is a native TypeScript class, we can use require() instead
+// todo: once FormEngine is a native TypeScript class, we can use require() instead
 // and drop amd-dependency and declare
-/// <amd-dependency path="TYPO3/CMS/Backend/FormEngineValidation" name="FormEngineValidation">
-declare let FormEngineValidation: any;
+/// <amd-dependency path="TYPO3/CMS/Backend/FormEngine" name="FormEngine">
+declare let FormEngine: any;
 declare let TYPO3: any;
 
 import $ = require('jquery');
@@ -33,7 +33,7 @@ class FormEngineReview {
      * @return {$}
      */
     public static findInvalidField(): any {
-        return $(document).find('.tab-content .' + FormEngineValidation.errorClass);
+        return $(document).find('.tab-content .' + FormEngine.Validation.errorClass);
     }
 
     /**
index d776cac..0923267 100644 (file)
@@ -38,7 +38,7 @@ define(['jquery',
 
        /**
         *
-        * @type {{formName: *, openedPopupWindow: window, legacyFieldChangedCb: Function, browserUrl: string}}
+        * @type {{Validation: object, formName: *, openedPopupWindow: window, legacyFieldChangedCb: Function, browserUrl: string}}
         * @exports TYPO3/CMS/Backend/FormEngine
         */
        var FormEngine = {
@@ -49,14 +49,6 @@ define(['jquery',
                browserUrl: ''
        };
 
-       /**
-        *
-        * @param {String} browserUrl
-        */
-       FormEngine.setBrowserUrl = function(browserUrl) {
-               FormEngine.browserUrl = browserUrl;
-       };
-
        // functions to connect the db/file browser with this document and the formfields on it!
 
        /**
@@ -589,9 +581,6 @@ define(['jquery',
         * as it using deferrer methods only
         */
        FormEngine.initializeEvents = function() {
-
-               FormEngine.initializeSelectCheckboxes();
-
                $(document).on('click', '.t3js-btn-moveoption-top, .t3js-btn-moveoption-up, .t3js-btn-moveoption-down, .t3js-btn-moveoption-bottom, .t3js-btn-removeoption', function(evt) {
                        evt.preventDefault();
 
@@ -1089,7 +1078,7 @@ define(['jquery',
                                }
                        });
                } else {
-                       FormEngine.closeDocument()
+                       FormEngine.closeDocument();
                }
        };
 
@@ -1126,13 +1115,32 @@ define(['jquery',
        };
 
        /**
+        * Main init function called from outside
+        *
+        * Sets some options and registers the DOMready handler to initialize further things
+        *
+        * @param {String} browserUrl
+        * @param {Number} mode
+        */
+       FormEngine.initialize = function(browserUrl, mode) {
+               FormEngine.browserUrl = browserUrl;
+               FormEngine.Validation.setUsMode(mode);
+
+               $(function() {
+                       FormEngine.initializeSelectCheckboxes();
+                       FormEngine.Validation.initialize();
+                       FormEngine.reinitialize();
+               });
+       };
+
+       /**
         * initialize function, always require possible post-render hooks return the main object
         */
 
-       // the functions are both using delegates, thus no need to be called again
+       // the events are only bound to the document, which is already present for sure.
+       // no need to have it in DOMready handler
        FormEngine.initializeEvents();
        FormEngine.SelectBoxFilter.initializeEvents();
-       FormEngine.reinitialize();
 
        // load required modules to hook in the post initialize function
        if (undefined !== TYPO3.settings.RequireJS && undefined !== TYPO3.settings.RequireJS.PostInitializationModules['TYPO3/CMS/Backend/FormEngine']) {
index 8d7f6d3..aebaa64 100644 (file)
@@ -10,7 +10,7 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require", "exports", "TYPO3/CMS/Backend/FormEngineValidation", "jquery", "bootstrap"], function (require, exports, FormEngineValidation, $) {
+define(["require", "exports", "TYPO3/CMS/Backend/FormEngine", "jquery", "bootstrap"], function (require, exports, FormEngine, $) {
     "use strict";
     /**
      * Module: TYPO3/CMS/Backend/FormEngineReview
@@ -85,7 +85,7 @@ define(["require", "exports", "TYPO3/CMS/Backend/FormEngineValidation", "jquery"
          * @return {$}
          */
         FormEngineReview.findInvalidField = function () {
-            return $(document).find('.tab-content .' + FormEngineValidation.errorClass);
+            return $(document).find('.tab-content .' + FormEngine.Validation.errorClass);
         };
         /**
          * Renders an invisible button to toggle the review panel into the least possible toolbar
index b2c16fa..13810fd 100644 (file)
@@ -1036,9 +1036,5 @@ define(['jquery', 'moment'], function ($, moment) {
                return result;
        };
 
-       FormEngineValidation.registerReady = function() {
-               FormEngineValidation.initialize();
-       };
-
        return FormEngineValidation;
 });