This repository has been archived on 2020-06-25. You can view files and clone it, but cannot push or open issues or pull requests.
documentTemplates/Code.ts

162 lines
5.0 KiB
TypeScript

function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('CMS Document Generation')
.addItem('Generate document for current row', 'generateForCurrentRow')
.addItem('Generate document for all rows', 'generateForAllRows')
.addToUi();
}
type DocSection =
| GoogleAppsScript.Document.Body
| GoogleAppsScript.Document.HeaderSection
| GoogleAppsScript.Document.FooterSection;
function copyElement(
source_element: GoogleAppsScript.Document.Element,
dest: DocSection,
index?: number
) {
const element = source_element.copy();
switch (element.getType()) {
case DocumentApp.ElementType.PARAGRAPH:
if (index !== undefined)
dest.insertParagraph(index, element.asParagraph());
else dest.appendParagraph(element.asParagraph());
break;
case DocumentApp.ElementType.TABLE:
if (index !== undefined) dest.insertTable(index, element.asTable());
else dest.appendTable(element.asTable());
break;
case DocumentApp.ElementType.LIST_ITEM:
if (index !== undefined) dest.insertListItem(index, element.asListItem());
else dest.appendListItem(element.asListItem());
break;
case DocumentApp.ElementType.INLINE_IMAGE:
if (index !== undefined) dest.insertImage(index, element.asInlineImage());
else dest.appendImage(element.asInlineImage());
break;
default:
throw new Error(
"According to the doc this type couldn't appear in the body: " +
element.getType()
);
}
}
function copySection(source: DocSection, dest: DocSection, index?: number) {
const totalElements = source.getNumChildren();
for (let j = 0; j < totalElements; ++j) {
if (index) copyElement(source.getChild(j), dest, index + j);
else copyElement(source.getChild(j), dest);
}
}
function spreadsheetRowToObject(
sheet: GoogleAppsScript.Spreadsheet.Sheet,
rownum: number
): { [key: string]: any } {
// TODO: could be more efficient
const values = sheet.getDataRange().getValues();
const headers = values[0];
const row_data = values[rownum - 1];
return headers.reduce((acc, header, index) => {
acc[String(header)] = row_data[index];
return acc;
}, {});
}
function trashFiles(files: GoogleAppsScript.Drive.FileIterator) {
while (files.hasNext()) {
files.next().setTrashed(true);
}
}
function generateForRow(
spreadsheet: GoogleAppsScript.Spreadsheet.Spreadsheet,
row_num: number
) {
const row = spreadsheetRowToObject(spreadsheet.getActiveSheet(), row_num);
const template_doc = DocumentApp.openById(row['Template ID']);
const source_file = DriveApp.getFileById(row['Document ID']);
const out_folder = DriveApp.getFolderById(
'1ROyJXk-QANTHM6Jiw0ne3EQiR1f2UsLr'
);
const out_name = row['Document Name'] + '_' + row['Version'];
// Delete old files with the same name
trashFiles(out_folder.getFilesByName(out_name));
trashFiles(out_folder.getFilesByName(out_name + '.pdf'));
// Duplicate source document and open
const out_file = source_file.makeCopy(out_name, out_folder);
const out_doc = DocumentApp.openById(out_file.getId());
// Copy header
if (!out_doc.getHeader()) out_doc.addHeader();
copySection(template_doc.getHeader(), out_doc.getHeader().clear());
// Copy footer
if (!out_doc.getFooter()) out_doc.addFooter();
copySection(template_doc.getFooter(), out_doc.getFooter().clear());
const insert_point = template_doc
.getBody()
.findText('{{body}}')
?.getElement();
if (!insert_point) {
throw new Error("Could not find insert point '{{body}}'");
}
// find the parent element that is a direct descendant of the body
let parent = insert_point;
while (parent.getParent().getType() != DocumentApp.ElementType.BODY_SECTION) {
parent = parent.getParent();
}
const index = template_doc.getBody().getChildIndex(parent);
// Copy body contents above and below {{body}} tag
for (let j = 0; j < template_doc.getBody().getNumChildren(); j++) {
if (j < index)
copyElement(template_doc.getBody().getChild(j), out_doc.getBody(), j);
// don't copy {{body}} tag
else if (j == index) continue;
else copyElement(template_doc.getBody().getChild(j), out_doc.getBody());
}
// do text replacement
Object.entries(row).forEach(([header, data]) => {
out_doc.getBody().replaceText(`{{${header}}}`, String(data));
out_doc.getHeader().replaceText(`{{${header}}}`, String(data));
out_doc.getFooter().replaceText(`{{${header}}}`, String(data));
});
out_doc.saveAndClose();
// create PDF file
out_folder.createFile(out_file.getAs('application/pdf'));
}
function generateForCurrentRow() {
const spreadsheet = SpreadsheetApp.getActive();
const cell = spreadsheet.getCurrentCell();
if (!cell) throw new Error('No Cell selected for operation on row');
generateForRow(spreadsheet, cell.getRow());
}
function generateForAllRows() {
const spreadsheet = SpreadsheetApp.getActive();
const row_count = spreadsheet.getActiveSheet().getDataRange().getNumRows();
for (let row_num = 2; row_num < row_count; row_num++) {
generateForRow(spreadsheet, row_num);
}
}