From 0f24df96fd8bb08730d6d4b0354f7b8317db9232 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Wed, 5 Jul 2023 23:05:17 +0200 Subject: [PATCH] [BUGFIX] Fix workspace stage-change mail recipient selection Stage-change notification mails have only been delivered to the last recipient off the list of possible recipients, because Utility.convertFormToObject failed to detect checkbox elements from (other) frames. In this case the to-be-converted form elements are created on the top frame (modal contents are placed outside list frame on the top frame). Due to JavaScript being prototype based, instanceof checks do only operate per-frame. Prototypes are bound to the current window. `foo instanceof HTMLInputElement` is basically a shortcut and equivalent to `foo instanceof window.HTMLInputElement` while `window != top.window`. Instead of `instanceof` checks, we switch to a `tagName` comparision which is usable for cross-frame HTMLElement type detection. Resolves: #99784 Releases: main, 12.4, 11.5 Change-Id: If9bfd7be1e46d8c04619be3563d3bdba9d9de549 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/79953 Tested-by: Benjamin Franzke <ben@bnf.dev> Tested-by: core-ci <typo3@b13.com> Reviewed-by: Benjamin Franzke <ben@bnf.dev> --- Build/Sources/TypeScript/backend/utility.ts | 5 +++-- typo3/sysext/backend/Resources/Public/JavaScript/utility.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Build/Sources/TypeScript/backend/utility.ts b/Build/Sources/TypeScript/backend/utility.ts index c4dfd2ada2a1..e99b3d3cdcd8 100644 --- a/Build/Sources/TypeScript/backend/utility.ts +++ b/Build/Sources/TypeScript/backend/utility.ts @@ -129,11 +129,12 @@ class Utility { const value = element.value; if (name) { - if (element instanceof HTMLInputElement && element.type == 'checkbox') { + if (element.tagName.toLowerCase() === 'input' && element.type == 'checkbox') { + const checkbox = element as HTMLInputElement; if (obj[name] === undefined) { obj[name] = []; } - if (element.checked){ + if (checkbox.checked){ obj[name].push(value); } diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/utility.js b/typo3/sysext/backend/Resources/Public/JavaScript/utility.js index 3e4827278535..a6c1688d14e4 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/utility.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/utility.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -class Utility{static trimExplode(t,e){return e.split(t).map((t=>t.trim())).filter((t=>""!==t))}static trimItems(t){return t.map((t=>t instanceof String?t.trim():t))}static intExplode(t,e,r=!1){return e.split(t).map((t=>parseInt(t,10))).filter((t=>!isNaN(t)||r&&0===t))}static isNumber(t){return!isNaN(parseFloat(t.toString()))&&isFinite(t)}static getParameterFromUrl(t,e){if(console.warn("The function `getParameterFromUrl()` of `@typo3/backend/utility` has been marked as deprecated and will be removed in TYPO3 v13. Use `new URL(url, window.location.origin).searchParams.get(parameter)` instead."),"function"!=typeof t.split)return"";const r=t.split("?");let i="";if(r.length>=2){const t=r.join("?"),n=encodeURIComponent(e)+"=",a=t.split(/[&;]/g);for(let t=a.length;t-- >0;)if(-1!==a[t].lastIndexOf(n,0)){i=a[t].split("=")[1];break}}return i}static updateQueryStringParameter(t,e,r){const i=new RegExp("([?&])"+e+"=.*?(&|$)","i"),n=t.includes("?")?"&":"?";return t.match(i)?t.replace(i,"$1"+e+"="+r+"$2"):t+n+e+"="+r}static convertFormToObject(t){const e={};return t.querySelectorAll("input, select, textarea").forEach((t=>{const r=t.name,i=t.value;r&&(t instanceof HTMLInputElement&&"checkbox"==t.type?(void 0===e[r]&&(e[r]=[]),t.checked&&e[r].push(i)):e[r]=i)})),e}static mergeDeep(...t){const e=t=>t&&"object"==typeof t;return t.reduce(((t,r)=>(Object.keys(r).forEach((i=>{const n=t[i],a=r[i];Array.isArray(n)&&Array.isArray(a)?t[i]=n.concat(...a):e(n)&&e(a)?t[i]=Utility.mergeDeep(n,a):t[i]=a})),t)),{})}static urlsPointToSameServerSideResource(t,e){if(!t||!e)return!1;const r=window.location.origin;try{const i=new URL(t,Utility.isValidUrl(t)?void 0:r),n=new URL(e,Utility.isValidUrl(e)?void 0:r),a=i.origin+i.pathname+i.search;return a===n.origin+n.pathname+n.search}catch(t){return!1}}static isValidUrl(t){try{return new URL(t),!0}catch(t){return!1}}}export default Utility; \ No newline at end of file +class Utility{static trimExplode(t,e){return e.split(t).map((t=>t.trim())).filter((t=>""!==t))}static trimItems(t){return t.map((t=>t instanceof String?t.trim():t))}static intExplode(t,e,r=!1){return e.split(t).map((t=>parseInt(t,10))).filter((t=>!isNaN(t)||r&&0===t))}static isNumber(t){return!isNaN(parseFloat(t.toString()))&&isFinite(t)}static getParameterFromUrl(t,e){if(console.warn("The function `getParameterFromUrl()` of `@typo3/backend/utility` has been marked as deprecated and will be removed in TYPO3 v13. Use `new URL(url, window.location.origin).searchParams.get(parameter)` instead."),"function"!=typeof t.split)return"";const r=t.split("?");let i="";if(r.length>=2){const t=r.join("?"),a=encodeURIComponent(e)+"=",n=t.split(/[&;]/g);for(let t=n.length;t-- >0;)if(-1!==n[t].lastIndexOf(a,0)){i=n[t].split("=")[1];break}}return i}static updateQueryStringParameter(t,e,r){const i=new RegExp("([?&])"+e+"=.*?(&|$)","i"),a=t.includes("?")?"&":"?";return t.match(i)?t.replace(i,"$1"+e+"="+r+"$2"):t+a+e+"="+r}static convertFormToObject(t){const e={};return t.querySelectorAll("input, select, textarea").forEach((t=>{const r=t.name,i=t.value;if(r)if("input"===t.tagName.toLowerCase()&&"checkbox"==t.type){const a=t;void 0===e[r]&&(e[r]=[]),a.checked&&e[r].push(i)}else e[r]=i})),e}static mergeDeep(...t){const e=t=>t&&"object"==typeof t;return t.reduce(((t,r)=>(Object.keys(r).forEach((i=>{const a=t[i],n=r[i];Array.isArray(a)&&Array.isArray(n)?t[i]=a.concat(...n):e(a)&&e(n)?t[i]=Utility.mergeDeep(a,n):t[i]=n})),t)),{})}static urlsPointToSameServerSideResource(t,e){if(!t||!e)return!1;const r=window.location.origin;try{const i=new URL(t,Utility.isValidUrl(t)?void 0:r),a=new URL(e,Utility.isValidUrl(e)?void 0:r),n=i.origin+i.pathname+i.search;return n===a.origin+a.pathname+a.search}catch(t){return!1}}static isValidUrl(t){try{return new URL(t),!0}catch(t){return!1}}}export default Utility; \ No newline at end of file -- GitLab