Source: clickActions.js

"use strict";
// SPDX-License-Identifier: GPL-3.0-or-later
// myMPD (c) 2018-2024 Juergen Mang <mail@jcgames.de>
// https://github.com/jcorporation/mympd

/** @module clickActions_js */

/**
 * Handler for quick remove button
 * @param {EventTarget} target event target
 * @returns {void}
 */
function clickQuickRemove(target) {
    let dataNode = target.parentNode.parentNode;
    if (dataNode.classList.contains('row')) {
        dataNode = dataNode.parentNode;
    }
    switch(app.id) {
        case 'QueueCurrent': {
            const songId = getData(dataNode, 'songid');
            removeFromQueueIDs([songId]);
            break;
        }
        case 'BrowsePlaylistList': {
            const plist = getData(dataNode, 'uri');
            showDelPlaylist([plist]);
            break;
        }
        case 'BrowsePlaylistDetail': {
            const pos = getData(dataNode, 'pos');
            const plist = getDataId('BrowsePlaylistDetailList', 'uri');
            removeFromPlaylistPositions(plist, [pos]);
            break;
        }
        case 'QueueJukeboxSong':
        case 'QueueJukeboxAlbum': {
            const pos = getData(dataNode, 'pos');
            delQueueJukeboxEntries([pos]);
            break;
        }
        default:
            logError('Invalid appid' + app.id);
    }
}

/**
 * Handler for quick play button
 * @param {EventTarget} target event target
 * @returns {void}
 */
function clickQuickPlay(target) {
    let dataNode = target.parentNode.parentNode;
    if (dataNode.classList.contains('row')) {
        dataNode = dataNode.parentNode;
    }
    const type = getData(dataNode, 'type');
    const uri = [];
    switch(type) {
        case 'album':
            uri.push(getData(dataNode, 'AlbumId'));
            break;
        case 'disc':
            uri.push(getData(dataNode, 'AlbumId'), getData(dataNode, 'Disc'));
            break;
        case 'work':
            uri.push(getData(dataNode, 'AlbumId'), getData(dataNode, 'Work'));
            break;
        default:
            uri.push(getData(dataNode, 'uri'));
    }
    switch (settings.webuiSettings.clickQuickPlay) {
        case 'append': return appendQueue(type, uri);
        case 'appendPlay': return appendPlayQueue(type, uri);
        case 'insertAfterCurrent': return insertAfterCurrentQueue(type, uri);
        case 'insertPlayAfterCurrent': return insertPlayAfterCurrentQueue(type, uri);
        case 'replace': return replaceQueue(type, uri);
        case 'replacePlay': return replacePlayQueue(type, uri);
        default: logError('Invalid action: ' + settings.webuiSettings.clickQuickPlay);
    }
}

/**
 * Click song handler
 * @param {string} uri song uri
 * @param {event} event the event
 * @returns {void}
 */
function clickSong(uri, event) {
    switch (settings.webuiSettings.clickSong) {
        case 'append': return appendQueue('song', [uri]);
        case 'appendPlay': return appendPlayQueue('song', [uri]);
        case 'insertAfterCurrent': return insertAfterCurrentQueue('song', [uri]);
        case 'insertPlayAfterCurrent': return insertPlayAfterCurrentQueue('song', [uri]);
        case 'replace': return replaceQueue('song', [uri]);
        case 'replacePlay': return replacePlayQueue('song', [uri]);
        case 'view': return songDetails(uri);
        case 'context': return showContextMenu(event);
        default: logError('Invalid action: ' + settings.webuiSettings.clickSong);
    }
}

/**
 * Handler for webradioDB links
 * @param {string} uri stream uri
 * @param {event} event the event
 * @returns {void}
 */
function clickWebradiodb(uri, event) {
    switch (settings.webuiSettings.clickWebradiodb) {
        case 'append': return appendQueue('song', [uri]);
        case 'appendPlay': return appendPlayQueue('song', [uri]);
        case 'insertAfterCurrent': return insertAfterCurrentQueue('song', [uri]);
        case 'insertPlayAfterCurrent': return insertPlayAfterCurrentQueue('song', [uri]);
        case 'replace': return replaceQueue('song', [uri]);
        case 'replacePlay': return replacePlayQueue('song', [uri]);
        case 'view': return showWebradiodbDetails(uri);
        case 'context': return showContextMenu(event);
        default: logError('Invalid action: ' + settings.webuiSettings.clickWebradiodb);
    }
}

/**
 * Handler for webradio favorites links
 * @param {string} uri webradio favorite uri (filename only)
 * @param {event} event the event
 * @returns {void}
 */
