/*
All the code examples from "Google Spreadsheet Programming"
Author: Michael Maguire
*/
// Chapter 2
function sayHelloBrowser() {
// Declare a string literal variable.
var greeting = 'Hello world!';
// Display a message dialog with the greeting
//(visible from the containing spreadsheet).
Browser.msgBox(greeting);
}
function helloDocument() {
var greeting = 'Hello world!';
// Create DocumentApp instance.
var doc =
DocumentApp.create('test_DocumentApp');
// Write the greeting to a Google document.
doc.setText(greeting);
// Close the newly created document
doc.saveAndClose();
}
function helloLogger() {
var greeting = 'Hello world!';
//Write the greeting to a logging window.
// This is visible from the script editor
// window menu "View->Logs...".
Logger.log(greeting);
}
function helloSpreadsheet() {
var greeting = 'Hello world!',
sheet = SpreadsheetApp.getActiveSheet();
// Post the greeting variable value to cell A1
// of the active sheet in the containing
// spreadsheet.
sheet.getRange('A1').setValue(greeting);
// Using the LanguageApp write the
// greeting to cell:
// A2 in Spanish,
// cell A3 in German,
// and cell A4 in French.
sheet.getRange('A2')
.setValue(LanguageApp.translate(
greeting, 'en', 'es'));
sheet.getRange('A3')
.setValue(LanguageApp.translate(
greeting, 'en', 'de'));
sheet.getRange('A4')
.setValue(LanguageApp.translate(
greeting, 'en', 'fr'));
}
// Chapter 3
// Cannot be called as a UDF.
function setRangeFontBold (rangeAddress) {
var sheet =
SpreadsheetApp.getActiveSheet();
sheet.getRange(rangeAddress)
.setFontWeight('bold');
}
// Call "setRangeFontBold()" from editor.
function call_setCellFontBold () {
var rangeAddress = Browser.inputBox(
'Set Range Font Bold',
'Provide a range address',
Browser.Buttons.OK_CANCEL);
if (rangeAddress) {
setRangeFontBold(rangeAddress);
}
}
// Given the standard deviation and the mean,
// return the relative standard deviation.
function RSD (stdev, mean) {
if (!(typeof stdev === 'number' &&
typeof mean === 'number')) {
throw {'name': 'TypeError',
'message':
'Function "RSD()" requires ' +
'two numeric arguments'};
}
return (100 * (stdev/mean)).toFixed(2)*1;
}
// Given a temperature value in Celsius
// return the temperature in Fahrenheit.
function celsiusToFahrenheit (celsius) {
if (typeof celsius !== 'number') {
throw {
'name': 'TypeError',
'message': 'Function requires ' +
'a single number argument'};
}
return ((celsius * 9) / 5) + 32;
}
// Given a temperature in Fahrenheit,
// return the temperature in Celsius.
function fahrenheitToCelsius(fahrenheit) {
if (typeof fahrenheit !== 'number') {
throw {
'name': 'TypeError',
'message': 'Function requires ' +
' a single number argument'};
}
return ( fahrenheit - 32 ) * 5/9;
}
// Given the radius, return the
// area.
// Throw an error if the radius is
// negative.
function areaOfCircle (radius) {
if (typeof radius !== 'number'){
throw {
'name': 'TypeError',
'message': 'Function requires ' +
'a single numeric argument'};
}
if (radius < 0) {
throw {
'name': 'ValueError',
'message': 'Radius myst ' +
' be non-negative'};
}
return Math.PI * (radius * radius);
}
function test_intervalInDays() {
var date1 = new Date(),
date2 = new Date(1972, 7, 17);
Logger.log(intervalInDays(date1, date2));
}
// Write String methods to the logger.
function printStringMethods() {
var strMethods =
Object.getOwnPropertyNames(
String.prototype);
Logger.log('String has ' +
strMethods.length +
' properties.');
Logger.log(strMethods.sort().join('\n'));
}
// Reverse the alphabet.
function test_reverseString () {
var str = 'abcdefghijklmnopqrstuvwxyz';
Logger.log(reverseString(str));
}
// Return a string with the characters
// of the input string reversed.
function reverseString (str) {
var strReversed = '',
lastCharIndex = str.length - 1,
i;
if (typeof str !== 'string') {
throw {
'name': 'TypeError',
'message': 'Function requires a ' +
' single string argument.'};
}
for (i = lastCharIndex; i >= 0; i -= 1) {
strReversed += str[i];
}
return strReversed;
}
// Return a integer between
// 1 and 6 inclusive.
function throwDie () {
return 1 + Math.floor(Math.random() * 6);
}
// Concatenate cell values from
// an input range.
// Single quotes around concatenated
// elements are optional.
function concatRng(inputFromRng, concatStr,
addSingleQuotes) {
var cellValues;
if (addSingleQuotes) {
cellValues =
inputFromRng.map(
function (element) {
return "'" + element + "'";
});
return cellValues.join(concatStr);
}
return inputFromRng.join(concatStr);
}
// Print stockInfo object property
// names to the logger.
function printFinanceAppKeys() {
stockSymbol = 'GOOG';
Logger.log(Object.keys(
FinanceApp.getStockInfo(
stockSymbol))
.sort()
.join('\n'));
}
// Given a stock symbol, return the
// stock price (NYSE).
function getStockPrice(stockSymbol) {
return FinanceApp
.getStockInfo(stockSymbol)['price'];
}
// Given a stock symbol, return the
// full stock name.
function getStockName(stockSymbol) {
return FinanceApp
.getStockInfo(stockSymbol)['name'];
}
// Chapter 4
// Function to demonstrate the Spreadsheet
// object hierarchy.
// All the variables are gathered in a
// JavaScript array.
// At each iteration of the for loop the
// "toString()" method
// is called for each variable and its
// output is printed to the log.
function showGoogleSpreadsheetHierarchy() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getActiveSheet(),
rng = ss.getRange('A1:C10'),
innerRng = rng.getCell(3, 3),
innerRngAddress = innerRng.getA1Notation(),
column = innerRngAddress.slice(0,1),
googleObjects = [ss, sh, rng, innerRng,
innerRngAddress, column],
i;
for (i = 0; i < googleObjects.length; i += 1) {
Logger.log(googleObjects[i].toString());
}
}
// Print the column letter of the third row and
// third column of the range "A1:C10"
// of the active sheet in the active
// spreadsheet.
// This is for demonstration purposes only!
function getColumnLetter () {
Logger.log(
SpreadsheetApp.getActiveSpreadsheet()
.getActiveSheet().getRange('A1:C10')
.getCell(3, 3).getA1Notation()
.slice(0,1));
}
// Extract an array of all the property names
// defined for Spreadsheet and write them to
// column A of the active sheet in the active
// spreadsheet.
function testSpreadsheet () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getActiveSheet(),
i,
spreadsheetProperties = [],
outputRngStart = sh.getRange('A2');
sh.getRange('A1')
.setValue('spreadsheet_properties');
sh.getRange('A1')
.setFontWeight('bold');
spreadsheetProperties =
Object.keys(ss).sort();
for (i = 0;
i < spreadsheetProperties.length;
i += 1) {
outputRngStart.offset(i, 0)
.setValue(spreadsheetProperties[i]);
}
}
// Extract, an array of properties from a
// Sheet object.
// Sort the array alphabetically using the
// Array sort() method.
// Use the Array join() method to a create
// a string of all the Sheet properties
// separated by a new line.
function printSheetProperties () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getActiveSheet();
Logger.log(Object.keys(sh)
.sort().join('\n'));
}
// Call function listSheets() passing it the
// Spreadsheet object for the active
// spreadsheet.
// The try - catch construct handles the
// error thrown by listSheets() if the given
// argument is absent or something
// other than a Spreadsheet object.
function test_listSheets () {
var ss =
SpreadsheetApp.getActiveSpreadsheet();
try {
listSheets(ss);
} catch (error) {
Logger.log(error.message);
}
}
// Given a Spreadsheet object,
// print the names of its sheets
// to the logger.
// Throw an error if the argument
// is missing or if it is not
// of type Spreadsheet.
function listSheets (spreadsheet) {
var sheets,
i;
if (spreadsheet.toString()
!== 'Spreadsheet') {
throw {
'name': 'TypeError',
'message': 'Function "listSheets()" '
'requires ' +
'a single argument of ' +
'type "Spreadsheet".'};
}
sheets = spreadsheet.getSheets();
for (i = 0;
i < sheets.length; i += 1) {
Logger.log(sheets[i].getName());
}
}
// Create a Spreadsheet object and call
// "sheetExists()" for an array of sheet
// names to see if they exist in
// the given spreadsheet.
// Print the output to the log.
function test_sheetExists () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetNames = ['Sheet1',
'sheet1',
'Sheet2',
'SheetX'],
i;
for (i = 0;
i < sheetNames.length;
i +=1) {
Logger.log('Sheet Name ' +
sheetNames[i] +
' exists: ' +
sheetExists(ss,
sheetNames[i]));
}
}
// Given a Spreadsheet object and a sheet name,
// check for two arguments of the correct type.
// Return "true" if the given sheet name exists
// in the given Spreadsheet,
// else return "false".
function sheetExists(spreadsheet, sheetName) {
var sheet;
if (spreadsheet.toString() !==
'Spreadsheet') {
throw {
'name': 'TypeError',
'message': 'Function "sheetExists()" ' +
'first argument for ' +
'"spreadsheet" is ' +
'not type "Spreadsheet".'};
}
if (typeof sheetName !== 'string') {
throw {
'name': 'TypeError',
'message': 'Function "sheetExists()" ' +
'second argument ' +
'for "sheetName" ' +
'is not type string.'};
}
if (spreadsheet.getSheetByName(sheetName)) {
return true;
} else {
return false;
}
}
// Copy the first sheet of the active
// spreadsheet to a newly created
// spreadsheet.
function copySheetToSpreadsheet () {
var ssSource =
SpreadsheetApp.getActiveSpreadsheet(),
ssTarget =
SpreadsheetApp.create(
'CopySheetTest'),
sourceSpreadsheetName =
ssSource.getName(),
targetSpreadsheetName =
ssTarget.getName();
Logger.log(
'Copying the first sheet from ' +
sourceSpreadsheetName +
' to ' + targetSpreadsheetName);
// [0] extracts the first Sheet object
// from the array created by
// method call "getSheets()"
ssSource.getSheets()[0].copyTo(ssTarget);
}
// Create a Sheet object and pass it
// as an argument to getSheetSummary().
// Print the return value to the log.
function test_getSheetSummary () {
var sheet = SpreadsheetApp
.getActiveSpreadsheet()
.getSheets()[0];
Logger.log(getSheetSummary(sheet));
}
// Given a Sheet object as an argument,
// use Sheet methods to extract
// information about it.
// Collect this information into an object
// literal and return the object literal.
function getSheetSummary (sheet) {
var sheetReport = {};
if (sheet.toString() !== 'Sheet') {
throw {
'name': 'TypeError',
'message': 'Function "getSheetReport()" ' +
'requires a single ' +
'argument of type "Sheet".'};
}
sheetReport['Sheet Name'] =
sheet.getName();
sheetReport['Used Row Count'] =
sheet.getLastRow();
sheetReport['Used Column count'] =
sheet.getLastColumn();
sheetReport['Used Range Address'] =
'A1:' +
sheet.getRange(sheet.getLastRow(),
sheet.getLastColumn()).getA1Notation();
return sheetReport;
}
// Chapter 5
// Select a number of cells in a spreadsheet and
// then execute the following function.
// The address of the selected range, that is the
// active range, is written to the log.
function activeRangeFromSpreadsheetApp () {
var activeRange =
SpreadsheetApp.getActiveRange();
Logger.log(activeRange.getA1Notation());
}
// Get the active cell and print its containing
// sheet name and address to the log.
// Try re-running after adding a new sheet
// and selecting a cell at random.
function activeCellFromSheet () {
var activeSpreadsheet =
SpreadsheetApp.getActiveSpreadsheet(),
activeCell =
activeSpreadsheet.getActiveCell(),
activeCellSheetName =
activeCell.getSheet().getSheetName(),
activeCellAddress =
activeCell.getA1Notation();
Logger.log('The active cell is in sheet: ' +
activeCellSheetName);
Logger.log('The active cell address is: ' +
activeCellAddress);
}
// Print Range object properties
// (all are methods) to log.
function printRangeMethods () {
var rng =
SpreadsheetApp.getActiveRange();
Logger.log(Object.keys(rng)
.sort().join('\n'));
}
// Creating a Range object using two different
// overloaded versions of the Sheet
// "getRange()" method.
// "getSheets()[0]" gets the first sheet of the
// array of Sheet objects returned by
// "getSheets()".
// Both calls to "getRange()" return a Range
// object representing the same range address
// (A1:B10).
function getRangeObject () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheets()[0],
rngByAddress = sh.getRange('A1:B10'),
rngByRowColNums =
sh.getRange(1, 1, 10, 2);
Logger.log(rngByAddress.getA1Notation());
Logger.log(
rngByRowColNums.getA1Notation());
}
// Set a number of properties for a range.
// Add a new sheet.
// Set various properties for the cell
// A1 of the new sheet.
function setRangeA1Properties() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
newSheet,
rngA1;
newSheet = ss.insertSheet();
rngA1 = newSheet.getRange('A1');
rngA1.setComment(
'Hold The date returned by spreadsheet '
+ ' function "TODAY()"');
rngA1.setFormula('=TODAY()');
rngA1.setBackgroundColor('black');
rngA1.setFontColor('white');
rngA1.setFontWeight('bold');
}
// Demonstrate get methods for 'Range'
// properties.
// Assumes function "setRangeA1Properties()
// has been run.
// Prints the properties to the log.
// Demo purposes only!
function printA1PropertiesToLog () {
var rngA1 =
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('RangeTest').getRange('A1');
Logger.log(rngA1.getComment());
Logger.log(rngA1.getFormula());
Logger.log(rngA1.getBackground());
Logger.log(rngA1.getFontColor());
Logger.log(rngA1.getFontWeight());
}
// Starting with cell C10 of the active sheet,
// add comments to each of its adjoining cells
// stating the row and column offsets needed
// to reference the commented cell
// from cell C10.
function rangeOffsetDemo () {
var rng =
SpreadsheetApp.getActiveSheet()
.getRange('C10');
rng.setBackground('red');
rng.setValue('Method offset()');
rng.offset(-1,-1)
.setComment('Offset -1, -1 from cell '
+ rng.getA1Notation());
rng.offset(-1,0)
.setComment('Offset -1, 0 from cell '
+ rng.getA1Notation());
rng.offset(-1,1)
.setComment('Offset -1, 1 from cell '
+ rng.getA1Notation());
rng.offset(0,1)
.setComment('Offset 0, 1 from cell '
+ rng.getA1Notation());
rng.offset(1,0)
.setComment('Offset 1, 0 from cell '
+ rng.getA1Notation());
rng.offset(0,1)
.setComment('Offset 0, 1 from cell '
+ rng.getA1Notation());
rng.offset(1,1)
.setComment('Offset 1, 1 from cell '
+ rng.getA1Notation());
rng.offset(0,-1)
.setComment('Offset 0, -1 from cell '
+ rng.getA1Notation());
rng.offset(1,-1)
.setComment('Offset -1, -1 from cell '
+ rng.getA1Notation());
}
// Passing a deliberately "bad" argument to the
// Range offset() method.
// The row offset argument is -1 but
// there is no row above row 1
// (cell A1's row).
// Google Apps Script gives error:
// "It looks like someone else
// already deleted this cell."
function offsetError () {
var rng =
SpreadsheetApp.getActiveSpreadsheet()
.getActiveSheet()
.getRange('A1');
rng.offset(-1,0)
.setValue('bad offset argument.');
}
function offsetError () {
var rng =
SpreadsheetApp.getActiveSpreadsheet()
.getActiveSheet().getRange('A1');
Logger.log(rng.offset(-1,0).getValue());
}
// See the Sheet method getDataRange() in action.
// Print the range address of the used range for
// a sheet to the log.
function getDataRange () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetName = 'english_premier_league',
sh = ss.getSheetByName(sheetName),
dataRange = sh.getDataRange();
Logger.log(dataRange.getA1Notation());
}
// Read the entire data range of a sheet
// into a JavaScript array.
// Uses the JavaScript Array.isArray()
// method twice to verify that method
// getValues()returns an array-of-arrays.
// Print the number of array elements
// corresponding to the number of data
// range rows.
// Extract and print the first 10
// elements of the array using the
// array slice() method.
function dataRangeToArray () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetName = 'english_premier_league',
sh = ss.getSheetByName(sheetName),
dataRange = sh.getDataRange(),
dataRangeValues = dataRange.getValues();
Logger.log(Array.isArray(dataRangeValues));
Logger.log(Array.isArray(dataRangeValues[0]));
Logger.log(dataRangeValues.length);
Logger.log(dataRangeValues.slice(0, 10));
}
// Loop over the array returned by
// getRange() and a CSV-type output
// to the log using array join() method.
function loopOverArray () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetName = 'english_premier_league',
sh = ss.getSheetByName(sheetName),
dataRange = sh.getDataRange(),
dataRangeValues =
dataRange.getValues(),
i;
for ( i = 0;
i < dataRangeValues.length;
i += 1 ) {
Logger.log(
dataRangeValues[i].join(','));
}
}
// In production code, this function would be
// re-factored into smaller functions.
// Read the data range into a JavaScript array.
// Remove and store the header line using the
// array shift() method.
// Use the array filter() method with an anonymous
// function as a callback to implement the
// filtering logic.
// Determine the element count of the
// filter() output array.
// Add a new sheet and store a reference to it.
// Create a Range object from the new
// Sheet objectusing the getRange() method.
// The four arguments given to getRange() are:
// (1) first column, (2) first row,
// (3) last row, and (4) last column.
// This creates a range corresponding to
// range address "A1:C5".
// Write the values of the filtered array to the
// newly created range.
function writeFilteredArrayToRange () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetName = 'english_premier_league',
sh = ss.getSheetByName(sheetName),
dataRange = sh.getDataRange(),
dataRangeValues = dataRange.getValues(),
filteredArray,
header = dataRangeValues.shift(),
filteredArray,
filteredArrayColCount = 3,
filteredArrayRowCount,
newSheet,
outputRange;
filteredArray = dataRangeValues.filter(
function (innerArray) {
if (innerArray[2] >= 40) {
return innerArray;
}});
filteredArray.unshift(header);
filteredArrayRowCount = filteredArray.length;
newSheet = ss.insertSheet();
outputRange = newSheet
.getRange(1,
1,
filteredArrayRowCount,
filteredArrayColCount);
outputRange.setValues(filteredArray);
}
function setRangeName () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getActiveSheet(),
rng = sh.getRange('A1:B10'),
rngName 'MyData';
ss.setNamedRange(rngName, rng);
}
// Create a range object using the
// getDataRange() method.
// Pass the range and a colour name
// to function "setAlternateRowsColor()".
// Try changing the 'color' variable to
// something like:
// 'red', 'green', 'yellow', 'gray', etc.
function call_setAlternateRowsColor () {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetName = 'english_premier_league',
sh = ss.getSheetByName(sheetName),
dataRange = sh.getDataRange(),
color = 'grey';
setAlternateRowsColor(dataRange, color);
}
// Set every second row in a given range to
// the given colour.
// Check for two arguments:
// 1: Range, 2: string for colour.
// Throw a type error if either argument
// is missing or of the wrong type.
// Use the Range offset() to loop
// over the range rows.
// the for loop counter starts at 0.
// It is tested in each iteration with the
// modulus operator (%).
// If i is an odd number, the if condition
// evaluates to true and the colour
// change is applied.
// WARNING: If a non-existent colour is given,
// then the "color" is set to undefined
(no color). NO error is thrown!
function setAlternateRowsColor (range,
color) {
if (range.toString()
!== 'Range') {
throw {'name': 'TypeError',
'message':
'The first argument to ' +
'"setAlternateRowsColor()" ' +
' must be type Range'};
}
if (typeof color !== 'string') {
throw {'name': 'TypeError',
'message':
'The second argument to ' +
' "setAlternateRowsColor()" ' +
' must be a string for a color,' +
' e.g. "red"'};
}
var i,
startCell = range.getCell(1,1),
columnCount = range.getLastColumn(),
lastRow = range.getLastRow();
for (i = 0; i < lastRow; i += 1) {
if (i % 2) {
startCell.offset(i, 0, 1, columnCount)
.setBackgroundColor(color);
}
}
}
// Test function for
// "deleteLeadingTrailingSpaces()".
// Creates a Range object and passes
// it to this function.
function call_deleteLeadingTrailingSpaces() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetName = 'english_premier_league',
sh = ss.getSheetByName(sheetName),
dataRange = sh.getDataRange();
deleteLeadingTrailingSpaces(dataRange);
}
// Process each cell in the given range.
// If the cell is of type text
// (typeof === 'string') then
// remove leading and trailing white space.
// Else ignore it.
// Code note: The Range getCell() method
// takes two 1-based indexes
// (row and column).
// This is in contrast to the offset() method.
// rng.getCell(0,0) will throw an error!
function deleteLeadingTrailingSpaces(range) {
if (range.toString() !== 'Range') {
throw {'name': 'TypeError',
'message':
'Argument to ' +
'"deleteLeadingTrailingSpaces()" ' +
'must be type Range'};
}
var i,
j,
lastCol = range.getLastColumn(),
lastRow = range.getLastRow(),
cell,
cellValue;
for (i = 1; i <= lastRow; i += 1) {
for (j = 1; j <= lastCol; j += 1) {
cell = range.getCell(i,j);
cellValue = cell.getValue();
if (typeof cellValue === 'string') {
cellValue = cellValue.trim();
cell.setValue(cellValue);
}
}
}
}
// Create a Sheet object for the active sheet.
// Pass the sheet object to
// "getAllDataRangeFormulas()"
// Create an array of the keys in the returned
// object in default "sort()".
// Loop over the array of sorted keys and
// extract the values they keys map to.
// Write the output to the log.
function call_getAllDataRangeFormulas() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheet = ss.getActiveSheet(),
sheetFormulas = getAllDataRangeFormulas(sheet),
formulaLocations =
Object.keys(sheetFormulas).sort(),
formulaCount = formulaLocations.length,
i;
for (i = 0; i < formulaCount; i += 1) {
Logger.log(formulaLocations[i] +
' contains ' +
sheetFormulas[formulaLocations[i]]);
}
}
// Take a Sheet object as an argument,
// throw an error if the given argument
// is of the wrong type.
// Return an object literal where formula
// locations map to formulas for all formulas
// in the input sheet data range.
// Loop through every cell in the data range.
// If a cell has a formula,
// store that cells location as
// the key and its formula as the value
// in the object literal.
// Return the populated object literal.
function getAllDataRangeFormulas(sheet) {
if (sheet.toString() !== 'Sheet') {
throw {'name': 'TypeError',
'message':
'Function "getAllDataRangeFormulas()" ' +
' expects a single argument of ' +
' type Sheet.'};
}
var dataRange = sheet.getDataRange(),
i,
j,
lastCol = dataRange.getLastColumn(),
lastRow = dataRange.getLastRow(),
cell,
cellFormula,
formulasLocations = {},
sheetName = sheet.getSheetName(),
cellAddress;
for (i = 1; i <= lastRow; i += 1) {
for (j = 1; j <= lastCol; j += 1) {
cell = dataRange.getCell(i,j);
cellFormula = cell.getFormula();
if (cellFormula) {
cellAddress = sheetName + '!' +
cell.getA1Notation();
formulasLocations[cellAddress] =
cellFormula;
}
}
}
return formulasLocations;
}
// Call copyColumns() function passing it:
// 1: The active sheet
// 2: A newly inserted sheet
// 3: An array of column indexes to copy
// to the new sheet
// The output in the newly inserted sheet
// contains the columns for the indexes
// given in the array in the
// order specified in the array.
function call_copyColumns() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
inputSheet = ss.getActiveSheet(),
outputSheet = ss.insertSheet(),
columnIndexes = [4,3,2,1];
copyColumns(inputSheet,
outputSheet,
columnIndexes);
}
// Given an input sheet, an output sheet,
// and an array:
// Use the numeric column indexes in
// the array to copy those columns from
// the input sheet to the output sheet.
// The function checks its input arguments
// and throws an error
// if they are not Sheet, Sheet, Array.
// The array is expected to be an array of
// integers but it does
// not check the array element types
function copyColumns(inputSheet,
outputSheet,
columnIndexes) {
if (! (inputSheet.toString() ===
'Sheet'
&&
outputSheet.toString() === 'Sheet') ) {
throw {'name': 'TypeError',
'message': 'Function ' + '
"copyColumns()": ' +
'First two arguments must ' +
' be Sheet objects'};
}
if (! Array.isArray(columnIndexes)) {
throw {'name': 'TypeError',
'message': 'Function ' +
'"copyColumns()": ' +
'Third argument has to be ' +
' an array of indexes'};
}
var dataRangeRowCount =
inputSheet.getDataRange()
.getNumRows(),
columnsToCopyCount =
columnIndexes.length,
i,
columnIndexesCount,
valuesToCopy = [];
for (i = 0;
i < columnsToCopyCount;
i += 1) {
valuesToCopy =
inputSheet
.getRange(1,
columnIndexes[i],
dataRangeRowCount,
1).getValues();
outputSheet
.getRange(1,
i+1,
dataRangeRowCount,
1).setValues(valuesToCopy);
}
}
// Chapter 6
// Test connection to a MySQ
// cloud instance created earlier.
// Check log for output.
function connectMySqlCloud() {
var connStr =
'jdbc:google:rdbms://' +
'elwarbito:chapter6/contacts',
conn;
try {
conn =
Jdbc.getCloudSqlConnection(connStr);
Logger.log('Connection OK!');
} catch (err) {
Logger.log(err);
throw err;
} finally {
if (conn) {
conn.close();
}
}
}
// Execute a CREATE TABLE DDL statement for a
// database named "contacts".
function createTable() {
var connStr =
'jdbc:google:rdbms://' +
'elwarbito:chapter6/contacts',
conn,
stmt,
ddl;
ddl = 'CREATE TABLE person(' +
' person_id MEDIUMINT ' +
'AUTO_INCREMENT' +
' NOT NULL PRIMARY KEY,' +
' first_name VARCHAR(100) NOT NULL,' +
' last_name VARCHAR(100) NOT NULL,' +
' date_of_birth DATE,' +
' height_cm SMALLINT)';
try {
conn =
Jdbc.getCloudSqlConnection(connStr);
stmt = conn.createStatement();
stmt.execute(ddl);
Logger.log('Table created!');
} catch (ex) {
Logger.log(ex);
throw(ex);
} finally {
Logger.log('Cleaning up.');
if (stmt) {
stmt.close();
}
if (conn) {
conn.close();
}
}
}
// Add 6 rows to newly created table.
// Data source is a JavaScript array-of-arrays.
// Uses bind parameters.
// Executes an SQL INSERT INTO statement
// within a for loop.
function addRowsToTable() {
var connStr = 'jdbc:google:rdbms://' +
'elwarbito:chapter6/contacts',
conn,
dml,
prepStmt,
rows,
i,
row,
firstName,
lastName,
dateOfBirth,
heightcm;
dml = 'INSERT INTO person(first_name, ' +
'last_name, ' +
'date_of_birth, ' +
'height_cm) ' +
'VALUES(?, ?, ?, ?)';
rows = [['Joe', 'Grey', '1970-06-11', 182],
['Raj', 'Patel', '1975-03-13', 188],
['Amy', 'Lopez', '1972-08-17', 166],
['Bill', 'Grimes', '1954-10-20', 181],
['Jane', 'Rice', '1961-04-30', 170],
['Alex', 'Lee', '1982-08-06', 190]
];
try {
conn =
Jdbc.getCloudSqlConnection(connStr);
prepStmt = conn.prepareStatement(dml);
for (i = 0; i < rows.length; i += 1) {
row = rows[i];
firstName = row[0];
lastName = row[1];
dateOfBirth = row[2];
heightcm = row[3];
prepStmt.setString(1, firstName);
prepStmt.setString(2, lastName);
prepStmt.setString(3, dateOfBirth);
prepStmt.setInt(4, heightcm);
prepStmt.execute();
}
Logger.log('Loaded row count: ' + i);
} catch(ex) {
Logger.log(ex);
throw(ex);
} finally {
if (prepStmt) {
prepStmt.close();
}
if (conn) {
conn.close();
}
}
}
// Retrieve all rows from a table and
// write the to a newly added sheet.
// If re-running this code, ensure
// that added sheet is deleted
// or re-named.
function writeDatabasRowsToSpreadsheet() {
var connStr = 'jdbc:google:rdbms://' +
'elwarbito:chapter6/contacts',
conn,
sql = 'SELECT * FROM person',
stmt,
rs,
colCount,
colVal,
rowVals = [],
i,
ss = SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.insertSheet();
sh.setName('QueryResults');
try {
conn =
Jdbc.getCloudSqlConnection(connStr);
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
colCount = rs.getMetaData()
.getColumnCount();
Logger.log('Col count: ' + colCount);
while (rs.next()) {
for (i = 1; i <= colCount; i += 1) {
colVal = rs.getString(i);
rowVals.push(colVal);
}
sh.appendRow(rowVals);
rowVals = [];
}
} catch(ex) {
Logger.log(ex);
throw(ex);
} finally {
if (rs) {
rs.close();
}
if (stmt) {
stmt.close()
};
if (conn) {
conn.close();
}
}
}
// Execute the MySQL "SHOW TABLES"
// statement and print the table
// names in the target database
// to the log.
// Exception handling is missing!
function showTables() {
var connStr =
'jdbc:google:rdbms://' +
'elwarbito:chapter6/contacts',
conn,
stmt,
rs,
sql;
sql = 'SHOW TABLES';
conn =
Jdbc.getCloudSqlConnection(connStr);
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while (rs.next()) {
Logger.log(rs.getString(1));
}
rs.close();
stmt.close();
conn.close();
}
// Print some metadata about the database created
// in earlier examples.
// Adds a sheet named "databaseMetadata".
// If re-running, remove sheet added previously.
// Exception handling dropped.
function writeMySQLMetadataToSheet() {
var connStr = 'jdbc:google:rdbms://' +
'elwarbito:chapter6/contacts',
dbMetadata,
rsTables,
rsColumns,
tableNames = [],
i,
tableCount,
ss,
sh;
ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.insertSheet()
conn =
Jdbc.getCloudSqlConnection(connStr);
dbMetadata = conn.getMetaData();
sh.setName('DatabaseMetadata');
sh.appendRow(['Major Version',
dbMetadata.getDatabaseMajorVersion()]);
sh.appendRow(['Minor Version',
dbMetadata.getDatabaseMinorVersion()]);
sh.appendRow(['Product Name',
dbMetadata.getDatabaseProductName()]);
sh.appendRow(['Product Version',
dbMetadata.getDatabaseProductVersion()]);
sh.appendRow(['Supports transactions',
dbMetadata.supportsTransactions()]);
rsTables = dbMetadata.getTables(
null, null, null, ['TABLE']);
while (rsTables.next()) {
tableNames.push(rsTables.getString(3));
}
tableCount = tableNames.length;
sh.appendRow(
['Table Names And Columns Names Are:']);
for (i = 0; i < tableCount; i += 1) {
rsColumns = dbMetadata.getColumns(
null, null, tableNames[i], null);
while (rsColumns.next()) {
sh.appendRow(
[tableNames[i], rsColumns.getString(4)]);
}
}
rsTables.close();
rsColumns.close();
conn.close();
}
/*
-- SQL for GAS that follows:
SELECT
tab.table_name,
tab.engine,
tab.table_rows,
col.column_name,
col.column_type
FROM
INFORMATION_SCHEMA.TABLES AS tab
JOIN INFORMATION_SCHEMA.COLUMNS AS col
ON tab.table_name = col.table_name
WHERE
tab.table_schema = ?
AND
tab.table_type = 'BASE TABLE';
*/
// Driver function for "getDocText()"
function test_getDocText() {
// Replace with your doc ID.
var docID = ;
Logger.log(getDocText(docID));
}
// Given a Document ID return
// its text as a JavaScript string.
// Requires "Authorization" to run.
function getDocText(docID) {
var txt;
try {
doc = DocumentApp.openById(docID);
txt = doc.getText();
return txt;
} catch (ex) {
Logger.log('Error in "getSql()": ' + ex);
throw(ex);
}
}
// Read in an SQL file as text.
// Connect to the MySQL instance containing the
// database of interest.
// Pass in a database name to bind parameter and
// generate a RecordSet.
// Add a sheet to the active spreadsheet with a
// user-specified name
// Process the RecordSet and write the output to
// the newly added sheet.
// Lacks argument checking and
// exception handling!
function writeMySqlDBSummaryToSheet(sqlFileId,
dbName,
sheetName) {
var connStr = 'jdbc:google:rdbms://' +
'elwarbito:chapter6/contacts',
conn,
sql,
prepStmt,
recSet,
ss,
sh,
colCount,
colNames = [],
i,
rowVals = [];
ss = SpreadsheetApp.getActiveSpreadsheet();
sh = ss.insertSheet();
sh.setName(sheetName);
// Read in the SQL file contents to a string.
sql = getDocText(sqlFileId);
conn =
Jdbc.getCloudSqlConnection(connStr);
prepStmt = conn.prepareStatement(sql);
// Set the bind parameter to the database name.
prepStmt.setString(1, dbName);
recSet = prepStmt.executeQuery();
colCount = recSet.getMetaData()
.getColumnCount();
// Get Column Names.
for (i = 1; i <= colCount; i += 1) {
colNames.push(recSet.getMetaData()
.getColumnName(i))
}
// Write column names to first row of new sheet.
sh.appendRow(colNames);
// Get column values from RecordSet.
while (recSet.next()) {
for (i = 1; i <= colCount; i += 1) {
rowVals.push(recSet.getString(i));
}
sh.appendRow(rowVals);
rowVals = [];
}
prepStmt.close();
conn.close();
}
// Driver function for
// "writeMySqlDBSummaryToSheet()"
function test_writeMySqlDBSummaryToSheet() {
// Replace with your doc ID.
var sqlFileId = '',
dbName = 'contacts',
sheetName = 'DBSummary';
writeMySqlDBSummaryToSheet(sqlFileId,
dbName,
sheetName);
}
// Chapter 7
// Pre-defined function that runs as a
// "trigger" when the spreadsheet is opened.
// Here it is set to build the menu.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
menuItems;
menuItems = [{name: 'Calculate BMI',
functionName: 'calculateBmi'}];
ss.addMenu('Custom Menu', menuItems);
}
// Displays two input box prompts:
// First for weight in kilograms
// Second for height in meters
// Displays result of calculation in a
// message box.
function calculateBmi() {
var bmiTitle = 'BMI Calculation',
massPrompt = 'Enter weight in Kg:',
bmiButtons = Browser.Buttons.OK_CANCEL,
inputMass,
heightPrompt = 'Enter height in meters:',
inputHeight,
msgTitle = 'BMI Calculation',
msgPrompt = 'BMI is: ',
bmiResult;
try {
inputMass = Browser.inputBox(bmiTitle,
massPrompt,
bmiButtons);
if (inputMass === 'cancel') {
return;
}
inputHeight = Browser.inputBox(bmiTitle,
heightPrompt,
bmiButtons);
if (inputHeight === 'cancel') {
return;
}
bmiResult = getBmiMetric(
parseFloat(inputMass, 10),
parseFloat(inputHeight, 10));
Browser.msgBox(Number(bmiResult).toFixed(2));
}
catch (ex) {
Browser.msgBox('Error: ' +
ex.name + ': ' +
ex.message);
}
}
// Performs Body-Mass Index (BMI) calculation.
// Requires two numeric arguments:
// 1: Weight in kilograms
// 2: Height in meters
// Can be called as a spreadsheet function:
// cell formula example
// "=getBmiMetric(90, 1.90)"
function getBmiMetric(massKg, heightM) {
Logger.log(massKg);
if (! (typeof massKg === 'number'
&& typeof heightM === 'number')) {
throw {'name': 'TypeError',
'message': 'Function requires ' +
'weight in Kg and ' +
'height in meters'};
}
return (massKg/(heightM * heightM));
}
// 7.3.1 First Form
// Menu is created and added when the containing
// spreadsheet is opened.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
menuItems;
menuItems = [{name: 'Show Form',
functionName: 'guiExample1'}];
ss.addMenu('Custom Menu', menuItems);
}
// Close the GUI
function close() {
var ui = UiApp.getActiveApplication();
return ui.close();
}
// Get the active user name.
// Write the active user name as text in a label
// widget on the form.
function displayUser() {
var ui = UiApp.getActiveApplication(),
user = Session.getActiveUser(),
lblUser = ui.getElementById('lblUser_ID');
lblUser.setText(user);
return ui;
}
// Create a simple GUI form with
// two buttons and one label.
// Uses default sizes and layouts
function guiExample1() {
var ui = UiApp.createApplication(),
ss = SpreadsheetApp.getActiveSpreadsheet(),
lblUser = ui.createLabel(''),
btnUser = ui.createButton('User'),
btnClose = ui.createButton('Close'),
closeFunction = 'close',
closeHandler =
ui.createServerHandler(closeFunction),
userFunction = 'displayUser',
userHandler =
ui.createServerHandler(userFunction);
lblUser.setId('lblUser_ID');
ui.setTitle('Display User ID');
btnUser.addClickHandler(userHandler);
btnClose.addClickHandler(closeHandler);
ui.add(lblUser);
ui.add(btnUser);
ui.add(btnClose);
ss.show(ui);
}
// Simple data entry form GUI.
// Contains paired labels and text boxes
// Uses panels as widget containers to
// get desired layout.
// To run add use the "onOpen()" trigger or
// execute it from the Script Editor.
function guiExample2() {
var ui = UiApp.createApplication(),
ss = SpreadsheetApp.getActiveSpreadsheet(),
pnlMain = ui.createVerticalPanel(),
pnlName = ui.createHorizontalPanel(),
pnlEmail = ui.createHorizontalPanel(),
pnlBtns = ui.createHorizontalPanel(),
lblName = ui.createLabel('Name: '),
txtName = ui.createTextBox(),
lblEmail = ui.createLabel('Email: '),
txtEmail = ui.createTextBox(),
btnAddRecord =
ui.createButton('Add Record'),
btnClose = ui.createButton('Close');
ui.setTitle('Data Entry Form');
ui.setHeight(80);
ui.setWidth(200);
btnClose.setWidth(90);
btnAddRecord.setWidth(90);
txtName.setWidth(150);
txtEmail.setWidth(150);
ui.add(pnlMain);
pnlName.add(lblName);
pnlName.add(txtName);
pnlMain.add(pnlName);
pnlEmail.add(lblEmail);
pnlEmail.add(txtEmail);
pnlMain.add(pnlEmail);
pnlBtns.add(btnAddRecord);
pnlBtns.add(btnClose);
pnlMain.add(pnlBtns);
ss.show(ui);
}
// Close the current UI
function close() {
var ui = UiApp.getActiveApplication();
return ui.close();
}
// Callback action for button labelled "Add Row"
// Take the values from two text boxes in the
// active GUI and add them as rows to the
// active sheet.
// Prepare for next input by:
// re-setting the text boxes to empty strings
// Set the focus to the first text box
function addRow(e) {
var ui = UiApp.getActiveApplication(),
sheet =
SpreadsheetApp.getActiveSheet(),
name = e.parameter.txtName_Name,
email = e.parameter.txtEmail_Name,
txtName =
ui.getElementById('txtName_Id'),
txtEmail =
ui.getElementById('txtEmail_Id'),
activeUser = Session.getActiveUser();
sheet.appendRow([name, email, activeUser]);
txtName.setValue('');
txtEmail.setValue('');
txtName.setFocus(true);
return ui;
}
// Build a GUI with two labels, two text
// boxes and two buttons.
// Layout uses panels as in previous example.
function dataEntryForm() {
var ui = UiApp.createApplication(),
ss =
SpreadsheetApp.getActiveSpreadsheet(),
uiTitle = 'Data Entry Form',
pnlMain = ui.createVerticalPanel(),
pnlName = ui.createHorizontalPanel(),
pnlEmail = ui.createHorizontalPanel(),
pnlButtons = ui.createHorizontalPanel(),
lblName = ui.createLabel('Name:'),
lblEmail = ui.createLabel('Email:'),
txtName = ui.createTextBox(),
txtEmail = ui.createTextBox(),
btnAddRow =
ui.createButton('Add Record'),
btnExit = ui.createButton('Close'),
exitHandler =
ui.createServerHandler('close'),
addRowHandler =
ui.createServerHandler('addRow');
pnlName.add(lblName);
pnlName.add(txtName);
pnlEmail.add(lblEmail);
pnlEmail.add(txtEmail);
pnlMain.add(pnlName);
pnlMain.add(pnlEmail);
pnlButtons.add(btnAddRow);
pnlButtons.add(btnExit);
pnlMain.add(pnlButtons);
ui.add(pnlMain);
ui.setWidth(200);
ui.setHeight(150);
btnExit.setWidth(80);
btnExit.addClickHandler(exitHandler);
btnAddRow.setWidth(80);
btnAddRow.addClickHandler(addRowHandler);
addRowHandler.addCallbackElement(txtName);
addRowHandler.addCallbackElement(txtEmail);
txtName.setName('txtName_Name');
txtEmail.setName('txtEmail_Name');
txtName.setId('txtName_Id');
txtEmail.setId('txtEmail_Id');
ui.setTitle(uiTitle);
txtName.setFocus(true);
ss.show(ui);
}
// Given a SpreadsheetApp instance
// as an argument:
// Return a list of sheet names.
function getSheetNames(ss) {
var sheets = ss.getSheets(),
sheetNames = [],
i;
for (i = 0; i < sheets.length; i += 1) {
sheetNames.push(sheets[i].getSheetName());
}
return sheetNames;
}
// Executes when the listbox selection
// is changed.
// Extracts the address of the selected
// sheet name
// data range (used range) and writes
// the address to a text box.
function writeSheetInfoToGui(e) {
var ui = UiApp.getActiveApplication(),
ss =
SpreadsheetApp.getActiveSpreadsheet(),
selectedSheetName =
e.parameter.lbxSheetNames_Name,
sheet,
dataRngAddress,
txtDataRng =
ui.getElementById('txtDataRng_Id');
// Avoid error if empty place-holder
// is selected.
if (selectedSheetName.length > 0) {
sheet =
ss.getSheetByName(selectedSheetName);
dataRngAddress =
sheet.getDataRange().getA1Notation();
txtDataRng.setValue(dataRngAddress);
} else {
txtDataRng.setValue('');
}
return ui; // NB always remember this line!
}
// Build a GUI to demonstrate list boxes.
// Sheet names of the active spreadsheet
// are added to the list box.
// When the selected sheet name in the
// list box is changed, the selected
// sheet data range is written to the
// text box.
// Shows how an application can respond
// dynamically to user interaction.
function spreadsheetInfo() {
var ui = UiApp.createApplication(),
ss =
SpreadsheetApp.getActiveSpreadsheet(),
uiTitle = 'Spreadsheet Info',
pnlMain = ui.createVerticalPanel(),
pnlSheetNames =
ui.createHorizontalPanel(),
pnlDataRng = ui.createHorizontalPanel(),
pnlRowCount = ui.createHorizontalPanel(),
pnlColCount = ui.createHorizontalPanel(),
lblDataRng =
ui.createLabel('Data Range Address'),
txtDataRng = ui.createTextBox(),
lblSheetNames =
ui.createLabel('Sheet Names:'),
lbxSheetNames = ui.createListBox(),
sheetNames = getSheetNames(ss),
i,
lbxHandler =
ui.createServerHandler(
'writeSheetInfoToGui');
lbxSheetNames.addChangeHandler(lbxHandler);
ui.add(pnlMain);
// Add an emty item to the list box
lbxSheetNames.addItem('');
// Add the sheet names to the list box
for (i = 0; i ,
file = DocsList.getFileById(id);
file.removeFromFolder(root);
}
// Remove a folder and its file contents
function deleteFolder() {
var root = DocsList.getRootFolder(),
folders = root.getFolders(),
i;
for (i = 0; i < folders.length; i += 1) {
if (folders[i].getName() === 'Test Folder') {
folders[i].setTrashed(true);
}
}
}
// Write properties of the Folder and
// File objects to separate newly-created
// sheets.
// Create a test folder and a test Google
// Spreadsheet.
// For the Spreadsheet, we want to treat it as
// a generic file for the purpose of retrieving
// File object properties.
// Call the function
// "writeObjectPropertiesToSheet()"
// twice passing it the Folder and File objects
// in turn with names for the sheets to where
// the object properties are written.
// Since this function creates a folder
// and a file,it requires authorisation.
function writePropertiesToSheets() {
var newFolder =
DocsList.createFolder("Test Folder"),
newSpreadsheet =
SpreadsheetApp.create('Test File'),
newSpreadsheetId =
newSpreadsheet.getId(),
newFile =
DocsList.getFileById(newSpreadsheetId),
folderPropsSheetName = 'FolderProperties',
filePropsSheetName = 'FileProperties';
writeObjectPropertiesToSheet(newFolder,
folderPropsSheetName);
writeObjectPropertiesToSheet(
newFile,
filePropsSheetName);
}
// Given any object and a string for a sheet
// name, insert a new sheet with the given
// name and extract all the properties from
// the object as a sorted array.
// Loop over the array and write the property
// names to the new sheet.
// Function checks for two arguments:
// 1: any type of object
// 2: A string for the new sheet name
function writeObjectPropertiesToSheet(obj,
sheetName) {
if (!(typeof obj === 'object' &&
typeof sheetName === 'string')) {
throw {'name': 'TypeError',
'message': 'Function expects ' +
'an object and a string.'};
}
var sh =
SpreadsheetApp.getActiveSpreadsheet()
.insertSheet(),
objProps = Object.keys(obj).sort(),
i;
sh.setName(sheetName);
for (i = 0; i < objProps.length; i += 1) {
sh.appendRow([objProps[i]]);
}
}
// Creates two files in "My Drive".
// (1) A spreadsheet and (2) A document.
// Records the name, ID and URL for the
// two new files in the active spreadsheet.
// Gives a range name to the two data rows.
// Script requires authorisation.
function createFiles() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getActiveSheet(),
newSsName = 'myspreadsheet',
newSs = SpreadsheetApp.create(newSsName),
newDocName = 'mydocument',
newDoc = DocumentApp.create(newDocName);
sh.appendRow(['File Name',
'File ID',
'File URL']);
sh.getRange(1, 1, 1, 3).setFontWeight('bold');
sh.appendRow([newSsName,
newSs.getId(),
newSs.getUrl()]);
sh.appendRow([newDocName,
newDoc.getId(),
newDoc.getUrl()]);
ss.setNamedRange('FileDetails',
sh.getRange(2, 1, 2, 3));
}
// Adds a viewer to the document created above.
// Uses the range name to access the file ID.
// Requires authorisation.
function addViewer() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
rngName = 'FileDetails',
inputRng = ss.getRangeByName(rngName),
docId = inputRng.getCell(2, 2).getValue(),
doc = DocsList.getFileById(docId),
newViewer =
'[email protected]';
doc.addViewer(newViewer);
}
// Adds an editor to the spreadshet whose ID
// is stored first row and second column of the
// named range
function addEditor() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
rngName = 'FileDetails',
inputRng = ss.getRangeByName(rngName),
ssToShareId =
inputRng.getCell(1, 2).getValue(),
ssToShare =
DocsList.getFileById(ssToShareId),
newEditor =
'[email protected]';
ssToShare.addEditor(newEditor);
}
// Create a new folder.
// Add the spreadsheet and document created
// earlier to this new folder.
// As in earlier examples, the file objects
// are retrieved using their IDs that
// were stored in the active spreadsheet.
// Remove them from the root folder.
function putFilesToShareInNewFolder() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
rootFolder = DocsList.getRootFolder(),
newFolder =
DocsList.createFolder('ToShareWithMick'),
rngName = 'FileDetails',
inputRng = ss.getRangeByName(rngName),
ssToShareId =
inputRng.getCell(1, 2).getValue(),
ssToShare =
DocsList.getFileById(ssToShareId),
docId = inputRng.getCell(2, 2).getValue(),
doc = DocsList.getFileById(docId);
ssToShare.addToFolder(newFolder);
doc.addToFolder(newFolder);
ssToShare.removeFromFolder(rootFolder);
doc.removeFromFolder(rootFolder);
}
// Add an editor to the new folder.
// The new folder is identified by its name.
// All folders are checked for the name
// (filter) and the first one with
// indicated name is returned.
// The folder ID is displayed in a messagebox
// for verification purposes only.
// An editor is added to the Folder object.
function shareFolderForEditing() {
var folders =
DocsList.getRootFolder().getFolders(),
folderName = 'ToShareWithMick',
folderToShare,
folderId,
collaborator =
'[email protected]';
folderToShare = folders.filter(
function (folder) {
return (folder.getName()
===
folderName);
})[0];
folderId = folderToShare.getId();
Browser.msgBox(folderId);
folderToShare.addEditor(collaborator);
}
// Given a Folder object and a sub-folder name,
// check to see if the sub-folder name exists
// in the given parent folder.
// Return true if it does, else return false
// Checks its arguments for a Folder object
// and a string.
function folderNameExists(parentFolder,
subfolderName) {
if (! (parentFolder.toString() ===
'Folder' &&
typeof subfolderName ===
'string') ) {
throw {'name': 'TypeError',
'message': 'Requires two ' +
'arguments: ' +
'Folder object and ' +
'String for folder name'};
}
var folderNames;
folderNames = parentFolder
.getFolders().map(
function (folder) {
return folder.getName();
});
Logger.log(folderNames);
if (folderNames
.indexOf(subfolderName) > -1) {
return true;
} else {
return false;
}
}
// Code to test "folderNameExists()"
// Change the value of folderName to existing
// and non-existent folder names to see
// how the tested function operates!
function test_folderNameExists() {
var folder = DocsList.getRootFolder(),
folderName = 'Javascript';
if (folderNameExists(folder, folderName)) {
Logger.log("yup");
} else {
Logger.log("Nope");
}
}
// Return an array of File objects
// for all files in the script user's
// Google Drive
function getAllFiles() {
return DocsList.getAllFiles();
}
// Filter all files based on a given cut-off date
// and return an array of files older than the
// cut-off date.
function getFilesOlderThan(cutoffDate) {
var filesOlderThan =
getAllFiles().filter(
function(file) {
return (file.getDateCreated()
<
cutoffDate)
});
return filesOlderThan;
}
// Write some file details for files older than
// a specified date to a new sheet.
function test_getFilesOlderThan() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
shName = 'OldFiles',
sh = ss.insertSheet(),
// 'July 28, 2010', months are 0-11 in JS
testDate = new Date(2010, 6, 28);
oldFiles = getFilesOlderThan(testDate);
sh.setName(shName);
oldFiles.forEach(
function (file) {
sh.appendRow([file.getName(),
file.getSize(),
file.getDateCreated()]);
});
}
// Given a file object, return number
// of days since its creation.
// Checks argument is type File.
function getFileAgeInDays(file) {
if (! file.toString() === 'File' ) {
throw {'name': 'TypeError',
'message': 'Argument must be ' +
'type File'};
}
var today = new Date(),
createdDate = file.getDateCreated(),
msecPerDay = 1000 * 60 * 60 * 24,
fileAgeInDays =
(today - createdDate)/msecPerDay;
return Math.round(
fileAgeInDays).toFixed(0);
}
// Get a test file ID from the URL
// and assign it to variable fileID
// Run and check the log
function test_getFileAgeInDays() {
var fileId = ,
file =
DocsList.getFileById(fileId),
fileAgeInDays =
getFileAgeInDays(file);
Logger.log('File ' +
file.getName() +
' is ' +
fileAgeInDays +
' days old.');
}
// Return an array of empty folder objects
// in the user's Google drive.
// An empty folder is one with no associated
// files or sub-folders.
function getEmptyFolders() {
var folders = DocsList.getAllFolders(),
emptyFolders = [];
emptyFolders =
folders.filter(
function (folder) {
return (
folder.getFiles().length === 0
&&
folder.getFolders().length === 0);
});
return emptyFolders;
}
// Write the IDs and names of
// all empty folders to the
// log.
function processEmptyFolders() {
var emptyFolders =
getEmptyFolders();
emptyFolders.forEach(
function (folder) {
Logger.log(folder.getName() +
': ' +
folder.getId());
});
}
// Return object mapping each
// file name to an array of file IDs.
// If file names are not duplicated,
// the arrays they map to will
// have a single element (file ID).
function getFilenameIdMap() {
var files = DocsList.getAllFiles(),
filenameIdMap = {},
i,
filename,
fileId;
for (i = 0; i < files.length; i += 1) {
filename = files[i].getName();
fileId = files[i].getId();
if (filename in filenameIdMap) {
filenameIdMap[filename]
.push(fileId);
} else {
filenameIdMap[filename] = [];
filenameIdMap[filename]
.push(fileId);
}
}
return filenameIdMap;
}
// Return an array of file IDs for files
// with duplicate names.
// Loops over the object returned by
// getFilenameIdMap() and returns
// only those file IDs for duplicate
// file names.
function getDuplicateFilenameIds() {
var filenameIdMap = getFilenameIdMap(),
filename,
duplicateFilenameIds = [];
for (filename in filenameIdMap) {
if (filenameIdMap[filename].length > 1) {
duplicateFilenameIds =
duplicateFilenameIds
.concat(filenameIdMap[filename]);
}
}
return duplicateFilenameIds;
}
// Add files with duplicated names to
// a newly created folder.
function addDuplicateFilesToFolder() {
var duplicateFilenameIds =
getDuplicateFilenameIds(),
folderName = 'DUPLICATE FILES',
folder =
DocsList.createFolder(folderName);
duplicateFilenameIds.forEach(
function (fileId) {
var file =
DocsList.getFileById(fileId);
file.addToFolder(folder);
});
}
// Chapter 9
// Return an array of cell values from a
// named range.
// The call to "map" is required because
// the array derived from the range is an
// array of arrays.
// For this example, the input range is only one
// column wide so only the first element of each
// array is needed.
function getEmailList() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
rngName = 'EmailContacts',
emailRng = ss.getRangeByName(rngName),
rngValues = emailRng.getValues(),
emails = [];
emails = rngValues.map(
function (row) {
return row[0];
});
return emails;
}
// Given a Folder object and an array of email
// addresses, add each email address as an
// editor for the Folder.
function addEditorsToFolder(folder, editors) {
editors.forEach(
function (editor) {
folder.addEditor(editor);
});
}
// Create a new folder, add a pre-defined
// list of editors to the new folder and
// email each of the editors to inform them.
// Will need to authorise!
function notifyEditors (){
var folderName = 'Important Files',
newFolder =
DocsList.createFolder(folderName),
newFolderUrl = newFolder.getUrl(),
emailList = getEmailList(),
subject = 'New Folder to Edit',
body =
'A new folder named ' +
folderName +
' has been created for important files. ' +
'You can add and edit files in this ' +
'location.\n' +
' The URL is:\n' +
newFolderUrl;
addEditorsToFolder(newFolder,
emailList);
MailApp.sendEmail(emailList.join(','),
subject,
body);
}
// To run, replace "" with
// real email addresses.
// Creates a document and write some text to it.
// Saves and closes the document,
// Beware: forgetting " doc.saveAndClose()"
// results in an empty PDF being sent.
// Use DocsList getFileById() method to
// return a File object.
// Read this as a PDF using the File getAs()
// method.
// Create the attachment object and send it.
// Requires authorisation.
function sendAttachment() {
var doc
= DocumentApp.create('ToSendAsAttachment'),
emailList = [],
file,
pdf,
pdfName = 'Test.pdf',
fileId = doc.getId(),
subject = 'Test attachment',
body = 'See attached PDF',
attachment,
paraText =
'This is text that will be written\n' +
'to a document that will then be saved\n' +
'as a PDF and sent as an attachment. ';
doc.appendParagraph(paraText);
doc.saveAndClose();
file = DocsList.getFileById(fileId);
pdf = file.getAs('application/pdf').getBytes();
attachment = {fileName: pdfName,
content:pdf,
mimeType:'application/pdf'};
MailApp.sendEmail(emailList.join(','),
subject,
body,
{attachments:[attachment]});
}
// Return a list of objects that contain
// selected details of the user's email
// threads.
// This will be slow for a large mail box
// so there is an optional argument to limit
// the returned array to a certain number.
// The most recent threads are returned
// returned first.
function getThreadSummaries(threadCount) {
var threads =
GmailApp.getInboxThreads(),
threadSummaries = [],
threadSummary = {},
recCount = 0;
if (typeof threadCount !== 'number') {
threadCount = GmailApp.getInboxThreads();
}
threads.forEach(
function (thread) {
recCount += 1;
if (recCount > threadCount) {
return;
}
threadSummary = {};
threadSummary['MessageCount'] =
thread.getMessageCount();
threadSummary['Subject'] =
thread.getFirstMessageSubject();
threadSummary['ThreadId'] =
thread.getId();
threadSummary['LastUpdate'] =
thread.getLastMessageDate();
threadSummary['URL'] =
thread.getPermalink();
threadSummaries
.push(threadSummary);
});
return threadSummaries;
}
// Write some thread details returned by
// function "getThreadSummaries()" to
// a newly inserted sheet named
// "EmailThreadSummary"
// Make sure the sheet is deleted before
// re-running or an error will be thrown
// when it attempts to insert a new sheet
// with the same name.
function writeThreadSummary() {
var threadCount = 10,
threadSummaries =
getThreadSummaries(threadCount),
ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.insertSheet(),
headerRow;
sh.setName('EmailThreadSummary');
sh.appendRow(['Subject',
'MessageCount',
'LastUpdate',
'ThreadId',
'URL']);
headerRow = sh.getRange(1,1,1,5);
headerRow.setFontWeight('bold');
threadSummaries.forEach(
function (threadSummary) {
sh.appendRow([threadSummary['Subject'],
threadSummary['MessageCount'],
threadSummary['LastUpdate'],
threadSummary['ThreadId'],
threadSummary['URL']]);
});
}
// Create an array of objects containing
// information extracted from each GmailMessage
// object for the given a thread ID.
// Each object property is populated by
// the return value of a GmailMessage
// method.
// Return 'undefined' if there are no
// messages.
function getMsgsForThread(threadId) {
var thread =
GmailApp.getThreadById(threadId),
messages,
msgSummaries = [],
messageSummary = {};
if (!thread) {
return;
}
messages = thread.getMessages();
messages.forEach(
function (message) {
messageSummary = {};
messageSummary['From'] =
message.getFrom();
messageSummary['Cced'] =
message.getCc();
messageSummary['Date'] =
message.getDate();
messageSummary['Body'] =
message.getPlainBody();
messageSummary['MsgId'] =
message.getId();
msgSummaries.push(messageSummary);
});
return msgSummaries;
}
// Given a message summary object as returned
// in an array by "getMsgsForThread" and
// a Google Document ID, open the document,
// extract the object values and write them
// to the document.
// Argument checks could/should be added to
// ensure that the first argument is an
// object and that the second is a valid
// ID for a document.
function writeMsgBodyToDoc(msgSummsForThread,
docId) {
var doc = DocumentApp.openById(docId),
header,
from =
msgSummsForThread['From'],
msgDate =
msgSummsForThread['Date'],
msgBody =
msgSummsForThread['Body'],
msgId =
msgSummsForThread['MsgId'],
docBody = doc.getBody(),
paraTitle;
docBody.appendParagraph('From: ' +
from +
'\rDate: ' +
msgDate +
'\rMessage ID: ' +
msgId);
docBody.appendParagraph(msgBody);
docBody
.appendParagraph(' #################### ');
doc.saveAndClose();
}
// Use the Thread IDs generated earlier
// to extract the message for each thread
// Create a new Google Document
// Write summary message data to the Google
// Document.
// Contains a nested forEach structure,
// see explanation in text.
function writeMsgsForThreads() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
shName = 'EmailThreadSummary',
sh = ss.getSheetByName(shName),
docName = 'ThreadMessages',
doc =
DocumentApp.create(docName),
docId = doc.getId(),
threadIdCount =
sh.getLastRow() -1,
rngThreadIds =
sh.getRange(2,
4,
threadIdCount,
1),
threadIds =
rngThreadIds.getValues();
threadIds.forEach(
function(row) {
var threadId
= row[0],
msgsForThread =
getMsgsForThread(threadId);
msgsForThread.forEach(
function (msg) {
writeMsgBodyToDoc(
msg,
docId);
});
});
}
// Add a label to all email threads where
// the first message in the thread has a
// specified text in its subject section.
// To do this:
// 1: Create a label object using the
// GmailApp createLabel() method.
// 2: Retrieve all the inbox threads.
// 3: Filter the resulting array of
// threads based on the specified
// subject text.
// 4: Add the label to each of the
// threads in the filtered array
// 5: Call the thread refresh method
// to display the label.
function labelAdd() {
var subjectText =
'[Leanpub] A new reader just purchased ' +
'Google Spreadsheet Programming!',
labelText = 'BooksBought',
label =
GmailApp.createLabel(labelText),
threadsAll =
GmailApp.getInboxThreads(),
threadsToLabel;
threadsToLabel = threadsAll.filter(
function (thread) {
return (thread.getFirstMessageSubject()
===
subjectText);
});
Logger.log(threadsToLabel.length);
threadsToLabel.forEach(
function (thread) {
thread.addLabel(label);
thread.refresh();
});
}
// Using a hard-code thread ID taken from
// the email URL, extract the first message
// from the thread and extract the first
// attachment from that message.
// Copy the attachment into a Blob.
// Use the DocsList object to create a File
// object from this blob.
function putAttachmentInGoogleDrive() {
var threadId = '140541c39ae7ce97',
thread =
GmailApp.getThreadById(threadId),
firstMsg =
thread.getMessages()[0],
firstAttachment =
firstMsg.getAttachments()[0],
blob =
firstAttachment.copyBlob();
DocsList.createFile(blob);
Logger.log('File named ' +
firstAttachment.getName() +
' has been saved to Google Drive');
}
// Write some basic information for all
// calendars available to the user to
// the log.
function calendarSummary() {
var cals =
CalendarApp.getAllOwnedCalendars();
Logger.log('Number of Calendars: '
+ cals.length);
cals.forEach(
function(cal) {
Logger.log('Calendar Name: ' +
cal.getName());
Logger.log('Is primary calendar? ' +
cal.isMyPrimaryCalendar());
Logger.log('Calendar description: ' +
cal.getDescription());
});
}
// Take a range of dates from 8th August to
// 16th August 2013 (inclusive) from a
// spreadsheet and create calendar
// all-day events for each of these dates.
// The title is set as "Holidays" and the
// description to "Forget about work".
function calAddEvents() {
var cal = CalendarApp.getDefaultCalendar(),
ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheetByName('Holidays'),
holDates =
sh.getRange('A1:A9').getValues().map(
function (row) {
return row[0];
});
holDates.forEach(
function (holDate) {
var calEvent;
calEvent =
cal.createAllDayEvent('Holiday',
holDate);
calEvent.setDescription(
'Forget about work')
});
}
// Remove all events from the default calendar
// for the dates between Aug 8th and Aug 16th
// inclusive where the event title equals
// "Holiday".
// First get all events for the date range
// as an array.
// Then filter this array to
// get only those with the indicated title.
// Remove those filtered events from the
// calendar.
function calRemoveEvents() {
var cal = CalendarApp.getDefaultCalendar(),
calEvents,
eventTitleToCancel = 'Holiday',
toCancelEvents = [];
calEvents =
cal.getEvents(new Date('August 08, 2013'),
new Date('August 16, 2013'));
toCancelEvents = calEvents.filter(
function (calEvent) {
return (calEvent.getTitle()
===
eventTitleToCancel);
});
toCancelEvents.forEach(
function (eventToCancel) {
eventToCancel.deleteEvent();
});
}
// Get the default calendar object.
// Insert a new sheet into the active
// spreadsheet.
// Retrieve all CalendarEvent objects
// for a specified date interval
// (month of August 2013).
// Append a header row to the new sheet
// and populate it.
// Make the header row font bold.
// Loop over the array of CalendarEvent objects
// and use their methods to extract property
// values of interest.
// Write the property values to the new sheet.
function writeCalEventsToSheet() {
var cal = CalendarApp.getDefaultCalendar(),
ss =
SpreadsheetApp.getActiveSpreadsheet(),
newShName = 'CalendarEvents',
newSh = ss.insertSheet(newShName),
startDate = new Date('August 01, 2013'),
endDate = new Date('August 31, 2013'),
calEvents = cal.getEvents(startDate, endDate),
colHeaders = [],
colCount,
colHeaderRng;
colHeaders = ['Title',
'Description',
'EventId',
'DateCreated',
'IsAllDay',
'MyStatus',
'StartTime',
'EndTime',
'Location'];
colCount = colHeaders.length;
newSh.appendRow(colHeaders);
colHeaderRng = newSh.getRange(1,
1,
1,
colCount);
colHeaderRng.setFontWeight('bold');
calEvents.forEach(
function (calEvent) {
newSh.appendRow(
[calEvent.getTitle(),
calEvent.getDescription(),
calEvent.getId(),
calEvent.getDateCreated(),
calEvent.isAllDayEvent(),
calEvent.getMyStatus(),
calEvent.getStartTime(),
calEvent.getEndTime(),
calEvent.getLocation()
]);
});
}
// Chapter 10
// For this chapter, HTML and client JavaScript will be enclosed in /* */ comment blocks!
// Execute this function and switch to
// spreadsheet tab to see the HTML form
// built in the file index.html.
function demoHtmlServices() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
html =
HtmlService
.createHtmlOutputFromFile('index');
ss.show(html);
}
// This function is called by the JavaScript
// function "formSubmit()" defined in the
// accompanying HTML file.
function getValuesFromForm(form){
var firstName = form.firstName,
lastName = form.lastName,
sheet =
SpreadsheetApp
.getActiveSpreadsheet()
.getActiveSheet();
sheet.appendRow([firstName, lastName]);
}
/*
Add Row To Spreadsheet
*/
/*
*/
// Required function name for web apps.
function doGet() {
var html =
HtmlService
.createHtmlOutputFromFile('survey');
html.setTitle('Customer Survey');
html.setHeight(600);
return html;
}
// Extract values from the web app form
// and write them to a sheet named
// "Feedback".
function getValuesFromForm(form){
var email = form.email,
gender = form.gender,
country = form.country,
note = form.note,
ssId =
'0Amdsdq7IKB9ydExEanFqMm5ocmRSMndyRmFOeTgxckE',
ss = SpreadsheetApp.openById(ssId),
shName = 'Feedback',
sheet = ss.getSheetByName(shName);
sheet.appendRow([email,
gender,
country,
note]);
}
/*
English Premier League
var data = getData(); ?>
for (var i = 0; i < data.length; i++) { ?>
for (var j = 0;
j < data[i].length; j++) { ?>
|
= data[i][j] ?> |
} ?>
} ?>
*/
function doGet() {
var html =
HtmlService
.createTemplateFromFile('premier_league');
return html.evaluate();
}
function getData() {
var ssId =
'0Amdsdq7IKB9ydE5KYXkyRmJZZ244Qmo0ODVrX0dXekE',
ss = SpreadsheetApp.openById(ssId),
rng =
ss.getRangeByName('premier_league_table'),
data = rng.getValues();
return data;
}
// Appendix A
// Equivalent VBA code is in /* */ comment blocks
/*
Public Sub SpreadsheetInstance(()
Dim ss As Workbook
Set ss = Application.ActiveWorkbook
Debug.Print ss.Name
End Sub
*/
function spreadsheetInstance() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
Logger.log(ss.getName());
}
/*
Public Sub FirstSheetInfo()
Dim sh1 As Worksheet
Set sh1 = ActiveWorkbook.Worksheets(1)
Dim usedRng As Range
Set usedRng = sh1.UsedRange
Debug.Print sh1.Name
Debug.Print usedRng.Address
End Sub
*/
function firstSheetInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheets = ss.getSheets(),
// getSheets() returns an array
// JavaScript arrays are always zero-based
sh1 = sheets[0];
Logger.log(sh1.getName());
// getDataRange is analagous to UsedRange
//in VBA
// getA1Notation() is functional equivalent to
// Address in VBA
Logger.log(sh1.getDataRange().getA1Notation());
}
/*
Public Sub PrintSheetNames()
Dim sheets As Worksheets
Dim sheet As Worksheet
For Each sheet In ActiveWorkbook.Sheets
Debug.Print sheet.Name
Next sheet
End Sub
*/
// Print the names of all sheets in the active
// spreadsheet.
function printSheetNames() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheets = ss.getSheets(),
i;
for (i = 0; i < sheets.length; i += 1) {
Logger.log(sheets[i].getName());
}
}
/*
' Add a new sheet to a workbook.
' Call the Add method of the
' Worksheets collection
' Assign a name to the returned
' Worksheet instance
' Name property.
Sub AddNewSheet()
Dim newSheet As Worksheet
Set newSheet = ActiveWorkbook.Worksheets.Add
newSheet.Name = "AddedSheet"
MsgBox "New Sheet Added!"
End Sub
' Delete a named sheet from the
' active spreadsheet.
' The sheet to delete is identified
' in the Worksheets collection
' by name. The returned instance
' is deleted by calling its
' Delete method.
' MS Excel will prompt to confirm.
Sub RemoveSheet()
Dim sheetToRemove As Worksheet
Set sheetToRemove = _
ActiveWorkbook.Worksheets("AddedSheet")
sheetToRemove.Delete
MsgBox "Sheet Deleted!"
End Sub
*/
// Add a new sheet to the active spreadsheet.
// Get an instance of the active spreadsheet.
// Call its insertSheet method.
// Call the setName method of the
// returned instance.
function addNewSheet() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
newSheet;
newSheet = ss.insertSheet();
newSheet.setName("AddedSheet");
Browser.msgBox("New Sheet Added!");
}
// Remove a named sheet from the
// active spreadsheet.
// Get an instance of the active
// spreadsheet.
// Get an instance of the sheet to remove.
// Activate the sheet to remove
// Call the spreadsheet instance method
// deleteActiveSheet.
function removeSheet() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheetToRemove =
ss.getSheetByName("AddedSheet");
sheetToRemove.activate();
ss.deleteActiveSheet();
Browser.msgBox("SheetDeleted!");
}
/*
Public Sub SheetHide()
Dim sh As Worksheet
Set sh = Worksheets.Item("ToHide")
sh.Visible = False
End Sub
*/
// Hide a sheet specified by its name.
function sheetHide() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheetByName('ToHide');
sh.hideSheet()
}
/*
Public Sub ListHiddenSheetNames()
Dim sheet As Worksheet
For Each sheet In Worksheets
If sheet.Visible = False Then
Debug.Print sheet.Name
End If
Next sheet
End Sub
*/
// Write a list of hidden sheet names to log.
function listHiddenSheetNames() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheets = ss.getSheets();
sheets.forEach(
function (sheet) {
if (sheet.isSheetHidden()) {
Logger.log(sheet.getName());
}
});
}
/*
Public Sub SheetsUnhide()
Dim sheet As Worksheet
For Each sheet In Worksheets
If sheet.Visible = False Then
sheet.Visible = True
End If
Next sheet
End Sub
*/
// Unhide all hidden sheets.
function sheetsUnhide() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheets = ss.getSheets();
sheets.forEach(
function (sheet) {
if (sheet.isSheetHidden()) {
sheet.showSheet();
}
});
}
/*
' Password-protect rotect a sheet identified
' by name
Public Sub SheetProtect()
Dim sh As Worksheet
Dim pwd As String: pwd = "secret"
Set sh = Worksheets.Item("ToProtect")
sh.Protect pwd
End Sub
*/
// Identify a sheet by name to protect
// When this code runs, the lock icon
// will appear on the sheet name.
// Share the spreadsheet with another user
// as an editor. That user can edit all
// sheets except the protected one. The user
// can still edit the protected sheet.
function sheetProtect() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheetByName('ToProtect'),
permissions = sh.getSheetProtection();
ss.addEditor();
permissions.setProtected(true);
sh.setSheetProtection(permissions);
}
/*
Public Sub PrintSelectionDetails()
Debug.Print "Selected Range Details: "
Debug.Print "-- Sheet: " & _
Selection.Worksheet.Name
Debug.Print "-- Address: " & _
Selection.Address
Debug.Print "-- Row Count: " & _
Selection.Rows.Count
Debug.Print "'-- Column Count: " & _
Selection.Columns.Count
End Sub
*/
// Prints details about selected range in
// active spreadsheet
// To run, paste code into script editor,
// select some cells on any sheet,
// execute code and
// check log to see details
// Prints details about selected range
// in active spreadsheet
// To run, paste code into script editor,
// select some cells on any sheet,
// execute code and
// check log to see details
function printSelectionDetails() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
selectedRng = ss.getActiveRange();
Logger.log('Selected Range Details:');
Logger.log('-- Sheet: '
+ selectedRng
.getSheet()
.getSheetName());
Logger.log('-- Address: '
+ selectedRng.getA1Notation());
Logger.log('-- Row Count: '
+ ((selectedRng.getLastRow() + 1)
- selectedRng.getRow()));
Logger.log('-- Column Count: '
+ ((selectedRng.getLastColumn() + 1)
- selectedRng.getColumn()));
}
/*
Public Function GetUsedRangeAsArray(sheetName _
As String) As Variant
Dim sh As Worksheet
Set sh = _
ActiveWorkbook.Worksheets(sheetName)
GetUsedRangeAsArray = sh.UsedRange.value
End Function
Sub test_GetUsedRangeAsArray()
Dim sheetName As String
Dim rngValues
Dim firstRow As Variant
sheetName = "Sheet1"
rngValues = GetUsedRangeAsArray(sheetName)
Debug.Print rngValues(1, 1)
Debug.Print UBound(rngValues)
Debug.Print UBound(rngValues, 2)
End Sub
*/
function getUsedRangeAsArray(sheetName) {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheetByName(sheetName);
// The getValues() method of the
// Range object returns an array of arrays
return sh.getDataRange().getValues();
}
// JavaScript does not distinguish between
// subroutines and functions.
// When the return statement is omitted,
// functions return undefined.
function test_getUsedRangeAsArray() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheetName = 'Sheet1',
rngValues = getUsedRangeAsArray(sheetName);
// Print the number of rows in the range
// The toString() call to suppress the
// decimal point so
// that, for example, 10.0, is reported as 10
Logger.log((rngValues.length).toString());
// Print the number of columns
// The column count will be the same
// for all rows so only need the first row
Logger.log((rngValues[0].length).toString());
// Print the value in the first cell
Logger.log(rngValues[0][0]);
}
/*
Sub AddColorsToRange()
Dim sh1 As Worksheet
Dim addr As String: addr = "A4:B10"
Set sh1 = ActiveWorkbook.Worksheets(1)
sh1.Range(addr).Interior.ColorIndex = 3
sh1.Range(addr).Font.ColorIndex = 10
End Sub
*/
// Select a block of cells in the first sheet.
// Use Range methods to set both the font and
// background colors.
function addColorsToRange() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sheets = ss.getSheets(),
sh1 = sheets[0],
addr = 'A4:B10',
rng;
// getRange is overloaded. This method can
// also accept row and column integers
rng = sh1.getRange(addr);
rng.setFontColor('green');
rng.setBackgroundColor('red');
}
/*
Public Sub OffsetDemo()
Dim sh As Worksheet
Dim cell As Range
Set sh = _
ActiveWorkbook.Worksheets(1)
Set cell = sh.Range("B2")
cell.value = "Middle"
cell.Offset(-1, -1).value = "Top Left"
cell.Offset(0, -1).value = "Left"
cell.Offset(1, -1).value = "Bottom Left"
cell.Offset(-1, 0).value = "Top"
cell.Offset(1, 0).value = "Bottom"
cell.Offset(-1, 1).value = "Top Right"
cell.Offset(0, 1).value = "Right"
cell.Offset(1, 1).value = "Bottom Right"
End Sub
*/
// The Spreadsheet method getSheets() returns
// an array.
// The code "ss.getSheets()[0]"
// returns the first sheet and is equivalent to
// "ActiveWorkbook.Worksheets(1)" in VBA.
// Note that the VBA version is 1-based!
function offsetDemo() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheets()[0],
cell = sh.getRange('B2');
cell.setValue('Middle');
cell.offset(-1,-1).setValue('Top Left');
cell.offset(0, -1).setValue('Left');
cell.offset(1, -1).setValue('Bottom Left');
cell.offset(-1, 0).setValue('Top');
cell.offset(1, 0).setValue('Bottom');
cell.offset(-1, 1).setValue('Top Right');
cell.offset(0, 1).setValue('Right');
cell.offset(1, 1).setValue('Bottom Right');
}
/*
' Mimicking Google Apps Script
' offset() method overloads.
Public Sub OffsetOverloadDemo()
Dim sh As Worksheet
Dim cell As Range
Dim offsetRng2 As Range
Dim offsetRng3 As Range
Set sh = ActiveWorkbook.Worksheets(1)
Set cell = sh.Range("A1")
'Offset returns a Range so Offset
' can be called again
' on the returned Range from
' first Offset call.
Set offsetRng2 = Range(cell.Offset(1, 4), _
cell.Offset(1, 4).Offset(1, 0))
Set offsetRng3 = Range(cell.Offset(10, 4), _
cell.Offset(10, 4).Offset(3, 4))
Debug.Print offsetRng2.Address
Debug.Print offsetRng3.Address
End Sub
*/
// Demonstrating overloaded versions of offset()
// Output:
// Address of offset() overload 2
// (rowOffset, columnOffset, numRows) is: E2:E3
// Address of offset() overload 3 (rowOffset,
// columnOffset, numRows, numColumns)
// is: E11:I14
function offsetOverloadDemo() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheets()[0],
cell = sh.getRange('A1'),
offsetRng2 = cell.offset(1, 4, 2),
offsetRng3 = cell.offset(10, 4, 4, 5);
Logger.log('Address of offset() overload 2 ' +
'(rowOffset, columnOffset, numRows) is: '
+ offsetRng2.getA1Notation());
Logger.log('Address of offset() overload 3 ' +
'(rowOffset, columnOffset, numRows, ' +
'numColumns) is: '
+ offsetRng3.getA1Notation());
}
/*
Public Sub PrintRangeNames()
Dim namedRng As Name
For Each namedRng In ActiveWorkbook.Names
Debug.Print "The name of the range is: " & _
namedRng.Name & _
" It refers to this address: " & _
namedRng.RefersTo
Next namedRng
End Sub
*/
/*
Public Sub SetCellComment(sheetName As String, _
cellAddress As String, _
cellComment As String)
Dim sh As Worksheet
Dim cell As Range
Set sh = ActiveWorkbook.Worksheets(sheetName)
Set cell = sh.Range(cellAddress)
cell.AddComment cellComment
End Sub
Public Sub test_SetCellComment()
Dim sheetName As String
sheetName = "Sheet1"
Dim cellAddress As String
cellAddress = "C10"
Dim cellComment As String
cellComment = "Comment added: " & Now()
Call SetCellComment(sheetName, _
cellAddress, _
cellComment)
End Sub
*/
function setCellComment(sheetName, cellAddress,
cellComment) {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheetByName(sheetName),
cell = sh.getRange(cellAddress);
cell.setNote(cellComment);
}
function test_setCellComment() {
var sheetName = 'Sheet1',
cellAddress = 'C10',
cellComment = 'Comment added ' + Date();
setCellComment(sheetName, cellAddress, cellComment);
}
/*
' Need to check if the cell has a comment.
' If it does not, then exit the sub but if
' it does, then remove it.
Public Sub RemoveCellComment(sheetName _
As String, _
cellAddress As String)
Dim sh As Worksheet
Dim cell As Range
Set sh = ActiveWorkbook.Worksheets(sheetName)
Set cell = sh.Range(cellAddress)
If cell.Comment Is Nothing Then
Exit Sub
Else
cell.Comment.Delete
End If
End Sub
Public Sub test_RemoveCellComment()
Dim sheetName As String
sheetName = "Sheet1"
Dim cellAddress As String
cellAddress = "C10"
Call RemoveCellComment(sheetName, _
cellAddress)
End Sub
*/
// To remove a comment, just pass an empty string
// to the setNote() method.
function removeCellComment(sheetName, cellAddress) {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sh = ss.getSheetByName(sheetName),
cell = sh.getRange(cellAddress);
cell.setNote('');
}
function test_removeCellComment() {
var sheetName = 'Sheet1',
cellAddress = 'C10';
removeCellComment(sheetName, cellAddress);
}
/*
' This VBA code is commented because the
' VBA approach differs
' considerably from the Google Apps Script one.
' Note: the Offset() method of the Range
' object uses 0-based indexes.
Public Sub copyRowsToNewSheet()
Dim sourceSheet As Worksheet
Dim newSheet As Worksheet
Dim newSheetName As String
newSheetName = "Target"
Dim sourceRng As Range
Dim sourceRows As Variant
Dim i As Long
Set sourceSheet = _
Application.Worksheets("Source")
Set newSheet = ActiveWorkbook.Worksheets.Add
newSheet.Name = newSheetName
' Use a named range as marker
' for row copying (VBA hack!)
newSheet.Range("A1").Name = "nextRow"
Set sourceRng = sourceSheet.UsedRange
' Copy the header row
sourceRng.Rows(1).Copy Range("nextRow")
' Moved the named range marker down one row
Range("nextRow").Offset(1, 0).Name = _
"nextRow"
'Skip header row by setting i,
' the row counter, = 2
' i starts at 2 to skip header row
For i = 2 To sourceRng.Rows.Count
If sourceRng.Cells(i, 2).value _
<= 10000 Then
' Define the row range to copy
' using the first and
' last cell in the row.
Range(sourceRng.Cells(i, 1), _
sourceRng.Cells(i, _
sourceRng.Columns.Count)).Copy _
Range("nextRow")
Range("nextRow").Offset(1, 0).Name _
= "nextRow"
End If
Next i
End Sub
*/
// Longer example
// Copy rows from one sheet named "Source" to
// a newly inserted
// one based on a criterion check of second
// column.
// Copy the header row to the new sheet.
// If Salary <= 10,000 then copy the entire row
function copyRowsToNewSheet() {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sourceSheet = ss.getSheetByName('Source'),
newSheetName = 'Target',
newSheet = ss.insertSheet(newSheetName),
sourceRng = sourceSheet.getDataRange(),
sourceRows = sourceRng.getValues(),
i;
newSheet.appendRow(sourceRows[0]);
for (i = 1; i < sourceRows.length; i += 1) {
if (sourceRows[i][1] <= 10000) {
newSheet.appendRow(sourceRows[i]);
}
}
}
/*
Public Sub test_PrintSheetFormulas()
Dim sheetName As String
sheetName = "Formulas"
Call PrintSheetFormulas(sheetName)
End Sub
Public Sub PrintSheetFormulas(sheetName _
As String)
Dim sourceSheet As Worksheet
Dim usedRng As Range
Dim i As Long
Dim j As Long
Dim cellAddr As String
Dim cellFormula As String
Set sourceSheet = _
ActiveWorkbook.Worksheets(sheetName)
Set usedRng = sourceSheet.UsedRange
For i = 1 To usedRng.Rows.Count
For j = 1 To usedRng.Columns.Count
cellAddr = _
usedRng.Cells(i, j).Address
cellFormula = _
usedRng.Cells(i, j).Formula
If Left(cellFormula, 1) = "=" Then
Debug.Print cellAddr & _
": " & cellFormula
End If
Next j
Next i
End Sub
*/
function test_printSheetFormulas() {
var sheetName = 'Formulas';
printSheetFormulas(sheetName);
}
function printSheetFormulas(sheetName) {
var ss =
SpreadsheetApp.getActiveSpreadsheet(),
sourceSheet = ss.getSheetByName(sheetName),
usedRng = sourceSheet.getDataRange(),
i,
j,
cell,
cellAddr,
cellFormula;
for (i = 1; i <= usedRng.getLastRow();
i += 1) {
for (j = 1; j <= usedRng.getLastColumn();
j += 1) {
cell = usedRng.getCell(i, j);
cellAddr = cell.getA1Notation();
cellFormula = cell.getFormula();
if (cellFormula) {
Logger.log(cellAddr +
': ' + cellFormula);
}
}
}
}