Skip to content

Instantly share code, notes, and snippets.

@jsdbroughton
Created May 31, 2013 11:56
Show Gist options
  • Save jsdbroughton/5684504 to your computer and use it in GitHub Desktop.
Save jsdbroughton/5684504 to your computer and use it in GitHub Desktop.
GAS for serving an XML gadget for GMail / Google Calendar that displays a list of people who are absent and codifies them accordingly. XML Gadget is served via content service, but this also runs on a timed trigger to update a calendar with one event per day that holds the same data. This is useful for subscribing to within calendar client apps.
function doGet(e) {
var output = ContentService.createTextOutput();
var xml;
var cache = CacheService.getPublicCache();
var cached = cache.get('xml');
if (cached != null) {
xml = JSON.parse(cached);
} else {
var out = whoIsOut('nofile');
xml = writeXML(out['description'],out['absencelist']);
cache.put('xml',JSON.stringify(xml),7100); // cache for just under 15 minutes;
}
output.setContent(xml);
output.setMimeType(ContentService.MimeType.XML);
return output;
}
/**
* Write out absences to an xml gadget
*/
function writeXML(content,absenceData) {
var xmlGadget = DocsList.getFileById(ScriptProperties.getProperty('xmlFile'))
var xmlStart = '\
<?xml version="1.0" encoding="UTF-8"?>\
<Module>\
<ModulePrefs title="Away today?" \
author="Allies and Morrison Architects" \
author_email="r+d@alliesandmorrison.com" \
author_affiliation="Allies and Morrison Architects" \
description="A Sidebar Gadget that Display\'s who is out of the office today" \
><!-- test removal of scrolling="true" -->\
<Require feature="dynamic-height"/>\
<Require feature="google.calendar-0.5"/>\
<Require feature="google.calendar-0.5.read"/>\
</ModulePrefs>\
<Content type="html">\
<![CDATA[\
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\
<style>\
@font-face {\
font-family: "calTool";\
src: url(data:font/svg;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8bWV0YWRhdGE+ClRoaXMgaXMgYSBjdXN0b20gU1ZHIGZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uCjEKPC9tZXRhZGF0YT4KPGRlZnM+Cjxmb250IGlkPSJjYWxUb29sIiBob3Jpei1hZHYteD0iNTEyIiA+Cjxmb250LWZhY2UgdW5pdHMtcGVyLWVtPSI1MTIiIGFzY2VudD0iMjU2IiBkZXNjZW50PSItMjU2IiAvPgo8bWlzc2luZy1nbHlwaCBob3Jpei1hZHYteD0iNTEyIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4NTQ7IiBkPSJNIDM2NC40OTYsMC4wMEMgNDMzLjM3Myw0My42NjcsIDQ4MC4wMCwxMjcuNjA0LCA0ODAuMDAsMjI0LjAwYzAuMDAsMTAuODM4LTAuNTk2LDIxLjUxNy0xLjczOSwzMi4wMEwgMzMuNzQsMjU2LjAwIEMgMzIuNTk1LDI0NS41MTYsIDMyLjAwLDIzNC44MzcsIDMyLjAwLDIyNC4wMAoJCWMwLjAwLTk2LjM5NiwgNDYuNjI3LTE4MC4zMzMsIDExNS41MDMtMjI0LjAwQyA3OC42MjctNDMuNjY3LCAzMi4wMC0xMjcuNjA0LCAzMi4wMC0yMjQuMDBjMC4wMC0xMC44MzgsIDAuNTk1LTIxLjUxNywgMS43MzktMzIuMDBsIDQ0NC41MjEsMC4wMCAKCQljIDEuMTQ0LDEwLjQ4MywgMS43MzksMjEuMTYyLCAxLjczOSwzMi4wMEMgNDgwLjAwLTEyNy42MDQsIDQzMy4zNzMtNDMuNjY3LCAzNjQuNDk2LDAuMDB6IE0gODAuMDAtMjI0LjAwYzAuMDAsOTMuNDU2LCA0MC4wODEsMTcyLjcwNywgMTEyLjAwLDE5OC44NTQKCQlsMC4wMCw1MC4yOTMgbDAuMDAsMC4wMCBDIDEyMC4wODEsNTEuMjkyLCA4MC4wMCwxMzAuNTQzLCA4MC4wMCwyMjQuMDBsMC4wMCwwLjAwIGwgMzUyLjAwLDAuMDAgbDAuMDAsMC4wMCBjMC4wMC05My40NTctNDAuMDgxLTE3Mi43MDgtMTEyLjAwLTE5OC44NTNsMC4wMC01MC4yOTMgCgkJQyAzOTEuOTE5LTUxLjI5MywgNDMyLjAwLTEzMC41NDQsIDQzMi4wMC0yMjQuMDBMIDgwLjAwLTIyNC4wMCB6TSAzMDkuODEzLTc4Ljc5N2MtMzUuODI3LDIwLjMyMi0zNy44MDQsNDYuNjg0LTM3LjgxMyw2Mi42ODNMIDI3Mi4wMCwxNi4wMCBjMC4wMCwxNS45OTcsIDEuOTAyLDQyLjQ1NywgMzcuODcyLDYyLjgzMgoJCWMgMTkuMjUyLDExLjE4MiwgMzUuOTA0LDI4LjE3NCwgNDguNTI0LDQ5LjE2OEwgMTUzLjYwNSwxMjguMDAgYyAxMi42MzMtMjEuMDE2LCAyOS4zMDYtMzguMDIxLCA0OC41ODMtNDkuMjAzCgkJYyAzNS44MjctMjAuMzIyLCAzNy44MDMtNDYuNjgzLCAzNy44MTMtNjIuNjgzTCAyNDAuMDAxLTE2LjAwIGMwLjAwLTE1Ljk5Ni0xLjkwMi00Mi40NTctMzcuODcyLTYyLjgzMmMtMzYuMzExLTIxLjA5LTYzLjM2OS02Mi44NDItNzEuNTQ1LTExMy4xNjgKCQlsIDI1MC44MzUsMC4wMCBDIDM3My4yMzctMTQxLjY0NiwgMzQ2LjE1NC05OS44NzYsIDMwOS44MTMtNzguNzk3eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDUyOyIgZD0iTSAyMjQuMDAtMTMxLjgxNEwgMjI0LjAwLTI1Ni4wMCBMIDMyLjAwLTY0LjAwbCAxOTIuMDAsMTkyLjAwbDAuMDAtMTI2LjkxMiBDIDQ0Ny4zNzUtNC4xNTIsIDQzNy43OTQsMTUyLjk4NCwgMzgwLjkzMSwyNTYuMDAKCUMgNTIxLjI4NiwxMDQuMjkzLCA0OTEuNDgxLTEzOC43ODUsIDIyNC4wMC0xMzEuODE0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDQzOyIgZD0iTSAxNjAuMDAsNjQuMDBMIDIyNC4wMCw2NC4wMEwgMjI0LjAwLDAuMDBMIDE2MC4wMCwwLjAwek0gMjU2LjAwLDY0LjAwTCAzMjAuMDAsNjQuMDBMIDMyMC4wMCwwLjAwTCAyNTYuMDAsMC4wMHpNIDM1Mi4wMCw2NC4wMEwgNDE2LjAwLDY0LjAwTCA0MTYuMDAsMC4wMEwgMzUyLjAwLDAuMDB6TSA2NC4wMC0xMjguMDBMIDEyOC4wMC0xMjguMDBMIDEyOC4wMC0xOTIuMDBMIDY0LjAwLTE5Mi4wMHpNIDE2MC4wMC0xMjguMDBMIDIyNC4wMC0xMjguMDBMIDIyNC4wMC0xOTIuMDBMIDE2MC4wMC0xOTIuMDB6TSAyNTYuMDAtMTI4LjAwTCAzMjAuMDAtMTI4LjAwTCAzMjAuMDAtMTkyLjAwTCAyNTYuMDAtMTkyLjAwek0gMTYwLjAwLTMyLjAwTCAyMjQuMDAtMzIuMDBMIDIyNC4wMC05Ni4wMEwgMTYwLjAwLTk2LjAwek0gMjU2LjAwLTMyLjAwTCAzMjAuMDAtMzIuMDBMIDMyMC4wMC05Ni4wMEwgMjU2LjAwLTk2LjAwek0gMzUyLjAwLTMyLjAwTCA0MTYuMDAtMzIuMDBMIDQxNi4wMC05Ni4wMEwgMzUyLjAwLTk2LjAwek0gNjQuMDAtMzIuMDBMIDEyOC4wMC0zMi4wMEwgMTI4LjAwLTk2LjAwTCA2NC4wMC05Ni4wMHpNIDQxNi4wMCwyNTYuMDBsMC4wMC0zMi4wMCBsLTY0LjAwLDAuMDAgTCAzNTIuMDAsMjU2LjAwIEwgMTI4LjAwLDI1Ni4wMCBsMC4wMC0zMi4wMCBMIDY0LjAwLDIyNC4wMCBMIDY0LjAwLDI1Ni4wMCBMMC4wMCwyNTYuMDAgbDAuMDAtNTEyLjAwIGwgNDgwLjAwLDAuMDAgTCA0ODAuMDAsMjU2LjAwIEwgNDE2LjAwLDI1Ni4wMCB6IE0gNDQ4LjAwLTIyNC4wMEwgMzIuMDAtMjI0LjAwIEwgMzIuMDAsMTI4LjAwIGwgNDE2LjAwLDAuMDAgTCA0NDguMDAtMjI0LjAwIHoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3g0MTsiIGQ9Ik0gMzExLjQxMy05NS4zNjhjLTExLjA1NSwxLjc1OS0xMS4zMDcsMzIuMTU3LTExLjMwNywzMi4xNTdzIDMyLjQ4NCwzMi4xNTgsIDM5LjU2NCw3NS40MDEKCWMgMTkuMDQ1LDAuMDAsIDMwLjgwOSw0NS45NzMsIDExLjc2MSw2Mi4xNDhDIDM1Mi4yMjYsOTEuMzY1LCAzNzUuOTExLDIwOC4wMCwgMjU2LjAwLDIwOC4wMGMtMTE5LjkxMSwwLjAwLTk2LjIyNS0xMTYuNjM1LTk1LjQzMi0xMzMuNjYyCgljLTE5LjA0Ny0xNi4xNzUtNy4yODUtNjIuMTQ4LCAxMS43NjEtNjIuMTQ4YyA3LjA3OS00My4yNDMsIDM5LjU2NC03NS40MDEsIDM5LjU2NC03NS40MDFzLTAuMjUyLTMwLjM5OC0xMS4zMDctMzIuMTU3CglDIDE2NC45NzYtMTAxLjAzNCwgMzIuMDAtMTU5LjY4NSwgMzIuMDAtMjI0LjAwbCAyMjQuMDAsMC4wMCBsIDIyNC4wMCwwLjAwIEMgNDgwLjAwLTE1OS42ODUsIDM0Ny4wMjQtMTAxLjAzNCwgMzExLjQxMy05NS4zNjh6IiAvPjwvZm9udD48L2RlZnM+PC9zdmc+) format("svg"),\
url(data:font/woff;charset=utf-8;base64,d09GRk9UVE8AAAcgAAsAAAAACeQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAABCAAAA9sAAAT6GiGwmkZGVE0AAATkAAAAGgAAABxiPsvwR0RFRgAABQAAAAAdAAAAIAAzAARPUy8yAAAFIAAAAEsAAABgUR7agGNtYXAAAAVsAAAAVgAAAWrisRSpaGVhZAAABcQAAAAtAAAANvnUm7toaGVhAAAF9AAAAB0AAAAkAzD/B2htdHgAAAYUAAAAFgAAABgKAABgbWF4cAAABiwAAAAGAAAABgAGUABuYW1lAAAGNAAAAN8AAAGGOwXbu3Bvc3QAAAcUAAAADAAAACAAAwAAeJxtVG1sk1UUPm/Xj9fSdBtbx8DuI7AlQxksbgoShwsu04CBZStRCNMhIYpbALU4+XAqTEm4mqhpwkIIzPERwkSNWYjKwtAETawY5wyLMjOYIs4uw2Q17dbax+e+nfpD37S3t+c85zzPPefc1xC7XQzDMDdvag1s394qhk0MuT/ut8ULMuL5duXJUB57oVvmNs6GUv9sPC6VCMVDsZDDL22ZfpEsv+zL9ovXbx+fLRk6iSmZkrdz29a6ioqKmex/k/C5WyqlROYbB8SpwTbb67brGXX2evsGL4zW9uk8SO21fcB362ogi7s6gHezisHnInDscJcC/li4i3+ffI+7hnIgdXU+dx0bTKQe2N3lTBvEvedUGiTus4OK65UDXJu3NOuk+yGNt65popWQO88w8/miCzO7gcdftLxptBVZB5HOBisTxCgt0tlvmjD6Xm120lByxOLXoJClKa1RWXp1wr0zZzhf1G6di0p/esWZCPpiUScJmoJ9wFCkFrK2ZiXwUW4fZF5ptwm5a7XNBXlQu+aVFkLKtIsgKyhlqkRUuUjTrWxpHz7ov5DG48YPo6ZSdF7uTTnSSWl7LE2kcVZcLUlufFMMeasy7oOUPPIw8Fvkc8jtvhrgyvJRiLm4k0lONpuA444VPK9Z7qWyxp0Eeb+HLLzIapasPQrxzXFDFsRZqNxmYV1+GaPs5+0Um5maNmE9UlywhHLw5zOQLDHYLGcpURtbgOFFqxjZsA0Y/3gOZJbmvdV4DpJtPARMNkXJYM+n4K++fIldntxEa8Q4SND6fC42DwP7WerowFNM5uJ4RLqEBHPzePKD1Tzv73KJMkZGB1hUsa3RBs6YMe0n4HiA2gfPMejs26Y3FgT2LjnqgzFrD6drytUKKfiaozmZEweeO8leHOpNQZYNTwCdiZuQ20Is8BM/VgDFZBVH9Q6TB28f25UIJAIxfh3eWFXYtzocdvXk/bsmoonAf41Vkf8BWj+x3livL5wMJYPxULgl3BMLtoSdPckARylZlYi6eIeWbv0E6HonzH4uOPI0ML3uZUjH1DBwaf2jrEL/+xvNRFDx46DCmvoT2nsVsvzUaR1RRvFn2ll/LxMYn61hqWrY4cItPytrnkb2D7GLZc8C8cgXvDMr7mHdo/fSE71vAlI+xSrleNimrEWX2egqVinbOQb8Wr8ZEux+E9I2tlTpdZnS1hOAatqhkS8AE1O6wTmeVWzoYKVO2Qp8q8PHo7uVpnyNN+jTMGV0sOkjQ29YoiiR74nrhwu07Fz2vPpD06tiIXuSryqXNx7KVb62Y7GQciqP+y/xuZ6sAHicY2BgYGQAgpOd+YYg+kzUungYDQBCrQZaAAB4nGNgZGBg4ANiCQYQYGJgBEJWIGYB8xgABIEAOAAAAHicY2BmYmCcwMDKwMHow5jGwMDgDqW/MkgytDAwMDGwMjPAAKMAAwIEpLmmMDgwOH5gYGT4z8CgxwikG4BqoEoZGBSAkBEAuiEIwwB4nGNgYGBmgGAZBkYGEEgB8hjBfBYGDyDNx8DBwMTABmQ5MjgzBDGEfGD4/x+sEoX///D/A/83/F8rwAo1BwkwAnVjCJIKWMCuRAJMlJtJRwAA2gwQRgAAeJxjYGRgYADikridUvH8Nl8ZuJkYQOBM1Lp4BP2fgQmkiIGBgwEsDQAJ0gjGAAAAeJxjYGRgYGT4z8Cgx8TAwPCPgQnERQVsADlqAjkAAAB4nGNiYGBgYmBQgGIwG0gxAAAFGABrAAAAAFAAAAYAAHicdY49asNAEIU/2bJDSAipQsqFNGkkpK2MD6ADBONemEUYhBbWNvgkrnKElDlGDpAj5Bh5UqZJ4R1m99vHmx/gngsZ48m44dF4Jn41nvPC2TiX/mG84I4v46X0Hzmz/FbKw1Q18kz8bDynoTLOpb8bL3ji03gp/ZsdLT0boqKHXdtvYhS8Eeg4SWtJ+obu1LeCRr6B4/QmOQIOT6lpjrXyf78/zSsKVkovX62bJg7HJqYuOF9Wbu1srsj7YlX4qpbp2m5bTU0c2E+7OHUc57MN6bCPg6vL6mrtL4A3OKcAeJxjYGbACwAAfQAE) format("woff");\
font-weight: normal;\
font-style: normal;\
}\
#main { font-family:Arial; font-size: 12px; color: #555; }\
dl { padding: 0px 5px 5px; margin:0 0 20px; max-height: 400px; overflow-y:auto; overflow-x:hidden; }\
dt { padding: 0; line-height:1.5em; white-space: nowrap; border-radius: 5px; }\
dt::before { display: inline-block; width: 1.25em; height: 1.25em; margin-right: 0.25em; background-size: contain; background-repeat: no-repeat; background-position: center center; position:relative; top:2px; content:""; opacity:0.5; }\
dt.Maternity::before { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9Ijc1LjkxNHB4IiBoZWlnaHQ9IjEwMHB4IiB2aWV3Qm94PSIwIDAgNzUuOTE0IDEwMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgNzUuOTE0IDEwMCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxjaXJjbGUgY3g9IjM3Ljk1NyIgY3k9IjE2LjM5NiIgcj0iMTYuMzk2Ii8+CjxwYXRoIGQ9Ik03My4yMDgsNTkuMjI4Yy0xLjgwMS0zLjg1OS00LjQxNC04LjE5OS02LjQ5Mi0xMS42ODFjLTMuMzU0LTUuNjIxLTcuMDcyLTEwLjEwOS0xNC44NjktMTAuMTA5ICBjLTIuNjMsMC0xMS41ODItMC4wMDEtMjUuNDE3LTAuMDAxYy0xMS45NzEsMC0xNi4yOTgsMTIuNDAzLTIwLjEwMywxOS41ODlDMy40MzIsNjIuNDk1LDAuMjg0LDcwLjksMC4wMjksNzUuNTY5ICBjLTAuNTIsOS41MDksNi4wODksMTUuNzMzLDcuMTA5LDE2LjQ2MmM1LjM0LDMuODEyLDExLjUzOSw3LjA1MywyMS42NzgsNy44OThjNy41NDksMC42MjgsMTQuMzcxLTMuMDMsMTUuMDY3LTcuMjAzICBjMC44MjUtNC45NTUtMi4zMjEtOC40MDctOC44MS04LjExNGMtMTAuMTQ2LDAuNDU4LTE2LjcxNC0yLjUxNy0xOC42OTYtMy41MDdjLTUuMDA4LTIuNTA0LDAuOTc5LTIuNDExLDIuMjQ4LTIuNTA5ICBjMy4xNDgtMC4yNDIsNi4yOTYtMC45NjksNy44NjktMi4zMDFjMS42MTQtMS4zNjYsMC4xNTMtMC45NDUtMS45NC03LjQ4NGMtMS41OTctNC45ODcsMC43MDUtNy4wNzEsMS45NjYtNy40ODMgIGMzLjEwOC0xLjAxNiw0Ljg5OSwwLjM1NSw2LjczOSwzLjcxOWMxLjIzNywyLjI2MSwyLjg2LDQuNzMyLDMuNzE3LDUuNzExYzEuMjY5LDEuNDUxLDIuMTg1LDMuMDgxLDQuODAzLDQuNjQ3ICBjMi4xNSwxLjI4Nyw0LjcwOCwyLjEwNiw2LjgxNCwyLjIyOWMyLjE0OSwwLjEyNywyLjAzNCwwLjAyMiwzLjk5Ni0wLjMyMmMtMi4wOTMsMS45NjYtOS4zMjgsNy4wMzktNC4zMTMsMTIuNDMyICBjMi42NjMsMi44NjUsOC42MywxLjc2NiwxMS40MjUsMC42NzlzNy42MDctNC40MDQsMTEuNzI5LTkuNTFDNzkuNDEsNzEuMDMsNzQuNTg0LDYyLjE3Niw3My4yMDgsNTkuMjI4eiBNNTAuNTczLDc1LjM0OCAgYy02LjI5LDAtMTEuMzkxLTUuMS0xMS4zOTEtMTEuMzkyYzAtNi4yOTEsNS4xMDEtMTEuMzkyLDExLjM5MS0xMS4zOTJjNi4yOTIsMCwxMS4zOTIsNS4xMDEsMTEuMzkyLDExLjM5MiAgQzYxLjk2NCw3MC4yNDgsNTYuODY1LDc1LjM0OCw1MC41NzMsNzUuMzQ4eiIvPgo8L3N2Zz4=); }\
dt.SicknessDoctor::before { top:4px; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBpZD0ic3ZnNjU4NCI+CiAgPGRlZnMgaWQ9ImRlZnM2NTg2Ii8+CiAgPG1ldGFkYXRhIGlkPSJtZXRhZGF0YTY1ODkiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZSByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIi8+CiAgICAgICAgPGRjOnRpdGxlLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtOTUyLjM2MikiIGlkPSJsYXllcjEiPgogICAgPHBhdGggZD0ibSA0My43NSw5NzEuMTEyMDYgYyAtMi4zMDgzMzMsMCAtNC4xNjY2NjcsMS44NTgzMyAtNC4xNjY2NjcsNC4xNjY2NiBsIDAsMTYuNjY2NjYgLTE2LjY2NjY2NiwwIGMgLTIuMzA4MzM0LDAgLTQuMTY2NjY3LDEuODU4MzMgLTQuMTY2NjY3LDQuMTY2NjYgbCAwLDEyLjQ5OTk2IGMgMCwyLjMwODQgMS44NTgzMzMsNC4xNjY3IDQuMTY2NjY3LDQuMTY2NyBsIDE2LjY2NjY2NiwwIDAsMTYuNjY2NiBjIDAsMi4zMDgzIDEuODU4MzM0LDQuMTY2NiA0LjE2NjY2Nyw0LjE2NjYgbCAxMi41LDAgYyAyLjMwODMzNCwwIDQuMTY2NjY3LC0xLjg1ODMgNC4xNjY2NjcsLTQuMTY2NiBsIDAsLTE2LjY2NjYgMTYuNjY2NjY3LDAgYyAyLjMwODMzMywwIDQuMTY2NjY2LC0xLjg1ODMgNC4xNjY2NjYsLTQuMTY2NyBsIDAsLTEyLjQ5OTk2IGMgMCwtMi4zMDgzMyAtMS44NTgzMzMsLTQuMTY2NjYgLTQuMTY2NjY2LC00LjE2NjY2IGwgLTE2LjY2NjY2NywwIDAsLTE2LjY2NjY2IGMgMCwtMi4zMDgzMyAtMS44NTgzMzMsLTQuMTY2NjYgLTQuMTY2NjY3LC00LjE2NjY2IHoiIGlkPSJyZWN0ODIwNi00IiBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjI7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIvPgogIDwvZz4KPC9zdmc+); }\
dt.period, dt.returning { background:rgba(243, 243, 243, .85); margin-bottom: 2px; }\
dt.period:hover, dt.returning:hover { background:rgba(223, 223, 223, 1); }\
dt.period, dt.returning, dt.period label, dt.returning label { cursor:pointer; }\
dt.period { background:rgba(255, 243, 243, .85); }\
dt.period:hover { background:rgba(235, 223, 223, 1); }\
dt.period label::after, dt.returning label::after { content: " +"; }\
dd { text-indent: 2em; padding: 0; margin:0 0 5px; display:none; }\
dt:last-of-type + dd, dt:last-child {\
margin-bottom: 20px;\
}\
label { display: inline-block; margin:0; padding:0; width:100%; }\
input:checked + dd { display:block; }\
input[type=checkbox] { display:none; }\
#options { white-space: nowrap; margin: 0 0 1ex; padding: 0 18px 6px; font-size:0; }\
#options li { opacity: 0.25; list-style: none; display: inline-block; overflow-x: hidden; cursor:pointer; margin-left: 6px; font-size: 15px; font-family:calTool; font-style:normal; speak:none; padding: 0; }\
.byAlpha {}\
.byReturn {pointer: default;}\
.byReturn::after {content: ""; border-left:1px #555 dashed; margin-left:6px; cursor:default; }\
.byToday {}\
.byCalendar {pointer: default;}\
.byAlpha:active, .byToday:active {color: red;}\
::-webkit-scrollbar-thumb { background-color: rgba(0, 0, 0, .2); background-clip: padding-box; border: solid transparent; border-width: 0 0 0 7px; min-height: 28px; box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1), inset -1px -1px 0 rgba(0, 0, 0, .07); }\
::-webkit-scrollbar { width: 16px; height: 16px; }\
::-webkit-scrollbar-button { width: 0; height: 0; display: none; }\
::-webkit-scrollbar-corner { background-color: transparent; }\
::-webkit-scrollbar-track { background-clip: padding-box; border: solid transparent; border-width: 0 0 0 7px; }\
</style>\
<div id="main">\
<ul id="options">\
<li class="byAlpha" title="Sort Alphabetically">A</li>\
<li class="byReturn" title="Sort By Return Date">R</li>\
<li class="byToday" title="Show Absences Today">T</li>\
<li class="byCalendar" title="Show Absences for Calendar Range">C</li>\
</ul>\
';
var xmlEnd = '\
</div>\
<script>\
gadgets.window.adjustHeight();\
</script>\
]]></Content> \
</Module>';
if (typeof absenceData !== "undefined") {
content="<dl>";
absenceData.sort(sortnames);
for (row in absenceData) {
var dataRow = absenceData[row];
var now = new Date();
var then = new Date(dataRow['end']);
if (then > now) {
content += "<dt class='" + dataRow['title'].replace(/[^a-zA-z0-9]/gi,"") + " ";
content += (dataRow['period'])? "period " : "";
content += (dataRow['returning'])? "returning " : "";
content += "'><label for='row" + row + "' onclick='gadgets.window.adjustHeight();'>" + dataRow['name'] + "</label></dt>";
if (dataRow['period']) {
content += "<input type='checkbox' id='row" + row + "' /><dd>" + dataRow['period'] + "</dd>";
} else if (dataRow['returning']) {
content += "<input type='checkbox' id='row" + row + "' /><dd>Returning: " + dataRow['returning']+"</dd>";
}
}
}
content += "</dl>";
}
var xmlContent = xmlStart + content + xmlEnd;
xmlGadget.replace(xmlContent);
return xmlContent;
}
function cacheBuster() {
var cache = CacheService.getPublicCache();
cache.removeAll(['out','xml','absences'])
}
function sortnames(a,b) {
if (a.firstname < b.firstname) {
return -1;
} else if (a.firstname > b.firstname) {
return 1;
} else {
return 0;
}
}
/**
* Parses the passed string (event title) to determine whether to list person as sick, vacation, conference or out (default)
*/
function getEventType(theevent) {
var eventType = "Out";
if (theevent.search(/sick|doctor|dr\.|dentist|dental|surgery|hospital|gp|medical/i)>-1) {
eventType = "Sickness/Doctor";
} else if (theevent.search(/on leave|vacation|annual|.*?holiday|hols|day\soff/i)>-1) {
eventType = "Annual leave";
} else if (theevent.search(/maternity/i)>-1) {
eventType = "Maternity";
} else if (theevent.search(/part\-time|part time|pt/i)>-1) {
eventType = "Non Work-day";
} else if (theevent.search(/parental/i)>-1) {
eventType = "Parental Leave";
} else if (theevent.search(/sab|sabbatical/i)>-1) {
eventType = "Sabbatical";
} else if (theevent.search(/training|conference|lecture|seminar|forum|network/i)>-1) {
eventType = "Training/Conference";
}
return eventType
}
/**
* Gathers absence information from the invited absence calendar
*/
function gatherAbsences(dayToday) {
var cache = CacheService.getPublicCache();
var cached = JSON.parse(cache.get('absences'));
if (cached != null) {
return cached;
}
var calDet = ScriptProperties.getProperty("absenceID");
var absencecal = CalendarApp.getCalendarById(calDet);
if (typeof dayToday == "undefined") {
var startOfDay = new Date();
} else {
var startOfDay = dayToday;
}
startOfDay.setUTCHours(0);
startOfDay.setMinutes(0);
startOfDay.setSeconds(0);
startOfDay.setMilliseconds(0);
var endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000);
var absenceEvents = absencecal.getEvents(startOfDay, endOfDay)
var absenceList = [];
for (event in absenceEvents) {
var absenceRow = {};
eventDetail = absenceEvents[event];
absenceRow["start"] = eventDetail.getStartTime();
absenceRow["end"] = eventDetail.getEndTime();
guestList = eventDetail.getGuestList();
var eventCreator = eventDetail.getCreators()[0];
var eventUser = "";
try {
eventUser = UserManager.getUser(eventCreator.slice(0,eventCreator.search("@")));
} catch(err) {
eventUser = eventCreator;
}
if (guestList.length === 0) {
absenceRow["name"] = (eventUser !== eventCreator) ? UserManager.getUser(eventUser) : eventUser;
} else {
for (guest in guestList) {
name = guestList[guest].getName();
if (name !== "Absence Calendar" && guestList[guest].getGuestStatus() != "NO" && guestList[guest].getEmail().search(/@alliesandmorrison\.com/i)>-1 && name.search(/@amwb\.co\.uk/i) == -1) {
absenceRow["name"] = name;
}
}
if (!absenceRow["name"]) {
var calendarId = eventDetail.getOriginalCalendarId().slice(0,eventDetail.getOriginalCalendarId().search("@"))
var userName;
try {
userName = UserManager.getUser(calendarId);
}
catch (err) {
eventCreator = eventDetail.getCreators()[0];
calendarId = eventCreator.slice(0,eventCreator.search("@"));
userName = UserManager.getUser(calendarId);
}
var calendarAsGuest =
userName.getGivenName()
+ " "
+ userName.getFamilyName();
absenceRow["name"] = (eventUser !== eventCreator) ? calendarAsGuest : eventUser;
}
}
absenceRow["title"] = getEventType(eventDetail.getTitle());
absenceRow["firstname"] = absenceRow["name"].toString().split(" ")[0];
if (absenceRow['name'] != "Absence Calendar") {
absenceList.push(absenceRow);
}
}
cache.put('absences',JSON.stringify(absenceList),7100); // cache for just under 15 minutes
return absenceList;
};
/**
* Creates the single Who is out post from the absence calendar
*/
function whoIsOut(doFile) {
var cache = CacheService.getPublicCache();
var cached = cache.get('out');
if (cached != null) {
return JSON.parse(cached);
}
var today = new Date();
var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
var cal = CalendarApp.getCalendarById(ScriptProperties.getProperty("absenceList"));
var startOfDay = new Date();
startOfDay.setUTCHours(0);
startOfDay.setMinutes(0);
startOfDay.setSeconds(0);
startOfDay.setMilliseconds(0);
var endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000);
var absenceEvents = cal.getEvents(startOfDay, endOfDay)
var entryDate = today;
var absences = gatherAbsences(today);
var descriptionRow = "";
var description = "";
for (var row in absences) {
var absentee = absences[row];
absentee["end"] = new Date(absentee["end"]);
absentee["start"] = new Date(absentee["start"]);
var duration = (absentee["end"]-absentee["start"]) / (24 * 60 * 60 * 1000);
var endDay = 0;
endDay += (absentee["end"].getUTCDay() == 6) ? 2 : (absentee["end"].getUTCDay() == 1) ? 1 : (absentee["end"].getUTCDay() == 0) ? 1 : 0;
var endDate = new Date(absentee["end"]);
endDate = new Date(endDate.getUTCFullYear(), endDate.getUTCMonth(), endDate.getUTCDate() + endDay); // create new increased date
descriptionRow = absentee["name"] + " (" + absentee["title"]+ ") ";
var dst = (DST()) ? 1 : 0;
if (duration <= 0.3) {
var startHours = absentee["start"].getUTCHours() + dst
var endHours = absentee["end"].getUTCHours() + dst
descriptionRow += " - " + pad(startHours,2) + ":" + pad(absentee["start"].getUTCMinutes(),2) + "-" + pad(endHours,2) + ":" + pad(absentee["end"].getUTCMinutes(),2);
absences[row]['period'] = pad(startHours,2) + ":" + pad(absentee["start"].getUTCMinutes(),2) + "-" + pad(endHours,2) +":" + pad(absentee["end"].getUTCMinutes(),2);
} else if (duration > 1) {
if (absentee["title"].search(/non/i) == -1) {
descriptionRow += " - Returning " + endDate.getUTCDate() + " " + months[endDate.getUTCMonth()];
absences[row]['returning'] = endDate.getUTCDate() + " " + months[endDate.getUTCMonth()];
}
}
description += descriptionRow + "\n";
}
var updated = "\nLast Updated: " + new Date().toLocaleString();
description += updated;
var eventDetails = {location: "London", description: description}
var now = new Date();
var title = "Who is out";// - (updated: " + (now.getUTCHours() + dst) + ":" + now.getUTCMinutes() +")";
debugger;
if (absenceEvents.length == 0) {
var event = cal.createAllDayEvent(title, entryDate, eventDetails)
} else {
absenceEvents[0].setDescription(description)
absenceEvents[0].setTitle(title)
}
if (doFile !== 'nofile') {
writeXML(description,absences);
}
var outList = {'description':description, 'absencelist': absences};
cache.put('out',JSON.stringify(outList),7100); // cache for just under 15 minutes
return outList;
}
function pad(number, length) {
var str = '' + number;
while (str.length < length) {
str = '0' + str;
}
return str;
}
function DST(){
var today = new Date;
var yr = today.getFullYear();
var dst_start = new Date("March 14, "+yr+" 02:00:00"); // 2nd Sunday in March can"t occur after the 14th
var dst_end = new Date("November 07, "+yr+" 02:00:00"); // 1st Sunday in November can"t occur after the 7th
var day = dst_start.getDay(); // day of week of 14th
dst_start.setDate(14-day); // Calculate 2nd Sunday in March of this year
day = dst_end.getDay(); // day of the week of 7th
dst_end.setDate(7-day); // Calculate first Sunday in November of this year
if (today >= dst_start && today < dst_end){ //does today fall inside of DST period?
return true; //if so then return true
}
return false; //if not then return false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment