Mailspring/internal_packages/quick-schedule/calendar.html

288 lines
No EOL
10 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<link rel='stylesheet' href='bootstrap.min.css'/>
<link rel='stylesheet' href='fullcalendar/fullcalendar.css'/>
<script src='fullcalendar/lib/jquery.min.js'></script>
<script src='fullcalendar/lib/moment.min.js'></script>
<script src='fullcalendar/lib/moment-timezone-with-data.min.js'></script>
<script src='fullcalendar/fullcalendar.js'></script>
<script src='bootstrap.min.js'></script>
<script>
function randomId(len) {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
newId = [];
for (var i = 0; i < len; i++)
newId[i] = chars[0 | Math.random()*chars.length];
return newId.join('');
}
// class to communicate with the parent window
Parent = (function(){
function Parent() {}
Parent.prototype.load_events = function (start, end, callback) {
$.ajax({
url: "quick-schedule://get_events",
data: {start:start, end:end},
success: callback,
dataType: 'json'
});
};
Parent.prototype.send_results = function(data) {
$.ajax({
url: "quick-schedule://available_times",
data: {data:JSON.stringify(data)}
});
};
return Parent})();
parent = new Parent();
function getUrlParam(name) {
var match = new RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
function resizeCalendar() {
$('#calendar').fullCalendar('option', 'height', $(window).height()-55);
}
var availableTimes = [];
var eventSlots = {};
var meetingLength = 0.5;
var nextId = 0;
function resetCalendar(opts,firstCall) {
if(!firstCall) $('#calendar').fullCalendar("destroy");
if(!opts) opts = {};
var defaults = {
header: {
left: 'prev,next',
center: 'title',
right: 'today'
},
defaultView: 'agendaWeek',
handleWindowResize: true,
windowResize: function(){
resizeCalendar();
},
eventRender: function(event, element) {
if(event.id === "available") {
element.append( "<span class='closeon'>✕</span>" );
element.find(".closeon").click(function() {
$('#calendar').fullCalendar('removeEvents',function(e){return e===event});
availableTimes = availableTimes.filter(function(e){return e.ext_id !== event.ext_id});
delete eventSlots[event.start.format() + event.end.format()];
});
}
},
aspectRatio: 1.3,
timezone: 'local',
selectable: true,
selectHelper: true,
select: function(start, end) {
// when a region of time on the calendar is selected, create events in the region to mark off
// available time slots. Also add these to our list of available times to be passed back from
// this window.
var new_events = [];
//increment through selected time range, in blocks of size `meetingLength`
while(start.isBefore(end)) {
e = {
title: "Available",
start: moment(start),
end: moment(start).add(meetingLength, "hours"),
color:"#8CA",
id: "available",
ext_id: nextId++
};
if(!eventSlots[e.start.format() + e.end.format()])
new_events.push(e);
start.add(meetingLength, "hours");
}
//add the events to the calendar and to `availableTimes`
new_events.forEach(function(e){
availableTimes.push(e);
eventSlots[e.start.format() + e.end.format()] = true;
$('#calendar').fullCalendar('renderEvent', e, true);
});
$('#calendar').fullCalendar('unselect');
},
events: function(start, end, timezone, callback) {
// When a page of the calendar is loaded, this function is called to retrieve existing events.
// Make a call to the parent window asking for events in the displayed time range, and convert
// them to the format expected by fullcalendar
parent.load_events(start.unix(), end.unix(), function(events){
callback(events.map(function(event){
return {
id: event.id,
title: event.title,
allDay: false,
start: new Date(event.when.start_time*1000),
end: new Date(event.when.end_time*1000)
}
}));
})
}
};
for (var key in opts) {
if (opts.hasOwnProperty(key))
defaults[key] = opts[key];
}
$('#calendar').fullCalendar(defaults);
resizeCalendar();
}
$(document).ready(function() {
//initialize the calendar
resetCalendar({},true);
$(".fc-button").toggleClass("btn btn-default",true);
$(".fc-button").toggleClass("fc-state-default",false);
//handle reset button click
$("#reset").click(function(e){
$('#calendar').fullCalendar('removeEvents', "available");
availableTimes = [];
eventSlots = {};
});
//handle meeting length dropdown
$("#meeting-length").change(function(e){
meetingLength = parseFloat($(this).val());
});
//handle done button click
$("#done").click(function(e){
parent.send_results({
draftClientId: getUrlParam("draftClientId"),
eventData: {
title: $("#title").val().trim(),
location: $("#location").val().trim(),
description: $("#description").val().trim()
},
events: availableTimes.map(function(e){
return {
start: e.start.unix(),
end: e.end.unix(),
date: e.start.format("dddd, MMM Do"), //event date, in local timezone
time: e.start.format("h:mma")+"-"+e.end.format("h:mma")+ //event duration, in local time
" ("+moment().tz(moment.tz.guess()).format("z")+")", //local time zone abbrev
serverKey: randomId(128) //string to access this time slot on the server
}
}).sort(function(a,b) { return a.start - b.start })
});
window.close();
});
});
</script>
<style>
body {font-family: sans-serif;}
.fc-day-header {font-size: 14px;}
.fc-axis {font-size: 13px;}
#calendar {
position: fixed;
left: 205px;
right: 5px;
top: 50px;
bottom: 5px;
}
#calendar h2 {
font-size: 20px;
margin-top: 5px;
}
#options {
position: fixed;
width: 200px;
left: 0;
top: 45px;
bottom: 0;
padding: 5px;
}
#options p{
line-height: 16px;
font-size: 13px;
color: #555;
}
#options label {
font-weight: normal;
}
#title-bar {
padding: 5px;
text-align: center;
background: #EEE;
}
#title-bar h2 {
margin: 0;
}
#reset, #done {
width: 93px;
}
#description {
height: 150px;
}
.closeon {
display: none;
color: #000;
position: absolute;
right: 0;
top: 0;
z-index: 100;
cursor: pointer;
}
.fc-event:hover .closeon {
display: block;
}
.fc-event:hover .closeon:hover {
color: #800;
}
</style>
</head>
<body>
<div id="title-bar">
<h2>QuickSchedule: Event Setup</h2>
</div>
<div id="options">
<h4>Event details:</h4>
<div class="form-group">
<label for="meeting-length">Length:</label>
<select id="meeting-length">
<option value="0.5">30 min</option>
<option value="1">1 hr</option>
<option value="1.5">1 hr 30 min</option>
<option value="2">2 hr</option>
</select>
</div>
<div class="form-group">
<input type="text" class="form-control" id="title" placeholder="Title"></input>
</div>
<div class="form-group">
<input type="text" class="form-control" id="location" placeholder="Location"></input>
</div>
<div class="form-group">
<textarea type="text" class="form-control" id="description" placeholder="Description"></textarea>
</div>
<div class="form-group">
<button class="btn btn-default" id="reset">Reset</button>
<button class="btn btn-primary" id="done">Done</button>
</div>
<p> Use this tool to offer options for scheduling a meeting or event. Click and drag in the
calendar to select time ranges when you're available. Enter event details on the left,
to be included in the event invitation.
</p>
</div>
<div id='calendar'></div>
</body>
</html>