Universal Iframe Spawner

Spawns multiple iframes of the current page on Shift + Left Click. Works in private/incognito mode and allows multi-account usage with separate iframe storage.

目前為 2025-06-30 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Universal Iframe Spawner
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Spawns multiple iframes of the current page on Shift + Left Click. Works in private/incognito mode and allows multi-account usage with separate iframe storage.
// @author       Adapted from maanimis's territorial.io script
// @match        *://*/*
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // Listen for Shift + Left Click on the document
    document.addEventListener("click", function (event) {
        if (event.shiftKey && event.button === 0) { // Shift + Left Click
            event.preventDefault();
            event.stopPropagation(); // Prevent the click from propagating further
            runScript();
        }
    }, true); // Use capturing to catch the event early

    function runScript() {
        const count = +prompt("How many iframes do you want to spawn?", "2");
        if (isNaN(count) || count <= 0) {
            return; // Exit if the user cancels or enters an invalid number
        }

        const URL = window.location.href; // Use the current page's URL

        createIframes(count, URL);
    }

    function createIframes(count, url) {
        let container = document.getElementById("universalIframeContainer");
        // If container doesn't exist, create and style it as an overlay
        if (!container) {
            container = document.createElement("div");
            container.id = "universalIframeContainer";

            // Style the container as a full-screen overlay
            Object.assign(container.style, {
                position: 'fixed',
                top: '0',
                left: '0',
                width: '100vw',
                height: '100vh',
                zIndex: '99999',
                backgroundColor: 'rgba(0, 0, 0, 0.8)',
                display: 'grid',
                gap: '10px',
                padding: '10px',
                boxSizing: 'border-box'
            });

            document.body.appendChild(container);

            // Add a "Close All" button to the container
            const closeAllButton = createButton("Close All ✖", () => container.remove(), "#d9534f");
            Object.assign(closeAllButton.style, {
                position: 'fixed',
                top: '15px',
                right: '15px',
                zIndex: '100000'
            });
            document.body.appendChild(closeAllButton);
            // Make sure the button is removed when the container is closed
            const observer = new MutationObserver(() => {
                if (!document.body.contains(container)) {
                    closeAllButton.remove();
                    observer.disconnect();
                }
            });
            observer.observe(document.body, { childList: true });
        }

        // Calculate grid dimensions
        const totalIframes = container.children.length + count;
        const gridSize = Math.ceil(Math.sqrt(totalIframes));
        container.style.gridTemplateColumns = `repeat(${gridSize}, 1fr)`;
        container.style.gridTemplateRows = `repeat(${Math.ceil(totalIframes / gridSize)}, 1fr)`;

        // Create and append the new iframes
        for (let i = 0; i < count; i++) {
            const iframeIndex = container.children.length + 1;
            const iframeWrapper = createIframeWrapper(iframeIndex, url);
            container.appendChild(iframeWrapper);
        }
    }

    function createIframeWrapper(index, url) {
        const wrapper = document.createElement("div");
        wrapper.className = "iframe-wrapper";
        Object.assign(wrapper.style, {
            position: 'relative',
            width: '100%',
            height: '100%',
            display: 'flex'
        });

        const controls = createControls(wrapper, index);
        const iframe = createIframe(index, url);

        wrapper.appendChild(controls);
        wrapper.appendChild(iframe);

        return wrapper;
    }

    function createIframe(index, url) {
        const iframe = document.createElement("iframe");
        iframe.id = `frame${index}`;
        iframe.src = url;
        Object.assign(iframe.style, {
            width: '100%',
            height: '100%',
            border: '2px solid white',
            borderRadius: '10px',
            backgroundColor: '#000',
            transition: 'transform 0.2s ease-in-out'
        });
        iframe.onmouseover = () => (iframe.style.transform = "scale(1.02)");
        iframe.onmouseout = () => (iframe.style.transform = "scale(1)");
        // Override storage once the iframe is loaded and has a contentWindow
        iframe.onload = () => overrideStorage(iframe, index);
        return iframe;
    }

    function createControls(wrapper, index) {
        const controls = document.createElement("div");
        controls.className = "controls";
        Object.assign(controls.style, {
            position: 'absolute',
            top: '5px',
            right: '5px',
            zIndex: '10',
            display: 'flex',
            gap: '5px'
        });

        const closeButton = createButton("✖", () => wrapper.remove(), "#d9534f"); // Red
        const maxButton = createButton("⛶", () => toggleMaximize(wrapper, maxButton), "#5cb85c"); // Green

        controls.appendChild(closeButton);
        controls.appendChild(maxButton);

        return controls;
    }

    function createButton(text, onClick, color) {
        const button = document.createElement("button");
        button.innerText = text;
        button.onclick = onClick;
        Object.assign(button.style, {
            background: color,
            border: 'none',
            padding: '5px 8px',
            cursor: 'pointer',
            color: 'white',
            borderRadius: '5px',
            fontSize: '14px',
            lineHeight: '1'
        });
        return button;
    }

    function toggleMaximize(wrapper, button) {
        const isMaximized = wrapper.classList.toggle('maximized');
        const container = document.getElementById("universalIframeContainer");

        if (isMaximized) {
            // Store original styles to restore them later
            wrapper.dataset.originalPosition = wrapper.style.position;
            wrapper.dataset.originalZIndex = wrapper.style.zIndex;

            Object.assign(wrapper.style, {
                position: 'absolute',
                top: '0',
                left: '0',
                zIndex: '100'
            });
            button.innerText = "🗗"; // Minimize symbol
            container.style.zIndex = '99998'; // Ensure container is just below maximized iframe
        } else {
            // Restore original styles
            wrapper.style.position = wrapper.dataset.originalPosition || 'relative';
            wrapper.style.zIndex = wrapper.dataset.originalZIndex || '1';
            button.innerText = "⛶"; // Maximize symbol
            container.style.zIndex = '99999';
        }
    }

    function overrideStorage(iframe, index) {
        // This works because the iframe src is the same origin as the parent window
        try {
            if (iframe.contentWindow) {
                iframe.contentWindow.localStorage = (() => {
                    let storage = {};
                    console.log(`[Iframe Spawner] Overriding localStorage for iframe ${index}`);
                    return {
                        setItem: (key, value) => (storage[key] = value),
                        getItem: (key) => storage[key] || null,
                        removeItem: (key) => delete storage[key],
                        clear: () => (storage = {}),
                        key: (i) => Object.keys(storage)[i] || null,
                        get length() {
                            return Object.keys(storage).length;
                        }
                    };
                })();
            }
        } catch (e) {
            console.error(`[Iframe Spawner] Could not override storage for iframe ${index} due to a security policy.`, e);
        }
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址