How do you place the index of a document, generated from a template, on a particular page in InDesign Server? - indesign-server

I've been given a template document and we've already worked out how to add data with index tags.
I've figured out how to use the generate function on the index object to place the index on some of the pages. However, when I specify the page that is supposed to hold the index I don't see the index. The Index page does have a master page.
Here is a test script I'm working with for reference. I expect it to place the index title on the appropriate page.
var myDocument = app.open(File("/c/Template.indt"));
var indexPage = myDocument.pages.item(7);
var index = myDocument.indexes.add();
var layer = myDocument.activeLayer;
index.generate(indexPage, [1,0], layer, true, true);
var webexportpreset = app.pdfExportPresets.item("[Smallest File Size]");
myDocument.exportFile(ExportFormat.pdfType, new File("/c/test.pdf"), webexportpreset);
myDocument.close();

Related

How to assign custom properties to Google Slides contents using Google-App-Script

I would like certain images have an extra property. Essentially my goal is to uniquely identify the images i've added using App Script code and not in the Google Slides app.
This is what I have so far
const dataBlob = Utilities.newBlob(dataBaseEight);
const presentation = SlidesApp.openByUrl('https://docs.google.com/presentation...');
const slides = presentation.getSlides();
const x = slides[0].insertImage(dataBlob);
x.isAddedUsingAppScript = true;
Logger.log(x.isAddedUsingAppScript);//true
Logger.log(slides[0].getImages()[0].isAddedUsingAppScript);//false
FYI I always make sure to have no images in the first slide prior to testing the code.
Looking at the Image Class, there are no methods to add custom attributes to the images, but you have a couple workarounds.
insertImage(blobSource) returns the image that was inserted, so you can use setDescription() on it to add your true/false value and call it later with getDescription():
const dataBlob = Utilities.newBlob(dataBaseEight);
const presentation = SlidesApp.openByUrl('https://docs.google.com/presentation...');
const slides = presentation.getSlides();
const x = slides[0].insertImage(dataBlob);
x.setDescription("true")
Logger.log(slides[0].getImages()[0].getDescription()) //returns "true"
The problem with this is that the "Description" field is also editable by right-clicking the image and selecting "Alt text", so users could mess with it or you may also want to use it for something else.
Another way to identify the images is by their getObjectID() method which returns a unique ID. You can get these unique IDs and store using the the Properties Service along with their true/false value:
const dataBlob = Utilities.newBlob(dataBaseEight);
const presentation = SlidesApp.openByUrl('https://docs.google.com/presentation...');
const slides = presentation.getSlides();
const x = slides[0].insertImage(dataBlob);
var id = x.getObjectID() // returns "some-id"
var props = PropertiesService.getDocumentProperties() // call the properties service
props.setProperty(id, true) // set "true" to the some-id key
Logger.log(slides[0].getImages()[0].getObjectID()) //returns "some-id" again
Logger.log(props.getProperty("some-id")) // returns "true"
This doesn't use up the description field and it's harder for users to accidentally change the values, but you may have to keep closer track of the images and their saved properties since the properties will remain even if the images are deleted.
Do note that in both cases the saved values are string, not boolean.
References
Class Image
Properties Service

How to add a table programatically at specific place in Google Document?

I am using Google document a template for generating PDFs files. The template contains placeholders - **name-of-placeholder** The placeholder is later on replaced with a value of corresponding variable. Now I need to replace a placeholder with a table.
Could someone suggest how to replace a text with a table using Google Application Script?
The template looks like that
I need to replace text detaily-programu with a table.
I managed to add a table
at the end of the document
// table method c.1
//Add a table in document
var table = body.appendTable()
at the point where is should be by replacing empty table
// table method c.2
// var searchType = DocumentApp.ElementType.TABLE
// var table = body.findElement(searchType).getElement()
// table.clear()
I would prefer to be able to replace the placeholder with a table. But I cannot make it work. .findText() finds the text but I do not know how to append the table after the element .findText() found. And of course delete the element.
// table method c.3
var text = body.findText("detaily-programu").getElement()
//var table = text.asParagraph().appendTable() // Exception: TEXT can't be cast to PARAGRAPH.
//var table = text.appendTable() // TypeError: text.appendTable is not a function
Thanks to Kos and this answer I was able to do exactly what I wanted. The code is
var rgel= args.body.findText("detaily-programu")
var element=rgel.getElement()
var childIndex= args.body.getChildIndex(element.getParent())
args.body.getChild(childIndex).asText().setText('')
var table = args.body.insertTable(childIndex)

Inserting variable data into an existing Google Sheet in Google Scripts

