Skip to content

Commit

Permalink
#340 change reload events for form input elements
Browse files Browse the repository at this point in the history
  • Loading branch information
digedag committed Nov 25, 2023
1 parent bc56259 commit a3a0f54
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Classes/Backend/Form/FormBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected function isNEWRecord($uid)
* @param string $uid
* @param array $record should contain pid and other default values for record
*
* @return multitype:
* @return array
*/
protected function compileFormData($table, $uid, $record)
{
Expand Down
82 changes: 54 additions & 28 deletions Classes/Backend/Form/ToolBox.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class ToolBox
public const OPTION_CONFIRM = 'confirm';
public const OPTION_ICON_NAME = 'icon';
public const OPTION_HOVER_TEXT = 'hover';
public const OPTION_HIDE_LABEL = 'hide-label';

public const OPTION_PARAMS = 'params';
public const OPTION_CSS_CLASSES = 'class';
Expand Down Expand Up @@ -576,14 +577,20 @@ public function createHidden($name, $value)
return '<input type="hidden" name="'.$name.'" value="'.htmlspecialchars($value).'" />';
}

/**
* @param string $onclick deprecated wird zukünftig wegen CSP nicht mehr unterstützt
*/
public function createRadio($name, $value, $checked = false, $onclick = '')
{
return '<input type="radio" name="'.$name.'" value="'.htmlspecialchars($value).'" '.($checked ? 'checked="checked"' : '').(strlen($onclick) ? ' onclick="'.$onclick.'"' : '').' />';
return '<input type="radio" class="rnbase-checkbox" name="'.$name.'" value="'.htmlspecialchars($value).'" '.($checked ? 'checked="checked"' : '').(strlen($onclick) ? ' onclick="'.$onclick.'"' : '').' />';
}

/**
* @param string $onclick deprecated wird zukünftig wegen CSP nicht mehr unterstützt
*/
public function createCheckbox($name, $value, $checked = false, $onclick = '')
{
return '<input type="checkbox" name="'.$name.'" value="'.htmlspecialchars($value).'" '.($checked ? 'checked="checked"' : '').(strlen($onclick) ? ' onclick="'.$onclick.'"' : '').' />';
return '<input type="checkbox" class="rnbase-checkbox" name="'.$name.'" value="'.htmlspecialchars($value).'" '.($checked ? 'checked="checked"' : '').(strlen($onclick) ? ' onclick="'.$onclick.'"' : '').' />';
}

/**
Expand Down Expand Up @@ -701,33 +708,27 @@ public function createSubmit($name, $value, $confirmMsg = '', $options = [])
$icon = $icon ? $icon->render() : '';

$class = array_key_exists('class', $options) ? htmlspecialchars($options['class']) : self::CSS_CLASS_BTN;
$class .= ' rnbase-btn';

$attributes = [
'name' => $name,
'value' => $value,
];

$hidden = '';
if (strlen($confirmMsg)) {
$class .= ' t3js-modal-trigger';
$attributes['data-content'] = $confirmMsg;
// Der Name des Submit-Buttons liegt nicht mehr im POST. Deshalb ein extra hidden field.
// Das funktioniert aber erst mal nur, wenn es nur einen Button mit Confirm im Formular gibt.
$hidden = sprintf('<input type="hidden" name="%s" value="1" />', $name);
// Der Name des Submit-Buttons liegt nicht mehr im POST. Deshalb ist zusätzliches JS notwendig.
$this->insertJsToolbox();
}

$attributes['class'] = $class;

$attributesString = T3General::implodeAttributes($attributes, true);

if ($icon) {
$btn = '<button type="submit" '.$attributesString.'>'.
$icon.$value.'</button>';
} else {
$btn = '<input type="submit" '.$attributesString.'/>';
}
$btn = '<button type="submit" '.$attributesString.'>'.$icon.$value.'</button>';

return $btn.$hidden;
return $btn;
}

/**
Expand Down Expand Up @@ -775,17 +776,17 @@ public function createIntInput($name, $value, $width, $maxlength = 10)

/**
* Erstellt ein Eingabefeld für DateTime.
*
* @todo fix prefilling of field in TYPO3 8.7
*/
public function createDateInput($name, $value)
public function createDateInput($name, $value, array $options = [])
{
// Take care of current time zone. Thanks to Thomas Maroschik!
if (Math::isInteger($value) && !TYPO3::isTYPO121OrHigher()) {
$value += date('Z', $value);
}
$this->initializeJavaScriptFormEngine();
$dateElementClass = \TYPO3\CMS\Backend\Form\Element\InputDateTimeElement::class;
$dateElementClass = TYPO3::isTYPO121OrHigher() ?
\TYPO3\CMS\Backend\Form\Element\DatetimeElement::class :
\TYPO3\CMS\Backend\Form\Element\InputDateTimeElement::class;

// [itemFormElName] => data[tx_cfcleague_games][4][status]
// [itemFormElID] => data_tx_cfcleague_games_4_status
Expand Down Expand Up @@ -828,6 +829,16 @@ public function createDateInput($name, $value)
$pageRenderer->loadRequireJsModule($moduleName, $callback);
}
}
} elseif ($renderedElement['javaScriptModules'] ?? null) {
$pageRenderer = $this->getDoc()->getPageRenderer();
foreach ($renderedElement['javaScriptModules'] as $moduleName) {
/* @var \TYPO3\CMS\Core\Page\JavaScriptModuleInstruction $moduleName */
$this->insertJsModule($moduleName->getName());
}
}

