diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/GlobalEventHandler.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/GlobalEventHandler.ts new file mode 100644 index 0000000000000000000000000000000000000000..86d12100ea8260d0646769f32bec681c913d056c --- /dev/null +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/GlobalEventHandler.ts @@ -0,0 +1,125 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +type HTMLFormChildElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; + +/** + * Module: TYPO3/CMS/Backend/GlobalEventHandler + * + * + `data-global-event="change"` + * + `data-action-submit="..."` submits form data + * + `$form` parent form element of current element is submitted + * + `<any CSS selector>` queried element is submitted (if implementing HTMLFormElement) + * + `data-action-navigate="..."` navigates to URL + * + `$value` URL taken from value of current element + * + `data-global-event="click"` + * + @todo + * + * @example + * <form action="..." id="..."> + * <input name="name" value="value" data-global-event="change" data-action-submit="$form"> + * </form> + */ +class GlobalEventHandler { + private options = { + onChangeSelector: '[data-global-event="change"]', + onClickSelector: '[data-global-event="click"]', + }; + + constructor() { + this.onReady(() => { + this.registerEvents(); + }); + }; + + private onReady(callback: Function): void { + if (document.readyState === 'complete') { + callback.call(this); + } else { + const delegate = () => { + window.removeEventListener('load', delegate); + document.removeEventListener('DOMContentLoaded', delegate); + callback.call(this); + }; + window.addEventListener('load', delegate); + document.addEventListener('DOMContentLoaded', delegate); + } + } + + private registerEvents(): void { + document.querySelectorAll(this.options.onChangeSelector).forEach((element: HTMLElement) => { + document.addEventListener('change', this.handleChangeEvent.bind(this)); + }); + document.querySelectorAll(this.options.onClickSelector).forEach((element: HTMLElement) => { + document.addEventListener('click', this.handleClickEvent.bind(this)); + }); + } + + private handleChangeEvent(evt: Event): void { + const resolvedTarget = evt.target as HTMLElement; + this.handleSubmitAction(evt, resolvedTarget) + || this.handleNavigateAction(evt, resolvedTarget); + } + + private handleClickEvent(evt: Event): void { + const resolvedTarget = evt.currentTarget as HTMLElement; + } + + private handleSubmitAction(evt: Event, resolvedTarget: HTMLElement): boolean { + const action: string = resolvedTarget.dataset.actionSubmit; + if (!action) { + return false; + } + // @example [data-action-submit]="$form" + if (action === '$form' && this.isHTMLFormChildElement(resolvedTarget)) { + (resolvedTarget as HTMLFormChildElement).form.submit(); + return true; + } + const formCandidate = document.querySelector(action); + if (formCandidate instanceof HTMLFormElement) { + formCandidate.submit(); + return true; + } + return false; + } + + private handleNavigateAction(evt: Event, resolvedTarget: HTMLElement): boolean { + const action: string = resolvedTarget.dataset.actionNavigate; + if (!action) { + return false; + } + const value = this.resolveHTMLFormChildElementValue(resolvedTarget); + if (action === '$value' && value) { + window.location.href = value; + return true; + } + return false; + } + + private isHTMLFormChildElement(element: HTMLElement): boolean { + return element instanceof HTMLSelectElement + || element instanceof HTMLInputElement + || element instanceof HTMLTextAreaElement; + } + + private resolveHTMLFormChildElementValue(element: HTMLElement): string | null { + if (element instanceof HTMLSelectElement) { + return element.options[element.selectedIndex].value; + } else if (element instanceof HTMLInputElement) { + return element.value; + } + return null; + } +} + +export = new GlobalEventHandler(); diff --git a/typo3/sysext/backend/Classes/Template/ModuleTemplate.php b/typo3/sysext/backend/Classes/Template/ModuleTemplate.php index 23f99afe9910fd294a87504e2731f418552f5ab3..2e032a7d2826788024b482d6663089fb25329b98 100644 --- a/typo3/sysext/backend/Classes/Template/ModuleTemplate.php +++ b/typo3/sysext/backend/Classes/Template/ModuleTemplate.php @@ -309,6 +309,7 @@ class ModuleTemplate $this->pageRenderer->enableConcatenateJavascript(); $this->pageRenderer->enableCompressCss(); $this->pageRenderer->enableCompressJavascript(); + $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/GlobalEventHandler'); $languageCode = $this->pageRenderer->getLanguage() === 'default' ? 'en' : $this->pageRenderer->getLanguage(); $this->pageRenderer->setHtmlTag('<html lang="' . htmlspecialchars($languageCode) . '">'); if ($GLOBALS['TYPO3_CONF_VARS']['BE']['debug']) { diff --git a/typo3/sysext/backend/Resources/Private/Partials/Menus/SelectBoxJumpMenu.html b/typo3/sysext/backend/Resources/Private/Partials/Menus/SelectBoxJumpMenu.html index cc1638df0fb892592e9dca3851d9924346f55d3c..e0b82cfebe752c0940e2fa8e365d8bdc54f8fa14 100644 --- a/typo3/sysext/backend/Resources/Private/Partials/Menus/SelectBoxJumpMenu.html +++ b/typo3/sysext/backend/Resources/Private/Partials/Menus/SelectBoxJumpMenu.html @@ -1,5 +1,8 @@ <f:if condition="{menu.menuItems -> f:count()} > 1"> - {menu.label} <select class="form-control t3-js-jumpMenuBox" name="{menu.identifier}" data-menu-identifier="{menu.dataIdentifier}" onchange="if(this.options[this.selectedIndex].value){window.location.href=(this.options[this.selectedIndex].value);}"> + {menu.label} <select class="form-control t3-js-jumpMenuBox" + name="{menu.identifier}" + data-menu-identifier="{menu.dataIdentifier}" + data-global-event="change" data-action-navigate="$value"> <f:for each="{menu.menuItems}" as="menuItem"> <option value="{menuItem.href}" {f:if(condition: '{menuItem.active}', then: ' selected="selected"')}>{menuItem.title}</option> </f:for> diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/GlobalEventHandler.js b/typo3/sysext/backend/Resources/Public/JavaScript/GlobalEventHandler.js new file mode 100644 index 0000000000000000000000000000000000000000..2bf7e9f1e76af98de3426633ddde6109b37fcf32 --- /dev/null +++ b/typo3/sysext/backend/Resources/Public/JavaScript/GlobalEventHandler.js @@ -0,0 +1,13 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ +define(["require","exports"],(function(e,t){"use strict";return new class{constructor(){this.options={onChangeSelector:'[data-global-event="change"]',onClickSelector:'[data-global-event="click"]'},this.onReady(()=>{this.registerEvents()})}onReady(e){if("complete"===document.readyState)e.call(this);else{const t=()=>{window.removeEventListener("load",t),document.removeEventListener("DOMContentLoaded",t),e.call(this)};window.addEventListener("load",t),document.addEventListener("DOMContentLoaded",t)}}registerEvents(){document.querySelectorAll(this.options.onChangeSelector).forEach(e=>{document.addEventListener("change",this.handleChangeEvent.bind(this))}),document.querySelectorAll(this.options.onClickSelector).forEach(e=>{document.addEventListener("click",this.handleClickEvent.bind(this))})}handleChangeEvent(e){const t=e.target;this.handleSubmitAction(e,t)||this.handleNavigateAction(e,t)}handleClickEvent(e){e.currentTarget}handleSubmitAction(e,t){const n=t.dataset.actionSubmit;if(!n)return!1;if("$form"===n&&this.isHTMLFormChildElement(t))return t.form.submit(),!0;const o=document.querySelector(n);return o instanceof HTMLFormElement&&(o.submit(),!0)}handleNavigateAction(e,t){const n=t.dataset.actionNavigate;if(!n)return!1;const o=this.resolveHTMLFormChildElementValue(t);return!("$value"!==n||!o)&&(window.location.href=o,!0)}isHTMLFormChildElement(e){return e instanceof HTMLSelectElement||e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement}resolveHTMLFormChildElementValue(e){return e instanceof HTMLSelectElement?e.options[e.selectedIndex].value:e instanceof HTMLInputElement?e.value:null}}})); \ No newline at end of file diff --git a/typo3/sysext/belog/Classes/Controller/BackendLogController.php b/typo3/sysext/belog/Classes/Controller/BackendLogController.php index 13dc1df9084ecbdd02990fd2fe8aab7c5626182f..8326969ef7ef2f65cac1c53123e9bd96c2b14787 100644 --- a/typo3/sysext/belog/Classes/Controller/BackendLogController.php +++ b/typo3/sysext/belog/Classes/Controller/BackendLogController.php @@ -15,10 +15,11 @@ namespace TYPO3\CMS\Belog\Controller; -use TYPO3\CMS\Backend\View\BackendTemplateView; use TYPO3\CMS\Belog\Domain\Model\Constraint; use TYPO3\CMS\Belog\Domain\Model\LogEntry; use TYPO3\CMS\Core\Messaging\AbstractMessage; +use TYPO3\CMS\Core\Page\PageRenderer; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; @@ -69,11 +70,6 @@ class BackendLogController extends ActionController */ protected $logEntryRepository; - /** - * @var BackendTemplateView - */ - protected $view; - /** * @param \TYPO3\CMS\Belog\Domain\Repository\LogEntryRepository $logEntryRepository */ @@ -95,6 +91,8 @@ class BackendLogController extends ActionController } $constraintConfiguration = $this->arguments->getArgument('constraint')->getPropertyMappingConfiguration(); $constraintConfiguration->allowAllProperties(); + GeneralUtility::makeInstance(PageRenderer::class) + ->loadRequireJsModule('TYPO3/CMS/Backend/GlobalEventHandler'); } /** diff --git a/typo3/sysext/belog/Resources/Private/Partials/Content/Filter.html b/typo3/sysext/belog/Resources/Private/Partials/Content/Filter.html index ff55a5c972317e308bc446d5c43c2d2afbf69a85..3f9c4fd9a2e0ce096bfb3e5334b2a0210674c9a4 100644 --- a/typo3/sysext/belog/Resources/Private/Partials/Content/Filter.html +++ b/typo3/sysext/belog/Resources/Private/Partials/Content/Filter.html @@ -20,7 +20,7 @@ <f:form.select property="userOrGroup" options="{userGroups}" - additionalAttributes="{onchange : 'submit()'}" + additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" class="form-control input-sm" id="belog-users" /> @@ -32,7 +32,7 @@ property="number" options="{settings.selectableNumberOfLogEntries}" optionLabelPrefix="LLL:EXT:belog/Resources/Private/Language/locallang.xlf:" - additionalAttributes="{onchange : 'submit()'}" + additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" class="form-control input-sm" id="belog-max" /> @@ -45,7 +45,7 @@ <f:form.select property="workspaceUid" options="{workspaces}" - additionalAttributes="{onchange : 'submit()'}" + additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" class="form-control input-sm" id="belog-workspaces" /> @@ -59,7 +59,7 @@ <f:form.select property="depth" options="{pageDepths}" - additionalAttributes="{onchange : 'submit()'}" + additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" class="form-control input-sm" id="belog-depth" /> @@ -72,7 +72,7 @@ property="timeFrame" options="{settings.selectableTimeFrames}" optionLabelPrefix="LLL:EXT:belog/Resources/Private/Language/locallang.xlf:" - additionalAttributes="{onchange : 'submit()'}" + additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" class="form-control input-sm" id="belog-time" /> @@ -84,7 +84,7 @@ property="action" options="{settings.selectableActions}" optionLabelPrefix="LLL:EXT:belog/Resources/Private/Language/locallang.xlf:" - additionalAttributes="{onchange : 'submit()'}" + additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" class="form-control input-sm" id="belog-action" /> @@ -96,7 +96,7 @@ <f:form.checkbox property="groupByPage" value="1" - additionalAttributes="{onchange : 'submit()'}" + additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" id="belog-group" /> </div> diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Statistic.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Statistic.html index b8961f0e59274f03e54f756c9bd150bb6a58d3dc..df35a18058d66eaa874ec6e7cbe314bb13777a77 100644 --- a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Statistic.html +++ b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Statistic.html @@ -10,8 +10,8 @@ <f:form.select name="mode" options="{ overview:'{f:translate(key:\'administration.statistics.view.overview\')}', content:'{f:translate(key:\'administration.statistics.view.content\')}' - }" value="{mode}" additionalAttributes="{onchange:'this.form.submit();'}" /> - <f:form.select name="depth" options="{levelTranslations}" value="{depth}" additionalAttributes="{onchange:'this.form.submit();'}" /> + }" value="{mode}" additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" /> + <f:form.select name="depth" options="{levelTranslations}" value="{depth}" additionalAttributes="{data-global-event='change', data-action-submit: '$form'}" /> </div> </div> </f:form>