Search code examples
javascriptgoogle-apps-scriptgoogle-docsfootnotes

Google apps script - retain links when copying footnote content


Background

I have a Google Apps Script that we use to parse the footnote content, wrapped in double parenthesis, in place of the footnote number superscript. The intended result should be:

Before Script

This is my footie index.1


1This is my footie content with a link and emphasis.

After Script

This is my footie index. (( This is my footie content with a link and emphasis.)

Problem

Everything works fine, except when I parse the footnotes in double parenthesis, they are losing all the links and formatting:

This is my footie index. (( This is my footie content with a link and emphasis.)

If anyone can assist me with fixing the code below I would really appreciate the help :)

SOLUTION:

function convertFootNotes () {
  var doc = DocumentApp.getActiveDocument()
  var copy = generateCopy(doc) // make a copy to avoid damaging the original
  var openCopy = doc; //DocumentApp.openById(copy.getId()) // you have to use the App API to copy, but the Doc API to manipulate
  performConversion(openCopy); // perform formatting on the copy
}

function performConversion (docu) {
  var footnotes = docu.getFootnotes(); // get the footnotes
  footnotes.forEach(function (note) {
    // Traverse the child elements to get to the `Text` object
    // and make a deep copy

    var paragraph = note.getParent(); // get the paragraph
    var noteIndex = paragraph.getChildIndex(note); // get the footnote's "child index"
    insertFootnote(note.getFootnoteContents(),true, paragraph, noteIndex);
    note.removeFromParent();
  })
} 

function insertFootnote(note, recurse, paragraph, noteIndex){
  var numC = note.getNumChildren(); //find the # of children
  paragraph.insertText(noteIndex," ((");
  noteIndex++;
  for (var i=0; i<numC; i++){
    var C = note.getChild(i).getChild(0).copy();

    if (i==0){
      var temp = C.getText();
      var char1 = temp[0];
      var char2 = temp[1];
      if (C.getText()[0]==" "){
        C = C.deleteText(0,0);
      }
    }

    if (i>0){
      paragraph.insertText(noteIndex,"\n");
      noteIndex++;
    }
    paragraph.insertText(noteIndex,C);
    noteIndex++;

  } //end of looping through children
  paragraph.insertText(noteIndex,"))");
}

function generateCopy (doc) {
  var name = doc.getName() + ' #PARSED_COPY' // rename copy for easy visibility in Drive
  var id = doc.getId()
  return DriveApp.getFileById(id).makeCopy(name)
}

Solution

  • Were there any changes to the code other than the added )) to make it not work? Removing the (( & )) still did not have the formatting applied when testing it; getText() returns the element contents as a String, not a rich text object/element which contains the formatting info.

    To get to the Text object:

    1. getFootnoteContents().getChild(0) returns the FootnoteSection Paragraph
    2. getChild(0).getChild(0) returns the Text object of that paragraph
    3. copy() returns a detached deep copy of the text object to work with

    Note: If there are other child elements in the FootnoteSection or in it's Paragraph child, you'll want to add some kind of type/index checking to get the correct one. However, with basic footnotes - as the above example - this is the correct path.

    function performConversion (docu) {
      var footnotes = docu.getFootnotes() // get the footnotes
      var noteText = footnotes.map(function (note) {
        // Traverse the child elements to get to the `Text` object
        // and make a deep copy
        var note_text_obj = note.getFootnoteContents().getChild(0).getChild(0).copy();
    
        // Add the `((` & `))` to the start and end of the text object
        note_text_obj.insertText(0, " ((");
        note_text_obj.appendText(")) ");
    
        return note_text_obj // reformat text with parens and save in array
      })
    
      ...
    
    }