diff --git a/Build/Sources/TypeScript/backend/multi-record-selection.ts b/Build/Sources/TypeScript/backend/multi-record-selection.ts index 2c3b81282ae9534e5d4a960455b81958b5ab6e49..e330dcb211952ecccb4d6459836d0ce4fdaaf152 100644 --- a/Build/Sources/TypeScript/backend/multi-record-selection.ts +++ b/Build/Sources/TypeScript/backend/multi-record-selection.ts @@ -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); } diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/multi-record-selection.js b/typo3/sysext/backend/Resources/Public/JavaScript/multi-record-selection.js index a6da74ebeba3bf1ade508311d4f7b0ccc281d781..fecaded89a9f03b2f0c15cec749e78a7d3e8096f 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/multi-record-selection.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/multi-record-selection.js @@ -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 diff --git a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php index 2f9a049d32f40c310ed8761b6dd34448d0b5dd35..1e6ff6bcbdd3fe261099016b49573db7dc3336a7 100644 --- a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php +++ b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php @@ -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>