Search code examples
javascripttampermonkeyuserscripts

Creating a custom shortcut for Google Docs (Alt + P download as pdf)


I wrote the following script to download as PDF a Google Docs file; when I click Alt + P nothing happens. I'm using Google Chrome.

// ==UserScript==
// @name         Google Docs PDF Download Shortcut
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Adds a keyboard shortcut to download Google Docs as PDF
// @author       You
// @match        https://docs.google.com/document/d/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    document.addEventListener('keydown', function(e) {
        if (e.altKey && e.key === 'p') {
            let fileId = window.location.pathname.split('/')[3];
            let downloadUrl = `https://docs.google.com/document/d/${fileId}/export?format=pdf`;
            window.open(downloadUrl, '_blank');
        }
    });
})();

What can I do to fix this issue?


Solution

  • It seems that, when the editor is focused, all keydown events are fired in an about:blank iframe. Since Tampermonkey doesn't allow userscripts to run in about:blank, monitoring keydown events on document won't work when the editor is in focus.

    Instead, you can wait for the iframe to appear and then add your listener using a modified version of this hack:

    // ==UserScript==
    // ...
    // @match        https://docs.google.com/document/*
    // @run-at       document-start
    // ==/UserScript==
    
    (function() {
        'use strict';
    
        function openInNewTab(event) {
            if (event.altKey && event.key === 'p') {
                const fileId = window.location.pathname.split('/')[3];
                const downloadUrl = `https://docs.google.com/document/d/${fileId}/export?format=pdf`;
    
                window.open(downloadUrl, '_blank');
            }
        }
    
        document.addEventListener('keydown', openInNewTab);
    
        setTimeout(function poll() {
            const iframe = document.querySelector('iframe.docs-texteventtarget-iframe');
    
            if (!iframe) return setTimeout(poll, 100);
    
            const doc = iframe?.contentDocument;
            const div = doc?.querySelector('div');
    
            if (!div) return setTimeout(poll, 100);
    
            div.addEventListener('keydown', openInNewTab);
        });
    })();