mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-14 13:44:41 +08:00
a3e986d94a
Summary: Fixes a number of smaller UI issues. Fixes T6173, T6207 Full list of changes: - Ensure time slots / days display in order - Allow time blocks of any size to be set on half hour intervals - Don't reset calendar when changing event length - Expand calendar on window resize - Change window title from "Electron" - Add delete button to cancel individual calendar events - Move event details box to the left side - Prevent addition of duplicate time slots Test Plan: manual Reviewers: bengotow Reviewed By: bengotow Maniphest Tasks: T6173, T6207 Differential Revision: https://phab.nylas.com/D2333
288 lines
No EOL
10 KiB
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> |