First pass at banishing the words "bug" and "OpenStreetBugs"
authorTom Hughes <tom@compton.nu>
Sat, 13 Aug 2011 17:33:22 +0000 (18:33 +0100)
committerTom Hughes <tom@compton.nu>
Sat, 13 Aug 2011 17:33:22 +0000 (18:33 +0100)
app/views/site/index.html.erb
config/locales/en.yml
public/images/icon_note_add.png [moved from public/images/icon_error_add.png with 100% similarity]
public/javascripts/notes.js [new file with mode: 0644]
public/javascripts/openstreetbugs.js [deleted file]
public/stylesheets/notes.css [new file with mode: 0644]
public/stylesheets/openstreetbugs.css [deleted file]

index b4719f6710966e5707eef1c1db86ba27d29cdcc7..fa790dbb1bcf999f468ec6fc340ec97b2d6b5eb2 100644 (file)
@@ -20,7 +20,7 @@
   <div id="permalink">
     <a href="/" id="permalinkanchor" class="geolink llz layers object"><%= t 'site.index.permalink' %></a><br/>
     <a href="/" id="shortlinkanchor"><%= t 'site.index.shortlink' %></a>
-    <a href="#" id="reportbuganchor">Report a problem</a>      
+    <a href="#" id="createnoteanchor">Report a problem</a>     
   </div>
 </div>
 
@@ -123,7 +123,7 @@ end
 
 <%= javascript_include_tag '/openlayers/OpenLayers.js' %>
 <%= javascript_include_tag '/openlayers/OpenStreetMap.js' %>
-<%= javascript_include_tag 'openstreetbugs.js' %>
+<%= javascript_include_tag 'notes.js' %>
 <%= javascript_include_tag 'map.js' %>
 
 <%= render :partial => 'resize' %>
@@ -146,24 +146,19 @@ end
       map.dataLayer.events.register("visibilitychanged", map.dataLayer, toggleData);
       map.addLayer(map.dataLayer);
 
