Created
May 31, 2013 11:56
-
-
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.
This file contains 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
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="[email protected]" \ | |
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,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) 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