bugmagnet
bugmagnet

Reputation: 7769

In Google Docs under script control, can a paragraph inserted automatically after the insertion of a table be addressed programmatically?

I have a Google Docs document with a PARAGRAPH followed by a TABLE followed by a TABLE. Visually there is a PARAGRAPH between the two TABLEs. Programatically, however, using the following code, the run log demonstrates that there is no PARAGRAPH, viz

[1] PARAGRAPH {'LEFT_TO_RIGHT' : true, 'LINE_SPACING' : 1.15, 'SPACING_AFTER' : 0, 'SPACING_BEFORE' : 0, 'INDENT_FIRST_LINE' : 0, 'INDENT_END' : 0, 'INDENT_START' : 0} 
[1/1] TEXT {} perth influencer
[2] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'} 
[3] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'} Keyword Research Volume
...

According to the Google Apps Script documentation for appendTable:

This method will also append an empty paragraph after the table, since Google Docs documents cannot end with a table.

This paragraph can be seen with the eyes but the script as it stands cannot "see" it. That is, stepping through the child elements of the document's body fails to detect the presence of the automatically-inserted paragraph. This is a problem because I want to reduce the point size of that paragraph.

This may be a known limitation of Google Docs via Google Apps Script. Or it may be my bad code, so below are the functions that I base my assertion on. They do nothing other than report on what they find but even so, maybe I'm missing something.

The output above was generated by coding LogChildren with a parameter of type GoogleAppsScript.Document.Body and referring to the body of the generated document.

String.prototype.quoted = function () {
  return  "'" + this.replace(/'/g,"\\'") + "'";
}

Number.prototype.quoted = function () {
  return String(this);
}

Boolean.prototype.quoted = function () {
    return this ? "true" : "false";
}

function getInnerText(child) {
    switch (child.getType().toString()) {
        case "BODY_SECTION":
            return child.asBody().getText();
            break;
        case "EQUATION":
            return child.asEquation().getText();
            break;
        case "EQUATION_FUNCTION":
            return child.asEquationFunction().getText();
            break;
        case "FOOTER_SECTION":
            return child.asFooterSection().getText();
            break;
        case "FOOTNOTE_SECTION":
            return child.asFootnoteSection().getText();
            break;
        case "HEADER_SECTION":
            return child.asHeaderSection().getText();
            break;
        case "LIST_ITEM":
            return child.asListItem().getText();
            break;
        case "PARAGRAPH":
            return "";
            break;
        case "TABLE":
            return child.asTable().getText();
            break;
        case "TABLE_CELL":
            return child.asTableCell().getText();
            break;
        case "TABLE_OF_CONTENTS":
            return child.asTableOfContents().getText();
            break;
        case "TABLE_ROW":
            return child.asTableRow().getText();
            break;
        case "TEXT":
            return child.asText().getText();
            break;
        case "PAGE_BREAK":
            return "";
            break;
        case "INLINE_IMAGE":
            return child.asInlineImage().getLinkUrl();
            break;
        default:
            return child.asText().getText();
            break;
    }
}
function getStyles(child) {
    const attribs = child.getAttributes();
    const attribList = [];
    for (let att in attribs) {
        try {
            if (null !== attribs[att])
                attribList.push(att.quoted() + " : " + attribs[att].quoted());
        }
        catch (E) { }
    }
    return "{" + attribList.join(", ") + "}";
}
function LogChild(index, child) {
    Logger.log("[%s] %s %s %s", index, child.getType().toString(), getStyles(child), getInnerText(child));
}
function LogChildren(body) {
    function LogDeeper(cc, child) {
        const childCount = child.getNumChildren();
        for (let c = 0; c < childCount; c++) {
            LogChild(String(cc) + "/" + String(c + 1), child.getChild(c));
        }
    }
    const childCount = body.getNumChildren();
    for (let c = 0; c < childCount; c++) {
        const child = body.getChild(c);
        LogChild(String(c + 1), child);
        if (isParagraph(child)) {
            LogDeeper(c + 1, child.asParagraph());
        }
        else if (isListItem(child)) {
            LogDeeper(c + 1, child.asListItem());
        }
    }
}
function isPageBreak(elem) {
    return elem.getType() === DocumentApp.ElementType.PAGE_BREAK;
}
function isText(elem) {
    return elem.getType() === DocumentApp.ElementType.TEXT;
}
function isParagraph(elem) {
    return elem.getType() === DocumentApp.ElementType.PARAGRAPH;
}
function isListItem(elem) {
    return elem.getType() === DocumentApp.ElementType.LIST_ITEM;
}
function isTable(elem) {
    return elem.getType() === DocumentApp.ElementType.TABLE;
}

Upvotes: 0

Views: 164

Answers (1)

TheMaster
TheMaster

Reputation: 50462

Use 's Document#get to retrieve the document structure and if there is a intervening paragraph recorded between the two tables, issue UpdateParagraphStyleRequest to modify that paragraph.

You can access the api from apps script through Advanced Google services

Upvotes: 2

Related Questions