Skip to content
Snippets Groups Projects
Commit 6b426d4d authored by Nicole Cordes's avatar Nicole Cordes Committed by Benjamin Franzke
Browse files

[BUGFIX] Support deferred ConsumerScope in GlobalEventHandler

The GlobalEventHandler changes the location of the current (target)
window. The location is set to a given destination without any ability
to interrupt. The existing ConsumerScope API isn't used even if the
current window is the ContentContainer. This patch extends the handling
of a navigation action by checking its target window and using proper
ContentContainer API to set the location. Therefore registered listener
can deny a location change and trigger own functions.

Resolves: #95474
Resolves: #100114
Releases: main, 12.4, 11.5
Change-Id: If6a3b1cc546e1f2ff0b8e9fed3f83055f3f55e49
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/79922


Tested-by: default avatarcore-ci <typo3@b13.com>
Tested-by: default avatarBenjamin Franzke <ben@bnf.dev>
Reviewed-by: default avatarBenjamin Franzke <ben@bnf.dev>
parent 10a41357
Branches
Tags
No related merge requests found
......@@ -13,6 +13,7 @@
import documentService from '@typo3/core/document-service';
import RegularEvent from '@typo3/core/event/regular-event';
import Viewport from './viewport';
type HTMLFormChildElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
......@@ -154,19 +155,19 @@ class GlobalEventHandler {
}
const value = this.resolveHTMLFormChildElementValue(resolvedTarget);
const navigateValue = resolvedTarget.dataset.navigateValue;
let locationHref = null;
if (actionNavigate === '$data=~s/$value/' && navigateValue && value !== null) {
window.location.href = this.substituteValueVariable(navigateValue, value);
return true;
locationHref = this.substituteValueVariable(navigateValue, value);
} else if (actionNavigate === '$data' && navigateValue) {
locationHref = navigateValue;
} else if (actionNavigate === '$value' && value) {
locationHref = value;
}
if (actionNavigate === '$data' && navigateValue) {
window.location.href = navigateValue;
return true;
}
if (actionNavigate === '$value' && value) {
window.location.href = value;
return true;
if (locationHref === null) {
return false;
}
return false;
Viewport.ContentContainer.setUrl(locationHref);
return true;
}
private handleFormNavigateAction(evt: Event, resolvedTarget: HTMLFormElement): boolean {
......@@ -178,15 +179,17 @@ class GlobalEventHandler {
const navigateValue = resolvedTarget.dataset.navigateValue;
const valueSelector = resolvedTarget.dataset.valueSelector;
const value = this.resolveHTMLFormChildElementValue(resolvedTarget.querySelector(valueSelector));
let locationHref = null;
if (actionNavigate === '$form=~s/$value/' && navigateValue && value !== null) {
window.location.href = this.substituteValueVariable(navigateValue, value);
return true;
locationHref = this.substituteValueVariable(navigateValue, value);
} else if (actionNavigate === '$form') {
locationHref = formAction;
}
if (actionNavigate === '$form') {
window.location.href = formAction;
return true;
if (locationHref === null) {
return false;
}
return false;
Viewport.ContentContainer.setUrl(locationHref);
return true;
}
private substituteValueVariable(haystack: string, substitute: string): string {
......
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
import documentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";class GlobalEventHandler{constructor(){this.options={onChangeSelector:'[data-global-event="change"]',onClickSelector:'[data-global-event="click"]',onSubmitSelector:'form[data-global-event="submit"]'},documentService.ready().then((()=>this.registerEvents()))}registerEvents(){new RegularEvent("change",this.handleChangeEvent.bind(this)).delegateTo(document,this.options.onChangeSelector),new RegularEvent("click",this.handleClickEvent.bind(this)).delegateTo(document,this.options.onClickSelector),new RegularEvent("submit",this.handleSubmitEvent.bind(this)).delegateTo(document,this.options.onSubmitSelector)}handleChangeEvent(e,t){e.preventDefault(),this.handleFormChildAction(e,t)||this.handleFormChildNavigateAction(e,t)}handleClickEvent(e,t){e.preventDefault(),this.handleFormChildAction(e,t)}handleSubmitEvent(e,t){e.preventDefault(),this.handleFormNavigateAction(e,t)}handleFormChildAction(e,t){const n=t.dataset.actionSubmit,a=t.dataset.actionFocus;if(!n&&!a)return!1;let l=null;const o=t.closest("form");if(n){const e="$form"!==n?document.querySelector(n):null;if("$form"===n&&this.isHTMLFormChildElement(t)?l=t.form:"$form"===n&&o?l=o:e instanceof HTMLFormElement&&(l=e),!(l instanceof HTMLFormElement))return!1;this.assignFormValues(l,t),l.submit()}if(a&&o){if(!(o instanceof HTMLFormElement))return!1;const e=o.querySelector(a);if(null===e)return!1;e.focus()}return!0}assignFormValues(e,t){const n=t.dataset.formValues,a=n?JSON.parse(n):null;return null!==a&&a instanceof Object&&(Object.entries(a).forEach((([t,n])=>{let a=e.querySelector("[name="+CSS.escape(t)+"]");a instanceof HTMLElement?this.assignHTMLFormChildElementValue(a,n.toString()):(a=document.createElement("input"),a.setAttribute("type","hidden"),a.setAttribute("name",t),a.setAttribute("value",n.toString()),e.appendChild(a))})),!0)}handleFormChildNavigateAction(e,t){const n=t.dataset.actionNavigate;if(!n)return!1;const a=this.resolveHTMLFormChildElementValue(t),l=t.dataset.navigateValue;return"$data=~s/$value/"===n&&l&&null!==a?(window.location.href=this.substituteValueVariable(l,a),!0):"$data"===n&&l?(window.location.href=l,!0):!("$value"!==n||!a)&&(window.location.href=a,!0)}handleFormNavigateAction(e,t){const n=t.action,a=t.dataset.actionNavigate;if(!n||!a)return!1;const l=t.dataset.navigateValue,o=t.dataset.valueSelector,i=this.resolveHTMLFormChildElementValue(t.querySelector(o));return"$form=~s/$value/"===a&&l&&null!==i?(window.location.href=this.substituteValueVariable(l,i),!0):"$form"===a&&(window.location.href=n,!0)}substituteValueVariable(e,t){return e.replace(/(\$\{value\}|%24%7Bvalue%7D|\$\[value\]|%24%5Bvalue%5D)/gi,t)}isHTMLFormChildElement(e){return e instanceof HTMLSelectElement||e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement}resolveHTMLFormChildElementValue(e){const t=e.getAttribute("type");if(e instanceof HTMLSelectElement)return e.options[e.selectedIndex].value;if(e instanceof HTMLInputElement&&"checkbox"===t){const t=e.dataset.emptyValue;return e.checked?e.value:void 0!==t?t:""}return e instanceof HTMLInputElement?e.value:null}assignHTMLFormChildElementValue(e,t){const n=e.getAttribute("type");if(e instanceof HTMLSelectElement)Array.from(e.options).some(((n,a)=>n.value===t&&(e.selectedIndex=a,!0)));else if(e instanceof HTMLInputElement&&"checkbox"===n){const n=e.dataset.emptyValue;void 0!==n&&n===t?e.checked=!1:e.value===t&&(e.checked=!0)}else e instanceof HTMLInputElement&&(e.value=t)}}export default new GlobalEventHandler;
\ No newline at end of file
import documentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";import Viewport from"@typo3/backend/viewport.js";class GlobalEventHandler{constructor(){this.options={onChangeSelector:'[data-global-event="change"]',onClickSelector:'[data-global-event="click"]',onSubmitSelector:'form[data-global-event="submit"]'},documentService.ready().then((()=>this.registerEvents()))}registerEvents(){new RegularEvent("change",this.handleChangeEvent.bind(this)).delegateTo(document,this.options.onChangeSelector),new RegularEvent("click",this.handleClickEvent.bind(this)).delegateTo(document,this.options.onClickSelector),new RegularEvent("submit",this.handleSubmitEvent.bind(this)).delegateTo(document,this.options.onSubmitSelector)}handleChangeEvent(e,t){e.preventDefault(),this.handleFormChildAction(e,t)||this.handleFormChildNavigateAction(e,t)}handleClickEvent(e,t){e.preventDefault(),this.handleFormChildAction(e,t)}handleSubmitEvent(e,t){e.preventDefault(),this.handleFormNavigateAction(e,t)}handleFormChildAction(e,t){const n=t.dataset.actionSubmit,l=t.dataset.actionFocus;if(!n&&!l)return!1;let a=null;const o=t.closest("form");if(n){const e="$form"!==n?document.querySelector(n):null;if("$form"===n&&this.isHTMLFormChildElement(t)?a=t.form:"$form"===n&&o?a=o:e instanceof HTMLFormElement&&(a=e),!(a instanceof HTMLFormElement))return!1;this.assignFormValues(a,t),a.submit()}if(l&&o){if(!(o instanceof HTMLFormElement))return!1;const e=o.querySelector(l);if(null===e)return!1;e.focus()}return!0}assignFormValues(e,t){const n=t.dataset.formValues,l=n?JSON.parse(n):null;return null!==l&&l instanceof Object&&(Object.entries(l).forEach((([t,n])=>{let l=e.querySelector("[name="+CSS.escape(t)+"]");l instanceof HTMLElement?this.assignHTMLFormChildElementValue(l,n.toString()):(l=document.createElement("input"),l.setAttribute("type","hidden"),l.setAttribute("name",t),l.setAttribute("value",n.toString()),e.appendChild(l))})),!0)}handleFormChildNavigateAction(e,t){const n=t.dataset.actionNavigate;if(!n)return!1;const l=this.resolveHTMLFormChildElementValue(t),a=t.dataset.navigateValue;let o=null;return"$data=~s/$value/"===n&&a&&null!==l?o=this.substituteValueVariable(a,l):"$data"===n&&a?o=a:"$value"===n&&l&&(o=l),null!==o&&(Viewport.ContentContainer.setUrl(o),!0)}handleFormNavigateAction(e,t){const n=t.action,l=t.dataset.actionNavigate;if(!n||!l)return!1;const a=t.dataset.navigateValue,o=t.dataset.valueSelector,i=this.resolveHTMLFormChildElementValue(t.querySelector(o));let r=null;return"$form=~s/$value/"===l&&a&&null!==i?r=this.substituteValueVariable(a,i):"$form"===l&&(r=n),null!==r&&(Viewport.ContentContainer.setUrl(r),!0)}substituteValueVariable(e,t){return e.replace(/(\$\{value\}|%24%7Bvalue%7D|\$\[value\]|%24%5Bvalue%5D)/gi,t)}isHTMLFormChildElement(e){return e instanceof HTMLSelectElement||e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement}resolveHTMLFormChildElementValue(e){const t=e.getAttribute("type");if(e instanceof HTMLSelectElement)return e.options[e.selectedIndex].value;if(e instanceof HTMLInputElement&&"checkbox"===t){const t=e.dataset.emptyValue;return e.checked?e.value:void 0!==t?t:""}return e instanceof HTMLInputElement?e.value:null}assignHTMLFormChildElementValue(e,t){const n=e.getAttribute("type");if(e instanceof HTMLSelectElement)Array.from(e.options).some(((n,l)=>n.value===t&&(e.selectedIndex=l,!0)));else if(e instanceof HTMLInputElement&&"checkbox"===n){const n=e.dataset.emptyValue;void 0!==n&&n===t?e.checked=!1:e.value===t&&(e.checked=!0)}else e instanceof HTMLInputElement&&(e.value=t)}}export default new GlobalEventHandler;
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment