From 976934a36c8efde01c31ed38cafec7340562e6f4 Mon Sep 17 00:00:00 2001 From: Markus Klein <markus.klein@typo3.org> Date: Mon, 27 Mar 2017 15:51:07 +0200 Subject: [PATCH] [BUGFIX] JS: Fix FormEngine initialization 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> --- .../Classes/Form/FormResultCompiler.php | 7 ++-- .../Private/TypeScript/FormEngineReview.ts | 8 ++-- .../Resources/Public/JavaScript/FormEngine.js | 38 +++++++++++-------- .../Public/JavaScript/FormEngineReview.js | 4 +- .../Public/JavaScript/FormEngineValidation.js | 4 -- 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/typo3/sysext/backend/Classes/Form/FormResultCompiler.php b/typo3/sysext/backend/Classes/Form/FormResultCompiler.php index 97d70bcadebf..1b6da7eda5c9 100644 --- a/typo3/sysext/backend/Classes/Form/FormResultCompiler.php +++ b/typo3/sysext/backend/Classes/Form/FormResultCompiler.php @@ -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; diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngineReview.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngineReview.ts index 284b4a68e9ea..b20651c3f503 100644 --- a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngineReview.ts +++ b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngineReview.ts @@ -13,10 +13,10 @@ /// <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); } /** diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js index d776cacbe7c1..0923267dcc9d 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js @@ -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(); } }; @@ -1125,14 +1114,33 @@ define(['jquery', document.editform.submit(); }; + /** + * 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']) { diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineReview.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineReview.js index 8d7f6d36d2b5..aebaa6422419 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineReview.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineReview.js @@ -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 diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineValidation.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineValidation.js index b2c16fa374b9..13810fde11ec 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineValidation.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineValidation.js @@ -1036,9 +1036,5 @@ define(['jquery', 'moment'], function ($, moment) { return result; }; - FormEngineValidation.registerReady = function() { - FormEngineValidation.initialize(); - }; - return FormEngineValidation; }); -- GitLab