Skip to content

Instantly share code, notes, and snippets.

@tsiemens
Last active April 2, 2020 19:02
Show Gist options
  • Select an option

  • Save tsiemens/5d6507590a35ebde833b388e48510862 to your computer and use it in GitHub Desktop.

Select an option

Save tsiemens/5d6507590a35ebde833b388e48510862 to your computer and use it in GitHub Desktop.
Google Docs Preview Redirect Tampermonkey Script
// ==UserScript==
// @name Preview Google Docs
// @version 1.0.0
// @description Same you some CPU and RAM
// @author Trevor Siemens
// @homepageUrl https://gist.github.com/tsiemens/5d6507590a35ebde833b388e48510862
// @match https://docs.google.com/document/d/*/edit*
// @match https://docs.google.com/document/d/*/preview*
// @run-at document-start
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @require https://openuserjs.org/src/libs/sizzle/GM_config.min.js
// ==/UserScript==
// ***************************************************
// General utils
// ***************************************************
const logSig = "Preview Google Docs (tamper):";
// ***************************************************
// GM_config
// https://github.com/sizzlemctwizzle/GM_config/
// ***************************************************
const settingsFieldDefs = {
'alwaysRedirectFrom': {
'section': [GM_config.create("Auto-Redirection Rules"), "One URL regex per line"],
'label': 'Always redirect to preview when coming from these domains',
'labelPos': 'top',
'type': 'textarea',
'default': 'https?:\/\/aid[\.\/]'
},
'neverRedirectFrom': {
'label': 'Do not ask or redirect to preview when coming from these domains',
'labelPos': 'top',
'type': 'textarea',
'default': ''
},
'showPreviewPageSnackbar': {
'section': "Preview page settings",
'label': 'Show notification when redirected to preview page',
'type': 'checkbox',
'default': true
}
};
function _addConfigErrorText(doc, parentElemId, id) {
let parentGrp = doc.getElementById(parentElemId);
let errorDiv = doc.createElement("div");
errorDiv.setAttribute("id", id);
errorDiv.className = "ugm_config_error_msg";
parentGrp.appendChild(errorDiv);
return errorDiv;
}
function _setConfigErrorMsg(configId, errorDiv) {
let text = GM_config.get(configId);
let res = _parsePatternsFromMultilineText(text);
errorDiv.innerHTML = res.errors.join("\n");
}
function _getRegexTestMatches(configId, testUrl) {
let text = GM_config.get(configId);
let res = _parsePatternsFromMultilineText(text);
let matches = [];
for (let pattern of res.patterns) {
if (testUrl.search(pattern) >= 0) {
matches.push(pattern.toString());
}
}
return matches;
}
var _updateRegexTestResult = null;
function _addRegexTestInput(doc) {
let section0Container = doc.getElementById("GM_config_section_0");
let inputWrapper = doc.createElement("div");
inputWrapper.className = "config_var"; // Standard GM_config class for config styles
// <input id="GM_config_field_name" type="text" size="25">
// <label id="GM_config_name_field_label" for="GM_config_field_name" class="field_label">Name</label>
let testInput = doc.createElement("input");
testInput.setAttribute("id", "GM_config_regex_test_input");
testInput.setAttribute("type", "text");
testInput.setAttribute("size", "25");
testInput.setAttribute("autocomplete", "off");
inputWrapper.appendChild(testInput);
let label = doc.createElement("label");
label.className = "field_label"; // Standard GM_config class for config styles
label.setAttribute("for", "GM_config_field_name");
label.innerHTML = "Enter a URL here to test (save first)";
inputWrapper.appendChild(label);
section0Container.appendChild(inputWrapper);
let testingResult = doc.createElement("p");
testingResult.setAttribute("id", "GM_config_regex_test_output");
section0Container.appendChild(testingResult);
_updateRegexTestResult = () => {
let matchesA = _getRegexTestMatches("alwaysRedirectFrom", testInput.value);
let matchesN = _getRegexTestMatches("neverRedirectFrom", testInput.value);
let matchText = "";
let lines = [];
if (matchesA.length > 0) {
lines.push("Matches from 'always redirect' patterns:");
for (let match of matchesA) {
lines.push(match);
}
}
if (matchesN.length > 0) {
lines.push("Matches from 'never redirect' patterns:");
for (let match of matchesN) {
lines.push(match);
}
}
if (lines.length == 0 && testInput.value.length > 0) {
lines.push("No matching patterns");
}
testingResult.innerHTML = lines.join("<br>");
};
testInput.addEventListener('input', _updateRegexTestResult);
}
function _gmConfigInit() {
// GM_config included from external lib
'use strict';
let context = {}
GM_config.init(
{
id: 'GM_config',
title: 'Preview Google Docs Settings',
fields: settingsFieldDefs,
css: `#GM_config_section_1 .config_var, #GM_config_section_2 .config_var, #GM_config_section_3 .config_var {
margin: 5% !important;display: inline !important;
}
.ugm_config_error_msg {
color: #f00;
}`,
events:
{
open: function(doc) {
// Custom modifications to the settings panel can be made here.
let errorDiv = _addConfigErrorText(doc, "GM_config_alwaysRedirectFrom_var",
"GM_config_alwaysRedirectFrom_errors");
context.alwaysRedirErrorDiv = errorDiv;
errorDiv = _addConfigErrorText(doc, "GM_config_neverRedirectFrom_var",
"GM_config_neverRedirectFrom_errors");
context.neverRedirErrorDiv = errorDiv;
_addRegexTestInput(doc);
},
save: function(values) {
// All the values that aren't saved are passed to this function
// for (i in values) alert(values[i]);
_setConfigErrorMsg("alwaysRedirectFrom", context.alwaysRedirErrorDiv);
_setConfigErrorMsg("neverRedirectFrom", context.neverRedirErrorDiv);
_updateRegexTestResult();
}
}
});
}
function _parsePatternsFromMultilineText(text) {
let lines = text.split('\n');
let patterns = [];
let errors = [];
for (let line of lines) {
if (line.length > 0) {
try {
let pat = RegExp(line);
patterns.push(pat);
} catch (e) {
errors.push("Error in \"" + line + "\" : " + e.message);
}
}
}
return {patterns: patterns, errors: errors};
}
function _getAlwaysRedirectFromList() {
let text = GM_config.get("alwaysRedirectFrom");
let res = _parsePatternsFromMultilineText(text);
return res.patterns;
}
function _getNeverRedirectFromList() {
let text = GM_config.get("neverRedirectFrom");
let res = _parsePatternsFromMultilineText(text);
return res.patterns;
}
// ***************************************************
// Preview page functions
// ***************************************************
function _addSnackbarStyles() {
'use strict';
GM_addStyle(`
#ugm_snackbar {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 1000;
left: 50%;
bottom: 30px;
font-size: 17px;
}
#ugm_snackbar.show {
visibility: visible;
// Each part is [ name, duration, delay (absolute) ]
-webkit-animation: ugm_fadein 0.5s, ugm_fadeout 0.5s 2.5s, ugm_stayout 20s 3s;
animation: ugm_fadein 0.5s, ugm_fadeout 0.5s 2.5s, ugm_stayout 20s 3s;
}
@-webkit-keyframes ugm_fadein {
from {bottom: 0; opacity: 0;}
to {bottom: 30px; opacity: 1;}
}
@keyframes ugm_fadein {
from {bottom: 0; opacity: 0;}
to {bottom: 30px; opacity: 1;}
}
@-webkit-keyframes ugm_fadeout {
from {bottom: 30px; opacity: 1;}
to {bottom: 0; opacity: 0;}
}
@keyframes ugm_fadeout {
from {bottom: 30px; opacity: 1;}
to {bottom: 0; opacity: 0;}
}
@-webkit-keyframes ugm_stayout {
from {opacity: 0;}
to {opacity: 0;}
}
@keyframes ugm_stayout {
from {opacity: 0;}
to {opacity: 0;}
}
`);
}
function _showSnackbar(text) {
'use strict';
let x = document.createElement("div");
x.innerHTML = text;
x.setAttribute("id", "ugm_snackbar");
document.body.appendChild(x);
// let initialDelay = 1000;
let initialDelay = 1000;
setTimeout(() => {
x.className = "show";
console.log("1");
setTimeout(() => {
console.log("2");
x.className = x.className.replace("show", "");
console.log("no show");
}, 3000);
},
initialDelay);
setTimeout(() => { document.body.removeChild(x); }, initialDelay + 5000);
}
function _handlePreviewPage() {
if (!GM_config.get("showPreviewPageSnackbar")) {
return;
}
window.addEventListener('load', function() {
'use strict';
_addSnackbarStyles();
let referrer = document.referrer;
console.log(logSig, "Referrer: \"" + referrer + "\"");
if (referrer.search(RegExp("https://docs.google.com/document/d/.*/edit.*")) >= 0) {
console.log(logSig, "Doc preview page was referred by edit page");
_showSnackbar("Redirected from Google Doc editor (tampermonkey)");
}
}, false);
}
// ***************************************************
// Redirection functions
// ***************************************************
function _isRefresh() {
'use strict';
if (window.performance) {
// performance is supported
let navEntries = window.performance.getEntriesByType("navigation");
if (navEntries.length == 0) {
console.log(logSig, "Found no performance nagivation entries");
return false;
}
let navType = navEntries[0].type;
console.log(logSig, "navigation type: " + navType);
return navType == "reload";
}
console.log(logSig, "window.performance not supported");
return false;
}
// ***************************************************
// Script entry point
// ***************************************************
(function() {
'use strict';
_gmConfigInit();
GM_registerMenuCommand('Settings', () => {
console.log(logSig, "Open settings");
GM_config.open();
});
if (window.location.href.match("https://docs.google.com/document/d/.*/preview")) {
_handlePreviewPage();
return;
}
let referrer = document.referrer;
console.log(logSig, "Referrer: \"" + referrer + "\"");
if (_isRefresh()) {
// Do not apply on refresh. This would most likely just be annoying.
return;
}
let noPrompt = false;
for (let pattern of _getAlwaysRedirectFromList()) {
if (referrer.search(pattern) >= 0) {
console.log(logSig, "Auto-previewing (matched " + pattern + ")");
noPrompt = true;
break;
}
}
for (let pattern of _getNeverRedirectFromList()) {
if (referrer.search(pattern) >= 0) {
console.log(logSig, "Not previewing (matched " + pattern + ")");
return;
}
}
if (noPrompt ||
window.confirm("Preview Google Docs (Tampermonkey):\n\nOpen Google Doc in preview mode?")) {
var url = window.location.href;
var previewUrl = url.replace(RegExp("(.*/)edit(.*)"), "$1preview$2");
window.location.replace(previewUrl);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment