From 7e04e684e5088b90ef447d00b25f0da18043af4d Mon Sep 17 00:00:00 2001 From: Marcel Werk Date: Mon, 15 Aug 2022 16:18:47 +0200 Subject: [PATCH] Overhaul of the user object watch button --- .../templates/__userObjectWatchButton.tpl | 29 ++++++ .../templates/categoryArticleList.tpl | 15 +-- ts/WoltLabSuite/Core/Ui/User/ObjectWatch.ts | 93 +++++++++++++++++++ wcfsetup/install/files/js/WCF.User.js | 2 + .../WoltLabSuite/Core/Ui/User/ObjectWatch.js | 85 +++++++++++++++++ wcfsetup/install/files/style/ui/dropdown.scss | 15 +++ wcfsetup/install/lang/de.xml | 5 + wcfsetup/install/lang/en.xml | 5 + 8 files changed, 236 insertions(+), 13 deletions(-) create mode 100644 com.woltlab.wcf/templates/__userObjectWatchButton.tpl create mode 100644 ts/WoltLabSuite/Core/Ui/User/ObjectWatch.ts create mode 100644 wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/ObjectWatch.js diff --git a/com.woltlab.wcf/templates/__userObjectWatchButton.tpl b/com.woltlab.wcf/templates/__userObjectWatchButton.tpl new file mode 100644 index 0000000000..4bc2afaaac --- /dev/null +++ b/com.woltlab.wcf/templates/__userObjectWatchButton.tpl @@ -0,0 +1,29 @@ +{if $__wcf->user->userID} + + + +{/if} diff --git a/com.woltlab.wcf/templates/categoryArticleList.tpl b/com.woltlab.wcf/templates/categoryArticleList.tpl index e2743f7e21..fecbe3989e 100644 --- a/com.woltlab.wcf/templates/categoryArticleList.tpl +++ b/com.woltlab.wcf/templates/categoryArticleList.tpl @@ -63,9 +63,8 @@ {/capture} {capture assign='contentInteractionButtons'} - {if $__wcf->user->userID} - {lang}wcf.user.objectWatch.button.subscribe{/lang} - {/if} + {include file='__userObjectWatchButton' isSubscribed=$category->isSubscribed() objectType="com.woltlab.wcf.article.category" objectID=$category->categoryID} + {if ARTICLE_ENABLE_VISIT_TRACKING} {lang}wcf.global.button.markAllAsRead{/lang} {/if} @@ -109,16 +108,6 @@ {/if} - - {include file='articleAddDialog'} {include file='footer'} diff --git a/ts/WoltLabSuite/Core/Ui/User/ObjectWatch.ts b/ts/WoltLabSuite/Core/Ui/User/ObjectWatch.ts new file mode 100644 index 0000000000..8304a6d4b4 --- /dev/null +++ b/ts/WoltLabSuite/Core/Ui/User/ObjectWatch.ts @@ -0,0 +1,93 @@ +/** + * Handles the object watch button. + * + * @author Marcel Werk + * @copyright 2001-2022 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Ui/User/ObjectWatch + * @since 6.0 + */ + +import * as Ajax from "../../Ajax"; +import * as UiNotification from "../Notification"; +import * as Language from "../../Language"; +import * as EventHandler from "../../Event/Handler"; + +const dropdowns = new Map>(); + +async function click(element: HTMLElement): Promise { + const dropdown = element.closest(".userObjectWatchDropdown") as HTMLElement; + const subscribe = parseInt(element.dataset.subscribe!, 10); + const objectID = parseInt(dropdown.dataset.objectId!, 10); + const objectType = dropdown.dataset.objectType!; + + await Ajax.dboAction("saveSubscription", "wcf\\data\\user\\object\\watch\\UserObjectWatchAction") + .payload({ + enableNotification: 1, + objectID, + objectType, + subscribe, + }) + .dispatch(); + + if (dropdowns.has(objectID)) { + dropdowns.get(objectID)!.forEach((element) => { + element.querySelectorAll(".userObjectWatchSelect").forEach((li) => { + li.classList.remove("active"); + }); + + element.querySelector(`.userObjectWatchSelect[data-subscribe="${subscribe}"]`)?.classList.add("active"); + }); + } + + document + .querySelectorAll(`.userObjectWatchDropdownToggle[data-object-type="${objectType}"][data-object-id="${objectID}"]`) + .forEach((element: HTMLElement) => { + const icon = element.querySelector(".icon")!; + const label = element.querySelector("span:not(.icon)")!; + + if (subscribe) { + element.classList.add("active"); + icon.classList.remove("fa-bookmark-o"); + icon.classList.add("fa-bookmark"); + label.textContent = Language.get(`wcf.user.objectWatch.button.subscribed`); + } else { + element.classList.remove("active"); + icon.classList.remove("fa-bookmark"); + icon.classList.add("fa-bookmark-o"); + label.textContent = Language.get("wcf.user.objectWatch.button.subscribe"); + } + + element.dataset.isSubscribed = subscribe.toString(); + }); + + EventHandler.fire("com.woltlab.wcf.objectWatch", "updatedSubscription"); + UiNotification.show(); +} + +export function setup(): void { + document.querySelectorAll(".userObjectWatchDropdown").forEach((element: HTMLElement) => { + if (!element.dataset.objectId) { + throw new Error("Missing objectId for '.userObjectWatchDropdown' element."); + } + + const objectId = parseInt(element.dataset.objectId, 10); + + if (!dropdowns.has(objectId)) { + dropdowns.set(objectId, new Set()); + } + + dropdowns.get(objectId)!.add(element); + + element.querySelectorAll(".userObjectWatchSelect").forEach((element: HTMLElement) => { + if (!element.dataset.subscribe) { + throw new Error("Missing 'data-subscribe' attribute for '.userObjectWatchSelect' element."); + } + + element.addEventListener("click", (event) => { + event.preventDefault(); + void click(element); + }); + }); + }); +} diff --git a/wcfsetup/install/files/js/WCF.User.js b/wcfsetup/install/files/js/WCF.User.js index 63fdce1837..0bd48341dd 100644 --- a/wcfsetup/install/files/js/WCF.User.js +++ b/wcfsetup/install/files/js/WCF.User.js @@ -2072,6 +2072,8 @@ WCF.User.ObjectWatch = {}; if (COMPILER_TARGET_DEFAULT) { /** * Handles subscribe/unsubscribe links. + * + * @deprecated since 6.0, use `WoltLabSuite/Core/Ui/User/ObjectWatch` instead. */ WCF.User.ObjectWatch.Subscribe = Class.extend({ /** diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/ObjectWatch.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/ObjectWatch.js new file mode 100644 index 0000000000..c9beb674ab --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/ObjectWatch.js @@ -0,0 +1,85 @@ +/** + * Handles the object watch button. + * + * @author Marcel Werk + * @copyright 2001-2022 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Ui/User/ObjectWatch + * @since 6.0 + */ +define(["require", "exports", "tslib", "../../Ajax", "../Notification", "../../Language", "../../Event/Handler"], function (require, exports, tslib_1, Ajax, UiNotification, Language, EventHandler) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.setup = void 0; + Ajax = tslib_1.__importStar(Ajax); + UiNotification = tslib_1.__importStar(UiNotification); + Language = tslib_1.__importStar(Language); + EventHandler = tslib_1.__importStar(EventHandler); + const dropdowns = new Map(); + async function click(element) { + const dropdown = element.closest(".userObjectWatchDropdown"); + const subscribe = parseInt(element.dataset.subscribe, 10); + const objectID = parseInt(dropdown.dataset.objectId, 10); + const objectType = dropdown.dataset.objectType; + await Ajax.dboAction("saveSubscription", "wcf\\data\\user\\object\\watch\\UserObjectWatchAction") + .payload({ + enableNotification: 1, + objectID, + objectType, + subscribe, + }) + .dispatch(); + if (dropdowns.has(objectID)) { + dropdowns.get(objectID).forEach((element) => { + var _a; + element.querySelectorAll(".userObjectWatchSelect").forEach((li) => { + li.classList.remove("active"); + }); + (_a = element.querySelector(`.userObjectWatchSelect[data-subscribe="${subscribe}"]`)) === null || _a === void 0 ? void 0 : _a.classList.add("active"); + }); + } + document + .querySelectorAll(`.userObjectWatchDropdownToggle[data-object-type="${objectType}"][data-object-id="${objectID}"]`) + .forEach((element) => { + const icon = element.querySelector(".icon"); + const label = element.querySelector("span:not(.icon)"); + if (subscribe) { + element.classList.add("active"); + icon.classList.remove("fa-bookmark-o"); + icon.classList.add("fa-bookmark"); + label.textContent = Language.get(`wcf.user.objectWatch.button.subscribed`); + } + else { + element.classList.remove("active"); + icon.classList.remove("fa-bookmark"); + icon.classList.add("fa-bookmark-o"); + label.textContent = Language.get("wcf.user.objectWatch.button.subscribe"); + } + element.dataset.isSubscribed = subscribe.toString(); + }); + EventHandler.fire("com.woltlab.wcf.objectWatch", "updatedSubscription"); + UiNotification.show(); + } + function setup() { + document.querySelectorAll(".userObjectWatchDropdown").forEach((element) => { + if (!element.dataset.objectId) { + throw new Error("Missing objectId for '.userObjectWatchDropdown' element."); + } + const objectId = parseInt(element.dataset.objectId, 10); + if (!dropdowns.has(objectId)) { + dropdowns.set(objectId, new Set()); + } + dropdowns.get(objectId).add(element); + element.querySelectorAll(".userObjectWatchSelect").forEach((element) => { + if (!element.dataset.subscribe) { + throw new Error("Missing 'data-subscribe' attribute for '.userObjectWatchSelect' element."); + } + element.addEventListener("click", (event) => { + event.preventDefault(); + void click(element); + }); + }); + }); + } + exports.setup = setup; +}); diff --git a/wcfsetup/install/files/style/ui/dropdown.scss b/wcfsetup/install/files/style/ui/dropdown.scss index c1b33f9afd..6360a227d0 100644 --- a/wcfsetup/install/files/style/ui/dropdown.scss +++ b/wcfsetup/install/files/style/ui/dropdown.scss @@ -101,3 +101,18 @@ display: inline-flex !important; } } + +.userObjectWatchSelect { + .userObjectWatchSelectHeader { + font-weight: 600; + padding-bottom: 0; + } + + .userObjectWatchSelectDescription { + @include wcfFontSmall; + + color: $wcfContentDimmedText; + padding-top: 0; + white-space: normal; + } +} diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 1d1cbafdc6..0577afa07d 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -5467,6 +5467,11 @@ Benachrichtigungen auf {PAGE_TITLE|phra + + + + + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index b7172fd06d..5e4ffffcf5 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -5469,6 +5469,11 @@ your notifications on {PAGE_TITLE|phras + + + + + -- 2.20.1