if (isset($options[self::OPTION_HIDE_LABEL])) {
$renderedElement['html'] = preg_replace('/<code.*<\/code>/', '', $renderedElement['html']);
}

return $renderedElement['html'];
Expand All @@ -843,17 +854,17 @@ protected function initializeJavaScriptFormEngine()
$usDateFormat = 0;
if (!TYPO3::isTYPO121OrHigher()) {
$usDateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0';
}
$initializeFormEngineCallback = 'function(FormEngine) {
FormEngine.initialize(
'.$moduleUrl.','.$usDateFormat.'
$initializeFormEngineCallback = 'function(FormEngine) {
FormEngine.initialize(
'.$moduleUrl.','.$usDateFormat.'
);
}';

$this->getDoc()->getPageRenderer()->loadRequireJsModule(
'TYPO3/CMS/Backend/FormEngine',
$initializeFormEngineCallback
);
}';

$this->getDoc()->getPageRenderer()->loadRequireJsModule(
'TYPO3/CMS/Backend/FormEngine',
$initializeFormEngineCallback
);
}
$this->getDoc()->getPageRenderer()->addInlineSetting('FormEngine', 'formName', 'editform');
}

Expand Down Expand Up @@ -900,6 +911,11 @@ public function createSelectSingleByArray($name, $value, $arr, $options = 0)
return $this->createSelectByArray($name, $value, $arr, $options);
}

private function insertJsToolbox()
{
$this->insertJsModule('@sys25/rn_base/toolbox.js');
}

