diff --git a/ts/WoltLabSuite/Core/Component/Inline/Actions/Disable.ts b/ts/WoltLabSuite/Core/Component/Inline/Actions/Disable.ts new file mode 100644 index 00000000000..2745b02da98 --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/Inline/Actions/Disable.ts @@ -0,0 +1,31 @@ +/** + * Inline editor action to disable an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ + +import { InlineEditor } from "WoltLabSuite/Core/Component/Inline/Editor"; +import { Simple } from "WoltLabSuite/Core/Component/Inline/Actions/Simple"; + +export class Disable extends Simple { + constructor(inlineEditor: InlineEditor, endpoint: string | URL) { + super(inlineEditor, "wcf.global.button.disable", endpoint); + } + + responseOk(): void { + this.inlineEditor.update({ + isDisabled: 1, + }); + } + + isVisible(): boolean { + return ( + this.inlineEditor.getPermissions()["canEnable"] && + !this.inlineEditor.getState("isDeleted") && + !this.inlineEditor.getState("isDisabled") + ); + } +} diff --git a/ts/WoltLabSuite/Core/Component/Inline/Actions/Enable.ts b/ts/WoltLabSuite/Core/Component/Inline/Actions/Enable.ts new file mode 100644 index 00000000000..03b5778933a --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/Inline/Actions/Enable.ts @@ -0,0 +1,70 @@ +/** + * Inline editor action to enable an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ + +import { Action, InlineEditor } from "WoltLabSuite/Core/Component/Inline/Editor"; +import { DropdownBuilderItemData } from "WoltLabSuite/Core/Ui/Dropdown/Builder"; +import { ApiResult, apiResultFromError, apiResultFromValue } from "WoltLabSuite/Core/Api/Result"; +import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend"; +import { dialogFactory } from "WoltLabSuite/Core/Component/Dialog"; +import { getPhrase } from "WoltLabSuite/Core/Language"; + +export class Enable implements Action { + protected readonly inlineEditor: InlineEditor; + protected readonly endpoint: string | URL; + protected readonly useFormBuilder: boolean; + + constructor(inlineEditor: InlineEditor, endpoint: string | URL, useFormBuilder: boolean = false) { + this.inlineEditor = inlineEditor; + this.endpoint = endpoint; + this.useFormBuilder = useFormBuilder; + } + + get item(): DropdownBuilderItemData { + return { + label: getPhrase("wcf.global.button.enable"), + callback: async () => { + if (this.useFormBuilder) { + const response = await dialogFactory() + .usingFormBuilder() + .fromEndpoint<{ isDisabled: boolean }>(this.endpoint.toString()); + + if (response.ok) { + this.inlineEditor.update({ + isDisabled: response.result.isDisabled ? 1 : 0, + }); + } + } else { + if ((await enable(this.endpoint)).ok) { + this.inlineEditor.update({ + isDisabled: 0, + }); + } + } + }, + }; + } + + isVisible(): boolean { + return ( + this.inlineEditor.getPermissions()["canEnable"] && + !this.inlineEditor.getState("isDeleted") && + this.inlineEditor.getState("isDisabled") + ); + } +} + +async function enable(endpoint: string | URL): Promise> { + try { + await prepareRequest(endpoint).post().fetchAsJson(); + } catch (e) { + return apiResultFromError(e); + } + + return apiResultFromValue([]); +} diff --git a/ts/WoltLabSuite/Core/Component/Inline/Actions/Restore.ts b/ts/WoltLabSuite/Core/Component/Inline/Actions/Restore.ts new file mode 100644 index 00000000000..16b38545851 --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/Inline/Actions/Restore.ts @@ -0,0 +1,27 @@ +/** + * Inline editor action to restore an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ + +import { InlineEditor } from "WoltLabSuite/Core/Component/Inline/Editor"; +import { Simple } from "WoltLabSuite/Core/Component/Inline/Actions/Simple"; + +export class Restore extends Simple { + constructor(inlineEditor: InlineEditor, endpoint: string | URL) { + super(inlineEditor, "wcf.global.button.restore", endpoint); + } + + responseOk(): void { + this.inlineEditor.update({ + isDeleted: 0, + }); + } + + isVisible(): boolean { + return this.inlineEditor.getPermissions()["canRestore"] && this.inlineEditor.getState("isDeleted"); + } +} diff --git a/ts/WoltLabSuite/Core/Component/Inline/Actions/Simple.ts b/ts/WoltLabSuite/Core/Component/Inline/Actions/Simple.ts new file mode 100644 index 00000000000..00e6d388741 --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/Inline/Actions/Simple.ts @@ -0,0 +1,50 @@ +/** + * Inline editor action to restore an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ + +import { Action, InlineEditor } from "WoltLabSuite/Core/Component/Inline/Editor"; +import { DropdownBuilderItemData } from "WoltLabSuite/Core/Ui/Dropdown/Builder"; +import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend"; +import { apiResultFromError, apiResultFromValue, ApiResult } from "WoltLabSuite/Core/Api/Result"; +import { getPhrase } from "WoltLabSuite/Core/Language"; + +export abstract class Simple implements Action { + protected readonly inlineEditor: InlineEditor; + protected readonly endpoint: string | URL; + protected readonly label: string; + + protected constructor(inlineEditor: InlineEditor, label: string, endpoint: string | URL) { + this.inlineEditor = inlineEditor; + this.endpoint = endpoint; + this.label = label; + } + + get item(): DropdownBuilderItemData { + return { + label: getPhrase(this.label), + callback: async () => { + const response = await request(this.endpoint); + if (response.ok) { + this.responseOk(); + } + }, + }; + } + + abstract responseOk(): void; +} + +async function request(endpoint: string | URL): Promise> { + try { + await prepareRequest(endpoint).post().fetchAsJson(); + } catch (e) { + return apiResultFromError(e); + } + + return apiResultFromValue([]); +} diff --git a/ts/WoltLabSuite/Core/Component/Inline/Actions/Trash.ts b/ts/WoltLabSuite/Core/Component/Inline/Actions/Trash.ts new file mode 100644 index 00000000000..fc12ff8fbe2 --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/Inline/Actions/Trash.ts @@ -0,0 +1,70 @@ +/** + * Inline editor action to trash an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ + +import { Action, InlineEditor } from "WoltLabSuite/Core/Component/Inline/Editor"; +import { DropdownBuilderItemData } from "WoltLabSuite/Core/Ui/Dropdown/Builder"; +import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend"; +import { apiResultFromError, apiResultFromValue, ApiResult } from "WoltLabSuite/Core/Api/Result"; +import { confirmationFactory } from "WoltLabSuite/Core/Component/Confirmation"; +import { getPhrase } from "WoltLabSuite/Core/Language"; + +export class Trash implements Action { + protected readonly inlineEditor: InlineEditor; + protected readonly endpoint: string | URL; + protected readonly title: string; + + constructor(inlineEditor: InlineEditor, title: string, endpoint: string | URL) { + this.inlineEditor = inlineEditor; + this.endpoint = endpoint; + this.title = title; + } + + get item(): DropdownBuilderItemData { + return { + label: getPhrase("wcf.global.button.trash"), + callback: async () => { + const result = await confirmationFactory().softDelete(this.title, true); + if (!result.result) { + return; + } + + const response = await trash(this.endpoint, result.reason); + if (response.ok) { + this.inlineEditor.update({ + isDeleted: 1, + deleteNote: response.value, + }); + } + }, + }; + } + + isVisible(): boolean { + return this.inlineEditor.getPermissions()["canTrash"] && !this.inlineEditor.getState("isDeleted"); + } +} + +type Response = { + deleteNote: string; +}; + +async function trash(endpoint: string | URL, reason: string): Promise> { + let response: Response; + try { + response = (await prepareRequest(endpoint) + .post({ + reason, + }) + .fetchAsJson()) as Response; + } catch (e) { + return apiResultFromError(e); + } + + return apiResultFromValue(response.deleteNote); +} diff --git a/ts/WoltLabSuite/Core/Component/Inline/Editor.ts b/ts/WoltLabSuite/Core/Component/Inline/Editor.ts new file mode 100644 index 00000000000..d857680f8cd --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/Inline/Editor.ts @@ -0,0 +1,131 @@ +/** + * Provides an inline editor for objects using a drop-down menu. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ + +import { + DropdownBuilderItemData, + create as createDropdownMenu, + setItems as setDropdownItems, +} from "WoltLabSuite/Core/Ui/Dropdown/Builder"; +import { show as showNotification } from "WoltLabSuite/Core/Ui/Notification"; +import { stringToBool } from "WoltLabSuite/Core/Core"; +import UiDropdownSimple from "WoltLabSuite/Core/Ui/Dropdown/Simple"; + +export interface Action { + isVisible?: () => boolean; + + get item(): DropdownBuilderItemData; +} + +export type State = string | boolean | number; + +const inlineEditors = new Map(); + +export class InlineEditor { + protected readonly element: HTMLElement; + readonly #dropdownToggle: HTMLElement; + protected permissions: Record = {}; + readonly #dropdownMenu: HTMLUListElement; + readonly #actions: Action[] = []; + + public constructor(element: HTMLElement, dropdownToggleSelector: string) { + this.element = element; + this.#dropdownToggle = this.element.querySelector(dropdownToggleSelector) as HTMLElement; + this.#dropdownMenu = createDropdownMenu([]); + + // @see WoltLabSuite/Core/Ui/Dropdown/Builder::attach() + UiDropdownSimple.initFragment(this.#dropdownToggle, this.#dropdownMenu); + + this.#dropdownToggle.addEventListener("click", (event) => { + event.preventDefault(); + event.stopPropagation(); + + // Rebuild the menu to ensure the menu items are displayed correctly, + // as states may change externally and cannot be detected automatically + this.#rebuildDropdownMenu(); + + UiDropdownSimple.toggleDropdown(this.#dropdownToggle.id); + }); + + inlineEditors.set(this.element, this); + } + + /** + * Gets the state of a property from the element's dataset as a boolean. + */ + public getState(propertyName: string): boolean { + if (!Object.prototype.hasOwnProperty.call(this.element.dataset, propertyName)) { + return false; + } + + return stringToBool(this.element.dataset[propertyName]!); + } + + /** + * Updates the element's dataset with the provided data. + */ + public update(data: Record): void { + showNotification(); + + Object.entries(data).forEach(([key, value]) => { + this.element.dataset[key] = typeof value === "boolean" ? (value ? "1" : "0") : value.toString(); + }); + } + + /** + * Merge the current permissions with the provided permissions. + */ + public addPermissions(permissions: Record): void { + this.permissions = { ...this.permissions, ...permissions }; + } + + /** + * Gets the permissions for the inline editor. + */ + public getPermissions(): Record { + return this.permissions; + } + + /** + * Adds an action to the inline editor. + */ + public addAction(action: Action): void { + this.#actions.push(action); + } + + /** + * Adds multiple actions to the inline editor. + */ + public addActions(actions: Action[]): void { + this.#actions.push(...actions); + } + + /** + * Rebuilds the dropdown menu based on the current menu items and their visibility. + */ + #rebuildDropdownMenu(): void { + const dropdownMenuItems = this.#actions + .filter((item) => { + return item.isVisible === undefined || item.isVisible(); + }) + .map((item) => item.item); + + if (dropdownMenuItems.length === 0) { + this.#dropdownMenu.innerHTML = ""; + } else { + setDropdownItems(this.#dropdownMenu, dropdownMenuItems); + } + } +} + +/** + * Gets the inline editor instance associated with the given element. + */ +export function getInlineEditor(element: HTMLElement): InlineEditor | undefined { + return inlineEditors.get(element); +} diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Disable.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Disable.js new file mode 100644 index 00000000000..9f166f52015 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Disable.js @@ -0,0 +1,29 @@ +/** + * Inline editor action to disable an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +define(["require", "exports", "WoltLabSuite/Core/Component/Inline/Actions/Simple"], function (require, exports, Simple_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Disable = void 0; + class Disable extends Simple_1.Simple { + constructor(inlineEditor, endpoint) { + super(inlineEditor, "wcf.global.button.disable", endpoint); + } + responseOk() { + this.inlineEditor.update({ + isDisabled: 1, + }); + } + isVisible() { + return (this.inlineEditor.getPermissions()["canEnable"] && + !this.inlineEditor.getState("isDeleted") && + !this.inlineEditor.getState("isDisabled")); + } + } + exports.Disable = Disable; +}); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Enable.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Enable.js new file mode 100644 index 00000000000..19675f91a2e --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Enable.js @@ -0,0 +1,62 @@ +/** + * Inline editor action to enable an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +define(["require", "exports", "WoltLabSuite/Core/Api/Result", "WoltLabSuite/Core/Ajax/Backend", "WoltLabSuite/Core/Component/Dialog", "WoltLabSuite/Core/Language"], function (require, exports, Result_1, Backend_1, Dialog_1, Language_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Enable = void 0; + class Enable { + inlineEditor; + endpoint; + useFormBuilder; + constructor(inlineEditor, endpoint, useFormBuilder = false) { + this.inlineEditor = inlineEditor; + this.endpoint = endpoint; + this.useFormBuilder = useFormBuilder; + } + get item() { + return { + label: (0, Language_1.getPhrase)("wcf.global.button.enable"), + callback: async () => { + if (this.useFormBuilder) { + const response = await (0, Dialog_1.dialogFactory)() + .usingFormBuilder() + .fromEndpoint(this.endpoint.toString()); + if (response.ok) { + this.inlineEditor.update({ + isDisabled: response.result.isDisabled ? 1 : 0, + }); + } + } + else { + if ((await enable(this.endpoint)).ok) { + this.inlineEditor.update({ + isDisabled: 0, + }); + } + } + }, + }; + } + isVisible() { + return (this.inlineEditor.getPermissions()["canEnable"] && + !this.inlineEditor.getState("isDeleted") && + this.inlineEditor.getState("isDisabled")); + } + } + exports.Enable = Enable; + async function enable(endpoint) { + try { + await (0, Backend_1.prepareRequest)(endpoint).post().fetchAsJson(); + } + catch (e) { + return (0, Result_1.apiResultFromError)(e); + } + return (0, Result_1.apiResultFromValue)([]); + } +}); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Restore.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Restore.js new file mode 100644 index 00000000000..8e2074274d6 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Restore.js @@ -0,0 +1,27 @@ +/** + * Inline editor action to restore an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +define(["require", "exports", "WoltLabSuite/Core/Component/Inline/Actions/Simple"], function (require, exports, Simple_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Restore = void 0; + class Restore extends Simple_1.Simple { + constructor(inlineEditor, endpoint) { + super(inlineEditor, "wcf.global.button.restore", endpoint); + } + responseOk() { + this.inlineEditor.update({ + isDeleted: 0, + }); + } + isVisible() { + return this.inlineEditor.getPermissions()["canRestore"] && this.inlineEditor.getState("isDeleted"); + } + } + exports.Restore = Restore; +}); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Simple.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Simple.js new file mode 100644 index 00000000000..3885dbac108 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Simple.js @@ -0,0 +1,44 @@ +/** + * Inline editor action to restore an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +define(["require", "exports", "WoltLabSuite/Core/Ajax/Backend", "WoltLabSuite/Core/Api/Result", "WoltLabSuite/Core/Language"], function (require, exports, Backend_1, Result_1, Language_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Simple = void 0; + class Simple { + inlineEditor; + endpoint; + label; + constructor(inlineEditor, label, endpoint) { + this.inlineEditor = inlineEditor; + this.endpoint = endpoint; + this.label = label; + } + get item() { + return { + label: (0, Language_1.getPhrase)(this.label), + callback: async () => { + const response = await request(this.endpoint); + if (response.ok) { + this.responseOk(); + } + }, + }; + } + } + exports.Simple = Simple; + async function request(endpoint) { + try { + await (0, Backend_1.prepareRequest)(endpoint).post().fetchAsJson(); + } + catch (e) { + return (0, Result_1.apiResultFromError)(e); + } + return (0, Result_1.apiResultFromValue)([]); + } +}); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Trash.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Trash.js new file mode 100644 index 00000000000..91d22576abf --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Actions/Trash.js @@ -0,0 +1,59 @@ +/** + * Inline editor action to trash an object. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +define(["require", "exports", "WoltLabSuite/Core/Ajax/Backend", "WoltLabSuite/Core/Api/Result", "WoltLabSuite/Core/Component/Confirmation", "WoltLabSuite/Core/Language"], function (require, exports, Backend_1, Result_1, Confirmation_1, Language_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Trash = void 0; + class Trash { + inlineEditor; + endpoint; + title; + constructor(inlineEditor, title, endpoint) { + this.inlineEditor = inlineEditor; + this.endpoint = endpoint; + this.title = title; + } + get item() { + return { + label: (0, Language_1.getPhrase)("wcf.global.button.trash"), + callback: async () => { + const result = await (0, Confirmation_1.confirmationFactory)().softDelete(this.title, true); + if (!result.result) { + return; + } + const response = await trash(this.endpoint, result.reason); + if (response.ok) { + this.inlineEditor.update({ + isDeleted: 1, + deleteNote: response.value, + }); + } + }, + }; + } + isVisible() { + return this.inlineEditor.getPermissions()["canTrash"] && !this.inlineEditor.getState("isDeleted"); + } + } + exports.Trash = Trash; + async function trash(endpoint, reason) { + let response; + try { + response = (await (0, Backend_1.prepareRequest)(endpoint) + .post({ + reason, + }) + .fetchAsJson()); + } + catch (e) { + return (0, Result_1.apiResultFromError)(e); + } + return (0, Result_1.apiResultFromValue)(response.deleteNote); + } +}); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Editor.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Editor.js new file mode 100644 index 00000000000..9bc8449f0b2 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Inline/Editor.js @@ -0,0 +1,104 @@ +/** + * Provides an inline editor for objects using a drop-down menu. + * + * @author Olaf Braun + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +define(["require", "exports", "tslib", "WoltLabSuite/Core/Ui/Dropdown/Builder", "WoltLabSuite/Core/Ui/Notification", "WoltLabSuite/Core/Core", "WoltLabSuite/Core/Ui/Dropdown/Simple"], function (require, exports, tslib_1, Builder_1, Notification_1, Core_1, Simple_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.InlineEditor = void 0; + exports.getInlineEditor = getInlineEditor; + Simple_1 = tslib_1.__importDefault(Simple_1); + const inlineEditors = new Map(); + class InlineEditor { + element; + #dropdownToggle; + permissions = {}; + #dropdownMenu; + #actions = []; + constructor(element, dropdownToggleSelector) { + this.element = element; + this.#dropdownToggle = this.element.querySelector(dropdownToggleSelector); + this.#dropdownMenu = (0, Builder_1.create)([]); + // @see WoltLabSuite/Core/Ui/Dropdown/Builder::attach() + Simple_1.default.initFragment(this.#dropdownToggle, this.#dropdownMenu); + this.#dropdownToggle.addEventListener("click", (event) => { + event.preventDefault(); + event.stopPropagation(); + // Rebuild the menu to ensure the menu items are displayed correctly, + // as states may change externally and cannot be detected automatically + this.#rebuildDropdownMenu(); + Simple_1.default.toggleDropdown(this.#dropdownToggle.id); + }); + inlineEditors.set(this.element, this); + } + /** + * Gets the state of a property from the element's dataset as a boolean. + */ + getState(propertyName) { + if (!Object.prototype.hasOwnProperty.call(this.element.dataset, propertyName)) { + return false; + } + return (0, Core_1.stringToBool)(this.element.dataset[propertyName]); + } + /** + * Updates the element's dataset with the provided data. + */ + update(data) { + (0, Notification_1.show)(); + Object.entries(data).forEach(([key, value]) => { + this.element.dataset[key] = typeof value === "boolean" ? (value ? "1" : "0") : value.toString(); + }); + } + /** + * Merge the current permissions with the provided permissions. + */ + addPermissions(permissions) { + this.permissions = { ...this.permissions, ...permissions }; + } + /** + * Gets the permissions for the inline editor. + */ + getPermissions() { + return this.permissions; + } + /** + * Adds an action to the inline editor. + */ + addAction(action) { + this.#actions.push(action); + } + /** + * Adds multiple actions to the inline editor. + */ + addActions(actions) { + this.#actions.push(...actions); + } + /** + * Rebuilds the dropdown menu based on the current menu items and their visibility. + */ + #rebuildDropdownMenu() { + const dropdownMenuItems = this.#actions + .filter((item) => { + return item.isVisible === undefined || item.isVisible(); + }) + .map((item) => item.item); + if (dropdownMenuItems.length === 0) { + this.#dropdownMenu.innerHTML = ""; + } + else { + (0, Builder_1.setItems)(this.#dropdownMenu, dropdownMenuItems); + } + } + } + exports.InlineEditor = InlineEditor; + /** + * Gets the inline editor instance associated with the given element. + */ + function getInlineEditor(element) { + return inlineEditors.get(element); + } +}); diff --git a/wcfsetup/install/files/lib/system/event/listener/PreloadPhrasesCollectingListener.class.php b/wcfsetup/install/files/lib/system/event/listener/PreloadPhrasesCollectingListener.class.php index 503adcdfd09..64c44596829 100644 --- a/wcfsetup/install/files/lib/system/event/listener/PreloadPhrasesCollectingListener.class.php +++ b/wcfsetup/install/files/lib/system/event/listener/PreloadPhrasesCollectingListener.class.php @@ -80,6 +80,8 @@ public function __invoke(PreloadPhrasesCollecting $event): void $event->preload('wcf.global.button.submit'); $event->preload('wcf.global.button.upload'); $event->preload('wcf.global.button.replace'); + $event->preload('wcf.global.button.trash'); + $event->preload('wcf.global.button.restore'); $event->preload('wcf.global.confirmation.cancel'); $event->preload('wcf.global.confirmation.confirm');