0% found this document useful (0 votes)
435 views18 pages

Google-Apps Script For Beginners Sample Chapter

Chapter No. 4 Embedding Scripts in Text Documents Customize Google Apps using Apps Script and explore its powerful features

Uploaded by

Packt Publishing
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
435 views18 pages

Google-Apps Script For Beginners Sample Chapter

Chapter No. 4 Embedding Scripts in Text Documents Customize Google Apps using Apps Script and explore its powerful features

Uploaded by

Packt Publishing
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Google Apps Script for Beginners

Serge Gabet

Chapter No. 4 "Embedding Scripts in Text Documents"

In this package, you will find:


A Biography of the author of the book A preview chapter from the book, Chapter NO.4 "Embedding Scripts in Text Documents" A synopsis of the books content Information on where to buy this book

About the Author


Serge Gabet has been a professional audio equipment manufacturer for 20 years and is now working for an artistic upper school in Brussels, Belgium as a teacher and Technical Manager. He is also in charge of the Google Apps administration of this school. He develops custom applications using Google Apps Script mainly for his school, though he also works in other areas.
He has been designated a Top Contributor by Google since June 2011. He was active on the Google Group Help forum till 2012, then on the Stack Overflow forum (the Google Help Group forum was closed in June 2012), and became a first ranker and an all-time contributor on the Stack Overflow forum a few months back. I'd like to thank all the forum contributors who were on the same forum at the time that I was new to the forum and helped me take my first steps. Most of them are now Top Contributors too and even if their knowledge was (and still is) greater than mine, they never make me feel it. Thanks for that. Also, thanks to Google collaborators for their day-to-day presence and for listening to our concerns.

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Google Apps Script for Beginners


A couple of years ago, I was asked by a colleague to create a form to collect invitation responses for a show that our school was organizing. Like most computer users, I had some experience with spreadsheets and had used them from time to time to do some basic calculations, so I created a form with the results in a spreadsheet. At this point, I simply wanted to count the responses and show the result somehow. As I didn't know how to get a clear view of these results and a simple addition of numbers was not very attractive to look at, I decided to take a quick peek at the documentation to see how to write a "macro" to eventually get things to look better. Three days later, the spreadsheet had a custom menu. It had functions that showed me the results in colorful tables and sent me an e-mail when too many people had made a reservation for the same day. I discovered that this "macro" that I was looking for had a lot more features than that; I had a whole bunch of tools and services that I was able to customize exactly to what I needed, without spending a single cent on it. This was the end of my ''peaceful life without Google Apps Script'' and the beginning of a real adventure. I didn't know a single word of JavaScript or HTML. My only programming experience was using BASIC on an 8-bit microcomputer from the 1980s, so I knew that there would be a few things to learn. This happened in 2009. At the time, Google Apps Script was just beginning its development. As it has grown a lot since then, it has provided an opportunity for my skills to improve as well. At that time, I found help from a couple of guys on the Google group help forum (now closed and wiped out). Thanks Henrique, scampmichael, and velosprinterthey know who they are. I know that each of us has a different background and follows a different path but, nevertheless, I decided to present this book following the same progression that I had followedfrom basic spreadsheet enhancement and customization to standalone web apps with really powerful features. In between, we shall see that other documents can have embedded scripts and that most of the Google services can communicate with Google Apps Script. There is probably no way to present every possible combination of scripts and methods that are available exhaustively in a single book. But, I'll try to pick up the most useful and interesting ones based on what I see every day on the well-known help site where I participate a lot: http://stackoverflow.com/questions/tagged/google-apps-script.

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

What This Book Covers