-      map.osbLayer = new OpenLayers.Layer.OpenStreetBugs("Notes", {
-          serverURL: "/api/0.6/",
-          iconOpen: new OpenLayers.Icon("<%= image_path "open_note_marker.png" %>", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
-          iconClosed: new OpenLayers.Icon("<%= image_path "closed_noe_marker.png" %>", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
-          readonly: false,
+      map.noteLayer = new OpenLayers.Layer.Notes("Notes", {
           setCookie: false,
           permalinkURL: "http://www.openstreetmap.org/",
-          theme: "<%= stylesheet_path "openstreetbugs" %>",
           visibility: <%= params[:notes] == "yes" %>
       });
-      map.addLayer(map.osbLayer);
+      map.addLayer(map.noteLayer);
 
-      map.osbControl = new OpenLayers.Control.OpenStreetBugs(map.osbLayer); 
-      map.addControl(map.osbControl);
+      map.noteControl = new OpenLayers.Control.Notes(map.noteLayer); 
+      map.addControl(map.noteControl);
 
-      $("reportbuganchor").observe("click", addBug);
+      $("createnoteanchor").observe("click", addNote);
 
-      map.events.register("zoomend", map, allowBugReports);
+      map.events.register("zoomend", map, allowNoteReports);
     <% end %>
 
     <% unless object_zoom %>
@@ -292,16 +287,16 @@ end
     <% end %>
   }
 
-  function addBug() {
-    map.osbControl.activate();
-    map.osbControl.addTemporaryMarker(map.getCenter());
+  function addNote() {
+    map.noteControl.activate();
+    map.noteControl.addTemporaryMarker(map.getCenter());
   }
 
-  function allowBugReports() { 
+  function allowNoteReports() { 
     if (map.getZoom() > 11) {
-      $("reportbuganchor").style.visibility = "visible";
+      $("createnoteanchor").style.visibility = "visible";
     } else {
-      $("reportbuganchor").style.visibility = "hidden";
+      $("createnoteanchor").style.visibility = "hidden";
     }
   }
 
index 685974ff9d53b1a16aedefc54d393e522ed9efe2..2f558eb4d2c31b6d4b8004c548472c1a98337329 100644 (file)
@@ -1956,25 +1956,23 @@ en:
       history_tooltip: View edits for this area
       history_disabled_tooltip: Zoom in to view edits for this area
       history_zoom_alert: You must zoom in to view edits for this area
-    osb:
-      Fixed Error: Fixed Error
-      Unresolved Error: Unresolved Error
-      Description: Description
-      Comment: Comment
-      Has been fixed: This error has been fixed already. However, it might take a couple of days before the map image is updated.
-      Comment/Close: Comment/Close
-      Nickname: Nickname
-      Add comment: Add comment
-      Mark as fixed: Mark as fixed
-      Cancel: Cancel
-      Create OpenStreetBug: Create OpenStreetBug
-      Create bug: Report a problem with the map
-      Bug description: Problem description
-      Create: Report problem
-      Permalink: Permalink
-      Login: Login
-      Details: Details
+    note:
+      closed: Closed Note
+      open: Open Note
+      details: Details
+      permalink: Permalink
+      description: Description
+      comment: Comment
+      render_warning: This error has been fixed already. However, it might take a couple of days before the map image is updated.
+      update: Update
+      nickname: Nickname
+      login: Login
+      add_comment: Add Comment
+      close: Close
+      cancel: Cancel
+      create: Create Note
+      create_title: Report a problem with the map
+      create_help1: Please drag the marker to the location of the problem
+      create_help2: and descripe it as accurate as possible
+      report: Report Problem
       edityourself: You can also edit the map directly your self
-      draghelp1: Please drag the marker to the location of the problem
-      draghelp2: and descripe it as accurate as possible
-
diff --git a/public/javascripts/notes.js b/public/javascripts/notes.js
new file mode 100644 (file)
index 0000000..4734985
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+       Dervied from the OpenStreetBugs client, which is available
+       under the following license.
+
+       This OpenStreetBugs client is free software: you can redistribute it
+       and/or modify it under the terms of the GNU Affero General Public License
+       as published by the Free Software Foundation, either version 3 of the
+       License, or (at your option) any later version.
+
+       This file is distributed in the hope that it will be useful, but
+       WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+       or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
+       License <http://www.gnu.org/licenses/> for more details.
+*/
+
+OpenLayers.Layer.Notes = new OpenLayers.Class(OpenLayers.Layer.Markers, {
+    /**
+     * The URL of the OpenStreetMap API.
+     *
+     * @var String
+     */
+    serverURL : "/api/0.6/",
+
+    /**
+     * Associative array (index: note ID) that is filled with the notes
+     * loaded in this layer.
+     *
+     * @var String
+     */
+    notes : { },
+
+    /**
+     * The username to be used to change or create notes on OpenStreetMap.
+     *
+     * @var String
+     */
+    username : "NoName",
+
+    /**
+     * The icon to be used for an open note.
+     *
+     * @var OpenLayers.Icon
+     */
+    iconOpen : new OpenLayers.Icon("/images/open_note_marker.png", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
+    
+    /**
+     * The icon to be used for a closed note.
+     *
+     * @var OpenLayers.Icon
+     */
+    iconClosed : new OpenLayers.Icon("/images/closed_note_marker.png", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
+
+    /**
+     * The projection of the coordinates sent by the OpenStreetMap API.
+     *
+     * @var OpenLayers.Projection
+     */
+    apiProjection : new OpenLayers.Projection("EPSG:4326"),
+
+    /**
+     * If this is set to true, the user may not commit comments or close notes.
+     *
+     * @var Boolean
+     */
+    readonly : false,
+    
+    /**
+     * When the layer is hidden, all open popups are stored in this
+     * array in order to be re-opened again when the layer is made
+     * visible again.
+     */
+    reopenPopups : [ ],
+    
+    /**
+     * The user name will be saved in a cookie if this isn’t set to false.
+     *
+     * @var Boolean
+     */
+    setCookie : true,
+
+    /**
+     * The lifetime of the user name cookie in days.
+     *
+     * @var Number
+     */
+    cookieLifetime : 1000,
+
+    /**
+     * The path where the cookie will be available on this server.
+     *
+     * @var String
+     */
+    cookiePath : null,
+
+    /**
+     * A URL to append lon=123&lat=123&zoom=123 for the Permalinks.
+     *
+     * @var String
+     */
+    permalinkURL : "http://www.openstreetmap.org/",
+
+    /**
+     * A CSS file to be included. Set to null if you don’t need this.
+     *
+     * @var String
+     */
+    theme : "/stylesheets/notes.css",
+
+    /**
+     * @param String name
+     */
+    initialize : function(name, options)
+    {
+       OpenLayers.Layer.Markers.prototype.initialize.apply(this, [ name, OpenLayers.Util.extend({ opacity: 0.7, projection: new OpenLayers.Projection("EPSG:4326") }, options) ]);
+       putAJAXMarker.layers.push(this);
+       this.events.addEventType("markerAdded");
+
+       this.events.register("visibilitychanged", this, this.updatePopupVisibility);
+       this.events.register("visibilitychanged", this, this.loadNotes);
+
+       var cookies = document.cookie.split(/;\s*/);
+       for(var i=0; i<cookies.length; i++)
+       {
+           var cookie = cookies[i].split("=");
+           if(cookie[0] == "osbUsername")
+           {
+               this.username = decodeURIComponent(cookie[1]);
+               break;
+           }
+       }
+
+       /* Copied from OpenLayers.Map */
+       if(this.theme) {
+            // check existing links for equivalent url
+            var addNode = true;
+            var nodes = document.getElementsByTagName('link');
+            for(var i=0, len=nodes.length; i<len; ++i) {
+                if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
+                                                   this.theme)) {
+                    addNode = false;
+                    break;
+                }
+            }
+            // only add a new node if one with an equivalent url hasn't already
+            // been added
+            if(addNode) {
+                var cssNode = document.createElement('link');
+                cssNode.setAttribute('rel', 'stylesheet');
+                cssNode.setAttribute('type', 'text/css');
+                cssNode.setAttribute('href', this.theme);
+                document.getElementsByTagName('head')[0].appendChild(cssNode);
+            }
+        }
+    },
+
+    /**
+     * Is automatically called when the layer is added to an
+     * OpenLayers.Map. Initialises the automatic note loading in the
+     * visible bounding box.
+     */
+    afterAdd : function()
+    {
+       var ret = OpenLayers.Layer.Markers.prototype.afterAdd.apply(this, arguments);
+
+       this.map.events.register("moveend", this, this.loadNotes);
+       this.loadNotes();
+
+       return ret;
+    },
+
+    /**
+     * At the moment the OpenStreetMap API responses to requests using
+     * JavaScript code. This way the Same Origin Policy can be worked
+     * around. Unfortunately, this makes communicating with the API a
+     * bit too asynchronous, at the moment there is no way to tell to
+     * which request the API actually responses.
+     *
+     * This method creates a new script HTML element that imports the
+     * API request URL. The API JavaScript response then executes the
+     * global functions provided below.
+     *
+     * @param String url The URL this.serverURL + url is requested.
+     */
+    apiRequest : function(url) {
+       var script = document.createElement("script");
+       script.type = "text/javascript";
+       script.src = this.serverURL + url + "&nocache="+(new Date()).getTime();
+       document.body.appendChild(script);
+    },
+    
+    /**
+     * Is automatically called when the visibility of the layer
+     * changes. When the layer is hidden, all visible popups are
+     * closed and their visibility is saved. When the layer is made
+     * visible again, these popups are re-opened.
+     */
+    updatePopupVisibility : function()
+    {
+       if(this.getVisibility())
+       {
+           for(var i=0; i<this.reopenPopups.length; i++)
+               this.reopenPopups[i].show();
+           this.reopenPopups = [ ];
+       }
+       else
+       {
+           for(var i=0; i<this.markers.length; i++)
+           {
+               if(this.markers[i].feature.popup && this.markers[i].feature.popup.visible())
+               {
+                   this.markers[i].feature.popup.hide();
+                   this.reopenPopups.push(this.markers[i].feature.popup);
+               }
+           }
+       }
+    },
+
+    /**
+     * Sets the user name to be used for interactions with OpenStreetMap.
+     */
+    setUserName : function(username)
+    {
+       if(this.username == username)
+           return;
+
+       this.username = username;
+
+       if(this.setCookie)
+       {
+           var cookie = "osbUsername="+encodeURIComponent(username);
+           if(this.cookieLifetime)
+               cookie += ";expires="+(new Date((new Date()).getTime() + this.cookieLifetime*86400000)).toGMTString();
+           if(this.cookiePath)
+               cookie += ";path="+this.cookiePath;
+           document.cookie = cookie;
+       }
+
+       for(var i=0; i<this.markers.length; i++)
+       {
+           if(!this.markers[i].feature.popup) continue;
+           var els = this.markers[i].feature.popup.contentDom.getElementsByTagName("input");
+           for(var j=0; j<els.length; j++)
+           {
+               if(els[j].className != "osbUsername") continue;
+               els[j].value = username;
+           }
+       }
+    },
+
+    /**
+     * Returns the currently set username or “NoName” if none is set.
+     */
+    getUserName : function()
+    {
+       if(this.username)
+           return this.username;
+       else
+           return "NoName";
+    },
+
+    /**
+     * Loads the notes in the current bounding box. Is automatically
+     * called by an event handler ("moveend" event) that is created in
+     * the afterAdd() method.
+     */
+    loadNotes : function()
+    {
+       if(!this.getVisibility())
+           return true;
+
+       var bounds = this.map.getExtent();
+       if(!bounds) return false;
+       bounds.transform(this.map.getProjectionObject(), this.apiProjection);
+
+       this.apiRequest("notes"
+                       + "?bbox="+this.round(bounds.left, 5)
+                        + ","+this.round(bounds.bottom, 5)
+                       + ","+this.round(bounds.right, 5)                       
+                       + ","+this.round(bounds.top, 5));
+    },
+
+    /**
+     * Rounds the given number to the given number of digits after the
+     * floating point.
+     *
+     * @param Number number
+     * @param Number digits
+     * @return Number
+     */
+    round : function(number, digits)
+    {
+       var factor = Math.pow(10, digits);
+       return Math.round(number*factor)/factor;
+    },
+
+    /**
+     * Adds an OpenLayers.Marker representing a note to the map. Is
+     * usually called by loadNotes().
+     *
+     * @param Number id The note ID
+     */
+    createMarker: function(id)
+    {
+       if(this.notes[id])
+       {
+           if(this.notes[id].popup && !this.notes[id].popup.visible())
+               this.setPopupContent(id);
+           if(this.notes[id].closed != putAJAXMarker.notes[id][2])
+               this.notes[id].destroy();
+           else
+               return;
+       }
+
+       var lonlat = putAJAXMarker.notes[id][0].clone().transform(this.apiProjection, this.map.getProjectionObject());
+       var comments = putAJAXMarker.notes[id][1];
+       var closed = putAJAXMarker.notes[id][2];
+       var feature = new OpenLayers.Feature(this, lonlat, { icon: (closed ? this.iconClosed : this.iconOpen).clone(), autoSize: true });
+       feature.popupClass = OpenLayers.Popup.FramedCloud.Notes;
+       feature.noteId = id;
+       feature.closed = closed;
+        
+       var marker = feature.createMarker();
+       marker.feature = feature;
+       marker.events.register("click", feature, this.markerClick);
+       //marker.events.register("mouseover", feature, this.markerMouseOver);
+       //marker.events.register("mouseout", feature, this.markerMouseOut);
+       this.addMarker(marker);
+        
+       this.notes[id] = feature;
+       this.events.triggerEvent("markerAdded");
+    },
+
+    /**
+     * Recreates the content of the popup of a marker.
+     *
+     * @param Number id The note ID
+     */
+    setPopupContent: function(id) {
+       if(!this.notes[id].popup)
+           return;
+
+       var el1,el2,el3;
+       var layer = this;
+        
+       var newContent = document.createElement("div");
+        
+       el1 = document.createElement("h3");
+       el1.appendChild(document.createTextNode(putAJAXMarker.notes[id][2] ? i18n("javascripts.note.closed") : i18n("javascripts.note.open")));
+
+       el1.appendChild(document.createTextNode(" ["));
+       el2 = document.createElement("a");
+       el2.href = "/browse/note/" + id;
+       el2.onclick = function(){ layer.map.setCenter(putAJAXMarker.notes[id][0].clone().transform(layer.apiProjection, layer.map.getProjectionObject()), 15); };
+       el2.appendChild(document.createTextNode(i18n("javascripts.note.details")));
+       el1.appendChild(el2);
+       el1.appendChild(document.createTextNode("]"));
+        
+       if(this.permalinkURL)
+       {
+           el1.appendChild(document.createTextNode(" ["));
+           el2 = document.createElement("a");
+           el2.href = this.permalinkURL + (this.permalinkURL.indexOf("?") == -1 ? "?" : "&") + "lon="+putAJAXMarker.notes[id][0].lon+"&lat="+putAJAXMarker.notes[id][0].lat+"&zoom=15";
+           el2.appendChild(document.createTextNode(i18n("javascripts.note.permalink")));
+           el1.appendChild(el2);
+           el1.appendChild(document.createTextNode("]"));
+       }
+       newContent.appendChild(el1);
+        
+       var containerDescription = document.createElement("div");
+       newContent.appendChild(containerDescription);
+        
+       var containerChange = document.createElement("div");
+       newContent.appendChild(containerChange);
+        
+       var displayDescription = function(){
+           containerDescription.style.display = "block";
+           containerChange.style.display = "none";
+           layer.notes[id].popup.updateSize();
+       };
+       var displayChange = function(){
+           containerDescription.style.display = "none";
+           containerChange.style.display = "block";
+           layer.notes[id].popup.updateSize();
+       };
+       displayDescription();
+        
+       el1 = document.createElement("dl");
+       for(var i=0; i<putAJAXMarker.notes[id][1].length; i++)
+       {
+           el2 = document.createElement("dt");
+           el2.className = (i == 0 ? "note-description" : "note-comment");
+           el2.appendChild(document.createTextNode(i == 0 ? i18n("javascripts.note.description") : i18n("javascripts.note.comment")));
+           el1.appendChild(el2);
+           el2 = document.createElement("dd");
+           el2.className = (i == 0 ? "note-description" : "note-comment");
+           el2.appendChild(document.createTextNode(putAJAXMarker.notes[id][1][i]));
+           el1.appendChild(el2);
+            if (i == 0) { el2 = document.createElement("br"); el1.appendChild(el2);};
+       }
+       containerDescription.appendChild(el1);
+
+       if(putAJAXMarker.notes[id][2])
+       {
+           el1 = document.createElement("p");
+           el1.className = "note-fixed";
+           el2 = document.createElement("em");
+           el2.appendChild(document.createTextNode(i18n("javascripts.note.render_warning")));
+           el1.appendChild(el2);
+           containerDescription.appendChild(el1);
+       }
+       else if(!this.readonly)
+       {
+           el1 = document.createElement("div");
+           el2 = document.createElement("input");
+           el2.setAttribute("type", "button");
+           el2.onclick = function(){ displayChange(); };
+           el2.value = i18n("javascripts.note.update");
+           el1.appendChild(el2);
+           containerDescription.appendChild(el1);
+            
+           var el_form = document.createElement("form");
+           el_form.onsubmit = function(){ if(inputComment.value.match(/^\s*$/)) return false; layer.submitComment(id, inputComment.value); layer.hidePopup(id); return false; };
+            
+           el1 = document.createElement("dl");
+           el2 = document.createElement("dt");
+           el2.appendChild(document.createTextNode(i18n("javascripts.note.nickname")));
+           el1.appendChild(el2);
+           el2 = document.createElement("dd");
+           var inputUsername = document.createElement("input");
+           var inputUsername = document.createElement("input");;
+           if (typeof loginName === 'undefined') {
+               inputUsername.value = this.username;
+           } else {
+               inputUsername.value = loginName;
+               inputUsername.setAttribute('disabled','true');
+           }
+           inputUsername.className = "osbUsername";
+           inputUsername.onkeyup = function(){ layer.setUserName(inputUsername.value); };
+           el2.appendChild(inputUsername);
+           el3 = document.createElement("a");
+           el3.setAttribute("href","login");
+           el3.className = "hide_if_logged_in";
+           el3.appendChild(document.createTextNode(i18n("javascripts.note.login")));
+           el2.appendChild(el3)
+           el1.appendChild(el2);                       
+            
+           el2 = document.createElement("dt");
+           el2.appendChild(document.createTextNode(i18n("javascripts.note.comment")));
+           el1.appendChild(el2);
+           el2 = document.createElement("dd");
+           var inputComment = document.createElement("textarea");
+           inputComment.setAttribute("cols",40);
+            inputComment.setAttribute("rows",3);
+           
+           el2.appendChild(inputComment);
+           el1.appendChild(el2);
+           
+           el_form.appendChild(el1);
+            
+           el1 = document.createElement("ul");
+           el1.className = "buttons";
+           el2 = document.createElement("li");
+           el3 = document.createElement("input");
+           el3.setAttribute("type", "button");
+            el3.onclick = function(){ this.form.onsubmit(); return false; };
+           el3.value = i18n("javascripts.note.add_comment");
+           el2.appendChild(el3);
+           el1.appendChild(el2);
+
+           el2 = document.createElement("li");
+           el3 = document.createElement("input");
+           el3.setAttribute("type", "button");
+           el3.onclick = function(){ this.form.onsubmit(); layer.closeNote(id); layer.notes[id].popup.hide(); return false; };
+           el3.value = i18n("javascripts.note.close");
+           el2.appendChild(el3);
+           el1.appendChild(el2);
+           el_form.appendChild(el1);
+           containerChange.appendChild(el_form);
+
+           el1 = document.createElement("div");
+           el2 = document.createElement("input");
+           el2.setAttribute("type", "button");
+           el2.onclick = function(){ displayDescription(); };
+           el2.value = i18n("javascripts.note.cancel");
+           el1.appendChild(el2);
+           containerChange.appendChild(el1);
+       }
+        
+       this.notes[id].popup.setContentHTML(newContent);
+    },
+
+    /**
+     * Creates a new note.
+     *
+     * @param OpenLayers.LonLat lonlat The coordinates in the API projection.
+     * @param String description
+     */
+    createNote: function(lonlat, description) {
+       this.apiRequest("note/create"
+                       + "?lat="+encodeURIComponent(lonlat.lat)
+                       + "&lon="+encodeURIComponent(lonlat.lon)
+                       + "&text="+encodeURIComponent(description)
+                       + "&name="+encodeURIComponent(this.getUserName())
+                       + "&format=js"
+                      );
+    },
+    
+    /**
+     * Adds a comment to a note.
+     *
+     * @param Number id
+     * @param String comment
+     */
+    submitComment: function(id, comment) {
+       this.apiRequest("note/"+encodeURIComponent(id)+"/comment"
+                       + "?text="+encodeURIComponent(comment)
+                       + "&name="+encodeURIComponent(this.getUserName())
+                       + "&format=js"
+                      );
+    },
+
+    /**
+     * Marks a note as fixed.
+     *
+     * @param Number id
+     */
+    closeNote: function(id) {
+       this.apiRequest("note/"+encodeURIComponent(id)+"/close"
+                       + "?format=js"
+                      );
+    },
+    
+    /**
+     * Removes the content of a marker popup (to reduce the amount of
+     * needed resources).
+     *
+     * @param Number id
+     */
+    resetPopupContent: function(id) {
+       if(!this.notes[id].popup)
+           return;
+        
+       this.notes[id].popup.setContentHTML(document.createElement("div"));
+    },
+    
+    /**
+     * Makes the popup of the given marker visible. Makes sure that
+     * the popup content is created if it does not exist yet.
+     *
+     * @param Number id
+     */
+    showPopup: function(id) {
+       var add = null;
+       if(!this.notes[id].popup)
+       {
+           add = this.notes[id].createPopup(true);
+           add.events.register("close", this, function(){ this.resetPopupContent(id); if(this.notes[id].noteClicked) this.notes[id].noteClicked = false; });
+       }
+       else if(this.notes[id].popup.visible())
+           return;
+        
+       this.setPopupContent(id);
+       if(add)
+           this.map.addPopup(add);
+       this.notes[id].popup.show();
+       this.notes[id].popup.updateSize();
+    },
+    
+    /**
+     * Hides the popup of the given marker.
+     *
+     * @param Number id
+     */
+    hidePopup: function(id) {
+       if(!this.notes[id].popup || !this.notes[id].popup.visible())
+           return;
+        
+       this.notes[id].popup.hide();
+       this.notes[id].popup.events.triggerEvent("close");
+    },
+    
+    /**
+     * Is run on the “click” event of a marker in the context of its
+     * OpenLayers.Feature. Toggles the visibility of the popup.
+     */
+    markerClick: function(e) {
+       var feature = this; // Context is the feature
+        
+       feature.noteClicked = !feature.noteClicked;
+       if(feature.noteClicked)
+           feature.layer.showPopup(feature.noteId);
+       else
+           feature.layer.hidePopup(feature.noteId);
+       OpenLayers.Event.stop(e);
+    },
+    
+    /**
+     * Is run on the “mouseover” event of a marker in the context of
+     * its OpenLayers.Feature. Makes the popup visible.
+     */
+    markerMouseOver: function(e) {
+       var feature = this; // Context is the feature
+        
+       feature.layer.showPopup(feature.noteId);
+       OpenLayers.Event.stop(e);
+    },
+    
+    /**
+     * Is run on the “mouseout” event of a marker in the context of
+     * its OpenLayers.Feature. Hides the popup (if it has not been
+     * clicked).
+     */
+    markerMouseOut: function(e) {
+       var feature = this; // Context is the feature
+        
+       if(!feature.noteClicked)
+           feature.layer.hidePopup(feature.noteId);
+       OpenLayers.Event.stop(e);
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.Notes"
+});
+
+/**
+ * An OpenLayers control to create new notes on mouse clicks on the
+ * map. Add an instance of this to your map using the
+ * OpenLayers.Map.addControl() method and activate() it.
+ */
+OpenLayers.Control.Notes = new OpenLayers.Class(OpenLayers.Control, {
+    title : null, // See below because of translation call
+
+    /**
+     * The icon to be used for the temporary markers that the “create
+     * note” popup belongs to..
+     *
+     * @var OpenLayers.Icon
+     */
+    icon : new OpenLayers.Icon("/images/icon_note_add.png", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
+
+    /**
+     * An instance of the Notes layer that this control shall be
+     * connected to. Is set in the constructor.
+     *
+     * @var OpenLayers.Layer.Notes
+     */
+    noteLayer : null,
+
+    /**
+     * @param OpenLayers.Layer.Notes noteLayer The Notes layer that this control will be connected to.
+     */
+    initialize: function(noteLayer, options) {
+       this.noteLayer = noteLayer;
+        
+       this.title = i18n("javascripts.note.create");
+        
+       OpenLayers.Control.prototype.initialize.apply(this, [ options ]);
+        
+       this.events.register("activate", this, function() {
+           if(!this.noteLayer.getVisibility())
+               this.noteLayer.setVisibility(true);
+       });
+        
+       this.noteLayer.events.register("visibilitychanged", this, function() {
+           if(this.active && !this.noteLayer.getVisibility())
+               this.noteLayer.setVisibility(true);
+       });
+    },
+    
+    destroy: function() {
+       if (this.handler)
+           this.handler.destroy();
+       this.handler = null;
+        
+       OpenLayers.Control.prototype.destroy.apply(this, arguments);
+    },
+    
+    draw: function() {
+       this.handler = new OpenLayers.Handler.Click(this, {'click': this.click}, { 'single': true, 'double': false, 'pixelTolerance': 0, 'stopSingle': false, 'stopDouble': false });
+    },
+    
+    /**
+     * Map clicking event handler. Adds a temporary marker with a
+     * popup to the map, the popup contains the form to add a note.
+     */
+    click: function(e) {
+       var lonlat = this.map.getLonLatFromViewPortPx(e.xy);
+       this.addTemporaryMarker(lonlat);
+    },
+    
+    addTemporaryMarker: function(lonlat) {
+       if(!this.map) return true;
+       deactivateControl();
+        
+       var control = this;
+       var lonlatApi = lonlat.clone().transform(this.map.getProjectionObject(), this.noteLayer.apiProjection);
+       var feature = new OpenLayers.Feature(this.noteLayer, lonlat, { icon: this.icon.clone(), autoSize: true });
+       feature.popupClass = OpenLayers.Popup.FramedCloud.Notes;
+       var marker = feature.createMarker();
+       marker.feature = feature;
+       this.noteLayer.addMarker(marker);
+        
+        
+       /** Implement a drag and drop for markers */
+       /* TODO: veryfy that the scoping of variables works correctly everywhere */             
+       var dragging = false;
+       var dragFunction = function(e) {
+           map.events.unregister("mouseup",map,dragFunction);
+           lonlat = map.getLonLatFromViewPortPx(e.xy);
+           lonlatApi = lonlat.clone().transform(map.getProjectionObject(), map.noteLayer.apiProjection);
+           marker.moveTo(map.getLayerPxFromViewPortPx(e.xy));
+           marker.popup.moveTo(map.getLayerPxFromViewPortPx(e.xy));                    
+           marker.popup.updateRelativePosition();
+           dragging = false;
+           return false;
+       };
+        
+       marker.events.register("mouseover", this,
+                              function(){ document.getElementById("OpenLayers.Map_18_OpenLayers_Container").style.cursor = "move"; });
+       marker.events.register("mouseout", this,
+                              function(){ if (!dragging) {document.getElementById("OpenLayers.Map_18_OpenLayers_Container").style.cursor = "default"; }});
+       marker.events.register("mousedown", this,
+                              function() { dragging = true; map.events.register("mouseup",map, dragFunction); return false;});
+       
+        
+       var newContent = document.createElement("div");
+       var el1,el2,el3;
+       el1 = document.createElement("h3");
+       el1.appendChild(document.createTextNode(i18n("javascripts.note.create_title")));
+       newContent.appendChild(el1);
+       newContent.appendChild(document.createTextNode(i18n("javascripts.note.create_help1")));
+       newContent.appendChild(document.createElement("br"));
+       newContent.appendChild(document.createTextNode(i18n("javascripts.note.create_help2")));
+       newContent.appendChild(document.createElement("br"));
+       newContent.appendChild(document.createElement("br"));
+        
+       var el_form = document.createElement("form");
+        
+       el1 = document.createElement("dl");
+       el2 = document.createElement("dt");
+       el2.appendChild(document.createTextNode(i18n("javascripts.note.nickname")));
+       el1.appendChild(el2);
+       el2 = document.createElement("dd");
+       var inputUsername = document.createElement("input");;
+       if (typeof loginName === 'undefined') {
+           inputUsername.value = this.noteLayer.username;
+       } else {
+           inputUsername.value = loginName;
+           inputUsername.setAttribute('disabled','true');
+       }               
+       inputUsername.className = "osbUsername";
+       
+       inputUsername.onkeyup = function(){ control.noteLayer.setUserName(inputUsername.value); };
+       el2.appendChild(inputUsername);
+       el3 = document.createElement("a");
+       el3.setAttribute("href","login");
+       el3.className = "hide_if_logged_in";
+       el3.appendChild(document.createTextNode(i18n("javascripts.note.login")));
+       el2.appendChild(el3);
+       el1.appendChild(el2);
+       el2 = document.createElement("br");
+        el1.appendChild(el2);
+        
+       el2 = document.createElement("dt");
+       el2.appendChild(document.createTextNode(i18n("javascripts.note.description")));
+       el1.appendChild(el2);
+       el2 = document.createElement("dd");
+       var inputDescription = document.createElement("textarea");
+       inputDescription.setAttribute("cols",40);
+       inputDescription.setAttribute("rows",3);
+       el2.appendChild(inputDescription);
+       el1.appendChild(el2);
+       el_form.appendChild(el1);
+        
+       el1 = document.createElement("div");
+       el2 = document.createElement("input");
+       el2.setAttribute("type", "button");
+       el2.value = i18n("javascripts.note.report");
+        el2.onclick = function() { control.noteLayer.createNote(lonlatApi, inputDescription.value); marker.feature = null; feature.destroy(); return false; };
+       el1.appendChild(el2);
+       el2 = document.createElement("input");
+       el2.setAttribute("type", "button");
+       el2.value = i18n("javascripts.note.cancel");
+       el2.onclick = function(){ feature.destroy(); };
+       el1.appendChild(el2);
+       el_form.appendChild(el1);
+       newContent.appendChild(el_form);
+        
+       el2 = document.createElement("hr");
+       el1.appendChild(el2);
+       el2 = document.createElement("a");
+       el2.setAttribute("href","edit");
+       el2.appendChild(document.createTextNode(i18n("javascripts.note.edityourself")));
+       el1.appendChild(el2);
+        
+       feature.data.popupContentHTML = newContent;
+       var popup = feature.createPopup(true);
+       popup.events.register("close", this, function(){ feature.destroy(); });
+       this.map.addPopup(popup);
+       popup.updateSize();
+       marker.popup = popup;
+    },
+    
+    CLASS_NAME: "OpenLayers.Control.Notes"
+});
+
+
+/**
+ * This class changes the usual OpenLayers.Popup.FramedCloud class by
+ * using a DOM element instead of an innerHTML string as content for
+ * the popup.  This is necessary for creating valid onclick handlers
+ * that still work with multiple Notes layer objects.
+ */
+OpenLayers.Popup.FramedCloud.Notes = new OpenLayers.Class(OpenLayers.Popup.FramedCloud, {
+    contentDom : null,
+    autoSize : true,
+    
+    /**
+     * See OpenLayers.Popup.FramedCloud.initialize() for
+     * parameters. As fourth parameter, pass a DOM node instead of a
+     * string.
+     */
+    initialize: function() {
+       this.displayClass = this.displayClass + " " + this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
+        
+       var args = new Array(arguments.length);
+       for(var i=0; i<arguments.length; i++)
+           args[i] = arguments[i];
+        
+       // Unset original contentHTML parameter
+       args[3] = null;
+        
+       var closeCallback = arguments[6];
+        
+       // Add close event trigger to the closeBoxCallback parameter
+       args[6] = function(e){ if(closeCallback) closeCallback(); else this.hide(); OpenLayers.Event.stop(e); this.events.triggerEvent("close"); };
+        
+       OpenLayers.Popup.FramedCloud.prototype.initialize.apply(this, args);
+        
+       this.events.addEventType("close");
+        
+       this.setContentHTML(arguments[3]);
+    },
+    
+    /**
+     * Like OpenLayers.Popup.FramedCloud.setContentHTML(), but takes a
+     * DOM element as parameter.
+     */
+    setContentHTML: function(contentDom) {
+       if(contentDom != null)
+           this.contentDom = contentDom;
+        
+       if(this.contentDiv == null || this.contentDom == null || this.contentDom == this.contentDiv.firstChild)
+           return;
+        
+       while(this.contentDiv.firstChild)
+           this.contentDiv.removeChild(this.contentDiv.firstChild);
+        
+       this.contentDiv.appendChild(this.contentDom);
+        
+       // Copied from OpenLayers.Popup.setContentHTML():
+       if(this.autoSize)
+       {
+           this.registerImageListeners();
+           this.updateSize();
+       }
+    },
+    
+    destroy: function() {
+       this.contentDom = null;
+       OpenLayers.Popup.FramedCloud.prototype.destroy.apply(this, arguments);
+    },
+    
+    CLASS_NAME: "OpenLayers.Popup.FramedCloud.Notes"
+});
+
+
+/**
+ * This global function is executed by the OpenStreetMap API getBugs script.
+ *
+ * Each Notes layer adds itself to the putAJAXMarker.layer array. The
+ * putAJAXMarker() function executes the createMarker() method on each
+ * layer in that array each time it is called. This has the
+ * side-effect that notes displayed in one map on a page are already
+ * loaded on the other map as well.
+ */
+function putAJAXMarker(id, lon, lat, text, closed)
+{
+    var comments = text.split(/<hr \/>/);
+    for(var i=0; i<comments.length; i++)
+       comments[i] = comments[i].replace(/&quot;/g, "\"").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
+    putAJAXMarker.notes[id] = [
+       new OpenLayers.LonLat(lon, lat),
+       comments,
+       closed
+    ];
+    for(var i=0; i<putAJAXMarker.layers.length; i++)
+       putAJAXMarker.layers[i].createMarker(id);
+}
+
+/**
+ * This global function is executed by the OpenStreetMap API. The
+ * “create note”, “comment” and “close note” scripts execute it to give
+ * information about their success.
+ *
+ * In case of success, this function is called without a parameter, in
+ * case of an error, the error message is passed. This is lousy
+ * workaround to make it any functional at all, the OSB API is likely
+ * to be extended later (then it will provide additional information
+ * such as the ID of a created note and similar).
+ */
+function osbResponse(error)
+{
+    if(error)
+       alert("Error: "+error);
+    
+    for(var i=0; i<putAJAXMarker.layers.length; i++)
+       putAJAXMarker.layers[i].loadNotes();
+}
+
+putAJAXMarker.layers = [ ];
+putAJAXMarker.notes = { };
+
+function deactivateControl() { 
+    map.noteControl.deactivate(); 
+    document.getElementById("OpenLayers.Map_18_OpenLayers_Container").style.cursor = "default"; 
+}
diff --git a/public/javascripts/openstreetbugs.js b/public/javascripts/openstreetbugs.js
deleted file mode 100644 (file)
index 323b044..0000000
+++ /dev/null
@@ -1,989 +0,0 @@
-/*
-       This OpenStreetBugs client is free software: you can redistribute it
-       and/or modify it under the terms of the GNU Affero General Public License
-       as published by the Free Software Foundation, either version 3 of the
-       License, or (at your option) any later version.
-
-       This file is distributed in the hope that it will be useful, but
-       WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-       or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
-       License <http://www.gnu.org/licenses/> for more details.
-*/
-
-/**
- * A fully functional OpenStreetBugs layer. See http://openstreetbugs.schokokeks.org/.
- * Even though the OpenStreetBugs API originally does not intend this, you can create multiple instances of this Layer and add them to different maps (or to one single map for whatever crazy reason) without problems.
-*/
-
-/** This version has been adapted from the original javascript library to fit the openstreetmap rails_port implementation */
-
-OpenLayers.Layer.OpenStreetBugs = new OpenLayers.Class(OpenLayers.Layer.Markers, {
-       /**
-        * The URL of the OpenStreetBugs API.
-        * @var String
-       */
-       serverURL : "/api/0.6/",
-
-       /**
-        * Associative array (index: bug ID) that is filled with the bugs loaded in this layer
-        * @var String
-       */
-       bugs : { },
-
-       /**
-        * The username to be used to change or create bugs on OpenStreetBugs
-        * @var String
-       */
-       username : "NoName",
-
-       /**
-        * The icon to be used for an open bug
-        * @var OpenLayers.Icon
-       */
-       iconOpen : new OpenLayers.Icon("/images/open_bug_marker.png", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
-
-       /**
-        * The icon to be used for a closed bug
-        * @var OpenLayers.Icon
-       */
-       iconClosed : new OpenLayers.Icon("/images/closed_bug_marker.png", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
-
-       /**
-        * The projection of the coordinates sent by the OpenStreetBugs API.
-        * @var OpenLayers.Projection
-       */
-       apiProjection : new OpenLayers.Projection("EPSG:4326"),
-
-       /**
-        * If this is set to true, the user may not commit comments or close bugs.
-        * @var Boolean
-       */
-       readonly : false,
-
-       /**
-        * When the layer is hidden, all open popups are stored in this array in order to be re-opened again when the layer is made visible again.
-       */
-       reopenPopups : [ ],
-
-       /**
-        * The user name will be saved in a cookie if this isn’t set to false.
-        * @var Boolean
-       */
-       setCookie : true,
-
-       /**
-        * The lifetime of the user name cookie in days.
-        * @var Number
-       */
-       cookieLifetime : 1000,
-
-       /**
-        * The path where the cookie will be available on this server.
-        * @var String
-       */
-       cookiePath : null,
-
-       /**
-        * A URL to append lon=123&lat=123&zoom=123 for the Permalinks.
-        * @var String
-       */
-       permalinkURL : "http://www.openstreetmap.org/",
-
-       /**
-        * A CSS file to be included. Set to null if you don’t need this.
-        * @var String
-       */
-       theme : "http://osm.cdauth.de/map/openstreetbugs.css",
-
-       /**
-        * @param String name
-       */
-       initialize : function(name, options)
-       {
-               OpenLayers.Layer.Markers.prototype.initialize.apply(this, [ name, OpenLayers.Util.extend({ opacity: 0.7, projection: new OpenLayers.Projection("EPSG:4326") }, options) ]);
-               putAJAXMarker.layers.push(this);
-               this.events.addEventType("markerAdded");
-
-               this.events.register("visibilitychanged", this, this.updatePopupVisibility);
-               this.events.register("visibilitychanged", this, this.loadBugs);
-
-               var cookies = document.cookie.split(/;\s*/);
-               for(var i=0; i<cookies.length; i++)
-               {
-                       var cookie = cookies[i].split("=");
-                       if(cookie[0] == "osbUsername")
-                       {
-                               this.username = decodeURIComponent(cookie[1]);
-                               break;
-                       }
-               }
-
-               /* Copied from OpenLayers.Map */
-               if(this.theme) {
-            // check existing links for equivalent url
-            var addNode = true;
-            var nodes = document.getElementsByTagName('link');
-            for(var i=0, len=nodes.length; i<len; ++i) {
-                if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
-                                                   this.theme)) {
-                    addNode = false;
-                    break;
-                }
-            }
-            // only add a new node if one with an equivalent url hasn't already
-            // been added
-            if(addNode) {
-                var cssNode = document.createElement('link');
-                cssNode.setAttribute('rel', 'stylesheet');
-                cssNode.setAttribute('type', 'text/css');
-                cssNode.setAttribute('href', this.theme);
-                document.getElementsByTagName('head')[0].appendChild(cssNode);
-            }
-        }
-       },
-
-       /**
-        * Is automatically called when the layer is added to an OpenLayers.Map. Initialises the automatic bug loading in the visible bounding box.
-       */
-       afterAdd : function()
-       {
-               var ret = OpenLayers.Layer.Markers.prototype.afterAdd.apply(this, arguments);
-
-               this.map.events.register("moveend", this, this.loadBugs);
-               this.loadBugs();
-
-               return ret;
-       },
-
-       /**
-        * At the moment the OSB API responses to requests using JavaScript code. This way the Same Origin Policy can be worked around. Unfortunately, this makes communicating with the API a bit too asynchronous, at the moment there is no way to tell to which request the API actually responses.
-        * This method creates a new script HTML element that imports the API request URL. The API JavaScript response then executes the global functions provided below.
-        * @param String url The URL this.serverURL + url is requested.
-       */
-       apiRequest : function(url) {
-               var script = document.createElement("script");
-               script.type = "text/javascript";
-               script.src = this.serverURL + url + "&nocache="+(new Date()).getTime();
-               document.body.appendChild(script);
-       },
-
-       /**
-        * Is automatically called when the visibility of the layer changes. When the layer is hidden, all visible popups
-        * are closed and their visibility is saved. When the layer is made visible again, these popups are re-opened.
-       */
-       updatePopupVisibility : function()
-       {
-               if(this.getVisibility())
-               {
-                       for(var i=0; i<this.reopenPopups.length; i++)
-                               this.reopenPopups[i].show();
-                       this.reopenPopups = [ ];
-               }
-               else
-               {
-                       for(var i=0; i<this.markers.length; i++)
-                       {
-                               if(this.markers[i].feature.popup && this.markers[i].feature.popup.visible())
-                               {
-                                       this.markers[i].feature.popup.hide();
-                                       this.reopenPopups.push(this.markers[i].feature.popup);
-                               }
-                       }
-               }
-       },
-
-       /**
-        * Sets the user name to be used for interactions with OpenStreetBugs.
-       */
-       setUserName : function(username)
-       {
-               if(this.username == username)
-                       return;
-
-               this.username = username;
-
-               if(this.setCookie)
-               {
-                       var cookie = "osbUsername="+encodeURIComponent(username);
-                       if(this.cookieLifetime)
-                               cookie += ";expires="+(new Date((new Date()).getTime() + this.cookieLifetime*86400000)).toGMTString();
-                       if(this.cookiePath)
-                               cookie += ";path="+this.cookiePath;
-                       document.cookie = cookie;
-               }
-
-               for(var i=0; i<this.markers.length; i++)
-               {
-                       if(!this.markers[i].feature.popup) continue;
-                       var els = this.markers[i].feature.popup.contentDom.getElementsByTagName("input");
-                       for(var j=0; j<els.length; j++)
-                       {
-                               if(els[j].className != "osbUsername") continue;
-                               els[j].value = username;
-                       }
-               }
-       },
-
-       /**
-        * Returns the currently set username or “NoName” if none is set.
-       */
-
-       getUserName : function()
-       {
-               if(this.username)
-                       return this.username;
-               else
-                       return "NoName";
-       },
-
-       /**
-        * Loads the bugs in the current bounding box. Is automatically called by an event handler ("moveend" event) that is created in the afterAdd() method.
-       */
-       loadBugs : function()
-       {
-               if(!this.getVisibility())
-                       return true;
-
-               var bounds = this.map.getExtent();
-               if(!bounds) return false;
-               bounds.transform(this.map.getProjectionObject(), this.apiProjection);
-
-               this.apiRequest("notes"
-                       + "?bbox="+this.round(bounds.left, 5)
-            + ","+this.round(bounds.bottom, 5)
-                   + ","+this.round(bounds.right, 5)                   
-                       + ","+this.round(bounds.top, 5));
-       },
-
-       /**
-        * Rounds the given number to the given number of digits after the floating point.
-        * @param Number number
-        * @param Number digits
-        * @return Number
-       */
-       round : function(number, digits)
-       {
-               var factor = Math.pow(10, digits);
-               return Math.round(number*factor)/factor;
-       },
-
-       /**
-        * Adds an OpenLayers.Marker representing a bug to the map. Is usually called by loadBugs().
-        * @param Number id The bug ID
-       */
-       createMarker: function(id)
-       {
-               if(this.bugs[id])
-               {
-                       if(this.bugs[id].popup && !this.bugs[id].popup.visible())
-                               this.setPopupContent(id);
-                       if(this.bugs[id].closed != putAJAXMarker.bugs[id][2])
-                               this.bugs[id].destroy();
-                       else
-                               return;
-               }
-
-               var lonlat = putAJAXMarker.bugs[id][0].clone().transform(this.apiProjection, this.map.getProjectionObject());
-               var comments = putAJAXMarker.bugs[id][1];
-               var closed = putAJAXMarker.bugs[id][2];
-               var feature = new OpenLayers.Feature(this, lonlat, { icon: (closed ? this.iconClosed : this.iconOpen).clone(), autoSize: true });
-               feature.popupClass = OpenLayers.Popup.FramedCloud.OpenStreetBugs;
-               feature.osbId = id;
-               feature.closed = closed;
-
-               var marker = feature.createMarker();
-               marker.feature = feature;
-               marker.events.register("click", feature, this.markerClick);
-               //marker.events.register("mouseover", feature, this.markerMouseOver);
-               //marker.events.register("mouseout", feature, this.markerMouseOut);
-               this.addMarker(marker);
-
-               this.bugs[id] = feature;
-               this.events.triggerEvent("markerAdded");
-       },
-
-       /**
-        * Recreates the content of the popup of a marker.
-        * @param Number id The bug ID
-       */
-
-       setPopupContent: function(id) {
-               if(!this.bugs[id].popup)
-                       return;
-
-               var el1,el2,el3;
-               var layer = this;
-
-               var newContent = document.createElement("div");
-
-               el1 = document.createElement("h3");
-               el1.appendChild(document.createTextNode(putAJAXMarker.bugs[id][2] ? i18n("javascripts.osb.Fixed Error") : i18n("javascripts.osb.Unresolved Error")));
-
-               el1.appendChild(document.createTextNode(" ["));
-               el2 = document.createElement("a");
-               el2.href = "/browse/note/" + id;
-               el2.onclick = function(){ layer.map.setCenter(putAJAXMarker.bugs[id][0].clone().transform(layer.apiProjection, layer.map.getProjectionObject()), 15); };
-               el2.appendChild(document.createTextNode(i18n("javascripts.osb.Details")));
-               el1.appendChild(el2);
-               el1.appendChild(document.createTextNode("]"));
-
-               if(this.permalinkURL)
-               {
-                       el1.appendChild(document.createTextNode(" ["));
-                       el2 = document.createElement("a");
-                       el2.href = this.permalinkURL + (this.permalinkURL.indexOf("?") == -1 ? "?" : "&") + "lon="+putAJAXMarker.bugs[id][0].lon+"&lat="+putAJAXMarker.bugs[id][0].lat+"&zoom=15";
-                       el2.appendChild(document.createTextNode(i18n("javascripts.osb.Permalink")));
-                       el1.appendChild(el2);
-                       el1.appendChild(document.createTextNode("]"));
-               }
-               newContent.appendChild(el1);
-
-               var containerDescription = document.createElement("div");
-               newContent.appendChild(containerDescription);
-
-               var containerChange = document.createElement("div");
-               newContent.appendChild(containerChange);
-
-               var displayDescription = function(){
-                       containerDescription.style.display = "block";
-                       containerChange.style.display = "none";
-                       layer.bugs[id].popup.updateSize();
-               };
-               var displayChange = function(){
-                       containerDescription.style.display = "none";
-                       containerChange.style.display = "block";
-                       layer.bugs[id].popup.updateSize();
-               };
-               displayDescription();
-
-               el1 = document.createElement("dl");
-               for(var i=0; i<putAJAXMarker.bugs[id][1].length; i++)
-               {
-                       el2 = document.createElement("dt");
-                       el2.className = (i == 0 ? "osb-description" : "osb-comment");
-                       el2.appendChild(document.createTextNode(i == 0 ? i18n("javascripts.osb.Description") : i18n("javascripts.osb.Comment")));
-                       el1.appendChild(el2);
-                       el2 = document.createElement("dd");
-                       el2.className = (i == 0 ? "osb-description" : "osb-comment");
-                       el2.appendChild(document.createTextNode(putAJAXMarker.bugs[id][1][i]));
-                       el1.appendChild(el2);
-            if (i == 0) { el2 = document.createElement("br"); el1.appendChild(el2);};
-               }
-               containerDescription.appendChild(el1);
-
-               if(putAJAXMarker.bugs[id][2])
-               {
-                       el1 = document.createElement("p");
-                       el1.className = "osb-fixed";
-                       el2 = document.createElement("em");
-                       el2.appendChild(document.createTextNode(i18n("javascripts.osb.Has been fixed")));
-                       el1.appendChild(el2);
-                       containerDescription.appendChild(el1);
-               }
-               else if(!this.readonly)
-               {
-                       el1 = document.createElement("div");
-                       el2 = document.createElement("input");
-                       el2.setAttribute("type", "button");
-                       el2.onclick = function(){ displayChange(); };
-                       el2.value = i18n("javascripts.osb.Comment/Close");
-                       el1.appendChild(el2);
-                       containerDescription.appendChild(el1);
-
-                       var el_form = document.createElement("form");
-                       el_form.onsubmit = function(){ if(inputComment.value.match(/^\s*$/)) return false; layer.submitComment(id, inputComment.value); layer.hidePopup(id); return false; };
-
-                       el1 = document.createElement("dl");
-                       el2 = document.createElement("dt");
-                       el2.appendChild(document.createTextNode(i18n("javascripts.osb.Nickname")));
-                       el1.appendChild(el2);
-                       el2 = document.createElement("dd");
-                       var inputUsername = document.createElement("input");
-                       var inputUsername = document.createElement("input");;
-                       if (typeof loginName === 'undefined') {
-                               inputUsername.value = this.username;
-                       } else {
-                               inputUsername.value = loginName;
-                               inputUsername.setAttribute('disabled','true');
-                       }
-                       inputUsername.className = "osbUsername";
-                       inputUsername.onkeyup = function(){ layer.setUserName(inputUsername.value); };
-                       el2.appendChild(inputUsername);
-                       el3 = document.createElement("a");
-                       el3.setAttribute("href","login");
-                       el3.className = "hide_if_logged_in";
-                       el3.appendChild(document.createTextNode(i18n("javascripts.osb.Login")));
-                       el2.appendChild(el3)
-                       el1.appendChild(el2);                   
-
-                       el2 = document.createElement("dt");
-                       el2.appendChild(document.createTextNode(i18n("javascripts.osb.Comment")));
-                       el1.appendChild(el2);
-                       el2 = document.createElement("dd");
-                       var inputComment = document.createElement("textarea");
-                       inputComment.setAttribute("cols",40);
-            inputComment.setAttribute("rows",3);
-       
-                       el2.appendChild(inputComment);
-                       el1.appendChild(el2);
-                       
-                       el_form.appendChild(el1);
-
-                       el1 = document.createElement("ul");
-                       el1.className = "buttons";
-                       el2 = document.createElement("li");
-                       el3 = document.createElement("input");
-                       el3.setAttribute("type", "button");
-            el3.onclick = function(){ this.form.onsubmit(); return false; };
-                       el3.value = i18n("javascripts.osb.Add comment");
-                       el2.appendChild(el3);
-                       el1.appendChild(el2);
-
-                       el2 = document.createElement("li");
-                       el3 = document.createElement("input");
-                       el3.setAttribute("type", "button");
-                       el3.onclick = function(){ this.form.onsubmit(); layer.closeBug(id); layer.bugs[id].popup.hide(); return false; };
-                       el3.value = i18n("javascripts.osb.Mark as fixed");
-                       el2.appendChild(el3);
-                       el1.appendChild(el2);
-                       el_form.appendChild(el1);
-                       containerChange.appendChild(el_form);
-
-                       el1 = document.createElement("div");
-                       el2 = document.createElement("input");
-                       el2.setAttribute("type", "button");
-                       el2.onclick = function(){ displayDescription(); };
-                       el2.value = i18n("javascripts.osb.Cancel");
-                       el1.appendChild(el2);
-                       containerChange.appendChild(el1);
-               }
-
-               this.bugs[id].popup.setContentHTML(newContent);
-       },
-
-       /**
-        * Creates a new bug.
-        * @param OpenLayers.LonLat lonlat The coordinates in the API projection.
-        * @param String description
-       */
-       createBug: function(lonlat, description) {
-               this.apiRequest("note/create"
-                       + "?lat="+encodeURIComponent(lonlat.lat)
-                       + "&lon="+encodeURIComponent(lonlat.lon)
-                       + "&text="+encodeURIComponent(description)
-                       + "&name="+encodeURIComponent(this.getUserName())
-                       + "&format=js"
-               );
-       },
-
-       /**
-        * Adds a comment to a bug.
-        * @param Number id
-        * @param String comment
-       */
-       submitComment: function(id, comment) {
-               this.apiRequest("note/"+encodeURIComponent(id)+"/comment"
-                       + "?text="+encodeURIComponent(comment)
-                       + "&name="+encodeURIComponent(this.getUserName())
-                       + "&format=js"
-               );
-       },
-
-       /**
-        * Marks a bug as fixed.
-        * @param Number id
-       */
-       closeBug: function(id) {
-               this.apiRequest("note/"+encodeURIComponent(id)+"/close"
-                       + "?format=js"
-               );
-       },
-
-       /**
-        * Removes the content of a marker popup (to reduce the amount of needed resources).
-        * @param Number id
-       */
-       resetPopupContent: function(id) {
-               if(!this.bugs[id].popup)
-                       return;
-
-               this.bugs[id].popup.setContentHTML(document.createElement("div"));
-       },
-
-       /**
-        * Makes the popup of the given marker visible. Makes sure that the popup content is created if it does not exist yet.
-        * @param Number id
-       */
-       showPopup: function(id) {
-               var add = null;
-               if(!this.bugs[id].popup)
-               {
-                       add = this.bugs[id].createPopup(true);
-                       add.events.register("close", this, function(){ this.resetPopupContent(id); if(this.bugs[id].osbClicked) this.bugs[id].osbClicked = false; });
-               }
-               else if(this.bugs[id].popup.visible())
-                       return;
-
-               this.setPopupContent(id);
-               if(add)
-                       this.map.addPopup(add);
-               this.bugs[id].popup.show();
-               this.bugs[id].popup.updateSize();
-       },
-
-       /**
-        * Hides the popup of the given marker.
-        * @param Number id
-       */
-       hidePopup: function(id) {
-               if(!this.bugs[id].popup || !this.bugs[id].popup.visible())
-                       return;
-
-               this.bugs[id].popup.hide();
-               this.bugs[id].popup.events.triggerEvent("close");
-       },
-
-       /**
-        * Is run on the “click” event of a marker in the context of its OpenLayers.Feature. Toggles the visibility of the popup.
-       */
-       markerClick: function(e) {
-               var feature = this; // Context is the feature
-
-               feature.osbClicked = !feature.osbClicked;
-               if(feature.osbClicked)
-                       feature.layer.showPopup(feature.osbId);
-               else
-                       feature.layer.hidePopup(feature.osbId);
-               OpenLayers.Event.stop(e);
-       },
-
-       /**
-        * Is run on the “mouseover” event of a marker in the context of its OpenLayers.Feature. Makes the popup visible.
-       */
-       markerMouseOver: function(e) {
-               var feature = this; // Context is the feature
-
-               feature.layer.showPopup(feature.osbId);
-               OpenLayers.Event.stop(e);
-       },
-
-       /**
-        * Is run on the “mouseout” event of a marker in the context of its OpenLayers.Feature. Hides the popup (if it has not been clicked).
-       */
-       markerMouseOut: function(e) {
-               var feature = this; // Context is the feature
-
-               if(!feature.osbClicked)
-                       feature.layer.hidePopup(feature.osbId);
-               OpenLayers.Event.stop(e);
-       },
-
-       CLASS_NAME: "OpenLayers.Layer.OpenStreetBugs"
-});
-
-/**
- * An OpenLayers control to create new bugs on mouse clicks on the map. Add an instance of this to your map using
- * the OpenLayers.Map.addControl() method and activate() it.
-*/
-
-OpenLayers.Control.OpenStreetBugs = new OpenLayers.Class(OpenLayers.Control, {
-       title : null, // See below because of translation call
-
-       /**
-        * The icon to be used for the temporary markers that the “create bug” popup belongs to.
-        * @var OpenLayers.Icon
-       */
-       icon : new OpenLayers.Icon("/images/icon_error_add.png", new OpenLayers.Size(22, 22), new OpenLayers.Pixel(-11, -11)),
-
-       /**
-        * An instance of the OpenStreetBugs layer that this control shall be connected to. Is set in the constructor.
-        * @var OpenLayers.Layer.OpenStreetBugs
-       */
-       osbLayer : null,
-
-       /**
-        * @param OpenLayers.Layer.OpenStreetBugs osbLayer The OpenStreetBugs layer that this control will be connected to.
-       */
-       initialize: function(osbLayer, options) {
-               this.osbLayer = osbLayer;
-
-               this.title = i18n("javascripts.osb.Create OpenStreetBug");
-
-               OpenLayers.Control.prototype.initialize.apply(this, [ options ]);
-
-               this.events.register("activate", this, function() {
-                       if(!this.osbLayer.getVisibility())
-                               this.osbLayer.setVisibility(true);
-               });
-
-               this.osbLayer.events.register("visibilitychanged", this, function() {
-                       if(this.active && !this.osbLayer.getVisibility())
-                               this.osbLayer.setVisibility(true);
-               });
-       },
-
-       destroy: function() {
-               if (this.handler)
-                       this.handler.destroy();
-               this.handler = null;
-
-               OpenLayers.Control.prototype.destroy.apply(this, arguments);
-       },
-
-       draw: function() {
-               this.handler = new OpenLayers.Handler.Click(this, {'click': this.click}, { 'single': true, 'double': false, 'pixelTolerance': 0, 'stopSingle': false, 'stopDouble': false });
-       },
-
-       /**
-        * Map clicking event handler. Adds a temporary marker with a popup to the map, the popup contains the form to add a bug.
-       */
-       click: function(e) {
-               var lonlat = this.map.getLonLatFromViewPortPx(e.xy);
-               this.addTemporaryMarker(lonlat);
-       },
-
-       addTemporaryMarker: function(lonlat) {
-               if(!this.map) return true;
-               deactivateControl();
-
-               var control = this;
-               var lonlatApi = lonlat.clone().transform(this.map.getProjectionObject(), this.osbLayer.apiProjection);
-               var feature = new OpenLayers.Feature(this.osbLayer, lonlat, { icon: this.icon.clone(), autoSize: true });
-               feature.popupClass = OpenLayers.Popup.FramedCloud.OpenStreetBugs;
-               var marker = feature.createMarker();
-               marker.feature = feature;
-               this.osbLayer.addMarker(marker);
-
-
-               /** Implement a drag and drop for markers */
-               /* TODO: veryfy that the scoping of variables works correctly everywhere */             
-               var dragging = false;
-               var dragFunction = function(e) {
-                       map.events.unregister("mouseup",map,dragFunction);
-                       lonlat = map.getLonLatFromViewPortPx(e.xy);
-                       lonlatApi = lonlat.clone().transform(map.getProjectionObject(), map.osbLayer.apiProjection);
-                       marker.moveTo(map.getLayerPxFromViewPortPx(e.xy));
-                       marker.popup.moveTo(map.getLayerPxFromViewPortPx(e.xy));                        
-                       marker.popup.updateRelativePosition();
-                       dragging = false;
-                       return false;
-               };
-
-               marker.events.register("mouseover", this,
-                               function(){ document.getElementById("OpenLayers.Map_18_OpenLayers_Container").style.cursor = "move"; });
-               marker.events.register("mouseout", this,
-                               function(){ if (!dragging) {document.getElementById("OpenLayers.Map_18_OpenLayers_Container").style.cursor = "default"; }});
-               marker.events.register("mousedown", this,
-                               function() { dragging = true; map.events.register("mouseup",map, dragFunction); return false;});
-               
-
-               var newContent = document.createElement("div");
-               var el1,el2,el3;
-               el1 = document.createElement("h3");
-               el1.appendChild(document.createTextNode(i18n("javascripts.osb.Create bug")));
-               newContent.appendChild(el1);
-               newContent.appendChild(document.createTextNode(i18n("javascripts.osb.draghelp1")));
-               newContent.appendChild(document.createElement("br"));
-               newContent.appendChild(document.createTextNode(i18n("javascripts.osb.draghelp2")));
-               newContent.appendChild(document.createElement("br"));
-               newContent.appendChild(document.createElement("br"));
-
-               var el_form = document.createElement("form");
-
-               el1 = document.createElement("dl");
-               el2 = document.createElement("dt");
-               el2.appendChild(document.createTextNode(i18n("javascripts.osb.Nickname")));
-               el1.appendChild(el2);
-               el2 = document.createElement("dd");
-               var inputUsername = document.createElement("input");;
-               if (typeof loginName === 'undefined') {
-                   inputUsername.value = this.osbLayer.username;
-               } else {
-                       inputUsername.value = loginName;
-                       inputUsername.setAttribute('disabled','true');
-               }               
-               inputUsername.className = "osbUsername";
-               
-               inputUsername.onkeyup = function(){ control.osbLayer.setUserName(inputUsername.value); };
-               el2.appendChild(inputUsername);
-               el3 = document.createElement("a");
-               el3.setAttribute("href","login");
-               el3.className = "hide_if_logged_in";
-               el3.appendChild(document.createTextNode(i18n("javascripts.osb.Login")));
-               el2.appendChild(el3);
-               el1.appendChild(el2);
-               el2 = document.createElement("br");
-        el1.appendChild(el2);
-
-               el2 = document.createElement("dt");
-               el2.appendChild(document.createTextNode(i18n("javascripts.osb.Bug description")));
-               el1.appendChild(el2);
-               el2 = document.createElement("dd");
-               var inputDescription = document.createElement("textarea");
-               inputDescription.setAttribute("cols",40);
-               inputDescription.setAttribute("rows",3);
-               el2.appendChild(inputDescription);
-               el1.appendChild(el2);
-               el_form.appendChild(el1);
-
-               el1 = document.createElement("div");
-               el2 = document.createElement("input");
-               el2.setAttribute("type", "button");
-               el2.value = i18n("javascripts.osb.Create");
-        el2.onclick = function() { control.osbLayer.createBug(lonlatApi, inputDescription.value); marker.feature = null; feature.destroy(); return false; };
-               el1.appendChild(el2);
-               el2 = document.createElement("input");
-               el2.setAttribute("type", "button");
-               el2.value = i18n("javascripts.osb.Cancel");
-               el2.onclick = function(){ feature.destroy(); };
-               el1.appendChild(el2);
-               el_form.appendChild(el1);
-               newContent.appendChild(el_form);
-
-               el2 = document.createElement("hr");
-               el1.appendChild(el2);
-               el2 = document.createElement("a");
-               el2.setAttribute("href","edit");
-               el2.appendChild(document.createTextNode(i18n("javascripts.osb.edityourself")));
-               el1.appendChild(el2);
-
-               feature.data.popupContentHTML = newContent;
-               var popup = feature.createPopup(true);
-               popup.events.register("close", this, function(){ feature.destroy(); });
-               this.map.addPopup(popup);
-               popup.updateSize();
-               marker.popup = popup;
-       },
-
-       CLASS_NAME: "OpenLayers.Control.OpenStreetBugs"
-});
-
-
-/**
- * This class changes the usual OpenLayers.Popup.FramedCloud class by using a DOM element instead of an innerHTML string as content for the popup.
- * This is necessary for creating valid onclick handlers that still work with multiple OpenStreetBugs layer objects.
-*/
-
-OpenLayers.Popup.FramedCloud.OpenStreetBugs = new OpenLayers.Class(OpenLayers.Popup.FramedCloud, {
-       contentDom : null,
-       autoSize : true,
-
-       /**
-        * See OpenLayers.Popup.FramedCloud.initialize() for parameters. As fourth parameter, pass a DOM node instead of a string.
-       */
-       initialize: function() {
-               this.displayClass = this.displayClass + " " + this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
-
-               var args = new Array(arguments.length);
-               for(var i=0; i<arguments.length; i++)
-                       args[i] = arguments[i];
-
-               // Unset original contentHTML parameter
-               args[3] = null;
-
-               var closeCallback = arguments[6];
-
-               // Add close event trigger to the closeBoxCallback parameter
-               args[6] = function(e){ if(closeCallback) closeCallback(); else this.hide(); OpenLayers.Event.stop(e); this.events.triggerEvent("close"); };
-
-               OpenLayers.Popup.FramedCloud.prototype.initialize.apply(this, args);
-
-               this.events.addEventType("close");
-
-               this.setContentHTML(arguments[3]);
-       },
-
-       /**
-        * Like OpenLayers.Popup.FramedCloud.setContentHTML(), but takes a DOM element as parameter.
-       */
-       setContentHTML: function(contentDom) {
-               if(contentDom != null)
-                       this.contentDom = contentDom;
-
-               if(this.contentDiv == null || this.contentDom == null || this.contentDom == this.contentDiv.firstChild)
-                       return;
-
-               while(this.contentDiv.firstChild)
-                       this.contentDiv.removeChild(this.contentDiv.firstChild);
-
-               this.contentDiv.appendChild(this.contentDom);
-
-               // Copied from OpenLayers.Popup.setContentHTML():
-               if(this.autoSize)
-               {
-                       this.registerImageListeners();
-                       this.updateSize();
-               }
-       },
-
-       destroy: function() {
-               this.contentDom = null;
-               OpenLayers.Popup.FramedCloud.prototype.destroy.apply(this, arguments);
-       },
-
-       CLASS_NAME: "OpenLayers.Popup.FramedCloud.OpenStreetBugs"
-});
-
-
-/**
- * This global function is executed by the OpenStreetBugs API getBugs script.
- * Each OpenStreetBugs layer adds itself to the putAJAXMarker.layer array. The putAJAXMarker() function executes the createMarker() method
- * on each layer in that array each time it is called. This has the side-effect that bugs displayed in one map on a page are already loaded
- * on the other map as well.
-*/
-
-function putAJAXMarker(id, lon, lat, text, closed)
-{
-       var comments = text.split(/<hr \/>/);
-       for(var i=0; i<comments.length; i++)
-               comments[i] = comments[i].replace(/&quot;/g, "\"").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
-       putAJAXMarker.bugs[id] = [
-               new OpenLayers.LonLat(lon, lat),
-               comments,
-               closed
-       ];
-       for(var i=0; i<putAJAXMarker.layers.length; i++)
-               putAJAXMarker.layers[i].createMarker(id);
-}
-
-/**
- * This global function is executed by the OpenStreetBugs API. The “create bug”, “comment” and “close bug” scripts execute it to give information about their success.
- * In case of success, this function is called without a parameter, in case of an error, the error message is passed. This is lousy workaround to make it any functional at all, the OSB API is likely to be extended later (then it will provide additional information such as the ID of a created bug and similar).
-*/
-
-function osbResponse(error)
-{
-       if(error)
-               alert("Error: "+error);
-
-       for(var i=0; i<putAJAXMarker.layers.length; i++)
-               putAJAXMarker.layers[i].loadBugs();
-}
-
-putAJAXMarker.layers = [ ];
-putAJAXMarker.bugs = { };
-
-function deactivateControl() { 
-    map.osbControl.deactivate(); 
-    document.getElementById("OpenLayers.Map_18_OpenLayers_Container").style.cursor = "default"; 
-  }
-
-
-/* Translations */
-
-/*
-
-OpenLayers.Lang.en = OpenLayers.Util.extend(OpenLayers.Lang.en, {
-       "Fixed Error" : "Fixed Error",
-       "Unresolved Error" : "Unresolved Error",
-       "Description" : "Description",
-       "Comment" : "Comment",
-       "Has been fixed." : "This error has been fixed already. However, it might take a couple of days before the map image is updated.",
-       "Comment/Close" : "Comment/Close",
-       "Nickname" : "Nickname",
-       "Add comment" : "Add comment",
-       "Mark as fixed" : "Mark as fixed",
-       "Cancel" : "Cancel",
-       "Create OpenStreetBug" : "Create OpenStreetBug",
-       "Create bug" : "Create bug",
-       "Bug description" : "Bug description",
-       "Create" : "Create",
-       "Permalink" : "Permalink",
-       "Zoom" : "Zoom"
-});
-
-OpenLayers.Lang.de = OpenLayers.Util.extend(OpenLayers.Lang.de, {
-       "Fixed Error" : "Behobener Fehler",
-       "Unresolved Error" : "Offener Fehler",
-       "Description" : "Beschreibung",
-       "Comment" : "Kommentar",
-       "Has been fixed." : "Der Fehler wurde bereits behoben. Es kann jedoch bis zu einigen Tagen dauern, bis die Kartenansicht aktualisiert wird.",
-       "Comment/Close" : "Kommentieren/Schließen",
-       "Nickname" : "Benutzername",
-       "Add comment" : "Kommentar hinzufügen",
-       "Mark as fixed" : "Als behoben markieren",
-       "Cancel" : "Abbrechen",
-       "Create OpenStreetBug" : "OpenStreetBug melden",
-       "Create bug" : "Bug anlegen",
-       "Bug description" : "Fehlerbeschreibung",
-       "Create" : "Anlegen",
-       "Permalink" : "Permalink",
-       "Zoom" : "Zoom"
-});
-
-OpenLayers.Lang.fr = OpenLayers.Util.extend(OpenLayers.Lang.fr, {
-       "Fixed Error" : "Erreur corrigée",
-       "Unresolved Error" : "Erreur non corrigée",
-       "Description" : "Description",
-       "Comment" : "Commentaire",
-       "Has been fixed." : "Cette erreur a déjà été corrigée. Cependant, il peut être nécessaire d'attendre quelques jours avant que l'image de la carte ne soit mise à jour.",
-       "Comment/Close" : "Commenter/Fermer",
-       "Nickname" : "Surnom",
-       "Add comment" : "Ajouter un commentaire",
-       "Mark as fixed" : "Marquer comme corrigé",
-       "Cancel" : "Annuler",
-       "Create OpenStreetBug" : "Créer OpenStreetBug",
-       "Create bug" : "Ajouter un bug",
-       "Bug description" : "Description du bug",
-       "Create" : "Créer",
-       "Permalink" : "Lien permanent",
-       "Zoom" : "Zoom"
-});
-
-OpenLayers.Lang.nl = OpenLayers.Util.extend(OpenLayers.Lang.nl, {
-       "Fixed Error" : "Fout verholpen",
-       "Unresolved Error" : "Openstaande fout",
-       "Description" : "Beschrijving",
-       "Comment" : "Kommentaar",
-       "Has been fixed." : "De fout is al eerder opgelost. Het kan echter nog een paar dagen duren voordat het kaartmateriaal geactualiseerd is.",
-       "Comment/Close" : "Bekommentariëren/Sluiten",
-       "Nickname" : "Gebruikersnaam",
-       "Add comment" : "Kommentaar toevoegen",
-       "Mark as fixed" : "Als opgelost aanmerken",
-       "Cancel" : "Afbreken",
-       "Create OpenStreetBug" : "OpenStreetBug melden",
-       "Create bug" : "Bug melden",
-       "Bug description" : "Foutomschrijving",
-       "Create" : "Aanmaken",
-       "Permalink" : "Permalink",
-       "Zoom" : "Zoom"
-});
-
-OpenLayers.Lang.it = OpenLayers.Util.extend(OpenLayers.Lang.it, {
-       "Fixed Error" : "Sbaglio coretto",
-       "Unresolved Error" : "Sbaglio non coretto",
-       "Description" : "Descrizione",
-       "Comment" : "Commento",
-       "Has been fixed." : "Questo sbaglio è già coretto. Forse ci metto qualche giorni per aggiornare anche i quadri.",
-       "Comment/Close" : "Commenta/Chiude",
-       "Nickname" : "Nome",
-       "Add comment" : "Aggiunge commento",
-       "Mark as fixed" : "Marca che è coretto",
-       "Cancel" : "Annulla",
-       "Create OpenStreetBug" : "Aggiunge OpenStreetBug",
-       "Create bug" : "Aggiunge un sbaglio",
-       "Bug description" : "Descrizione del sbaglio",
-       "Create" : "Aggiunge",
-       "Permalink" : "Permalink",
-       "Zoom" : "Zoom"
-});
-
-OpenLayers.Lang.ro = OpenLayers.Util.extend(OpenLayers.Lang.ro, {
-       "Fixed Error" : "Eroare rezolvată",
-       "Unresolved Error" : "Eroare nerezolvată",
-       "Description" : "Descriere",
-       "Comment" : "Comentariu",
-       "Has been fixed." : "Această eroare a fost rezolvată. Totuși este posibil să dureze câteva zile până când imaginea hărții va fi actualizată.",
-       "Comment/Close" : "Comentariu/Închide",
-       "Nickname" : "Nume",
-       "Add comment" : "Adaugă comentariu",
-       "Mark as fixed" : "Marchează ca rezolvată",
-       "Cancel" : "Anulează",
-       "Create OpenStreetBug" : "Crează OpenStreetBug",
-       "Create bug" : "Adaugă eroare",
-       "Bug description" : "Descrierea erorii",
-       "Create" : "Adaugă",
-       "Permalink" : "Permalink",
-       "Zoom" : "Zoom"
-});
-*/
diff --git a/public/stylesheets/notes.css b/public/stylesheets/notes.css
new file mode 100644 (file)
index 0000000..ee6198b
--- /dev/null
@@ -0,0 +1,42 @@
+.olPopupFramedCloudNotes dl {
+    margin: 0px;
+    padding: 0px;
+}
+
+.olPopupFramedCloudNotes dt {
+    margin: 0px;
+    padding: 0px;
+    font-weight: bold;
+    float: left;
+    clear: left;
+}
+
+.olPopupFramedCloudNotes dt:after {
+    content: ": ";
+}
+
+.olPopupFramedCloudNotes dt {
+    margin-right: 1ex;
+}
+
+.olPopupFramedCloudNotes dd {
+    margin: 0px;
+    padding: 0px;
+}
+
+.olPopupFramedCloudNotes ul.buttons {
+    list-style-type: none;
+    padding: 0px;
+    margin: 0px;
+}
+
+.olPopupFramedCloudNotes ul.buttons li {
+    display: inline;
+    margin: 0px;
+    padding: 0px;
+}
+
+.olPopupFramedCloudNotes h3 {
+    font-size: 1.2em;
+    margin: 0.2em 0em 0.7em 0em;
+}
diff --git a/public/stylesheets/openstreetbugs.css b/public/stylesheets/openstreetbugs.css
deleted file mode 100644 (file)
index b1859f7..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-.olPopupFramedCloudOpenStreetBugs dl { margin:0; padding:0; }
-.olPopupFramedCloudOpenStreetBugs dt { margin:0; padding:0; font-weight:bold; float:left; clear:left; }
-.olPopupFramedCloudOpenStreetBugs dt:after { content:": "; }
-* html .olPopupFramedCloudOpenStreetBugs dt { margin-right:1ex; }
-.olPopupFramedCloudOpenStreetBugs dd { margin:0; padding:0; }
-.olPopupFramedCloudOpenStreetBugs ul.buttons { list-style-type:none; padding:0; margin:0 }
-.olPopupFramedCloudOpenStreetBugs ul.buttons li { display:inline; margin:0; padding:0; }
-.olPopupFramedCloudOpenStreetBugs h3 { font-size:1.2em; margin:.2em 0 .7em 0; }