Bind Delete Key to Delete in Rabbit Hole with multiple selection support

Binds the Delete key to trigger delete in rabbit hole journal backend. Multiple selection is made with ctrl key.

От 19.10.2024. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Bind Delete Key to Delete in Rabbit Hole with multiple selection support
// @namespace    http://tampermonkey.net/
// @license      MIT
// @version      2.1
// @description  Binds the Delete key to trigger delete in rabbit hole journal backend. Multiple selection is made with ctrl key.
// @author       Rekt
// @match        *://hole.rabbit.tech/*
// @grant        none
// ==/UserScript==
(function() {
    'use strict';

    let selectedItems = new Set();
    let accessToken = null;

    // Hook into fetch to capture access token
    const originalFetch = window.fetch;
    window.fetch = async function(...args) {
        const response = await originalFetch(...args);
        if (args[1] && args[1].body) {
            try {
                const body = JSON.parse(args[1].body);
                if (body.accessToken) {
                    accessToken = body.accessToken;
                }
            } catch (error) {
                console.error("Error parsing request body:", error);
            }
        }
        return response;
    };

    // Function to delete entries using HTTP deletion and remove placeholders
    async function deleteEntries(entryIds) {
        if (!accessToken) {
            console.error('Access token not available');
            return;
        }

        for (let entryId of entryIds) {
            try {
                const payload = { accessToken, entryId, deleteEntry: true };

                const response = await fetch('/apis/updateJournalEntry', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${accessToken}`
                    },
                    body: JSON.stringify(payload)
                });

                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }

                // Remove placeholder from the page
                const element = document.querySelector(`[data-entry-id="${entryId}"]`);
                if (element) {
                    element.remove();
                }
            } catch (error) {
                console.error(`Error deleting entry ${entryId}:`, error);
            }
        }
    }

    // Function to handle the delete key
    function handleDeleteKey(event) {
        // Prevent deletion if the user is focused on a contenteditable element
        const focusedElement = document.activeElement;
        if (focusedElement.hasAttribute('contenteditable')) {
            return;
        }

        // If delete key is pressed and there are selected items, delete them
        if (event.key === 'Delete') {
            const entryIds = Array.from(selectedItems);
            if (entryIds.length > 0) {
                deleteEntries(entryIds);
                selectedItems.clear();
            } else {
                // Delete single selected item without Ctrl
                const target = document.querySelector('li[data-entry-id].selected');
                if (target) {
                    const entryId = target.getAttribute('data-entry-id');
                    deleteEntries([entryId]);
                    target.classList.remove('selected');
                }
            }
            event.preventDefault(); // Prevent default behavior if necessary
        }
    }

    // Function to handle selection with Ctrl key
    function handleSelection(event) {
        // Check if the clicked element is a list item with a data-entry-id
        const target = event.target.closest('li[data-entry-id]');
        if (!target) return;

        const entryId = target.getAttribute('data-entry-id');

        // If Ctrl is pressed, allow multiple selection and toggle current selection state
        if (event.ctrlKey) {
            if (selectedItems.has(entryId)) {
                selectedItems.delete(entryId);
                target.classList.remove('selected');
            } else {
                selectedItems.add(entryId);
                target.classList.add('selected');
            }
        } else { 
            // Single selection without Ctrl, clear previous selections and select current item
            selectedItems.forEach(id => {
                const element = document.querySelector(`[data-entry-id="${id}"]`);
                if (element) element.classList.remove('selected');
            });
            selectedItems.clear();
            selectedItems.add(entryId);

            // Do not apply styling for single selection
        }

        // Apply styling only for multiple selections
        selectedItems.forEach(id => {
            const element = document.querySelector(`[data-entry-id="${id}"]`);
            if (element && selectedItems.size > 1) element.classList.add('selected');
        });
    }

    // Add event listeners
    document.addEventListener('keydown', handleDeleteKey);
    document.addEventListener('click', handleSelection);

    // Add CSS for the selected class to highlight the selected items
    const style = document.createElement('style');
    style.innerHTML = `
        .selected {
            background-color: yellow;
        }
    `;
    document.head.appendChild(style);

})();