1

I need the full text of a user-made selection in Google Docs which may stretch over multiple lines.

This is different from this question: Get user-selected text because in that question the request was to get the text of individual words or lines that are selected. I need to be able to handle multiple lines with the correct whitespace.

I wrote the code below, and it almost works, but it smashes the text from two lines together without a newline character (or anything) separating them. It also doesn't include tabs from the original text. I'm guessing there are other limitations I haven't come across!

function getSelectedText()
{
  var selection = DocumentApp.getActiveDocument().getSelection();
  if( !selection )
    return "";
  var selectedElements = selection.getRangeElements();

  var theText = "";  
  for( var i=0; i < selectedElements.length; i++ )
  {
    var thisText = selectedElements[i].getElement().asText().getText();
    if( selectedElements[i].isPartial() )
    {
      var thisText = thisText.substring( selectedElements[i].getStartOffset(), selectedElements[i].getEndOffsetInclusive() + 1)
    }
    theText += thisText;
  }

  return theText;  
}

So let's say I have a document that looks like this with all the text selected by the user (with a tab in the second line):

Line 1    
Line 2

My script will construct the string, "Line 1Line 2". The string I would like is, "Line 1\nLine 2" or "Line 1\rLine 2".

Joe Conway
  • 11
  • 4

3 Answers3

1

This function came from a function I wrote to high light selected text. I modified it to append selected text back into the document so that it could be displayed in a non html format which will not display white space. Hopefully this will be helpful to you.

function getCurrentSelection() {
  var doc=DocumentApp.getActiveDocument();
  var selection=doc.getSelection();
  var total="";
  if(selection) {
    var selectedElements = selection.getRangeElements();
    for(var i=0;i<selectedElements.length;i++) {
      var selElem = selectedElements[i];
      var el = selElem.getElement();
      var isPartial = selElem.isPartial();
      if(isPartial) {
        var selStart = selElem.getStartOffset();
        var selEnd = selElem.getEndOffsetInclusive();
      }else {
        var selStart = selElem.getStartOffset();
        var selEnd = selElem.getEndOffsetInclusive();
      }
      var elType=el.getType();
      if(elType==DocumentApp.ElementType.TEXT) {
        var txt = selElem.getElement().asText().getText().slice(selStart,selEnd+1);
      }
      if(elType==DocumentApp.ElementType.PARAGRAPH) {
        var txt = selElem.getElement().asParagraph().getText();
      }
      total+=txt;
    }
  }else {
    total='';
  }
  doc.getBody().appendParagraph(total);
}
Cooper
  • 59,616
  • 6
  • 23
  • 54
  • I appreciate the effort, but as far as I can tell this ignores line breaks just like mine does! (Yours does handle tabs which I originally asked for, but I was mistaken about mine NOT handling them.) – Joe Conway Jan 31 '20 at 16:20
0

I have managed to copy the selected text (with line-breaks and tabs) with the following modification of your code:

function myFunction() {
  var doc=DocumentApp.getActiveDocument();
  var selection = DocumentApp.getActiveDocument().getSelection();
  if( !selection )
    return "";
  var selectedElements = selection.getRangeElements(); 
  for( var i=0; i < selectedElements.length; i++ )
  {
    var thisText = selectedElements[i].getElement().asText().getText();
    doc.getBody().appendParagraph(thisText);
  }
}

On selectedElements you get each of the paragraphs you have selected, lets say 2 paragraphs and an intro in the middle. Then you append each of these elements / paragraphs as a new paragraph.

Check if this works for you and let me know!

Kessy
  • 1,894
  • 1
  • 8
  • 15
  • Well you're essentially manually adding a '\r' between elements by outputting them with appendParagraph. I'm looking to have a string of the text to work with, not a direct output, BUT you've prompted me to believe I was overthinking it. Maybe I just need to manually add a '\r' between elements as I construct the string. I had presumed that elements weren't always new paragraphs, but maybe they are? So far adding the carriage return manually is working for me, so thank you! I just added the following to my for loop: if( i+1 < selectedElements.length ) theText += '\r'; – Joe Conway Feb 05 '20 at 18:09
0

Kessy's answer made me hypothesize I'm overthinking what elements are, and that it may be appropriate to manually add a single carriage return between them in constructing a string. Here's my original code with that slight modification.

So far it works, but if my assumption about elements is wrong, it may fail with text formatted in some untested way. (Though if text is formatted in a much more complicated way, it may not make sense to have a specific and unique string version of it anyway. E.g. text in a table.)

function getSelectedText()
{
  var selection = DocumentApp.getActiveDocument().getSelection();
  if( !selection )
    return "";
  var selectedElements = selection.getRangeElements();
  var theText = "";

  for( var i=0; i < selectedElements.length; i++ )
  {
    var thisText = selectedElements[i].getElement().asText().getText();
    if( selectedElements[i].isPartial() )
      var thisText = thisText.substring( selectedElements[i].getStartOffset(), selectedElements[i].getEndOffsetInclusive() + 1)
    theText += thisText;
    //I'm assuming each element is separated by one carriage return.
    if( i+1 < selectedElements.length )
      theText += '\r';
  }
  return theText;
}
Joe Conway
  • 11
  • 4