Skip to content

Instantly share code, notes, and snippets.

@zachthedev
Last active January 13, 2024 16:32
Show Gist options
  • Save zachthedev/0df884f490ec4a171ff0a8f8403a7926 to your computer and use it in GitHub Desktop.
Save zachthedev/0df884f490ec4a171ff0a8f8403a7926 to your computer and use it in GitHub Desktop.
Brings back visual last edit text in drive apps due to M3 migration by Google.
// ==UserScript==
// @name Restore Revision Time Visual Text in Google Apps
// @version 1.2
// @description Brings back visual last edit text in drive apps due to M3 migration by Google.
// @author ZachTheDev
// @match https://docs.google.com/document*
// @match https://docs.google.com/presentation*
// @match https://docs.google.com/spreadsheets*
// ==/UserScript==
(function() {
function addBackRevisionVisualText() {
const escapeHTMLPolicy = trustedTypes.createPolicy("use-raw-string", {
createHTML: (string) => string,
});
const revisionButtonElement = document.getElementById("docs-revisions-appbarbutton");
var revisionTextFromButton = revisionButtonElement.getAttribute("data-tooltip");
const menubarElement = document.getElementById("docs-menubar");
const revisionVisualTextHTML = "<div id=\"revisionVisualText\" class=\"menu-button goog-control goog-inline-block\" role=\"menuitem\" style=\"background-color: transparent;text-decoration: underline;\" data-tooltip=\"Open version history\"></div>";
const rangeForRevisionVisualTextHTML = document.createRange();
const fragmentForRevisionVisualTextHTML = rangeForRevisionVisualTextHTML.createContextualFragment(escapeHTMLPolicy.createHTML(revisionVisualTextHTML));
menubarElement.appendChild(fragmentForRevisionVisualTextHTML);
const revisionVisualTextElement = document.getElementById("revisionVisualText");
const setAttributeWatcher = revisionButtonElement.setAttribute;
revisionButtonElement.setAttribute = (key, value) => {
revisionTextFromButton = revisionButtonElement.getAttribute("data-tooltip");
revisionVisualTextElement.innerHTML = escapeHTMLPolicy.createHTML(revisionTextFromButton);
setAttributeWatcher.call(revisionButtonElement, key, value);
};
revisionVisualTextElement.addEventListener("mousedown", function (event) {
revisionButtonElement.dispatchEvent(new MouseEvent("mousedown"));
revisionButtonElement.classList.remove("jfk-button-hover");
revisionButtonElement.dispatchEvent(new MouseEvent("mouseup"));
event.stopPropagation(); // fixes bug where menus would open on hover after first click of the revisionVisualTextElement
});
revisionButtonElement.addEventListener("mouseenter", (event) => {revisionButtonElement.classList.add("jfk-button-hover");}, false);
}
addBackRevisionVisualText();
})();
@zachthedev
Copy link
Author

zachthedev commented Mar 9, 2023

Details

In March 2023, Google transitioned to Material Design v3 for Google Docs, Slides, and Sheets.
Amongst many things, this change also removed the "Last edit was ______ ago" text in the menubar.
This script replaces it by using DOM manipulation by grabbing the text of the tooltip from the new revisions button.

Installation

Prereq: Install Userscript Extension
Google Chrome: Install Tampermonkey or Violentmonkey.
Mozilla Firefox: Install Greasemonkey, Tampermonkey or Violentmonkey.
Opera: Install this extension first, then you can install Tampermonkey or Violentmonkey from the Chrome extension store.
Microsoft Edge: Install Tampermonkey from the Edge Add-On Repository.

Then do the following:

  1. Click here
  2. Click "Install this script"
  3. Confirm the installation by clicking "Install"

@andersonaddo
Copy link

Updated version that works on Firefox (not updated on Chrome).
https://greasyfork.org/en/scripts/462209-restore-revision-time-visual-text-in-google-apps

I thought it'd just be faster to hack a fix than bother you haha.
Thanks for taking the initiative!

@tech234a
Copy link

tech234a commented Jan 2, 2024

Useful script! Worked for awhile but broke because Google changed their CSP. Luckily it is simple to fix. Add this at the top of the function:

const escapeHTMLPolicy = trustedTypes.createPolicy("default", {
    createHTML: (string) => string,
});

Then tweak the two lines that set use HTML strings to use the sanitization function as follows:

const fragmentForRevisionVisualTextHTML = rangeForRevisionVisualTextHTML.createContextualFragment(escapeHTMLPolicy.createHTML(revisionVisualTextHTML));
revisionVisualTextElement.innerHTML = escapeHTMLPolicy.createHTML(revisionTextFromButton);

@zachthedev
Copy link
Author

@tech234a Thank you so much for you contribution! I haven't been in any drive files for a few weeks and did not notice it being broken. I just patched the gist to include your work. Updated my local version and it worked like a charm :)

@andersonaddo
Copy link

@tech234a thanks for the heads up, I changed my script as well. I had to make mine more type safe since trustedTypes exists on Chrome but not Firefox. Also, we shouldn't name this policy "default", since it will be used everywhere (not sure if its everywhere in the script or in the entire document). Reference: https://developer.mozilla.org/en-US/docs/Web/API/TrustedTypePolicyFactory/createPolicy

cc @zachthedev

@tech234a
Copy link

tech234a commented Jan 3, 2024

@andersonaddo Good catch about not naming it "default", I was wondering why a policy name had to be provided when creating a policy

@zachthedev
Copy link
Author

@andersonaddo Thanks for catching that. I have updated my version to reflect this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment