]> dev.renevier.net Git - syj.git/blob - public/js/syj.js
ajax for account creation to known if a pseudo is available
[syj.git] / public / js / syj.js
1 /*  This file is part of Syj, Copyright (c) 2010 Arnaud Renevier,
2     and is published under the AGPL license. */
3
4 // avoid openlayers alerts
5 OpenLayers.Console.userError = function(error) {
6     SYJView.messenger.setMessage(error, "error");
7 };
8
9 var SyjSaveUI = {
10     status: "unknown",
11
12     init: function() {
13         $("geom_title").observe('contentchange', this.enableSubmit.bindAsEventListener(this));
14         return this;
15     },
16
17     hide: function() {
18         $("geom_submit").blur();
19         $("geom_title").blur();
20         $("geomform").hide();
21         return this;
22     },
23
24     show: function() {
25         $("geomform").show();
26         return this;
27     },
28
29     enable: function() {
30         if (this.status === "enabled") {
31             return this;
32         }
33         this.enableSubmit();
34         $("geom_title").disabled = false;
35         $("geom_title").activate();
36         $("geomform").removeClassName("disabled");
37         this.status = "enabled";
38         return this;
39     },
40
41     disable: function() {
42         if (this.status === "disabled") {
43             return this;
44         }
45         this.disableSubmit();
46         $("geom_title").blur();
47         $("geom_title").disabled = true;
48         $("geomform").addClassName("disabled");
49         this.status = "disabled";
50         return this;
51     },
52
53     enableSubmit: function() {
54         $("geom_submit").disabled = false;
55         this.status = "partial";
56         return this;
57     },
58
59     disableSubmit: function() {
60         $("geom_submit").blur();
61         $("geom_submit").disabled = true;
62         this.status = "partial";
63         return this;
64     }
65 };
66
67 var SyjEditUI = {
68     hide: function() {
69         $("edit-btn").blur();
70         $("edit-btn").hide();
71         return this;
72     },
73
74     show: function() {
75         $("edit-btn").show();
76         return this;
77     }
78 };
79
80 OpenLayers.Handler.SyjModifiablePath = OpenLayers.Class(OpenLayers.Handler.ModifiablePath, {
81     mouseup: function(evt) {
82         // do not add a point when navigating
83         var mapControls = this.control.map.controls, idx, ctrl;
84
85         for (idx = mapControls.length; idx-->0; ) {
86             ctrl = mapControls[idx];
87             if (this.isCtrlNavigationActive(ctrl, evt)) {
88                 return true;
89             }
90         }
91         return OpenLayers.Handler.ModifiablePath.prototype.mouseup.apply(this, arguments);
92     },
93
94     addPoints: function(pixel) {
95         // redraw before last point. As we have a special style for last point, we
96         // need to redraw before last point after adding a new point (otherwise, it
97         // keeps special style forever)
98         var oldpoint = this.point;
99         OpenLayers.Handler.ModifiablePath.prototype.addPoints.apply(this, arguments);
100         this.layer.drawFeature(oldpoint);
101     },
102
103     isCtrlNavigationActive: function(ctrl, evt) {
104         var tolerance = 4, xDiff, yDiff;
105
106         if (!(ctrl instanceof OpenLayers.Control.Navigation)) {
107             return false;
108         }
109
110         if (ctrl.zoomBox &&
111             ctrl.zoomBox.active &&
112             ctrl.zoomBox.handler &&
113             ctrl.zoomBox.handler.active &&
114             ctrl.zoomBox.handler.dragHandler &&
115             ctrl.zoomBox.handler.dragHandler.start) {
116             return true;
117         }
118
119         if (!ctrl.dragPan ||
120             !ctrl.dragPan.active ||
121             !ctrl.dragPan.handler ||
122             !ctrl.dragPan.handler.started ||
123             !ctrl.dragPan.handler.start) {
124             return false;
125         }
126
127         // if mouse moved 4 or less pixels, consider it has not moved.
128         tolerance = 4;
129
130         xDiff = evt.xy.x - ctrl.dragPan.handler.start.x;
131         yDiff = evt.xy.y - ctrl.dragPan.handler.start.y;
132
133         if (Math.sqrt(Math.pow(xDiff,2) + Math.pow(yDiff,2)) <= tolerance) {
134             return false;
135         }
136         return true;
137     },
138
139     finalize: function(cancel) {
140         // do nothing. We don't want to finalize path
141     }
142 });
143
144 var styleMap = {
145     edit: new OpenLayers.StyleMap({
146         "default": new OpenLayers.Style({
147             pointRadius: "${radius}", // sized according to type attribute
148             fillColor: "#ffcc66",
149             strokeColor: "#ff9933",
150             strokeWidth: 2,
151             strokeOpacity: "${opacity}",
152             fillOpacity: "${opacity}"
153         },
154         {
155             context: {
156                 radius: function(feature) {
157                     var features;
158
159                     if (!(feature.geometry instanceof OpenLayers.Geometry.Point)) {
160                         return 0;
161                     }
162                     if (feature.type === "middle") {
163                         return 4;
164                     }
165                     features = feature.layer.features;
166                     if (OpenLayers.Util.indexOf(features, feature) === 0) {
167                         return 5;
168                     } else if (OpenLayers.Util.indexOf(features, feature) === features.length - 1) {
169                         return 5;
170                     }
171                     return 3;
172                 },
173                 opacity: function (feature) {
174                     if (feature.type === "middle") {
175                         return 0.5;
176                     } else {
177                         return 1;
178                     }
179                 }
180             }
181         }),
182
183         "select": new OpenLayers.Style({
184             externalGraphic: "icons/delete.png",
185             graphicHeight: 16
186         }),
187
188         "select_for_canvas": new OpenLayers.Style({
189             strokeColor: "blue",
190             fillColor: "lightblue"
191         })
192
193     }),
194
195     view: new OpenLayers.StyleMap({
196         "default": new OpenLayers.Style({
197             strokeColor: "blue",
198             strokeWidth: 5,
199             strokeOpacity: 0.7
200         })
201     })
202 };
203
204 var WGS84 = new OpenLayers.Projection("EPSG:4326");
205 var Mercator = new OpenLayers.Projection("EPSG:900913");
206
207 var SYJView = {
208     viewLayer: null,
209     editControl: null,
210     map: null,
211     wkt: new OpenLayers.Format.WKT({ internalProjection: Mercator, externalProjection: WGS84 }),
212     needsFormResubmit: false,
213
214     init: function() {
215         var externalGraphic, baseURL, baseLayer, layerOptions, extent, hidemessenger;
216
217         // is svg context, opera does not resolve links with base element is svg context
218         externalGraphic = styleMap.edit.styles.select.defaultStyle.externalGraphic;
219         baseURL = document.getElementsByTagName("base")[0].href;
220         styleMap.edit.styles.select.defaultStyle.externalGraphic = baseURL + externalGraphic;
221
222         this.map = new OpenLayers.Map('map', {
223             controls: [
224                 new OpenLayers.Control.Navigation(),
225                 new OpenLayers.Control.PanZoom(),
226                 new OpenLayers.Control.Attribution()
227             ],
228             theme: null
229         });
230
231         baseLayer = new OpenLayers.Layer.OSM("OSM", null, { wrapDateLine: true , attribution: SyjStrings.osmAttribution });
232
233         layerOptions = {format:     OpenLayers.Format.WKT,
234                         projection: WGS84,
235                         styleMap:   styleMap.view};
236         if (gLoggedInfo.creatorname) {
237             layerOptions.attribution = SyjStrings.routeBy + ' ' + '<strong>' + gLoggedInfo.creatorname + '</strong>';
238         }
239
240         this.viewLayer = new OpenLayers.Layer.Vector("View Layer", layerOptions);
241         this.map.addLayers([baseLayer, this.viewLayer]);
242
243         $("edit-btn").observe('click', (function() {
244             this.messenger.hide();
245             this.editMode();
246         }).bind(this));
247
248         $("geomform").ajaxize({
249                 presubmit: this.prepareForm.bind(this),
250                 onSuccess: this.saveSuccess.bind(this),
251                 onFailure: this.saveFailure.bind(this)
252                 });
253         SyjSaveUI.init().hide();
254
255         this.messenger = $('message');
256         hidemessenger = this.messenger.empty();
257         new CloseBtn(this.messenger, {
258             style: {
259                 margin: "-1em"
260             }
261         });
262         if (hidemessenger) {
263             this.messenger.hide();
264         }
265
266         if ($("geom_data").value) {
267             this.viewLayer.addFeatures([this.wkt.read($("geom_data").value)]);
268             extent = this.viewLayer.getDataExtent();
269             // XXX: ie has not guessed height of map main div yet during map
270             // initialisation. Now, it will read it correctly.
271             this.map.updateSize();
272         } else {
273             extent = new OpenLayers.Bounds(gMaxExtent.minlon, gMaxExtent.minlat, gMaxExtent.maxlon, gMaxExtent.maxlat)
274                                          .transform(WGS84, Mercator);
275         }
276         this.map.zoomToExtent(extent);
277         document.observe('simplebox:shown', this.observer.bindAsEventListener(this));
278     },
279
280     observer: function(evt) {
281         if (evt.eventName === "simplebox:shown" && evt.memo.element !== $("termsofusearea")) {
282             this.messenger.hide();
283         }
284     },
285
286     prepareForm: function(form) {
287         if (!LoginMgr.logged && !$("geom_accept").checked) {
288             this.messenger.setMessage(SyjStrings.acceptTermsofuseWarn, "warn");
289             $("geom_accept_container").highlight('#F08080');
290             $("geom_accept").activate();
291             return false;
292         }
293
294         var line, realPoints, idx, handler;
295
296         line = new OpenLayers.Geometry.LineString();
297         realPoints = this.editControl.handler.realPoints;
298         for (idx = 0; idx < realPoints.length; idx++) {
299             line.addComponent(realPoints[idx].geometry.clone());
300         }
301         this.viewLayer.addFeatures(new OpenLayers.Feature.Vector(line));
302         handler = this.editControl.handler;
303         OpenLayers.Handler.ModifiablePath.prototype.finalize.apply(handler, arguments);
304         // we need to recreate them on next createFeature; otherwise
305         // they'll reference destroyed features
306         delete(handler.handlers.drag);
307         delete(handler.handlers.feature);
308         this.editControl.deactivate();
309
310         $("geom_data").value = this.wkt.write(new OpenLayers.Feature.Vector(line));
311         this.needsFormResubmit = false;
312         SyjSaveUI.disable.bind(SyjSaveUI).defer();
313         this.messenger.hide();
314         return true;
315     },
316
317     editMode: function() {
318         var components, point0, point, pixels, pixel, idx;
319
320         this.initEditControl();
321
322         this.editControl.activate();
323         if (this.viewLayer.features.length) {
324             components = this.viewLayer.features[0].geometry.components;
325             point0 = components[0];
326             if (point0) {
327                 pixel = this.map.getPixelFromLonLat(new OpenLayers.LonLat(point0.x, point0.y));
328                 this.editControl.handler.createFeature(pixel);
329                 this.editControl.handler.lastUp = pixel;
330                 pixels = [];
331                 for (idx = 1; idx < components.length; idx++) {
332                     point = components[idx];
333                     pixels.push(this.map.getPixelFromLonLat(new OpenLayers.LonLat(point.x, point.y)));
334                 }
335                 this.editControl.handler.addPoints(pixels);
336             }
337         }
338
339         this.viewLayer.destroyFeatures();
340
341         SyjEditUI.hide();
342         if (this.editControl.handler.realPoints && this.editControl.handler.realPoints.length >= 2) {
343             SyjSaveUI.show().disableSubmit();
344         } else {
345             SyjSaveUI.show().disable();
346         }
347     },
348
349     initEditControl: function() {
350         var styles;
351
352         if (this.editControl) {
353             return;
354         }
355
356         this.editControl = new OpenLayers.Control.DrawFeature(new OpenLayers.Layer.Vector(), OpenLayers.Handler.SyjModifiablePath, {
357             callbacks: {
358                 modify: function(f, line) {
359                     if (this.handler.realPoints.length < 2) {
360                         SyjSaveUI.show().disable();
361                     } else {
362                         SyjSaveUI.show().enable();
363                     }
364                 }
365             },
366
367             handlerOptions: {
368                 layerOptions: {
369                     styleMap: styleMap.edit
370                 }
371             }
372         });
373         this.map.addControl(this.editControl);
374         if (this.editControl.layer.renderer instanceof OpenLayers.Renderer.Canvas) {
375             // using externalGraphic with canvas renderer is definitively too buggy
376             styles = this.editControl.handler.layerOptions.styleMap.styles;
377             styles.select = styles.select_for_canvas;
378         }
379     },
380
381     saveSuccess: function(transport) {
382       if (transport.responseJSON && (typeof transport.responseJSON.redirect === "string")) {
383           location = transport.responseJSON.redirect;
384           return;
385       }
386
387       this.messenger.setMessage(SyjStrings.saveSuccess, "success");
388       SyjSaveUI.hide();
389       SyjEditUI.show();
390       document.title = $('geom_title').value;
391     },
392
393     saveFailure: function(transport) {
394         var httpCode = 0, message = "";
395
396         if (transport) {
397             httpCode = transport.getStatus();
398         }
399         switch (httpCode) {
400             case 0:
401                 message = SyjStrings.notReachedError;
402             break;
403             case 400:
404             case 404:
405                 message = SyjStrings.requestError;
406                 if (transport.responseJSON) {
407                     switch (transport.responseJSON.message) {
408                         case "uniquepath":
409                             message = SyjStrings.uniquePathError;
410                         break;
411                         default:
412                         break;
413                     }
414                 }
415             break;
416             case 403:
417                 message = "";
418                 SYJLogin.messenger.setMessage(SyjStrings.loginNeeded, "warn");
419                 SYJLogin.modalbox.show();
420                 this.needsFormResubmit = true;
421             break;
422             case 410:
423                 message = SyjStrings.gonePathError;
424             break;
425             case 500:
426                 message = SyjStrings.serverError;
427                 this.needsFormResubmit = true;
428             break;
429             default:
430                 message = SyjStrings.unknownError;
431             break;
432         }
433
434         this.editMode();
435         // is some cases, we let the user resubmit, in some other cases, he
436         // needs to modify the path before submitting again
437         if (this.needsFormResubmit) {
438             SyjSaveUI.enable();
439         }
440
441         this.messenger.setMessage(message, "error");
442     }
443 };
444
445 var SYJModalClass = Class.create({
446     type: "",
447
448     init: function() {
449         this.area = $(this.type + '_area');
450         this.messenger = $(this.type + "_message");
451         this.modalbox = new SimpleBox(this.area, {
452             closeMethods: ["onescapekey", "onouterclick", "onbutton"]
453         });
454
455         $(this.type + "_control_anchor").observe("click", function(evt) {
456             this.modalbox.show();
457             evt.stop();
458         }.bindAsEventListener(this));
459
460         document.observe('simplebox:shown', this.observer.bindAsEventListener(this));
461         document.observe('simplebox:hidden', this.observer.bindAsEventListener(this));
462
463         $(this.type + "form").ajaxize({
464             presubmit: this.presubmit.bind(this),
465             onSuccess: this.success.bind(this),
466             onFailure: this.failure.bind(this)
467         });
468     },
469
470     checkNotEmpty: function(input, message) {
471         if ($(input).value.strip().empty()) {
472             this.messenger.setMessage(message, "warn");
473             $(input).highlight('#F08080').activate();
474             return false;
475         }
476         return true;
477     },
478
479     observer: function(evt) {
480         var simplebox, input;
481
482         if (evt.eventName === "simplebox:shown" && evt.memo.element !== $("termsofusearea")) {
483             simplebox = evt.memo;
484             if (simplebox === this.modalbox) {
485                 input = this.area.select('input[type="text"]')[0];
486                 (function () {
487                     input.activate();
488                 }).defer();
489             } else {
490                 this.modalbox.hide();
491             }
492
493         } else if (evt.eventName === "simplebox:hidden" && evt.memo.element !== $("termsofusearea")) {
494             simplebox = evt.memo;
495             if (simplebox === this.modalbox) {
496                 this.reset();
497             }
498         }
499     },
500
501     failure: function(transport) {
502         var httpCode = 0, message = SyjStrings.unknownError, input; // default message error
503
504         if (transport) {
505             httpCode = transport.getStatus();
506         }
507
508         switch (httpCode) {
509             case 0:
510                 message = SyjStrings.notReachedError;
511             break;
512             case 400:
513             case 404:
514             case 410:
515                 message = SyjStrings.requestError;
516             break;
517             case 500:
518                 message = SyjStrings.serverError;
519             break;
520         }
521
522         this.messenger.setMessage(message, "error");
523         input = this.area.select('input[type="text"]')[0];
524         input.highlight('#F08080').activate();
525     },
526
527     reset: function() {
528         this.messenger.hide();
529         this.area.select('.message').invoke('setMessageStatus', null);
530     }
531 });
532
533 var SYJUserClass = Class.create(SYJModalClass, {
534     type: "user",
535     toubox: null,
536
537     init: function($super) {
538         $super();
539         $("termsofusearea").hide();
540
541         $$("#user_termsofuse_anchor, #geom_termsofuse_anchor").invoke('observe', "click", function(evt) {
542             if (!this.toubox) {
543                 $("termsofusearea").show();
544                 $("termsofuseiframe").setAttribute("src", evt.target.href);
545                 this.toubox = new SimpleBox($("termsofusearea"), {
546                     closeMethods: ["onescapekey", "onouterclick", "onbutton"]
547                 });
548             }
549             this.toubox.show();
550             evt.stop();
551         }.bindAsEventListener(this));
552
553         $$("#login_area_create > a").invoke('observe', 'click',
554             function(evt) {
555                 this.modalbox.show();
556                 evt.stop();
557             }.bindAsEventListener(this));
558
559         $("user_pseudo-desc").hide();
560         $("user_pseudo").observe('contentchange', function(evt) {
561             var value = evt.target.value;
562             PseudoChecker.reset();
563             if (value && !(value.match(/^[a-zA-Z0-9_.]+$/))) {
564                 $("user_pseudo-desc").show().setMessageStatus("warn");
565             } else {
566                 $("user_pseudo-desc").hide();
567             }
568         }).timedobserve(function() {
569             PseudoChecker.check();
570         });
571
572         $("user_password").observe('contentchange', function(evt) {
573             if (evt.target.value.length < 6) {
574                 $("user_password-desc").setMessageStatus("warn");
575             } else {
576                 $("user_password-desc").setMessageStatus("success");
577             }
578         }.bindAsEventListener(this));
579
580         $("account-info").hide();
581         $("account-info-bullet").observe('click', function(evt) {
582             var elt = $("account-info");
583             if (elt.visible()) {
584                 evt.target.src = "icons/bullet_arrow_right.png";
585                 elt.hide();
586             } else {
587                 evt.target.src = "icons/bullet_arrow_down.png";
588                 elt.show();
589             }
590             evt.stop();
591         });
592     },
593
594     presubmit: function() {
595         this.messenger.hide();
596         PseudoChecker.reset();
597         if (!(this.checkNotEmpty("user_pseudo", SyjStrings.userEmptyWarn))) {
598             return false;
599         }
600
601         if (!($("user_pseudo").value.match(/^[a-zA-Z0-9_.]+$/))) {
602             $("user_pseudo-desc").show().setMessageStatus("warn");
603             $("user_pseudo").highlight('#F08080').activate();
604             return false;
605         }
606
607         if (PseudoChecker.exists[$("user_pseudo").value]) {
608             PseudoChecker.availableMessage(false);
609             $("user_pseudo").highlight('#F08080').activate();
610             return false;
611         }
612
613         if (!(this.checkNotEmpty("user_password", SyjStrings.passwordEmptyWarn))) {
614             return false;
615         }
616
617         if ($("user_password").value.length < 6) {
618             $("user_password-desc").setMessageStatus("warn");
619             $("user_password").highlight('#F08080').activate();
620             return false;
621         }
622
623         if ($("user_password").value !== $("user_password_confirm").value) {
624             this.messenger.setMessage(SyjStrings.passwordNoMatchWarn, "warn");
625             $("user_password").highlight('#F08080').activate();
626             return false;
627         }
628
629         if (!(this.checkNotEmpty("user_email", SyjStrings.emailEmptyWarn))) {
630             return false;
631         }
632
633         if (!$("user_accept").checked) {
634             this.messenger.setMessage(SyjStrings.acceptTermsofuseWarn, "warn");
635             $("user_accept_container").highlight('#F08080');
636             $("user_accept").activate();
637             return false;
638         }
639
640         this.reset();
641         return true;
642     },
643
644     success: function(transport) {
645         LoginMgr.login();
646         SYJView.messenger.setMessage(SyjStrings.userSuccess, "success");
647         this.modalbox.hide();
648         if (SYJView.needsFormResubmit) {
649             SYJView.messenger.addMessage(SyjStrings.canResubmit);
650             $("geom_submit").activate();
651         }
652     },
653
654     failure: function($super, transport) {
655         var httpCode = 0, focusInput = null, message = "";
656
657         if (transport) {
658             httpCode = transport.getStatus();
659         }
660
661         focusInput = null;
662         message = "";
663
664         switch (httpCode) {
665             case 400:
666                 if (transport.responseJSON) {
667                     switch (transport.responseJSON.message) {
668                         case "invalidemail":
669                             message = SyjStrings.emailInvalidWarn;
670                             focusInput = $("user_email");
671                         break;
672                         case "uniquepseudo":
673                             PseudoChecker.availableMessage(false);
674                             focusInput = $("user_pseudo");
675                         break;
676                         case "uniqueemail":
677                             message = SyjStrings.uniqueEmailError;
678                             focusInput = $("user_email");
679                         break;
680                     }
681                 }
682             break;
683         }
684
685         if (focusInput) {
686             if (message) {
687                 this.messenger.setMessage(message, "error");
688             }
689             focusInput.highlight('#F08080').activate();
690             return;
691         }
692
693         $super(transport);
694     }
695 });
696 var SYJUser = new SYJUserClass();
697
698 var SYJLoginClass = Class.create(SYJModalClass, {
699     type: "login",
700
701     init: function($super) {
702         $super();
703     },
704
705     presubmit: function() {
706         this.messenger.hide();
707         if (!(this.checkNotEmpty("login_user", SyjStrings.userEmptyWarn))) {
708             return false;
709         }
710
711         this.reset();
712         return true;
713     },
714
715     success: function(transport) {
716         if (transport.responseText === "1") {
717             LoginMgr.login(true);
718         } else {
719             LoginMgr.login();
720         }
721         SYJView.messenger.setMessage(SyjStrings.loginSuccess, "success");
722         this.modalbox.hide();
723         if (SYJView.needsFormResubmit) {
724             SYJView.messenger.addMessage(SyjStrings.canResubmit);
725             $("geom_submit").activate();
726         }
727     },
728
729     failure: function($super, transport) {
730         var httpCode = 0, focusInput = null, message = "";
731
732         if (transport) {
733             httpCode = transport.getStatus();
734         }
735
736         focusInput = null;
737         message = "";
738
739         switch (httpCode) {
740             case 403:
741                 message = SyjStrings.loginFailure;
742                 focusInput = $("login_user");
743             break;
744         }
745
746         if (message) {
747             this.messenger.setMessage(message, "error");
748             if (focusInput) {
749                 focusInput.highlight('#F08080').activate();
750             }
751             return;
752         }
753
754         $super(transport);
755     }
756 });
757 var SYJLogin = new SYJLoginClass();
758
759 var SYJNewpwdClass = Class.create(SYJModalClass, {
760     type: "newpwd",
761
762     presubmit: function() {
763         if (!(this.checkNotEmpty("newpwd_email", SyjStrings.emailEmptyWarn))) {
764             return false;
765         }
766         this.reset();
767         return true;
768     },
769     success: function(transport) {
770         SYJView.messenger.setMessage(SyjStrings.newpwdSuccess, "success");
771         this.modalbox.hide();
772     }
773
774 });
775 var SYJNewpwd = new SYJNewpwdClass();
776
777 var LoginMgr = Object.extend(gLoggedInfo, {
778     controlsdeck: null,
779
780     updateUI: function() {
781         if (!this.controlsdeck) {
782             this.controlsdeck = new Deck("login_controls");
783         }
784         if (this.logged) {
785             this.controlsdeck.setIndex(1);
786             $$(".logged-hide").invoke('hide');
787             $$(".logged-show").invoke('show');
788         } else {
789             this.controlsdeck.setIndex(0);
790             $$(".logged-hide").invoke('show');
791             $$(".logged-show").invoke('hide');
792         }
793
794         if (this.iscreator) {
795             $("data_controls").show();
796         } else {
797             $("data_controls").hide();
798         }
799     },
800
801     login: function(aIsCreator) {
802         if (typeof aIsCreator === "boolean") {
803             this.iscreator = aIsCreator;
804         }
805         this.logged = true;
806         this.updateUI();
807     }
808 });
809
810 var PseudoChecker = {
811     req: null,
812     exists: {},
813     currentvalue: null,
814     messageelt: null,
815     throbber: null,
816
817     message: function(str, status, throbber) {
818         var row;
819         if (!this.messageelt) {
820             row = new Element('tr');
821             // we can't use row.update('<td></td><td><div></div></td>')
822             // because gecko would mangle the <td>s
823             row.insert(new Element('td'))
824                .insert((new Element('td')).update(new Element('div')));
825
826             $("user_pseudo").up('tr').insert({after: row});
827             this.messageelt = new Element('span');
828             this.throbber = new Element("img", { src: "icons/pseudo-throbber.gif"});
829             row.down('div').insert(this.throbber).insert(this.messageelt);
830         }
831         if (throbber) {
832             this.throbber.show();
833         } else {
834             this.throbber.hide();
835         }
836         this.messageelt.up().setStyle({visibility: ''});
837         this.messageelt.className = status;
838         this.messageelt.update(str);
839     },
840
841     availableMessage: function(available) {
842         var message = available ? SyjStrings.availablePseudo: SyjStrings.unavailablePseudo,
843             status = available ? "success": "warn";
844         this.message(message, status, false);
845     },
846
847     reset: function() {
848         if (this.req) {
849             this.req.abort();
850             this.req = this.currentvalue = null;
851         }
852         if (this.messageelt) {
853             this.messageelt.up().setStyle({visibility: 'hidden'});
854         }
855     },
856
857     check: function() {
858         var pseudo = $("user_pseudo").value;
859
860         this.reset();
861
862         if (!pseudo || !(pseudo.match(/^[a-zA-Z0-9_.]+$/))) {
863             return;
864         }
865
866         if (typeof this.exists[pseudo] === "boolean") {
867             this.reset();
868             this.availableMessage(!this.exists[pseudo]);
869             return;
870         }
871
872         this.message(SyjStrings.pseudoChecking, "", true);
873
874         this.currentvalue = pseudo;
875         this.req = new Ajax.TimedRequest('userexists/' + encodeURIComponent(pseudo), 20, {
876             onFailure: this.failure.bind(this),
877             onSuccess: this.success.bind(this)
878         });
879     },
880
881     failure: function(transport) {
882         var httpCode = 0, value = this.currentvalue;
883
884         if (transport) {
885             httpCode = transport.getStatus();
886         }
887         this.reset();
888         if (httpCode === 404) {
889             this.exists[value] = false;
890             this.availableMessage(true);
891         }
892
893     },
894
895     success: function(transport) {
896         var httpCode = transport.getStatus(), value = this.currentvalue;
897         this.reset();
898         this.exists[value] = true;
899         this.availableMessage(false);
900     }
901 };
902
903
904 document.observe("dom:loaded", function() {
905     SYJLogin.init();
906     SYJUser.init();
907     SYJView.init();
908     SYJNewpwd.init();
909     LoginMgr.updateUI();
910 });