Rework and feature parity to existing site
[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     ProtoDiv.inject("PROTO_login_info", user)
50     $("#login_status").show();
51     $('#login_link').text('Logout').attr('href', '/logout');
52     $('#register_link').hide();
53     $('#profile_link').show();
54   } else {
55     ProtoDiv.reset("PROTO_login_info");
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         console.log(this.id, this.data)
65         ProtoDiv.reset("PROTO_" + this.id)
66         ProtoDiv.replicate("PROTO_" + this.id, this.data)
67       })
68     } else {
69       ProtoDiv.reset("PROTO_" + response.id)
70       ProtoDiv.replicate("PROTO_" + response.id, response.data)
71     }
72   }
73   $("#pg_" + pageId).fadeIn(100);
74 }
75
76 function message(type, msg) {
77   ProtoDiv.reset("PROTO_message");
78   ProtoDiv.replicate("PROTO_message", {type: type, msg: msg})
79   $("#messages").fadeIn(100);
80 }
81
82 function checkUser(cb) {
83   $.get('/checkuser', function(data) {
84     if (data.user) {
85       user = data.user;
86     } else {
87       user = {};
88     }
89
90     if (cb) {
91       cb();
92     }
93   })
94 }
95
96 router.add('404', false, function() {
97   $("#pg_notfound").fadeIn(100);
98   window.scroll(0, 0)
99 });
100
101 router.add('home', false, function(cb) {
102   $('#learnsomething').unbind();
103         cb("home");
104   $('#learnsomething').click(function(e) {
105     $.get('/learn/random', function(data) {
106       if (data.status === 'ok') {
107         goPage(data.data);
108       }
109     })
110   });
111   if ($('#vimeo-screencast').length === 0) {
112     $('#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>');
113   }
114 });
115
116
117
118 // go to the page that lists the schools
119 router.add('schools', function(data, cb) {
120
121   var response = {
122     id: 'school',
123     data: data.schools
124   }
125
126   cb("schools", response);
127 });
128
129
130
131 // go to the page that lists the courses for a specific school
132 router.add('school', function(data, cb) {
133   $('#new_course').hide().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     $('#new_course').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   $('#new_lecture').hide().unbind();
175   $('#form_lecture').hide().unbind();;
176
177   var response = [];
178
179   if (data.course) {
180     response.push({
181       id: 'lectures_head',
182       data: data.course
183     })
184   }
185
186   if (data.instructor) {
187     response.push({
188       id: 'lectures_instructor',
189       data: data.instructor
190     })
191   }
192
193   if (data.lectures) {
194     response.push({
195       id: 'lecture',
196       data: data.lectures
197     })
198   }
199
200   if (data.course.authorized) {
201     $('#new_lecture').show();
202     $('#new_lecture').click(function(e) {
203       e.preventDefault();
204
205       var form = $('#form_lecture');
206
207       form.toggle();
208
209       form.submit(function(e) {
210         e.preventDefault();
211
212         $.post(window.location.pathname, form.serialize(), function(data) {
213           if (data.status === 'error') {
214             message('error', data.message);
215           } else if (data.status === 'ok') {
216             form.hide();
217             goPage(window.location.pathname);
218             message('info', data.message);
219           }
220         });
221       })
222     });
223   }
224
225   cb('lectures', response);
226 });
227
228
229
230 // go to the page that lists the note taking sessions for a specific lecture
231 router.add('lecture', function(data, cb) {
232   $('#new_note').hide().unbind();
233   $('#form_note').hide().unbind();;
234
235   var response = [];
236
237   if (data.notes) {
238     response.push({
239       id: 'note',
240       data: data.notes
241     })
242   }
243   
244   if (data.lecture.authorized) {
245     $('#new_note').show();
246     $('#new_note').click(function(e) {
247       e.preventDefault();
248
249       var form = $('#form_note');
250
251       form.toggle();
252
253       form.submit(function(e) {
254         e.preventDefault();
255
256         $.post(window.location.pathname, form.serialize(), function(data) {
257           if (data.status === 'error') {
258             message('error', data.message);
259           } else if (data.status === 'ok') {
260             form.hide();
261             goPage(window.location.pathname);
262             message('info', data.message);
263           }
264         });
265       })
266     });
267   }
268   cb("notes", response);
269 });
270
271
272 // go to the page that lists the archived subject names
273 router.add('archive', function(data, cb) {
274
275   var response = {
276     id: 'archive_subject',
277     data: data.subjects
278   }
279
280   cb("archive_subjects", response)
281 });
282
283
284
285 router.add('archivesubject', function(data, cb) {
286
287   var response = {
288     id: 'archive_course',
289     data: data.courses
290   }
291
292   cb("archive_courses", response)
293 });
294
295
296
297 router.add('archivecourse', function(data, cb) {
298
299   var response = {
300     id: 'archive_note',
301     data: data.notes
302   }
303
304   cb("archive_notes", response)
305 });
306
307
308
309 router.add('archivenote', function(data, cb) {
310
311   var response = {
312     id: 'archive_note_display',
313     data: data.note
314   }
315
316   cb("archive_note_display", response)
317 });
318
319
320
321 // go to the account registration page
322 router.add('register', false, function(cb) {
323   $('#form_register').submit(function(e) {
324     e.preventDefault();
325
326     console.log('register')
327     var form = $(this);
328
329     $.post(window.location.pathname, form.serialize(), function(data) {
330       if (data.status === 'error') {
331         message('error', data.message);
332         return false;
333       } else if (data.status === 'ok') {
334         goPage('/')
335         message('info', data.message);
336       }
337     })
338   })
339         cb("register");
340 });
341
342 router.add('activate', function(data, cb) {
343   goPage('/')
344   message('info', data.message);
345 });
346
347 router.add('profile', false, function(cb) {
348   var form = $('#form_profile');
349   $('input[type=password]','#form_profile').val('');
350   $('#affiliation').attr('value', user.affil);
351   $('#showName').attr('checked', user.showName)
352   form.find('.email').text(user.email);
353   form.find('input[name=name]').val(user.name);
354   form.submit(function(e) {
355     console.log('test')
356     e.preventDefault();
357
358     $.post(window.location.pathname, form.serialize(), function(data) {
359       if (data.status === 'error') {
360         message('error', data.message);
361         return false;
362       } else if (data.status === 'ok') {
363         goPage('/profile');
364         message('info', data.message);
365       }
366     })
367   })
368         cb("profile");
369 });
370
371 router.add('login', false, function(cb) {
372   $('input','#form_login').val('');
373   $('#form_login').submit(function(e) {
374     e.preventDefault();
375
376     var form = $(this);
377
378     $.post(window.location.pathname, form.serialize(), function(data) {
379       if (data.status === 'error') {
380         message('error', data.message);
381         return false;
382       } else if (data.status === 'ok') {
383         goPage('/')
384         message('info', 'Successfully logged in');
385       }
386     })
387   })
388         cb("login");
389 });
390
391 router.add('logout', function(data, cb) {
392   goPage('/')
393   message('info', 'Successfully logged out');
394 });
395
396 router.add('resetpass', false, function(cb) {
397   $('input','#form_resetpass').val('');
398   $('#form_resetpass').submit(function(e) {
399     e.preventDefault();
400
401     var form = $(this);
402
403     $.post(window.location.pathname, form.serialize(), function(data) {
404       if (data.status === 'error') {
405         message('error', data.message);
406         return false;
407       } else if (data.status === 'ok') {
408         goPage('/')
409         message('info', data.message);
410       }
411     })
412   })
413         cb("resetpass");
414 });
415
416 router.add('resetpw', false, function(cb) {
417   $('input','#form_resetpw').val('');
418   $('#form_resetpw').submit(function(e) {
419     e.preventDefault();
420
421     var form = $(this);
422
423     $.post(window.location.pathname, form.serialize(), function(data) {
424       if (data.status === 'error') {
425         message('error', data.message);
426         return false;
427       } else if (data.status === 'ok') {
428         goPage('/')
429         message('info', data.message);
430       }
431     })
432   })
433         cb("resetpw");
434 });
435
436 // go to the press articles page
437 router.add('press', false, function(cb) {
438         cb("press");
439 });
440
441
442 // go to the "code of conduct" page
443 router.add('conduct', false, function(cb) {
444         cb("conduct");
445 });
446
447
448
449 /* Do and show the appropriate thing, based on the pages current URL */
450 function showPage(y) {
451
452         $(".page").hide(); //(100);             // hide all pseudo pages
453
454         var path = document.location.pathname
455   var routes = router.routes;
456
457   var slugs = path.split('/');
458
459   slugs.shift();
460
461   mainSlug = slugs[0].toLowerCase() || 'home';
462
463   if (mainSlug === 'archive') {
464     if (slugs[1]) {
465       mainSlug = mainSlug + slugs[1];
466     }
467   }
468
469   if (routes[mainSlug]) {
470     router.run(mainSlug, path)
471   } else {
472     router.run('404')
473   }
474
475 }
476
477
478
479
480 /* Simulates a page load.
481         'path' is something like "/schools", etc.
482         A page fetch doesn't really happen.
483         Based on what path looks like, an appropriate DIV is shown, and action taken
484 */
485 var topQueue = [0]
486 function goPage(path) {
487         var y = 0 + window.pageYOffset
488         topQueue.push(y)
489         history.pushState({}, path, path);
490         showPage(0);
491 }
492
493
494 /* Simulates a "back" browser navigation.  */
495 function goBack(event) {
496         var y = topQueue.pop()
497         showPage( y );
498 }
499
500
501         window.onpopstate = goBack
502
503 $(document).ready(function() {
504
505         // This code executes after the page has been fully loaded
506
507   $('body').on('click', 'a[href^=/]', function(e) {
508     var path = e.target.pathname || '/';
509     var checkNote = path.match(/\/([a-zA-Z]+)/);
510     if (checkNote && checkNote[1] == 'note') {
511       return true;
512     } else if (!history.pushState) {
513       return true;
514     } else {
515       goPage(path)
516       return false;
517     }
518   })
519
520         // xxx older FF browsers don't fire a page load/reload - deal with it somehow.
521         // showPage( 0 );               // needed for some older browsers, redundant for chrome
522
523 })
524
525
526
527
528