1: ////////////////////////////////////////////////////////////////////////////////
2: ////////////////////////////////////////////////////////////////////////////////
3: //
4: // ccc_login.js: CloudSession(.com) Control Center login program
5: //
6: // copyright 2010 Douglas McClendon -- dawg AT cloudsession DOT com
7: //
8: //
9: // This is/was my first javascript program. It started as literally hello
10: // world (see EOF comments), and quickly progressed into a full fledge AJAX
11: // login handler for CloudSession.com.
12: //
13: // Please feel free to send any comments or critiques to the author, as no
14: // doubt due to his inexperience with javascript, there are many imperfections.
15: //
16: // Potential employers: note that this is still in early rapid development,
17: // and not at all polished yet. It is what it is.
18: //
19: ////////////////////////////////////////////////////////////////////////////////
20: ////////////////////////////////////////////////////////////////////////////////
21:
22:
23: ////////////////////////////////////////////////////////////////////////////////
24: //
25: // TODO
26: //
27: // see ccc/notes.txt
28: //
29: // - perhaps objectify the main mode screens. shared virtual/inherited func
30: // for transitions
31: //
32: ////////////////////////////////////////////////////////////////////////////////
33:
34:
35: ////////////////////////////////////////////////////////////////////////////////
36: //
37: // Enums
38: //
39: ////////////////////////////////////////////////////////////////////////////////
40:
41: /* unused, found a better way, and I think there are better ways to do this
42: ccc = new Object();
43:
44: ccc.dyn_pg_states = {
45: "NONE" : 0,
46: "LOGIN" : 1,
47: "ABOUT" : 2,
48: "SIGNUP" : 3
49: "LOGGEDIN" : 3
50: }
51: */
52:
53:
54: ////////////////////////////////////////////////////////////////////////////////
55: //
56: // Globals
57: //
58: ////////////////////////////////////////////////////////////////////////////////
59:
60: // developer mode
61: var dev = 0;
62: // comment this out for a slower non-development experience
63: dev = 1;
64:
65: // e.g. get object of url parms
66: //var all_url_vars = $.getUrlVars();
67:
68: // this gets set if an insufficient browser version is detected
69: var browser_bail = 0;
70: var browser_brand = '';
71: var browser_version = 0;
72:
73: // main page state (login/about/signup/...)
74: var ccc_dyn_pg;
75:
76: // authenticated correctly yet?
77: var logged_in = 0;
78:
79: // TODO: make this a simple hash/object
80: var logged_in_username = '';
81: var logged_in_password = '';
82:
83: // alias
84: var body;
85:
86: // seedstuffs
87: var seed_id = -1;
88: var seed = '';
89:
90: //
91: // rendering feature flags
92: //
93:
94: // OSX.4 not so happy with showing content right justified
95: var use_animated_show = 1;
96:
97: //
98: // user controllable
99: //
100: var bg_shown = 1;
101:
102:
103: ////////////////////////////////////////////////////////////////////////////////
104: //
105: // classes
106: //
107: ////////////////////////////////////////////////////////////////////////////////
108:
109: // note: this describes javascripts _two ways_ of implementing inheritance-
110: // http://www.webreference.com/js/column79/3.html
111: // with the second being 'more robust'
112: // http://www.webreference.com/js/column79/4.html
113:
114: // edunote/reviewer?: References for OOP in javascript seem very confused.
115: // For now, I'll just go with this-
116: //
117: // function AdBox() {
118: // this.width = 200;
119: // this.height = 60;
120: // this.text = 'default ad text';
121: // this.prototype.move = function() {
122: // // code for move method goes here
123: // }
124: // this.prototype.display = function() {
125: // // code for display method goes here
126: // }
127: // }
128:
129:
130: ////////////////////////////////////////////////////////////////////////////////
131: //
132: // functions
133: //
134: ////////////////////////////////////////////////////////////////////////////////
135:
136:
137: ////////////////////////////////////////////////////////////////////////////////
138: function setup_initial_page_unveil_anim ()
139: {
140: // animation timing
141: var ccc_main_logo_text_start_t;
142: var ccc_main_logo_text_anim_t;
143: var ccc_main_logo_anim_t;
144: var ccc_login_anim_t;
145: var ccc_all_else_wait_t;
146: var ccc_all_else_anim_t;
147: var ccc_main_logo_fadein_start_t;
148: var ccc_main_logo_animate_start_t;
149: var ccc_login_slide_start_t;
150: var ccc_all_else_start_t;
151: var ccc_all_else_done_t;
152:
153: // initially hide all of the dynamic pages
154: $(".ccc_dyn_pg_right").hide();
155: $(".ccc_dyn_pg_left").hide();
156: $(".ccc_dyn_pg_bottom").hide();
157:
158: // hide everything else too
159: $("#ccc_main_logo_text").hide();
160: $("#ccc_main_logo").hide();
161: $("#ccc_dyn_pg_filler_area").hide();
162:
163:
164: // use a fast mode if in development
165: if (dev == 1) {
166: ccc_main_logo_text_start_t = 250;
167: ccc_main_logo_text_anim_t = 200;
168: ccc_main_logo_anim_t = 1000;
169: ccc_login_anim_t = 200;
170: ccc_all_else_wait_t = 123;
171: ccc_all_else_anim_t = 200;
172: } else {
173: ccc_main_logo_text_start_t = 500;
174: ccc_main_logo_text_anim_t = 1000;
175: ccc_main_logo_anim_t = 2000;
176: ccc_login_anim_t = 1000;
177: ccc_all_else_wait_t = 500;
178: ccc_all_else_anim_t = 1000;
179:
180: }
181:
182:
183: //
184: // calculate animation times (for code readability)
185: //
186: ccc_main_logo_fadein_start_t =
187: ccc_main_logo_text_start_t + ccc_main_logo_text_anim_t;
188:
189: ccc_main_logo_animate_start_t =
190: ccc_main_logo_fadein_start_t + ccc_main_logo_anim_t;
191:
192: ccc_login_slide_start_t =
193: ccc_main_logo_animate_start_t + ccc_main_logo_anim_t;
194:
195: ccc_all_else_start_t =
196: ccc_login_slide_start_t + ccc_login_anim_t + ccc_all_else_wait_t;
197:
198: ccc_all_else_done_t =
199: ccc_all_else_start_t + ccc_all_else_anim_t;
200:
201: // start at top on page reload
202: smooth_scroll_to_top();
203:
204: //
205: // set up initial animation sequence
206: //
207: setTimeout(function () {
208: if (use_animated_show) {
209: $("#ccc_main_logo_text").show(ccc_main_logo_text_anim_t);
210: } else {
211: $("#ccc_main_logo_text").fadeIn(ccc_main_logo_text_anim_t);
212: }
213: }, ccc_main_logo_text_start_t);
214: setTimeout(function () {
215: $("#ccc_main_logo").fadeIn(ccc_main_logo_anim_t);
216: }, ccc_main_logo_fadein_start_t);
217: setTimeout(function () {
218: $("#ccc_main_logo").animate({width: '20em'},ccc_main_logo_anim_t);
219: }, ccc_main_logo_animate_start_t);
220: setTimeout(function () {
221: if (use_animated_show) {
222: $("#ccc_dyn_pg_left_login").show(ccc_login_anim_t);
223: } else {
224: $("#ccc_dyn_pg_left_login").fadeIn(ccc_login_anim_t);
225: }
226: }, ccc_login_slide_start_t);
227: // note, bottom, with login button is here because otherwise the right would
228: // cause it to slide down a bit more after the first slide.
229: setTimeout(function () {
230: if (use_animated_show) {
231: $("#ccc_dyn_pg_right_login").show(ccc_all_else_anim_t);
232: $("#ccc_dyn_pg_bottom_login").show(ccc_all_else_anim_t);
233: } else {
234: $("#ccc_dyn_pg_right_login").fadeIn(ccc_all_else_anim_t);
235: $("#ccc_dyn_pg_bottom_login").fadeIn(ccc_all_else_anim_t);
236: }
237: $('#username').focus();
238: }, ccc_all_else_start_t);
239: setTimeout(function () {
240: $("#ccc_dyn_pg_filler_area").hide(ccc_all_else_anim_t);
241: // set dynamic page state
242: ccc_dyn_pg = ".ccc_dyn_pg_login";
243: }, ccc_all_else_done_t);
244:
245: // show or hide the background, as possibly determined from user cookie
246: if (bg_shown == 1) {
247: setTimeout(function () {$(".bgmaximage").fadeIn(3000);}, 3000);
248: } else {
249: setTimeout(function () {$(".bgmaximage").fadeOut(3000);}, 3000);
250: }
251:
252:
253: }
254:
255:
256: ////////////////////////////////////////////////////////////////////////////////
257: // this function taken from a comment from user edeiller on api.jquery.com page
258: function detect_browser_version()
259: {
260: var userAgent = navigator.userAgent.toLowerCase();
261: $.browser.chrome = /chrome/.test(navigator.userAgent.toLowerCase());
262: var version = 0;
263:
264: // Is this a version of IE?
265: if($.browser.msie){
266: userAgent = $.browser.version;
267: userAgent = userAgent.substring(0,userAgent.indexOf('.'));
268: version = userAgent;
269: }
270:
271: // Is this a version of Chrome?
272: if($.browser.chrome){
273: userAgent = userAgent.substring(userAgent.indexOf('chrome/') +7);
274: userAgent = userAgent.substring(0,userAgent.indexOf('.'));
275: version = userAgent;
276: // If it is chrome then jQuery thinks it's safari so we have to tell it it isn't
277: $.browser.safari = false;
278: }
279:
280: // Is this a version of Safari?
281: if($.browser.safari){
282: userAgent = userAgent.substring(userAgent.indexOf('safari/') +7);
283: userAgent = userAgent.substring(0,userAgent.indexOf('.'));
284: version = userAgent;
285: }
286:
287: // Is this a version of Mozilla?
288: if($.browser.mozilla){
289: //Is it Firefox?
290: if(navigator.userAgent.toLowerCase().indexOf('firefox') != -1){
291: userAgent = userAgent.substring(userAgent.indexOf('firefox/') +8);
292: userAgent = userAgent.substring(0,userAgent.indexOf('.'));
293: version = userAgent;
294: }
295: // If not then it must be another Mozilla
296: else{
297: }
298: }
299:
300: // Is this a version of Opera?
301: if($.browser.opera){
302: userAgent = userAgent.substring(userAgent.indexOf('version/') +8);
303: userAgent = userAgent.substring(0,userAgent.indexOf('.'));
304: version = userAgent;
305: }
306: return version;
307: }
308:
309:
310: ////////////////////////////////////////////////////////////////////////////////
311: // count words in a textelement
312: // note: this is stripped down version of (the presumably public domain)-
313: // http://javascript.internet.com/forms/word-count.html
314: function te_word_count(textelement)
315: {
316: var char_count = textelement.val().length;
317: var fullStr = textelement.val() + " ";
318: var initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi;
319: var left_trimmedStr = fullStr.replace(initial_whitespace_rExp, "");
320: var non_alphanumerics_rExp = rExp = /[^A-Za-z0-9]+/gi;
321: var cleanedStr = left_trimmedStr.replace(non_alphanumerics_rExp, " ");
322: var splitString = cleanedStr.split(" ");
323: var word_count = splitString.length - 1;
324: if (fullStr.length <2) {
325: word_count = 0;
326: }
327: return word_count;
328: }
329:
330:
331: ////////////////////////////////////////////////////////////////////////////////
332: // scroll to top of page smoothly (mostly from user glenngv at codingforums.com)
333: var sstt_timeout;
334: function smooth_scroll_to_top()
335: {
336: if (document.body.scrollTop != 0 ||
337: document.documentElement.scrollTop != 0) {
338: window.scrollBy(0,-5);
339: sstt_timeout = setTimeout('smooth_scroll_to_top()', 10);
340: } else {
341: clearTimeout(sstt_timeout);
342: }
343: }
344:
345:
346: ////////////////////////////////////////////////////////////////////////////////
347: // switch to new dynamic page mode (login/signup/about/...)
348: function dyn_pg_mode_switch(new_mode)
349: {
350: // animation timing
351: var ccc_dyn_pg_pause_t;
352: var ccc_dyn_pg_fadein_t;
353: var ccc_dyn_pg_fadeout_t;
354:
355:
356: // use a fast mode if in development
357: if (dev == 1) {
358: ccc_dyn_pg_pause_t = 200;
359: ccc_dyn_pg_fadein_t = 500;
360: ccc_dyn_pg_fadeout_t = 500;
361: } else {
362: ccc_dyn_pg_pause_t = 300;
363: ccc_dyn_pg_fadein_t = 1000;
364: ccc_dyn_pg_fadeout_t = 1000;
365: }
366:
367: //
368: // do fadeout of current dynamic content, and set up fadein
369: //
370: setTimeout(function () {
371: // edunote: the focus thing works here, while document.getElementById on its own
372: // would not, because apparently when not shown, d.gEBI returns
373: // null, wheras this selector does the right thing in both cases.
374: // Thus, right answer is to have one line here per mode-
375:
376: // start user at the top of the metapage
377: // jumpy
378: // scroll(0,0);
379: smooth_scroll_to_top();
380:
381: $(".ccc_dyn_pg_right" + ccc_dyn_pg).fadeOut(ccc_dyn_pg_fadeout_t, function () {
382: $(".ccc_dyn_pg_right" + new_mode).fadeIn(ccc_dyn_pg_fadein_t);
383: });
384: $(".ccc_dyn_pg_left" + ccc_dyn_pg).fadeOut(ccc_dyn_pg_fadeout_t, function () {
385: $(".ccc_dyn_pg_left" + new_mode).fadeIn(ccc_dyn_pg_fadein_t);
386: // default focus for login
387: $('#username').focus();
388: });
389: $(".ccc_dyn_pg_bottom" + ccc_dyn_pg).fadeOut(ccc_dyn_pg_fadeout_t, function () {
390: $(".ccc_dyn_pg_bottom" + new_mode).fadeIn(ccc_dyn_pg_fadein_t);
391: });
392: // set the new mode, and assume (see TODO) all inputs will be blocked during
393: // transition animations.
394: ccc_dyn_pg = new_mode;
395: }, ccc_dyn_pg_pause_t);
396: }
397:
398:
399: ////////////////////////////////////////////////////////////////////////////////
400: function do_signed_up(xml, req_username)
401: {
402: signup_success_text = "CCC Sign-up for the new user - " + req_username +
403: " - has been processed and is pending" +
404: " administrator approval. If you supplied an email address, you" +
405: " will receive confirmation when your account has been activated." +
406: " Thank you, have an excellent day.";
407: document.getElementById('ccc_signup_success_dialog').innerHTML =
408: signup_success_text;
409: $('#ccc_signup_success_dialog').dialog({
410: width: 600,
411: close:
412: function (evenut,ui) {
413: // clear the signup form
414: signup_req_clear_button_handler();
415: // switch to the about page
416: dyn_pg_mode_switch(".ccc_dyn_pg_about");
417: }
418: });
419: }
420:
421:
422: ////////////////////////////////////////////////////////////////////////////////
423: function do_log_on(xml)
424: {
425: var loggedin_div;
426:
427: logged_in = 1;
428: logged_in_username = document.getElementById('username').value;
429: logged_in_password = document.getElementById('password').value;
430:
431: clear_userpass();
432: $('#username').attr('disabled', true);
433: $('#password').attr('disabled', true);
434:
435:
436: document.getElementById('ccc_login_status').innerHTML =
437: "logged in";
438: $('#ccc_login_server_response').hide('fast');
439:
440: /*
441: // old reference: how I first played with tabs in js only (!php/ajax)
442: newtabs = document.createElement('div');
443: newtabs.setAttribute('id', 'loggedin_tabs');
444:
445: tablist = document.createElement('ul');
446: newtabs.appendChild(tablist);
447:
448: tab_one = document.createElement('li');
449: tablist.appendChild(tab_one);
450: tab_one_link = document.createElement('a');
451: tab_one_link.setAttribute('href', '#loggedin_tabs-1');
452: tab_one.appendChild(tab_one_link);
453: tab_one_link_text = document.createTextNode('something');
454: tab_one_link.appendChild(tab_one_link_text);
455:
456: tab_one_div = document.createElement('div');
457: newtabs.appendChild(tab_one_div);
458: tab_one_div.setAttribute('id', 'loggedin_tabs-1');
459: tab_one_content = document.createElement('p');
460: tab_one_div.appendChild(tab_one_content);
461: tab_one_content_text = document.createTextNode('some text');
462: tab_one_content.appendChild(tab_one_content_text);
463:
464: tab_two = document.createElement('li');
465: tablist.appendChild(tab_two);
466: tab_two_link = document.createElement('a');
467: tab_two_link.setAttribute('href', '#loggedin_tabs-2');
468: tab_two.appendChild(tab_two_link);
469: tab_two_link_text = document.createTextNode('someotherthing');
470: tab_two_link.appendChild(tab_two_link_text);
471:
472: tab_two_div = document.createElement('div');
473: newtabs.appendChild(tab_two_div);
474: tab_two_div.setAttribute('id', 'loggedin_tabs-2');
475: tab_two_content = document.createElement('p');
476: tab_two_div.appendChild(tab_two_content);
477: tab_two_content_text = document.createTextNode('some other text');
478: tab_two_content.appendChild(tab_two_content_text);
479:
480: document.getElementById('ccc_dyn_pg_left_loggedin').appendChild(newtabs);
481: */
482:
483: ////////////////////////////////////////////////////////////////////////////////
484: // note: major: This is, gross ugly and hackish _looking_. The first cleanup
485: // might be to use a seperate ajax response that only returns the
486: // renderable x/ht/ml, ... but actually, I think I'd still have to
487: // use these replaces (which could probably be made prettier).
488: // The real solution, seems to be elucidated(word?) in this article,
489: // and I was happy that it actually reassures me that the painful
490: // brute force 'right' method that I had been coming to in my mind,
491: // turns out to actually be the correct one. Though I still need to
492: // dig a few links to see a good example of such an xml walkthru
493: // cloning.
494: //
495: // http://slayeroffice.com/articles/innerHTML_alternatives/#6a
496: //
497: // note: also todo: try $.load(), described as simply ajax loading a div,
498: // though not appropriate here, as I want the content to not be available
499: // to unauthenticated users. (but I'll no doubt learn more by using it)
500: ////////////////////////////////////////////////////////////////////////////////
501:
502: // note: ]]> in place of the final replace's ... will work, but messes with
503: // emac's syntax recognition
504: document.getElementById('ccc_dyn_pg_left_loggedin').innerHTML =
505: $('loggedin_xml', xml).text().
506: replace(/^.*xml.version......../g, '').replace(/...$/g, '');
507:
508:
509: $("#loggedin_tabs").tabs();
510: $("#loggedin_tabs").tabs('select', '#loggedin_tabs-control');
511:
512: dyn_pg_mode_switch(".ccc_dyn_pg_loggedin");
513: }
514:
515:
516: ////////////////////////////////////////////////////////////////////////////////
517: //
518: function do_log_out(xml)
519: {
520: logged_in = 0;
521: clear_userpass();
522: logged_in_username = '';
523: logged_in_password = '';
524:
525: $('#username').removeAttr('disabled');
526: $('#password').removeAttr('disabled');
527:
528:
529: document.getElementById('ccc_login_status').innerHTML =
530: "logged out";
531: document.getElementById('ccc_login_server_response').innerHTML =
532: "cloudsession user logged out";
533:
534: dyn_pg_mode_switch(".ccc_dyn_pg_login");
535: }
536:
537:
538: ////////////////////////////////////////////////////////////////////////////////
539: // handle a server authentication request response
540: function seed_response_handler(xml)
541: {
542:
543: if ($('seed_id', xml).text() == '') {
544: document.getElementById('ccc_login_server_response').innerHTML =
545: "server failed to acknowledge login request, please try again";
546: return;
547: }
548:
549: hashed_password = $.sha256($.sha256($("input[name=password]")) +
550: $('seed', xml).text());
551:
552: $.post("cgi/ccc_login.php", {
553: command: "validate-login",
554: username: $("input[name=username]").val(),
555: hashed_password: hashed_password,
556: seed_id: $('seed_id', xml).text()
557: }, function (xml) {auth_response_handler(xml);});
558:
559: /* why does this not work when commenting out the post above??
560: document.getElementById('ccc_login_server_response').innerHTML =
561: "posted:: " + "username: " + $("input[name=username]").val() +
562: "hashed_password: " + hashed_password + "seed_id: " + $('seed_id', xml).text();
563: document.getElementById('ccc_login_server_response').show('fast');
564: */
565:
566: // TODO: need busy indicator and 7(+?)s timeout here
567: }
568:
569:
570: ////////////////////////////////////////////////////////////////////////////////
571: // handle a server authentication request response
572: function auth_response_handler(xml)
573: {
574: if ( $("validate_login_result", xml).text().match(/valid login/g) ) {
575: do_log_on(xml);
576: } else {
577: $('#ccc_login_server_response').show('fast');
578: document.getElementById('ccc_login_status').innerHTML =
579: "login failed, not logged in";
580: if ( $("server_error", xml).text() != "" ) {
581: document.getElementById('ccc_login_server_response').innerHTML =
582: $("server_error", xml).text() + ",<br/>please try again";
583: }
584: if ( $("validate_login_result", xml).text() != "" ) {
585: document.getElementById('ccc_login_server_response').innerHTML =
586: $("validate_login_result", xml).text() + ",<br/>please try again";
587: }
588: }
589: }
590:
591:
592: ////////////////////////////////////////////////////////////////////////////////
593: // handle a server authentication request response
594: function signup_response_handler(xml, req_username)
595: {
596: if ( $("validate_signup_result", xml).text().match(/valid signup/g) ) {
597: do_signed_up(xml, req_username);
598: } else {
599: signup_response_text = '';
600: signup_response_text += "CCC Sign-up failed.<br/><br/>";
601: if ( $("server_error", xml).text() != "" ) {
602: signup_response_text +=
603: $("server_error", xml).text() + ",<br/>please try again";
604: } else if ( $("validate_signup_result", xml).text() != "" ) {
605: signup_response_text +=
606: $("validate_signup_result", xml).text() + ",<br/>please try again";
607: }
608: document.getElementById('ccc_signup_server_error_dialog').innerHTML =
609: signup_response_text;
610: $('#ccc_signup_server_error_dialog').dialog({ width: 600 });
611: }
612: }
613:
614:
615: ////////////////////////////////////////////////////////////////////////////////
616: // check if any of the dynamic page mode switch animations are active
617: function check_for_animation() {
618: // this should work (maybe more correct all selector syntax is needed)
619: // if ($(':animated').length) {return true;}
620:
621: // this does work
622: if ($('.ccc_dyn_pg_right:animated').length) {return true;}
623: if ($('.ccc_dyn_pg_left:animated').length) {return true;}
624: if ($('.ccc_dyn_pg_bottom:animated').length) {return true;}
625: return false;
626: }
627:
628:
629: ////////////////////////////////////////////////////////////////////////////////
630: function clear_userpass()
631: {
632: document.getElementById('username').value = '';
633: document.getElementById('password').value = '';
634: // reviewer: why don't these work the same?
635: // $('#username').value = '';
636: // $('#password').value = '';
637: // hide any server response
638: $('#ccc_login_server_response').hide();
639: $('#username').focus();
640:
641: }
642:
643:
644: ////////////////////////////////////////////////////////////////////////////////
645: //
646: // button press event handlers
647: //
648:
649:
650: ////////////////////////////////////////////////////////////////////////////////
651: function login_attempt_button_handler()
652: {
653: // if an animation is in progress, ignore the click
654: if (check_for_animation()) {return false;}
655:
656: // reviewer question: jquery .html no work with xml???
657: //$("#ccc_login_status_text").html = "logging in...";
658: document.getElementById('ccc_login_status').innerHTML =
659: "logging in...";
660:
661: // first we get a seed, then the seed_response_handler will
662: // handle the rest of the process
663: $.post("cgi/ccc_login.php", {
664: command: "get-seed",
665: }, function (xml) {seed_response_handler(xml);});
666: }
667:
668:
669: ////////////////////////////////////////////////////////////////////////////////
670: function login_clear_button_handler()
671: {
672: if (check_for_animation()) {return false;}
673:
674: clear_userpass();
675: }
676:
677:
678: ////////////////////////////////////////////////////////////////////////////////
679: function login_about_button_handler()
680: {
681: // if an animation is in progress, ignore the click
682: if (check_for_animation()) {return false;}
683:
684: dyn_pg_mode_switch(".ccc_dyn_pg_about");
685: }
686:
687:
688: ////////////////////////////////////////////////////////////////////////////////
689: function login_signup_button_handler()
690: {
691: // if an animation is in progress, ignore the click
692: if (check_for_animation()) {return false;}
693:
694: dyn_pg_mode_switch(".ccc_dyn_pg_signup");
695: }
696:
697:
698: ////////////////////////////////////////////////////////////////////////////////
699: function login_gotologin_button_handler()
700: {
701: // if an animation is in progress, ignore the click
702: if (check_for_animation()) {return false;}
703:
704: dyn_pg_mode_switch(".ccc_dyn_pg_login");
705: }
706:
707:
708: ////////////////////////////////////////////////////////////////////////////////
709: function logout_button_handler()
710: {
711: // if an animation is in progress, ignore the click
712: if (check_for_animation()) {return false;}
713:
714: do_log_out();
715: }
716:
717:
718: ////////////////////////////////////////////////////////////////////////////////
719: function help_button_handler()
720: {
721: // if an animation is in progress, ignore the click
722: if (check_for_animation()) {return false;}
723:
724: $('#ccc_help_dialog').dialog();
725:
726: /* even on ff35, not so smooth, but perhaps next year
727: $('#ccc_help_dialog').dialog({
728: show: "slide",
729: hide: "slide",
730: });
731: */
732: }
733:
734:
735: ////////////////////////////////////////////////////////////////////////////////
736: function signup_req_send_button_handler()
737: {
738: var req_hashed_password = '';
739:
740:
741: // if an animation is in progress, ignore the click
742: if (check_for_animation()) {return false;}
743:
744: if ($('#req_password').val() != $('#req_password_vfy').val()) {
745: $('#ccc_signup_req_pwnomatch_dialog').dialog();
746: return false;
747: }
748:
749: if (!$('#req_password').val().match(/^[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]+/)) {
750: $('#ccc_signup_req_alphanum_dialog').dialog();
751: return false;
752: }
753:
754: req_username = $("input[name=req_username]").val();
755: req_hashed_password = $.sha256($("input[name=req_password]"));
756:
757: $.post("cgi/ccc_login.php", {
758: command: "validate-signup",
759: req_username: req_username,
760: req_hashed_password: req_hashed_password,
761: req_sapcha: document.getElementById('req_sapcha').value
762: },
763: function (xml) {
764: signup_response_handler(xml, req_username);
765: }
766: );
767:
768: // TODO: need busy indicator and 7(+?)s timeout here
769: }
770:
771:
772: ////////////////////////////////////////////////////////////////////////////////
773: function signup_req_clear_button_handler()
774: {
775: // if an animation is in progress, ignore the click
776: if (check_for_animation()) {return false;}
777:
778: document.getElementById('req_username').value = '';
779: document.getElementById('req_password').value = '';
780: document.getElementById('req_password_vfy').value = '';
781: document.getElementById('req_sapcha').value = '';
782:
783: // reset the wordcount
784: req_sapcha_keyup_handler();
785: }
786:
787:
788: ////////////////////////////////////////////////////////////////////////////////
789: function toggle_bg_button_handler()
790: {
791: // if an animation is in progress, ignore the click
792: if (check_for_animation()) {return false;}
793:
794: if (bg_shown == 1) {
795: $(".bgmaximage").fadeOut('slow');
796: $.cookie('ccc_background_pref',
797: null,
798: { path: '/', expires: 369 });
799: $.cookie('ccc_background_pref',
800: '0',
801: { path: '/', expires: 369 });
802: bg_shown = 0;
803: } else {
804: $(".bgmaximage").fadeIn('slow');
805: $.cookie('ccc_background_pref',
806: null,
807: { path: '/', expires: 369 });
808: $.cookie('ccc_background_pref',
809: '1',
810: { path: '/', expires: 369 });
811: bg_shown = 1;
812: }
813:
814: }
815:
816:
817: ////////////////////////////////////////////////////////////////////////////////
818: //
819: // text input keyup handlers
820: //
821:
822:
823: ////////////////////////////////////////////////////////////////////////////////
824: function req_username_keyup_handler()
825: {
826: if ($('#req_username').val().length > 2) {
827: $('#req_username_advice_text').css('color', '#007700');
828: } else {
829: $('#req_username_advice_text').css('color', '#770000');
830: }
831: }
832:
833:
834: ////////////////////////////////////////////////////////////////////////////////
835: function req_password_keyup_handler()
836: {
837:
838: // technically the input box should prevent > 42 as well
839: if (($('#req_password').val().length < 3) ||
840: ($('#req_password_vfy').val().length < 3) ||
841: ($('#req_password').val().length > 42) ||
842: ($('#req_password_vfy').val().length > 42)) {
843: $('#req_password_length_text').css('color', '#770000');
844: } else {
845: $('#req_password_length_text').css('color', '#007700');
846: }
847:
848: // now check for match
849: if ($('#req_password').val() != $('#req_password_vfy').val()) {
850: document.getElementById('req_password_match_text').innerHTML =
851: "* Password and verify-pw do not match.";
852: $('#req_password_match_text').css('color', '#770000');
853: } else {
854: document.getElementById('req_password_match_text').innerHTML =
855: "* Password and verify-pw match.";
856: $('#req_password_match_text').css('color', '#007700');
857: }
858: }
859:
860:
861: ////////////////////////////////////////////////////////////////////////////////
862: function req_sapcha_keyup_handler()
863: {
864: word_count = te_word_count($('#req_sapcha'));
865: document.getElementById('req_sapcha_advice_text').innerHTML =
866: 'word count :: ' + word_count;
867: if (word_count > 41) {
868: $('#req_sapcha_advice_text').css('color', '#007700');
869: } else {
870: $('#req_sapcha_advice_text').css('color', '#770000');
871: }
872: }
873:
874: ////////////////////////////////////////////////////////////////////////////////
875: //
876: // main
877: //
878: ////////////////////////////////////////////////////////////////////////////////
879:
880:
881: ////////////////////////////////////////////////////////////////////////////////
882: //
883: function ccc_login_main()
884: {
885:
886: // TODO: move all but first sentence to an in-html div
887: if (browser_bail) {
888: $(".bgmaximage").hide();
889: $("#ccc_total_area").hide();
890: document.getElementById('ccc_browser_bail_area').innerHTML =
891: "<br/><br/>Your browser- " + browser_brand + " ( version " +
892: browser_version + " ) may be insufficient to render" +
893: " the CloudSession Control Center demo.<br/><br/>Please visit" +
894: " mozilla.org to download and use the latest version of" +
895: " Firefox. Or send an email to Dawg AT CloudSession DOT com," +
896: " to get the detection code fixed if this blocking is" +
897: " unnecessary. Alternately, you can use this url-" +
898: " <a href='http://cloudsession.com/login/?no_browser_check>" +
899: "http://cloudsession.com/login/?no_browser_check</a>.";
900: return;
901: }
902:
903: // init the main application state/mode
904: ccc_dyn_pg = ".ccc_dyn_pg_none";
905:
906: // a useful alias
907: body = document.getElementById('body');
908:
909: // clear the form inputs once on main page load
910: document.getElementById('username').value = '';
911: document.getElementById('password').value = '';
912: document.getElementById('req_username').value = '';
913: document.getElementById('req_password').value = '';
914: document.getElementById('req_sapcha').value = '';
915:
916: // init advice defaults
917: req_username_keyup_handler();
918: req_password_keyup_handler();
919: req_sapcha_keyup_handler();
920:
921:
922: // not so happy yet (simple temp test rig)
923: document.getElementById('ccc_login_status').innerHTML =
924: "not logged in";
925:
926: // it seems wrong, but a page reload doesn't seem to clear these
927: $('#username').removeAttr('disabled');
928: $('#password').removeAttr('disabled');
929:
930:
931: //disable debug info
932: $('#ccc_login_status').hide();
933:
934: // initially hide server response that hasn't been received yet
935: $('#ccc_login_server_response').hide('fast');
936:
937: //
938: // setup button event handlers
939: //
940:
941: // edunote: wrapping arg in "function () {X()}" makes it a funcptr.
942: $("#ccc_button_login_attempt").click(function () {
943: login_attempt_button_handler();
944: });
945: $("#ccc_button_login_clear").click(function () {
946: login_clear_button_handler();
947: });
948: // note: these are classes because they exist in more than one page
949: $(".ccc_button_about").click(function () {
950: login_about_button_handler();
951: });
952: $(".ccc_button_signup").click(function () {
953: login_signup_button_handler();
954: });
955: $(".ccc_button_gotologin").click(function () {
956: login_gotologin_button_handler();
957: });
958: $(".ccc_button_logout").click(function () {
959: logout_button_handler();
960: });
961: $(".ccc_button_help").click(function () {
962: help_button_handler();
963: });
964: $(".ccc_button_signup_req_send").click(function () {
965: signup_req_send_button_handler();
966: });
967: $(".ccc_button_signup_req_clear").click(function () {
968: signup_req_clear_button_handler();
969: });
970: $("#ccc_button_toggle_bg").click(function () {
971: toggle_bg_button_handler();
972: });
973:
974: //
975: // setup text input keypress handlers (username/password advise)
976: //
977: $("#req_username").keyup(function () {
978: req_username_keyup_handler();
979: });
980: $("#req_password").keyup(function () {
981: req_password_keyup_handler();
982: });
983: $("#req_password_vfy").keyup(function () {
984: req_password_keyup_handler();
985: });
986: $("#req_sapcha").keyup(function () {
987: req_sapcha_keyup_handler();
988: });
989:
990: //
991: // various UI features init
992: //
993:
994: // add spiffy jqui/ui-state-hover button hovering to ccc_button(s)
995: // edunote::js:: apparently this kind of line breaking works
996: $(".ccc_button:not(.ui-state-disabled)")
997: .hover(function(){ $(this).addClass("ui-state-hover"); },
998: function(){ $(this).removeClass("ui-state-hover"); });
999:
1000: // for maximage bg scaling plugin
1001: jQuery('img.bgmaximage').maxImage({
1002: isBackground: true,
1003: overflow: 'auto'
1004: });
1005:
1006: //
1007: // setup initial page unvel animation
1008: //
1009:
1010: setup_initial_page_unveil_anim();
1011:
1012:
1013: } // end ccc_login_main
1014:
1015:
1016: ////////////////////////////////////////////////////////////////////////////////
1017: // insecure bounces to secure
1018:
1019: if (window.location.hostname != 'localhost') {
1020: if (window.location.protocol != 'https:') {
1021: window.open('https://ssl.perfora.net/secure.cloudsession.com/login/',
1022: '_self');
1023: }
1024: }
1025:
1026: ////////////////////////////////////////////////////////////////////////////////
1027: // browser bail handling
1028:
1029: // let the user opt out of browser unsupport
1030: if (!('no_browser_check' in $.get_url_vars())) {
1031: browser_version = detect_browser_version();
1032: if ($.browser.mozilla) {
1033: browser_brand = 'Mozilla/Firefox';
1034: if (browser_version < 3) {
1035: browser_bail = 1;
1036: } else {
1037: }
1038: } else if ($.browser.msie) {
1039: browser_brand = 'Internet/Explorer';
1040: if (browser_version < 8) {
1041: browser_bail = 1;
1042: } else {
1043: // no point in dev for IE
1044: dev = 0;
1045: }
1046: } else if ($.browser.webkit) {
1047: browser_brand = 'Webkit/Safari';
1048: if (browser_version < 531) {
1049: browser_bail = 1;
1050: } else {
1051: // no point in dev for safari
1052: dev = 0;
1053: // does not work so well
1054: use_animated_show = 0;
1055: }
1056: } else {
1057: browser_brand = 'Unknown/Opera';
1058: browser_bail = 1;
1059: }
1060: }
1061:
1062: // manual testing hook
1063: if ('use_animated_show' in $.get_url_vars()) {
1064: use_animated_show = $.get_url_vars['use_animated_show'];
1065: }
1066:
1067: // check for background disable cookie
1068: if ($.cookie('ccc_background_pref') == null) {
1069: bg_shown = 1;
1070: } else {
1071: bg_shown = $.cookie('ccc_background_pref');
1072: }
1073:
1074:
1075: ////////////////////////////////////////////////////////////////////////////////
1076: // 'run' main (when DOM is fully loaded, I think this means)
1077: jQuery(document).ready(function () {ccc_login_main();});
1078:
1079:
1080: ////////////////////////////////////////////////////////////////////////////////
1081: //
1082: // end code (comments below)
1083: //
1084: ////////////////////////////////////////////////////////////////////////////////
1085:
1086: //
1087: // The first javascript style guide I found. Best and winner thus far...
1088: //
1089: // http://javascript.crockford.com/code.html
1090: //
1091: // and longterm security todo- top ten web application issues from owasp
1092: //
1093: // http://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project
1094: //
1095:
1096: // // edu: historical
1097: // Hello World: clicks on links cause graffiti alert
1098: // $("a").click(function() {
1099: // alert("DMC wuz here!");
1100: // });
1101:
1102: // edu: todo: need a good use of an object as associative array...
1103: // http://www.quirksmode.org/js/associative.html
1104: // http://www.mojavelinux.com/articles/javascript_hashes.html
1105:
1106: ////////////////////////////////////////////////////////////////////////////////
1107: //
1108: // EOF
1109: //
1110: ////////////////////////////////////////////////////////////////////////////////
1111: ////////////////////////////////////////////////////////////////////////////////
1112: