4 This is the core logic for the main page.
5 It implements most page transitions by showing and hiding DIV elements
6 in the page with javascript+jquery
11 /* Convert a JSON string to an object, or null if unparseable */
12 function j2o(json) { try { return JSON.parse(json); } catch(e) { return null; } }
14 /* Convert an object to a JSON string (just easier to type than "JSON.stringify" */
15 function o2j(obj) { return JSON.stringify(obj); }
24 add: function(name, useAjax, cb) {
25 if (typeof useAjax === 'function') {
36 run: function(name, path) {
38 $('.nav').removeClass('active');
40 checkUser( function() {
42 if (router.routes[name].useAjax) {
49 if (data.status === 'not_found' || (typeof data === 'string')) {
50 return router.run('404');
52 router.routes[name].fn(data, render);
56 router.routes[name].fn(render);
62 function render(pageId, response) {
64 $('.username').text("Hi, "+user.name+"!");
65 $("#login_status").show();
66 $('#login_link').text('Logout').attr('href', '/logout');
67 $('#register_link').hide();
68 $('#profile_link').show();
70 $('.username').text('Guest');
71 $("#login_status").hide();
72 $('#login_link').text('Login').attr('href', '/login');
73 $('#register_link').show();
74 $('#profile_link').hide();
78 if (response instanceof Array) {
79 $.each(response, function() {
80 ProtoDiv.reset("PROTO_" + this.id)
81 ProtoDiv.replicate("PROTO_" + this.id, this.data)
84 ProtoDiv.reset("PROTO_" + response.id)
85 ProtoDiv.replicate("PROTO_" + response.id, response.data)
88 $("#pg_" + pageId).fadeIn(100);
91 function message(type, msg) {
92 ProtoDiv.reset("PROTO_message");
93 ProtoDiv.replicate("PROTO_message", {type: type, msg: msg})
94 $("#messages").fadeIn(100);
97 function checkUser(cb) {
98 $.get('/checkuser', function(data) {
111 router.add('404', false, function() {
112 $("#pg_notfound").fadeIn(100);
116 router.add('home', false, function(cb) {
117 $('#learnsomething').unbind();
118 $('.nav').removeClass('active');
120 $('#signup').click(function(e) {
123 $('#learnsomething').click(function(e) {
124 $.get('/learn/random', function(data) {
125 if (data.status === 'ok') {
130 if ($('#vimeo-screencast').length === 0) {
131 $('.video-wrapper').html('<iframe id="vimeo-screencast" src="http://player.vimeo.com/video/30647271?title=0&byline=0&portrait=0&color=367da9" width="400" height="225" frameborder="0" webkitAllowFullScreen allowFullScreen></iframe>');
135 // go to the page that lists the schools
136 router.add('schools', function(data, cb) {
138 $('#school_link').addClass('active');
145 $('#pg_schools').fadeIn();
146 $('#schoolTmpl').tmpl( data.schools ).appendTo("#pg_schools #schools");
149 // go to the page that lists the courses for a specific school
150 router.add('school', function(data, cb) {
151 $('#school_link').addClass('active');
152 $('.sub_menu').hide();
153 //$('#new_course').unbind();
154 $('#form_course').hide().unbind();
157 data: data.school.courses
160 $("#school_name").html(data.school.name);
162 if (data.school.authorized) {
163 $('.sub_menu').show();
164 var form = $('#form_course');
168 form.submit(function(e) {
171 $.post(window.location.pathname, form.serialize(), function(data) {
172 if (data.status === 'error') {
173 message('error', data.message);
174 } else if (data.status === 'ok') {
176 goPage(window.location.pathname);
177 message('info', data.message);
182 cb("courses", response)
185 // go to the page that lists the lectures for a specific course
186 router.add('course', function(data, cb) {
187 $('#school_link').addClass('active');
188 $('.sub_menu').hide();
189 $('#new_lecture').unbind();
190 $('#form_lecture').hide().unbind();;
201 if (data.instructor) {
203 id: 'lectures_instructor',
204 data: data.instructor
211 data: data.lectures.map(function(lecture) {
212 var date = new Date(lecture.date);
213 lecture.date = date.toDateString();
218 cb('lectures', response);
220 if (!data.instructor.email) {
221 $('.instructor_email').hide();
223 $('.instructor_email').show();
226 if (data.course.authorized) {
227 $('.sub_menu').show();
228 $('#new_lecture').click(function(e) {
231 var form = $('#form_lecture');
235 form.submit(function(e) {
238 $.post(window.location.pathname, form.serialize(), function(data) {
239 if (data.status === 'error') {
240 message('error', data.message);
241 } else if (data.status === 'ok') {
243 goPage(window.location.pathname);
244 message('info', data.message);
254 // go to the page that lists the note taking sessions for a specific lecture
255 router.add('lecture', function(data, cb) {
256 $('#school_link').addClass('active');
257 $('.sub_menu').hide();
258 $('#new_note').unbind();
259 $('#form_note').hide().unbind();;
270 if (data.instructor) {
272 id: 'notes_instructor',
273 data: data.instructor
284 cb("notes", response);
286 if (!data.instructor.email) {
287 $('.instructor_email').hide();
289 $('.instructor_email').show();
292 if (data.lecture.authorized) {
293 $('.sub_menu').show();
294 $('#new_note').click(function(e) {
297 var form = $('#form_note');
301 form.submit(function(e) {
304 $.post(window.location.pathname, form.serialize(), function(data) {
305 if (data.status === 'error') {
306 message('error', data.message);
307 } else if (data.status === 'ok') {
309 goPage(window.location.pathname);
310 message('info', data.message);
319 // go to the page that lists the archived subject names
320 router.add('archive', function(data, cb) {
321 $('#archive_link').addClass('active');
324 id: 'archive_subject',
328 cb("archive_subjects", response)
333 router.add('archivesubject', function(data, cb) {
334 $('.nav').removeClass('active');
335 $('#archive_link').addClass('active');
338 id: 'archive_course',
342 cb("archive_courses", response)
347 router.add('archivecourse', function(data, cb) {
348 $('#archive_link').addClass('active');
355 cb("archive_notes", response)
360 router.add('archivenote', function(data, cb) {
361 $('#archive_link').addClass('active');
364 id: 'archive_note_display',
368 cb("archive_note_display", response)
373 // go to the account registration page
374 router.add('register', false, function(cb) {
375 $('#register_link').addClass('active');
376 $('#form_register').submit(function(e) {
381 $.post(window.location.pathname, form.serialize(), function(data) {
382 if (data.status === 'error') {
383 message('error', data.message);
385 } else if (data.status === 'ok') {
387 message('info', data.message);
394 router.add('activate', function(data, cb) {
396 message('info', data.message);
399 router.add('profile', false, function(cb) {
400 $('#profile_link').addClass('active');
401 var form = $('#form_profile');
402 $('input[type=password]','#form_profile').val('');
403 $('#affiliation').attr('value', user.affil);
404 $('#showName').attr('checked', user.showName)
405 form.find('.email').text(user.email);
406 form.find('input[name=name]').val(user.name);
407 form.submit(function(e) {
410 $.post(window.location.pathname, form.serialize(), function(data) {
411 if (data.status === 'error') {
412 message('error', data.message);
414 } else if (data.status === 'ok') {
416 message('info', data.message);
423 router.add('login', false, function(cb) {
424 $('input','#form_login').val('');
425 $('#form_login').submit(function(e) {
430 $.post(window.location.pathname, form.serialize(), function(data) {
431 if (data.status === 'error') {
432 message('error', data.message);
434 } else if (data.status === 'ok') {
436 message('info', 'Successfully logged in');
443 router.add('logout', function(data, cb) {
445 message('info', 'Successfully logged out');
448 router.add('resetpass', false, function(cb) {
449 $('input','#form_resetpass').val('');
450 $('#form_resetpass').submit(function(e) {
455 $.post(window.location.pathname, form.serialize(), function(data) {
456 if (data.status === 'error') {
457 message('error', data.message);
459 } else if (data.status === 'ok') {
461 message('info', data.message);
468 router.add('resetpw', false, function(cb) {
469 $('input','#form_resetpw').val('');
470 $('#form_resetpw').submit(function(e) {
475 $.post(window.location.pathname, form.serialize(), function(data) {
476 if (data.status === 'error') {
477 message('error', data.message);
479 } else if (data.status === 'ok') {
481 message('info', data.message);
488 // go to the press articles page
489 router.add('press', false, function(cb) {
490 $('#press_link').addClass('active');
495 // go to the "code of conduct" page
496 router.add('conduct', false, function(cb) {
502 /* Do and show the appropriate thing, based on the pages current URL */
503 function showPage(y) {
505 $('.page').hide(); //(100);// hide all pseudo pages
508 path = document.location.pathname,
509 routes = router.routes,
510 slugs = path.split('/');
514 var mainSlug = slugs[0].toLowerCase() || 'home';
516 if (mainSlug === 'archive') {
518 mainSlug = mainSlug + slugs[1];
522 if (routes[mainSlug]) {
523 router.run(mainSlug, path)
532 /* Simulates a page load.
533 'path' is something like "/schools", etc.
534 A page fetch doesn't really happen.
535 Based on what path looks like, an appropriate DIV is shown, and action taken
538 function goPage(path) {
539 if (history.pushState !== undefined) {
540 topQueue.push(window.pageYOffset)
541 history.pushState({}, path, path);
544 document.location = path;
548 /* Simulates a "back" browser navigation. */
550 function goBack(event) {
552 console.timeEnd('pop')
553 showPage( topQueue.pop() );
557 console.time('no-pop')
558 window.onpopstate = goBack
560 $(document).ready(function() {
562 // This code executes after the page has been fully loaded
564 $('body').on('click', 'a[href^=/]', function(e) {
565 var path = e.target.pathname || '/';
566 var checkNote = path.match(/\/([a-zA-Z]+)/);
567 if (checkNote && checkNote[1] == 'note') {
569 } else if (!history.pushState) {
577 // xxx older FF browsers don't fire a page load/reload - deal with it somehow.
578 // I've increased the timeout, we need to avoid calling showPage twice. It causes page flicker.
579 setTimeout(function() {
580 console.timeEnd('no-pop')
582 showPage( 0 ); // needed for some older browsers, redundant for chrome