From 153ba2d962c32093429965f197d0d9f81f17f3bb Mon Sep 17 00:00:00 2001 From: Philipp Kitzberger Date: Tue, 30 Jul 2024 18:46:00 +0200 Subject: [PATCH 1/3] [DOCUMENTATION] Fix typo --- Resources/Private/Build/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Private/Build/readme.md b/Resources/Private/Build/readme.md index fcbf7cb..71691f8 100644 --- a/Resources/Private/Build/readme.md +++ b/Resources/Private/Build/readme.md @@ -2,7 +2,7 @@ ## Small guide -* Go to Recources/Private/Build +* Go to Resources/Private/Build * `nvm use` will change to needed npm version * `npm i` will install the node modules (if not yet installed) * Then start with `npm run build` or the watch task with `npm run watch` From 868fe17076fa7b13eb389f7350443b035d6f5539 Mon Sep 17 00:00:00 2001 From: Philipp Kitzberger Date: Tue, 30 Jul 2024 18:52:46 +0200 Subject: [PATCH 2/3] [TASK] Implement way to reduce initial flickering --- Classes/Controller/ConditionController.php | 78 ++---------------- Classes/Service/ConditionService.php | 81 +++++++++++++++++++ Classes/ViewHelpers/ConditionsViewHelper.php | 49 +++++++++++ .../Build/JavaScript/PowermailConditions.js | 22 ++++- .../JavaScript/PowermailCondition.min.js | 2 +- readme.md | 18 +++++ 6 files changed, 178 insertions(+), 72 deletions(-) create mode 100644 Classes/Service/ConditionService.php create mode 100644 Classes/ViewHelpers/ConditionsViewHelper.php diff --git a/Classes/Controller/ConditionController.php b/Classes/Controller/ConditionController.php index 1b97fa3..bfa8d91 100644 --- a/Classes/Controller/ConditionController.php +++ b/Classes/Controller/ConditionController.php @@ -4,44 +4,21 @@ namespace In2code\PowermailCond\Controller; -use function array_key_exists; -use In2code\Powermail\Domain\Model\Field; -use In2code\Powermail\Domain\Model\Form; -use In2code\Powermail\Domain\Model\Page; -use In2code\Powermail\Domain\Repository\FormRepository; -use In2code\PowermailCond\Domain\Repository\ConditionContainerRepository; -use In2code\PowermailCond\Exception\MissingPowermailParameterException; -use In2code\PowermailCond\Exception\UnsupportedVariableTypeException; -use function is_array; -use function is_string; -use function json_encode; -use const JSON_THROW_ON_ERROR; +use In2code\PowermailCond\Service\ConditionService; use Psr\Http\Message\ResponseInterface; use Throwable; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; -use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; + +use const JSON_THROW_ON_ERROR; +use function json_encode; class ConditionController extends ActionController { - protected FormRepository $formRepository; + protected ConditionService $conditionService; - protected ConditionContainerRepository $conditionContainerRepository; - - protected TypoScriptFrontendController $typoscriptFrontendController; - - public function __construct() + public function injectConditionService(ConditionService $conditionService): void { - $this->typoscriptFrontendController = $GLOBALS['TSFE']; - } - - public function injectFormRepository(FormRepository $formRepository): void - { - $this->formRepository = $formRepository; - } - - public function injectConditionContainerRepository(ConditionContainerRepository $conditionContainerRepository): void - { - $this->conditionContainerRepository = $conditionContainerRepository; + $this->conditionService = $conditionService; } /** @@ -52,47 +29,8 @@ public function injectConditionContainerRepository(ConditionContainerRepository public function buildConditionAction(): ResponseInterface { $requestBody = $this->request->getParsedBody(); - if (empty($requestBody['tx_powermail_pi1']['mail']['form'])) { - throw new MissingPowermailParameterException(); - } - $powermailArguments = $requestBody['tx_powermail_pi1']; - unset($powermailArguments['__referrer'], $powermailArguments['__trustedProperties']); - - /** @var Form $form */ - $form = $this->formRepository->findByIdentifier($powermailArguments['mail']['form']); - - /** @var array $fields */ - $fields = []; - - /** @var Page $page */ - foreach ($form->getPages() as $page) { - /** @var Field $field */ - foreach ($page->getFields() as $field) { - $fields[$field->getMarker()] = $field; - } - } - - foreach ($powermailArguments['field'] as $fieldName => $fieldValue) { - if (!array_key_exists($fieldName, $fields)) { - continue; - } - if (is_array($fieldValue)) { - $fieldValue = json_encode($fieldValue, JSON_THROW_ON_ERROR); - } - if (!is_string($fieldValue)) { - throw new UnsupportedVariableTypeException(); - } - $fields[$fieldName]->setText($fieldValue); - } - $arguments = []; - // Use the forms non-localized UID, because the field is l10n_mode exclude - $conditionContainer = $this->conditionContainerRepository->findOneByForm($form->getUid()); - if ($conditionContainer !== null) { - $arguments = $conditionContainer->applyConditions($form, $powermailArguments); - $this->typoscriptFrontendController->fe_user->setAndSaveSessionData('tx_powermail_cond', $arguments); - unset($arguments['backup'], $arguments['field']); - } + $arguments = $this->conditionService->getArguments($requestBody['tx_powermail_pi1']); return $this->jsonResponse(json_encode($arguments, JSON_THROW_ON_ERROR)); } diff --git a/Classes/Service/ConditionService.php b/Classes/Service/ConditionService.php new file mode 100644 index 0000000..406e6fe --- /dev/null +++ b/Classes/Service/ConditionService.php @@ -0,0 +1,81 @@ +typoscriptFrontendController = $GLOBALS['TSFE']; + } + + public function injectFormRepository(FormRepository $formRepository): void + { + $this->formRepository = $formRepository; + } + + public function injectConditionContainerRepository(ConditionContainerRepository $conditionContainerRepository): void + { + $this->conditionContainerRepository = $conditionContainerRepository; + } + + public function getArguments(array $powermailArguments = []): array + { + if (empty($powermailArguments['mail']['form'])) { + throw new MissingPowermailParameterException(); + } + + unset($powermailArguments['__referrer'], $powermailArguments['__trustedProperties']); + + /** @var Form $form */ + $form = $this->formRepository->findByIdentifier($powermailArguments['mail']['form']); + + /** @var array $fields */ + $fields = []; + + /** @var Page $page */ + foreach ($form->getPages() as $page) { + /** @var Field $field */ + foreach ($page->getFields() as $field) { + $fields[$field->getMarker()] = $field; + } + } + + foreach ($powermailArguments['field'] ?? [] as $fieldName => $fieldValue) { + if (!array_key_exists($fieldName, $fields)) { + continue; + } + if (is_array($fieldValue)) { + $fieldValue = json_encode($fieldValue, JSON_THROW_ON_ERROR); + } + if (!is_string($fieldValue)) { + throw new UnsupportedVariableTypeException(); + } + $fields[$fieldName]->setText($fieldValue); + } + + $arguments = []; + // Use the forms non-localized UID, because the field is l10n_mode exclude + $conditionContainer = $this->conditionContainerRepository->findOneByForm($form->getUid()); + if ($conditionContainer !== null) { + $arguments = $conditionContainer->applyConditions($form, $powermailArguments); + $this->typoscriptFrontendController->fe_user->setAndSaveSessionData('tx_powermail_cond', $arguments); + unset($arguments['backup'], $arguments['field']); + } + + return $arguments; + } +} diff --git a/Classes/ViewHelpers/ConditionsViewHelper.php b/Classes/ViewHelpers/ConditionsViewHelper.php new file mode 100644 index 0000000..eaf0d5d --- /dev/null +++ b/Classes/ViewHelpers/ConditionsViewHelper.php @@ -0,0 +1,49 @@ +conditionService = $conditionService; + } + + public function initializeArguments() + { + parent::initializeArguments(); + $this->registerArgument('form', Form::class, 'Form', true); + } + + /** + * Returns Data Attribute Array to enable validation + * + * @return string + */ + public function render(): string + { + /** @var Form $field */ + $form = $this->arguments['form']; + + if ($this->renderingContext->getRequest()->getParsedBody()) { + $params = $this->renderingContext->getRequest()->getParsedBody()['tx_powermail_pi1']; + } else { + $params = ['mail' => ['form' => $form->getUid()]]; + } + + $arguments = $this->conditionService->getArguments($params); + + return json_encode($arguments, JSON_THROW_ON_ERROR); + } +} diff --git a/Resources/Private/Build/JavaScript/PowermailConditions.js b/Resources/Private/Build/JavaScript/PowermailConditions.js index 6136a9c..67b033e 100644 --- a/Resources/Private/Build/JavaScript/PowermailConditions.js +++ b/Resources/Private/Build/JavaScript/PowermailConditions.js @@ -15,7 +15,19 @@ class PowermailConditions { initialize = function () { const that = this; - that.#sendFormValuesToPowermailCond(); + + let formUid = this.#form.querySelector('input.powermail_form_uid').value; + let formActionSelector = '#form-' + formUid + '-actions'; + + if (document.querySelector(formActionSelector) === null) { + // Loading conditions via AJAX + that.#sendFormValuesToPowermailCond(); + } else { + // Using prerendered conditions + let actions = JSON.parse(document.querySelector(formActionSelector).textContent); + that.#processActions(actions); + } + that.#fieldListener(); } @@ -72,6 +84,14 @@ class PowermailConditions { } } } + let fieldsets = this.#form.querySelectorAll('.powermail_fieldset'); + fieldsets.forEach(function(fieldset) { + if (window.getComputedStyle(fieldset).visibility === 'hidden') { + // Making initially invisible fieldset visible + fieldset.style.visibility = 'visible'; + fieldset.style.opacity = 1; + } + }); }; #enableAllFields() { diff --git a/Resources/Public/JavaScript/PowermailCondition.min.js b/Resources/Public/JavaScript/PowermailCondition.min.js index 293bcf2..a0c363d 100644 --- a/Resources/Public/JavaScript/PowermailCondition.min.js +++ b/Resources/Public/JavaScript/PowermailCondition.min.js @@ -1 +1 @@ -!function(){"use strict";function t(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function e(t,e){for(var i=0;i99?console.log("Too much loops reached by parsing conditions and rules. Check for conflicting conditions."):u(t,p,O).call(t,e)})).catch((function(t){console.log(t)}))}function O(t){if(void 0!==t.todo)for(var e in t.todo)for(var i in t.todo[e])for(var n in"hide"===t.todo[e][i]["#action"]&&u(this,k,G).call(this,u(this,j,U).call(this,i)),"un_hide"===t.todo[e][i]["#action"]&&u(this,g,B).call(this,u(this,j,U).call(this,i)),t.todo[e][i])"hide"===t.todo[e][i][n]["#action"]&&u(this,S,N).call(this,n),"un_hide"===t.todo[e][i][n]["#action"]&&u(this,y,L).call(this,n)}function x(){o(this,h).querySelectorAll('[disabled="disabled"]').forEach((function(t){t.removeAttribute("disabled")}))}function D(){return o(this,h).querySelectorAll('input:not([data-powermail-validation="disabled"]):not([type="hidden"]):not([type="submit"]), textarea:not([data-powermail-validation="disabled"]), select:not([data-powermail-validation="disabled"])')}function F(){var t=document.querySelector("[data-condition-uri]");return null===t&&console.log("Tag with data-condition-uri not found. Maybe TypoScript was not included."),t.getAttribute("data-condition-uri")}function L(t){var e=u(this,_,Q).call(this,t);null!==e&&d.showElement(e);var i=u(this,T,R).call(this,t);null!==i&&(i.removeAttribute("disabled"),u(this,W,I).call(this,i))}function N(t){var e=u(this,_,Q).call(this,t);null!==e&&d.hideElement(e);var i=u(this,T,R).call(this,t);null!==i&&(i.setAttribute("disabled","disabled"),u(this,q,H).call(this,i))}function B(t){d.showElement(t)}function G(t){d.hideElement(t)}function H(t){(t.hasAttribute("required")||t.hasAttribute("data-powermail-required"))&&(t.removeAttribute("required"),t.removeAttribute("data-powermail-required"),t.setAttribute("data-powermailcond-required","required"))}function I(t){"required"===t.getAttribute("data-powermailcond-required")&&(u(this,E,K).call(this)||u(this,A,J).call(this))&&t.setAttribute("required","required"),t.removeAttribute("data-powermailcond-required")}function J(){return"data-powermail-validate"===o(this,h).getAttribute("data-powermail-validate")}function K(){return"html5"===o(this,h).getAttribute("data-validate")}function Q(t){var e=u(this,C,V).call(this,t);if(null!==e)return e;var i=u(this,T,R).call(this,t);if(null!==i){var n=i.closest(".powermail_fieldwrap");if(null!==n)return n}return console.log('Error: Could not find field by fieldMarker "'+t+'"'),null}function R(t){var e="tx_powermail_pi1[field]["+t+"]";return o(this,h).querySelector('[name="'+e+'"]:not([type="hidden"])')||o(this,h).querySelector('[name="'+e+'[]"]')}function U(t){return o(this,h).querySelector(".powermail_fieldset_"+t)}function V(t){return o(this,h).querySelector(".powermail_fieldwrap_"+t)}document.querySelectorAll(".powermail_form").forEach((function(t){new P(t).initialize()}))}(); +!function(){"use strict";function t(t,e,i){if("function"==typeof t?t===e:t.has(e))return arguments.length<3?e:i;throw new TypeError("Private element is not present on this object")}function e(t,e){if(e.has(t))throw new TypeError("Cannot initialize the same private elements twice on an object")}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(e,i){return e.get(t(e,i))}function r(t,e){for(var i=0;i99?console.log("Too much loops reached by parsing conditions and rules. Check for conflicting conditions."):t(s,e,m).call(e,i)})).catch((function(t){console.log(t)}))}function m(e){if(void 0!==e.todo)for(var i in e.todo)for(var r in e.todo[i])for(var o in"hide"===e.todo[i][r]["#action"]&&t(s,this,g).call(this,t(s,this,C).call(this,r)),"un_hide"===e.todo[i][r]["#action"]&&t(s,this,q).call(this,t(s,this,C).call(this,r)),e.todo[i][r])"hide"===e.todo[i][r][o]["#action"]&&t(s,this,w).call(this,o),"un_hide"===e.todo[i][r][o]["#action"]&&t(s,this,y).call(this,o);n(c,this).querySelectorAll(".powermail_fieldset").forEach((function(t){"hidden"===window.getComputedStyle(t).visibility&&(t.style.visibility="visible",t.style.opacity=1)}))}function p(){n(c,this).querySelectorAll('[disabled="disabled"]').forEach((function(t){t.removeAttribute("disabled")}))}function v(){return n(c,this).querySelectorAll('input:not([data-powermail-validation="disabled"]):not([type="hidden"]):not([type="submit"]), textarea:not([data-powermail-validation="disabled"]), select:not([data-powermail-validation="disabled"])')}function b(){var t=document.querySelector("[data-condition-uri]");return null===t&&console.log("Tag with data-condition-uri not found. Maybe TypoScript was not included."),t.getAttribute("data-condition-uri")}function y(e){var i=t(s,this,j).call(this,e);null!==i&&u.showElement(i);var n=t(s,this,k).call(this,e);null!==n&&(n.removeAttribute("disabled"),t(s,this,S).call(this,n))}function w(e){var i=t(s,this,j).call(this,e);null!==i&&u.hideElement(i);var n=t(s,this,k).call(this,e);null!==n&&(n.setAttribute("disabled","disabled"),t(s,this,A).call(this,n))}function q(t){u.showElement(t)}function g(t){u.hideElement(t)}function A(t){(t.hasAttribute("required")||t.hasAttribute("data-powermail-required"))&&(t.removeAttribute("required"),t.removeAttribute("data-powermail-required"),t.setAttribute("data-powermailcond-required","required"))}function S(e){"required"===e.getAttribute("data-powermailcond-required")&&(t(s,this,_).call(this)||t(s,this,E).call(this))&&e.setAttribute("required","required"),e.removeAttribute("data-powermailcond-required")}function E(){return"data-powermail-validate"===n(c,this).getAttribute("data-powermail-validate")}function _(){return"html5"===n(c,this).getAttribute("data-validate")}function j(e){var i=t(s,this,T).call(this,e);if(null!==i)return i;var n=t(s,this,k).call(this,e);if(null!==n){var r=n.closest(".powermail_fieldwrap");if(null!==r)return r}return console.log('Error: Could not find field by fieldMarker "'+e+'"'),null}function k(t){var e="tx_powermail_pi1[field]["+t+"]";return n(c,this).querySelector('[name="'+e+'"]:not([type="hidden"])')||n(c,this).querySelector('[name="'+e+'[]"]')}function C(t){return n(c,this).querySelector(".powermail_fieldset_"+t)}function T(t){return n(c,this).querySelector(".powermail_fieldwrap_"+t)}document.querySelectorAll(".powermail_form").forEach((function(t){new d(t).initialize()}))}(); diff --git a/readme.md b/readme.md index a5e9b0f..b8edf7d 100644 --- a/readme.md +++ b/readme.md @@ -62,6 +62,24 @@ routeEnhancers: There is a docker based local development environment available. See [Readme.md](Documentation/ForDevelopers/Readme.md) for more information. +## Less flickering + +To prevent the flickering that occurs when loading a form with conditions the usually asynchronously loaded "condition JSON" can be rendered directly into the HTML source code via this viewhelper in your copy of `EXT:powermail/Resources/Private/Templates/Form/Form.html` + +```xml +{namespace pc=In2code\PowermailCond\ViewHelpers} + + +``` + +This way the initial asynchronous call will be skipped which reduces the flickering to a minimum. + ## Early Access Programm (EAP) You can support the development via our EAP on https://www.in2code.de/en/agency/typo3-extensions/early-access-program/ From b4e1ad464bcb07ad7c8835ce7499f18052744ab4 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Wed, 2 Oct 2024 11:21:20 +0200 Subject: [PATCH 3/3] [TASK] Fix PHP codestyle --- Classes/Controller/ConditionController.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Classes/Controller/ConditionController.php b/Classes/Controller/ConditionController.php index bfa8d91..27fe655 100644 --- a/Classes/Controller/ConditionController.php +++ b/Classes/Controller/ConditionController.php @@ -5,13 +5,12 @@ namespace In2code\PowermailCond\Controller; use In2code\PowermailCond\Service\ConditionService; +use function json_encode; +use const JSON_THROW_ON_ERROR; use Psr\Http\Message\ResponseInterface; use Throwable; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; -use const JSON_THROW_ON_ERROR; -use function json_encode; - class ConditionController extends ActionController { protected ConditionService $conditionService;