/**
* Erstellt eine Select-Box aus dem übergebenen Array.
* in den Options kann mit dem key reload angegeben werden,
Expand All @@ -921,7 +937,17 @@ public function createSelectByArray($name, $currentValues, array $selectOptions,
$options = is_array($options) ? $options : [];

$attrArr = [];
$onChangeStr = !empty($options['reload']) ? ' this.form.submit(); ' : '';
$onChangeStr = '';
if (!empty($options['reload'])) {
if (TYPO3::isTYPO121OrHigher()) {
$attrArr[] = 'data-global-event="change" data-action-submit="$form"';
} else {
// TODO: fix for older versions
$onChangeStr = ' this.form.submit(); ';
}
$this->insertJsToolbox();
}

if (isset($options['onchange'])) {
$onChangeStr .= $options['onchange'];
}
Expand Down
10 changes: 10 additions & 0 deletions Configuration/JavaScriptModules.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

return [
'dependencies' => [
'backend',
],
'imports' => [
'@sys25/rn_base/' => 'EXT:rn_base/Resources/Public/JavaScript/es6/',
],
];
59 changes: 59 additions & 0 deletions Resources/Public/JavaScript/es6/toolbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import jQuery from 'jquery';


const FormTool = {

init: function() {
const self = this;
// Alle reload Elemente suchen
const elems = document.querySelectorAll('[data-action-submit="$form"][data-global-event]');
elems.forEach(function(elem) {
var event = elem.getAttribute('data-global-event');
elem.addEventListener(event, function() {
// Alle hidden Submit-Buttons suchen und entfernen
// Das ist hier kein Problem, weil sofort der Reload erfolgt
const hiddens = document.querySelectorAll('input[type="hidden"].rnbase-modal-submit-btn')
hiddens.forEach(function(hidden){
if (hidden.form) {
hidden.form.removeChild(hidden);
}
})
});
});
const editForm = document.forms['editform'];

// const btns = document.querySelectorAll('button[type="submit"].rnbase-btn.t3js-modal-trigger, input[type="submit"].rnbase-btn.t3js-modal-trigger');
const btns = document.querySelectorAll('button[type="submit"].rnbase-btn, input[type="submit"].rnbase-btn');
btns.forEach(function(btn) {
btn.addEventListener('click', function(evt) {
const hiddenField = document.querySelector('input[type="hidden"].rnbase-modal-submit-btn');
if (btn.classList.contains('t3js-modal-trigger')) {
// Hole den Namen des Submit-Buttons
hiddenField.name = btn.getAttribute('name');
hiddenField.value = '1';
} else {
hiddenField.name = '_none';
}
})
});
if (editForm) {
// Das hidden-Feld wird den Namen des Submit-Buttons bei Modal-Dialogen schicken
var hiddenField = document.querySelector('input[type="hidden"].rnbase-modal-submit-btn');
if (!hiddenField) {
hiddenField = document.createElement('input');
hiddenField.type = 'hidden';
hiddenField.className = 'rnbase-modal-submit-btn';
hiddenField.name = '_none';

// Füge das hidden-Feld zum Formular hinzu
editForm.appendChild(hiddenField);
}
}

console.info('Toolbox loaded');
}
}

FormTool.init();


23 changes: 19 additions & 4 deletions tests/Classes/Backend/Form/ToolBoxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Sys25\RnBase\Backend\Form;

use Prophecy\PhpUnit\ProphecyTrait;
use Sys25\RnBase\Backend\Template\Override\DocumentTemplate;
use Sys25\RnBase\Testing\BaseTestCase;
use Sys25\RnBase\Utility\TYPO3;
Expand Down Expand Up @@ -39,6 +40,8 @@
*/
class ToolBoxTest extends BaseTestCase
{
use ProphecyTrait;

protected function setUp(): void
{
if (TYPO3::isTYPO90OrHigher()) {
Expand Down Expand Up @@ -86,14 +89,20 @@ public function testCreateSelectByArray()
*/
public function testCreateSelectByArrayIfReloadOption()
{
$formTool = tx_rnbase::makeInstance(ToolBox::class);
/** @var ToolBox $formTool */
$formTool = $this->getMock(ToolBox::class, ['insertJsModule']);
$formTool
->expects(self::once())
->method('insertJsModule')
->with('@sys25/rn_base/toolbox.js');

$select = $formTool->createSelectByArray(
'testSelect',
1,
[1 => 'John', 2 => 'Doe'],
['reload' => true]
);
$expectedSelect = '<select name="testSelect" class="select" onchange=" this.form.submit(); "><option value="1" selected="selected">John</option><option value="2" >Doe</option></select>';
$expectedSelect = '<select name="testSelect" class="select" data-global-event="change" data-action-submit="$form"><option value="1" selected="selected">John</option><option value="2" >Doe</option></select>';

self::assertEquals($expectedSelect, $select);
}
Expand All @@ -120,14 +129,20 @@ public function testCreateSelectByArrayIfOnchangeOption()
*/
public function testCreateSelectByArrayIfReloadAndOnchangeOption()
{
$formTool = tx_rnbase::makeInstance(ToolBox::class);
/** @var ToolBox $formTool */
$formTool = $this->getMock(ToolBox::class, ['insertJsModule']);
$formTool
->expects(self::once())
->method('insertJsModule')
->with('@sys25/rn_base/toolbox.js');

$select = $formTool->createSelectByArray(
'testSelect',
1,
[1 => 'John', 2 => 'Doe'],
['onchange' => 'myJsFunction', 'reload' => true]
);
$expectedSelect = '<select name="testSelect" class="select" onchange=" this.form.submit(); myJsFunction"><option value="1" selected="selected">John</option><option value="2" >Doe</option></select>';
$expectedSelect = '<select name="testSelect" class="select" data-global-event="change" data-action-submit="$form" onchange="myJsFunction"><option value="1" selected="selected">John</option><option value="2" >Doe</option></select>';

self::assertEquals($expectedSelect, $select);
}
Expand Down

0 comments on commit a3a0f54

Please sign in to comment.