mod/forum/amd/src/forum_overview_toggle.js

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Handle forum subscription/tracking toggling.
 *
 * @module     mod_forum/forum_overview_toggle
 * @copyright  2025 Sara Arjona <sara@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

import Notification from 'core/notification';
import {getString} from 'core/str';
import Repository from 'mod_forum/repository';

/**
 * Register event listeners for the subscription/tracking toggles in the overview.
 * @param {HTMLElement} toggleElement The toggle root element
 */
function registerEventListeners(toggleElement) {
    toggleElement.addEventListener('change', () => {
        if (toggleElement.dataset.type === 'forum-subscription-toggle') {
            subscriptionToggleClickHandler(toggleElement);
        }
        if (toggleElement.dataset.type === 'forum-track-toggle') {
            trackToggleClickHanldler(toggleElement);
        }
    });
}

/**
 * Toggle subscription element click handler.
 *
 * @param {HTMLElement} toggleElement The toggle element that was clicked
 * @return {Promise<void>}
 */
async function subscriptionToggleClickHandler(toggleElement) {
    const forumId = toggleElement.dataset.forumid;
    const newState = toggleElement.dataset.targetstate;
    if (!forumId || !newState) {
        return;
    }
    try {
        const context = await Repository.setForumSubscriptionState(forumId, newState);
        const newTargetState = !!context.userstate.subscribed;

        updateSwitchState(
            toggleElement,
            newTargetState,
            newTargetState ? 'subscribe' : 'unsubscribe',
        );
    } catch (error) {
        Notification.exception(error);
    }
}

/**
 * Toggle track element click handler.
 *
 * @param {HTMLElement} toggleElement The toggle element that was clicked
 * @return {Promise<void>}
 */
async function trackToggleClickHanldler(toggleElement) {
    const forumId = toggleElement.dataset.forumid;
    const newState = toggleElement.dataset.targetstate;
    if (!forumId || !newState) {
        return;
    }
    try {
        const context = await Repository.setForumTrackingState(forumId, newState);
        const newTargetState = !!context.userstate.tracked;

        updateSwitchState(
            toggleElement,
            newTargetState,
            newTargetState ? 'trackingon' : 'trackingoff',
        );
    } catch (error) {
        Notification.exception(error);
    }
}

/**
 * Update the switch state of the toggle element.
 *
 * @param {HTMLElement} toggleElement The toggle element to update
 * @param {Boolean} newTargetState The new target state to set (true for subscribed, false for unsubscribed)
 * @param {string} stringKey The string key to retrieve the label text
 * @return {Promise<void>}
 */
async function updateSwitchState(toggleElement, newTargetState, stringKey) {
    toggleElement.dataset.targetstate = newTargetState ? 0 : 1;
    const string = await getString(stringKey, 'mod_forum');
    const label = toggleElement.closest('td').querySelector(`label[for="${toggleElement.id}"] span`);
    label.textContent = string;
}

/**
 * Initialize the forum overview toggle functionality.
 *
 * @param {string} toggleSelector The CSS selector for the toggle element to initialize
 * @throws {Error} If no elements are found with the provided selector
 */
export const init = (toggleSelector) => {
    const toggleElement = document.querySelector(toggleSelector);
    if (!toggleElement) {
        // If the user cannot track/subscribe to any course forum, the toggle will not be present.
        return;
    }
    registerEventListeners(toggleElement);
};