I'm building a script that will ultimately take data from a csv file, populate a spreadsheet, use that spreadsheet to autofill a number of documents, and then automatically e-mail those documents to customers. It's also moving the documents from each time the script runs to a new folder with just that day's reports. I'm pretty new to Google Scripts, and this has been my learning project.
The steps I've got to work so far is the creation of documents for the spreadsheet with dummy data.
I ended up creating a second script to send e-mails which sends e-mails, but it is set up to look for all documents in the folder that are google docs, so it send a copy of every document to each customer. I thought that if I pointed the e-mail back to the original spreadsheet to grab just the correct document IDs (instead of the type) , I could only send customers the reports that belonged to them (all in PDF form). The step of creating a new folder and moving the documents into it afterwards works fine.
What I'm having an issue with is inputting data into my document ID column in the original spreadsheet. I have been able to watch it put the document ID of the first document into every row that has info to iterate over in the column, and then replace every row again with the second document's ID, etc.
I looked for ways to add data to a spreadsheet. Every method I've found so far involves creating a new column or row with new information from data within the spreadsheet. I need to put in data that I'm just now creating outside of the spreadsheet and then put it in the right place so I can point to it later.
I've gone over the methods within the documentation. It looks like .getCell.setvalue(variable) should work...if I could find a way to get the cell from the range (Which keeps showing me out of range).
function createDocument() {
var headers = Sheets.Spreadsheets.Values.get('17jXy9IlLt8C41tWEG5iQR31GjzOftlJs73y2L_0ZWNM', 'A1:P1');
var tactics = Sheets.Spreadsheets.Values.get('17jXy9IlLt8C41tWEG5iQR31GjzOftlJs73y2L_0ZWNM', 'A2:P');
var templateId = '1DU13OJHWyYnO5mLFovm97pWwXuU7ZTTDVJb2Mpdeebk';
for(var i = 0; i < tactics.values.length; i++){
var customer = tactics.values[i][0];
var pcname = tactics.values[i][1];
var date = tactics.values[i][2];
var virusvalue = tactics.values[i][3];
var cpuuse = tactics.values[i][4];
var ramuse = tactics.values[i][5];
var harddrive = tactics.values[i][6];
var netuse = tactics.values[i][7];
var downtime = tactics.values[i][8];
var cpuperform = tactics.values[i][9];
var ramperform = tactics.values[i][10];
var harddiskperform = tactics.values[i][11];
var reccomend = tactics.values[i][13];
var custID = tactics.values[i][14];
var newdoc = tactics.values[i][15];
//Make a copy of the template file
var documentID = DriveApp.getFileById(templateId).makeCopy(DriveApp.getFolderById('1zV-WpzUKoRurE9FnBcfjBygBA5rCO67I')).getId();
//rename the copied file
DriveApp.getFileById(documentID).setName('MCHA ' + customer + ' - ' + pcname);
Logger.log('value1 ' + documentID);
//THIS IS THE AREA I'M TRYING TO FIX
var ss = SpreadsheetApp.openById('113aqWVAjjUYCmI2oFc_BTbXkWMPFPjk_SschsKEx6qU');
var cell = ss.getRange('P2:P').getCell([i], [15]);
cell.setValue(documentID);
SpreadsheetApp.flush();
Logger.log('value2 ' + documentID);
//This area has code to replace the tags in the document with values from the spreadsheet. I cut it for not being relevant.
}
}
Obviously defining the range is just going to fill and autofill each cell. That code worked when I tried it
I originally tried using the variable from my earlier list for the autofill, but I've since realized that shouldn't work at all.
I tried to set the range of cells and then set the current cell by the same notation ([i][15] etc.) which throws an 'Range not found' error. I feel like I must be missing some syntax.
A link to the folder with all the documents is below, if that helps.
https://drive.google.com/drive/folders/1sRhti3R8R-Cym0hr2S4XkAVn3wyBbSRu?usp=sharing
I may not have entirely understood the problem you are facing. But I can see the cause of the 'Range not found' error.
Your loop starts with a value of 0 for i. This causes the script to look for a range called P0 in the first iteration.
One way to avoid that is to try :
var cell = ss.getRange("P"+(i+1));
For code efficiency, I'd also suggest moving some of the code outside the loop. For example, the following line runs each time in the loop. But it could be defined once outside the loop and then the variable ss could be reused inside the loop.
var ss = SpreadsheetApp.openById('113aqWVAjjUYCmI2oFc_BTbXkWMPFPjk_SschsKEx6qU');
Similarly, you could define the template file outside the loop and then sue it inside to make copies:
var templateFile = DriveApp.getFileById(templateId); // Outside the loop
And then inside the loop:
var documentID = templateFile.makeCopy(DriveApp.getFolderById('1zV-WpzUKoRurE9FnBcfjBygBA5rCO67I')).getId();
Google apps script best practices suggests minimising calls to the spreadsheet, i.e. get the data in one call, process it, and then post the data to the sheet in one call. More here.
Hope this helps.

