var DEBUG = localStorage['debug'];
var NAV;
var SRCDATA = [];
var DOMDATA = [];
var SUBPAGES = [];
var INITIALIZED = [];
var NOW = new Date();
var GRACE_PERIOD = 60 * 15 * 1000; // 15 minutes
var PENDING_REQUESTS = 0;
var SECTION;
var DROPBOX;
var FILES;
var SECTIONS = ['a', 'b'];
var COURSE = 'info344';
var QUARTER = '13sp';
// why cookies...?
// if (!Cookies.exists('section')) {
// Cookies.set('section', 'a', 14); // TODO: ask!
// } else {
// SECTION = Cookies.get('section');
// }
// var UPDATESFILE = 'updates.xml?section=' + SECTION;
var DEPS = {
home: ['updates.xml', 'calendar.xml', 'lectures.xml', 'labs.xml'],
calendar: ['updates.xml', 'calendar.xml', 'lectures.xml', 'labs.xml'],
lectures: ['calendar.xml', 'lectures.xml', 'labs.xml', 'video.html'],
labs: ['calendar.xml', 'lectures.xml', 'labs.xml'],
homework: ['homeworks.xml', 'assignments.xml'],
syllabus: ['syllabus.html'],
software: ['software.html'],
staff: ['staff.html'],
dropbox: ['dropbox.html', 'calendar.xml', 'assignments.xml', 'lectures.xml', 'labs.xml', 'homeworks.xml', 'tags.txt', 'dropbox_feedback.html']
};
document.observe('dom:loaded', function() {
// $('main_content').hide();
// addSectionToFeedLink();
drawDropBoxArrows();
drawWeekNavArrows();
$$('.subpage').each(function(subpage) {
var name = subpage.className.replace(/subpage/g, '').trim();
SUBPAGES[name] = subpage;
subpage.remove();
});
// determine section
if (!localStorage['section']) {
new Ajax.Request('html/section.html', {
method: 'GET',
onSuccess: function(ajax) {
ajaxDialog(ajax, sectionInit);
},
onFailure: ajaxFailure,
onException: ajaxFailure
});
} else {
SECTION = localStorage['section'];
goToSubpagePath();
createSectionSelector();
}
});
function ajaxDialog(ajax, initFunction) {
showDialog(ajax.responseText);
initFunction();
}
function showDialog(contents) {
var dialog = $(document.createElement('div'));
dialog.id = 'dialog';
dialog.innerHTML = '<div id="screen"></div>' + contents;
$(document.body).insert(dialog);
}
function sectionInit() {
$('section_dialog').select('li').each(function(li) {
li.observe('click', function(event) {
SECTION = localStorage['section'] = event.findElement('li').innerHTML.trim().toLowerCase();
// SECTION = event.findElement('li').innerHTML.trim().toLowerCase();
dialogDismiss(function() {
goToSubpagePath();
createSectionSelector();
});
});
});
}
function dialogDismiss(postFunction) {
$('dialog').remove();
if (postFunction)
postFunction();
}
function loading() {
PENDING_REQUESTS++;
}
function resolveDependenciesForSubpage(subpage) {
// enforce https on dropbox
if (subpage == 'dropbox' && location.protocol != 'https:') {
location.replace(location.href.replace(/^http:/, 'https:'));
}
var complete = true;
DEPS[subpage].each(function(depfile) {
if (!SRCDATA[depfile]) {
complete = false;
loading();
var dir = depfile.substring(depfile.lastIndexOf('.') + 1);
dir = dir == 'txt' ? '.' : dir; // for tags.txt
// console.log(depfile + " > " + dir);
var requestfile = dir + '/' + depfile;
new Ajax.Request(requestfile, {
method: 'GET',
onSuccess: function(ajax) {
SRCDATA[depfile] = ajax.responseXML ? ajax.responseXML : ajax.responseText;
// console.log("Loaded depfile '" + depfile + "' for subpage '" + subpage + "': " + SRCDATA[depfile]);
depsLoadedForSubpage(subpage);
},
onFailure: ajaxFailure,
onException: ajaxFailure
})
} else {
// console.log("Depfile '" + depfile + "' for subpage '" + subpage + "' already loaded: " + SRCDATA[depfile]);
}
});
if (complete) {
initContentForSubpage(subpage);
}
}
function depsLoadedForSubpage(subpage) {
if (!--PENDING_REQUESTS) {
initContentForSubpage(subpage);
}
}
function initContentForSubpage(subpage) {
if (!INITIALIZED[subpage]) {
// console.log("Going to initialize subpage '" + subpage + "'.");
switch (subpage) {
case 'lectures':
case 'labs':
case 'homework':
case 'dropbox':
window[subpage + 'Init']();
break;
case 'calendar':
case 'home':
calendarInit();
updatesInit();
break;
case 'syllabus':
case 'staff':
case 'software':
SUBPAGES[subpage].insert(SRCDATA[subpage + '.html']);
break;
}
if (['home', 'staff', 'syllabus'].indexOf(subpage) != -1) {
createEmailLinks(SUBPAGES[subpage]);
}
INITIALIZED[subpage] = true;
}
displaySubpage(subpage);
}
function dateDiff(date1, date2) {
return date2.getTime() - date1.getTime();
}
function prettyTime(ms) {
function pluralize(val, singular, plural) {
return val + ' ' + (val == 1 ? singular : plural);
}
var ary = [], days, hours, minutes, seconds = Math.abs(parseInt(ms / 1000));
if (seconds >= 84600) {
days = parseInt(seconds / 84600);
seconds %= 84600;
ary.push(pluralize(days, "day", "days"));
}
if (seconds >= 3600) {
hours = parseInt(seconds / 3600);
seconds %= 3600;
ary.push(pluralize(hours, "hour", "hours"));
}
if (seconds >= 60) {
minutes = parseInt(seconds / 60);
seconds %= 60;
ary.push(pluralize(minutes, "minute", "minutes"));
}
return ary.join(', ') + (ms < 0 ? ' ago' : ' from now');
}
function dropboxInit() {
SUBPAGES['dropbox'].insert(SRCDATA['dropbox.html']);
SUBPAGES['dropbox'].select('form#dropbox')[0].observe('submit', dropboxSubmit);
SUBPAGES['dropbox'].select('div.submit input[type="submit"]')[0].disabled = true;
SUBPAGES['dropbox'].select('img#submitting')[0].style.visibility = 'hidden';
SUBPAGES['dropbox'].select('div.submit .checkbox_advisory')[0].style.visibility = 'hidden';
SUBPAGES['dropbox'].select('li.authenticate input[type="text"]#username')[0].observe('keydown', dropboxValidate);
SUBPAGES['dropbox'].select('li.authenticate input[type="password"]#password')[0].observe('keydown', dropboxValidate);
SUBPAGES['dropbox'].select('li.authenticate input[type="checkbox"]')[0].observe('change', dropboxValidate);
SUBPAGES['dropbox'].select('li.authenticate input[type="checkbox"]')[0].observe('change', dropboxShowHideAcademicIntegrityMessage);
SUBPAGES['dropbox'].select('form#dropbox')[0].observe('submit', dropboxSubmit);
var dropbox = SUBPAGES['dropbox'];
dropbox.select('ol > li').each(function(step, i) {
if (step.hasClassName('selectassignment')) {
var ul = step.select('ul.assignments')[0];
var assignments = $x('assignments/*', SRCDATA['assignments.xml']);
var open_assignments = false;
assignments.each(function(assignment, i) {
var type = assignment.nodeName;
var id = $x('@id', assignment)[0].textContent;
console.log('[' + i + '] ' + id + ', ' + SECTION);
var turnin = $x('turnin[@section="' + SECTION + '"] | turnin[@section="all"]', assignment)[0];
var opens = new Date($x('@opens', turnin)[0].textContent);
console.log('[' + i + '] NOW: ' + NOW);
console.log('[' + i + '] opens: ' + opens + ' (' + prettyTime(dateDiff(NOW, opens)) + ')');
if (NOW >= opens) {
var closes = new Date($x('@closes', turnin)[0].textContent);
console.log('[' + i + '] closes: ' + closes + ' (' + prettyTime(dateDiff(NOW, closes)) + ')');
var cutoff = new Date(closes.getTime() + GRACE_PERIOD);
console.log('[' + i + '] with grace period: ' + cutoff + ' (' + prettyTime(dateDiff(NOW, cutoff)) + ')');
if ($x('@latedays', turnin)[0]) {
var latedays = parseInt($x('@latedays', turnin)[0].textContent);
console.log('[' + i + '] late days: ' + latedays);
cutoff = new Date(cutoff.getTime() + (latedays * 60 * 60 * 24 * 1000));
}
console.log('[' + i + '] cutoff: ' + cutoff + ' (' + prettyTime(dateDiff(NOW, cutoff)) + ')');
if (NOW <= cutoff) {
open_assignments = true;
console.log('[' + i + '] ' + type);
var assignmentData = SRCDATA[(type == 'minilab' ? 'lecture' : type) + 's.xml'];
console.log('[' + i + '] ' + assignmentData);
var path = '//' + type + '[@id="' + id + '"]';
console.log('[' + i + '] ' + path);
var title = $x(path + '/title', assignmentData)[0].textContent;
console.log('[' + i + '] ' + title);
var label = $x(path + '/label', assignmentData);
if (label.length) {
label = label[0].textContent;
} else {
label = $x(path + '/description', assignmentData)[0].textContent;
}
console.log('[' + i + '] ' + label);
var li = $(document.createElement('li'));
li.className = 'assignment';
li.insert(['<a data-type="' + type + '" data-id="' + id + '">',
'<h4>', title, '</h4>',
'<p>', label, '</p>',
'</a>'].join(''));
li.select('a')[0].observe('click', selectAssignment);
ul.appendChild(li);
}
}
});
if (!open_assignments) {
SUBPAGES['dropbox'].select('form#dropbox')[0].remove();
SUBPAGES['dropbox'].appendChild($(document.createElement('p')).update('There are currently no open assignments to submit.'));
}
} else {
// step.style.visibility = 'hidden';
}
});
}
function dropboxShowHideAcademicIntegrityMessage() {
if ($('academic_integrity_chk').checked) {
SUBPAGES['dropbox'].select('.submit .checkbox_advisory')[0].style.visibility = 'hidden';
} else {
SUBPAGES['dropbox'].select('.submit .checkbox_advisory')[0].style.visibility = 'visible';
}
}
function dropboxFilesValidate() {
var complete = true;
FILES.each(function(f, i) {
// console.log("dropcomplete[" + i + "] wasdroppedon(): " + f.wasdroppedon());
if (f.isrequired() && !f.wasdroppedon()) {
complete = false;
}
});
return complete;
}
function dropboxValidate(event) {
var valid = dropboxFilesValidate();
if (valid) {
[$('username'), $('password'), $('academic_integrity_chk')].each(function(elem) {
if ((elem.type == 'checkbox' && !elem.checked) || !elem.value) {
valid = false;
}
});
}
SUBPAGES['dropbox'].select('.submit input[type="submit"]')[0].disabled = !valid;
}
function dropboxSubmit(event) {
event.stop();
var xhr = new XMLHttpRequest();
xhr.open("POST", "submit.php");
xhr.onload = function() {
dropboxSubmitted(xhr, $('username').value);
};
DROPBOX.append('username', $('username').value);
DROPBOX.append('password', $('password').value);
DROPBOX.append('timestamp', Date.now());
xhr.send(DROPBOX);
dropboxSubmitting();
}
function dropboxSubmitted(xhr) {
var url, message, latedays;
switch (xhr.status) {
case 200:
url = 'html/dropbox_accepted.html';
var matches = xhr.responseText.match(/accepted. Receipt: ([a-f0-9]+)\n(?:on time|(\d) days? late)/);
message = matches[1];
if (matches[2]) {
url = 'html/dropbox_late.html';
latedays = matches[2];
}
break;
case 401:
url = 'html/dropbox_authentication.html';
// message = xhr.responseText;
break;
case 400:
case 500:
default:
url = 'html/dropbox_error.html';
message = xhr.responseText;
break;
}
new Ajax.Request(url, {
method: 'GET',
onSuccess: function(ajax) {
var dropboxsection = $('dropbox').parentNode;
// console.log("in dropboxFeedbackInit");
var assignmenttype = $('dropbox').select('input[name="assignmenttype"]')[0].value;
var assignmentid = $('dropbox').select('input[name="assignmentid"]')[0].value;
var username = $('dropbox').select('input[name="username"]')[0].value;
// var section = $F('dropbox')['section'];
$('dropbox').remove();
$('main_content').scrollTo();
dropboxsection.hide();
dropboxsection.innerHTML += ajax.responseText;
if (message) {
$$('.subpage.dropbox div.outcome section.response code')[0].update(message);
}
if (latedays) {
$('latedays').update(latedays == 1 ? '1 day late' : latedays + ' days late');
}
if (xhr.status == 200) {
dropboxsection.select('div.outcome')[0].innerHTML += SRCDATA['dropbox_feedback.html'];
new Ajax.Request('feedback.php', {
method: 'GET',
synchronous: true,
parameters: {
'username': username,
'assignmenttype': assignmenttype,
'assignmentid': assignmentid
},
onSuccess: function(ajax) {
dropboxFeedbackInit(username, assignmenttype, assignmentid, ajax.responseText);
},
onFailure: function(ajax) {
dropboxFeedbackInit(username, assignmenttype, assignmentid);
}
})
// dropboxFeedbackInit(username, assignmenttype, assignmentid);
}
dropboxsection.show();
},
onFailure: ajaxFailure,
onException: ajaxFailure
});
}
function dropboxFeedbackInit(username, assignmenttype, assignmentid, existingdata) {
var form = SUBPAGES['dropbox'].select('div.outcome section.feedback form#feedback')[0];
form.select('input[name="username"]')[0].value = username;
form.select('input[name="assignmenttype"]')[0].value = assignmenttype;
form.select('input[name="assignmentid"]')[0].value = assignmentid;
var existing;
if (existingdata) {
existing = [];
var parts = existingdata.split(/\n/);
existing['rating'] = parts[0];
existing['time'] = parts[1];
existing['tags'] = parts[2].split(/, ?/);
existing['comments'] = parts[3];
}
// create rating elements
var rating_ul = form.select('dl.feedback dd.rating ul')[0];
// console.log(rating_ul);
for (var i = 1; i <= 5; i++) {
var li = $(document.createElement('li'));
li.innerHTML = ['<label>', '<input type="radio" name="rating" value="' + i + '" />', i, '</label>'].join('');
li.observe('click', function(event) {
var ul = event.findElement('ul');
ul.addClassName('rated');
ul.select('li').each(function(elem) {
if (elem == event.findElement('li')) {
// elem.select('input[type="radio"]')[0].checked = true;
elem.addClassName('selected');
} else {
// elem.select('input[type="radio"]')[0].checked = false;
elem.removeClassName('selected');
}
});
});
// console.log(i + ' =? ' + existing['rating']);
if (existing && i == existing['rating']) {
rating_ul.addClassName('rated');
li.select('input')[0].checked = true;
li.addClassName('selected');
}
rating_ul.appendChild(li);
}
// create tags
var tags_ul = form.select('dl.feedback dd.tags ul')[0];
var tags = SRCDATA['tags.txt'].split(/\n/);
for (var i = 0; i < tags.length; i++) {
var tag = tags[i];
var li = $(document.createElement('li'));
li.innerHTML = ['<label>', '<input type="checkbox" name="tags[]" value="' + tag + '" />',
tag, '</label>'].join('');
li.observe('click', function(event) {
// console.log(event.element());
if (event.element().checked) {
event.findElement('li').addClassName('selected');
} else {
event.findElement('li').removeClassName('selected');
}
});
if (existing && existing['tags'].indexOf(tag) != -1) {
li.select('input')[0].checked = true;
li.addClassName('selected');
}
tags_ul.appendChild(li);
}
// prep time for assignment type
var time = form.select('#time')[0];
var timeunits = form.select('#timeunits')[0];
switch (assignmenttype) {
case 'homework':
time.value = '2';
time.step = '0.5';
// time.max = '15';
timeunits.innerHTML = 'hrs.';
break;
case 'lab':
time.value = '50';
time.step = '5';
// time.max = '60';
timeunits.innerHTML = 'mins.';
break;
case 'minilab':
time.value = '25';
time.step = '5';
// time.max = '45';
timeunits.innerHTML = 'mins.';
break;
}
// update time, comments
if (existing) {
var p = $(document.createElement('p')).update('Your previous feedback is pre-populated below. Thanks!');
p.addClassName('notice');
form.childElements()[0].insert(p, { position: 'after' });
form.select('input[name="time"]')[0].value = existing['time'];
form.select('textarea')[0].innerHTML = existing['comments'];
form.select('input[type="submit"]')[0].addClassName('submitted');
form.select('input[type="submit"]')[0].value = 'Update';
}
// prepare for submission
form.observe('submit', function(event) {
event.stop();
var data = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action);
xhr.onload = function() {
form.select('input[type="submit"]')[0].addClassName('submitted');
form.select('input[type="submit"]')[0].value = 'Update';
form.select('p#feedback_thankyou')[0].update('<strong>Thanks for the feedback!</strong> Now go look at <a href="http://cuteroulette.com/">something cute</a>.');
};
xhr.send(data);
});
}
function dropboxSubmitting() {
SUBPAGES['dropbox'].select('.submit input[type="submit"]')[0].disabled = true;
$$('.subpage.dropbox .submit input[type="submit"]')[0].value = "Submitting…";
$('submitting').style.visibility = 'visible';
}
function homeworkInit() {
function dateString(date) {
var weekday = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][date.getDay()];
var month = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][date.getMonth()];
var day = date.getDate();
var year = date.getFullYear();
var hours = date.getHours();
var minutes = zeroPad(date.getMinutes());
var am_pm = (hours >= 0 && hours < 12) ? 'AM' : 'PM';
hours %= 12;
return [weekday, ', ', month, ' ', day, ', ', year, ', ', hours, ':', minutes, ' ', am_pm].join('');
}
var now = new Date();
var homeworks = $x('//homework', SRCDATA['homeworks.xml']);
if (homeworks.length) {
// alert(homeworks.length);
homeworks.reverse().each(function(homework, i) {
// get date-related stuff from calendar
var id = $x('@id', homework)[0].textContent;
var turnin = $x('//homework[@id="' + id + '"]/turnin', SRCDATA['assignments.xml'])[0];
var opens = new Date($x('@opens', turnin)[0].textContent);
var closes = new Date($x('@closes', turnin)[0].textContent);
var shown = (opens <= now);
if (shown) {
var article = $(document.createElement('article'));
var title = $x('title', homework)[0].textContent;
var description = $x('description', homework)[0] ? $x('description', homework)[0].textContent : '';
var open = (now <= closes);
var closemonth = zeroPad(closes.getMonth() + 1);
var closeday = zeroPad(closes.getDate());
var content = ['<hgroup>',
'<h3 id="', id, '">', title, '</h3>',
'<h4>', closemonth + '.' + closeday, '</h4>',
'</hgroup>',
'<p>', description, '</p>',
'<p class="duedate">Due: <time>' + dateString(closes) + '</time></p>'].join('');
// if (!open) {
// article.addClassName('closed');
// article.innerHTML = content;
// } else {
article.innerHTML = linkNode(homework, id, content, false);
// }
SUBPAGES['homework'].appendChild(article);
}
});
} else {
SUBPAGES['homework'].appendChild(noneYet('homework assignments'));
}
}
function noneYet(type) {
var p = $(document.createElement('p'));
p.innerHTML = 'No ' + type + ' posted yet.';
return p;
}
function dropcomplete() {
if (dropboxFilesValidate()) {
// $$('.submit input[type="submit"]')[0].disabled = false;
// dropboxSubmit();
$$('.subpage.dropbox li.step.authenticate')[0].removeClassName('disabled');
$('username').disabled = false;
$('password').disabled = false;
$('academic_integrity_chk').disabled = false;
$$('.subpage.dropbox div.submit')[0].removeClassName('disabled');
// $$('.subpage.dropbox div.submit input[type="submit"]')[0].disabled = false;
// $$('.subpage.dropbox div.submit')[0].style.visibility = 'visible';
dropboxShowHideAcademicIntegrityMessage();
}
}
function selectAssignment(event) {
// console.log("clicked on: " + event.element());
var a = event.element().up('a');
if (!a) a = event.element();
// console.log("found a: " + a);
var type = a.dataset['type'];
var id = a.dataset['id'];
// console.log('assignment type: ' + type);
// console.log('assignment id: ' + id);
FILES = [];
DROPBOX = new FormData();
DROPBOX.append('assignmenttype', type);
DROPBOX.append('assignmentid', id);
DROPBOX.append('section', localStorage['section']);
// console.log("assignmenttype: " + type + "; assignmentid: " + id);
$('dropbox').select('input[name="assignmenttype"]')[0].value = type;
$('dropbox').select('input[name="assignmentid"]')[0].value = id;
$('dropbox').select('input[name="section"]')[0].value = localStorage['section'];
$$('.subpage.dropbox li.step.selectassignment ul.assignments li').each(function(assignment) {
if (assignment == a.up('li')) {
assignment.removeClassName('deselected');
assignment.addClassName('selected');
} else {
assignment.removeClassName('selected');
assignment.addClassName('deselected');
}
});
$$('li.uploadfiles ul.files')[0].update();
// $('dropbox')['assignmenttype'].value = type;
// $('dropbox')['assignmentid'].value = id;
// console.log('type: ' + $('dropbox')['assignmenttype'].value);
// console.log('id: ' + $('dropbox')['assignmentid'].value);
var path = '//' + type + '[@id="' + id + '"]';
// console.log('path: ' + path);
var files = $x(path + '/file', SRCDATA['assignments.xml']);
// console.log('files: ' + files.length);
files.each(function(file, i) {
var type = $x('@type', file)[0].textContent;
var name = $x('@name', file)[0].textContent;
var required = $x('@required="true"', file);
// console.log('File "' + name + '" is required: ' + required);
var li = dropboxCreateNewFileDrop(name, type, required);
$$('li.uploadfiles ul.files')[0].insert(li);
});
$$('.subpage.dropbox li.step.uploadfiles')[0].removeClassName('disabled');
}
function dropboxCreateNewFileDrop(name, type, required) {
var li = $(document.createElement('li'));
var label;
li.addClassName('filedrop');
if (name == '*' && type == '*') {
label = '(another file)';
li.addClassName('another');
li.addClassName('variable');
} else if (name == '*') {
label = '(a file of type ' + type + ')';
li.addClassName('variable');
} else if (name.indexOf('*') != -1) {
label = '(a file named ' + name + ')';
li.addClassName('variable');
} else if (required) {
label = name;
li.addClassName('required');
}
li.innerHTML = label;
FILES.push(new DNDFileController(li, name, type, required, dropcomplete));
return li;
}
function calendarInit() {
function getContent(entry, date) {
var title = $x('title', entry)[0].textContent;
var description = $x('description', entry)[0] ? $x('description', entry)[0].textContent : '';
return cell_content = ['<hgroup>',
'<h3>', title, '</h3>',
'<h4>', date.substring(4, 6) + '.' + date.substring(6), '</h4>',
'</hgroup>',
'<p>', description, '</p>'].join('');
// cell.innerHTML = linkNode(entry, id, cell_content);
}
DOMDATA['calendar'] = [];
$x('//week', SRCDATA['calendar.xml']).each(function(week, i) {
var tr = $(document.createElement('tr'));
var entries = $x('//week[@number="' + (i+1) + '"]/section[@id="' + localStorage['section'] + '"]/*', week);
entries.each(function(calendar_entry, j) {
var cell = $(document.createElement('td'));
cell.className = ['lecture-a', 'lab', 'lecture-b'][j];
var date = $x('@date', calendar_entry)[0].textContent;
if ($x('@blank="true"', calendar_entry)) {
cell.innerHTML = '';
} else if ($x('@id', calendar_entry)[0]) {
var id = $x('@id', calendar_entry)[0].textContent;
var type = calendar_entry.nodeName;
var doc = SRCDATA[type + 's' + '.xml'];
var source_entry = $x('//*[@id="' + id + '"]', doc)[0];
if ($x('@tentative="true"', calendar_entry)) {
cell.addClassName('tentative');
cell.innerHTML = getContent(source_entry, date);
} else {
cell.innerHTML = linkNode(source_entry, id, getContent(source_entry, date), type == 'lecture');
}
if (type == 'lecture') {
var minilab = getMinilabContent(source_entry);
if (!minilab) {
cell.addClassName('noaside');
} else {
cell.innerHTML += minilab;
}
}
} else {
cell.innerHTML = getContent(calendar_entry, date);
cell.addClassName('noaside');
if ($x('@tentative="true"', calendar_entry)) {
cell.addClassName('tentative');
}
}
cell.innerHTML = '<div class="wrapper">' + cell.innerHTML + '</div>';
tr.appendChild(cell);
});
DOMDATA['calendar'].push(tr);
});
}
function showWeekInElement(week, element) {
var calendar = element.select('table.calendar')[0];
calendar.select('tr').each(function(tr) { // TODO: save the one to show if it's there
tr.remove();
});
calendar.insert(DOMDATA['calendar'][week - 1]);
}
function zeroPad(num) {
return num < 10 ? '0' + num : num;
}
function updatesInit() {
// console.log("Initializing updates.");
var items = $x('//item', SRCDATA['updates.xml']);
[SUBPAGES['home'], SUBPAGES['calendar']].each(function(subpage) {
var dl = subpage.select('dl')[0];
// console.log("Initializing dl: " + dl);
dl.update();
var charcount = 0;
items.each(function(item, i) {
// limit to 6 entries on home page, regardless of character count
if (i > 5 && subpage.hasClassName('home')) {
throw $break;
}
// console.log('[' + i + '] Parsing item: ' + item.textContent);
var date = new Date($x('pubDate', item)[0].textContent);
// console.log('[' + i + '] Date: ' + date);
var month = zeroPad(date.getMonth() + 1);
var day = zeroPad(date.getDate());
var dateelem = new Element('dt').update(month + '.' + day);
var title = $x('title', item)[0].textContent;
var description = $x('description', item)[0].textContent;
var link = $x('link', item)[0];
if (link) {
title = ['<a href="' + link.textContent + '">', title, '</a>'].join('');
}
var content = title;
// add title only if it's significantly different (non-alphabetic characters and tags)
if (title.replace(/<[^>]+>/g, '').replace(/[^\w]/g, '') != description.replace(/<[^>]+>/g, '').replace(/[^\w]/g, '')) {
content = ['<p>', title, '</p>', '<aside>', description, '</aside>'].join('');
}
var message = new Element('dd').update(content);
// ensure home page updates list isn't too long (≤500 chars and ≤5 entries)
var text = message.textContent.replace(/\s+/g, ' ');
console.log("[item " + i + "]: message: '" + text + "' (" + text.length + " / " + charcount + ")");
if (i > 0 && subpage.hasClassName('home') && (charcount + text.length > 500 || i > 5)) {
throw $break;
} else {
dl.appendChild(dateelem);
dl.appendChild(message);
charcount += text.length;
}
});
});
}
function getMinilabContent(container) {
var minilab = $x('minilab', container)[0];
if (minilab) {
var ml_title = $x('title', minilab)[0].textContent;
var ml_description, ml_id;
['description', '@id'].each(function(field, k) {
var elem = $x(field, minilab)[0];
if (elem) {
eval('ml_' + field.replace(/@/, '') + ' = "' + elem.textContent + '";');
}
});
var ml_content = ['<strong>', ml_title, ':</strong>'].join('');
if (ml_description) ml_content += ['<span class="space"> </span>', ml_description].join('');
ml_content = ['<aside>', ml_content, '</aside>'].join('');
if (ml_id) {
return linkNode(minilab, ml_id, ml_content, false);
} else {
return ml_content;
}
} else {
return '';
}
}
function lecturesInit() {
$x('//lecture', SRCDATA['lectures.xml']).each(function(lecture, i) {
var article = $(document.createElement('article'));
var id = $x('@id', lecture)[0].textContent;
var title = $x('title', lecture)[0].textContent;
var description = $x('description', lecture)[0] ? $x('description', lecture)[0].textContent : '';
// get date-related stuff from calendar
var calendar = SRCDATA['calendar.xml'];
var section = localStorage['section'];
var path = '//section[@id="' + section + '"]/lecture[@id="' + id + '"]';
var date = $x(path + '/@date', calendar)[0].textContent;
var tentative = $x(path + '/@tentative="true"', calendar);
// get mini-lab
var minilab = getMinilabContent(lecture);
var content = ['<hgroup>',
'<h3 id="', id, '">', title, '</h3>',
'<h4>', date.substring(4, 6) + '.' + date.substring(6), '</h4>',
'</hgroup>',
'<p>', description, '</p>'].join('');
var files = '';
var filesets = $x(path + '/fileset', calendar);
if (filesets.length) {
files = ['<dl class="fileset">'];
filesets.each(function(fileset, i) {
var label = $x('@label', fileset)[0].textContent;
files.push('<dt>', label, ':</dt>', '<dd>', '<ul>');
var ul = $(document.createElement('ul'));
$x('file', fileset).each(function(file, i) {
var li = $(document.createElement('li'));
var a = $(document.createElement('a'));
var name = $x('@name', file)[0].textContent;
var label;
if ($x('@label', file).length) {
label = $x('@label', file)[0].textContent;
}
if (/^(\w+:)?\/\/?/.test(name)) {
a.href = name;
} else {
a.href = 'lectures/' + id + '/files/' + section + '/' + name;
}
a.innerHTML = name.split('/').pop();
li.appendChild(a);
if (label)
li.innerHTML += " " + label;
if ($x('@supporting="true"', file)) {
li.addClassName('supporting');
}
ul.appendChild(li);
});
files.push(ul.innerHTML, '</ul>', '</dd>');
});
files.push('</dl>');
files = files.join('');
console.log('Files: ' + files);
}
var video = '';
if ($x(path + '/@recorded="true"', calendar)) {
var datestr = date.substring(0, 4) + '-' + date.substring(4, 6) + '-' + date.substring(6);
var link = $(document.createElement('a'));
link.className = 'videolink';
link.href = "javascript:playlecture('" + id + "','" + datestr + "','" + section + "')";
link.innerHTML = '<span class="play">▶</span> <span class="textonly">Play lecture</span>';
var temp = $(document.createElement('div'));
temp.appendChild(link);
video = temp.innerHTML;
}
if (tentative) {
article.addClassName('tentative');
article.innerHTML = content + minilab + video + files;
} else {
article.innerHTML = linkNode(lecture, id, content, false) + minilab + video + files;
}
SUBPAGES['lectures'].appendChild(article);
});
}
function playlecture(id, date, section) {
var urlbase = location.protocol + '//' + COURSE + '.ischool.uw.edu/lectures/' + QUARTER + '/' + date + '-' + id + '-section-' + section;
console.log("Going to play to video: " + urlbase + ".*");
var template = SRCDATA['video.html'];
$H({
'URLBASE': urlbase,
'WIDTH': 768,
'HEIGHT': 432,
'VIDEOID': 'video_lecture_' + date.replace(/-/g, '') + '_' + section
}).each(function(pair) {
template = template.replace(new RegExp("%%" + pair.key + "%%", "g"), pair.value);
});
console.log("video HTML: " + template);
showDialog(template);
videojs('video_lecture_' + date.replace(/-/g, '') + '_' + section, {
"controls": true,
"autoplay": false,
"preload": "auto"
});
$('screen').observe('click', dialogClick);
}
function dialogClick(event) {
dialogDismiss();
}
function labsInit() {
var labs = $x('//lab', SRCDATA['labs.xml']);
if (labs.length) {
labs.each(function(lab, i) {
var article = $(document.createElement('article'));
var id = $x('@id', lab)[0].textContent;
// get date-related stuff from calendar
var calendar = SRCDATA['calendar.xml'];
var section = localStorage['section'];
var path = '//section[@id="' + section + '"]/lab[@id="' + id + '"]';
var date = $x(path + '/@date', calendar)[0].textContent;
var tentative = $x(path + '/@tentative="true"', calendar);
var title = $x('title', lab)[0] ? $x('title', lab)[0].textContent : '';
var description = $x('description', lab)[0] ? $x('description', lab)[0].textContent : '';
var content = ['<hgroup>',
'<h3 id="', id, '">', title, '</h3>',
'<h4>', date.substring(4, 6) + '.' + date.substring(6), '</h4>',
'</hgroup>',
'<p>', description, '</p>'].join('');
if (tentative) {
article.addClassName('tentative');
article.innerHTML = content;
SUBPAGES['labs'].appendChild(article);
throw $break; // only display first tentative lab
} else {
article.innerHTML = linkNode(lab, id, content, false);
SUBPAGES['labs'].appendChild(article);
}
});
} else {
SUBPAGES['labs'].appendChild(noneYet('labs'));
}
}
function getWeekNum(date) {
date = date ? date : new Date();
// debug('getting week num for date: ' + date);
var startdate = new Date($x('//start/@date', SRCDATA['calendar.xml'])[0].textContent);
// debug('start date: ' + startdate.getTime());
var enddate = new Date($x('//end/@date', SRCDATA['calendar.xml'])[0].textContent);
// debug('end date: ' + enddate.getTime());
var weeks = $x('//week', SRCDATA['calendar.xml']);
// debug('weeks: ' + weeks);
if (date.getTime() < startdate.getTime()) {
return 1;
} else if (date.getTime() > enddate.getTime()) {
return weeks.length;
} else {
var weekinseconds = 60 * 60 * 24 * 7; // !!! WARNING: DST !!!
for (var i = 0; i < weeks.length; i++) {
var startofweek = startdate.getTime() + (weekinseconds * i * 1000);
if (date.getTime() <= startofweek) {
return i;
}
}
return i;
}
// if (date.getFullYear() < 2012)
// return 1;
// else if (date.getFullYear() > 2012)
// return 11;
// var m = date.getMonth();
// var d = date.getDate();
// switch (m) {
// case 0:
// case 1:
// case 2: // march
// return Math.max(Math.floor((d - 4) / 7) - 2, 1);
// break;
// case 3: // april
// return Math.floor((d - 2) / 7) + 2;
// break;
// case 4: // may
// return Math.floor((d + 1) / 7) + 6;
// break;
// case 5: // june
// default:
// return Math.min(Math.floor((d + 3) / 7) + 10, 11);
// break;
// }
}
function goToSubpagePath() {
// parse hash path
if (location.hash.substring(0, 2) == '#!') {
NAV = location.hash.split(/\//).slice(1, location.hash.lastIndexOf('/'));
} else {
NAV = [];
}
// populate empty spaces up to 3
for (var i = 0; i <= 2; i++) {
if (NAV.length <= i) {
NAV[i] = null;
}
}
if (!NAV[0])
NAV[0] = 'home'
// load subpage content, resolving any depencencies
resolveDependenciesForSubpage(NAV[0]);
}
function displaySubpage(name) {
var content = SUBPAGES[name];
content.style.display = 'none';
// console.log("Going to display subpage '" + name + "': " + SUBPAGES[name]);
// remove previous target
$$('.targeted').each(function(elem) {
elem.removeClassName('targeted');
});
// populate page with subpage content
$('main_content').update(content);
// revert to a previous WEEK if new data is not posted yet
if (name == 'home' || name == 'calendar') {
var WEEK = getWeekNum(NOW);
debug('WEEK: ' + WEEK);
// console.log("Looking for most current week (currently " + WEEK + ')...');
while (WEEK && !$x('//week[@number="' + WEEK + '"]', SRCDATA['calendar.xml'])[0]) {
// console.log("Week " + WEEK + ' not found, decrementing');
WEEK--;
}
// console.log("Settled on week " + WEEK);
}
// configure and display the appropriate page
switch (name) {
case 'home':
showWeek('home', WEEK);
break;
case 'calendar':
var showall = $$('.subpage.calendar header menu.show a.showall')[0];
switch (NAV[1]) {
case 'full':
showall.innerHTML = 'show only this week';
showall.href = '#!/calendar/';
showFullCalendar();
break;
case 'week':
showall.innerHTML = 'show entire quarter';
showall.href = '#!/calendar/full/';
showWeek('calendar', parseInt(NAV[2]));
break;
default:
showall.innerHTML = 'show entire quarter';
showall.href = '#!/calendar/full/';
showWeek('calendar', WEEK);
break;
}
break;
case 'lectures':
case 'labs':
case 'homework':
case 'syllabus':
case 'staff':
case 'software':
case 'dropbox':
default:
}
content.style.display = 'block';
$('main_content').style.visibility = 'visible';
document.body.className = name;
window.onhashchange = goToSubpagePath;
// setTimeout(function() {
// handle target scrolling
switch (name) {
case 'calendar':
var showall = $$('.subpage.calendar header menu.show a.showall')[0];
switch (NAV[1]) {
case 'full':
if (NAV[2]) {
$('week_' + NAV[2]).scrollTo();
}
break;
case 'week':
default:
}
break;
case 'home':
case 'lectures':
case 'labs':
case 'homework':
case 'syllabus':
case 'staff':
case 'software':
default:
if (NAV[1]) {
$(NAV[1]).addClassName('targeted');
$(NAV[1]).scrollTo();
}
}
// }, 50);
}
function showWeek(subpage, week) {
var subpageClass = '.subpage.' + subpage;
var cal = $$(subpageClass + ' table.calendar')[0];
cal.childElements().each(function(elem) {
elem.remove();
});
cal.appendChild(DOMDATA['calendar'][week-1]);
if (subpage == 'calendar') {
$$(subpageClass + ' nav.week span.number')[0].innerHTML = 'Week ' + week;
updateWeekNavArrowsForWeek(week);
}
}
function updateWeekNavArrowsForWeek(week) {
$$('.subpage.calendar nav.week')[0].show();
$$('.subpage.calendar header nav.week a.week').each(function(link, i) {
var chg = i == 0 ? -1 : 1;
var newweek = week + chg;
if (newweek > 0 && newweek < DOMDATA['calendar'].length + 1) {
link.href = '#!/calendar/week/' + newweek;
link.stopObserving('click', nullClick);
} else {
link.href = 'javascript:';
link.observe('click', nullClick);
}
});
}
function nullClick(event) {
event.stop();
}
function showFullCalendar() {
var cal = $$('.subpage.calendar table.calendar')[0];
cal.innerHTML = '';
DOMDATA['calendar'].each(function(row, i) {
cal.appendChild(row);
});
$$('.subpage.calendar nav.week')[0].hide();
// updateWeekNavArrows();
}
function linkNode(node, identifier, content, internal) {
var type = node.nodeName;
var target = type == 'lecture' || /^mini-homework/.test(identifier) ? identifier : identifier.replace(type + '-', '');
var label = type == 'homework' ? type : type + 's';
if (internal) {
return ['<a href="#!/', label, '/', target, '/">', content, '</a>'].join('');
} else {
return ['<a href="', label, '/', target, '/">', content, '</a>'].join('');
}
}
function $x(path, node, type) {
if (DEBUG) {
debug("path: " + path);
debug("node: " + node);
}
if (!type)
type = XPathResult.ANY_TYPE;
var xpe = node.ownerDocument || node;
if (DEBUG) {
debug("xpe: " + xpe);
}
var nsResolver = xpe.createNSResolver(xpe.documentElement);
var result = xpe.evaluate(path, node, nsResolver, type, null);
switch (result.resultType) {
case XPathResult.NUMBER_TYPE:
return result.numberValue;
break;
case XPathResult.STRING_TYPE:
return result.stringValue;
break;
case XPathResult.BOOLEAN_TYPE:
return result.booleanValue;
break;
default:
var found = new Array();
var res;
while (res = result.iterateNext()) {
found.push(res);
}
return found;
}
}
function debug(msg) {
var caller = debug.caller;
if (caller) {
caller = caller.caller;
}
caller = caller ? caller.name : 'anonymous';
console.log("[debug@" + caller + "] " + msg);
}
function ajaxFailure(ajax, e) {
// alert('failure!');
console.log(e);
}
function createSectionSelector() {
$('course_id').insert(new Element('ul', {
'id': 'section',
}));
SECTIONS.each(function(section, i) {
var a = new Element('a');
a.update(section.toUpperCase());
a.observe('click', sectionChange);
var li = new Element('li');
li.insert(a);
if (SECTION == section) {
li.addClassName('selected');
}
$('section').insert(li);
});
var offset = SECTIONS.indexOf(SECTION);
$('section').firstChild.style.marginTop = (-offset * .85) + 'em';
}
function createEmailLinks(section) {
section.select('.email').each(function(elem, i) {
var username = elem.innerHTML;
var text = elem.nodeName == 'ADDRESS' ? username + '@uw.edu' : username;
elem.update(new Element('a', { href: "mailto:" + username + "@uw.edu" }).update(text));
});
}
function sectionChange(event) {
event.stop();
localStorage['section'] = this.innerHTML.toLowerCase();
location.reload();
// TODO: soft refresh
}
function drawWeekNavArrows() {
$$('.subpage.calendar header nav.week a.week').each(function(link, i) {
link.innerHTML = '';
var s = parseInt($(document.body).getStyle('font-size')) / 18;
var canvas = $(document.createElement('canvas'));
canvas.width = 51 * s;
canvas.height = 13 * s;
// c.lineCap = 'square';
var c = canvas.getContext('2d');
c.lineWidth = 1 * s;
c.strokeStyle = '#000000';
c.beginPath();
if (i == 0) {
c.moveTo( 0.5 * s, 12.5 * s);
c.lineTo(25.5 * s, 0.5 * s);
c.lineTo(50.5 * s, 12.5 * s);
c.lineTo( 0.5 * s, 12.5 * s);
} else {
c.moveTo( 0.5 * s, 0.5 * s);
c.lineTo(50.5 * s, 0.5 * s);
c.lineTo(25.5 * s, 12.5 * s);
c.lineTo( 0.5 * s, 0.5 * s);
}
c.stroke();
link.appendChild(canvas);
});
}
function drawDropBoxArrows() {
var s = parseInt($(document.body).getStyle('font-size')) / 18;
var canvas = $(document.createElement('canvas'));
canvas.width = 45 * s;
canvas.height = 115 * s;
// c.lineCap = 'square';
var labs = $('nav_labs');
var homework = $('nav_homework');
$('main_nav').appendChild(canvas);
var c = canvas.getContext('2d');
c.lineWidth = .5 * s;
c.strokeStyle = '#000000';
c.beginPath();
c.moveTo( 0.5 * s, 0.0 * s);
c.lineTo( 0.5 * s, 84.5 * s);
c.lineTo(37.5 * s, 84.5 * s);
c.moveTo(37.5 * s, 35.0 * s);
c.lineTo(37.5 * s, 110.5 * s);
c.moveTo(32.5 * s, 105.5 * s);
c.lineTo(37.5 * s, 110.5 * s);
c.lineTo(42.5 * s, 105.5 * s);
c.stroke();
}