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();
69 $('#sign_up-link').hide();
71 $('.username').text('Guest');
72 $("#login_status").hide();
73 $('#login_link').text('Login').attr('href', '/login');
74 $('#register_link').show();
75 $('#profile_link').hide();
76 $('#sign_up-link').show();
80 if (response instanceof Array) {
81 $.each(response, function() {
82 ProtoDiv.reset("PROTO_" + this.id)
83 ProtoDiv.replicate("PROTO_" + this.id, this.data)
86 ProtoDiv.reset("PROTO_" + response.id)
87 ProtoDiv.replicate("PROTO_" + response.id, response.data)
90 $("#pg_" + pageId).fadeIn(100);
93 function message(type, msg) {
94 ProtoDiv.reset("PROTO_message");
95 ProtoDiv.replicate("PROTO_message", {type: type, msg: msg})
96 $("#messages").fadeIn(100);
99 function checkUser(cb) {
100 $.get('/checkuser', function(data) {
113 router.add('404', false, function() {
114 $("#pg_notfound").fadeIn(100);
118 router.add('home', false, function(cb) {
119 $('#learnsomething').unbind();
120 $('.nav').removeClass('active');
122 $('#signup').click(function(e) {
125 $('#learnsomething').click(function(e) {
126 $.get('/learn/random', function(data) {
127 if (data.status === 'ok') {
132 if ($('#vimeo-screencast').length === 0) {
133 $('.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>');
137 // go to the page that lists the schools
138 router.add('schools', function(data, cb) {
140 $('#school_link').addClass('active');
147 $('#pg_schools').fadeIn();
148 $('#schoolTmpl').tmpl( data.schools ).appendTo("#pg_schools #schools");
151 // go to the page that lists the courses for a specific school
152 router.add('school', function(data, cb) {
153 $('#school_link').addClass('active');
154 $('.sub_menu').hide();
155 //$('#new_course').unbind();
156 $('#form_course').hide().unbind();
159 data: data.school.courses
162 $("#school_name").html(data.school.name);
164 if (data.school.authorized) {
165 $('.sub_menu').show();
166 var form = $('#form_course');
170 form.submit(function(e) {
173 $.post(window.location.pathname, form.serialize(), function(data) {
174 if (data.status === 'error') {
175 message('error', data.message);
176 } else if (data.status === 'ok') {
178 goPage(window.location.pathname);
179 message('info', data.message);
184 cb("courses", response)
187 // go to the page that lists the lectures for a specific course
188 router.add('course', function(data, cb) {
189 $('#school_link').addClass('active');
190 $('.sub_menu').hide();
191 $('#new_lecture').unbind();
192 $('#form_lecture').hide().unbind();;
203 if (data.instructor) {
205 id: 'lectures_instructor',
206 data: data.instructor
213 data: data.lectures.map(function(lecture) {
214 var date = new Date(lecture.date);
215 lecture.date = date.toDateString();
220 cb('lectures', response);
222 if (!data.instructor.email) {
223 $('.instructor_email').hide();
225 $('.instructor_email').show();
228 if (data.course.authorized) {
229 $('.sub_menu').show();
230 $('#new_lecture').click(function(e) {
233 var form = $('#form_lecture');
237 form.submit(function(e) {
240 $.post(window.location.pathname, form.serialize(), function(data) {
241 if (data.status === 'error') {
242 message('error', data.message);
243 } else if (data.status === 'ok') {
245 goPage(window.location.pathname);
246 message('info', data.message);
256 // go to the page that lists the note taking sessions for a specific lecture
257 router.add('lecture', function(data, cb) {
258 $('#school_link').addClass('active');
259 $('.sub_menu').hide();
260 $('#new_note').unbind();
261 $('#form_note').hide().unbind();;
272 if (data.instructor) {
274 id: 'notes_instructor',
275 data: data.instructor
286 cb("notes", response);
288 if (!data.instructor.email) {
289 $('.instructor_email').hide();
291 $('.instructor_email').show();
294 if (data.lecture.authorized) {
295 $('.sub_menu').show();
296 $('#new_note').click(function(e) {
299 var form = $('#form_note');
303 form.submit(function(e) {
306 $.post(window.location.pathname, form.serialize(), function(data) {
307 if (data.status === 'error') {
308 message('error', data.message);
309 } else if (data.status === 'ok') {
311 goPage(window.location.pathname);
312 message('info', data.message);
321 // go to the page that lists the archived subject names
322 router.add('archive', function(data, cb) {
323 $('#archive_link').addClass('active');
326 id: 'archive_subject',
330 cb("archive_subjects", response)
335 router.add('archivesubject', function(data, cb) {
336 $('.nav').removeClass('active');
337 $('#archive_link').addClass('active');
340 id: 'archive_course',
344 cb("archive_courses", response)
349 router.add('archivecourse', function(data, cb) {
350 $('#archive_link').addClass('active');
357 cb("archive_notes", response)
362 router.add('archivenote', function(data, cb) {
363 $('#archive_link').addClass('active');
366 id: 'archive_note_display',
370 cb("archive_note_display", response)
375 // go to the account registration page
376 router.add('register', false, function(cb) {
377 $('#register_link').addClass('active');
378 $('#form_register').submit(function(e) {
383 $.post(window.location.pathname, form.serialize(), function(data) {
384 if (data.status === 'error') {
385 message('error', data.message);
387 } else if (data.status === 'ok') {
389 message('info', data.message);
396 router.add('activate', function(data, cb) {
398 message('info', data.message);
401 router.add('profile', false, function(cb) {
402 $('#profile_link').addClass('active');
403 var form = $('#form_profile');
404 $('input[type=password]','#form_profile').val('');
405 $('#affiliation').attr('value', user.affil);
406 $('#showName').attr('checked', user.showName)
407 form.find('.email').text(user.email);
408 form.find('input[name=name]').val(user.name);
409 form.submit(function(e) {
412 $.post(window.location.pathname, form.serialize(), function(data) {
413 if (data.status === 'error') {
414 message('error', data.message);
416 } else if (data.status === 'ok') {
418 message('info', data.message);
425 router.add('login', false, function(cb) {
426 $('input','#form_login').val('');
427 $('#form_login').submit(function(e) {
432 $.post(window.location.pathname, form.serialize(), function(data) {
433 if (data.status === 'error') {
434 message('error', data.message);
436 } else if (data.status === 'ok') {
438 message('info', 'Successfully logged in');
445 router.add('logout', function(data, cb) {
447 message('info', 'Successfully logged out');
450 router.add('resetpass', false, function(cb) {
451 $('input','#form_resetpass').val('');
452 $('#form_resetpass').submit(function(e) {
457 $.post(window.location.pathname, form.serialize(), function(data) {
458 if (data.status === 'error') {
459 message('error', data.message);
461 } else if (data.status === 'ok') {
463 message('info', data.message);
470 router.add('resetpw', false, function(cb) {
471 $('input','#form_resetpw').val('');
472 $('#form_resetpw').submit(function(e) {
477 $.post(window.location.pathname, form.serialize(), function(data) {
478 if (data.status === 'error') {
479 message('error', data.message);
481 } else if (data.status === 'ok') {
483 message('info', data.message);
490 // go to the press articles page
491 router.add('press', false, function(cb) {
492 $('#press_link').addClass('active');
497 // go to the "code of conduct" page
498 router.add('conduct', false, function(cb) {
504 /* Do and show the appropriate thing, based on the pages current URL */
505 function showPage(y) {
507 $('.page').hide(); //(100);// hide all pseudo pages
510 path = document.location.pathname,
511 routes = router.routes,
512 slugs = path.split('/');
516 var mainSlug = slugs[0].toLowerCase() || 'home';
518 if (mainSlug === 'archive') {
520 mainSlug = mainSlug + slugs[1];
524 if (routes[mainSlug]) {
525 router.run(mainSlug, path)
534 /* Simulates a page load.
535 'path' is something like "/schools", etc.
536 A page fetch doesn't really happen.
537 Based on what path looks like, an appropriate DIV is shown, and action taken
540 function goPage(path) {
541 if (history.pushState !== undefined) {
542 topQueue.push(window.pageYOffset)
543 history.pushState({}, path, path);
546 document.location = path;
550 /* Simulates a "back" browser navigation. */
552 function goBack(event) {
554 console.timeEnd('pop')
555 showPage( topQueue.pop() );
559 console.time('no-pop')
560 window.onpopstate = goBack
562 $(document).ready(function() {
564 // This code executes after the page has been fully loaded
566 $('body').on('click', 'a[href^=/]', function(e) {
567 var path = e.target.pathname || '/';
568 var checkNote = path.match(/\/([a-zA-Z]+)/);
569 if (checkNote && checkNote[1] == 'note') {
571 } else if (!history.pushState) {
579 // xxx older FF browsers don't fire a page load/reload - deal with it somehow.
580 // I've increased the timeout, we need to avoid calling showPage twice. It causes page flicker.
581 setTimeout(function() {
582 console.timeEnd('no-pop')
584 showPage( 0 ); // needed for some older browsers, redundant for chrome