function clickRadioFavorites(uri, event) {
    switch(settings.webuiSettings.clickRadioFavorites) {
        case 'append': return appendQueue('webradio', [uri]);
        case 'appendPlay': return appendPlayQueue('webradio', [uri]);
        case 'insertAfterCurrent': return insertAfterCurrentQueue('webradio', [uri]);
        case 'insertPlayAfterCurrent': return insertPlayAfterCurrentQueue('webradio', [uri]);
        case 'replace': return replaceQueue('webradio', [uri]);
        case 'replacePlay': return replacePlayQueue('webradio', [uri]);
        case 'edit': return editRadioFavorite(uri);
        case 'context': return showContextMenu(event);
        default: logError('Invalid action: ' + settings.webuiSettings.clickRadioFavorites);
    }
}

/**
 * Handler for song links in queue
 * @param {string} songid the song id
 * @param {string} uri the song uri
 * @param {event} event the event
 * @returns {void}
 */
function clickQueueSong(songid, uri, event) {
    switch(settings.webuiSettings.clickQueueSong) {
        case 'play':
            if (songid === null) {
                return;
            }
            if (currentState.currentSongId === songid) {
                return clickPlay();
            }
            return sendAPI("MYMPD_API_PLAYER_PLAY_SONG", {
                "songId": songid
            }, null, false);
        case 'view':
            if (uri === null) {
                return;
            }
            return songDetails(uri);
        case 'context':
            return showContextMenu(event);
        default: logError('Invalid action: ' + settings.webuiSettings.clickQueueSong);
    }
}

/**
 * Handler for playlist links
 * @param {string} uri playlist uri
 * @param {event} event the event
 * @returns {void}
 */
function clickPlaylist(uri, event) {
    switch(settings.webuiSettings.clickPlaylist) {
        case 'append': return appendQueue('plist', [uri]);
        case 'appendPlay': return appendPlayQueue('plist', [uri]);
        case 'insertAfterCurrent': return insertAfterCurrentQueue('plist', [uri]);
        case 'insertPlayAfterCurrent': return insertPlayAfterCurrentQueue('plist', [uri]);
        case 'replace': return replaceQueue('plist', [uri]);
        case 'replacePlay': return replacePlayQueue('plist', [uri]);
        case 'view': return gotoPlaylist(uri);
        case 'context': return showContextMenu(event);
        default: logError('Invalid action: ' + settings.webuiSettings.clickPlaylist);
    }
}

/**
 * Handler for click on playlists in filesystem view
 * @param {string} uri playlist uri
 * @param {event} event the event
 * @returns {void}
 */
function clickFilesystemPlaylist(uri, event) {
    switch(settings.webuiSettings.clickFilesystemPlaylist) {
        case 'append': return appendQueue('plist', [uri]);
        case 'appendPlay': return appendPlayQueue('plist', [uri]);
        case 'insertAfterCurrent': return insertAfterCurrentQueue('plist', [uri]);
        case 'insertPlayAfterCurrent': return insertPlayAfterCurrentQueue('plist', [uri]);
        case 'replace': return replaceQueue('plist', [uri]);
        case 'replacePlay': return replacePlayQueue('plist', [uri]);
        case 'view':
            //remember offset for current browse uri
            browseFilesystemHistory[app.current.filter] = {
                "offset": app.current.offset,
                "scrollPos": document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop
            };
            //reset search and show playlist
            app.current.search = '';
            appGoto('Browse', 'Filesystem', undefined, 0, app.current.limit, uri, app.current.sort, 'plist', '', 0);
            break;
        case 'context': return showContextMenu(event);
        default: logError('Invalid action: ' + settings.webuiSettings.clickFilesystemPlaylist);
    }
}

/**
 * Handler for click on folder in filesystem view
 * @param {string} uri folder uri
 * @returns {void}
 */
function clickFolder(uri) {
    //remember offset for current browse uri
    browseFilesystemHistory[app.current.filter] = {
        "offset": app.current.offset,
        "scrollPos": getScrollPosY()
    };
    //reset search and open folder
    app.current.search = '';
    appGoto('Browse', 'Filesystem', undefined, 0, app.current.limit, uri, app.current.sort, 'dir', '', 0);
}

/**
 * Seeks the current song forward by 5s
 * @returns {void}
 */
function seekRelativeForward() {
    seekRelative(5);
}

/**
 * Seeks the current song backward by 5s
 * @returns {void}
 */
function seekRelativeBackward() {
    seekRelative(-5);
}

/**
 * Seeks the current song by offset seconds
 * @param {number} offset relative seek offset
 * @returns {void}
 */
function seekRelative(offset) {
    sendAPI("MYMPD_API_PLAYER_SEEK_CURRENT", {
        "seek": offset,
        "relative": true
    }, null, false);
}

