Commit a1325680 authored by Oliver Bartsch's avatar Oliver Bartsch
Browse files

[BUGFIX] Disable toggle all action in multi record selection

If a table in recordlist only contains records
which do not provide a checkbox, the "toggle
all" action should be disabled as well, since
using this action would have no effect.

Resolves: #97685
Releases: main, 11.5
Change-Id: Id87bb5dd9df10c33acd03d0c5dbca179bb7f1cdd
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/74736


Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Jochen's avatarJochen <rothjochen@gmail.com>
Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Jochen's avatarJochen <rothjochen@gmail.com>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
parent 48975aef
Pipeline #27483 passed with stages
in 19 minutes and 30 seconds
......@@ -386,6 +386,15 @@ class MultiRecordSelection {
if (checkNone !== null) {
checkNone.classList.toggle('disabled', !MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier).length);
}
const toggle: HTMLButtonElement = document.querySelector([
MultiRecordSelection.getCombinedSelector(Selectors.checkboxActionsSelector, identifier),
'button[data-multi-record-selection-check-action="' + CheckboxActions.toggle + '"]'
].join(' '));
if (toggle !== null) {
toggle.classList.toggle('disabled', !MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).length);
}
}).delegateTo(document, Selectors.checkboxActionsToggleSelector);
}
......
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
import Notification from"@typo3/backend/notification.js";import DocumentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";var Selectors,Buttons,CheckboxActions,CheckboxState;!function(e){e.actionsSelector=".t3js-multi-record-selection-actions",e.checkboxSelector=".t3js-multi-record-selection-check",e.checkboxActionsSelector=".t3js-multi-record-selection-check-actions",e.checkboxActionsToggleSelector=".t3js-multi-record-selection-check-actions-toggle",e.rowSelectionSelector="[data-multi-record-selection-row-selection] tr"}(Selectors||(Selectors={})),function(e){e.actionButton="button[data-multi-record-selection-action]",e.checkboxActionButton="button[data-multi-record-selection-check-action]"}(Buttons||(Buttons={})),function(e){e.checkAll="check-all",e.checkNone="check-none",e.toggle="toggle"}(CheckboxActions||(CheckboxActions={})),function(e){e.any="",e.checked=":checked",e.unchecked=":not(:checked)"}(CheckboxState||(CheckboxState={}));class MultiRecordSelection{constructor(){this.lastChecked=null,DocumentService.ready().then(()=>{MultiRecordSelection.restoreTemporaryState(),this.registerActions(),this.registerActionsEventHandlers(),this.registerCheckboxActions(),this.registerCheckboxKeyboardActions(),this.registerCheckboxTableRowSelectionAction(),this.registerToggleCheckboxActions(),this.registerDispatchCheckboxStateChangedEvent(),this.registerCheckboxStateChangedEventHandler()})}static getCheckboxes(e=CheckboxState.any,t=""){return document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.checkboxSelector+e,t))}static getCombinedSelector(e,t){return""!==t?['[data-multi-record-selection-identifier="'+t+'"]',e].join(" "):e}static getIdentifier(e){return e.closest("[data-multi-record-selection-identifier]")?.dataset.multiRecordSelectionIdentifier||""}static changeCheckboxState(e,t){e.checked===t||e.dataset.manuallyChanged||(e.checked=t,e.dispatchEvent(new CustomEvent("multiRecordSelection:checkbox:state:changed",{detail:{identifier:MultiRecordSelection.getIdentifier(e)},bubbles:!0,cancelable:!1})))}static restoreTemporaryState(){const e=MultiRecordSelection.getCheckboxes(CheckboxState.checked);if(!e.length)return;let t=!1,c=[];e.forEach(e=>{e.closest("tr").classList.add("success");const o=MultiRecordSelection.getIdentifier(e);""===o||c.includes(o)||(c.push(o),t=!0,MultiRecordSelection.toggleActionsState(o))}),t||MultiRecordSelection.toggleActionsState()}static toggleActionsState(e=""){const t=document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,e));if(!t.length)return;if(!MultiRecordSelection.getCheckboxes(CheckboxState.checked,e).length)return void t.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e,!1));t.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e));const c=document.querySelectorAll([MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,e),Buttons.actionButton].join(" "));c.length&&c.forEach(t=>{if(!t.dataset.multiRecordSelectionActionConfig)return;const c=JSON.parse(t.dataset.multiRecordSelectionActionConfig);if(!c.idField)return;t.classList.add("disabled");const o=MultiRecordSelection.getCheckboxes(CheckboxState.checked,e);for(let e=0;e<o.length;e++)if(o[e].closest("tr").dataset[c.idField]){t.classList.remove("disabled");break}})}static changeActionContainerVisibility(e,t=!0){const c=e.closest(".multi-record-selection-panel")?.children;if(t){if(c)for(let e=0;e<c.length;e++)c[e].classList.add("hidden");e.classList.remove("hidden")}else{if(c)for(let e=0;e<c.length;e++)c[e].classList.remove("hidden");e.classList.add("hidden")}}static unsetManuallyChangedAttribute(e){MultiRecordSelection.getCheckboxes(CheckboxState.any,e).forEach(e=>{e.removeAttribute("data-manually-changed")})}registerActions(){new RegularEvent("click",(e,t)=>{t.dataset.multiRecordSelectionAction;const c=MultiRecordSelection.getIdentifier(t),o=JSON.parse(t.dataset.multiRecordSelectionActionConfig||"{}"),i=MultiRecordSelection.getCheckboxes(CheckboxState.checked,c);i.length&&t.dispatchEvent(new CustomEvent("multiRecordSelection:action:"+t.dataset.multiRecordSelectionAction,{detail:{identifier:c,checkboxes:i,configuration:o},bubbles:!0,cancelable:!1}))}).delegateTo(document,[Selectors.actionsSelector,Buttons.actionButton].join(" "))}registerActionsEventHandlers(){new RegularEvent("multiRecordSelection:actions:show",e=>{const t=e.detail?.identifier||"",c=document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,t));c.length&&c.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e))}).bindTo(document),new RegularEvent("multiRecordSelection:actions:hide",e=>{const t=e.detail?.identifier||"",c=document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,t));c.length&&c.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e,!1))}).bindTo(document)}registerCheckboxActions(){new RegularEvent("click",(e,t)=>{if(e.preventDefault(),!t.dataset.multiRecordSelectionCheckAction)return;const c=MultiRecordSelection.getIdentifier(t),o=MultiRecordSelection.getCheckboxes(CheckboxState.any,c);if(o.length){switch(MultiRecordSelection.unsetManuallyChangedAttribute(c),t.dataset.multiRecordSelectionCheckAction){case CheckboxActions.checkAll:o.forEach(e=>{MultiRecordSelection.changeCheckboxState(e,!0)});break;case CheckboxActions.checkNone:o.forEach(e=>{MultiRecordSelection.changeCheckboxState(e,!1)});break;case CheckboxActions.toggle:o.forEach(e=>{MultiRecordSelection.changeCheckboxState(e,!e.checked)});break;default:Notification.warning("Unknown checkbox action")}MultiRecordSelection.unsetManuallyChangedAttribute(c)}}).delegateTo(document,[Selectors.checkboxActionsSelector,Buttons.checkboxActionButton].join(" "))}registerCheckboxKeyboardActions(){new RegularEvent("click",(e,t)=>this.handleCheckboxKeyboardActions(e,t)).delegateTo(document,Selectors.checkboxSelector)}registerCheckboxTableRowSelectionAction(){new RegularEvent("click",(e,t)=>{const c=e.target.tagName;if("TH"!==c&&"TD"!==c)return;const o=t.querySelector(Selectors.checkboxSelector);null!==o&&(MultiRecordSelection.changeCheckboxState(o,!o.checked),this.handleCheckboxKeyboardActions(e,o,!1))}).delegateTo(document,Selectors.rowSelectionSelector),new RegularEvent("mousedown",e=>(e.shiftKey||e.altKey||e.ctrlKey)&&e.preventDefault()).delegateTo(document,Selectors.rowSelectionSelector)}registerDispatchCheckboxStateChangedEvent(){new RegularEvent("change",(e,t)=>{t.dispatchEvent(new CustomEvent("multiRecordSelection:checkbox:state:changed",{detail:{identifier:MultiRecordSelection.getIdentifier(t)},bubbles:!0,cancelable:!1}))}).delegateTo(document,Selectors.checkboxSelector)}registerCheckboxStateChangedEventHandler(){new RegularEvent("multiRecordSelection:checkbox:state:changed",e=>{const t=e.target,c=e.detail?.identifier||"";t.checked?t.closest("tr").classList.add("success"):t.closest("tr").classList.remove("success"),MultiRecordSelection.toggleActionsState(c)}).bindTo(document)}registerToggleCheckboxActions(){new RegularEvent("click",(e,t)=>{const c=MultiRecordSelection.getIdentifier(t),o=document.querySelector([MultiRecordSelection.getCombinedSelector(Selectors.checkboxActionsSelector,c),'button[data-multi-record-selection-check-action="'+CheckboxActions.checkAll+'"]'].join(" "));null!==o&&o.classList.toggle("disabled",!MultiRecordSelection.getCheckboxes(CheckboxState.unchecked,c).length);const i=document.querySelector([MultiRecordSelection.getCombinedSelector(Selectors.checkboxActionsSelector,c),'button[data-multi-record-selection-check-action="'+CheckboxActions.checkNone+'"]'].join(" "));null!==i&&i.classList.toggle("disabled",!MultiRecordSelection.getCheckboxes(CheckboxState.checked,c).length)}).delegateTo(document,Selectors.checkboxActionsToggleSelector)}handleCheckboxKeyboardActions(e,t,c=!0){const o=MultiRecordSelection.getIdentifier(t);if(this.lastChecked&&document.body.contains(this.lastChecked)&&MultiRecordSelection.getIdentifier(this.lastChecked)===o&&(e.shiftKey||e.altKey||e.ctrlKey)){if(c&&MultiRecordSelection.unsetManuallyChangedAttribute(o),e.shiftKey){const e=Array.from(MultiRecordSelection.getCheckboxes(CheckboxState.any,o)),c=e.indexOf(t),i=e.indexOf(this.lastChecked);e.slice(Math.min(c,i),Math.max(c,i)+1).forEach(e=>{e!==t&&MultiRecordSelection.changeCheckboxState(e,t.checked)})}this.lastChecked=t,(e.altKey||e.ctrlKey)&&MultiRecordSelection.getCheckboxes(CheckboxState.any,o).forEach(e=>{e!==t&&MultiRecordSelection.changeCheckboxState(e,!e.checked)}),MultiRecordSelection.unsetManuallyChangedAttribute(o)}else this.lastChecked=t}}export default new MultiRecordSelection;
\ No newline at end of file
import Notification from"@typo3/backend/notification.js";import DocumentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";var Selectors,Buttons,CheckboxActions,CheckboxState;!function(e){e.actionsSelector=".t3js-multi-record-selection-actions",e.checkboxSelector=".t3js-multi-record-selection-check",e.checkboxActionsSelector=".t3js-multi-record-selection-check-actions",e.checkboxActionsToggleSelector=".t3js-multi-record-selection-check-actions-toggle",e.rowSelectionSelector="[data-multi-record-selection-row-selection] tr"}(Selectors||(Selectors={})),function(e){e.actionButton="button[data-multi-record-selection-action]",e.checkboxActionButton="button[data-multi-record-selection-check-action]"}(Buttons||(Buttons={})),function(e){e.checkAll="check-all",e.checkNone="check-none",e.toggle="toggle"}(CheckboxActions||(CheckboxActions={})),function(e){e.any="",e.checked=":checked",e.unchecked=":not(:checked)"}(CheckboxState||(CheckboxState={}));class MultiRecordSelection{constructor(){this.lastChecked=null,DocumentService.ready().then(()=>{MultiRecordSelection.restoreTemporaryState(),this.registerActions(),this.registerActionsEventHandlers(),this.registerCheckboxActions(),this.registerCheckboxKeyboardActions(),this.registerCheckboxTableRowSelectionAction(),this.registerToggleCheckboxActions(),this.registerDispatchCheckboxStateChangedEvent(),this.registerCheckboxStateChangedEventHandler()})}static getCheckboxes(e=CheckboxState.any,t=""){return document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.checkboxSelector+e,t))}static getCombinedSelector(e,t){return""!==t?['[data-multi-record-selection-identifier="'+t+'"]',e].join(" "):e}static getIdentifier(e){return e.closest("[data-multi-record-selection-identifier]")?.dataset.multiRecordSelectionIdentifier||""}static changeCheckboxState(e,t){e.checked===t||e.dataset.manuallyChanged||(e.checked=t,e.dispatchEvent(new CustomEvent("multiRecordSelection:checkbox:state:changed",{detail:{identifier:MultiRecordSelection.getIdentifier(e)},bubbles:!0,cancelable:!1})))}static restoreTemporaryState(){const e=MultiRecordSelection.getCheckboxes(CheckboxState.checked);if(!e.length)return;let t=!1,c=[];e.forEach(e=>{e.closest("tr").classList.add("success");const o=MultiRecordSelection.getIdentifier(e);""===o||c.includes(o)||(c.push(o),t=!0,MultiRecordSelection.toggleActionsState(o))}),t||MultiRecordSelection.toggleActionsState()}static toggleActionsState(e=""){const t=document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,e));if(!t.length)return;if(!MultiRecordSelection.getCheckboxes(CheckboxState.checked,e).length)return void t.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e,!1));t.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e));const c=document.querySelectorAll([MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,e),Buttons.actionButton].join(" "));c.length&&c.forEach(t=>{if(!t.dataset.multiRecordSelectionActionConfig)return;const c=JSON.parse(t.dataset.multiRecordSelectionActionConfig);if(!c.idField)return;t.classList.add("disabled");const o=MultiRecordSelection.getCheckboxes(CheckboxState.checked,e);for(let e=0;e<o.length;e++)if(o[e].closest("tr").dataset[c.idField]){t.classList.remove("disabled");break}})}static changeActionContainerVisibility(e,t=!0){const c=e.closest(".multi-record-selection-panel")?.children;if(t){if(c)for(let e=0;e<c.length;e++)c[e].classList.add("hidden");e.classList.remove("hidden")}else{if(c)for(let e=0;e<c.length;e++)c[e].classList.remove("hidden");e.classList.add("hidden")}}static unsetManuallyChangedAttribute(e){MultiRecordSelection.getCheckboxes(CheckboxState.any,e).forEach(e=>{e.removeAttribute("data-manually-changed")})}registerActions(){new RegularEvent("click",(e,t)=>{t.dataset.multiRecordSelectionAction;const c=MultiRecordSelection.getIdentifier(t),o=JSON.parse(t.dataset.multiRecordSelectionActionConfig||"{}"),i=MultiRecordSelection.getCheckboxes(CheckboxState.checked,c);i.length&&t.dispatchEvent(new CustomEvent("multiRecordSelection:action:"+t.dataset.multiRecordSelectionAction,{detail:{identifier:c,checkboxes:i,configuration:o},bubbles:!0,cancelable:!1}))}).delegateTo(document,[Selectors.actionsSelector,Buttons.actionButton].join(" "))}registerActionsEventHandlers(){new RegularEvent("multiRecordSelection:actions:show",e=>{const t=e.detail?.identifier||"",c=document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,t));c.length&&c.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e))}).bindTo(document),new RegularEvent("multiRecordSelection:actions:hide",e=>{const t=e.detail?.identifier||"",c=document.querySelectorAll(MultiRecordSelection.getCombinedSelector(Selectors.actionsSelector,t));c.length&&c.forEach(e=>MultiRecordSelection.changeActionContainerVisibility(e,!1))}).bindTo(document)}registerCheckboxActions(){new RegularEvent("click",(e,t)=>{if(e.preventDefault(),!t.dataset.multiRecordSelectionCheckAction)return;const c=MultiRecordSelection.getIdentifier(t),o=MultiRecordSelection.getCheckboxes(CheckboxState.any,c);if(o.length){switch(MultiRecordSelection.unsetManuallyChangedAttribute(c),t.dataset.multiRecordSelectionCheckAction){case CheckboxActions.checkAll:o.forEach(e=>{MultiRecordSelection.changeCheckboxState(e,!0)});break;case CheckboxActions.checkNone:o.forEach(e=>{MultiRecordSelection.changeCheckboxState(e,!1)});break;case CheckboxActions.toggle:o.forEach(e=>{MultiRecordSelection.changeCheckboxState(e,!e.checked)});break;default:Notification.warning("Unknown checkbox action")}MultiRecordSelection.unsetManuallyChangedAttribute(c)}}).delegateTo(document,[Selectors.checkboxActionsSelector,Buttons.checkboxActionButton].join(" "))}registerCheckboxKeyboardActions(){new RegularEvent("click",(e,t)=>this.handleCheckboxKeyboardActions(e,t)).delegateTo(document,Selectors.checkboxSelector)}registerCheckboxTableRowSelectionAction(){new RegularEvent("click",(e,t)=>{const c=e.target.tagName;if("TH"!==c&&"TD"!==c)return;const o=t.querySelector(Selectors.checkboxSelector);null!==o&&(MultiRecordSelection.changeCheckboxState(o,!o.checked),this.handleCheckboxKeyboardActions(e,o,!1))}).delegateTo(document,Selectors.rowSelectionSelector),new RegularEvent("mousedown",e=>(e.shiftKey||e.altKey||e.ctrlKey)&&e.preventDefault()).delegateTo(document,Selectors.rowSelectionSelector)}registerDispatchCheckboxStateChangedEvent(){new RegularEvent("change",(e,t)=>{t.dispatchEvent(new CustomEvent("multiRecordSelection:checkbox:state:changed",{detail:{identifier:MultiRecordSelection.getIdentifier(t)},bubbles:!0,cancelable:!1}))}).delegateTo(document,Selectors.checkboxSelector)}registerCheckboxStateChangedEventHandler(){new RegularEvent("multiRecordSelection:checkbox:state:changed",e=>{const t=e.target,c=e.detail?.identifier||"";t.checked?t.closest("tr").classList.add("success"):t.closest("tr").classList.remove("success"),MultiRecordSelection.toggleActionsState(c)}).bindTo(document)}registerToggleCheckboxActions(){new RegularEvent("click",(e,t)=>{const c=MultiRecordSelection.getIdentifier(t),o=document.querySelector([MultiRecordSelection.getCombinedSelector(Selectors.checkboxActionsSelector,c),'button[data-multi-record-selection-check-action="'+CheckboxActions.checkAll+'"]'].join(" "));null!==o&&o.classList.toggle("disabled",!MultiRecordSelection.getCheckboxes(CheckboxState.unchecked,c).length);const i=document.querySelector([MultiRecordSelection.getCombinedSelector(Selectors.checkboxActionsSelector,c),'button[data-multi-record-selection-check-action="'+CheckboxActions.checkNone+'"]'].join(" "));null!==i&&i.classList.toggle("disabled",!MultiRecordSelection.getCheckboxes(CheckboxState.checked,c).length);const n=document.querySelector([MultiRecordSelection.getCombinedSelector(Selectors.checkboxActionsSelector,c),'button[data-multi-record-selection-check-action="'+CheckboxActions.toggle+'"]'].join(" "));null!==n&&n.classList.toggle("disabled",!MultiRecordSelection.getCheckboxes(CheckboxState.any,c).length)}).delegateTo(document,Selectors.checkboxActionsToggleSelector)}handleCheckboxKeyboardActions(e,t,c=!0){const o=MultiRecordSelection.getIdentifier(t);if(this.lastChecked&&document.body.contains(this.lastChecked)&&MultiRecordSelection.getIdentifier(this.lastChecked)===o&&(e.shiftKey||e.altKey||e.ctrlKey)){if(c&&MultiRecordSelection.unsetManuallyChangedAttribute(o),e.shiftKey){const e=Array.from(MultiRecordSelection.getCheckboxes(CheckboxState.any,o)),c=e.indexOf(t),i=e.indexOf(this.lastChecked);e.slice(Math.min(c,i),Math.max(c,i)+1).forEach(e=>{e!==t&&MultiRecordSelection.changeCheckboxState(e,t.checked)})}this.lastChecked=t,(e.altKey||e.ctrlKey)&&MultiRecordSelection.getCheckboxes(CheckboxState.any,o).forEach(e=>{e!==t&&MultiRecordSelection.changeCheckboxState(e,!e.checked)}),MultiRecordSelection.unsetManuallyChangedAttribute(o)}else this.lastChecked=t}}export default new MultiRecordSelection;
\ No newline at end of file
......@@ -3141,7 +3141,7 @@ class DatabaseRecordList
$dropdownItems['toggleSelection'] = '
<li>
<button type="button" class="btn btn-link dropdown-item" data-multi-record-selection-check-action="toggle" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleSelection')) . '">
<button type="button" class="btn btn-link dropdown-item disabled" data-multi-record-selection-check-action="toggle" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleSelection')) . '">
' . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . '
' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleSelection')) . '
</button>
......
Supports Markdown
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