Chapter 1, Enhancing Spreadsheets, is an introduction to JavaScript as a spreadsheet macro language. It shows you how many aspects of a spreadsheet document could be modified using Google Scriptnot only layout and formatting but sharing and publishing as well. Chapter 2, Create and Manipulate Forms, deals with an automated form creation and modification with Google Apps Script. It demonstrates the ability of forms to respond to triggers, thereby automatically sending an evaluation with reference to good and bad answers. Chapter 3, Managing an E-mail Account, shows you how to send messages, filter your messages, and combine Gmail with documents to create your own workflow. You will learn that Google service offers an impressive panel of methods that allows for almost any possible manipulation of your mailbox content. Chapter 4, Embedding Scripts in Text Documents, shows you how to build and analyse Google documents using JavaScript. You will also see how to build or change a document's content and how to analyze what is already present in the document. Chapter 5, Embedding Scripts in Google Sites, demonstrates how a script updates your Google site automatically. This chapter also demonstrates the multiple aspects and advantages of the communication and combination of multiple services. Chapter 6, Standalone Web Applications / User Interfaces, teaches you how to create web applications that work everywhere and that anyone can use. It also shows you how to protect your private data across the Internet. Chapter 7, Using User Interfaces in Spreadsheets and Documents, empowers you to use your new skills to create more user-friendly documents and worksheets. It will simplify your work with spreadsheets and documents to either show data in a way that is not directly available or to add extra functionalities. Chapter 8, How to Expand Your Knowledge, gives you tips and tricks to learn what this book could not cover. It will give you an overview of the many resources available to help improve your learning experience. Chapter 9, Conclusion, ends with perspectives, secrets, and the author's personal point of view.

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Embedding Scripts in Text Documents


In the previous chapter, through the example of compiling the boss' e-mails, we learned that Google documents can have embedded scripts just like spreadsheets or forms do. This example use case could well have been implemented in a spreadsheet and in some aspects, it probably would have been easier, but the reason was more an aesthetic choice; in spreadsheets there is an absence of grid and cell limitations and the ability to customize the appearance with styles and colors. That is only a small example of what can be done in Google documents.

What can be done


If we consider the way these online documents work "behind the scenes", that is, the functioning of the backend software that Google has put in place to allow real-time editing and sharing, we shouldn't be surprised that a part of it has become available to Apps Script programmers. Remember that the le we are about to manipulate will not be hosted on our computer, but somewhere on Google's servers. The page we actually see is nothing but the rendering of a set of instructions that we sent to this server. Each keystroke, paragraph, or format we change may be considered as a small code sent to the server running an application. Of course, we don't need to know all of them. The engineers who designed the Google Docs service API had to translate it in a JavaScript-compliant language that anyone could use.

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Embedding Scripts in Text Documents

A look at the available methods at https://developers.google.com/appsscript/reference/document will tell you more about the plethora of methods than a description in this book ever could, even if I had a 100 pages to ll. So, let us focus on a couple of pleasant features illustrated with practical examples in the following sections.

Generating a Google document from spreadsheet data using a script


I mentioned earlier that we could have used a spreadsheet in the previous Gmail example to log the data we retrieved from the e-mail messages, but that the document approach was more pleasant in terms of "look". So I suggest that we try to build a Google document from data stored in a spreadsheet. The data can be a list of addresses or recipes. It doesn't really matter what data we use as the methods we use will be the same, but we'll use the list of recipes because they have pictures in them and had might as well give you some ideas for your next weekend lunch. The following screenshot shows how our current data sheet looksit's not very elegant:

We already know how to get data from a spreadsheet (see Chapter 1, Enhancing Spreadsheets) and that using getValues() will return an array of arrays with all the cells' data in a raw format. Each row will be an array of values corresponding to each cell; these arrays will in turn be wrapped in an array. We also see in our example that the rst row in the sheet has headers that we may want to use to get the structure of the data.

