main.js 14 KB

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