I would like to programmatically edit my Google Doc externally via a Google Chrome extension or a simple JavaScript and see the changes live (in real-time) in the Google Doc. When this question came up, I was looking for Chrome Extensions that edit a Google Doc and save the changes programmatically. During my research, I came across Grammarly. I am impressed by how they manage to apply their spelling corrections to the Google Doc in near real-time. You can reproduce it like this:
Grammarly will then update the Google Doc. What I noticed thereby:
save
HTTP request is executedsi
(startIndex) and ei
(endIndex) defined in the 1st command of the array is replaced by the new word in the 2nd command)[{"commands":[{"ty":"ds","si":229,"ei":232}, {"ty":"is","ibi":229,"s":"Test"}]}]
I have already tried the following solutions:
gapi.client.docs.documents.batchUpdate({
documented: <docId>,
requests: [
{
deleteContentRange: {
range: {
startIndex: 1,
endIndex: 10,
},
},
},
{
insertText: {
location: {
index: 1,
},
text: 'Lorem ipsum',
},
},
],
})
// API call
await gapi.client.script.scripts.run({
scriptId: <scriptId>,
resource: {
function: 'myFunction'
}
})
// AppScript function from Google Script Editor
function myFunction() {
var body = DocumentApp.openById(<docId>).getBody()
body.appendParagraph("Lorem ipsum")
}
Unfortunately, all attempts so far have been unsuccessful or have not delivered the desired result.
(This methods works even with new canvas-based rendering)
Turns out it's super easy; we were all overthinking it. You can just simulate a keypress with an event, and use a for loop to instantly replace whatever text you need to modify. However, Google Docs listens to key events using an Iframe with the contents
<html>
<head></head>
<body spellcheck="false" role="textbox" aria-label="Document content" contenteditable="true" style="background-color: transparent;"></body>
</html>
so we have to trigger the event on the IFrame rather than the document. Also, it wasn't working for me from the content script, so I had to inject another script into the page and use a custom event to tell the injected script to simulate a keypress. You can inject a script as described here, then, from the injected script, you can simulate keypresses on the document like this:
const keyEvent = document.createEvent('Event')
keyEvent.initEvent('keypress', true, true)
keyEvent.key = KEY // A key like 'a' or 'B' or 'Backspace'
// You will need to change this line if you want to use other special characters such as the left and right arrows
keyEvent.keyCode = KEY.charCodeAt(0)
document.querySelector('.docs-texteventtarget-iframe')
.contentDocument.activeElement
.dispatchEvent(keyEvent)
(obtained from this answer).
You can wrap the above code in an event listener in your injected script and dispatch a custom event , with the detail
as the key name, from your content script, to trigger a keypress like this.
For my use case I didn't care where the cursor was, but if you need to find our where the cursor is so you can know how many times to simulate the left/right keys, you can get the index easily by counting the length of all the text classes and finding where the cursor is relative to each character. I found a nice little library for doing this (although, it has caveats as Google Docs apparently only loads one page at a time) that's too long to include here but you can view it on GitHub.
As already answered here - yes, you need send key events to special iframe, not current document.
I'm searched for same functionality recently. After finding it, i made a library. In further you can use this - google-docs-utils
.
You can use it with Node.js or directly in browser:
Here is the code which solves your task using google-docs-utils
package:
GoogleDocsUtils.typeText('test text'); // types at current caret position
GoogleDocsUtils.pressOn.Enter(); // move to new line
GoogleDocsUtils.typeText('another test text');
I looked at the source code of Grammarly - it uses same approach as this lib.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With