Created
February 17, 2018 21:51
-
-
Save sliminality/a2e467f9770a53572c8334e203cb998c to your computer and use it in GitHub Desktop.
Google Sheets script for my ops keystone, inspired by http://sebastianmarshall.com/key-points-week-one
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var config = { | |
templateSheetName: 'TEMPLATE', | |
dateFormat: 'ddd M/d', | |
sheetTitlePrefix: 'Week ', | |
daysPerSheet: 7, | |
showLatestOnLeft: true, | |
dateHeaderRow: 1, | |
}; | |
// Get the first sheet from the given spreadsheet. | |
// If no spreadsheet is passed, defaults to active spreadsheet. | |
function getFirstSheet(ss) { | |
var ss = ss || SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = ss.getSheets()[0]; | |
return sheet; | |
} | |
// Get the sheet labeled 'TEMPLATE'. | |
function getTemplateSheet(ss) { | |
var ss = ss || SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = ss.getSheetByName(config.templateSheetName); | |
return sheet; | |
} | |
// Return a record {row, column, value, cell} of the first non-frozen cell. | |
function getFirstNonFrozenCol(sheet) { | |
var sheet = sheet || SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); | |
var frozenCols = sheet.getFrozenColumns(); | |
var totalCols = sheet.getLastColumn(); | |
if (totalCols === frozenCols) { | |
throw new Error('getFirstNonFrozenCol: sheet ' + sheet.getSheetName() + | |
' has no non-frozen columns'); | |
} | |
var row = config.dateHeaderRow; | |
var column = frozenCols + 1; | |
var cell = sheet.getRange(row, column, 1, 1); | |
var value = cell.getValue(); | |
return {row: row, column: column, value: value, cell: cell}; | |
} | |
// Get the most recent date column from the given sheet. | |
// Returns a Date object. | |
function getLatestDateCell(sheet) { | |
// If the most recent date is on the left, then we can just return the | |
// first non-frozen cell. | |
if (config.showLatestOnLeft) { | |
return getFirstNonFrozenCol(sheet); | |
} | |
var lastCol = sheet.getLastColumn(); | |
var cell = sheet.getRange(config.dateHeaderRow, lastCol, 1, 1); | |
var value = cell.getValue(); | |
return {row: config.dateHeaderRow, column: lastCol, cell: cell, value: value}; | |
} | |
// Parse the week number from a sheet title. | |
// e.g. "Week 15" -> 15 | |
function parseWeekNumber(str) { | |
var re = new RegExp('^' + config.sheetTitlePrefix + '([0-9]+)'); | |
var match = str.match(re); | |
if (!match || match.length < 2) { | |
throw new Error('parseWeekNumber: could not parse week from title '.concat(str)); | |
} | |
var week = parseInt(match[1], 10); | |
return week; | |
} | |
// Create a new weekly sheet, and set it to the active sheet. | |
function addWeeklySheet(ss) { | |
var ss = ss || SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = getFirstSheet(ss); | |
// Get the week number from the latest sheet's title. | |
var lastWeek = parseWeekNumber(sheet.getSheetName()); | |
var week = lastWeek + 1; | |
var name = config.sheetTitlePrefix.concat(week); | |
// Get the date range from the latest sheet's leftmost column. | |
var lastDate = getLatestDateCell(sheet); | |
if (!(lastDate.value instanceof Date)) { | |
throw new Error('addWeeklySheet: expected Date object, got ' + lastDate.value); | |
} | |
var dates = generateNextDates(lastDate.value, config.daysPerSheet); | |
// Show dates from left to right. | |
if (config.showLatestOnLeft) { | |
dates.reverse(); | |
} | |
ss.insertSheet(name, 0, {template: getTemplateSheet()}); | |
var newSheet = getFirstSheet(ss); | |
return addDates(newSheet, dates); | |
} | |
// Takes a Date object and a number of days to generate, and returns | |
// a list of Date objects representing that many days afterwards. | |
function generateNextDates(start, n) { | |
var startMs = start.getTime(); | |
var MS_PER_DAY = 1000 * 60 * 60 * 24; | |
var result = []; | |
for (var i = 1; i < n + 1; i += 1) { | |
var delta = i * MS_PER_DAY; | |
var date = new Date(startMs + delta); | |
result.push(date); | |
} | |
return result; | |
} | |
// Insert the given range of dates in the non-frozen header cells of the | |
// given sheet. | |
function addDates(sheet, dates) { | |
var lastCol = sheet.getLastColumn(); | |
var available = lastCol - sheet.getFrozenColumns(); | |
if (available < dates.length) { | |
sheet.insertColumnsAfter(lastCol, dates.length - available); | |
} | |
var range = sheet.getRange(1, sheet.getFrozenColumns() + 1, 1, dates.length); | |
range.setValues([dates]).setNumberFormat(config.dateFormat); | |
return sheet; | |
} | |
// Create menu. | |
function onOpen(e) { | |
SpreadsheetApp.getUi() | |
.createMenu('Keystone') | |
.addItem('Add weekly sheet', 'addWeeklySheet') | |
.addToUi(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment