6607b07d99220e3b4dfa71d6830e8f73610b64ca
[oweals/finalsclub.git] / public / javascripts / main.js
1
2 /*
3
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
7
8 */
9
10
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; } }
13
14 /* Convert an object to a JSON string (just easier to type than "JSON.stringify" */
15 function o2j(obj) { return JSON.stringify(obj); }
16
17 var user = {};
18
19 var router = {
20   routes: {},
21   add: function(name, useAjax, cb) {
22     if (typeof useAjax === 'function') {
23       cb = useAjax;
24       useAjax = true;
25     }
26     this.routes[name] = {
27       fn: cb,
28       useAjax: useAjax
29     }
30   },
31   run: function(name, path) {
32     checkUser(function() {
33       if (router.routes[name].useAjax) {
34         $.get(path, {cache: false}, function(data) {
35           if (data.status === 'not_found' || (typeof data === 'string')) {
36             return router.run('404');
37           }
38           router.routes[name].fn(data, render);
39         });
40       } else {
41         router.routes[name].fn(render);
42       }
43     });
44   }
45 }
46
47 function render(pageId, response) {
48   if (user.name) {
49     $('.username').text(user.name);
50     $("#login_status").show();
51     $('#login_link').text('Logout').attr('href', '/logout');
52     $('#register_link').hide();
53     $('#profile_link').show();
54   } else {
55     $('.username').text('');
56     $("#login_status").hide();
57     $('#login_link').text('Login').attr('href', '/login');
58     $('#register_link').show();
59     $('#profile_link').hide();
60   }
61   if (response) {
62     if (response instanceof Array) {
63       $.each(response, function() {
64         ProtoDiv.reset("PROTO_" + this.id)
65         ProtoDiv.replicate("PROTO_" + this.id, this.data)
66       })
67     } else {
68       ProtoDiv.reset("PROTO_" + response.id)
69       ProtoDiv.replicate("PROTO_" + response.id, response.data)
70     }
71   }
72   $("#pg_" + pageId).fadeIn(100);
73 }
74
75 function message(type, msg) {
76   ProtoDiv.reset("PROTO_message");
77   ProtoDiv.replicate("PROTO_message", {type: type, msg: msg})
78   $("#messages").fadeIn(100);
79 }
80
81 function checkUser(cb) {
82   $.get('/checkuser', function(data) {
83     if (data.user) {
84       user = data.user;
85     } else {
86       user = {};
87     }
88
89     if (cb) {
90       cb();
91     }
92   })
93 }
94
95 router.add('404', false, function() {
96   $("#pg_notfound").fadeIn(100);
97   window.scroll(0, 0)
98 });
99
100 router.add('home', false, function(cb) {
101   $('#learnsomething').unbind();
102         cb("home");
103   $('#learnsomething').click(function(e) {
104     $.get('/learn/random', function(data) {
105       if (data.status === 'ok') {
106         goPage(data.data);
107       }
108     })
109   });
110   if ($('#vimeo-screencast').length === 0) {
111     $('#screencast').html('<iframe id="vimeo-screencast" src="http://player.vimeo.com/video/30647271?title=0&amp;byline=0&amp;portrait=0" width="350" height="250" frameborder="0" webkitallowfullscreen="webkitAllowFullScreen" allowfullscreen="allowFullScreen"></iframe>');
112   }
113 });
114
115
116
117 // go to the page that lists the schools
118 router.add('schools', function(data, cb) {
119
120   var response = {
121     id: 'school',
122     data: data.schools
123   }
124
125   cb("schools", response);
126 });
127
128
129
130 // go to the page that lists the courses for a specific school
131 router.add('school', function(data, cb) {
132   $('.sub_menu').hide();
133   $('#new_course').unbind();
134   $('#form_course').hide().unbind();
135   var response = {
136     id: 'course',
137     data: data.school.courses
138   }
139
140   $("#school_name").html(data.school.name);
141
142   if (data.school.authorized) {
143     $('.sub_menu').show();
144     $('#new_course').click(function(e) {
145       e.preventDefault();
146
147       var form = $('#form_course');
148
149       form.toggle();
150
151       form.submit(function(e) {
152         e.preventDefault();
153
154         $.post(window.location.pathname, form.serialize(), function(data) {
155           if (data.status === 'error') {
156             message('error', data.message);
157           } else if (data.status === 'ok') {
158             form.hide();
159             goPage(window.location.pathname);
160             message('info', data.message);
161           }
162         });
163       })
164     });
165   }
166   cb("courses", response)
167 });
168
169
170
171
172 // go to the page that lists the lectures for a specific course
173 router.add('course', function(data, cb) {
174   $('.sub_menu').hide();
175   $('#new_lecture').unbind();
176   $('#form_lecture').hide().unbind();;
177
178   var response = [];
179
180   if (data.course) {
181     response.push({
182       id: 'lectures_head',
183       data: data.course
184     })
185   }
186
187   if (data.instructor) {
188     response.push({
189       id: 'lectures_instructor',
190       data: data.instructor
191     })
192   }
193
194   if (data.lectures) {
195     response.push({
196       id: 'lecture',
197       data: data.lectures.map(function(lecture) {
198         var date = new Date(lecture.date);
199         lecture.date = date.toDateString();
200         return lecture;
201       })
202     })
203   }
204   cb('lectures', response);
205
206   if (!data.instructor.email) {
207     $('.instructor_email').hide();
208   } else {
209     $('.instructor_email').show();
210   }
211
212   if (data.course.authorized) {
213     $('.sub_menu').show();
214     $('#new_lecture').click(function(e) {
215       e.preventDefault();
216
217       var form = $('#form_lecture');
218
219       form.toggle();
220
221       form.submit(function(e) {
222         e.preventDefault();
223
224         $.post(window.location.pathname, form.serialize(), function(data) {
225           if (data.status === 'error') {
226             message('error', data.message);
227           } else if (data.status === 'ok') {
228             form.hide();
229             goPage(window.location.pathname);
230             message('info', data.message);
231           }
232         });
233       })
234     });
235   }
236
237 });
238
239
240
241 // go to the page that lists the note taking sessions for a specific lecture
242 router.add('lecture', function(data, cb) {
243   $('.sub_menu').hide();
244   $('#new_note').unbind();
245   $('#form_note').hide().unbind();;
246
247   var response = [];
248
249   if (data.course) {
250     response.push({
251       id: 'notes_head',
252       data: data.course
253     })
254   }
255
256   if (data.instructor) {
257     response.push({
258       id: 'notes_instructor',
259       data: data.instructor
260     })
261   }
262
263   if (data.notes) {
264     response.push({
265       id: 'note',
266       data: data.notes
267     })
268   }
269   
270   cb("notes", response);
271
272   if (!data.instructor.email) {
273     $('.instructor_email').hide();
274   } else {
275     $('.instructor_email').show();
276   }
277   
278   if (data.lecture.authorized) {
279     $('.sub_menu').show();
280     $('#new_note').click(function(e) {
281       e.preventDefault();
282
283       var form = $('#form_note');
284
285       form.toggle();
286
287       form.submit(function(e) {
288         e.preventDefault();
289
290         $.post(window.location.pathname, form.serialize(), function(data) {
291           if (data.status === 'error') {
292             message('error', data.message);
293           } else if (data.status === 'ok') {
294             form.hide();
295             goPage(window.location.pathname);
296             message('info', data.message);
297           }
298         });
299       })
300     });
301   }
302 });
303
304
305 // go to the page that lists the archived subject names
306 router.add('archive', function(data, cb) {
307
308   var response = {
309     id: 'archive_subject',
310     data: data.subjects
311   }
312
313   cb("archive_subjects", response)
314 });
315
316
317
318 router.add('archivesubject', function(data, cb) {
319
320   var response = {
321     id: 'archive_course',
322     data: data.courses
323   }
324
325   cb("archive_courses", response)
326 });
327
328
329
330 router.add('archivecourse', function(data, cb) {
331
332   var response = {
333     id: 'archive_note',
334     data: data.notes
335   }
336
337   cb("archive_notes", response)
338 });
339
340
341
342 router.add('archivenote', function(data, cb) {
343
344   var response = {
345     id: 'archive_note_display',
346     data: data.note
347   }
348
349   cb("archive_note_display", response)
350 });
351
352
353
354 // go to the account registration page
355 router.add('register', false, function(cb) {
356   $('#form_register').submit(function(e) {
357     e.preventDefault();
358
359     var form = $(this);
360
361     $.post(window.location.pathname, form.serialize(), function(data) {
362       if (data.status === 'error') {
363         message('error', data.message);
364         return false;
365       } else if (data.status === 'ok') {
366         goPage('/')
367         message('info', data.message);
368       }
369     })
370   })
371         cb("register");
372 });
373
374 router.add('activate', function(data, cb) {
375   goPage('/')
376   message('info', data.message);
377 });
378
379 router.add('profile', false, function(cb) {
380   var form = $('#form_profile');
381   $('input[type=password]','#form_profile').val('');
382   $('#affiliation').attr('value', user.affil);
383   $('#showName').attr('checked', user.showName)
384   form.find('.email').text(user.email);
385   form.find('input[name=name]').val(user.name);
386   form.submit(function(e) {
387     e.preventDefault();
388
389     $.post(window.location.pathname, form.serialize(), function(data) {
390       if (data.status === 'error') {
391         message('error', data.message);
392         return false;
393       } else if (data.status === 'ok') {
394         goPage('/profile');
395         message('info', data.message);
396       }
397     })
398   })
399         cb("profile");
400 });
401
402 router.add('login', false, function(cb) {
403   $('input','#form_login').val('');
404   $('#form_login').submit(function(e) {
405     e.preventDefault();
406
407     var form = $(this);
408
409     $.post(window.location.pathname, form.serialize(), function(data) {
410       if (data.status === 'error') {
411         message('error', data.message);
412         return false;
413       } else if (data.status === 'ok') {
414         goPage('/')
415         message('info', 'Successfully logged in');
416       }
417     })
418   })
419         cb("login");
420 });
421
422 router.add('logout', function(data, cb) {
423   goPage('/')
424   message('info', 'Successfully logged out');
425 });
426
427 router.add('resetpass', false, function(cb) {
428   $('input','#form_resetpass').val('');
429   $('#form_resetpass').submit(function(e) {
430     e.preventDefault();
431
432     var form = $(this);
433
434     $.post(window.location.pathname, form.serialize(), function(data) {
435       if (data.status === 'error') {
436         message('error', data.message);
437         return false;
438       } else if (data.status === 'ok') {
439         goPage('/')
440         message('info', data.message);
441       }
442     })
443   })
444         cb("resetpass");
445 });
446
447 router.add('resetpw', false, function(cb) {
448   $('input','#form_resetpw').val('');
449   $('#form_resetpw').submit(function(e) {
450     e.preventDefault();
451
452     var form = $(this);
453
454     $.post(window.location.pathname, form.serialize(), function(data) {
455       if (data.status === 'error') {
456         message('error', data.message);
457         return false;
458       } else if (data.status === 'ok') {
459         goPage('/')
460         message('info', data.message);
461       }
462     })
463   })
464         cb("resetpw");
465 });
466
467 // go to the press articles page
468 router.add('press', false, function(cb) {
469         cb("press");
470 });
471
472
473 // go to the "code of conduct" page
474 router.add('conduct', false, function(cb) {
475         cb("conduct");
476 });
477
478
479
480 /* Do and show the appropriate thing, based on the pages current URL */
481 function showPage(y) {
482
483         $(".page").hide(); //(100);             // hide all pseudo pages
484
485         var path = document.location.pathname
486   var routes = router.routes;
487
488   var slugs = path.split('/');
489
490   slugs.shift();
491
492   mainSlug = slugs[0].toLowerCase() || 'home';
493
494   if (mainSlug === 'archive') {
495     if (slugs[1]) {
496       mainSlug = mainSlug + slugs[1];
497     }
498   }
499
500   if (routes[mainSlug]) {
501     router.run(mainSlug, path)
502   } else {
503     router.run('404')
504   }
505
506 }
507
508
509
510
511 /* Simulates a page load.
512         'path' is something like "/schools", etc.
513         A page fetch doesn't really happen.
514         Based on what path looks like, an appropriate DIV is shown, and action taken
515 */
516 var topQueue = [0]
517 function goPage(path) {
518   if (history.pushState !== undefined) {
519     topQueue.push(window.pageYOffset)
520     history.pushState({}, path, path);
521     showPage(0);
522   } else {
523     document.location = path;
524   }
525 }
526
527
528 /* Simulates a "back" browser navigation.  */
529 var popped = false;
530 function goBack(event) {
531   popped = true;
532         showPage( topQueue.pop() );
533 }
534
535
536 window.onpopstate = goBack
537
538 $(document).ready(function() {
539
540         // This code executes after the page has been fully loaded
541
542   $('body').on('click', 'a[href^=/]', function(e) {
543     var path = e.target.pathname || '/';
544     var checkNote = path.match(/\/([a-zA-Z]+)/);
545     if (checkNote && checkNote[1] == 'note') {
546       return true;
547     } else if (!history.pushState) {
548       return true;
549     } else {
550       goPage(path)
551       return false;
552     }
553   })
554
555         // xxx older FF browsers don't fire a page load/reload - deal with it somehow.
556   setTimeout(function() {
557     if (!popped) {
558       showPage( 0 );            // needed for some older browsers, redundant for chrome
559     }
560   }, 200)
561
562 })
563
564
565
566
567