[ 64 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Chapter 4

Speaking of structure, if you read the tutorials on Google's help page (https://developers.google.com/apps-script/articles), you have probably noticed that they use a method to get data from a spreadsheet as objects, with the object of each row having its cell properties labelled using header values (https://developers.google.com/apps-script/guides/sheets#reading). There are actually many ways to manipulate data from spreadsheets. A Two-Dimensional (2D) array (in other words, an array of arrays) is a pleasant one. JavaScript-named objects are also nice to use and I have no real opinion about which is best, so I suggest that this time we give the object method a try. The next time will use pure array manipulation. Both approaches begin the same way: select a range in the sheet and get its values, then isolate the headers to know what data it has. This is done using the following code:
var data = SpreadsheetApp.getActive().getDataRange().getValues(); var headers = data.shift();

The preceding code results in the following output:

var data contains all the cells in an array of arrays. The shift() method removes the rst array (which is equal to the rst row) and assigns it to var headers. See the example documentation from w3schools at the following link: http://www.w3schools.com/jsref/jsref_shift.asp

[ 65 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Embedding Scripts in Text Documents

That is the common part of the two approaches. From now on, we must change our script to get JavaScript objects. As explained in the Google tutorial, it is advisable to use a CamelCase format for the object's variable names. It suggests a script to do so, but we're going to try something else, such as playing with a few string and array methods. See the comments in the following code and use the Logger to see every step of the process:
function camelise(stringArray) { var camelised = [];// this will hold the function result for(var n in stringArray){ Logger.log('title original = '+stringArray[n]) var title = stringArray[n].replace(/\W/gi,' ').split(' '); // replace every non "word" char with space and split string into an array (split on space) Logger.log('title array alphanumeric only = '+title) var result = ''; for(var t in title){ if(title[t].replace(/ /g,'')==''){ continue }; // skip any empty field result+=title[t].replace(/ /g,'')+'|'; // compose a result string with | separators (easier to see in the Logger) and no spaces } title = result.toLowerCase().split('|'); // everything in lowercase and convert back to an array splitting on | separators var camelCase = '';// initialize the result string for(t=0 ; t<title.length-1 ; t++){ // let's handle each word separately, the first word (index 0) should remain unchanged if(t==0){ var capWord = title[t]; }else{ capWord = title[t].substring(0,1).toUpperCase()+title[t]. substr(1); } // every following item gets a capital first letter camelCase+=capWord;// compose output result } // view each result in the Logger and store in an array Logger.log('camelCase = '+camelCase); camelised.push(camelCase); } // return the array of headers in CamelCase format return camelised; }

[ 66 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Chapter 4

Now we can test the preceding code using a special temporary function such as the one in the following code snippet:
function testGetHeadersAsCamelCase(){ var data = SpreadsheetApp.getActive().getDataRange().getValues();// we get all the cells with data in one call var headers = data.shift();// the first row is headers row and we remove this row from data altogether var ccHeaders = camelise(headers); for(var n in headers){ // create a loop Logger.log(headers[n]+' becomes >> '+ccHeaders[n]); } }

So we get the following partial log:


. [13-12-31 [13-12-31 [13-12-31 [13-12-31 [13-12-31 [13-12-31 [13-12-31 [13-12-31 09:16:19:385 09:16:19:385 09:16:19:386 09:16:19:386 09:16:19:386 09:16:19:386 09:16:19:387 09:16:19:387 CET] CET] CET] CET] CET] CET] CET] CET] Recipe title becomes >> recipeTitle Meal category becomes >> mealCategory main ingredient becomes >> mainIngredient all ingredients becomes >> allIngredients time to prepare becomes >> timeToPrepare number of guests becomes >> numberOfGuests directions becomes >> directions image url becomes >> imageUrl

Now that we have our headers in the right format, that is CamelCase, we can read the data in the sheet using the headers as keys and each cell row as value to build JavaScript Objects with key:value pairs as properties; the following code snippet depicts this:
function getObjects(data, keys) { var objects = [];// create an empty array variable for (var i = 0; i < data.length; ++i) {// iterate sheet data var object = {}; // create an empty "object" variable and then iterate each row's content for (var j = 0; j < data[i].length; ++j) { var cellData = data[i][j]; // check if cell is empty or contains any white space if (cellData.toString().replace(/ /g,'')=='') { continue; }else{ object[keys[j]] = cellData;// assign value to key } } [ 67 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Embedding Scripts in Text Documents objects.push(object);//store every object in array } return objects; }

Create a new document to hold the values as shown in the following piece of code:
var docId = DocumentApp.create('Recipes in a doc').getId(); Logger.log(docId);

We use another function to populate the document with text, tables, and images. In this chapter, I have called this function exportToDoc(docId,objects,keys, headers). It has four parameters: the newly created document ID, the array of objects, the keys (in case we need them), and the headers to show eld information. The next part of the code is not very hard to read. The various style denitions are dened as global variables at the end of the script as usual, but the data handling itself is very simple, thanks to the array-of-objects structure. The document formatting function is reproduced in the following code with comments on the important parts:
function exportToDoc(docId,objects,keys,headers){ var doc = DocumentApp.openById(docId); var body = doc.getBody(); var docHeader = doc.addHeader().appendParagraph('My favourite recipes\rCreated by script on ' +Utilities.formatDate(new Date(), Session. getTimeZone(),'MMM dd @ HH:mm')); // use the style defined outside of the function and use an alignment setting docHeader.setAttributes(styleHeader).setAlignment(DocumentApp. HorizontalAlignment.CENTER); for(var n in objects){ body.appendParagraph('An idea for a meal with '+objects[n] [keys[1]]+' composed mainly of '+objects[n][keys[2]]+' for '+objects[n][keys[5]]+' :').setAttributes(styleBase); body.appendParagraph('The name of this recipe is "'+objects[n] [keys[0]]+'" but I invented it myself \rso you can change it if you want').setAttributes(styleBase); body.appendHorizontalRule(); body.appendParagraph('List of '+headers[3]+' :'); var table = []; var ing = objects[n][keys[3]].split(','); for(var i in ing){ table.push(['You must have '+ ing[i]]) };

[ 68 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Chapter 4 body.appendTable(table).setAttributes(styleTable); body.appendParagraph('Try to get some free time, it will take approximately '+objects[n][keys[4]]+', then clean up your kitchen and '+objects[n][keys[6]]).setAttributes(styleDirections); body.appendHorizontalRule(); var image = DriveApp.getFileById(objects[n][keys[7]].split('d/') [1].split('/')[0]).getBlob();// retrieve ID from URL // https://drive.google.com/file/d/0B3qSFd3iikE3UmpjelRQdlZmQXc/ edit?usp=sharing This is a typical link body.appendParagraph('good apetite ;) ').appendInlineImage(image). setWidth(300).setHeight(200).getParent().setAttributes(styleImage); body.appendHorizontalRule(); if(n<objects.length){body.appendPageBreak()}; } }

The style denitions are grouped at the end of the script. They can even be stored in a separate script le within the same project. This is shown in the following code snippet:
// Style definitions as global variables var bodyStyle = {};// define a style for body, margin etc... bodyStyle[DocumentApp.Attribute.MARGIN_LEFT] = 30; bodyStyle[DocumentApp.Attribute.MARGIN_BOTTOM] = 20; bodyStyle[DocumentApp.Attribute.MARGIN_RIGHT] = 30; bodyStyle[DocumentApp.Attribute.MARGIN_TOP] = 20; body.setAttributes(bodyStyle); var styleBase = {};// a "base" style for paragraphs styleBase[DocumentApp.Attribute.FONT_SIZE] = 11; styleBase[DocumentApp.Attribute.FONT_FAMILY] = DocumentApp. FontFamily.AMARANTH; styleBase[DocumentApp.Attribute.FOREGROUND_COLOR] = "#444400"; var styleHeader = {};// define a style for document header styleHeader[DocumentApp.Attribute.BACKGROUND_COLOR] = '#eeeeff' styleHeader[DocumentApp.Attribute.FONT_SIZE] = 16; styleHeader[DocumentApp.Attribute.FONT_FAMILY] = DocumentApp. FontFamily.CORSIVA; styleHeader[DocumentApp.Attribute.FOREGROUND_COLOR] = '#0000aa'; var styleTable = {};// define a style for table styleTable[DocumentApp.Attribute.FONT_SIZE] = 10; styleTable[DocumentApp.Attribute.FONT_FAMILY] =DocumentApp. FontFamily.AMARANTH; styleTable[DocumentApp.Attribute.FOREGROUND_COLOR] = "#005500"; styleTable[DocumentApp.Attribute.BORDER_WIDTH] = 0 ;

[ 69 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Embedding Scripts in Text Documents var styleDirections = {};// define a style for direction paragraph styleDirections[DocumentApp.Attribute.FONT_SIZE] = 12; styleDirections[DocumentApp.Attribute.FONT_FAMILY] = DocumentApp. FontFamily.CONSOLAS; styleDirections[DocumentApp.Attribute.ITALIC] = true; styleDirections[DocumentApp.Attribute.FOREGROUND_COLOR] = "#000066"; var styleImage = {}; styleImage[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER; // end of file

We can now write a main function that will call all the others in turn; the function generateDoc() will be the one to call to create the document as shown in the following code snippet:
function generateDoc(){ var data = SpreadsheetApp.getActive().getDataRange().getValues(); // we first get all the cells with data in one call var headers = data.shift(); // shift is an array function the removes the first row // and assign it to the variable headers var keys = getHeadersAsCamelCase(headers); // get the CamelCase formatted headers using a separate function var objects = getObjects(data, keys); for(var n in objects){ for(var k in keys){ Logger.log('Object '+n+' properties '+keys[k]+' = '+objects[n] [keys[k]]); } } // we get all the values using 2 loops var docId = DocumentApp.create('Recipes in a doc').getId(); //create a doc as a container for our recipes Logger.log(docId); exportToDoc(docId,objects,keys,headers); }

Running generateDoc() is going to create a multipage document with one recipe per page with a better layout and an inline image.

[ 70 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Chapter 4

The next step would be to create a form linked to the source spreadsheet (as seen in Chapter 2, Create and Manipulate Forms) so that all your friends can add their own recipes. With a single click, you will be ready to publish a cookbook with no effort. If you do, just let me know, I love cooking! The following screenshot shows the document created:

[ 71 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Embedding Scripts in Text Documents

Analyzing, duplicating, and modifying document elements


In the rst section of this chapter, we have built a document from scratch using various methods, but we could also try the reverse process; in other words, we can analyze a document to see its content. In doing so, we will be able to copy a part of the document, modify the document's content, and even insert new elements in the document or simply assemble multiple documents in one (see, for example, my last answer on this post at http://stackoverflow.com/questions/10939031/how-to-delete-blankpages-in-a-multipage-). Just about every method set in DocumentApp has a symmetric get method that returns precise information on every element. Elements can be built hierarchically with parents and children (I used that hierarchy when inserting the image in our example; the image was a child of the paragraph : body.appendParagraph('good apetite').appendInlineImage(image) and a good analyze script will have to examine elements at every level.

Using a script to insert an image into a document


A complete example including every method would be very long, so I'll show a simplied layout to show how it works, but that only identies every type of element and replaces a paragraph with an image if a predened placeholder =='###', is found in the paragraph. You should easily be able to implement a more universal version yourself that adds or modies elements based on certain conditions. Test the following code in a text document, such as the one we just created with our recipes.
function findMarkAndReplace() { var Doc = DocumentApp.getActiveDocument(); var image = DocsList.getFileById('0B3qSFd3iikE3UmpjelRQdlZmQXc'); // this is an image from the recipe's example stored on my drive and shared publicly var totalElements = Doc.getNumChildren(); var el=[]; for( var j = 0; j < totalElements; ++j ) { var element = Doc.getChild(j); var type = element.getType(); Logger.log('element '+j+" : "+type); // to see doc's content type [ 72 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Chapter 4 if (type =='PARAGRAPH'){ el[j]=element.getText(); if(el[j]=='###'){ element.removeFromParent(); // remove the ### placeholder Doc.insertImage(j, image); // 'image' is the image file as blob } } } }

Compiling and presenting data from other services


In the example we used to create a document, we were getting data from a spreadsheet; but, of course, you can get data from any other Google service and, although it is not as simple, any other data server on the Internet. This is one of the major advantages of the document creation mode that Google has implemented in this service. Just about anything that contains text can be imported and presented in a Google document along with images, drawings, and even math formulas. The preceding example showed how to insert an image stored in our drive; the next one will get text from our personal calendar. Calendar, contact, spreadsheets, and forms are really easy to get data from in a way that ts pretty well in a text document, because every property can be obtained as a string. It is only a matter of imagination and creativity on your part to concatenate everything in a pleasant way. The following is a very basic example of a script that gets events from your default calendar and writes them in an open document. I haven't used any style parameters apart from background color and horizontal alignment to keep it as short as possible:
function importFromCal(){ var cal = CalendarApp.getDefaultCalendar(); var endDate = new Date(); var startDate = new Date(endDate.getTime()-30*24*3600000); // start date is 30 days before end date var events = cal.getEvents(startDate, endDate); var doc = DocumentApp.getActiveDocument(); var body = doc.getBody(); var styleEvent = {}; //define a style object to play with for(var n=0 ; n<events.length; n++){ [ 73 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Embedding Scripts in Text Documents if( n % 2 == 0){ // every odd row will be right aligned, every even row will be left aligned styleEvent[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT; }else{ styleEvent[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.RIGHT; } var bgColor = parseInt(0xff*(n+1)/events.length); // fade color to white using hex values Logger.log('color = #'+bgColor.toString(16)+'ffff'); styleEvent[DocumentApp.Attribute.FOREGROUND_COLOR] = '#222222'; styleEvent[DocumentApp.Attribute.BACKGROUND_COLOR] = '#'+bgColor. toString(16)+'ffff'; body.appendParagraph(events[n].getTitle()+'\r'+events[n]. getDescription()+'\ron '+Utilities.formatDate(events[n]. getStartTime(), Session.getTimeZone(),'MMM dd, yyyy')+'\r@'+events[n]. getLocation()).setAttributes(styleEvent); } }

The following screenshot shows the result of the preceding code:

[ 74 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Chapter 4

In the preceding code, we used some pure JavaScript methods such as Math.floor and % that are well explained on many JavaScript reference websites (for example,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ Global_Objects/Math).

Spend some time reading the documentation about all the elements that you can include in a document and all the data sources you can use. In the next chapter, we will use a document embedded in a Google website and update it automatically everyday with data from a spreadsheet.

Summary
Document-embedded scripts can be used on many different occasions; we have seen how to build or change the content of a document and analyze what is already in it; this process could easily be developed to create an elegant mail-merge workow, getting data directly from your Gmail contact. In Chapter 7, Using User Interfaces in Spreadsheets and Documents, we'll see that we can also add a custom user interface to a document and create new features that make the documents even more attractive and efcient. In the next chapter, we will learn about embedding scripts on Google sites.

[ 75 ]

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

Where to buy this book


You can buy Google Apps Script for Beginners from the Packt Publishing website: http://www.packtpub.com/google-apps-script-for-beginners/book.
Free shipping to the US, UK, Europe and selected Asian countries. For more information, please read our shipping policy.

Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and most internet book retailers.

www.PacktPub.com

For More Information: www.packtpub.com/google-apps-script-for-beginners/book

You might also like