2

If I have the string:

var text = "Altman, R. (1992). Sound space. In R. Altman (Ed.), <em>Sound Theory Sound Practice</em> (pp. 46–64). New York: Routledge.";

How can I insert this into Google Docs with the required italics intact?

var cursor = DocumentApp.getActiveDocument().getCursor();
cursor.insertText('here: ' + text);

Inserts the text as is (without displaying italics and showing the <em>...</em>).

A few people have asked similar questions here without success mostly getting answers that relate to creating a new document using the Drive service (I want to insert HTML text anywhere in an existing document).

I've come across intriguing snippets such as:

var text = Utilities.newBlob("").setDataFromString(response.bibEntry, "UTF-8").setContentType("text/html");

or:

var text = doGet('<b>Hello, world!</b>');
function doGet(text) {
return HtmlService.createHtmlOutput(text);
}

But these appear to return objects which I've no idea how to use – trying to use insertText(text), I get 'Blob' and 'HtmlOutput' respectively.

2 Answers 2

2

I've taken what Rubén has provided above and bits and pieces from elsewhere to come up with a reasonably flexible way to convert HTML styling on external text for insertion at the cursor position in a google document. The caveat is that you need to know precisely the HTML tags that are in the external text (in my case, I do). This code does the italics plus a few other tags, deals with nested and multiple tags, and deletes the HTML code. For fun, I've added in HREF handling. I'm sure it can be improved and/or made more efficient (e.g. I'd love to know how to get away with just the one regExp(), for example) – how can it be improved?

var regexpItalics = RegExp(/(<em>)(.*?)(<\/em>)/, 'g');
var regexpBold = RegExp(/(<strong>)(.*?)(<\/strong>)/, 'g');
var regexpUnderline = RegExp(/(<span style="text-decoration: underline;">)(.*?)(<\/span>)/, 'g');
var regexpSub = RegExp(/(<sub>)(.*?)(<\/sub>)/, 'g');
var regexpSup = RegExp(/(<sup>)(.*?)(<\/sup>)/, 'g');
var regexpHref = RegExp(/(<a class="rLink" href=".*>)(.*?)(<\/a>)/, 'g');
var deleteArray = [];
var i;
var text = "some text with <em>itali<strong>cs</em> and bold</strong>";

var document = DocumentApp.getActiveDocument();
var cursor = document.getCursor();
var element = cursor.insertText(text);
var styles = ['italics', 'bold', 'underline', 'super', 'sub', 'href'];
for (i = 0; i < styles.length; i++) {
  insertHtmlText(element, text, styles[i]);
}
deleteArray.sort(function (b, a) {
  return a.end - b.end;
});
for(i = 0; i < deleteArray.length; i++) {
  element.editAsText().deleteText(deleteArray[i].start, deleteArray[i].end);
}

function insertHtmlText(element, text, style) {
  var i;
  var matches = [];
  var transformArray = [];

  switch (style) {
    case 'italics': 
      matches = [...text.matchAll(regexpItalics)];
      transformArray = findTags(matches);
      for(i = 0; i < transformArray.length; i++) {
        element.editAsText().setItalic(transformArray[i].textStart, transformArray[i].textEnd, true);
      }
      break;
    case 'bold': 
      matches = [...text.matchAll(regexpBold)];
      transformArray = findTags(matches);
      for(i = 0; i < transformArray.length; i++) {
        element.editAsText().setBold(transformArray[i].textStart, transformArray[i].textEnd, true);
      }
      break;
    case 'underline': 
      matches = [...text.matchAll(regexpUnderline)];
      transformArray = findTags(matches);
      for(i = 0; i < transformArray.length; i++) {
        element.editAsText().setUnderline(transformArray[i].textStart, transformArray[i].textEnd, true);
      }
      break;
    case 'super': 
      matches = [...text.matchAll(regexpSup)];
      transformArray = findTags(matches);
      for(i = 0; i < transformArray.length; i++) {
        element.editAsText().setTextAlignment(transformArray[i].textStart, transformArray[i].textEnd, DocumentApp.TextAlignment.SUPERSCRIPT);
      }
      break;
    case 'sub': 
      matches = [...text.matchAll(regexpSub)];
      transformArray = findTags(matches);
      for(i = 0; i < transformArray.length; i++) {
        element.editAsText().setTextAlignment(transformArray[i].textStart, transformArray[i].textEnd, DocumentApp.TextAlignment.SUBSCRIPT);
      }
      break;
    case 'href': 
      matches = [...text.matchAll(regexpHref)];
      transformArray = findTags(matches);
      for(i = 0; i < transformArray.length; i++) {
        element.editAsText().setLinkUrl(transformArray[i].textStart, transformArray[i].textEnd, transformArray[i].capture);
      }
      break;
    default: 
      break; // Missing format
  }
}
function findTags(matches) {
  var openTagStart, openTagEnd, textStart, textEnd, closeTagStart, closeTagEnd;
  var transformArray = [];

  for (let match of matches) {
    openTagStart = match.index;
    openTagEnd = openTagStart + match[1].length - 1;
    textStart = openTagEnd + 1;
    textEnd = textStart + match[2].length - 1;
    closeTagStart = textEnd + 1;
    closeTagEnd = closeTagStart + match[3].length -1;
    transformArray.push({
      openTagStart: openTagStart,
      openTagEnd: openTagEnd,
      textStart: textStart,
      textEnd: textEnd,
      closeTagStart: closeTagStart,
      closeTagEnd: closeTagEnd,
      capture: match[2]
    });
    deleteArray.push({start: openTagStart, end: openTagEnd});
    deleteArray.push({start: closeTagStart, end: closeTagEnd});
  }
  return transformArray;
}
1

It's not possible to use HTML tags to format text in Google Docs on Google Apps Script, instead you should use the appropriated classes and methods. The following example use setItalic(startOffset, endOffsetInclusive, italic) ;

function myFunction() {
  const text1 = "Altman, R. (1992). Sound space. In R. Altman (Ed.),";
  const text2 = "Sound Theory Sound Practice";
  const text3 = "(pp. 46–64). New York: Routledge.";
  const doc = DocumentApp.getActiveDocument();
  const body = doc.getBody()
  body.setText([text1,text2,text3].join(" "))
  const start = text1.length + 1;
  const end = start + text2.length;
  body.editAsText().setItalic(start, end, true);
}

Resources

2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.