Edge Android 全屏浏览 (可拖动按钮)

在Android版Edge浏览器中添加一个可拖动的按钮来切换全屏模式。

// ==UserScript==
// @name         Edge Android 全屏浏览 (可拖动按钮)
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  在Android版Edge浏览器中添加一个可拖动的按钮来切换全屏模式。
// @author       Gemini
// @match        *://*/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 创建一个悬浮按钮
    const fullscreenButton = document.createElement('button');
    fullscreenButton.textContent = '进入全屏'; // 按钮初始文本
    fullscreenButton.style.position = 'fixed';
    fullscreenButton.style.bottom = '20px';
    fullscreenButton.style.right = '20px';
    fullscreenButton.style.zIndex = '9999';
    fullscreenButton.style.padding = '10px 15px';
    fullscreenButton.style.backgroundColor = '#0078D4'; // Edge 蓝色
    fullscreenButton.style.color = 'white';
    fullscreenButton.style.border = 'none';
    fullscreenButton.style.borderRadius = '5px';
    fullscreenButton.style.cursor = 'grab'; // 初始光标样式表示可抓取
    fullscreenButton.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
    fullscreenButton.style.fontSize = '14px';
    fullscreenButton.style.userSelect = 'none'; // 防止拖动时选中文本

    document.body.appendChild(fullscreenButton);

    // 检查当前是否处于全屏状态的函数
    function isFullscreen() {
        return document.fullscreenElement ||
               document.mozFullScreenElement ||
               document.webkitFullscreenElement ||
               document.msFullscreenElement;
    }

    // 切换全屏的函数
    function toggleFullScreen() {
        if (!isFullscreen()) {
            if (document.documentElement.requestFullscreen) {
                document.documentElement.requestFullscreen();
            } else if (document.documentElement.mozRequestFullScreen) { // Firefox
                document.documentElement.mozRequestFullScreen();
            } else if (document.documentElement.webkitRequestFullscreen) { // Chrome, Safari and Opera
                document.documentElement.webkitRequestFullscreen();
            } else if (document.documentElement.msRequestFullscreen) { // IE/Edge
                document.documentElement.msRequestFullscreen();
            }
        } else {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.mozCancelFullScreen) { // Firefox
                document.mozCancelFullScreen();
            } else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera
                document.webkitExitFullscreen();
            } else if (document.msExitFullscreen) { // IE/Edge
                document.msExitFullscreen();
            }
        }
    }

    // 监听全屏状态变化,更新按钮文本
    document.addEventListener('fullscreenchange', updateButtonText);
    document.addEventListener('webkitfullscreenchange', updateButtonText);
    document.addEventListener('mozfullscreenchange', updateButtonText);
    document.addEventListener('MSFullscreenChange', updateButtonText);

    function updateButtonText() {
        if (isFullscreen()) {
            fullscreenButton.textContent = '退出全屏';
        } else {
            fullscreenButton.textContent = '进入全屏';
        }
    }
    updateButtonText(); // 初始加载时更新一次

    // --- 拖动逻辑 ---
    let isDragging = false;
    let hasDraggedSignificantDistance = false; // 是否已发生有意义的拖动
    let offsetX, offsetY; // 鼠标/触摸点相对于按钮左上角的偏移
    let initialMoveCheckX, initialMoveCheckY; // 用于拖拽阈值判断的初始位置
    const DRAG_THRESHOLD = 5; // 至少拖动5像素才算作有效拖动

    function dragStart(e) {
        isDragging = true;
        hasDraggedSignificantDistance = false;
        fullscreenButton.style.cursor = 'grabbing'; // 拖动时光标样式

        // 判断是触摸事件还是鼠标事件
        const clientX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
        const clientY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY;

        initialMoveCheckX = clientX; // 记录用于拖拽阈值判断的初始点
        initialMoveCheckY = clientY;

        const rect = fullscreenButton.getBoundingClientRect();
        offsetX = clientX - rect.left;
        offsetY = clientY - rect.top;

        // 确保按钮使用 left/top 定位以便拖动计算
        // getComputedStyle 用于获取最终应用的样式值
        if (getComputedStyle(fullscreenButton).position === 'fixed') {
            // 如果按钮当前是通过 right/bottom 定位的,则转换为 left/top
            if (fullscreenButton.style.right !== 'auto' || fullscreenButton.style.bottom !== 'auto') {
                fullscreenButton.style.left = rect.left + 'px';
                fullscreenButton.style.top = rect.top + 'px';
                fullscreenButton.style.right = 'auto';
                fullscreenButton.style.bottom = 'auto';
            }
        }

        // 阻止默认行为:
        // - 鼠标:防止选中文本
        // - 触摸:防止页面滚动/缩放
        e.preventDefault();

        if (e.type === 'mousedown') {
            document.addEventListener('mousemove', dragMove);
            document.addEventListener('mouseup', dragEnd);
        } else if (e.type === 'touchstart') {
            // { passive: false } 允许在 touchmove 中调用 e.preventDefault()
            document.addEventListener('touchmove', dragMove, { passive: false });
            document.addEventListener('touchend', dragEnd);
        }
    }

    function dragMove(e) {
        if (!isDragging) return;

        // 对于触摸移动,也需要阻止默认行为
        if (e.type === 'touchmove') {
            e.preventDefault();
        }

        const clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
        const clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;

        // 检查是否拖动超过阈值
        if (!hasDraggedSignificantDistance) {
            const dx = Math.abs(clientX - initialMoveCheckX);
            const dy = Math.abs(clientY - initialMoveCheckY);
            if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD) {
                hasDraggedSignificantDistance = true;
            }
        }

        let newLeft = clientX - offsetX;
        let newTop = clientY - offsetY;

        const buttonWidth = fullscreenButton.offsetWidth;
        const buttonHeight = fullscreenButton.offsetHeight;

        // 边界检查,防止按钮拖出视窗
        if (newLeft < 0) newLeft = 0;
        if (newTop < 0) newTop = 0;
        if (newLeft + buttonWidth > window.innerWidth) newLeft = window.innerWidth - buttonWidth;
        if (newTop + buttonHeight > window.innerHeight) newTop = window.innerHeight - buttonHeight;

        fullscreenButton.style.left = newLeft + 'px';
        fullscreenButton.style.top = newTop + 'px';
    }

    function dragEnd(e) {
        if (!isDragging) return;
        isDragging = false;
        fullscreenButton.style.cursor = 'grab'; // 恢复光标样式

        if (e.type === 'mouseup') {
            document.removeEventListener('mousemove', dragMove);
            document.removeEventListener('mouseup', dragEnd);
        } else if (e.type === 'touchend') {
            document.removeEventListener('touchmove', dragMove);
            document.removeEventListener('touchend', dragEnd);
        }
        // hasDraggedSignificantDistance 的状态会保留,用于 click 事件判断
    }

    // 为按钮添加拖动相关的事件监听器 (鼠标和触摸)
    fullscreenButton.addEventListener('mousedown', dragStart);
    fullscreenButton.addEventListener('touchstart', dragStart, { passive: false });

    // 修改后的点击事件处理,区分单击和拖拽后的释放
    fullscreenButton.addEventListener('click', (e) => {
        if (hasDraggedSignificantDistance) {
            // 如果是拖拽后释放,则阻止默认的点击行为(切换全屏)
            e.stopPropagation();
            e.preventDefault();
            // hasDraggedSignificantDistance 会在下一次 dragStart 时重置
            return;
        }
        // 如果不是拖拽,则执行全屏切换
        toggleFullScreen();
    });

})();