]> dev.renevier.net Git - syj.git/blobdiff - public/js/syj.js
merge linestrings for gpx containting multiple trkseg elements.
[syj.git] / public / js / syj.js
index 54677a27fb09992e40fdfb09f53e4d5078651622..8f5f509020fd0f6251055213aa3d050169f963fe 100644 (file)
@@ -1,11 +1,15 @@
-/*  This file is part of Syj, Copyright (c) 2010 Arnaud Renevier,
+/*  This file is part of Syj, Copyright (c) 2010-2011 Arnaud Renevier,
     and is published under the AGPL license. */
 
+"use strict";
+
 // avoid openlayers alerts
 OpenLayers.Console.userError = function(error) {
     SYJView.messenger.setMessage(error, "error");
 };
 
+OpenLayers.Layer.Vector.prototype.renderers = ["SVG2", "VML", "Canvas"];
+
 var SyjSaveUI = {
     status: "unknown",
 
@@ -21,7 +25,7 @@ var SyjSaveUI = {
         this.enableSubmit();
         $("geom_title").disabled = false;
         $("geom_title").activate();
-        $("geomform").removeClassName("disabled");
+        $$("#geom_accept_container, #geom_title_container").invoke('removeClassName', "disabled");
         this.status = "enabled";
         return this;
     },
@@ -33,7 +37,7 @@ var SyjSaveUI = {
         this.disableSubmit();
         $("geom_title").blur();
         $("geom_title").disabled = true;
-        $("geomform").addClassName("disabled");
+        $$("#geom_accept_container, #geom_title_container").invoke('addClassName', "disabled");
         this.status = "disabled";
         return this;
     },
@@ -100,7 +104,12 @@ var SYJDataUi = (function() {
             if (!infotoggler) {
                 infotoggler = new Toggler('path-infos-content');
                 $("path-infos-toggler").insert({bottom: infotoggler.element});
-                $("path-infos-anchor").observe('click', function(evt) {
+                var anchor = $("path-infos-anchor");
+                var parent = anchor.up('.menu-item');
+                if (parent) {
+                    anchor = parent;
+                }
+                anchor.observe('click', function(evt) {
                     evt.stop();
                     infotoggler.toggle(evt);
                 });
@@ -267,7 +276,7 @@ var SYJView = {
     mode: 'view',
 
     init: function() {
-        var externalGraphic, baseURL, baseLayer, layerOptions, extent, hidemessenger;
+        var externalGraphic, baseURL, baseLayer, layerOptions, hidemessenger;
 
         // is svg context, opera does not resolve links with base element is svg context
         externalGraphic = styleMap.edit.styles.select.defaultStyle.externalGraphic;
@@ -283,7 +292,11 @@ var SYJView = {
             theme: null
         });
 
-        baseLayer = new OpenLayers.Layer.OSM("OSM", null, { wrapDateLine: true , attribution: SyjStrings.osmAttribution });
+        baseLayer = new OpenLayers.Layer.OSM("OSM", [
+                'http://a.tile.openstreetmap.org/${z}/${x}/${y}.png',
+                'http://b.tile.openstreetmap.org/${z}/${x}/${y}.png',
+                'http://c.tile.openstreetmap.org/${z}/${x}/${y}.png'],
+                { attribution: SyjStrings.osmAttribution });
 
         layerOptions = {format:     OpenLayers.Format.WKT,
                         projection: WGS84,
@@ -296,7 +309,7 @@ var SYJView = {
         if ($("edit-btn")) {
             $("edit-btn").observe('click', function() {
                 $("geom_submit").value = SyjStrings.editAction;
-                this.messenger.hide();
+                this.messenger.clearMessages();
                 this.editMode();
                 this.mode = 'edit';
             }.bind(this));
@@ -305,7 +318,7 @@ var SYJView = {
         if ($("create-btn")) {
             $("create-btn").observe('click', function() {
                 $("geom_submit").value = SyjStrings.createAction;
-                this.messenger.hide();
+                this.messenger.clearMessages();
                 this.editMode();
                 this.mode = 'create';
             }.bind(this));
@@ -315,7 +328,7 @@ var SYJView = {
             $("clone-btn").observe('click', function() {
                 $("geom_submit").value = SyjStrings.cloneAction;
                 $("geom_title").value = "";
-                this.messenger.hide();
+                this.messenger.clearMessages();
                 this.editMode();
                 this.mode = 'create';
             }.bind(this));
@@ -341,22 +354,118 @@ var SYJView = {
 
         if (typeof gInitialGeom !== "undefined" && typeof gInitialGeom.data !== "undefined") {
             this.viewLayer.addFeatures([this.wkt.read(gInitialGeom.data)]);
-            extent = this.viewLayer.getDataExtent();
             // XXX: ie has not guessed height of map main div yet during map
             // initialisation. Now, it will read it correctly.
             this.map.updateSize();
+            this.map.zoomToExtent(this.viewLayer.getDataExtent());
         } else {
-            extent = new OpenLayers.Bounds(gMaxExtent.minlon, gMaxExtent.minlat, gMaxExtent.maxlon, gMaxExtent.maxlat)
-                                         .transform(WGS84, Mercator);
-        }
-        this.map.zoomToExtent(extent);
+            this.initMaPos(gInitialPos);
+        }
+
+        $("map-overlay").hide();
+        $("geom_upload").observe('change', function(evt) {
+            var file = null, reader = null, readerror = null;
+            if (window.FileList && window.FileReader) {
+                file = evt.target.files[0];
+                reader = new FileReader();
+                readerror = function() {
+                    this.messenger.setMessage(SyjStrings.uploadFileError, "warn");
+                }.bind(this);
+                reader.onload = function(evt) {
+                    var data = null, results = null, engine = null, vector = null, i = 0, format = null, formats = ['KML', 'GPX', 'GeoJSON'];
+
+                    $("geom_upload_container").removeClassName("disabled");
+                    $("geom_upload").disabled = false;
+                    if (evt.error) {
+                        readerror();
+                        return;
+                    }
+                    data = evt.target.result;
+
+                    for (i = 0; i < formats.length; i++) {
+                        format = formats[i];
+                        engine = new OpenLayers.Format[format]({ internalProjection: Mercator, externalProjection: WGS84 });
+                        try {
+                            results = engine.read(data);
+                        } catch(e) {
+                        }
+                        if (results && results.length) {
+                            break;
+                        }
+                    }
+                    if (!results || !results.length) {
+                        readerror();
+                        return;
+                    }
+
+                    vector = results[0];
+                    if (vector.geometry.CLASS_NAME !== "OpenLayers.Geometry.LineString") {
+                        readerror();
+                        return;
+                    }
+                    // merge linestrings for gpx containting multiple trkseg elements.
+                    if (format === 'GPX') {
+                      for (i = 1; i < results.length; i++) {
+                        vector.geometry.addComponents(results[i].geometry.components);
+                      }
+                    }
+                    this.viewLayer.addFeatures([vector]);
+                    this.map.zoomToExtent(this.viewLayer.getDataExtent());
+
+                    if ($("edit-btn")) {
+                        $("edit-btn").click();
+                    } else if ($("create-btn")) {
+                        $("create-btn").click();
+                    }
+
+                    if (this.editControl.handler.realPoints.length < 2) {
+                        SyjSaveUI.disable();
+                    } else {
+                       SyjSaveUI.enable();
+                    }
+
+                    if (vector.data && vector.data.name) {
+                        $("geom_title").value = vector.data.name;
+                    }
+                }.bind(this);
+                $("geom_upload_container").addClassName("disabled");
+                $("geom_upload").disabled = true;
+                reader.readAsText(file);
+                return;
+            }
+            $("map-overlay").show();
+            SyjSaveUI.enable();
+            this.editControl.deactivate();
+        }.bind(this));
+
         document.observe('simplebox:shown', this.observer.bindAsEventListener(this));
         SYJPathLength.update();
     },
 
+    initMaPos: function (aPos) {
+        var extent = null, center = null, zoom = 0;
+
+        if (aPos.hasOwnProperty('lon') && aPos.hasOwnProperty('lat') && aPos.hasOwnProperty('zoom')) {
+            center = new OpenLayers.LonLat(parseFloat(aPos.lon), parseFloat(aPos.lat)).transform(WGS84, Mercator);
+            zoom = parseInt(aPos.zoom, 10);
+        } else if (aPos.hasOwnProperty('minlon') && aPos.hasOwnProperty('minlat')
+                    && aPos.hasOwnProperty('maxlon') && aPos.hasOwnProperty('maxlat')) {
+            extent = new OpenLayers.Bounds(aPos.minlon, aPos.minlat, aPos.maxlon, aPos.maxlat)
+                                         .transform(WGS84, Mercator);
+        } else {
+            extent = new OpenLayers.Bounds(-160, -70, 160, 70).transform(WGS84, Mercator);
+        }
+
+        if (extent) {
+            this.map.zoomToExtent(extent);
+        } else {
+            this.map.setCenter(center, zoom);
+        }
+    },
+
     observer: function(evt) {
         if (evt.eventName === "simplebox:shown" && evt.memo.element !== $("termsofusearea")) {
-            this.messenger.hide();
+            this.messenger.clearMessages();
         }
     },
 
@@ -379,7 +488,12 @@ var SYJView = {
 
         this.viewMode();
 
-        $("geom_data").value = this.wkt.write(new OpenLayers.Feature.Vector(line));
+        if (line.components.length) {
+            $("geom_data").value = this.wkt.write(new OpenLayers.Feature.Vector(line));
+        } else {
+            $("geom_data").value = "";
+        }
+
         if (this.mode === "edit" && typeof gLoggedInfo.pathid !== "undefined") {
             $("geomform").setAttribute("action", "path/" + gLoggedInfo.pathid.toString() + '/update');
         } else {
@@ -387,7 +501,7 @@ var SYJView = {
         }
         this.needsFormResubmit = false;
         SyjSaveUI.disable.bind(SyjSaveUI).defer();
-        this.messenger.hide();
+        this.messenger.clearMessages();
         return true;
     },
 
@@ -448,15 +562,27 @@ var SYJView = {
             callbacks: {
                 modify: function(f, line) {
                     SYJPathLength.update();
-                    if (!SYJView.unsavedRoute) {
-                        SYJView.unsavedRoute = {};
+
+                    var npoints = this.handler.realPoints.length;
+                    if (npoints === 0) {
+                        $("geom_upload_container").show();
+                        SYJView.unsavedRoute = null;
+                    } else {
+                        if (!SYJView.unsavedRoute) {
+                            SYJView.unsavedRoute = {};
+                        }
                     }
-                    if (this.handler.realPoints.length < 2) {
+
+                    if (npoints < 2) {
                         SyjSaveUI.disable();
                     } else {
                         SyjSaveUI.enable();
                     }
-                }
+                },
+                create: function(f, line) {
+                    this.messenger.clearMessages();
+                    $("geom_upload_container").hide();
+                }.bind(this)
             },
 
             handlerOptions: {
@@ -471,33 +597,17 @@ var SYJView = {
             styles = this.editControl.handler.layerOptions.styleMap.styles;
             styles.select = styles.select_for_canvas;
         }
-        new CloseBtn($("geomform"), {
-            style : {
-                marginRight: "-40px",
-                marginTop: "-20px"
-            },
-            callback: function(form) {
-                this.viewMode();
-                this.mode = 'view';
-                SYJDataUi.viewmode();
-                this.messenger.hide();
-
-                if (this.unsavedRoute && typeof this.unsavedRoute.features !== "undefined") {
-                    this.viewLayer.addFeatures(this.unsavedRoute.features);
-                }
-                if (this.unsavedRoute && typeof this.unsavedRoute.title !== "undefined") {
-                    $("geom_title").value = this.unsavedRoute.title;
-                } else {
-                    $("geom_title").value = "";
-                }
-                this.unsavedRoute = null;
-            }.bind(this)
-        });
     },
 
     saveSuccess: function(transport) {
-      this.unsavedRoute = null;
+      // server sends and empty response on success. If we get a response, that
+      // probably means an error or warning has been printed by server.
+      if (!transport.responseJSON && transport.responseText.length) {
+          this.saveFailure(null, 500);
+          return;
+      }
 
+      this.unsavedRoute = null;
       if (transport.responseJSON && (typeof transport.responseJSON.redirect === "string")) {
           location = transport.responseJSON.redirect;
           return;
@@ -508,12 +618,12 @@ var SYJView = {
       document.title = $('geom_title').value;
     },
 
-    saveFailure: function(transport) {
-        var httpCode = 0, message = "";
-
-        if (transport) {
-            httpCode = transport.getStatus();
+    saveFailure: function(transport, httpCode) {
+        var message = "";
+        if (typeof httpCode === "undefined") {
+            httpCode = transport? transport.getStatus(): 0;
         }
+
         switch (httpCode) {
             case 0:
                 message = SyjStrings.notReachedError;
@@ -521,15 +631,6 @@ var SYJView = {
             case 400:
             case 404:
                 message = SyjStrings.requestError;
-                if (transport.responseJSON) {
-                    switch (transport.responseJSON.message) {
-                        case "uniquepath":
-                            message = SyjStrings.uniquePathError;
-                        break;
-                        default:
-                        break;
-                    }
-                }
             break;
             case 403:
                 message = "";
@@ -570,7 +671,12 @@ var SYJModalClass = Class.create({
             closeMethods: ["onescapekey", "onouterclick", "onbutton"]
         });
 
-        $(this.type + "_control_anchor").observe("click", function(evt) {
+        var anchor = $(this.type + '_control_anchor');
+        var parent = anchor.up('.menu-item');
+        if (parent) {
+            anchor = parent;
+        }
+        anchor.observe("click", function(evt) {
             this.modalbox.show();
             evt.stop();
         }.bindAsEventListener(this));
@@ -603,7 +709,7 @@ var SYJModalClass = Class.create({
                 input = this.area.select('input[type="text"]')[0];
                 (function () {
                     input.activate();
-                }).defer();
+                }.defer());
             } else {
                 this.modalbox.hide();
             }
@@ -643,7 +749,7 @@ var SYJModalClass = Class.create({
     },
 
     reset: function() {
-        this.messenger.hide();
+        this.messenger.clearMessages();
         this.area.select('.message').invoke('setMessageStatus', null);
     }
 });
@@ -656,7 +762,11 @@ var SYJUserClass = Class.create(SYJModalClass, {
         $super();
         $("termsofusearea").hide();
 
-        $$("#user_termsofuse_anchor, #geom_termsofuse_anchor").invoke('observe', "click", function(evt) {
+        var touevt = (function(evt) {
+            if (evt.type === "keyup" && evt.keyCode !== 32) { // 32 = space
+                // allow opening box by pressing space
+                return;
+            }
             if (!this.toubox) {
                 this.toubox = new SimpleBox($("termsofusearea"), {
                     closeMethods: ["onescapekey", "onouterclick", "onbutton"]
@@ -668,7 +778,11 @@ var SYJUserClass = Class.create(SYJModalClass, {
                 $("termsofuseiframe").setAttribute("src", evt.target.href);
             }
             evt.stop();
-        }.bindAsEventListener(this));
+        }).bindAsEventListener(this);
+
+        ["click", "keyup"].each(function (evtName) {
+            $$("#user_termsofuse_anchor, #geom_termsofuse_anchor").invoke('observe', evtName, touevt);
+        })
 
         $$("#login_area_create > a").invoke('observe', 'click',
             function(evt) {
@@ -701,7 +815,7 @@ var SYJUserClass = Class.create(SYJModalClass, {
     },
 
     presubmit: function() {
-        this.messenger.hide();
+        this.messenger.clearMessages();
         PseudoChecker.reset();
         if (!(this.checkNotEmpty("user_pseudo", SyjStrings.userEmptyWarn))) {
             return false;
@@ -751,7 +865,14 @@ var SYJUserClass = Class.create(SYJModalClass, {
     },
 
     success: function(transport) {
-        LoginMgr.login();
+        if (!transport.responseJSON ||
+            typeof transport.responseJSON.pseudo !== "string"
+            ) {
+            this.messenger.setMessage(SyjStrings.unknownError, "error");
+            return;
+        }
+
+        LoginMgr.login(transport.responseJSON.pseudo);
         SYJView.messenger.setMessage(SyjStrings.userSuccess, "success");
         this.modalbox.hide();
         if (SYJView.needsFormResubmit) {
@@ -812,7 +933,7 @@ var SYJLoginClass = Class.create(SYJModalClass, {
     },
 
     presubmit: function() {
-        this.messenger.hide();
+        this.messenger.clearMessages();
         if (!(this.checkNotEmpty("login_user", SyjStrings.userEmptyWarn))) {
             return false;
         }
@@ -829,14 +950,8 @@ var SYJLoginClass = Class.create(SYJModalClass, {
             this.messenger.setMessage(SyjStrings.unknownError, "error");
             return;
         }
-        LoginMgr.login(transport.responseJSON.iscreator);
-        $$('.logged-pseudo').each(function(elt) {
-            $A(elt.childNodes).filter(function(node) {
-                return (node.nodeType === 3 || node.tagName.toLowerCase() === 'br');
-            }).each(function(node) {
-                node.nodeValue = node.nodeValue.replace('%s', transport.responseJSON.pseudo);
-            });
-        });
+        LoginMgr.login(transport.responseJSON.pseudo, transport.responseJSON.iscreator);
+
         SYJView.messenger.setMessage(SyjStrings.loginSuccess, "success");
         this.modalbox.hide();
         if (SYJView.needsFormResubmit) {
@@ -919,11 +1034,18 @@ var LoginMgr = Object.extend(gLoggedInfo, {
         }
     },
 
-    login: function(aIsCreator) {
+    login: function(aPseudo, aIsCreator) {
         if (typeof aIsCreator === "boolean") {
             this.iscreator = aIsCreator;
         }
         this.logged = true;
+        $$('.logged-pseudo').each(function(elt) {
+            $A(elt.childNodes).filter(function(node) {
+                return (node.nodeType === 3 || node.tagName.toLowerCase() === 'br');
+            }).each(function(node) {
+                node.nodeValue = node.nodeValue.replace('%s', aPseudo);
+            });
+        });
         this.updateUI();
     }
 });
@@ -1046,7 +1168,7 @@ var Nominatim = (function() {
             center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
         }
         this.setCenter(center, this.getZoomForExtent(bounds), false, true);
-    }
+    };
 
     var success = function(transport) {
         $("nominatim-throbber").hide();
@@ -1080,7 +1202,8 @@ var Nominatim = (function() {
             };
         };
 
-        for (var i = 0; i < transport.responseJSON.length; i++) {
+        var i;
+        for (i = 0; i < transport.responseJSON.length; i++) {
             var item = transport.responseJSON[i];
             if (item.display_name && item.boundingbox && item.boundingbox.length === 4) {
                 var li = new Element("li");
@@ -1090,13 +1213,12 @@ var Nominatim = (function() {
                 });
 
                 anchor.observe('click', clickhandler(item.boundingbox));
+                Element.text(anchor, item.display_name);
 
-                var text = document.createTextNode(item.display_name);
                 var icon = new Element("img", {
                     className: "nominatim-suggestions-icon",
                     src: item.icon || 'icons/world.png'
                 });
-                anchor.appendChild(text); // insert does not work; see prototype #1125
                 li.insert(icon).insert(anchor);
                 $("nominatim-suggestions-list").insert(li);
                 if ($("nominatim-suggestions-list").childNodes.length >= 6) {
@@ -1108,7 +1230,7 @@ var Nominatim = (function() {
         if ($("nominatim-suggestions-list").childNodes.length > 1) {
             var bottomOffset = $('data_controls').measure('height') + 3;
             $("nominatim-suggestions").setStyle({
-                bottom: bottomOffset.toString() + 'px'
+                bottom: (document.viewport.getHeight() - $('data_controls').cumulativeOffset().top + 3).toString() + 'px'
             }).show();
             $("nominatim-suggestions-list").select("li:first-child")[0].addClassName('current');
         } else {