javascriptgoogle-chrome-extensionhtml5-canvasgoogle-docs

Get selected text


I'm building a Chrome Extension for Google Docs, and I am trying to get the selected text from the current document being edited:

Snapshot of selected text in Google Docs

However when I trying running this code, it's returning an empty string ' ':

const docsFrame = document.getElementsByClassName('docs-texteventtarget-iframe')[0]
docsFrame.contentDocument.getSelection().toString()

There was a library called Google Docs Utils that used to be able to do this, but since Docs switched to Canvas-based rendering, the library no longer works.

EDIT:

Here's an example Google Docs to test it out

EDIT # 2:

Made some progress, found this thread with a lot of potential soltutions on it: https://github.com/Amaimersion/google-docs-utils/issues/10


Solution

  • I figured out how to accomplish it with the help of the thread I mentioned above and through studying some open source code. I am not sure if I am allowed to post open source code here and to avoid licensing conflicts, I will post here the general steps I found:

    1. Enable screen reader functionality / SVG reading. Google will add svg and rect elements to ".kix-canvas-tile-selection" that contain the text that was typed in. Look towards the second half of this thread for different solutions to enabling this.

    2. Use $(".kix-page-paginated").get() to get the current page on Google Docs. Then use $(window).height() calculations to figure out what page the user is currently on.

    3. After accomplishing the two above, you can use a function like so below to get the line of text

       function getSelectedLineOfText(page) {
         const overlaps = (a, b) => a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top
         const selectionRects = $(".kix-canvas-tile-selection > svg > rect", page).get()
           .map(el => el.getBoundingClientRect())
         // Using text elements on that page and the selection rects, find the actual selected line of text.
         const textElements $("svg > g[role=paragraph] > rect", page).get(); 
      

    Note: as you can see from the function name, this can only get an entire selected line in the file. It can't get the specific text selected within a line.

    enter image description here

    So here, "name is Bob. Hi my name is Bob. Hi my name is Bob." will be returned. I was struggling to get more specific than this, so if anyone has a clue, please feel free to add / create another answer.