How to copy one or more existing pages of a document using google apps script

I have sucessfully written a small script, which creates a serial letter (physical letter to several recipients) based on data in a Google spreadsheet creating a new document for each letter/addresse.
It works, but for large mailings this approach is a bit cumbersome as a large amount of documents are created and need to be printed individually.
Now i would like to do the same but as a result having all of the letters in one single Google document.
Is there any way to copy the content of an existing document and inserting it a number of times into the same or any other documents (i.e. copy/paste via apps script)?
Following your comment, here is the full code I use to merge an undetermined number of docs in a new one.
All document IDs are in an array of IDs as argument for the main function, the results is a new doc with "multi-page" appended to the name. If you need more explanation than provided by the in code comments just let me know... (note that it will work only for documents containing text and tables, if you have images ot other data type you'll have to handle that case in the main loop where we check the ElementType following the same logic)
EDIT : first code removed, following your update I tried this approach assuming you have only paragraphs in your master doc... give it a try and I guess you could start from there to developp your project.
function Serialletter_Singledocument() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Datenbank");
var LastColumn = sheet.getLastColumn();
//here you need to get document id from url (Example, 1oWyVMa-8fzQ4leCrn2kIk70GT5O9pqsXsT88ZjYE_z8)
var FileTemplateFileId = "1Wrf2qvUTyc5tMmJIly40Z4U4sJb4-QhT5z-UfJmtQ-M" //Browser.inputBox("ID der Serienbriefvorlage (aus Dokumentenlink kopieren):");
var doc = DocumentApp.openById(FileTemplateFileId);
var DocName = doc.getName();
var headpara=' ***** ';
// Fetch entire table containing data
var data = sheet.getDataRange().getValues();
//Create copy of the template document and open it
var SerialLetterID = DocsList.getFileById(FileTemplateFileId).makeCopy(DocName +" Serienbrief").getId();
var docCopy = DocumentApp.openById(SerialLetterID);
var totalParagraphs = docCopy.getBody().getParagraphs() ;// get the total number of paragraphs elements
Logger.log(totalParagraphs);
var elements = [];
for ( var i = 1; i < data.length; i++) { //do for every record in the spreadsheet (containing the content to replace the variables in the letter)
for (var e=0;e<totalParagraphs.length;e++){
var element = totalParagraphs[e].copy();
// Logger.log(element.editAsText().getText())
for(var c=0;c<data[0].length;c++){
element.replaceText("<" +data[0][c] +">", data[i][c]); //replace variable (from column title) with actual value
}
elements.push(element);// store paragraphs in an array
}
for(var el=0;el<elements.length;el++){
var paragraph = elements[el].copy();
docCopy.getBody().appendParagraph(paragraph);
}
docCopy.getBody().appendPageBreak()
}
docCopy.saveAndClose();
Browser.msgBox("Serienbrief ist erstellt. Sie finden die erstellten Dokumente in Google Drive unter Meine Ablage");
}

How to get a document object from a file object in a Google-Apps Script

My problem is that I have a number of Google documents (docs) and each has a table of contents. I want to grab the TOC's and place them in another document. This should be easy, but I have run into a snag.
I can grab all of files in a folder with:
var folder = DocsList.getFolder('yourfolder');
var contents = folder.getFilesByType(DocsList.FileType.DOCUMENT);
This gives me an array of files as the variable 'contents'
Great.
I also know that
var TOC = **doc**.getAs(DocumentApp.ElementType.TABLE_OF_CONTENTS)
The problem is that I cannot figure out how to get a document object from a file object or alternately how to get an array of documents in a folder rather than an array of files.
I have searched for an answer and not only on this site. If anyone can help, I would appreciate it very much
DocsList and DocumentApp have at least one method in common which is that they have access to the ID of documents so it is quite straightforward to pass this ID parameter from one method to the other.
This code demonstrates :
function myFunction() {
var folder = DocsList.getFolder('yourfolder');
var contents = folder.getFilesByType(DocsList.FileType.DOCUMENT);
var docObject = [];
for(var c in contents){
docObject.push(DocumentApp.openById(contents[c].getId()));
}
Logger.log(docObject);// now you have an array of DocumentApp objects
}