]> dev.renevier.net Git - syp.git/blob - js/admin.js
d950aeba91275e5055d3f0dda8f87508d8e3ea6b
[syp.git] / js / admin.js
1 /* Copyright (c) 2009 Arnaud Renevier, Inc, published under the modified BSD
2  * license. */
3
4 // drag feature with tolerance
5 OpenLayers.Control.SypDragFeature = OpenLayers.Class (OpenLayers.Control.DragFeature, {
6     startPixel: null,
7     dragStart: null,
8     pixelTolerance : 0,
9     timeTolerance: 300,
10
11     downFeature: function(pixel) {
12         OpenLayers.Control.DragFeature.prototype.downFeature.apply(this, arguments);
13         this.dragStart = (new Date()).getTime(); 
14         this.startPixel = pixel; 
15     },
16
17     doneDragging: function(pixel) {
18         OpenLayers.Control.DragFeature.prototype.doneDragging.apply(this, arguments);
19         // Check tolerance. 
20         var passesTimeTolerance =  
21                     (new Date()).getTime() > this.dragStart + this.timeTolerance; 
22
23         var xDiff = this.startPixel.x - pixel.x; 
24         var yDiff = this.startPixel.y - pixel.y; 
25
26         var passesPixelTolerance =  
27         Math.sqrt(Math.pow(xDiff,2) + Math.pow(yDiff,2)) > this.pixelTolerance; 
28
29         if(passesTimeTolerance && passesPixelTolerance){ 
30             this.onComplete(this.feature, pixel);    
31         } else { 
32             var feature = this.feature; 
33             var res = this.map.getResolution(); 
34             this.feature.geometry.move(res * (this.startPixel.x - this.lastPixel.x), 
35                     res * (this.lastPixel.y - this.startPixel.y)); 
36             this.layer.drawFeature(this.feature); 
37         }
38         this.layer.drawFeature(this.feature, "select");
39     },
40
41     moveFeature: function(pixel) {
42         OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this, arguments);
43         this.layer.drawFeature(this.feature, "temporary");
44     },
45
46     overFeature: function (feature) {
47         // can only drag and drop currently selected feature
48         if (feature != Admin.currentFeature) {
49             return;
50         }
51         OpenLayers.Control.DragFeature.prototype.overFeature.apply(this, arguments);
52     },
53
54     CLASS_NAME: "OpenLayers.Control.SypDragFeature"
55 });
56
57 var Admin = {
58     Markers: {
59         ICON: "media/marker-normal.png",
60         SELECT_ICON: "media/marker-selected.png",
61         TEMPORARY_ICON: "media/marker-temp.png",
62         HEIGHT: 25
63     },
64
65     map: null,
66     baseLayer: null,
67     dataLayer: null,
68     selFeatureControl: null,
69     moveFeatureControl: null,
70     addFeatureControl: null,
71
72     currentFeature: null,
73     currentFeatureLocation: null,
74
75     init: function () {
76         this.map = new OpenLayers.Map ("map", {
77                 controls:[
78                     new OpenLayers.Control.Navigation (),
79                     new OpenLayers.Control.PanZoom ()
80                 ],
81                 projection: new OpenLayers.Projection("EPSG:900913"),
82                 displayProjection: new OpenLayers.Projection("EPSG:4326")
83          });
84
85          this.baseLayer = this.createBaseLayer ();
86          this.map.addLayer(this.baseLayer);
87
88          this.map.setCenter(new OpenLayers.LonLat(0, 0), 0);
89          if (sypSettings.loggedUser) {
90             this.dataLayer = this.createDataLayer (sypSettings.loggedUser);
91             this.map.addLayer(this.dataLayer);
92             this.reset();
93          }
94     },
95
96     reset: function() {
97         this.addFeatureControl.deactivate();
98         this.moveFeatureControl.deactivate();
99         this.selFeatureControl.activate();
100         this.checkForFeatures();
101         $("#newfeature_button").show().val(SypStrings.AddItem);
102         $("#newfeature_button").unbind("click").click(function () {
103             Admin.addNewFeature();
104         });
105     },
106
107     createBaseLayer: function () {
108         return new OpenLayers.Layer.OSM("OSM");
109     },
110
111     createDataLayer: function (user) {
112         var styleMap = new OpenLayers.StyleMap (
113                         {"default": {
114                              externalGraphic: this.Markers.ICON,
115                              graphicHeight: this.Markers.HEIGHT || 32 
116                                 },
117                          "temporary": { 
118                              externalGraphic: this.Markers.TEMPORARY_ICON,
119                              graphicHeight: this.Markers.HEIGHT || 32 
120                          },
121                          "select": { 
122                              externalGraphic: this.Markers.SELECT_ICON,
123                              graphicHeight: this.Markers.HEIGHT || 32 
124                     }});
125
126         var layer = new OpenLayers.Layer.GML("KML", "items.php?from_user=" + encodeURIComponent(user),
127            {
128             styleMap: styleMap,
129             format: OpenLayers.Format.KML, 
130             projection: this.map.displayProjection,
131             eventListeners: { scope: this,
132                 loadend: this.dataLayerEndLoad
133             }
134        });
135
136         // controls
137         this.selFeatureControl = this.createSelectFeatureControl(layer)
138         this.map.addControl(this.selFeatureControl);
139         this.moveFeatureControl = this.createMoveFeatureControl(layer)
140         this.map.addControl(this.moveFeatureControl);
141         this.addFeatureControl = this.createNewfeatureControl();
142         this.map.addControl(this.addFeatureControl);
143
144         return layer;
145     },
146
147     createMoveFeatureControl: function (layer) {
148         var control = new OpenLayers.Control.SypDragFeature(
149                 layer, {
150                          });
151         return control;
152     },
153
154     createSelectFeatureControl: function (layer) {
155         var control = new OpenLayers.Control.SelectFeature(
156                 layer, {
157                         onSelect: OpenLayers.Function.bind(this.onFeatureSelect, this)
158                          });
159         return control;
160     },
161
162     createNewfeatureControl: function () {
163         var control = new OpenLayers.Control ();
164         var handler = new OpenLayers.Handler.Click(control, {
165                 'click': OpenLayers.Function.bind(FeatureMgr.add, FeatureMgr)
166             });
167         control.handler = handler;
168         return control;
169     },
170
171     onFeatureSelect: function (feature) {
172         this.showEditor(feature);
173         FeatureMgr.reset();
174         this.selFeatureControl.deactivate();
175         this.moveFeatureControl.activate();
176     },
177
178     closeEditor: function() {
179         if (this.currentFeature && this.currentFeature.layer) {
180             this.selFeatureControl.unselect(this.currentFeature);
181         }
182         this.currentFeature = null;
183         this.currentFeatureLocation = null;
184         $("#img").removeAttr('src');
185         $("#img").parent().html($("#img").parent().html());
186         $("#img").parent().show();
187         $("#title, #description").val("");
188         $("#editor").hide();
189         // do it once before hidding and once after hidding to work in all cases
190         $("#title, #description").val(""); 
191         $("#image_file").parent().html($("#image_file").parent().html());
192         $(document).unbind("keydown");
193         this.checkForFeatures();
194         this.reset();
195     },
196
197     showEditor: function (feature) {
198         $("#newfeature_button").hide();
199         if (feature.fid) {
200             $("#delete").show();
201         } else {
202             $("#delete").hide();
203         }
204         $(document).unbind("keydown").keydown(function(e) { 
205             if (e.keyCode == 27) {
206                 Admin.cancelCurrentFeature()
207                 e.preventDefault();
208             }
209         });
210         this.currentFeature = feature;
211         this.currentFeatureLocation = new OpenLayers.Pixel(feature.geometry.x, feature.geometry.y);
212         $("#editor").show();
213         $("#instructions").text(SypStrings.DragDropHowto);
214         $("#title").val(feature.attributes.name);
215         var fullDesc = $(feature.attributes.description).parent();
216         $("#description").val(fullDesc.find('p').text());
217         var src = fullDesc.find('img').attr('src');
218         if (src) {
219             $("#img").parent().show();
220             $("#img").attr('src', src);
221             $("#image_file").parent().hide();
222             $("#image_delete").show();
223         } else {
224             $("#img").parent().hide();
225             $("#image_file").parent().show();
226             $("#image_delete").hide();
227         }
228         $("#title").select().focus(); 
229     },
230
231     dataLayerEndLoad: function() {
232         // only set zoom extent once
233         this.dataLayer.events.unregister('loadend', this, this.dataLayerEndLoad);
234         this.dataLayer.events.register('loadend', this, this.checkForFeatures);
235
236         if (!this.checkForFeatures()) {
237             return;
238         }
239
240         var map = this.map;
241         var orig = this.Utils.mbr (this.dataLayer);
242         var centerBounds = new OpenLayers.Bounds();
243
244         var mapProj = map.getProjectionObject();
245         var sypOrigProj = new OpenLayers.Projection("EPSG:4326");
246
247         var bottomLeft = new OpenLayers.LonLat(orig[0],orig[1]);
248         bottomLeft = bottomLeft.transform(sypOrigProj, mapProj);
249         var topRight = new OpenLayers.LonLat(orig[2],orig[3])
250         topRight = topRight.transform(sypOrigProj, mapProj);
251
252         centerBounds.extend(bottomLeft);
253         centerBounds.extend(topRight);
254         map.zoomToExtent(centerBounds);
255     },
256
257     checkForFeatures: function () {
258         var features = this.dataLayer.features;
259         if (features.length != 0) {
260             $("#instructions").text(SypStrings.SelectHowto);
261         }
262         return !!features.length;
263     },
264
265     addNewFeature: function () {
266         function cancel() {
267             $(document).unbind("keydown");
268             Admin.reset()
269         }
270         $(document).unbind("keydown").keydown(function(e) { 
271             if (e.keyCode == 27) {
272                 e.preventDefault();
273                 cancel();
274             }
275         });
276
277         $("#newfeature_button").val("annuler");
278         $("#newfeature_button").unbind("click").click(cancel);
279
280         $("#instructions").text(SypStrings.AddHowto);
281         this.selFeatureControl.deactivate();
282         this.addFeatureControl.activate();
283         FeatureMgr.reset();
284     },
285
286     cancelCurrentFeature: function() {
287         if (AjaxMgr.running) {
288             return;
289         }
290         var feature = this.currentFeature;
291         if (feature.fid) {
292             FeatureMgr.move (feature, this.currentFeatureLocation);
293         } else {
294             this.dataLayer.removeFeatures([feature]);
295         }
296         this.closeEditor();
297     },
298
299     reloadLayer: function (layer) {
300         layer.destroyFeatures();
301         layer.loaded = false;
302         layer.loadGML();
303     },
304
305     Utils: {
306         /* minimum bounds rectangle containing all feature locations.
307          * FIXME: if two features are close, but separated by 180th meridian,
308          * their mbr will span the whole earth. Actually, 179° lon and -170°
309          * lon are considerated very near.
310          */
311         mbr: function (layer) {
312             var features = [];
313             var map = layer.map;
314
315             var mapProj = map.getProjectionObject();
316             var sypOrigProj = new OpenLayers.Projection("EPSG:4326");
317
318             for (var i =0; i < layer.features.length; i++) {
319                 if (layer.features[i].cluster) {
320                     features = features.concat(layer.features[i].cluster);
321                 } else {
322                     features = features.concat(layer.features);
323                 }
324             }
325
326             var minlon = 180;
327             var minlat = 88;
328             var maxlon = -180;
329             var maxlat = -88;
330
331             if (features.length == 0) {
332                 // keep default values
333             } else if (features.length == 1) {
334                 // in case there's only one feature, we show an area of at least 
335                 // 4 x 4 degrees
336                 var pos = features[0].geometry.getBounds().getCenterLonLat().clone();
337                 var lonlat = pos.transform(mapProj, sypOrigProj);
338
339                 minlon = Math.max (lonlat.lon - 2, -180);
340                 maxlon = Math.min (lonlat.lon + 2, 180);
341                 minlat = Math.max (lonlat.lat - 2, -90);
342                 maxlat = Math.min (lonlat.lat + 2, 90);
343             } else {
344                 for (var i = 0; i < features.length; i++) {
345                     var pos = features[i].geometry.getBounds().getCenterLonLat().clone();
346                     var lonlat = pos.transform(mapProj, sypOrigProj);
347                     minlon = Math.min (lonlat.lon, minlon);
348                     minlat = Math.min (lonlat.lat, minlat);
349                     maxlon = Math.max (lonlat.lon, maxlon);
350                     maxlat = Math.max (lonlat.lat, maxlat);
351                 }
352             }
353
354             return [minlon, minlat, maxlon, maxlat];
355
356         },
357
358
359         escapeHTML: function (str) {
360             if (!str) {
361                 return "";
362             }
363             return str.
364              replace(/&/gm, '&amp;').
365              replace(/'/gm, '&#39;').
366              replace(/"/gm, '&quot;').
367              replace(/>/gm, '&gt;').
368              replace(/</gm, '&lt;');
369         },
370
371         startsWith: function (str, prefix) {
372             return (str.slice(0, prefix.length) == prefix);
373         },
374
375         indexOf: function (array, item) {
376             if (array.indexOf !== undefined) {
377                 return array.indexOf(item);
378             } else {
379                 return OpenLayers.Util.indexOf(array, item);
380             }
381         }
382     }
383 }
384
385 var FeatureMgr = {
386     reset: function() {
387         this.commError("");
388     },
389
390     add: function(evt) {
391         var map = Admin.map;
392         var pos = map.getLonLatFromViewPortPx(evt.xy);
393         feature = this.update (null, pos, "", "", "");
394         Admin.addFeatureControl.deactivate();
395         Admin.selFeatureControl.select(feature);
396     },
397
398     move: function (feature, aLocation) {
399         if (!feature || !aLocation) {
400             return;
401         }
402         var curLoc = feature.geometry;
403         feature.geometry.move(aLocation.x - curLoc.x, aLocation.y - curLoc.y);
404         feature.layer.drawFeature(feature); 
405     },
406
407     update: function(feature, lonlat, imgurl, title, description) {
408         var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
409         if (!feature) {
410             feature = new OpenLayers.Feature.Vector(point);
411             Admin.dataLayer.addFeatures([feature]);
412         } else {
413             this.move (feature, point);
414         }
415         feature.attributes.name = title;
416         feature.attributes.description = "<p>" + Admin.Utils.escapeHTML(description) + "</p>"
417                                 + "<img src=\"" + imgurl + "\">"
418         return feature;
419     },
420
421     del: function (feature) {
422         var form = $("#feature_delete");
423         form.find('input[name="fid"]').val(feature.fid);
424         AjaxMgr.add({
425             form: form,
426             oncomplete: OpenLayers.Function.bind(this.ajaxReply, this),
427             onsend: function() { $("#editor_throbber").css("visibility", "visible"); }
428         });
429     },
430
431     save: function (feature) {
432         var x = feature.geometry.x;
433         var y = feature.geometry.y;
434
435         var mapProj = feature.layer.map.getProjectionObject();
436         var lonlat = new OpenLayers.LonLat(x, y).
437                                     transform(mapProj,
438                                               new OpenLayers.Projection("EPSG:4326"));
439         var form = $("#feature_update");
440         form.find('input[name="lon"]').val(lonlat.lon);
441         form.find('input[name="lat"]').val(lonlat.lat);
442         form.find('input[name="fid"]').val(feature.fid);
443         form.find('input[name="keep_img"]').val(
444             $("#img").attr("src") ? "yes": "no"
445         );
446
447         if (feature.fid) {
448             form.find('input[name="request"]').val("update");
449         } else {
450             form.find('input[name="request"]').val("add");
451         }
452         AjaxMgr.add({
453             form: form,
454             oncomplete: OpenLayers.Function.bind(this.ajaxReply, this),
455             onsend: function() { $("#editor_throbber").css("visibility", "visible"); }
456         });
457     },
458
459     ajaxReply: function (data) {
460         $("#editor_throbber").css("visibility", "hidden");
461         if (!data) {
462             this.commError(SypStrings.ServerError);
463             return;
464         }
465
466         var xml = new OpenLayers.Format.XML().read(data);
467
468         switch (xml.documentElement.nodeName.toLowerCase()) {
469             case "error":
470                 switch (xml.documentElement.getAttribute("reason")) {
471                     case "unauthorized":
472                         $("#login_area").show();
473                         $("#password").val("");
474                         $("#user").val(sypSettings.loggedUser).focus().select();
475                         $("#cookie_warning").show();
476                         this.reset();
477                         Admin.cancelCurrentFeature();
478                         Admin.reset();
479                     break;
480                     case "server":
481                         this.commError(SypStrings.ServerError);
482                         $("title").focus();
483                     break;
484                     case "unreferenced":
485                         this.commError(SypStrings.UnreferencedError);
486                         Admin.reloadLayer(Admin.dataLayer);
487                         Admin.closeEditor();
488                     break;
489                     case "nochange":
490                         this.commError(SypStrings.NochangeError);
491                         Admin.closeEditor();
492                     break;
493                     case "request":
494                         this.commError(SypStrings.RequestError);
495                         $("title").focus();
496                     break;
497                     case "toobig":
498                         this.commError(SypStrings.ToobigError);
499                         $("#image_file").parent().html($("#image_file").parent().html());
500                         $("#image_file").focus();
501                     break;
502                     case "notimage":
503                         this.commError(SypStrings.NotimageError);
504                         $("#image_file").parent().html($("#image_file").parent().html());
505                         $("#image_file").focus();
506                     break;
507                     default:
508                         this.commError(SypStrings.UnknownError);
509                         $("title").focus();
510                     break;
511                 }
512             break;
513             case "success":
514                 switch (xml.documentElement.getAttribute("request")) {
515                     case "del":
516                         this.commSuccess(SypStrings.DelSucces);
517                         var someFeature = false;
518                         var self = this;
519                         $.each($(xml).find("FEATURE,feature"), function () {
520                              someFeature = true;
521                              var id = parseFloat($(this).find("ID:first,id:first").text());
522                              if ((id === null) || isNaN (id)) {
523                                 return;;
524                              }
525                              var features = Admin.dataLayer.features;
526                              for (var idx = 0; idx < features.length; idx++) {
527                                  if (features[idx].fid == id) {
528                                      Admin.dataLayer.removeFeatures([features[idx]]);
529                                  }
530                              }
531                         });
532                         if (someFeature == false) {
533                             this.commError(SypStrings.UnconsistentError);
534                         } else {
535                             Admin.closeEditor();
536                         }
537                     break;
538                     case "update":
539                     case "add":
540                         var someFeature = false;
541                         var self = this;
542                         $.each($(xml).find("FEATURE,feature"), function () {
543                                 someFeature = true;
544                                 var id = parseFloat($(this).find("ID:first,id:first").text());
545                                 if ((id === null) || isNaN (id)) {
546                                     return;;
547                                 }
548
549                                 var lon = parseFloat($(this).find("LON:first,lon:first").text());
550                                 if ((typeof (lon) != "number") || isNaN (lon) ||
551                                         (lon < -180) || (lon > 180)) {
552                                     return;;
553                                 }
554
555                                 var lat = parseFloat($(this).find("LAT:first,lat:first").text());
556                                 if ((typeof (lat) != "number") || isNaN (lat) ||
557                                         (lat < -90) || (lat > 90)) {
558                                     return;;
559                                 }
560
561                                 var mapProj = Admin.map.getProjectionObject();
562                                 var lonlat = new OpenLayers.LonLat (lon, lat).
563                                                 transform( new OpenLayers.Projection("EPSG:4326"), mapProj);
564
565                                 var imgurl = $(this).find("IMGURL:first,imgurl:first").text();
566                                 var title = $(this).find("HEADING:first,heading:first").text();
567                                 var description = $(this).find("DESCRIPTION:first,description:first").text();
568
569                                 feature = self.update (Admin.currentFeature, lonlat, imgurl, title, description); 
570                                 feature.fid = id;
571                         });
572
573                         if (someFeature == false) {
574                             this.commError(SypStrings.UnconsistentError);
575                         } else {
576                             this.commSuccess(SypStrings.UpdateSucces);
577                             Admin.closeEditor();
578                         }
579
580                     break;
581                     default:
582                         this.commError(SypStrings.UnconsistentError);
583                    break;
584                 }
585             break;
586             default:
587                 this.commError(SypStrings.UnconsistentError);
588             break;
589         }
590     },
591
592     commSuccess: function (message) {
593         $("#server_comm").text(message);
594         $("#server_comm").removeClass().addClass("success");
595     },
596
597     commError: function (message) {
598         $("#server_comm").text(message);
599         $("#server_comm").removeClass().addClass("error");
600     }
601 }
602
603 /* maintains a queue of ajax queries, so I'm sure they all execute in the same
604  * order they were defined */
605 var AjaxMgr = {
606     _queue: [],
607
608     running: false,
609
610     add: function(query) {
611         this._queue.push(query);
612         if (this._queue.length > 1) {
613             return;
614         } else {
615             this._runQuery(query);
616         }
617     },
618
619     _runQuery: function(query) {
620         var self = this;
621         $('#api_frame').one("load", function() {
622             self.running = false;
623             self._reqEnd();
624             if (typeof (query.oncomplete) == "function") {
625                 var body = null;
626                 try {
627                     if (this.contentDocument) {
628                         body = this.contentDocument.body;
629                     } else if (this.contentWindow) {
630                         body = this.contentWindow.document.body;
631                     } else {
632                         body = document.frames[this.id].document.body;
633                     }
634                 } catch (e) {}
635                     if (body) {
636                         query.oncomplete(body.innerHTML);
637                     } else {
638                         query.oncomplete(null);
639                     }
640             }
641         });
642         query.form.attr("action", "api.php");
643         query.form.attr("target", "api_frame");
644         query.form.attr("method", "post");
645         this.running = true;
646         query.form.get(0).submit();
647         if (typeof (query.onsend) == "function") {
648             query.onsend();
649         }
650     },
651
652     _reqEnd: function() {
653         this._queue.shift();
654         if (this._queue.length > 0) {
655             this._reqEnd(this._queue[0]);
656         }
657     }
658 }
659
660 var pwdMgr = {
661
662     init: function () {
663         $("#login_form").submit(this.submit);
664         $("#user").focus().select();
665     },
666
667     reset: function() {
668         this.commError ("");
669     },
670
671     submit: function () {
672         try {
673             pwdMgr.commError("");
674             var req = {
675                 form:  $("#login_form"),
676                 onsend: function() {
677                     $("#pwd_throbber").css("visibility", "visible");
678                     $("#login_error").hide();
679
680                     // we need a timeout; otherwise those fields will not be submitted
681                     window.setTimeout(function() { 
682                             // removes focus from #password before disabling it. Otherwise, opera
683                             // prevents re-focusing it after re-enabling it.
684                             $("#user, #password").blur(); 
685                             $("#login_submit, #user, #password").attr("disabled", "disabled");
686                     }, 0)
687                 },
688                 oncomplete: OpenLayers.Function.bind(pwdMgr.ajaxReply, pwdMgr)
689             };
690             AjaxMgr.add(req);
691         } catch(e) {}
692         return false;
693     },
694
695     ajaxReply: function (data) {
696
697         $("#pwd_throbber").css("visibility", "hidden");
698         // here, we need a timeout because onsend timeout sometimes has not been triggered yet
699         window.setTimeout(function() {
700             $("#login_submit, #user, #password").removeAttr("disabled");
701         }, 0);
702
703         if (!data) {
704             this.commError(SypStrings.ServerError);
705             $("#login_error").show();
706             window.setTimeout(function() {
707                     $("#user").focus().select();
708             }, 0);
709             return;
710         }
711         var xml = new OpenLayers.Format.XML().read(data);
712
713         switch (xml.documentElement.nodeName.toLowerCase()) {
714             case "error":
715                 switch (xml.documentElement.getAttribute("reason")) {
716                     case "server":
717                         this.commError(SypStrings.ServerError);
718                     break;
719                     case "unauthorized":
720                         this.commError(SypStrings.UnauthorizedError);
721                     break;
722                     case "request":
723                         this.commError(SypStrings.RequestError);
724                     break;
725                     default:
726                         this.commError(SypStrings.UnknownError);
727                     break;
728                 }
729                 $("#login_error").show();
730                 window.setTimeout(function() {
731                         $("#user").focus().select();
732                 }, 0);
733             break;
734             case "success":
735                 $("#login_area").hide();
736
737                 user = $(xml).find("USER,user").text();
738                 sypSettings.loggedUser = user;
739
740                 if (Admin.selFeatureControl) {
741                     Admin.selFeatureControl.destroy();
742                 }
743                 if (Admin.moveFeatureControl) {
744                     Admin.moveFeatureControl.destroy();
745                 }
746                 if (Admin.addFeatureControl) {
747                     Admin.addFeatureControl.destroy();
748                 }
749                 if (Admin.dataLayer) {
750                     Admin.dataLayer.destroy();
751                 }
752
753                 Admin.dataLayer = Admin.createDataLayer(user);
754                 Admin.map.addLayer(Admin.dataLayer);
755                 Admin.reset();
756
757             break;
758             default:
759                 this.commError(SypStrings.UnconsistentError);
760             break;
761         }
762     },
763
764     commError: function (message) {
765         $("#login_error").text(message);
766         if (message) {
767             $("#login_error").show();
768         } else {
769             $("#login_error").hide();
770         }
771     }
772 }
773
774 $(window).load(function () {
775     // if using .ready, ie triggers an error when trying to access
776     // document.namespaces
777     pwdMgr.init();
778     $("#newfeature_button").click(function () {
779         Admin.addNewFeature();
780     });
781     $("#editor_close").click(function () {
782         Admin.cancelCurrentFeature()
783     });
784     $("#feature_update").submit(function() {
785         try {
786             FeatureMgr.save(Admin.currentFeature);
787         } catch(e) {}
788         return false;
789     });
790     $("#feature_delete").submit(function() {
791         try {
792             FeatureMgr.del(Admin.currentFeature);
793         } catch(e) {}
794         return false;
795     });
796     $("#image_delete").click(function() {
797             $("#img").removeAttr('src');
798             // needs to rebuild element otherwise some browsers still
799             // display image.
800             $("#img").parent().html($("#img").parent().html());
801             $("#img").parent().hide();
802             $("#image_delete").hide();
803             $("#image_file").parent().show();
804     });
805
806     Admin.init();
807 });