/* This is the core logic for the main page. It implements most page transitions by showing and hiding DIV elements in the page with javascript+jquery */ /* Convert a JSON string to an object, or null if unparseable */ function j2o(json) { try { return JSON.parse(json); } catch(e) { return null; } } /* Convert an object to a JSON string (just easier to type than "JSON.stringify" */ function o2j(obj) { return JSON.stringify(obj); } var user = {}, router = { routes: {}, add: function(name, useAjax, cb) { if (typeof useAjax === 'function') { cb = useAjax; useAjax = true; } this.routes[name] = { fn: cb, useAjax: useAjax } }, run: function(name, path) { $('.nav').removeClass('active'); checkUser( function() { if (router.routes[name].useAjax) { $.get( path, {cache: false}, function(data) { if (data.status === 'not_found' || (typeof data === 'string')) { return router.run('404'); } router.routes[name].fn(data, render); } ); } else { router.routes[name].fn(render); } }); } } function tmpl_render() { if (user.name) { $('.username').text(user.name).attr('href', '/profile'); $("#login_status").show(); $('#login_link').text('Logout').attr('href', '/logout'); $('#register_link').hide(); $('#sign_up-link').hide(); } else { $('.username').text('Guest'); $("#login_status").hide(); $('#login_link').text('Login').attr('href', '/login'); $('#register_link').show(); $('#sign_up-link').show(); } }; function render(pageId, response) { console.log(user); if (user.name) { $('.username').text(user.name).attr('href', '/profile'); $("#login_status").show(); $('#login_link').text('Logout').attr('href', '/logout'); $('#register_link').hide(); $('#sign_up-link').hide(); } else { $('.username').text('Guest'); $("#login_status").hide(); $('#login_link').text('Login').attr('href', '/login'); $('#register_link').show(); $('#sign_up-link').show(); } if (response) { if (response instanceof Array) { $.each(response, function() { ProtoDiv.reset("PROTO_" + this.id) ProtoDiv.replicate("PROTO_" + this.id, this.data) }) } else { ProtoDiv.reset("PROTO_" + response.id) ProtoDiv.replicate("PROTO_" + response.id, response.data) } } $("#pg_" + pageId).fadeIn(function() { $("#g-footer").fadeIn(); // we don't want the footer jumping up and down }); } function message(type, msg) { ProtoDiv.reset("PROTO_message"); ProtoDiv.replicate("PROTO_message", {type: type, msg: msg}) $("#messages").fadeIn(100); } function checkUser(cb) { $.get('/checkuser', function(data) { console.log(data); if (data.user) { user = data.user; } else { user = {}; } if (cb) { cb(); } }) } router.add('404', false, function() { $("#pg_notfound").fadeIn(100); window.scroll(0, 0) }); // Legal page router.add('legal', false, function() { $("#pg_legal").fadeIn(100); }); // Team Page router.add('team', false, function() { $("#pg_team").fadeIn(100); }); // Contact Page router.add('contact', false, function() { $("#pg_contact").fadeIn(100); }); // About Page router.add('about', false, function() { $("#pg_about").fadeIn(100); }); router.add('home', false, function(cb) { $('#learnsomething').unbind(); $('.nav').removeClass('active'); cb("home"); $('#signup').click(function(e) { goPage('/register'); }); $('#learnsomething').click(function(e) { $.get('/learn/random', function(data) { if (data.status === 'ok') { goPage(data.data); } }) }); if ($('#vimeo-screencast').length === 0) { $('.video-wrapper').html(''); } }); // go to the page that lists the schools router.add('schools', function(data, cb) { $('#school_link').addClass('active'); tmpl_render(); var response = { id: 'school', data: data.schools } $('#pg_schools').fadeIn(function() { $('#g-footer').fadeIn(); }); $('#schoolTmpl').tmpl( data.schools ).appendTo("#pg_schools #schools"); }); // go to the page that lists the courses for a specific school router.add('school', function(data, cb) { $('#school_link').addClass('active'); $('.sub_menu').hide(); //$('#new_course').unbind(); $('#form_course').hide().unbind(); response = { id: 'course', data: data.school.courses } $('#pg_courses').fadeIn(function() { $('#g-footer').fadeIn(); }); $("#school_name").html(data.school.name); if (data.school.authorized) { $('.sub_menu').show(); var form = $('#form_course'); form.toggle(); form.submit(function(e) { e.preventDefault(); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); } else if (data.status === 'ok') { form.hide(); goPage(window.location.pathname); message('info', data.message); } }); }) } $('#courseTmpl').tmpl( data.school.courses ).appendTo("#pg_courses #main-content"); }); // go to the page that lists the lectures for a specific course router.add('course', function(data, cb) { $('#school_link').addClass('active'); $('.sub_menu').hide(); $('#new_lecture').unbind(); var response = []; if (data.course) { response.push({ id: 'lectures_head', data: data.course }) } if (data.instructor) { response.push({ id: 'lectures_instructor', data: data.instructor }) } if (data.lectures) { response.push({ id: 'lecture', data: data.lectures.map(function(lecture) { var date = new Date(lecture.date); lecture.date = date.toDateString(); return lecture; }) }) } cb('lectures', response); if (!data.instructor.email) { $('.instructor_email').hide(); } else { $('.instructor_email').show(); } if (data.course.authorized) { $('.sub_menu').show(); var form = $('#form_lecture'); form.show(); form.submit(function(e) { e.preventDefault(); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); } else if (data.status === 'ok') { form.hide(); goPage(window.location.pathname); message('info', data.message); } }); }) } }); // go to the page that lists the note taking sessions for a specific lecture router.add('lecture', function(data, cb) { $('#school_link').addClass('active'); $('.sub_menu').hide(); $('#new_note').unbind(); $('#form_note').hide().unbind();; var response = []; if (data.course) { response.push({ id: 'notes_head', data: data.course }) } if (data.instructor) { response.push({ id: 'notes_instructor', data: data.instructor }) } if (data.notes) { response.push({ id: 'note', data: data.notes }) } cb("notes", response); if (!data.instructor.email) { $('.instructor_email').hide(); } else { $('.instructor_email').show(); } if (data.lecture.authorized) { var form = $('#form_note').show(); form.submit(function(e) { e.preventDefault(); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); } else if (data.status === 'ok') { form.hide(); goPage(window.location.pathname); message('info', data.message); } }); }) } }); // go to the page that lists the archived subject names router.add('archive', function(data, cb) { $('#archive_link').addClass('active'); var response = { id: 'archive_subject', data: data.subjects } cb("archive_subjects", response) }); router.add('archivesubject', function(data, cb) { $('.nav').removeClass('active'); $('#archive_link').addClass('active'); var response = { id: 'archive_course', data: data.courses } cb("archive_courses", response) }); router.add('archivecourse', function(data, cb) { $('#archive_link').addClass('active'); var response = { id: 'archive_note', data: data.notes } cb("archive_notes", response) }); router.add('archivenote', function(data, cb) { $('#archive_link').addClass('active'); var response = { id: 'archive_note_display', data: data.note } cb("archive_note_display", response) }); // go to the account registration page router.add('register', false, function(cb) { $('#register_link').addClass('active'); $('#form_register').submit(function(e) { e.preventDefault(); var form = $(this); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); return false; } else if (data.status === 'ok') { goPage('/') message('info', data.message); } }) }) cb("register"); }); router.add('activate', function(data, cb) { goPage('/') message('info', data.message); }); router.add('profile', false, function(cb) { $('#profile_link').addClass('active'); var form = $('#form_profile'); $('input[type=password]','#form_profile').val(''); $('#affiliation').attr('value', user.affil); $('#showName').attr('checked', user.showName) form.find('.email').text(user.email); form.find('input[name=name]').val(user.name); form.submit(function(e) { e.preventDefault(); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); return false; } else if (data.status === 'ok') { goPage('/profile'); message('info', data.message); } }) }) cb("profile"); }); router.add('login', false, function(cb) { $('input','#form_login').val(''); $('#form_login').submit(function(e) { e.preventDefault(); var form = $(this); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); return false; } else if (data.status === 'ok') { goPage('/') message('info', 'Successfully logged in'); } }) }) cb("login"); }); router.add('logout', function(data, cb) { goPage('/') message('info', 'Successfully logged out'); }); router.add('resetpass', false, function(cb) { $('input','#form_resetpass').val(''); $('#form_resetpass').submit(function(e) { e.preventDefault(); var form = $(this); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); return false; } else if (data.status === 'ok') { goPage('/') message('info', data.message); } }) }) cb("resetpass"); }); router.add('resetpw', false, function(cb) { $('input','#form_resetpw').val(''); $('#form_resetpw').submit(function(e) { e.preventDefault(); var form = $(this); $.post(window.location.pathname, form.serialize(), function(data) { if (data.status === 'error') { message('error', data.message); return false; } else if (data.status === 'ok') { goPage('/') message('info', data.message); } }) }) cb("resetpw"); }); // go to the press articles page router.add('press', false, function(cb) { $('#press_link').addClass('active'); cb("press"); }); // go to the "code of conduct" page router.add('conduct', false, function(cb) { cb("conduct"); }); /* Do and show the appropriate thing, based on the pages current URL */ function showPage(y) { $('.page').hide(); //(100);// hide all pseudo pages $('#g-footer').hide(); var path = document.location.pathname, routes = router.routes, slugs = path.split('/'); slugs.shift(); var mainSlug = slugs[0].toLowerCase() || 'home'; console.log(slugs[0].toLowerCase()); if (mainSlug === 'archive') { if (slugs[1]) { mainSlug = mainSlug + slugs[1]; } } if (routes[mainSlug]) { router.run(mainSlug, path) } else { router.run('404') } } /* Simulates a page load. 'path' is something like "/schools", etc. A page fetch doesn't really happen. Based on what path looks like, an appropriate DIV is shown, and action taken */ var topQueue = [0] function goPage(path) { if (history.pushState !== undefined) { topQueue.push(window.pageYOffset) history.pushState({}, path, path); showPage(0); } else { document.location = path; } } /* Simulates a "back" browser navigation. */ var popped = false; function goBack(event) { popped = true; console.timeEnd('pop') showPage( topQueue.pop() ); } console.time('pop') console.time('no-pop') window.onpopstate = goBack $(document).ready(function() { // This code executes after the page has been fully loaded $('body').on('click', 'a[href^=/]', function(e) { var path = e.target.pathname || '/'; var checkNote = path.match(/\/([a-zA-Z]+)/); if (checkNote && checkNote[1] == 'note') { return true; } else if (!history.pushState) { return true; } else { goPage(path) return false; } }) // xxx older FF browsers don't fire a page load/reload - deal with it somehow. // I've increased the timeout, we need to avoid calling showPage twice. It causes page flicker. setTimeout(function() { console.timeEnd('no-pop') if (!popped) { showPage( 0 ); // needed for some older browsers, redundant for chrome } }, 1200) })