Skip to content
This repository has been archived by the owner on May 25, 2021. It is now read-only.

Commit

Permalink
Merge pull request #169 from YACS-RCOS/staging
Browse files Browse the repository at this point in the history
ICS downloads, Fix CRN List, Fix Noon display
  • Loading branch information
Bad-Science committed Nov 6, 2016
2 parents d484666 + 8307d6c commit 52fe43d
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 12 deletions.
2 changes: 1 addition & 1 deletion app/assets/javascripts/controllers/courses/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Handlebars.registerHelper('day_name', function (n) {
Handlebars.registerHelper('time_range', function (start, end) {
return new Handlebars.SafeString([start, end].map(function (time) {
var hour = Math.floor(time / 100);
var ampm = hour > 12 ? 'p' : 'a';
var ampm = hour >= 12 ? 'p' : 'a';
hour = hour > 12 ? hour - 12 : hour == 0 ? 12 : hour;
var minutes = time % 100;
minutes = minutes > 9 ? minutes : minutes == 0 ? '' : '0' + minutes;
Expand Down
22 changes: 20 additions & 2 deletions app/assets/javascripts/controllers/schedules/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Yacs.views.schedules = function (target, params) {
var scheduleNumElement = target.querySelector('#schedule-num');
var scheduleCountElement = target.querySelector('#schedule-count');
var scheduleStatusElement = target.querySelector('#schedule-status');
var crnListElement = target.querySelector('#crn-list');
var downloadICSElement = target.querySelector('#ics-btn');
var schedule = new Schedule(scheduleElement);
var scheduleData = [];
var scheduleIndex = 0;
Expand Down Expand Up @@ -123,6 +123,20 @@ Yacs.views.schedules = function (target, params) {
}
};

/**
* Format the current schedule as a vCalendar (ICS file format),
* and prompt the user to download it as a file.
*/
var getICSDownload = function() {
if(scheduleData.length < 1) {
return;
}
// current periods being displayed only
periods = scheduleData[scheduleIndex].events;
vCalendarData = Yacs.vCalendar.createVCalendar(periods);
Yacs.vCalendar.download(vCalendarData);
};

/**
* Show schedule at given index, and display corresponding CRNs.
* If index is -1, show nil schedule.
Expand Down Expand Up @@ -176,10 +190,14 @@ Yacs.views.schedules = function (target, params) {
Yacs.user.clearSelections();
});

/* Prompt the creation and download of the schedule ICS when the button is clicked.
*/
Yacs.on('click', downloadICSElement, getICSDownload);

/**
* Show selected courses / sections on the schedule page. The courses shown
* are explicitly the courses that had one or more sections selected at the
* time the view was rendered.
* time the view was rendered.
*/
var selections = Yacs.user.getSelections();
if (selections.length > 0) {
Expand Down
88 changes: 88 additions & 0 deletions app/assets/javascripts/lib/vcalendar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* @namespace vCalendar
* @description Functions associated with the vCalendar (ICS) download on the schedule page
* @memberOf Yacs
*/
window.Yacs.vCalendar = new function() {
var self = this;

/**
* Given a set of periods in the same form as they would be used
* to generate a single schedule, return a string containing
* that data formatted into a VCalendar, which if it were a file
* could be imported into a calendar application.
* All periods are set to recur weekly, starting at the current
* week.
*/
self.createVCalendar = function(periods) {
var vCalendarData = 'BEGIN:VCALENDAR\r\n'+
'VERSION:2.0\r\n' +
'PRODID:-//yacs//NONSGML v1.0//EN\r\n';

var uidCounter = 0;

// Helper to pad single digit numbers with a 0 and leave double digit numbers unchanged.
var pad0 = function(num) { return ('0' + num).slice(-2); }

// Helper to extract the vCalendar formatted time from a Date. It looks like this:
// YYYYMMDDTHHMMSS, where T is a literal T
var getVCalendarStamp = function(d) {
return d.getFullYear() + pad0(d.getMonth()+1) + pad0(d.getDate()) + 'T'
+ pad0(d.getHours()) + pad0(d.getMinutes()) + '00';
}

// Helper to convert a single period into a full VEVENT.
var periodToVevent = function(period) {
var d = new Date();
var nowstamp = getVCalendarStamp(d); // save for the DTSTAMP field

// dates need to be shuffled around by setting the date, so calculate how much it
// needs to move by
var weekday_offset = period.day - d.getDay();
d.setDate(d.getDate() + weekday_offset);

// at this point the date is set correctly, then the time needs to be set
d.setHours(Math.floor(period.start / 60));
d.setMinutes(period.start % 60);

var startstamp = getVCalendarStamp(d);

// compute end and take end stamp
d.setMinutes(d.getMinutes() + (period.end - period.start));
var endstamp = getVCalendarStamp(d);

uidCounter++;
return 'BEGIN:VEVENT\r\n' +
'UID:event' + uidCounter + '@yacs.cs.rpi.edu\r\n' +
'SUMMARY:' + period.tooltip + '\r\n' +
'DTSTAMP:' + nowstamp + '\r\n' +
'DTSTART:' + startstamp + '\r\n' +
'DTEND:' + endstamp + '\r\n' +
'RRULE:FREQ=WEEKLY' + '\r\n' +
'END:VEVENT\r\n';

};

each(periods, function(period) {
vCalendarData += periodToVevent(period);
});
vCalendarData += 'END:VCALENDAR';
return vCalendarData;

};

/**
* Prompt the user to download a vCalendar string as a file
* named yacs-schedule.ics.
* Do this by attaching a phantom <a> to the DOM and setting its
* href to the calendar data, then simulating a click on it.
*/
self.download = function(vCalendarData) {
var elt = document.createElement('a');
elt.setAttribute('href', 'data:text/calendar;charset=utf8,' + encodeURIComponent(vCalendarData));
elt.setAttribute('download', 'yacs-schedule.ics');
document.body.appendChild(elt);
elt.click();
document.body.removeChild(elt);
};
};
1 change: 1 addition & 0 deletions app/assets/javascripts/templates/schedules/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<span id="right-switch" class="schedule-switch">&#9654;</span>
</div>
<button type="button" id="clear-btn" class="clear-button">Clear</button>
<button type="button" id="ics-btn" class="clear-button">Download ICS</button>
</div>
<div id="right">
<div id="schedule-status"></div>
Expand Down
16 changes: 8 additions & 8 deletions app/assets/stylesheets/schedule.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@
-webkit-user-select: none;
-ms-user-select:none;
}
#schedule-bar:after {
#schedule-bar:after {
content: " ";
display: block;
height: 0;
display: block;
height: 0;
clear: both;
}
#crn-list {
font-size: 90%;
float: right;
}
#switch {
float: left;
}
Expand All @@ -34,6 +30,10 @@
}
#schedule-status {
margin: 0 auto;
font-size: 90%;
-moz-user-select:text;
-webkit-user-select:text;
-ms-user-select:text;
}
#schedule-bar>#left {
float: left;
Expand Down Expand Up @@ -67,4 +67,4 @@

.clear-button:focus {
background-color: #c65353;
}
}
2 changes: 1 addition & 1 deletion features/step_definitions/schedule_page_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
end

And(/^I should see a (.*) with text "(.*)"$/) do |elem, text|
expect(page.find(elem)).to have_content text
expect(page.all(elem, text: text)).not_to be_empty
end

Then(/^I should see the (.*) with id (\d+) is selected$/) do |type, id|
Expand Down

0 comments on commit 52fe43d

Please sign in to comment.