PDF Viewer Embedder

Embeds PDFs directly in the page instead of downloading if it is stored on the same domain

目前为 2025-04-29 提交的版本。查看 最新版本

// ==UserScript==
// @name         PDF Viewer Embedder
// @namespace    *
// @version      1.0
// @author       zinchaiku
// @description  Embeds PDFs directly in the page instead of downloading if it is stored on the same domain
// @match        *://*/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // Helper to create and insert the PDF viewer
    function showPDF(blobUrl) {
        // Remove any existing viewer
        let existing = document.getElementById('tampermonkey-pdf-viewer');
        if (existing) existing.remove();

        // Create overlay
        const overlay = document.createElement('div');
        overlay.id = 'tampermonkey-pdf-viewer';
        overlay.style.position = 'fixed';
        overlay.style.top = 0;
        overlay.style.left = 0;
        overlay.style.width = '100vw';
        overlay.style.height = '100vh';
        overlay.style.background = 'rgba(0,0,0,0.8)';
        overlay.style.zIndex = 99999;
        overlay.style.display = 'flex';
        overlay.style.alignItems = 'center';
        overlay.style.justifyContent = 'center';

        // Create iframe
        const iframe = document.createElement('iframe');
        iframe.src = blobUrl;
        iframe.title = "Embedded PDF Viewer";
        iframe.style.width = '80vw';
        iframe.style.height = '90vh';
        iframe.style.border = 'none';
        iframe.style.background = '#fff';
        overlay.appendChild(iframe);

        // Close button
        const closeBtn = document.createElement('button');
        closeBtn.textContent = 'Close PDF';
        closeBtn.style.position = 'absolute';
        closeBtn.style.top = '20px';
        closeBtn.style.right = '40px';
        closeBtn.style.zIndex = 100000;
        closeBtn.style.padding = '2px 6px';
        closeBtn.style.fontSize = '1.2em';
        closeBtn.onclick = () => {
            overlay.remove();
            URL.revokeObjectURL(blobUrl);
        };
        overlay.appendChild(closeBtn);

        document.body.appendChild(overlay);
    }

    // Attach to all download links (adjust selector as needed)
    function attachPDFInterceptors() {
        document.querySelectorAll('a[href$=".pdf"], a[href*="_download.html"]').forEach(link => {
            // Avoid double-binding
            if (link.dataset.tmPdfBound) return;
            link.dataset.tmPdfBound = "1";

            link.addEventListener('click', function(e) {
    e.preventDefault();

    const linkHost = new URL(link.href).host;
    const sameOrigin = linkHost === window.location.host;

    // Use fetch only for same-origin links (like ILIAS downloads)
    if (sameOrigin) {
        fetch(link.href, { credentials: 'include' })
            .then(res => {
                const contentType = res.headers.get('Content-Type') || '';
                if (contentType.includes('pdf')) {
                    return res.blob().then(blob => {
                        const blobUrl = URL.createObjectURL(blob);
                        showPDF(blobUrl);
                    });
                } else {
                    window.location.href = link.href;
                }
            })
            .catch(err => {
                alert("Could not open PDF: " + err);
                window.location.href = link.href;
            });
    } else {
        // External .pdf link — open in a new tab
        window.open(link.href, '_blank');
    }
});
        });
    }
    window.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') {
        const viewer = document.getElementById('tampermonkey-pdf-viewer');
        if (viewer) {
            const iframe = viewer.querySelector('iframe');
            if (iframe?.src?.startsWith('blob:')) {
                URL.revokeObjectURL(iframe.src);
            }
            viewer.remove();
        }
    }
});

    // Run on page load and after AJAX navigation (if any)
    attachPDFInterceptors();
    // Optional: observe DOM changes for dynamically loaded links
    const observer = new MutationObserver(attachPDFInterceptors);
    observer.observe(document.body, { childList: true, subtree: true });
})();