Greasy Fork is available in English.

Pixiv QuickSelect

Allows quick selection of many items. Select one, hold shift and select another!

// ==UserScript==
// @name         Pixiv QuickSelect
// @version      0.1
// @description  Allows quick selection of many items. Select one, hold shift and select another!
// @author       8uurg
// @match        https://www.pixiv.net/bookmark.php*
// @grant        GM_addStyle
// @namespace https://greasyfork.org/users/368765
// ==/UserScript==

(function() {
    'use strict';

    // Find item
    const itemsContainer = document.querySelector("._image-items");
    if(itemsContainer === null) { return; }
    // If found, insert css
    GM_addStyle(`
        .betweenSelected {
            box-shadow: 0px 0px 5px 2px lightblue;
        }
    `)
    // Find the checkboxes and add logic.
    const bookmarksOrigin = itemsContainer.querySelectorAll('input[type=checkbox]')
    let lastIndex = 0;
    let lastHovered = -1;
    let currentState = false;

    function activateHoverEffect(from, to) {
        if(currentState) { return; }
        const tfrom = Math.min(from, to)
        const tto = Math.max(from, to)

        // console.log(`Activating from ${lastIndex} to ${lastHovered}`)
        for (let i=tfrom; i <= tto; i++) {
            bookmarksOrigin[i].classList.add('betweenSelected')
        }
        currentState = true;
    }
    function deactivateHoverEffect(from, to) {
        if(!currentState) { return; }
        const tfrom = Math.min(from, to)
        const tto = Math.max(from, to)

        // console.log(`Deactivating from ${lastIndex} to ${lastHovered}`)
        for (let i=tfrom; i <= tto; i++) {
            bookmarksOrigin[i].classList.remove('betweenSelected')
        }
        currentState = false;
    }
    function mouseEnterHandler(e) {
        const i = e.target.listedIndex;
        lastHovered = i;
        if (e.shiftKey) {
            activateHoverEffect(lastIndex, lastHovered)
        }
    }
    function mouseLeaveHandler(e) {
        deactivateHoverEffect(lastIndex, lastHovered)
        lastHovered = -1;
    }
    function keyDownHandler(e) {
        if(lastHovered === -1) { return; }

        if(e.keyCode === 16) {
            activateHoverEffect(lastIndex, lastHovered)
        }
    }
    function keyUpHandler(e) {
        if(lastHovered === -1) { return; }

        if(e.keyCode === 16) {
            deactivateHoverEffect(lastIndex, lastHovered)
        }
    }
    document.addEventListener('keydown', keyDownHandler)
    document.addEventListener('keyup', keyUpHandler)

    function clickHandler(e) {
        if(currentState && lastHovered !== -1) {
            deactivateHoverEffect(lastIndex, lastHovered)
        }
        const newState = e.target.checked;
        const i = e.target.listedIndex;
        if(e.shiftKey) {
            const tfrom = Math.min(i, lastIndex)
            const tto = Math.max(i, lastIndex)
            // console.log(`Setting from ${tfrom} to ${tto} to ${newState}`)
            for(let j=tfrom; j<=tto; j++) {
                bookmarksOrigin[j].checked = newState;
            }
        }
        lastIndex = i;
        if(currentState) {
            activateHoverEffect(lastIndex, lastHovered)
        }
    }

    for(let i=0; i < bookmarksOrigin.length; i++) {
        // Allow for mass selection.
        bookmarksOrigin[i].listedIndex = i;
        bookmarksOrigin[i].addEventListener('click', clickHandler);

        // For fancy hover when holding shift effect.
        bookmarksOrigin[i].addEventListener('mouseenter', mouseEnterHandler);
        bookmarksOrigin[i].addEventListener('mouseleave', mouseLeaveHandler);
    }
})();