Skip to content

Commit

Permalink
[BUGFIX] Render proper markup for datetime picker buttons
Browse files Browse the repository at this point in the history
To make datetimer picker buttons focus the belonging textfield, the
buttons were rendered as `<label>` which is a very dirty hack, leading
to clitching buttons.

To solve this, the `@typo3/backend/global-event-handler` module is now
capable of focussing a specific element after clicking a trigger
element.

Resolves: #98054
Releases: main, 11.5
Change-Id: I828785267e6a8c25f3ed7c17221e903cd4cc3220
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/75392
Tested-by: core-ci <typo3@b13.com>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
  • Loading branch information
andreaskienast committed Sep 22, 2022
1 parent 2f70b7a commit 7e5c9ed
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 27 deletions.
Expand Up @@ -34,6 +34,7 @@ type HTMLFormChildElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaE
* + `$form=~s/$value/` URL taken from `form[action]`,
* substituting literal `${value}` and `$[value]` taken from `data-value-selector`
* + `data-global-event="click"`
* * `data-action-focus="..."` focus form field
* + @todo
*
* @example
Expand Down Expand Up @@ -63,35 +64,57 @@ class GlobalEventHandler {

private handleChangeEvent(evt: Event, resolvedTarget: HTMLElement): void {
evt.preventDefault();
this.handleFormChildSubmitAction(evt, resolvedTarget)
this.handleFormChildAction(evt, resolvedTarget)
|| this.handleFormChildNavigateAction(evt, resolvedTarget);
}

private handleClickEvent(evt: Event, resolvedTarget: HTMLElement): void {
evt.preventDefault();
this.handleFormChildAction(evt, resolvedTarget);
}

private handleSubmitEvent(evt: Event, resolvedTarget: HTMLFormElement): void {
evt.preventDefault();
this.handleFormNavigateAction(evt, resolvedTarget);
}

private handleFormChildSubmitAction(evt: Event, resolvedTarget: HTMLElement): boolean {
private handleFormChildAction(evt: Event, resolvedTarget: HTMLElement): boolean {
const actionSubmit: string = resolvedTarget.dataset.actionSubmit;
if (!actionSubmit) {
const actionFocus: string = resolvedTarget.dataset.actionFocus;
if (!actionSubmit && !actionFocus) {
return false;
}
// @example [data-action-submit]="$form"
if (actionSubmit === '$form' && this.isHTMLFormChildElement(resolvedTarget)) {
(resolvedTarget as HTMLFormChildElement).form.submit();
return true;

const parentForm = resolvedTarget.closest('form');

if (actionSubmit) {
// @example [data-action-submit]="$form"
if (actionSubmit === '$form' && this.isHTMLFormChildElement(resolvedTarget)) {
(resolvedTarget as HTMLFormChildElement).form.submit();
return true;
}
const formCandidate = document.querySelector(actionSubmit);
if (formCandidate instanceof HTMLFormElement) {
formCandidate.submit();
return true;
}
return false;
}
const formCandidate = document.querySelector(actionSubmit);
if (formCandidate instanceof HTMLFormElement) {
formCandidate.submit();
return true;

if (actionFocus && parentForm) {
if (!(parentForm instanceof HTMLFormElement)) {
return false;
}

const formFieldElement: HTMLElement|null = parentForm.querySelector(actionFocus);
if (formFieldElement === null) {
return false;
}

formFieldElement.focus();
}
return false;

return true;
}

private handleFormChildNavigateAction(evt: Event, resolvedTarget: HTMLElement): boolean {
Expand Down
Expand Up @@ -199,11 +199,9 @@ public function render()
$expansionHtml[] = '<div class="input-group">';
$expansionHtml[] = '<input type="text" ' . GeneralUtility::implodeAttributes($attributes, true) . ' />';
$expansionHtml[] = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($itemValue) . '" />';
$expansionHtml[] = '<span class="input-group-btn">';
$expansionHtml[] = '<label class="btn btn-default" for="' . $attributes['id'] . '">';
$expansionHtml[] = $this->iconFactory->getIcon('actions-edit-pick-date', Icon::SIZE_SMALL)->render();
$expansionHtml[] = '</label>';
$expansionHtml[] = '</span>';
$expansionHtml[] = '<button class="btn btn-default" type="button" data-global-event="click" data-action-focus="#' . $attributes['id'] . '">';
$expansionHtml[] = $this->iconFactory->getIcon('actions-edit-pick-date', Icon::SIZE_SMALL)->render();
$expansionHtml[] = '</button>';
$expansionHtml[] = '</div>';
$expansionHtml[] = '</div>';
if (!empty($fieldControlHtml)) {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions typo3/sysext/lowlevel/Classes/Database/QueryGenerator.php
Expand Up @@ -2808,11 +2808,9 @@ protected function getDateTimePickerField($name, $timestamp, $type)
$html[] = ' <div class="input-group" id="' . $id . '-wrapper">';
$html[] = ' <input data-formengine-input-name="' . htmlspecialchars($name) . '" value="' . $value . '" class="form-control t3js-datetimepicker t3js-clearable" data-date-type="' . htmlspecialchars($type) . '" type="text" id="' . $id . '">';
$html[] = ' <input name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($timestamp) . '" type="hidden">';
$html[] = ' <span class="input-group-btn">';
$html[] = ' <label class="btn btn-default" for="' . $id . '">';
$html[] = ' <span class="fa fa-calendar"></span>';
$html[] = ' </label>';
$html[] = ' </span>';
$html[] = ' <button class="btn btn-default" type="button" data-global-event="click" data-action-focus="#' . $id . '">';
$html[] = ' <span class="fa fa-calendar"></span>';
$html[] = ' </button>';
$html[] = ' </div>';
$html[] = '</div>';
return implode(LF, $html);
Expand Down
Expand Up @@ -77,9 +77,9 @@
<div class="input-group" id="tceforms-datetimefield-task_start_row-wrapper">
<input name="tx_scheduler[start]_hr" value="{start_value_hr}" class="form-control t3js-datetimepicker t3js-clearable" data-date-type="datetime" data-date-offset="0" type="text" id="tceforms-datetimefield-task_start_row">
<input name="tx_scheduler[start]" value="{start_value}" type="hidden">
<label class="mb-0 btn btn-default" for="tceforms-datetimefield-task_start_row">
<button class="btn btn-default" type="button" data-global-event="click" data-action-focus="#tceforms-datetimefield-task_start_row">
<core:icon identifier="actions-edit-pick-date" />
</label>
</button>
</div>
</div>
</div>
Expand All @@ -89,9 +89,9 @@
<div class="input-group" id="tceforms-datetimefield-task_end_row-wrapper">
<input name="tx_scheduler[end]_hr" value="{end_value_hr}" class="form-control t3js-datetimepicker t3js-clearable" data-date-type="datetime" data-date-offset="0" type="text" id="tceforms-datetimefield-task_end_row">
<input name="tx_scheduler[end]" value="{end_value}" type="hidden">
<label class="mb-0 btn btn-default" for="tceforms-datetimefield-task_end_row">
<button class="btn btn-default" type="button" data-global-event="click" data-action-focus="#tceforms-datetimefield-task_end_row">
<core:icon identifier="actions-edit-pick-date" />
</label>
</button>
</div>
</div>
</div>
Expand Down

0 comments on commit 7e5c9ed

Please sign in to comment.