diff --git a/ts/WoltLabSuite/Core/Component/Interaction/InteractionEffect.ts b/ts/WoltLabSuite/Core/Component/Interaction/InteractionEffect.ts new file mode 100644 index 00000000000..c348a0afca6 --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/Interaction/InteractionEffect.ts @@ -0,0 +1,14 @@ +/** + * Represents an effect that is to be applied after an interaction has been executed. + * + * @author Marcel Werk + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ + +export enum InteractionEffect { + ReloadItem = "ReloadItem", + ReloadList = "ReloadList", + RemoveItem = "RemoveItem", +} diff --git a/ts/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.ts b/ts/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.ts index fa397c90665..a292f96388d 100644 --- a/ts/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.ts +++ b/ts/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.ts @@ -12,14 +12,17 @@ import { dboAction } from "WoltLabSuite/Core/Ajax"; import { ConfirmationType, handleConfirmation } from "./Confirmation"; import { showDefaultSuccessSnackbar, showSuccessSnackbar } from "WoltLabSuite/Core/Component/Snackbar"; import { getPhrase } from "WoltLabSuite/Core/Language"; +import { InteractionEffect } from "./InteractionEffect"; async function handleDboAction( + container: HTMLElement, element: HTMLElement, objectName: string, className: string, actionName: string, confirmationType: ConfirmationType, customConfirmationMessage: string = "", + interactionEffect: InteractionEffect = InteractionEffect.ReloadItem, ): Promise { const confirmationResult = await handleConfirmation(objectName, confirmationType, customConfirmationMessage); if (!confirmationResult.result) { @@ -31,21 +34,25 @@ async function handleDboAction( .payload(confirmationResult.reason ? { reason: confirmationResult.reason } : {}) .dispatch(); - if (confirmationType == ConfirmationType.Delete) { + if (interactionEffect === InteractionEffect.ReloadItem) { element.dispatchEvent( - new CustomEvent("interaction:remove", { + new CustomEvent("interaction:invalidate", { bubbles: true, }), ); - - showSuccessSnackbar(getPhrase("wcf.global.success.delete")); + } else if (interactionEffect === InteractionEffect.ReloadList) { + container.dispatchEvent(new CustomEvent("interaction:invalidate-all")); } else { element.dispatchEvent( - new CustomEvent("interaction:invalidate", { + new CustomEvent("interaction:remove", { bubbles: true, }), ); + } + if (confirmationType == ConfirmationType.Delete) { + showSuccessSnackbar(getPhrase("wcf.global.success.delete")); + } else { showDefaultSuccessSnackbar(); } } @@ -54,12 +61,14 @@ export function setup(identifier: string, container: HTMLElement): void { container.addEventListener("interaction:execute", (event: CustomEvent) => { if (event.detail.interaction === identifier) { void handleDboAction( + container, event.target as HTMLElement, event.detail.objectName, event.detail.className, event.detail.actionName, event.detail.confirmationType, event.detail.confirmationMessage, + event.detail.interactionEffect, ); } }); diff --git a/ts/WoltLabSuite/Core/Component/Interaction/Rpc.ts b/ts/WoltLabSuite/Core/Component/Interaction/Rpc.ts index 89d84ed804e..143bdf0a47f 100644 --- a/ts/WoltLabSuite/Core/Component/Interaction/Rpc.ts +++ b/ts/WoltLabSuite/Core/Component/Interaction/Rpc.ts @@ -12,6 +12,7 @@ import { postObject } from "WoltLabSuite/Core/Api/PostObject"; import { ConfirmationType, handleConfirmation } from "./Confirmation"; import { showDefaultSuccessSnackbar, showSuccessSnackbar } from "WoltLabSuite/Core/Component/Snackbar"; import { getPhrase } from "WoltLabSuite/Core/Language"; +import { InteractionEffect } from "./InteractionEffect"; async function handleRpcInteraction( container: HTMLElement, @@ -20,7 +21,7 @@ async function handleRpcInteraction( endpoint: string, confirmationType: ConfirmationType, customConfirmationMessage: string = "", - invalidatesAllItems = false, + interactionEffect: InteractionEffect = InteractionEffect.ReloadItem, ): Promise { const confirmationResult = await handleConfirmation(objectName, confirmationType, customConfirmationMessage); if (!confirmationResult.result) { @@ -42,25 +43,25 @@ async function handleRpcInteraction( } } - if (confirmationType === ConfirmationType.Delete) { + if (interactionEffect === InteractionEffect.ReloadItem) { + element.dispatchEvent( + new CustomEvent("interaction:invalidate", { + bubbles: true, + }), + ); + } else if (interactionEffect === InteractionEffect.ReloadList) { + container.dispatchEvent(new CustomEvent("interaction:invalidate-all")); + } else { element.dispatchEvent( new CustomEvent("interaction:remove", { bubbles: true, }), ); + } + if (confirmationType === ConfirmationType.Delete) { showSuccessSnackbar(getPhrase("wcf.global.success.delete")); } else { - if (invalidatesAllItems) { - container.dispatchEvent(new CustomEvent("interaction:invalidate-all")); - } else { - element.dispatchEvent( - new CustomEvent("interaction:invalidate", { - bubbles: true, - }), - ); - } - showDefaultSuccessSnackbar(); } } @@ -75,7 +76,7 @@ export function setup(identifier: string, container: HTMLElement): void { event.detail.endpoint, event.detail.confirmationType, event.detail.confirmationMessage, - event.detail.invalidatesAllItems === "true", + event.detail.interactionEffect, ); } }); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/InteractionEffect.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/InteractionEffect.js new file mode 100644 index 00000000000..70e92a4b1d5 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/InteractionEffect.js @@ -0,0 +1,19 @@ +/** + * Represents an effect that is to be applied after an interaction has been executed. + * + * @author Marcel Werk + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +define(["require", "exports"], function (require, exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.InteractionEffect = void 0; + var InteractionEffect; + (function (InteractionEffect) { + InteractionEffect["ReloadItem"] = "ReloadItem"; + InteractionEffect["ReloadList"] = "ReloadList"; + InteractionEffect["RemoveItem"] = "RemoveItem"; + })(InteractionEffect || (exports.InteractionEffect = InteractionEffect = {})); +}); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.js index 810036b3bc6..39ac3c77932 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/LegacyDboAction.js @@ -7,11 +7,11 @@ * @since 6.2 * @deprecated 6.2 DBO actions are considered outdated and should be migrated to RPC endpoints. */ -define(["require", "exports", "WoltLabSuite/Core/Ajax", "./Confirmation", "WoltLabSuite/Core/Component/Snackbar", "WoltLabSuite/Core/Language"], function (require, exports, Ajax_1, Confirmation_1, Snackbar_1, Language_1) { +define(["require", "exports", "WoltLabSuite/Core/Ajax", "./Confirmation", "WoltLabSuite/Core/Component/Snackbar", "WoltLabSuite/Core/Language", "./InteractionEffect"], function (require, exports, Ajax_1, Confirmation_1, Snackbar_1, Language_1, InteractionEffect_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setup = setup; - async function handleDboAction(element, objectName, className, actionName, confirmationType, customConfirmationMessage = "") { + async function handleDboAction(container, element, objectName, className, actionName, confirmationType, customConfirmationMessage = "", interactionEffect = InteractionEffect_1.InteractionEffect.ReloadItem) { const confirmationResult = await (0, Confirmation_1.handleConfirmation)(objectName, confirmationType, customConfirmationMessage); if (!confirmationResult.result) { return; @@ -20,23 +20,30 @@ define(["require", "exports", "WoltLabSuite/Core/Ajax", "./Confirmation", "WoltL .objectIds([parseInt(element.dataset.objectId)]) .payload(confirmationResult.reason ? { reason: confirmationResult.reason } : {}) .dispatch(); - if (confirmationType == Confirmation_1.ConfirmationType.Delete) { - element.dispatchEvent(new CustomEvent("interaction:remove", { + if (interactionEffect === InteractionEffect_1.InteractionEffect.ReloadItem) { + element.dispatchEvent(new CustomEvent("interaction:invalidate", { bubbles: true, })); - (0, Snackbar_1.showSuccessSnackbar)((0, Language_1.getPhrase)("wcf.global.success.delete")); + } + else if (interactionEffect === InteractionEffect_1.InteractionEffect.ReloadList) { + container.dispatchEvent(new CustomEvent("interaction:invalidate-all")); } else { - element.dispatchEvent(new CustomEvent("interaction:invalidate", { + element.dispatchEvent(new CustomEvent("interaction:remove", { bubbles: true, })); + } + if (confirmationType == Confirmation_1.ConfirmationType.Delete) { + (0, Snackbar_1.showSuccessSnackbar)((0, Language_1.getPhrase)("wcf.global.success.delete")); + } + else { (0, Snackbar_1.showDefaultSuccessSnackbar)(); } } function setup(identifier, container) { container.addEventListener("interaction:execute", (event) => { if (event.detail.interaction === identifier) { - void handleDboAction(event.target, event.detail.objectName, event.detail.className, event.detail.actionName, event.detail.confirmationType, event.detail.confirmationMessage); + void handleDboAction(container, event.target, event.detail.objectName, event.detail.className, event.detail.actionName, event.detail.confirmationType, event.detail.confirmationMessage, event.detail.interactionEffect); } }); } diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/Rpc.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/Rpc.js index 1e576629bd8..a985e2b36e8 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/Rpc.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Interaction/Rpc.js @@ -6,11 +6,11 @@ * @license GNU Lesser General Public License * @since 6.2 */ -define(["require", "exports", "WoltLabSuite/Core/Api/DeleteObject", "WoltLabSuite/Core/Api/PostObject", "./Confirmation", "WoltLabSuite/Core/Component/Snackbar", "WoltLabSuite/Core/Language"], function (require, exports, DeleteObject_1, PostObject_1, Confirmation_1, Snackbar_1, Language_1) { +define(["require", "exports", "WoltLabSuite/Core/Api/DeleteObject", "WoltLabSuite/Core/Api/PostObject", "./Confirmation", "WoltLabSuite/Core/Component/Snackbar", "WoltLabSuite/Core/Language", "./InteractionEffect"], function (require, exports, DeleteObject_1, PostObject_1, Confirmation_1, Snackbar_1, Language_1, InteractionEffect_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setup = setup; - async function handleRpcInteraction(container, element, objectName, endpoint, confirmationType, customConfirmationMessage = "", invalidatesAllItems = false) { + async function handleRpcInteraction(container, element, objectName, endpoint, confirmationType, customConfirmationMessage = "", interactionEffect = InteractionEffect_1.InteractionEffect.ReloadItem) { const confirmationResult = await (0, Confirmation_1.handleConfirmation)(objectName, confirmationType, customConfirmationMessage); if (!confirmationResult.result) { return; @@ -27,28 +27,30 @@ define(["require", "exports", "WoltLabSuite/Core/Api/DeleteObject", "WoltLabSuit return; } } - if (confirmationType === Confirmation_1.ConfirmationType.Delete) { + if (interactionEffect === InteractionEffect_1.InteractionEffect.ReloadItem) { + element.dispatchEvent(new CustomEvent("interaction:invalidate", { + bubbles: true, + })); + } + else if (interactionEffect === InteractionEffect_1.InteractionEffect.ReloadList) { + container.dispatchEvent(new CustomEvent("interaction:invalidate-all")); + } + else { element.dispatchEvent(new CustomEvent("interaction:remove", { bubbles: true, })); + } + if (confirmationType === Confirmation_1.ConfirmationType.Delete) { (0, Snackbar_1.showSuccessSnackbar)((0, Language_1.getPhrase)("wcf.global.success.delete")); } else { - if (invalidatesAllItems) { - container.dispatchEvent(new CustomEvent("interaction:invalidate-all")); - } - else { - element.dispatchEvent(new CustomEvent("interaction:invalidate", { - bubbles: true, - })); - } (0, Snackbar_1.showDefaultSuccessSnackbar)(); } } function setup(identifier, container) { container.addEventListener("interaction:execute", (event) => { if (event.detail.interaction === identifier) { - void handleRpcInteraction(container, event.target, event.detail.objectName, event.detail.endpoint, event.detail.confirmationType, event.detail.confirmationMessage, event.detail.invalidatesAllItems === "true"); + void handleRpcInteraction(container, event.target, event.detail.objectName, event.detail.endpoint, event.detail.confirmationType, event.detail.confirmationMessage, event.detail.interactionEffect); } }); } diff --git a/wcfsetup/install/files/lib/system/interaction/DeleteInteraction.class.php b/wcfsetup/install/files/lib/system/interaction/DeleteInteraction.class.php index caae8bd8118..eb188eb9ea2 100644 --- a/wcfsetup/install/files/lib/system/interaction/DeleteInteraction.class.php +++ b/wcfsetup/install/files/lib/system/interaction/DeleteInteraction.class.php @@ -22,7 +22,8 @@ public function __construct( 'wcf.global.button.delete', InteractionConfirmationType::Delete, '', - $isAvailableCallback + $isAvailableCallback, + InteractionEffect::RemoveItem ); } } diff --git a/wcfsetup/install/files/lib/system/interaction/InteractionEffect.class.php b/wcfsetup/install/files/lib/system/interaction/InteractionEffect.class.php new file mode 100644 index 00000000000..d48f4d11662 --- /dev/null +++ b/wcfsetup/install/files/lib/system/interaction/InteractionEffect.class.php @@ -0,0 +1,27 @@ + + * @since 6.2 + */ +enum InteractionEffect +{ + case ReloadItem; + case ReloadList; + case RemoveItem; + + public function toString(): string + { + return match ($this) { + self::ReloadItem => 'ReloadItem', + self::ReloadList => 'ReloadList', + self::RemoveItem => 'RemoveItem', + }; + } +} diff --git a/wcfsetup/install/files/lib/system/interaction/LegacyDboInteraction.class.php b/wcfsetup/install/files/lib/system/interaction/LegacyDboInteraction.class.php index ca956dc07a7..ce26dd4dfe5 100644 --- a/wcfsetup/install/files/lib/system/interaction/LegacyDboInteraction.class.php +++ b/wcfsetup/install/files/lib/system/interaction/LegacyDboInteraction.class.php @@ -27,7 +27,8 @@ public function __construct( protected readonly string|\Closure $languageItem, protected readonly InteractionConfirmationType $confirmationType = InteractionConfirmationType::None, protected readonly string|\Closure $confirmationMessage = '', - ?\Closure $isAvailableCallback = null + ?\Closure $isAvailableCallback = null, + protected readonly InteractionEffect $interactionEffect = InteractionEffect::ReloadItem, ) { parent::__construct($identifier, $isAvailableCallback); } @@ -67,6 +68,7 @@ public function render(DatabaseObject $object): string data-action-name="{$actionName}" data-confirmation-type="{$this->confirmationType->toString()}" data-confirmation-message="{$confirmationMessage}" + data-interaction-effect="{$this->interactionEffect->toString()}" > {$label} diff --git a/wcfsetup/install/files/lib/system/interaction/RpcInteraction.class.php b/wcfsetup/install/files/lib/system/interaction/RpcInteraction.class.php index 69c29f25e18..6e1047693d3 100644 --- a/wcfsetup/install/files/lib/system/interaction/RpcInteraction.class.php +++ b/wcfsetup/install/files/lib/system/interaction/RpcInteraction.class.php @@ -27,7 +27,7 @@ public function __construct( protected readonly InteractionConfirmationType $confirmationType = InteractionConfirmationType::None, protected readonly string|\Closure $confirmationMessage = '', ?\Closure $isAvailableCallback = null, - protected readonly bool $invalidatesAllItems = false, + protected readonly InteractionEffect $interactionEffect = InteractionEffect::ReloadItem, ) { parent::__construct($identifier, $isAvailableCallback); } @@ -68,8 +68,6 @@ public function render(DatabaseObject $object): string } } - $invalidatesAllItems = $this->invalidatesAllItems ? 'true' : 'false'; - return << {$label} diff --git a/wcfsetup/install/files/lib/system/interaction/admin/LanguageInteractions.class.php b/wcfsetup/install/files/lib/system/interaction/admin/LanguageInteractions.class.php index eb58ece0ae9..3456712b6f6 100644 --- a/wcfsetup/install/files/lib/system/interaction/admin/LanguageInteractions.class.php +++ b/wcfsetup/install/files/lib/system/interaction/admin/LanguageInteractions.class.php @@ -8,6 +8,7 @@ use wcf\system\event\EventHandler; use wcf\system\interaction\AbstractInteractionProvider; use wcf\system\interaction\DeleteInteraction; +use wcf\system\interaction\InteractionEffect; use wcf\system\interaction\LinkInteraction; use wcf\system\interaction\RpcInteraction; @@ -30,7 +31,7 @@ public function __construct() "core/languages/%s/default", "wcf.acp.language.setAsDefault", isAvailableCallback: static fn(Language $language) => !$language->isDefault, - invalidatesAllItems: true + interactionEffect: InteractionEffect::ReloadList ), new DeleteInteraction( "core/languages/%s", diff --git a/wcfsetup/install/files/lib/system/interaction/admin/StyleInteractions.class.php b/wcfsetup/install/files/lib/system/interaction/admin/StyleInteractions.class.php index 014457d0d22..d06479743ce 100644 --- a/wcfsetup/install/files/lib/system/interaction/admin/StyleInteractions.class.php +++ b/wcfsetup/install/files/lib/system/interaction/admin/StyleInteractions.class.php @@ -9,6 +9,7 @@ use wcf\system\interaction\AbstractInteractionProvider; use wcf\system\interaction\DeleteInteraction; use wcf\system\interaction\InteractionConfirmationType; +use wcf\system\interaction\InteractionEffect; use wcf\system\interaction\LinkInteraction; use wcf\system\interaction\RpcInteraction; use wcf\system\WCF; @@ -32,7 +33,7 @@ public function __construct() 'core/styles/%s/set-as-default', 'wcf.acp.style.button.setAsDefault', isAvailableCallback: static fn(Style $object) => !$object->isDefault, - invalidatesAllItems: true + interactionEffect: InteractionEffect::ReloadList ), new RpcInteraction( 'copy', @@ -43,7 +44,7 @@ public function __construct() 'wcf.acp.style.copyStyle.confirmMessage', ['style' => $object] ), - invalidatesAllItems: true + interactionEffect: InteractionEffect::ReloadList ), new LinkInteraction('export', StyleExportForm::class, 'wcf.acp.style.exportStyle'), new RpcInteraction(