/**
 * Handler for click on play button
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickPlay() {
    switch(currentState.state) {
        case 'play':
            if (settings.webuiSettings.footerPlaybackControls === 'stop') {
                sendAPI("MYMPD_API_PLAYER_STOP", {}, null, false);
            }
            else {
                sendAPI("MYMPD_API_PLAYER_PAUSE", {}, null, false);
            }
            break;
        case 'pause':
            sendAPI("MYMPD_API_PLAYER_RESUME", {}, null, false);
            break;
        default:
            //fallback if playstate is stop or unknown
            sendAPI("MYMPD_API_PLAYER_PLAY", {}, null, false);
    }
}

/**
 * Handler for click on stop button
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickStop() {
    sendAPI("MYMPD_API_PLAYER_STOP", {}, null, false);
}

/**
 * Handler for click on prev song button
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickPrev() {
    sendAPI("MYMPD_API_PLAYER_PREV", {}, null, false);
}

/**
 * Handler for click on next song button
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickNext() {
    sendAPI("MYMPD_API_PLAYER_NEXT", {}, null, false);
}

/**
 * Handler for click on fast rewind button
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickFastRewind() {
    clickSeek(-settings.webuiSettings.seekStep, true);
}

/**
 * Handler for click on fast rewind button in playback controls popover
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickFastRewindValue() {
    lastSeekStep = parseToSeconds(elGetById('popoverFooterSeekInput').value);
    clickSeek(-lastSeekStep, true);
}

/**
 * Handler for click on fast rewind button
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickFastForward() {
    clickSeek(settings.webuiSettings.seekStep, true);
}

/**
 * Handler for click on fast rewind button in playback controls popover
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickFastForwardValue() {
    lastSeekStep = parseToSeconds(elGetById('popoverFooterSeekInput').value);
    clickSeek(lastSeekStep, true);
}

/**
 * Handler for click on goto position button in playback controls popover
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickGotoPos() {
    const seekToPos = parseToSeconds(elGetById('popoverFooterGotoInput').value);
    clickSeek(seekToPos, false);
}

/**
 * Shows the advanced playback control popover
 * @param {Event} event triggering event
 * @returns {void}
 */
function toggleAdvPlaycontrolsPopover(event) {
    if (event.target.closest('.dropdown-menu') !== null) {
        return;
    }
    event.preventDefault();
    event.stopPropagation();
    if (domCache.footer.getAttribute('aria-describedby') === null) {
        showPopover(domCache.footer, 'footer');
    }
    else {
        hidePopover();
    }
}

/**
 * Seek handler
 * @param {number} value seek by/to value
 * @param {boolean} relative true = number is relative
 * @returns {void}
 */
function clickSeek(value, relative) {
    sendAPI("MYMPD_API_PLAYER_SEEK_CURRENT", {
        "seek": value,
        "relative": relative
    }, null, false);
}

/**
 * Handler for click on single button
 * @param {string} mode single mode: "0" = off, "1" = single, "oneshot" = single one shot
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickSingle(mode) {
    sendAPI("MYMPD_API_PLAYER_OPTIONS_SET", {
        "single": mode
    }, null, false);
}

/**
 * Handler for click on consume button
 * @param {string} mode single mode: "0" = off, "1" = consume, "oneshot" = consume one shot
 * @returns {void}
 */
//eslint-disable-next-line no-unused-vars
function clickConsume(mode) {
    sendAPI("MYMPD_API_PLAYER_OPTIONS_SET", {
        "consume": mode
    }, null, false);
}

/**
 * Handler for resume song dropdown actions
 * @param {Event} event Click event
 * @returns {void}
 */
function clickResumeSong(event) {
    event.preventDefault();
    if (event.target.nodeName !== 'BUTTON') {
        return;
    }
    const dataNode = event.target.closest('.btn-group');
    const uri = getData(dataNode, 'uri');
    const action = event.target.getAttribute('data-action');
    resumeSong(uri, action);
}

/**
 * Handler for song resume - click on resume indicator
 * @param {EventTarget} target event target
 * @returns {void}
 */
function clickQuickResumeSong(target) {
    const uri = getData(target, 'uri');
    resumeSong(uri, settings.webuiSettings.clickQuickPlay);
}

/**
 * Handler for resume playlist dropdown actions
 * @param {Event} event Click event
 * @returns {void}
 */
function clickResumePlist(event) {
    event.preventDefault();
    if (event.target.nodeName !== 'BUTTON') {
        return;
    }
    const dataNode = event.target.closest('.btn-group');
    const pos = getData(dataNode, 'pos');
    const uri = getDataId('BrowsePlaylistDetailList', 'uri');
    const action = event.target.getAttribute('data-action');
    resumePlist(uri, pos, action);
}

/**
 * Handler for resume album dropdown actions
 * @param {Event} event Click event
 * @returns {void}
 */
function clickResumeAlbum(event) {
    event.preventDefault();
    if (event.target.nodeName !== 'BUTTON') {
        return;
    }
    const dataNode = event.target.closest('.btn-group');
    const pos = getData(dataNode, 'pos');
    const albumId = getDataId('viewDatabaseAlbumDetailCover', 'AlbumId');
    const action = event.target.getAttribute('data-action');
    resumeAlbum(albumId, pos, action);
}