Greasy Fork

Greasy Fork is available in English.

📘点击全屏翻页丨自定义翻页区域丨点击翻页丨悬浮窗设置丨电纸书墨水屏

👍通过点击页面上下左右不同区域快速翻页,支持自定义翻页比例及区域,可选择禁用页面其他区域点击,只允许悬浮窗和设置窗口操作。轻松实现高效的页面浏览体验。

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         📘点击全屏翻页丨自定义翻页区域丨点击翻页丨悬浮窗设置丨电纸书墨水屏
// @version      1.0
// @license      GPL
// @match        *://*/*
// @description  👍通过点击页面上下左右不同区域快速翻页,支持自定义翻页比例及区域,可选择禁用页面其他区域点击,只允许悬浮窗和设置窗口操作。轻松实现高效的页面浏览体验。
// @namespace http://greasyfork.icu/users/1292046
// ==/UserScript==

(function() {
    'use strict';

    let LANG = {
        en: {
            buttons: {
                toggle: 'Close',
                settings: 'Settings'
            },
            settings: {
                reserveHeightUpper: 'Reserved Height Percentage (Upper)',
                reserveHeightLower: 'Reserved Height Percentage (Lower)',
                pageMode: 'Page Turn Mode',
                upDown: 'Up/Down',
                downUp: 'Down/Up',
                leftRight: 'Left/Right',
                rightLeft: 'Right/Left',
                upperPart: 'Enable Upper Part',
                lowerPart: 'Enable Lower Part',
                disablePageClick: 'Disable Page Click When Open',
                save: 'Save',
                close: 'Close',
                pageTurnUpper: 'Page Turn Percentage (Upper/Left)',
                pageTurnLower: 'Page Turn Percentage (Lower/Right)'
            }
        }
    };

    const userLang = navigator.language.slice(0, 2);
    const currentLang = LANG[userLang] ? userLang : 'en';

    const state = {
        isEnabled: GM_getValue('isEnabled', false),
        reservedHeightUpperPercentage: GM_getValue('reservedHeightUpperPercentage', 50),
        reservedHeightLowerPercentage: GM_getValue('reservedHeightLowerPercentage', 50),
        pageTurnMode: GM_getValue('pageTurnMode', 'upDown'),
        enableUpperPart: GM_getValue('enableUpperPart', true),
        enableLowerPart: GM_getValue('enableLowerPart', true),
        floatWindowLeft: GM_getValue('floatWindowLeft', 'calc(100% - 110px)'),
        floatWindowTop: GM_getValue('floatWindowTop', 'calc(100% - 70px)'),
        disablePageClick: GM_getValue('disablePageClick', false),
        pageTurnUpperPercentage: GM_getValue('pageTurnUpperPercentage', 20),
        pageTurnLowerPercentage: GM_getValue('pageTurnLowerPercentage', 30)
    };

    const floatWindow = document.createElement('div');
    const toggleButton = document.createElement('button');
    const settingsButton = document.createElement('button');

    const updateToggleButton = () => {
        toggleButton.innerHTML = state.isEnabled ? 'Open' : 'Close';
    };

    const createTransparentLayer = () => {
        const layer = document.createElement('div');
        layer.id = 'transparentLayer';
        layer.style = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0);
            z-index: 9999;
            pointer-events: auto;
        `;
        document.body.appendChild(layer);
        return layer;
    };

    const transparentLayer = createTransparentLayer();
    transparentLayer.style.display = 'none';

    toggleButton.onclick = (e) => {
        e.stopPropagation();
        state.isEnabled = !state.isEnabled;
        GM_setValue('isEnabled', state.isEnabled);
        updateToggleButton();

        if (state.isEnabled && state.disablePageClick) {
            transparentLayer.style.display = 'block';
        } else {
            transparentLayer.style.display = 'none';
        }
    };

    settingsButton.innerHTML = LANG[currentLang].buttons.settings;
    settingsButton.onclick = (e) => {
        e.stopPropagation();
        showSettings();
    };

    floatWindow.id = 'clickPageTurnerWindow';
    floatWindow.style = `
        position: fixed;
        left: ${state.floatWindowLeft};
        top: ${state.floatWindowTop};
        width: 100px;
        height: 60px;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: space-around;
        z-index: 10001;
        cursor: pointer;
    `;

    const applyDraggable = (element) => {
        let isDragging = false;
        let dragOffsetX, dragOffsetY;

        element.addEventListener('mousedown', (event) => {
            isDragging = true;
            dragOffsetX = element.offsetLeft - event.clientX;
            dragOffsetY = element.offsetTop - event.clientY;
        });

        document.addEventListener('mousemove', (event) => {
            if (isDragging) {
                element.style.left = event.clientX + dragOffsetX + 'px';
                element.style.top = event.clientY + dragOffsetY + 'px';
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                GM_setValue('floatWindowLeft', element.style.left);
                GM_setValue('floatWindowTop', element.style.top);
                isDragging = false;
            }
        });
    };

    applyDraggable(floatWindow);

    floatWindow.appendChild(toggleButton);
    floatWindow.appendChild(settingsButton);
    document.body.appendChild(floatWindow);

    const showSettings = () => {
        state.isEnabled = false;
        updateToggleButton();

        const settingsWindow = document.createElement('div');
        settingsWindow.classList.add('settings-window');
        settingsWindow.style = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 300px;
            background-color: white;
            color: black;
            border: 1px solid #ccc;
            z-index: 10001;
            padding: 20px;
            border-radius: 5px;
        `;

        const closeButton = document.createElement('button');
        closeButton.innerHTML = LANG[currentLang].settings.close;
        closeButton.style = `
            position: absolute;
            top: 10px;
            right: 10px;
            background: none;
            border: none;
            font-size: 16px;
            color: black;
            cursor: pointer;
        `;
        closeButton.onclick = () => {
            document.body.removeChild(settingsWindow);
            if (state.isEnabled) {
                state.isEnabled = true;
                updateToggleButton();
            }
        };

        settingsWindow.appendChild(closeButton);

        const settingsContainer = document.createElement('div');
        settingsContainer.style = `
            display: flex;
            flex-direction: column;
            align-items: flex-start;
        `;

        const createPercentageInput = (labelText, value, min, max, onChange) => {
            const container = document.createElement('div');
            container.style = `
                display: flex;
                justify-content: space-between;
                width: 100%;
                margin-bottom: 10px;
            `;

            const label = document.createElement('label');
            label.innerText = labelText;
            container.appendChild(label);

            const input = document.createElement('input');
            input.type = 'number';
            input.value = value;
            input.min = min;
            input.max = max;
            input.oninput = onChange;

            container.appendChild(input);
            return container;
        };

        const reserveHeightUpperInput = createPercentageInput(LANG[currentLang].settings.reserveHeightUpper, state.reservedHeightUpperPercentage, 0, 100, (e) => {
            state.reservedHeightUpperPercentage = parseInt(e.target.value, 10);
        });
        const reserveHeightLowerInput = createPercentageInput(LANG[currentLang].settings.reserveHeightLower, state.reservedHeightLowerPercentage, 0, 100, (e) => {
            state.reservedHeightLowerPercentage = parseInt(e.target.value, 10);
        });
        settingsContainer.appendChild(reserveHeightUpperInput);
        settingsContainer.appendChild(reserveHeightLowerInput);

        const pageTurnUpperInput = createPercentageInput(LANG[currentLang].settings.pageTurnUpper, state.pageTurnUpperPercentage, 0, 100, (e) => {
            state.pageTurnUpperPercentage = parseInt(e.target.value, 10);
        });
        const pageTurnLowerInput = createPercentageInput(LANG[currentLang].settings.pageTurnLower, state.pageTurnLowerPercentage, 0, 100, (e) => {
            state.pageTurnLowerPercentage = parseInt(e.target.value, 10);
        });
        settingsContainer.appendChild(pageTurnUpperInput);
        settingsContainer.appendChild(pageTurnLowerInput);

        const createDropdown = (labelText, options, selectedValue, onChange) => {
            const container = document.createElement('div');
            container.style = `
                display: flex;
                justify-content: space-between;
                width: 100%;
                margin-bottom: 10px;
            `;

            const label = document.createElement('label');
            label.innerText = labelText;
            container.appendChild(label);

            const select = document.createElement('select');
            options.forEach(option => {
                const opt = document.createElement('option');
                opt.value = option.value;
                opt.innerText = option.text;
                if (option.value === selectedValue) {
                    opt.selected = true;
                }
                select.appendChild(opt);
            });
            select.onchange = onChange;
            container.appendChild(select);
            return container;
        };

        const pageModeOptions = [{
                value: 'upDown',
                text: LANG[currentLang].settings.upDown
            },
            {
                value: 'downUp',
                text: LANG[currentLang].settings.downUp
            },
            {
                value: 'leftRight',
                text: LANG[currentLang].settings.leftRight
            },
            {
                value: 'rightLeft',
                text: LANG[currentLang].settings.rightLeft
            }
        ];

        const pageModeDropdown = createDropdown(LANG[currentLang].settings.pageMode, pageModeOptions, state.pageTurnMode, (e) => {
            state.pageTurnMode = e.target.value;
        });
        settingsContainer.appendChild(pageModeDropdown);

        const createCheckbox = (labelText, checked, onChange) => {
            const container = document.createElement('div');
            container.style = `
                display: flex;
                justify-content: space-between;
                width: 100%;
                margin-bottom: 10px;
            `;

            const label = document.createElement('label');
            label.innerText = labelText;
            container.appendChild(label);

            const input = document.createElement('input');
            input.type = 'checkbox';
            input.checked = checked;
            input.onchange = onChange;

            container.appendChild(input);
            return container;
        };

        const upperPartCheckbox = createCheckbox(LANG[currentLang].settings.upperPart, state.enableUpperPart, (e) => {
            state.enableUpperPart = e.target.checked;
        });
        settingsContainer.appendChild(upperPartCheckbox);

        const lowerPartCheckbox = createCheckbox(LANG[currentLang].settings.lowerPart, state.enableLowerPart, (e) => {
            state.enableLowerPart = e.target.checked;
        });
        settingsContainer.appendChild(lowerPartCheckbox);

        const disablePageClickCheckbox = createCheckbox(LANG[currentLang].settings.disablePageClick, state.disablePageClick, (e) => {
            state.disablePageClick = e.target.checked;
        });
        settingsContainer.appendChild(disablePageClickCheckbox);

        const saveButton = document.createElement('button');
        saveButton.innerHTML = LANG[currentLang].settings.save;
        saveButton.onclick = () => {
            const upperPercentage = state.reservedHeightUpperPercentage;
            const lowerPercentage = state.reservedHeightLowerPercentage;
            const pageTurnUpper = state.pageTurnUpperPercentage;
            const pageTurnLower = state.pageTurnLowerPercentage;

            if (upperPercentage + lowerPercentage <= 100 && upperPercentage >= 0 && lowerPercentage >= 0 &&
                pageTurnUpper + pageTurnLower <= 100 && pageTurnUpper >= 0 && pageTurnLower >= 0) {
                GM_setValue('reservedHeightUpperPercentage', upperPercentage);
                GM_setValue('reservedHeightLowerPercentage', lowerPercentage);
                GM_setValue('pageTurnMode', state.pageTurnMode);
                GM_setValue('enableUpperPart', state.enableUpperPart);
                GM_setValue('enableLowerPart', state.enableLowerPart);
                GM_setValue('disablePageClick', state.disablePageClick);
                GM_setValue('pageTurnUpperPercentage', pageTurnUpper);
                GM_setValue('pageTurnLowerPercentage', pageTurnLower);
                document.body.removeChild(settingsWindow);
                location.reload();
            } else {
                alert('The combined percentages must be between 0% and 100%.');
            }
        };
        settingsContainer.appendChild(saveButton);

        settingsWindow.appendChild(settingsContainer);
        document.body.appendChild(settingsWindow);
    };

    const handlePageTurn = (e) => {
        if (!state.isEnabled) return;

        const screenHeight = window.innerHeight;
        const screenWidth = window.innerWidth;

        const pageTurnUpper = screenHeight * state.pageTurnUpperPercentage / 100;
        const pageTurnLower = screenHeight * state.pageTurnLowerPercentage / 100;

        const isLeftPart = e.clientX < screenWidth * state.pageTurnUpperPercentage / 100;
        const isRightPart = e.clientX > screenWidth * (1 - state.pageTurnLowerPercentage / 100);
        const isUpperPart = e.clientY < screenHeight * state.pageTurnUpperPercentage / 100;
        const isLowerPart = e.clientY > screenHeight * (1 - state.pageTurnLowerPercentage / 100);

        if (state.pageTurnMode === 'upDown' || state.pageTurnMode === 'downUp') {
            if (isUpperPart && state.enableUpperPart) {
                window.scrollBy(0, state.pageTurnMode === 'upDown' ? -(screenHeight - pageTurnUpper) : screenHeight - pageTurnUpper);
            } else if (isLowerPart && state.enableLowerPart) {
                window.scrollBy(0, state.pageTurnMode === 'upDown' ? screenHeight - pageTurnLower : -(screenHeight - pageTurnLower));
            }
        } else if (state.pageTurnMode === 'leftRight' || state.pageTurnMode === 'rightLeft') {
            if (isLeftPart) {
                if (state.pageTurnMode === 'leftRight') {
                    window.scrollBy(0, -(screenHeight - pageTurnUpper));
                } else {
                    window.scrollBy(0, screenHeight - pageTurnLower);
                }
            } else if (isRightPart) {
                if (state.pageTurnMode === 'leftRight') {
                    window.scrollBy(0, screenHeight - pageTurnLower);
                } else {
                    window.scrollBy(0, -(screenHeight - pageTurnUpper));
                }
            }
        }
    };

    document.addEventListener('click', handlePageTurn);

    updateToggleButton();
})();