aboutsummaryrefslogtreecommitdiff
path: root/apps/calendar
diff options
context:
space:
mode:
Diffstat (limited to 'apps/calendar')
-rw-r--r--apps/calendar/css/charms.css195
-rw-r--r--apps/calendar/img/close-light.pngbin0 -> 3786 bytes
-rw-r--r--apps/calendar/img/close.pngbin0 -> 3516 bytes
-rw-r--r--apps/calendar/img/left-light.pngbin0 -> 3572 bytes
-rw-r--r--apps/calendar/img/left.pngbin0 -> 3644 bytes
-rw-r--r--apps/calendar/img/plus-light.pngbin0 -> 3525 bytes
-rw-r--r--apps/calendar/img/plus.pngbin0 -> 3597 bytes
-rw-r--r--apps/calendar/img/right-light.pngbin0 -> 3667 bytes
-rw-r--r--apps/calendar/img/right.pngbin0 -> 3711 bytes
-rw-r--r--apps/calendar/index.html170
-rw-r--r--apps/calendar/lib.js585
-rw-r--r--apps/calendar/splashscreen.pngbin0 -> 3038 bytes
-rw-r--r--apps/calendar/style.css498
13 files changed, 1448 insertions, 0 deletions
diff --git a/apps/calendar/css/charms.css b/apps/calendar/css/charms.css
new file mode 100644
index 0000000..54337b7
--- /dev/null
+++ b/apps/calendar/css/charms.css
@@ -0,0 +1,195 @@
+body {
+ font-family:Segoe UI;
+ margin:0px;
+ padding:0px;
+}
+img, a {
+ outline:none;
+ border:none;
+}
+#splashscreen {
+ position:fixed;
+ width:100%;
+ height:100%;
+ color:#FFFFFF;
+ background-image:url('../splashscreen.png');
+ background-position:center;
+ background-color:#5133AB;
+ background-repeat:no-repeat;
+ animation:splash 4s;
+ -ms-animation:splash 4s;
+ -webkit-animation:splash 4s;
+ -o-animation:splash 4s;
+ opacity:0;
+ z-index:-1;
+}
+@keyframes splash {
+ from {
+ z-index:2;
+ opacity: 1;
+ }
+ 66% {
+ opacity: 1;
+ }
+ to {
+ opacity:0;
+ z-index:1;
+ display:none;
+ }
+}
+@-webkit-keyframes splash {
+ from {
+ z-index:2;
+ opacity: 1;
+ }
+ 66% {
+ opacity: 1;
+ }
+ to {
+ opacity:0;
+ z-index:1;
+ display:none;
+ }
+}
+@-ms-keyframes splash {
+ from {
+ z-index:2;
+ opacity: 1;
+ }
+ 66% {
+ opacity: 1;
+ }
+ to {
+ opacity:0;
+ z-index:1;
+ display:none;
+ }
+}
+@-o-keyframes splash {
+ from {
+ z-index:2;
+ opacity: 1;
+ }
+ 66% {
+ opacity: 1;
+ }
+ to {
+ opacity:0;
+ z-index:1;
+ display:none;
+ }
+}
+#hoverarea {
+ position:fixed;
+ top:0px;
+ right:0px;
+ width:15px;
+ height:15px;
+}
+#bottomhoverarea {
+ position:fixed;
+ bottom:0px;
+ right:0px;
+ width:15px;
+ height:15px;
+}
+#starthoverarea {
+ position:fixed;
+ bottom:0px;
+ left:0px;
+ width:15px;
+ height:15px;
+}
+#charmsbar {
+ display:none;
+ background-color:#111111;
+ position:fixed;
+ padding:5% 0;
+ top:0px;
+ right:0px;
+ height:100%;
+ width: 86px;
+
+}
+#settingscharms {
+ padding : 40px;
+ display:none;
+ background-color:#5133AB;
+ position:fixed;
+ top:0px;
+ right:0px;
+ height:100%;
+ width: 345px;
+ font-size:9pt;
+ color:#FFFFFF !important;
+}
+#settingscharms a {
+ color:#FFFFFF !important;
+}
+#startbutton {
+ display:none;
+ position:fixed;
+ left:0px;
+ bottom:0px;
+}
+#iconnetwork {
+ position:absolute;
+ top:35px;
+ left:25px;
+}
+#iconbattery {
+ position:absolute;
+ bottom:35px;
+ left:32px;
+}
+#datetime {
+ display:none;
+ position:fixed;
+ left:50px;
+ bottom:50px;
+ width:490px;
+ height:139px;
+ background-color: rgba(17,17,17,1);
+}
+#ctime {
+ position:absolute;
+ left:70px;
+ bottom:19px;
+ font-family: Segoe UI Light;
+ font-size: 64pt;
+ color:#FFFFFF;
+}
+#date {
+ margin-top:20px;
+ margin-right:20px;
+ float:right;
+ font-size:24pt;
+ font-family: Segoe UI;
+ color:#FFFFFF;
+}
+.cheading1 {
+ font-family:Segoe UI Semilight;
+ font-size:28px;
+ margin-bottom:25px;
+ display:block;
+}
+.cheading2 {
+ font-size:11pt;
+ margin-bottom:25px;
+ display:block;
+}
+.cheading2d {
+ font-size:11pt;
+ color:#A8A8A8;
+ margin-bottom:25px;
+ display:block;
+}
+#settingscharms a {
+ display:block;
+ margin-bottom:25px;
+}
+.closecharms {
+ width:32px;
+ height:32px;
+ float:right;
+} \ No newline at end of file
diff --git a/apps/calendar/img/close-light.png b/apps/calendar/img/close-light.png
new file mode 100644
index 0000000..3ede172
--- /dev/null
+++ b/apps/calendar/img/close-light.png
Binary files differ
diff --git a/apps/calendar/img/close.png b/apps/calendar/img/close.png
new file mode 100644
index 0000000..7173f58
--- /dev/null
+++ b/apps/calendar/img/close.png
Binary files differ
diff --git a/apps/calendar/img/left-light.png b/apps/calendar/img/left-light.png
new file mode 100644
index 0000000..b581ca9
--- /dev/null
+++ b/apps/calendar/img/left-light.png
Binary files differ
diff --git a/apps/calendar/img/left.png b/apps/calendar/img/left.png
new file mode 100644
index 0000000..02d77e1
--- /dev/null
+++ b/apps/calendar/img/left.png
Binary files differ
diff --git a/apps/calendar/img/plus-light.png b/apps/calendar/img/plus-light.png
new file mode 100644
index 0000000..40039c0
--- /dev/null
+++ b/apps/calendar/img/plus-light.png
Binary files differ
diff --git a/apps/calendar/img/plus.png b/apps/calendar/img/plus.png
new file mode 100644
index 0000000..19d9cf6
--- /dev/null
+++ b/apps/calendar/img/plus.png
Binary files differ
diff --git a/apps/calendar/img/right-light.png b/apps/calendar/img/right-light.png
new file mode 100644
index 0000000..0bb359b
--- /dev/null
+++ b/apps/calendar/img/right-light.png
Binary files differ
diff --git a/apps/calendar/img/right.png b/apps/calendar/img/right.png
new file mode 100644
index 0000000..e915318
--- /dev/null
+++ b/apps/calendar/img/right.png
Binary files differ
diff --git a/apps/calendar/index.html b/apps/calendar/index.html
new file mode 100644
index 0000000..fbe49c8
--- /dev/null
+++ b/apps/calendar/index.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+ <title>Calendar</title>
+ <meta charset="utf-8" />
+ <meta http-equiv="x-ua-compatible" content="IE=edge">
+ <link href="style.css" rel="stylesheet" type="text/css" />
+ <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.min.js"></script>
+ <script src="lib.js"></script>
+ <!--Stylesheet that styles the charms bar and the startbutton -->
+ <link rel="stylesheet" href="css/charms.css"/>
+ <!--Script that powers the charms bar-->
+ <script>
+function charms(){
+ document.getElementById('charmsbar').style.display='block';
+ document.getElementById('datetime').style.display='block';
+ document.getElementById('ctime').style.display='inline';
+}
+function destroycharms() {
+ document.getElementById('charmsbar').style.display='none';
+ document.getElementById('datetime').style.display='none';
+ document.getElementById('ctime').style.display='none';
+}
+function start(){
+ document.getElementById('startbutton').style.display='block';
+}
+function destroystart() {
+ document.getElementById('startbutton').style.display='none';
+}
+ </script>
+<script>
+var settingscharms = 'document.getElementById('settingscharms')'
+</script>
+</head>
+<body class="dark">
+<div id="splashscreen"></div>
+<div id="calendar-wrap" class="box">
+ <div id="calendar">
+ <h1 id="calendar-title"> </h1>
+ <ul id="controls">
+ <li><a href="#" id="btn-previous"></a></li>
+ <li><a href="#" id="btn-today">Today</a></li>
+ <li><a href="#" id="btn-next"></a></li>
+ </ul>
+ <div class="clear"> </div>
+ <h3 id="time"> </h3>
+ <table id="table">
+ <thead>
+ </thead>
+ <tbody>
+ </tbody>
+ </table>
+ <div class="clear"> </div>
+ <span id="stats"></span>
+ <!--<p class="info">
+ Click on a date to view events. Use arrow keys to browser the calendar.
+ </p>
+ <div class="clear"> </div-->
+ </div>
+ <div class="clear"> </div>
+</div>
+
+<div id="diary-wrap" class="box">
+ <div class="content">
+ <a href="#" id="diary-close"></a>
+ <h2 id="diary-title">&nbsp;</h2>
+ <div class="clear"> </div>
+
+ <ul id="diary"></ul>
+ <p class="info">Click on a time to add an event</p>
+ </div>
+</div>
+
+<div id="dialog">
+ <a href="" id="dialog-close"/></a>
+ <form id="add" class="target">
+ <h2 id="event-date"></h2>
+ <p class="time">
+ <label>Event time</label>
+ Hour <select id="event-hour"></select>
+ Minute <select id="event-minute"></select>
+ </p>
+ <p>
+ <label>Event description</label>
+ <input type="text" id="event-description" maxlength="100" />
+ </p>
+ <div id="event-label">
+ </div>
+ <p class="buttons">
+ <input type="submit" id="event-create" value="ok" class="button" />
+ <input type="button" id="event-close" value="cancel" class="button" />
+ <input type="button" id="event-delete" value="delete" class="button" />
+ <input type="button" id="event-tweet" value="tweet" class="button" />
+ </p>
+ </form>
+
+ <div id="ical2" class="target">
+ Copy the text and save it as calendar.ics file.<br />
+ <small>You can then import the file to Google Calendar, iCal etc.</small>
+ <textarea id="ical-data2"> </textarea>
+ </div>
+</div>
+<div class="clear"> </div>
+ <!-- CHARMS BAR CODE -->
+<div id="hoverarea" onmouseover="charms()" class="hotcorner">
+</div>
+<div id="charmsbar" onmouseover="charms()" onmouseout="destroycharms()">
+<img src="../../common/img/charmsbar/search.png" onmouseover="this.src='../../common/img/charmsbar/search-hover.png'" onmouseout="this.src='../../common/img/charmsbar/search.png'"/><br/>
+<img src="../../common/img/charmsbar/share.png" onmouseover="this.src='../../common/img/charmsbar/share-hover.png'" onmouseout="this.src='../../common/img/charmsbar/share.png'"/><br/>
+<a href="../../start/index.html"><img src="../../common/img/charmsbar/start.png" onmouseover="this.src='../../common/img/charmsbar/start-hover.png'" onmouseout="this.src='../../common/img/charmsbar/start.png'"/></a><br/>
+<img src="../../common/img/charmsbar/devices.png" onmouseover="this.src='../../common/img/charmsbar/devices-hover.png'" onmouseout="this.src='../../common/img/charmsbar/devices.png'"/><br/>
+<img src="../../common/img/charmsbar/settings.png" onmouseover="this.src='../../common/img/charmsbar/settings-hover.png'" onmouseout="this.src='../../common/img/charmsbar/settings.png'" onclick="settingscharms.style.display='block'"/><br/>
+</div>
+<div id="datetime">
+<img src="../../common/img/network.png" id="iconnetwork" height="24px" width="24px"/>
+<img src="../../common/img/battery.png" id="iconbattery"/>
+<span id="ctime"></span>
+<script language="javascript" type="text/javascript">
+<!-- Begin
+function clock() {
+var digital = new Date();
+var hours = digital.getHours();
+var minutes = digital.getMinutes();
+var seconds = digital.getSeconds();
+var amOrPm = "AM";
+if (hours > 11) amOrPm = "PM";
+if (hours > 12) hours = hours - 12;
+if (hours == 0) hours = 12;
+if (minutes <= 9) minutes = "0" + minutes;
+if (seconds <= 9) seconds = "0" + seconds;
+dispTime = hours + ":" + minutes ;
+document.getElementById('ctime').innerHTML = dispTime;
+setTimeout("clock()", 1000);
+}
+window.onload=clock;
+// End -->
+</script>
+<div id="date"><script language="Javascript">
+
+ var dayName = new Array ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
+
+ var monName = new Array ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")
+
+ var now = new Date
+
+ document.write("" + dayName[now.getDay()] + "<br/>" +"<span id=month>" + monName[now.getMonth()] + " "+now.getDate() +"")
+ </script>
+</div>
+</div>
+<div id="bottomhoverarea" onmouseover="charms()" class="hotcorner">
+</div>
+<div id="starthoverarea" onmouseover="start()" class="hotcorner">
+</div>
+<div id="startbutton" onmouseout="destroystart()">
+<a href="../../start/index.html"><img src="../../common/img/start.png"/></a>
+</div>
+<div id="settingscharms">
+<img src="img/close.png" class="closecharms" onclick="settingscharms.style.display='none'"/>
+<span class="cheading1">Settings</span>
+<span class="cheading2d">Calendar</span>
+<span class="cheading2">Theme</span>
+<a href="#" id="btn-theme">light</a>
+<span class="cheading2">Get as iCal</span>
+<a href="#" id="btn-ical">Click here to show code</a>
+<div id="ical">
+<textarea id="ical-data"></textarea>
+</div>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/apps/calendar/lib.js b/apps/calendar/lib.js
new file mode 100644
index 0000000..43327cc
--- /dev/null
+++ b/apps/calendar/lib.js
@@ -0,0 +1,585 @@
+/*
+ Simple Planner
+ A localStorage based personal planner prototype
+ Made for 10K Apart
+
+ Kailash Nadh, http://kailashnadh.name (August 2011)
+*/
+var Planner = {
+ DAYS: ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday', 'Sunday'],
+ MONTHS: ['January','February','March','April','May','June','July','August','September','October','November','December'],
+ LABELS: ['todo', 'personal', 'work', 'important', 'misc'],
+ Date: new Date(),
+ UI: null,
+ EVENTS: {},
+ diary_open: false,
+
+ init: function() {
+ this.EVENTS = localStorage['events'];
+ if(!this.EVENTS) {
+ this.EVENTS = {};
+ if(!localStorage.setup) {
+ // initial setup
+ var holidays = {'1-0': 'New Year', '8-2': 'Commonwealth Day', '17-2': 'St. Patrick\'s Day', '1-3': 'April fools', '22-3': 'Earth Day', '1-4': 'May Day', '5-4': 'Cinco de Mayo', '4-6': 'Independence Day (US)', '3-7': 'Friendship Day', '10-7': 'Rollercoaster Day', '17-8': 'International Day of Peace', '16-9': 'World Food Day', '31-9': 'Halloween', '4-10': 'Diwali', '17-10': 'World Peace Day', '22-10': 'Thanksgiving', '25-11': 'Christmas'};
+
+ for(var year=this.Date.getFullYear(); year<=this.Date.getFullYear()+1; year++) {
+ for(var id in holidays) {
+ this.createEvent(
+ id + '-' + year,
+ '00',
+ '00',
+ holidays[id],
+ 'misc'
+ );
+ }
+ }
+
+ // random entries
+ for(var i=0; i<7; i++) {
+ this.createEvent(
+ Math.floor(Math.random()*28) + '-'+ this.Date.getMonth() + '-'+ this.Date.getFullYear(),
+ Math.floor(Math.random()*23).pad(2),
+ '00',
+ 'This is a dummy event. The number ' + i + ' is cool!',
+ this.LABELS[Math.floor(Math.random()*(this.LABELS.length-1))]
+ );
+ }
+ localStorage.setup = 1;
+ }
+ } else {
+ try{
+ this.EVENTS = JSON.parse(this.EVENTS);
+ } catch(e) {
+ localStorage.clear();
+ this.EVENTS = {};
+ }
+ }
+
+ this.phone = navigator.userAgent.match(/phone/i) || navigator.userAgent.match(/android/i);
+
+ this.setDate();
+ this.initUI();
+
+ // what month to render first?
+ var hash = document.location.href.match(/([0-9]{1,2})\-([0-9]{4})/i);
+ if(hash && hash[1] >= 1 && hash[1] <= 12 && hash[2] >= 1900 && hash[2] <= 2050) {
+ this.specificMonth(hash[1], hash[2]);
+ } else {
+ this.today();
+ }
+
+ // only load the diary on pageload if there's enough space to render it
+ Planner.renderDiary( $('.day' + this.date).data('id') );
+ this.UI.resize();
+
+ Planner.UI.diary_wrap.show();
+ var covered = (Planner.UI.diary_wrap.offset().left - Planner.UI.calendar_wrap.innerWidth());
+ Planner.UI.diary_wrap.hide();
+ if(!this.phone && covered > -35 && new Date().getMonth() == this.month ) {
+ Planner.showDiary();
+ }
+ },
+ initUI: function() {
+ this.UI = {
+ themes: ['Switch to dark theme', 'Switch to light theme'],
+ 'calendar': $('#calendar'),
+ 'dialog': $('#dialog'),
+ 'add': $('#add'),
+ 'calendar_wrap': $('#calendar-wrap'),
+ 'diary_wrap': $('#diary-wrap'),
+ 'event_label': $('#event-label'),
+ 'event_hour': $('#event-hour'),
+ 'event_minute': $('#event-minute'),
+ 'event_description': $('#event-description'),
+ 'event_delete': $('#event-delete'),
+ 'event_tweet': $('#event-tweet'),
+ 'diary': $('#diary')
+ };
+
+ // time in create event dialog
+ var val = '';
+ for(i=0; i<24; i++) {
+ val = i.pad(2);
+ this.UI.event_hour.append( $('<option value="'+val+'">').html(val) );
+ }
+ for(i=0; i<60; i+=15) {
+ val = i.pad(2);
+ val = val.substr(val.length-2);
+ this.UI.event_minute.append( $('<option value="'+val+'">').html(val) );
+ }
+
+ // label colors in create event dialog
+ var labels = $('<div class="labels">'), lbl = '';
+ for(var i in this.LABELS) {
+ lbl = this.LABELS[i];
+ labels.append( $('<label class="'+lbl+' label" for="label-'+lbl+'">'+lbl+' <input type="radio" name="event-label" value="'+lbl+'" id="label-'+lbl+'" class="'+ lbl +'"></label>') );
+ }
+ this.UI.event_label.append(labels);
+
+ // day names
+ var html = '';
+ for(var i=0; i<7; i++) {
+ html += '<td>'+this.DAYS[i]+'</td>';
+ }
+ $('thead').append( $('<tr>').html(html) );
+
+ // close add prompt
+ $('#event-close').click(function() {
+ Planner.closeAddPrompt();
+ });
+ $('#dialog-close').click(function() {
+ Planner.closeDialog();
+ return false;
+ });
+ $(document).keyup(function(e) {
+ if(e.altKey) return;
+
+ if (e.keyCode == 27) {
+ Planner.closeAddPrompt();
+ } else if (e.keyCode == 37) {
+ Planner.previousMonth();
+ } else if (e.keyCode == 39) {
+ Planner.nextMonth();
+ } else if (e.keyCode == 38 || e.keyCode == 40) {
+ Planner.today();
+ }
+ });
+
+
+ // event form add
+ this.UI.add.submit(function() {
+ Planner.createEvent(
+ Planner.new_id,
+ Planner.UI.event_hour.val(),
+ Planner.UI.event_minute.val(),
+ Planner.UI.event_description.val().replace(/<\/?(?!\!)[^>]*>/gi, ''),
+ Planner.UI.event_label.find('input[name="event-label"]:checked').val(),
+ Planner.event_i
+ );
+ Planner.closeAddPrompt();
+ Planner.renderEvents();
+ if(Planner.diary_open) {
+ Planner.renderDiary(Planner.new_id);
+ }
+ return false;
+ });
+
+ this.UI.event_delete.click(function() {
+ var id = $(this).data('id');
+ Planner.deleteEvent( id, $(this).data('i') );
+ Planner.closeDialog();
+ Planner.renderCalendar();
+ Planner.renderDiary(id);
+ return false;
+ });
+
+ this.UI.event_tweet.click(function() {
+ var id = $(this).data('id');
+ var tweet = Planner.EVENTS[id][$(this).data('i')];
+
+ window.open('http://twitter.com/home?status=' + escape(tweet.description + ' @ ' + tweet.hour + ':' + tweet.minute + ', ' + Planner.dateStringID(id)) );
+ return false;
+ });
+
+ // previous and next buttons
+ $('#btn-previous').click(function() {
+ Planner.previousMonth();
+ return false;
+ });
+ $('#btn-next').click(function() {
+ Planner.nextMonth();
+ return false;
+ });
+ $('#btn-today').click(function() {
+ Planner.today();
+ return false;
+ });
+
+ // theme
+ $('#btn-theme').click(function() {
+ var t = (parseInt($(this).data('theme'))+1) % 2;
+ localStorage.theme = t;
+
+ Planner.theme(t);
+ $(this).data('theme', t).html( Planner.UI.themes[ (t+1)%2 ] );
+ return false;
+ });
+ if(localStorage.theme) {
+ Planner.theme(localStorage.theme);
+ $('#btn-theme').data('theme', localStorage.theme).html( this.UI.themes[(parseInt(localStorage.theme)+1) % 2] );
+ } else {
+ $('#btn-theme').data('theme', 0 ).html( this.UI.themes[1] );
+ }
+
+ // ical
+ $('#ical-data').click(function() {
+ $(this).select();
+ });
+ $('#btn-ical').click(function() {
+ $('#ical-data').text(Planner.exportIcal());
+ return false;
+ });
+
+ // diary close
+ $('#diary-close').click(function() {
+ this.diary_open = true;
+ Planner.UI.diary_wrap.hide();
+ return false;
+ });
+
+ this.updateTime();
+ window.setInterval(function() {
+ Planner.updateTime();
+ }, 1000);
+
+ this.UI.resize = function() {
+ var wh = $(window).height(),
+ ww = $(window).width(),
+ ch = 0;
+ var min = ( Math.min(ww, wh) );
+ min = ( Math.max(min, 400) );
+
+ ch = min/1.2;
+ Planner.UI.calendar.width( ch + 105);
+ Planner.UI.calendar.height( ch + 105);
+
+ $('td').css('width', ch/7);
+
+ Planner.UI.diary_wrap.height('auto');
+ Planner.UI.calendar_wrap.height('auto');
+
+ var box_height = Math.max(Planner.UI.calendar_wrap.outerHeight(), Planner.UI.diary_wrap.outerHeight(), wh);
+
+ Planner.UI.calendar_wrap.height( box_height );
+ Planner.UI.diary_wrap.height( box_height );
+
+ Planner.UI.diary_wrap.width('auto');
+
+ if( Planner.UI.calendar_wrap.outerWidth() + Planner.UI.diary_wrap.outerWidth() > ww ) {
+ $('body').addClass('compact');
+ } else {
+ $('body').removeClass('compact');
+ }
+ };
+ $(window).resize(function() {
+ Planner.UI.resize();
+ });
+ },
+ renderCalendar: function() {
+ document.location.href = '#' + ( this.month+1 + '-' + this.year );
+
+ // rest of the days
+ var wn = 0,
+ tblweek = null,
+ table = $('<tbody class="month'+this.month+'">');
+
+ if(this.weekstart > 0) {
+ tblweek = $('<tr>').addClass('w0');
+
+ // blank days
+ for(var i=0; i<this.weekstart; i++) {
+ tblweek.append($('<td class="day">'));
+ }
+ table.append(tblweek);
+ wn++;
+ }
+
+ for(var d=1; d <=this.num_days; d++) {
+ var w = (this.weekstart+d-1)%7;
+ if(w == 0) { // new week
+ tblweek = $('<tr>');
+ table.append(tblweek);
+ wn++;
+ }
+
+ var id = d+'-'+this.month+'-'+this.year;
+ tblweek.append(
+ $('<td valign="top" class="day">').addClass('day'+d).addClass('day'+id)
+ .append( $('<div class="'+id+'">')
+ .append( $('<span class="d">').html(d) )
+ .append(
+ $('<a href="#" title="add an event" class="add"></a>')
+ .data('id', id)
+ .click(function() {
+ Planner.addPrompt($(this).data('id'));
+ return false;
+ })
+ )
+ ).data('id', id).click(function() {
+ Planner.renderDiary( $(this).data('id') );
+ Planner.showDiary();
+ })
+ );
+ }
+ $('#calendar-title').html(this.MONTHS[this.month] + ' ' + this.year);
+ $('tbody').replaceWith(table);
+
+ // today
+ $('.month' + new Date().getMonth() + ' .day' + this.date).addClass('today');
+ $('.month' + this.month + ' .day' + this.date).addClass('marked');
+
+
+ $('td.day').hover(function() {
+ $(this).find('.add').stop().animate({opacity: 1}, 300);
+ }, function() {
+ $(this).find('.add').stop().animate({opacity: 0}, 200);
+ });
+
+ this.renderEvents();
+ },
+ renderEvents: function() {
+ $('.d .events').remove();
+
+ for(var id in this.EVENTS) {
+ var ul = $('<ul>');
+ $.each(this.EVENTS[id], function() {
+ ul.append(
+ $('<li class="label '+this.label+'">').append(
+ $('<span class="time">' + this.hour + ':' + this.minute + '</span>')
+ ).append(
+ $('<span class="desc">' + this.description + '</span>')
+ )
+ );
+ });
+
+ $('.'+id).append(ul);
+ }
+
+ var stats = this.stats();
+ $('#stats').html( stats.future + ' upcoming events and ' + stats.past + ' past events' );
+ },
+ showDiary: function() {
+ this.diary_open = true;
+ this.UI.diary_wrap.show();
+ },
+ renderDiary: function(id) {
+ $('#diary li').remove();
+ $('#diary-title').html( this.dateStringID(id) );
+
+ $('.day').removeClass('selected');
+ $('.day'+id).addClass('selected');
+
+ for(var i=0; i<24; i++) {
+ var hour = ('0' + i);
+ hour = hour.substr(hour.length-2);
+
+ $('#diary').append(
+ $('<li>').append(
+ $('<a href="#" class="time">' + hour + ':00</a>').data({hour: hour, minute: '00'})
+ .data('hour', hour)
+ .click(function() {
+ Planner.addPrompt(id, null, $(this).data('hour'), '00');
+ return false;
+ })
+ ).append('<div class="clear"> </div>')
+ .addClass('hour'+hour)
+ );
+ }
+
+ if(!this.EVENTS[id]) return;
+
+ var removals={};
+ $.each(this.EVENTS[id], function(i) {
+ $('#diary .hour'+this.hour).after(
+ $('<li>').append(
+ $('<a href="#" class="time label '+this.label+'">' + this.hour + ':' + this.minute + '</a>')
+ .click(function() {
+ Planner.addPrompt(id, i);
+ return false;
+ })
+ ).append(
+ $('<span class="desc">' + this.description + '&nbsp;</span>')
+ ).append('<div class="clear"> </div>')
+ );
+ if(parseInt(this.minute) === 0) {
+ removals[this.hour] = true;
+ }
+ });
+
+ // remove redundant hours
+ for(var r in removals) {
+ $('#diary .hour' + r).remove();
+ }
+ },
+ dialog: function(target) {
+ this.UI.dialog.find('.target').hide();
+ target.show();
+
+ // position
+ this.UI.dialog.width( this.UI.calendar.width()/2 );
+ this.UI.dialog.css('top', ( $(window).height() - this.UI.dialog.height())/2)
+ .css('left', ( this.UI.calendar.width() - this.UI.dialog.width())/2);
+
+ this.UI.dialog.show();
+ },
+ closeDialog: function() {
+ this.UI.dialog.hide();
+ },
+ addPrompt: function(id, i, hour, minute) {
+ this.new_id = id;
+ this.event_i = null;
+
+ this.UI.event_description.val('');
+ this.UI.event_label.find('input:first').attr('checked', 'checked');
+
+ this.UI.event_tweet.hide();
+ this.UI.event_delete.hide();
+
+ // passing an existing item
+ if(id && i != null&& this.EVENTS[id][i]) {
+ this.UI.event_description.val( this.EVENTS[id][i].description );
+ this.UI.event_hour.val( this.EVENTS[id][i].hour );
+ this.UI.event_minute.val( this.EVENTS[id][i].minute );
+ this.UI.event_label.find('.' + this.EVENTS[id][i].label + ' input').attr('checked', 'checked');
+
+ this.event_i = i;
+ this.UI.event_delete.data({id: id, i: i}).show();
+ this.UI.event_tweet.data({id: id, i: i}).show();
+ } else if(hour && minute) {
+ this.UI.event_hour.val( hour );
+ this.UI.event_minute.val( minute );
+ }
+
+ $('#event-date').html( this.dateStringID(id) );
+ this.dialog( this.UI.add );
+ this.UI.event_description.focus();
+
+ return false;
+ },
+ closeAddPrompt: function() {
+ this.closeDialog();
+ },
+ deleteEvent: function(id, i) {
+ this.EVENTS[id].splice(i,1);
+ localStorage['events'] = JSON.stringify(this.EVENTS);
+ },
+ createEvent: function(id, hour, minute, description, label, i) {
+ if(!this.EVENTS[id]) {
+ this.EVENTS[id] = [];
+ }
+
+ var entry = {
+ description: description,
+ hour: hour,
+ minute: minute,
+ label: label
+ };
+ if(!i || i == null) {
+ this.EVENTS[id].push(entry);
+ } else {
+ this.EVENTS[id][i] = entry;
+ }
+
+ this.EVENTS[id].sort(function(a, b) {
+ return parseInt(a.hour+''+a.minute) - parseInt(b.hour+''+b.minute);
+ });
+
+ localStorage['events'] = JSON.stringify(this.EVENTS);
+ },
+
+ exportIcal: function() {
+ var ical = '';
+
+ ical = 'BEGIN:VCALENDAR\nMETHOD:PUBLISH\nVERSION:2.0\nCALSCALE:GREGORIAN\n\n';
+ for(var id in this.EVENTS) {
+ var date = Planner.dateFromID(id);
+
+ $.each(this.EVENTS[id], function() {
+ ical+= 'BEGIN:VEVENT\n';
+ ical+= 'DTSTART:'+ [date.getFullYear(), date.getMonth().pad(2), date.getDate().pad(2), 'T', this.hour, this.minute, '00'].join('') +'\n';
+ ical+= 'SUMMARY:'+this.description+'\n';
+ ical+= 'END:VEVENT\n\n';
+ });
+ }
+ ical+='\nEND:VCALENDAR';
+
+ return ical;
+ },
+
+
+ today: function() {
+ this.Date = new Date();
+ this.setDate();
+ this.renderCalendar();
+ },
+ nextMonth: function() {
+ this.Date.setMonth(this.month+1);
+ this.setDate();
+ this.renderCalendar();
+ },
+ previousMonth: function() {
+ this.Date.setMonth(this.Month-1 < 0 ? 11 : this.month-1);
+ this.setDate();
+ this.renderCalendar();
+ },
+ specificMonth: function(m, y) {
+ this.Date.setMonth(m-1);
+ this.Date.setYear(y);
+ this.setDate();
+ this.renderCalendar();
+ },
+
+ weekDay: function(d) {
+ return (d-1).mod(7);
+ },
+ setDate: function() {
+ this.day = this.Date.getDay();
+ this.weekstart = new Date(this.Date.getTime());
+ this.weekstart.setDate(1);
+ this.weekstart = this.weekDay( this.weekstart.getDay() );
+
+ this.date = this.Date.getDate();
+ this.month = this.Date.getMonth();
+ this.year = this.Date.getFullYear();
+
+ this.num_days = 32 - new Date(this.year, this.month, 32).getDate();
+ },
+ dateStringID: function(id) {
+ var date = this.dateFromID(id),
+ d = date.getDate()
+
+ d+=(d>10 && d<20 ? 'th' : {1:'st', 2:'nd', 3:'rd'}[d % 10] || 'th');
+
+ return this.DAYS[ this.weekDay( date.getDay() ) ] + ', ' +
+ d + ' ' + this.MONTHS[date.getMonth()] + ', ' + date.getFullYear();
+ },
+ dateFromID: function(id) {
+ id = id.split('-');
+ return new Date(id[2], id[1], id[0]);
+ },
+ updateTime: function() {
+ var time = new Date();
+ $('#time').html( time.getHours().pad(2) + ':' + time.getMinutes().pad(2) );
+ },
+ stats: function() {
+ var stats = {past: 0, future: 0};
+
+ var today = new Date();
+ for(var id in this.EVENTS) {
+ var date = Planner.dateFromID(id);
+
+ if(date.getTime() > today.getTime()) {
+ stats.future++;
+ } else {
+ stats.past++;
+ }
+ }
+
+ return stats;
+ },
+ theme: function(theme) {
+ $('body').removeClass(Planner.UI.themes.join(' ')).addClass( Planner.UI.themes[theme] );
+ }
+};
+
+Number.prototype.mod = function(n) {
+ return ((this%n)+n)%n;
+};
+Number.prototype.pad = function(n) {
+ var val = '0' + this;
+ return val.substr(val.length-n);
+};
+
+$(document).ready(function() {
+ Planner.init();
+}); \ No newline at end of file
diff --git a/apps/calendar/splashscreen.png b/apps/calendar/splashscreen.png
new file mode 100644
index 0000000..4e5c822
--- /dev/null
+++ b/apps/calendar/splashscreen.png
Binary files differ
diff --git a/apps/calendar/style.css b/apps/calendar/style.css
new file mode 100644
index 0000000..4e1112a
--- /dev/null
+++ b/apps/calendar/style.css
@@ -0,0 +1,498 @@
+html {
+ height: 100%;
+}
+body {
+ background: #eee;
+ font-family: Segoe UI;
+ font-size: 1em;
+ color: #000;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ transition:all 1s ease 0s;
+ -moz-transition:all 1s ease 0s;
+ -webkit-transition:all 1s ease 0s;
+}
+a {
+outline:none;
+}
+
+.box {
+ background: #fff;
+ box-shadow: 0 0 30px #ddd;
+}
+
+#calendar-wrap {
+ padding-right: 35px;
+ float: left;
+ z-index: 1;
+ overflow: hidden;
+ transition:all 1s ease 0s;
+ -moz-transition:all 1s ease 0s;
+ -webkit-transition:all 1s ease 0s;
+}
+ #calendar {
+ position: relative;
+ margin: 15px;
+ }
+ #stats {
+ color: #aaa;
+ line-height: 40px;
+ font-size:14pt;
+ }
+ #calendar-title {
+
+ margin-bottom: 10px;
+ float: left;
+ width: 40%;
+ font-family:Segoe UI Light;
+ color: rgb(0, 114, 198);
+ transition:all 1s ease 0s;
+ -moz-transition:all 1s ease 0s;
+ -webkit-transition:all 1s ease 0s;
+ }
+ #time {
+ color: #999;
+ }
+
+table {
+ width: 100%;
+ height: 80%;
+ margin-top: -20px;
+ border-spacing: 0;
+}
+thead td {
+ font-size: 11px;
+ text-transform:uppercase;
+ color: rgb(102, 102, 102);
+
+ height: 40px;
+}
+tbody td {
+ border-width: 0 1px 1px 0;
+ border-style: solid;
+ border-color: #ddd;
+ padding: 10px;
+ overflow: hidden;
+}
+thead td {
+ border-bottom: 1px solid #ddd;
+}
+tbody tr td:nth-child(1) {
+ border-left: 1px solid #ddd;
+}
+
+.day {
+ background: #fff url('w.png') repeat-x bottom left;
+ overflow: hidden;
+ cursor: pointer;
+}
+.day div {
+ position: relative;
+}
+.day:hover {
+ background: #fff;
+}
+.day .d {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+.selected .d {
+ text-decoration: underline;
+}
+.today {
+ background: #DFEDFA;
+ border-top:3px solid #0072C6;
+}
+ .marked .d {
+ font-weight: bold;
+ }
+#btn-previous {
+ width:32px;
+ height:32px;
+ padding:0px !important;
+ background-image:url(img/left-light.png) !important;
+ background-color:transparent !important;
+ vertical-align:middle;
+ opacity:0.8;
+
+}
+#btn-next {
+ width:32px;
+ height:32px;
+ padding:0px !important;
+ background-image:url(img/right-light.png) !important;
+ background-color:transparent !important;
+ vertical-align:middle;
+ opacity:0.8;
+}
+#btn-previous:hover , #btn-next:hover {
+ opacity:1;
+}
+#btn-today {
+ padding:0px !important;
+ background-color:transparent !important;
+ font-size:14pt !important;
+ vertical-align:middle;
+ margin-left:50px;
+ margin-right:50px;
+ color:#000;
+ transition:all 2s ease 0s;
+ -moz-transition:all 2s ease 0s;
+ -webkit-transition:all 2s ease 0s;
+
+}
+.day .add {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ line-height: 16px;
+ width: 16px;
+ height: 16px;
+ opacity: 0;
+ background-image:url(img/plus-light.png);
+ background-size:16px 16px;
+}
+ .day ul {
+ position: absolute;
+ font-size: 11px;
+ top: 25px;
+ width: 100%;
+ }
+ .day li {
+ padding: 2px;
+ width: 100%;
+ margin-bottom: 1px;
+ overflow: hidden;
+ height: 14px;
+ }
+ .day ul .time {
+ margin-right: 5px;
+ }
+
+
+#diary-wrap {
+ border-left: 1px solid #ddd;
+ float: left;
+ width: 30%;
+ display: none;
+ transition:all 1s ease 0s;
+ -moz-transition:all 1s ease 0s;
+ -webkit-transition:all 1s ease 0s;
+}
+ #diary-title {
+ float: left;
+ color: rgb(0, 114, 198);
+ font-family:Segoe UI Light;
+ }
+ #diary-close {
+ float: left;
+ margin: 1px 15px 10px 0;
+ background-image:url(img/close-light.png);
+ width:32px;
+ height:32px;
+ }
+
+ #diary-wrap .content {
+ margin: 15px;
+ }
+ .compact #diary-wrap {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 5;
+ margin-left: 40px;
+ }
+ .compact #calendar-title {
+ float: none;
+ }
+ .compact #controls {
+ float: none;
+ }
+#diary {
+ font-size: 12px;
+ margin: 15px;
+ transition:all 1s ease 0s;
+ -moz-transition:all 1s ease 0s;
+ -webkit-transition:all 1s ease 0s;
+}
+ #diary li {
+ margin-bottom: 3px;
+ }
+ #diary .time {
+ background: #bbb;
+ color: #fff;
+ padding: 2px;
+ display: block;
+ width: 100px;
+ float: left;
+ margin-right: 15px;
+ }
+ #diary .time:hover {
+ background: #000;
+ }
+ #diary .desc {
+ display: inline-block;
+ padding: 0 0 3px 0;
+ overflow: hidden;
+ border-bottom: 1px solid #ddd;
+ }
+
+#dialog {
+ background: #fff url('w.png') repeat-x bottom left;
+ display: none;
+ padding: 15px 25px;
+ position: absolute;
+ z-index: 10;
+
+ box-shadow: 0 0 30px #aaa;
+}
+ #dialog-close {
+ float: right;
+ margin: -5px -15px 10px 10px;
+ background-image:url(img/close-light.png);
+ width:32px;
+ height:32px;
+ }
+ #dialog .target {
+ display: none;
+ }
+
+
+ #add #event-description {
+ width: 90%;
+ }
+ #add label {
+ display: block;
+ font-weight: bold;
+ margin-bottom: 5px;
+ }
+ #add p.time {
+ margin-bottom: 10px;
+ }
+ #add .label {
+ font-size: 11px;
+ font-weight: normal;
+ display: inline-block;
+ margin-right: 10px;
+ }
+ #add #event-label input {
+ padding: 0;
+ }
+ #add .buttons {
+ margin-top: 30px;
+ }
+ #event-tweet,
+ #event-delete {
+ float: right;
+ display: none;
+ margin-left: 5px;
+ }
+ #event-tweet {
+ background-image: url('t.png');
+ background-repeat: no-repeat;
+ background-position: 3px 9px;
+ padding-left: 22px;
+ }
+
+ #ical-data {
+ margin-top: 15px;
+ width: 100%;
+ font-size: 11px;
+ height: 250px;
+ border:1px solid #EBEBEB;
+ transition:all 1s ease 0s;
+ -moz-transition:all 1s ease 0s;
+ -webkit-transition:all 1s ease 0s;
+ }
+
+#controls {
+ float: right;
+ margin-top: 8px;
+}
+ #controls li {
+ display: inline-block;
+ margin-left: 5px;
+ }
+ #controls a {
+ display: inline-block;
+ padding: 5px 12px;
+ }
+ #controls .sep {
+ margin-right: 35px;
+ }
+ .button {
+ border: 0;
+ margin: 0;
+ font-weight: bold;
+ font-size: 15px;
+ cursor: pointer;
+ }
+
+
+#credit {
+ background: #eee;
+ border-radius: 3px;
+ padding: 3px 5px;
+ margin-top: 15px;
+ display: inline-block;
+}
+
+/* ____________ */
+.label {
+ padding: 3px;
+ color: #fff !important;
+}
+.important {
+ background: #ff0000 !important;
+}
+.todo {
+ background: #3366cc !important;
+}
+.personal {
+ background: #35A200 !important;
+}
+.work {
+ background: #D89700 !important;
+}
+.misc {
+ background: #48BFF2 !important;
+}
+
+.clear {
+ clear: both;
+}
+
+.info {
+ font-size: 12px;
+ color: #666;
+}
+
+.round {
+ display: block;
+ width: 20px;
+ height: 20px;
+
+ border: 3px solid #000;
+ border-radius: 20px;
+ font-weight: bold;
+ text-align: center;
+ overflow: hidden;
+}
+ .round:hover {
+ border-color: #3366cc;
+ color: #3366cc;
+ }
+
+h1, h2, h3, h4 {
+ margin: 0 0 25px 0;
+ font-weight: normal;
+}
+a {
+ color: #000;
+ text-decoration: none;
+}
+input, select {
+ padding: 10px;
+ font-family:Segoe UI Light;
+ font-size:14pt;
+}
+ul {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+
+
+/* ___________ colour schemes */
+.dark {
+ background: #414141;
+ color: #FFF;
+ transition:all 2s ease 0s;
+}
+.dark #time {
+ color: #FFF;
+}
+.dark #stats {
+ color: #666;
+}
+.dark .box {
+ background: #212121;
+ box-shadow: 0 0 30px #111;
+}
+.dark #calendar-title , .dark #diary-title {
+ color: #FFF;
+}
+.dark #dialog {
+ background: #212121;
+ border: 1px solid #444;
+ box-shadow: 0 0 30px #000;
+}
+.dark #diary-wrap {
+ border: 0;
+ border-right: 1px solid #1e1e1e;
+}
+
+
+.dark .round {
+ border-color: #ff4800;
+ color: #ff4800;
+}
+ .dark .round:hover {
+ border-color: #aaa;
+ color: #aaa;
+ }
+.dark .day {
+ background: #191919;
+}
+.dark .day .add {
+ background-image:url(img/plus.png);
+ background-size:16px 16px;
+}
+.dark tbody td,
+.dark thead td,
+.dark tbody tr td:nth-child(1) {
+ border-color: #2e2e2e;
+}
+.dark #diary .time {
+ background: #444;
+ color: #ccc;
+}
+.dark #diary .desc {
+ border-color: #444;
+}
+
+.dark #credit {
+ background: #111;
+}
+.dark #credit a {
+ color: #ddd;
+}
+.dark .today {
+ background: #333;
+}
+.dark .info {
+ color: #999;
+}
+.dark #ical-data {
+ background: #222;
+ color: #aaa;
+ border: 1px solid #333;
+}
+.dark .button {
+ background: #666;
+}
+.dark #dialog-close , .dark #diary-close {
+ background-image:url(img/close.png);
+}
+.dark #btn-today {
+ color:#FFF;
+}
+.dark #btn-previous {
+ background-image:url(img/left.png) !important;
+}
+.dark #btn-next {
+ background-image:url(img/right.png) !important;
+} \ No newline at end of file