2020-03-17 15:38:37 -04:00
|
|
|
function onOpen() {
|
|
|
|
const ui = SpreadsheetApp.getUi();
|
2020-03-17 16:22:59 -04:00
|
|
|
ui.createMenu('CMS Document Generation')
|
|
|
|
.addItem('Generate document for current row', 'generateForCurrentRow')
|
2020-03-17 15:38:37 -04:00
|
|
|
.addToUi();
|
|
|
|
}
|
|
|
|
|
2020-03-18 14:38:34 -04:00
|
|
|
type DocSection =
|
|
|
|
| GoogleAppsScript.Document.Body
|
|
|
|
| GoogleAppsScript.Document.HeaderSection
|
|
|
|
| GoogleAppsScript.Document.FooterSection;
|
|
|
|
|
2020-03-17 15:38:37 -04:00
|
|
|
function copyElement(
|
|
|
|
source_element: GoogleAppsScript.Document.Element,
|
2020-03-18 14:38:34 -04:00
|
|
|
dest: DocSection,
|
2020-03-17 15:38:37 -04:00
|
|
|
index?: number
|
|
|
|
) {
|
|
|
|
const element = source_element.copy();
|
|
|
|
// based on https://stackoverflow.com/questions/6783819/google-app-script-copy-document-page
|
|
|
|
if (element.getType() == DocumentApp.ElementType.PARAGRAPH)
|
2020-03-18 14:33:06 -04:00
|
|
|
if (index !== undefined) dest.insertParagraph(index, element.asParagraph());
|
2020-03-17 15:38:37 -04:00
|
|
|
else dest.appendParagraph(element.asParagraph());
|
|
|
|
else if (element.getType() == DocumentApp.ElementType.TABLE)
|
2020-03-18 14:33:06 -04:00
|
|
|
if (index !== undefined) dest.insertTable(index, element.asTable());
|
2020-03-17 15:38:37 -04:00
|
|
|
else dest.appendTable(element.asTable());
|
|
|
|
else if (element.getType() == DocumentApp.ElementType.LIST_ITEM)
|
2020-03-18 14:33:06 -04:00
|
|
|
if (index !== undefined) dest.insertListItem(index, element.asListItem());
|
2020-03-17 15:38:37 -04:00
|
|
|
else dest.appendListItem(element.asListItem());
|
|
|
|
else if (element.getType() == DocumentApp.ElementType.INLINE_IMAGE)
|
2020-03-18 14:33:06 -04:00
|
|
|
if (index !== undefined) dest.insertImage(index, element.asInlineImage());
|
2020-03-17 15:38:37 -04:00
|
|
|
else dest.appendImage(element.asInlineImage());
|
|
|
|
else
|
|
|
|
throw new Error(
|
|
|
|
"According to the doc this type couldn't appear in the body: " +
|
|
|
|
element.getType()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-18 14:38:34 -04:00
|
|
|
function copySection(source: DocSection, dest: DocSection, index?: number) {
|
2020-03-17 16:59:20 -04:00
|
|
|
const totalElements = source.getNumChildren();
|
|
|
|
for (let j = 0; j < totalElements; ++j) {
|
2020-03-17 15:38:37 -04:00
|
|
|
if (index) copyElement(source.getChild(j), dest, index + j);
|
|
|
|
else copyElement(source.getChild(j), dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-17 18:27:50 -04:00
|
|
|
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;
|
|
|
|
}, {});
|
|
|
|
}
|
|
|
|
|
2020-03-17 16:22:59 -04:00
|
|
|
function generateForCurrentRow() {
|
2020-03-17 16:35:47 -04:00
|
|
|
const spreadsheet = SpreadsheetApp.getActive();
|
|
|
|
const cell = spreadsheet.getCurrentCell();
|
|
|
|
if (!cell) throw new Error('No Cell selected for operation on row');
|
2020-03-17 15:38:37 -04:00
|
|
|
|
2020-03-17 18:27:50 -04:00
|
|
|
const row = spreadsheetRowToObject(
|
|
|
|
spreadsheet.getActiveSheet(),
|
|
|
|
cell.getRow()
|
2020-03-17 15:38:37 -04:00
|
|
|
);
|
|
|
|
|
2020-03-17 18:27:50 -04:00
|
|
|
const source_doc = DocumentApp.openById(row['Document ID']);
|
|
|
|
|
|
|
|
const template_file = DriveApp.getFileById(row['Template ID']);
|
|
|
|
const out_folder = DriveApp.getFolderById(
|
|
|
|
'1ROyJXk-QANTHM6Jiw0ne3EQiR1f2UsLr'
|
|
|
|
);
|
2020-03-17 16:35:47 -04:00
|
|
|
|
2020-03-17 18:27:50 -04:00
|
|
|
const out_file = template_file.makeCopy(
|
|
|
|
row['Document Name'] + row['Version'],
|
|
|
|
out_folder
|
|
|
|
);
|
|
|
|
const out_doc = DocumentApp.openById(out_file.getId());
|
|
|
|
|
|
|
|
// 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));
|
2020-03-17 16:35:47 -04:00
|
|
|
});
|
|
|
|
|
2020-03-17 15:38:37 -04:00
|
|
|
const insert_point = out_doc
|
|
|
|
.getBody()
|
2020-03-17 16:08:32 -04:00
|
|
|
.findText('{{body}}')
|
2020-03-17 15:38:37 -04:00
|
|
|
?.getElement();
|
|
|
|
|
2020-03-17 16:08:32 -04:00
|
|
|
if (!insert_point) {
|
|
|
|
throw new Error("Could not find insert point '{{body}}'");
|
|
|
|
}
|
2020-03-17 15:38:37 -04:00
|
|
|
|
2020-03-17 16:08:32 -04:00
|
|
|
// 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();
|
2020-03-17 15:38:37 -04:00
|
|
|
}
|
2020-03-17 16:08:32 -04:00
|
|
|
const index = out_doc.getBody().getChildIndex(parent);
|
|
|
|
|
2020-03-18 14:33:06 -04:00
|
|
|
copyBody(source_doc.getBody(), out_doc.getBody(), index);
|
2020-03-17 16:08:32 -04:00
|
|
|
out_doc.getBody().removeChild(parent);
|
2020-03-17 18:27:50 -04:00
|
|
|
out_doc.saveAndClose();
|
|
|
|
|
|
|
|
// create PDF file
|
|
|
|
out_folder.createFile(out_file.getAs('application/pdf'));
|
2020-03-17 15:38:37 -04:00
|
|
|
}
|