]> git.openstreetmap.org Git - rails.git/commitdiff
Merge branch 'master' into notes
authorTom Hughes <tom@compton.nu>
Sat, 1 Dec 2012 18:22:30 +0000 (18:22 +0000)
committerTom Hughes <tom@compton.nu>
Sat, 1 Dec 2012 18:22:30 +0000 (18:22 +0000)
Conflicts:
app/assets/javascripts/browse.js
app/assets/javascripts/map.js.erb
app/assets/stylesheets/common.css.scss
app/views/site/index.html.erb

12 files changed:
1  2 
Gemfile
Gemfile.lock
app/assets/javascripts/browse.js
app/assets/javascripts/index.js
app/assets/javascripts/map.js.erb
app/assets/javascripts/osm.js.erb
app/assets/stylesheets/common.css.scss
app/views/site/index.html.erb
app/views/user/view.html.erb
config/locales/de.yml
config/locales/en.yml
config/routes.rb

diff --combined Gemfile
index 4b2d2ba9e0351ce6d7e2de3ab2ad17fbc1115498,7656092f1407d4dff7c98aec9ee2a3d58a1a0f55..5b5a76e650d15abc1f14bed7fe936864c1102c05
+++ b/Gemfile
@@@ -23,13 -23,12 +23,13 @@@ gem 'rinku', '>= 1.2.2', :require => 'r
  gem 'oauth-plugin', '>= 0.4.1', :require => 'oauth-plugin'
  gem 'open_id_authentication', '>= 1.1.0'
  gem 'validates_email_format_of', '>= 1.5.1'
- gem 'composite_primary_keys', '>= 5.0.9'
+ gem 'composite_primary_keys', '>= 5.0.10'
  gem 'http_accept_language', '>= 1.0.2'
  gem 'paperclip', '~> 2.0'
  gem 'deadlock_retry', '>= 1.2.0'
  gem 'i18n-js', '>= 3.0.0.rc2'
  gem 'rack-cors'
 +gem 'jsonify-rails'
  
  # We need ruby-openid 2.2.0 or later for ruby 1.9 support
  gem 'ruby-openid', '>= 2.2.0'
diff --combined Gemfile.lock
index eafd5d341a16a4ba61ad384214e5ce40c3cc6f78,5d4372f2a1670950a8ca3f1ec867d854a8767a53..8fea3da8e6f6d5b9265d9486dda3076946355a24
@@@ -40,8 -40,8 +40,8 @@@ GE
        coffee-script-source
        execjs
      coffee-script-source (1.4.0)
-     composite_primary_keys (5.0.9)
-       activerecord (~> 3.2.0, >= 3.2.8)
+     composite_primary_keys (5.0.10)
+       activerecord (~> 3.2.0, >= 3.2.9)
      deadlock_retry (1.2.0)
      dynamic_form (1.1.4)
      ejs (1.1.1)
        railties (>= 3.1.0, < 5.0)
        thor (~> 0.14)
      json (1.7.5)
 +    jsonify (0.3.1)
 +      multi_json (~> 1.0)
 +    jsonify-rails (0.3.2)
 +      actionpack
 +      jsonify (< 0.4.0)
      jwt (0.1.5)
        multi_json (>= 1.0)
      libv8 (3.3.10.4)
@@@ -173,7 -168,7 +173,7 @@@ DEPENDENCIE
    SystemTimer (>= 1.1.3)
    bigdecimal
    coffee-rails (~> 3.2.1)
-   composite_primary_keys (>= 5.0.9)
+   composite_primary_keys (>= 5.0.10)
    deadlock_retry (>= 1.2.0)
    dynamic_form
    ejs
    i18n-js (>= 3.0.0.rc2)
    iconv
    jquery-rails
 +  jsonify-rails
    libxml-ruby (>= 2.0.5)
    memcached (>= 1.4.1)
    minitest
index 906bb0baeb9f9749bbfda2eeccf2d12c0cf152b7,c3d67e57e215be0c7017ddc65fdb0114863f95d1..fb6d2d304e01383dd45da85ea188e7256370ccdd
@@@ -1,9 -1,9 +1,9 @@@
  $(document).ready(function () {
    function remoteEditHandler(bbox, select) {
-     var left = bbox.left - 0.0001;
-     var top = bbox.top + 0.0001;
-     var right = bbox.right + 0.0001;
-     var bottom = bbox.bottom - 0.0001;
+     var left = bbox.getWestLng() - 0.0001;
+     var top = bbox.getNorthLat() + 0.0001;
+     var right = bbox.getEastLng() + 0.0001;
+     var bottom = bbox.getSouthLat() - 0.0001;
      var loaded = false;
  
      $("#linkloader").load(function () { loaded = true; });
    }
  
    var map = createMap("small_map", {
-     controls: [ new OpenLayers.Control.Navigation() ]
+     layerControl: false,
+     panZoomControl: false,
+     attributionControl: false
    });
  
    var params = $("#small_map").data();
    if (params.type == "changeset") {
-     var bbox = new OpenLayers.Bounds(params.minlon, params.minlat, params.maxlon, params.maxlat);
-     var centre = bbox.getCenterLonLat();
+     var bbox = L.latLngBounds([params.minlat, params.minlon],
+                               [params.maxlat, params.maxlon]);
  
-     map.zoomToExtent(proj(bbox));
+     map.fitBounds(bbox);
      addBoxToMap(bbox);
  
      $("#loading").hide();
        return remoteEditHandler(bbox);
      });
  
 -    updatelinks(centre.lng, centre.lat, 16, null, params.minlon, params.minlat, params.maxlon, params.maxlat);
+     var centre = bbox.getCenter();
 +    updatelinks(centre.lon, centre.lat, 16, null, params.minlon, params.minlat, params.maxlon, params.maxlat);
 +  } else if (params.type == "note") {
 +    var centre = new OpenLayers.LonLat(params.lon, params.lat);
 +
 +    setMapCenter(centre, 16);
 +    addMarkerToMap(centre);
 +
 +    var bbox = unproj(map.getExtent());
 +
 +    $("#loading").hide();
 +    $("#browse_map .geolink").show();
 +
 +    $("a[data-editor=remote]").click(function () {
 +      return remoteEditHandler(bbox);
 +    });
 +
 +    updatelinks(centre.lon, centre.lat, 16, null, bbox.left, bbox.bottom, bbox.right, bbox.top)
    } else {
      $("#object_larger_map").hide();
      $("#object_edit").hide();
        $("#browse_map .geolink").show();
  
        if (extent) {
-         extent = unproj(extent);
-         var centre = extent.getCenterLonLat();
          $("a.bbox[data-editor=remote]").click(function () {
            return remoteEditHandler(extent);
          });
          $("#object_larger_map").show();
          $("#object_edit").show();
  
-         updatelinks(centre.lon, centre.lat, 16, null, extent.left, extent.bottom, extent.right, extent.top, object);
+         var centre = extent.getCenter();
+         updatelinks(centre.lng,
+                     centre.lat,
+                     16, null,
+                     extent.getWestLng(),
+                     extent.getSouthLat(),
+                     extent.getEastLng(),
+                     extent.getNorthLat(),
+                     object);
        } else {
          $("#small_map").hide();
        }
index c0decd6a6ce9a9af8e3bdc0a3eaffd8cae490af8,c908f1e3490353d72d53d067e2ad614ff8560aa7..c90d96c3997d93219c95293c8fd192f1bb27a7cc
@@@ -1,27 -1,32 +1,33 @@@
+ //= require_self
  //= require index/browse
  //= require index/export
  //= require index/key
 +//= require index/notes
  
  $(document).ready(function () {
+   var permalinks = $("#permalink").html();
    var marker;
    var params = OSM.mapParams();
    var map = createMap("map");
  
-   map.events.register("moveend", map, updateLocation);
-   map.events.register("changelayer", map, updateLocation);
+   L.control.scale().addTo(map);
+   map.attributionControl.setPrefix(permalinks);
+   map.on("moveend baselayerchange", updateLocation);
  
    if (!params.object_zoom) {
      if (params.bbox) {
-       var bbox = new OpenLayers.Bounds(params.minlon, params.minlat, params.maxlon, params.maxlat);
+       var bbox = L.latLngBounds([params.minlat, params.minlon],
+                                 [params.maxlat, params.maxlon]);
  
-       map.zoomToExtent(proj(bbox));
+       map.fitBounds(bbox);
  
        if (params.box) {
          addBoxToMap(bbox);
        }
      } else {
-       setMapCenter(new OpenLayers.LonLat(params.lon, params.lat), params.zoom);
+       map.setView([params.lat, params.lon], params.zoom);
      }
    }
  
@@@ -30,7 -35,7 +36,7 @@@
    }
  
    if (params.marker) {
-     marker = addMarkerToMap(new OpenLayers.LonLat(params.mlon, params.mlat));
+     marker = L.marker([params.mlat, params.mlon], {icon: getUserIcon()}).addTo(map);
    }
  
    if (params.object) {
  
    handleResize();
  
-   $("body").on("click", "a.set_position", function () {
+   $("body").on("click", "a.set_position", function (e) {
+     e.preventDefault();
      var data = $(this).data();
-     var centre = new OpenLayers.LonLat(data.lon, data.lat);
+     var centre = L.latLng(data.lat, data.lon);
  
      if (data.minLon && data.minLat && data.maxLon && data.maxLat) {
-       var bbox = new OpenLayers.Bounds(data.minLon, data.minLat, data.maxLon, data.maxLat);
-       map.zoomToExtent(proj(bbox));
+       map.fitBounds([[data.minLat, data.minLon],
+                      [data.maxLat, data.maxLon]]);
      } else {
-       setMapCenter(centre, data.zoom);
+       map.setView(centre, data.zoom);
      }
  
      if (marker) {
-       removeMarkerFromMap(marker);
+       map.removeLayer(marker);
      }
  
-     marker = addMarkerToMap(centre, getArrowIcon());
-     return false;
+     marker = L.marker(centre, {icon: getUserIcon()}).addTo(map);
    });
  
    function updateLocation() {
-     var lonlat = unproj(map.getCenter());
+     var center = map.getCenter();
      var zoom = map.getZoom();
      var layers = getMapLayers();
-     var extents = unproj(map.getExtent());
-     var expiry = new Date();
-     updatelinks(lonlat.lon, lonlat.lat, zoom, layers, extents.left, extents.bottom, extents.right, extents.top, params.object);
+     var extents = map.getBounds();
+     updatelinks(center.lng,
+                 center.lat,
+                 zoom,
+                 layers,
+                 extents.getWestLng(),
+                 extents.getSouthLat(),
+                 extents.getEastLng(),
+                 extents.getNorthLat(),
+                 params.object);
  
+     var expiry = new Date();
      expiry.setYear(expiry.getFullYear() + 10);
-     $.cookie("_osm_location", [lonlat.lon, lonlat.lat, zoom, layers].join("|"), {expires: expiry});
+     $.cookie("_osm_location", [center.lng, center.lat, zoom, layers].join("|"), {expires: expiry});
    }
  
-   function remoteEditHandler(event) {
-     var extent = unproj(map.getExtent());
+   function remoteEditHandler() {
+     var extent = map.getBounds();
      var loaded = false;
  
      $("#linkloader").load(function () { loaded = true; });
-     $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + extent.left + "&top=" + extent.top + "&right=" + extent.right + "&bottom=" + extent.bottom);
+     $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + extent.getWestLng()
+                                                                    + "&bottom=" + extent.getSouthLat()
+                                                                    + "&right=" + extent.getEastLng()
+                                                                    + "&top=" + extent.getNorthLat());
  
      setTimeout(function () {
        if (!loaded) alert(I18n.t('site.index.remote_failed'));
      remoteEditHandler();
    }
  
-   $(window).resize(function() {
-     var centre = map.getCenter();
-     var zoom = map.getZoom();
-     handleResize();
-     map.setCenter(centre, zoom);
-   });
+   $(window).resize(handleResize);
  
    $("#search_form").submit(function () {
-     var extent = unproj(map.getExtent());
+     var bounds = map.getBounds();
  
      $("#sidebar_title").html(I18n.t('site.sidebar.search_results'));
      $("#sidebar_content").load($(this).attr("action"), {
        query: $("#query").val(),
-       minlon: extent.left,
-       minlat: extent.bottom,
-       maxlon: extent.right,
-       maxlat: extent.top
+       minlon: bounds.getWestLng(),
+       minlat: bounds.getSouthLat(),
+       maxlon: bounds.getEastLng(),
+       maxlat: bounds.getNorthLat()
      }, openSidebar);
  
      return false;
index 4c1a849dc25d5f4a4572ac74e649515a378eb0e1,291633f53c1c04079311a7afd4437526ea9a2d48..f069eee993e76d90a6842e48cabf3dd70534f521
- var epsg4326 = new OpenLayers.Projection("EPSG:4326");
+ // Leaflet extensions
+ L.LatLngBounds.include({
+   getSouthLat: function () {
+     return this._southWest.lat;
+   },
+   getWestLng: function () {
+     return this._southWest.lng;
+   },
+   getNorthLat: function () {
+     return this._northEast.lat;
+   },
+   getEastLng: function () {
+     return this._northEast.lng;
+   },
+   toBBOX: function () {
+     var decimal = 6;
+     var mult = Math.pow(10, decimal);
+     var xmin = Math.round(this.getWestLng() * mult) / mult;
+     var ymin = Math.round(this.getSouthLat() * mult) / mult;
+     var xmax = Math.round(this.getEastLng() * mult) / mult;
+     var ymax = Math.round(this.getNorthLat() * mult) / mult;
+     return xmin + "," + ymin + "," + xmax + "," + ymax;
+   },
+   getSize: function () {
+     return (this._northEast.lat - this._southWest.lat) *
+            (this._northEast.lng - this._southWest.lng);
+   }
+ });
+ L.Bounds.include({
+   getWidth: function () {
+    return this.max.x - this.min.x;
+   },
+   getHeight: function () {
+    return this.max.y - this.min.y;
+   }
+ });
+ L.Icon.Default.imagePath = <%= "#{asset_prefix}/images".to_json %>;
  var map;
- var markers;
- var vectors;
- var popup;
+ var layers = [
+   {
+     klass: L.OSM.Mapnik,
+     attribution: "",
+     keyid: "mapnik",
+     layerCode: "M",
+     name: I18n.t("javascripts.map.base.standard")
+   },
+   {
+     klass: L.OSM.CycleMap,
+     attribution: "Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
+     keyid: "cyclemap",
+     layerCode: "C",
+     name: I18n.t("javascripts.map.base.cycle_map")
+   },
+   {
+     klass: L.OSM.TransportMap,
+     attribution: "Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
+     keyid: "transportmap",
+     layerCode: "T",
+     name: I18n.t("javascripts.map.base.transport_map")
+   },
+   {
+     klass: L.OSM.MapQuestOpen,
+     attribution: "Tiles courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'>",
+     keyid: "mapquest",
+     layerCode: "Q",
+     name: I18n.t("javascripts.map.base.mapquest")
+   }
+ ];
  
  function createMap(divName, options) {
-    options = options || {};
-    map = new OpenLayers.Map(divName, {
-       controls: options.controls || [
-          new OpenLayers.Control.ArgParser(),
-          new OpenLayers.Control.Attribution(),
-          new SimpleLayerSwitcher(),
-          new OpenLayers.Control.Navigation(),
-          new OpenLayers.Control.Zoom(),
-          new OpenLayers.Control.SimplePanZoom(),
-          new OpenLayers.Control.ScaleLine({geodesic: true})
-       ],
-       numZoomLevels: 20,
-       displayProjection: new OpenLayers.Projection("EPSG:4326"),
-       theme: "<%= asset_path 'theme/openstreetmap/style.css' %>"
-    });
-    var mapnik = new OpenLayers.Layer.OSM.Mapnik(I18n.t("javascripts.map.base.standard"), {
-       attribution: "",
-       keyid: "mapnik",
-       displayOutsideMaxExtent: true,
-       wrapDateLine: true,
-       layerCode: "M"
-    });
-    map.addLayer(mapnik);
-    var cyclemap = new OpenLayers.Layer.OSM.CycleMap(I18n.t("javascripts.map.base.cycle_map"), {
-       attribution: "Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
-       keyid: "cyclemap",
-       displayOutsideMaxExtent: true,
-       wrapDateLine: true,
-       layerCode: "C"
-    });
-    map.addLayer(cyclemap);
-    var transportmap = new OpenLayers.Layer.OSM.TransportMap(I18n.t("javascripts.map.base.transport_map"), {
-       attribution: "Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
-       keyid: "transportmap",
-       displayOutsideMaxExtent: true,
-       wrapDateLine: true,
-       layerCode: "T"
-    });
-    map.addLayer(transportmap);
-    var mapquest = new OpenLayers.Layer.OSM(I18n.t("javascripts.map.base.mapquest"), [
-       "http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png",
-       "http://otile2.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png",
-       "http://otile3.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png",
-       "http://otile4.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png"
-    ], {
-       attribution: "Tiles courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'>",
-       keyid: "mapquest",
-       displayOutsideMaxExtent: true,
-       wrapDateLine: true,
-       numZoomLevels: 19,
-       layerCode: "Q"
-    });
-    map.addLayer(mapquest);
-    markers = new OpenLayers.Layer.Markers("Markers", {
-       displayInLayerSwitcher: false,
-       numZoomLevels: 20,
-       projection: "EPSG:900913"
-    });
-    map.addLayer(markers);
-    map.dataLayer = new OpenLayers.Layer(I18n.t('browse.start_rjs.data_layer_name'), {
-      visibility: false,
-      displayInLayerSwitcher: false
-    });
-    map.addLayer(map.dataLayer);
-    $("#" + divName).on("resized", function () {
-      map.updateSize();
-    });
-    $("#" + divName).trigger("initialised");
-    return map;
- }
+   options = $.extend({zoomControl: true, panZoomControl: true, layerControl: true}, options);
  
- function getArrowIcon() {
-    var size = new OpenLayers.Size(25, 22);
-    var offset = new OpenLayers.Pixel(-22, -20);
-    var icon = new OpenLayers.Icon("<%= asset_path 'arrow.png' %>", size, offset);
+   map = L.map(divName, $.extend({}, options, {panControl: false, zoomsliderControl: false, maxZoom: 18}));
  
-    return icon;
- }
+   if (map.attributionControl) {
+     map.attributionControl.setPrefix('');
+   }
+   if (options.panZoomControl) {
+     new L.Control.Pan().addTo(map);
+     new L.Control.Zoomslider({stepHeight: 7}).addTo(map);
+   }
+   var layersControl = L.control.layers();
+   if (options.layerControl) {
+     layersControl.addTo(map);
+     map.layersControl = layersControl;
+   }
+   for (var i = 0; i < layers.length; i++) {
+     layers[i].layer = new (layers[i].klass)(layers[i]);
+     layersControl.addBaseLayer(layers[i].layer, layers[i].name);
+   }
  
- function addMarkerToMap(position, icon, description) {
-    var marker = new OpenLayers.Marker(proj(position), icon);
+   layers[0].layer.addTo(map);
  
-    markers.addMarker(marker);
+   $("#" + divName).on("resized", function () {
+     map.invalidateSize();
+   });
  
-    if (description) {
-        marker.events.register("mouseover", marker, function() {
-            openMapPopup(marker, description);
-        });
-    }
++ $("#" + divName).trigger("initialised");
 +
-    return marker;
+   return map;
+ }
+ function getUserIcon(url) {
+   return L.icon({
+     iconUrl: url || <%= asset_path('marker-red.png').to_json %>,
+     iconSize: [25, 41],
+     iconAnchor: [12, 41],
+     popupAnchor: [1, -34],
+     shadowUrl: <%= asset_path('images/marker-shadow.png').to_json %>,
+     shadowSize: [41, 41]
+   });
  }
  
  function addObjectToMap(object, zoom, callback) {
-    var layer = new OpenLayers.Layer.Vector("Objects", {
-       strategies: [ 
-           new OpenLayers.Strategy.Fixed()
-       ],
-       protocol: new OpenLayers.Protocol.HTTP({
-           url: OSM.apiUrl(object),
-           format: new OpenLayers.Format.OSM()
-       }),
-       style: {
+   $.ajax({
+     url: OSM.apiUrl(object),
+     dataType: "xml",
+     success: function (xml) {
+       var layer = new L.OSM.DataLayer(xml, {
+         style: {
            strokeColor: "blue",
            strokeWidth: 3,
            strokeOpacity: 0.5,
            fillOpacity: 0.2,
            fillColor: "lightblue",
            pointRadius: 6
-       },
-       projection: new OpenLayers.Projection("EPSG:4326"),
-       displayInLayerSwitcher: false
-    });
-    layer.events.register("loadend", layer, function() {
-       var extent;
-       if (this.features.length) {
-          extent = this.features[0].geometry.getBounds();
-          for (var i = 1; i < this.features.length; i++) {
-             extent.extend(this.features[i].geometry.getBounds());
-          }
-          if (zoom) {
-             if (extent) {
-                this.map.zoomToExtent(extent);
-             } else {
-                this.map.zoomToMaxExtent();
-             }
-          }
+         }
+       });
+       var bounds = layer.getBounds();
+       if (zoom) {
+         map.fitBounds(bounds);
        }
  
        if (callback) {
-          callback(extent);
+         callback(bounds);
        }
-    });
-    map.addLayer(layer);
- }
- function addBoxToMap(boxbounds, id, outline) {
-    if (!vectors) {
-      // Be aware that IE requires Vector layers be initialised on page load, and not under deferred script conditions
-      vectors = new OpenLayers.Layer.Vector("Boxes", {
-         displayInLayerSwitcher: false
-      });
-      map.addLayer(vectors);
-    }
-    var geometry;
-    if (outline) {
-      vertices = boxbounds.toGeometry().getVertices();
-      vertices.push(new OpenLayers.Geometry.Point(vertices[0].x, vertices[0].y));
-      geometry = proj(new OpenLayers.Geometry.LineString(vertices));
-    } else {
-      geometry = proj(boxbounds.toGeometry());
-    }
-    var box = new OpenLayers.Feature.Vector(geometry, {}, {
-       strokeWidth: 2,
-       strokeColor: '#ee9900',
-       fillOpacity: 0
-    });
-    box.fid = id;
-    vectors.addFeatures(box);
-    return box;
- }
- function openMapPopup(marker, description) {
-    closeMapPopup();
-    popup = new OpenLayers.Popup.FramedCloud("popup", marker.lonlat, null,
-                                             description, marker.icon, true);
-    popup.setBackgroundColor("#E3FFC5");
-    map.addPopup(popup);
-    return popup;
- }
  
- function closeMapPopup() {
-    if (popup) {
-       map.removePopup(popup);
-    }
+       layer.addTo(map);
+     }
+   });
  }
  
- function removeMarkerFromMap(marker){
-    markers.removeMarker(marker);
- }
+ function addBoxToMap(bounds) {
+   var box = L.rectangle(bounds, {
+     weight: 2,
+     color: '#e90',
+     fillOpacity: 0
+   });
  
- function proj(x) {
-     return x.clone().transform(epsg4326, map.getProjectionObject());
- }
+   box.addTo(map);
  
- function unproj(x) {
-     return x.clone().transform(map.getProjectionObject(), epsg4326);
+   return box;
  }
  
- function setMapCenter(center, zoom) {
-    zoom = parseInt(zoom, 10);
-    var numzoom = map.getNumZoomLevels();
-    if (zoom >= numzoom) zoom = numzoom - 1;
-    map.setCenter(proj(center), zoom);
- }
- function getEventPosition(event) {
-    return unproj(map.getLonLatFromViewPortPx(event.xy));
+ function getMapBaseLayer() {
+   for (var i = 0; i < layers.length; i++) {
+     if (map.hasLayer(layers[i].layer)) {
+       return layers[i];
+     }
+   }
  }
  
  function getMapLayers() {
-    var layerConfig = "";
-    for (var i = 0; i < map.layers.length; i++) {
-       if (map.layers[i].layerCode && map.layers[i].getVisibility()) {
-          layerConfig += map.layers[i].layerCode;
-       }
-    }
+   for (var i = 0; i < layers.length; i++) {
+     if (map.hasLayer(layers[i].layer)) {
+       return layers[i].layerCode;
+     }
+   }
  
-    return layerConfig;
+   return "";
  }
  
  function setMapLayers(layerConfig) {
-    if (layerConfig.charAt(0) == "B" || layerConfig.charAt(0) == "0") {
-       var l = 0;
-       for (var layers = map.getLayersBy("isBaseLayer", true), i = 0; i < layers.length; i++) {
-          var c = layerConfig.charAt(l++);
-          if (c == "B") {
-             map.setBaseLayer(layers[i]);
-          } else {
-             map.layers[i].setVisibility(false);
-          }
-       }
-    } else {
-       for (var i = 0; i < map.layers.length; i++) {
-          if (map.layers[i].layerCode) {
-             if (layerConfig.indexOf(map.layers[i].layerCode) >= 0) {
-                if (map.layers[i].isBaseLayer) {
-                   map.setBaseLayer(map.layers[i]);
-                } else {
-                   map.layers[i].setVisibility(true);
-                }
-             } else if (!map.layers[i].isBaseLayer) {
-                map.layers[i].setVisibility(false);
-             }
-          }
-       }
-    }
+   var foundLayer = false;
+   for (var i = 0; i < layers.length; i++) {
+     if (layerConfig.indexOf(layers[i].layerCode) >= 0) {
+       map.addLayer(layers[i].layer);
+       foundLayer = true;
+     } else {
+       map.removeLayer(layers[i].layer);
+     }
+   }
+   if (!foundLayer) {
+     map.addLayer(layers[0].layer);
+   }
  }
index e8428da3a13c53823d14637385f2386f3985141a,f3c1c3607a834ddb8b5e6879e677ee63f3d46880..7a8f3da3e96407ac952197053efbe3fca1d59940
@@@ -7,6 -7,7 +7,7 @@@ OSM = 
    MAX_REQUEST_AREA: <%= MAX_REQUEST_AREA.to_json %>,
    SERVER_URL:       <%= SERVER_URL.to_json %>,
    API_VERSION:      <%= API_VERSION.to_json %>,
+   STATUS:           <%= STATUS.to_json %>,
  
    apiUrl: function (object) {
      var url = "/api/" + OSM.API_VERSION + "/" + object.type + "/" + object.id;
        mapParams.lat = (mapParams.minlat + mapParams.maxlat) / 2;
      }
  
 +    mapParams.notes = params.notes == "yes";
 +
      var scale = parseFloat(params.scale);
      if (scale > 0) {
        mapParams.zoom = Math.log(360.0 / (scale * 512.0)) / Math.log(2.0);
index ec06997f8fc0bf4f93200d7a312e004b68b5878f,654bbab970d4f9eb427f92598eb0197d13ca1ecf..413133e456d533a1c5ee3d0437795f01a9990bf0
@@@ -332,6 -332,7 +332,7 @@@ h2 
  
  #top-bar {
    position: absolute;
+   z-index: 10000;
    top: 0;
    left: 185px;
    right: 0;
@@@ -430,7 -431,7 +431,7 @@@ body.site-export #tabnav a#exportancho
    left: 15px;
  }
  
- /* Rules for OpenLayers maps */
+ /* Rules for Leaflet maps */
  
  #map {
    margin: 0px;
    padding: 0px;
  }
  
- .olControlAttribution {
-   bottom: 15px !important;
-   left: 0px !important;
-   right: 0px !important;
-   text-align: center;
- }
  #permalink {
    z-index: 10000;
    position: absolute;
    padding: 5px;
  }
  
- .site-index #map .SimpleLayerSwitcher,
- .site-index #map .olControlSimplePanZoom,
- .site-export #map .SimpleLayerSwitcher,
- .site-export #map .olControlSimplePanZoom {
 +#permalink a.disabled {
 +  color: #ccc;
 +  cursor: default;
 +  text-decoration: none;
 +}
 +
+ .site-index .leaflet-top,
+ .site-export .leaflet-top {
    top: 40px !important;
+   .leaflet-control {
+     margin-top: 0px !important;
+   }
  }
  
  .site-index #map .olControlScaleLine,
@@@ -831,23 -821,6 +827,23 @@@ table.browse_details th 
    white-space: nowrap;
  }
  
 +td.browse_comments {
 +  padding: 0px;
 +}
 +
 +td.browse_comments table {
 +  border-collapse: collapse;
 +}
 +
 +td.browse_comments table td {
 +  padding-bottom: 10px;
 +}
 +
 +td.browse_comments table td span.by {
 +  font-size: small;
 +  color: #999999;
 +}
 +
  #browse_map {
    float: right;
    width: 250px;
@@@ -1121,16 -1094,21 +1117,21 @@@ p#contributorGuidance 
  
  /* Rules for the user map */
  
- .user_map .olControlSimplePanZoom {
+ .user_map .leaflet-control-pan,
+ .user_map .leaflet-control-zoomslider {
    display: none;
  }
  
- .user_map .olControlZoom {
+ .user_map .leaflet-control-zoom {
    display: block;
  }
  
  /* Rules for user popups on maps */
  
+ .user_popup {
+   min-width: 200px;
+ }
  .user_popup p {
    padding-top: 3px;
    padding-bottom: 3px;
@@@ -1413,14 -1391,3 +1414,14 @@@ abbr.geo 
      }
    }
  }
 +
 +/* Rules for the notes interface */
 +
 +.note {
 +  width: 300px;
 +
 +  .buttons {
 +    margin-top: 5px;
 +    text-align: right;
 +  }
 +}
index d4c33fcfd42900a21cb7e67273026bc3ec2d73ad,88bf4907320a8b98247ed5d5ecd5867ad2fc2fa7..06516a16f200bbf9800da170b82fee07eec12761
@@@ -2,13 -2,6 +2,12 @@@
    <%= javascript_include_tag "index" %>
  <% end %>
  
-     <li><%= link_to t("browse.start_rjs.data_layer_name"), { :controller => :browse, :action => :start }, :id => "show_data" %></li>
 +<% unless STATUS == :api_offline or STATUS == :database_offline -%>
 +  <% content_for :editmenu do -%>
 +    <li><%= link_to t("browse.start_rjs.notes_layer_name"), notes_url(:format => :json), :id => "show_notes" %></li>
 +  <% end -%>
 +<% end -%>
 +
  <% content_for :left_menu do %>
    <li><h4><%= link_to t("site.key.map_key"), {:action => :key}, :id => "open_map_key", :title => t("site.key.map_key_tooltip") %></h4></li>
  <% end %>
    <div id="permalink">
      <a href="/" id="permalinkanchor" class="geolink llz layers object"><%= t 'site.index.permalink' %></a>
      <a href="/" id="shortlinkanchor"><%= t 'site.index.shortlink' %></a>
 +    <%= link_to t("site.index.createnote"), notes_url(:format => :json),
 +        :id => "createnoteanchor",
 +        :data => { :minzoom => 12 },
 +        :title => "javascripts.site.createnote_tooltip",
 +        :class => "geolink"
 +    %>        
    </div>
  </div>
  
index 6eed09c505537bd10cbc7201175ddd7e66ee36dc,a8fce11cadffdfb9bf23b7888fa0d430f90e6df8..04fc4cb3b09346184981d3f27aca73108949fcaf
@@@ -11,8 -11,6 +11,8 @@@
      <%= link_to t('user.view.my traces'), :controller => 'trace', :action=>'mine' %>
      <span class='count-number'><%= number_with_delimiter(@user.traces.size) %></span>
      |
 +    <%= link_to t('user.view.my notes'), :controller => 'notes', :action=> 'mine' %>
 +    |
      <%= link_to t('user.view.my diary'), :controller => 'diary_entry', :action => 'list', :display_name => @user.display_name %>
      <span class='count-number'><%= number_with_delimiter(@user.diary_entries.size) %></span>
      |
@@@ -36,8 -34,6 +36,8 @@@
      <%= link_to t('user.view.traces'), :controller => 'trace', :action => 'list', :display_name => @this_user.display_name %>
      <span class='count-number'><%= number_with_delimiter(@this_user.traces.size) %></span>
      |
 +    <%= link_to t('user.view.notes'), :controller => 'notes', :action=> 'mine' %>
 +    |
      <!-- Displaying another user's profile page -->
      <%= link_to t('user.view.send message'), :controller => 'message', :action => 'new', :display_name => @this_user.display_name %>
      |
        user_data = {
          :lon => @user.home_lon,
          :lat => @user.home_lat,
-         :icon => "marker.png",
+         :icon => image_path("marker-red.png"),
          :description => render(:partial => "popup", :object => @user, :locals => {:type => "your location"})
        }
      %>
diff --combined config/locales/de.yml
index 007850fd348b77138da65914353c605a26d4f7ad,46ca5bce5db7f36810ae1190258b5183b8841200..9861997354b89e43f30052fc9bc8facfcfeb1be4
@@@ -218,14 -218,10 +218,10 @@@ de
          node: Knoten
          relation: Relation
          way: Weg
-     start: 
-       manually_select: Einen anderen Kartenausschnitt manuell auswählen
-       view_data: Daten des aktuellen Kartenausschnitts anzeigen
      start_rjs: 
        data_frame_title: Daten
        data_layer_name: Kartendaten durchsuchen
        details: Details
-       drag_a_box: Einen Rahmen über die Karte aufziehen, um einen Bereich auszuwählen
        edited_by_user_at_timestamp: Bearbeitet von %{user} am %{timestamp}
        hide_areas: Gebiete ausblenden
        history_for_feature: Chronik für %{feature}
        history_disabled_tooltip: Reinzoomen um Änderungen für diesen Bereich anzuzeigen
        history_tooltip: Änderungen für diesen Bereich anzeigen
        history_zoom_alert: Du musst näher heranzoomen, um die Chronik zu sehen
 +    osb:
 +      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: Anlegeeen
 +      Permalink: Permalink
    layouts: 
      community: Gemeinschaft
      community_blogs: Blogs
diff --combined config/locales/en.yml
index ffd180d363462201d19e817acabadd206dac8fe3,0c21b90275d5ee383ef30a90d46517115b500172..806b9ddd3df1143b0028ea7231ef320db0c79e8f
@@@ -120,8 -120,6 +120,8 @@@ en
          next_relation_tooltip: "Next relation"
          prev_changeset_tooltip: "Previous changeset"
          next_changeset_tooltip: "Next changeset"
 +        prev_note_tooltip: "Previous note"
 +        next_note_tooltip: "Next note"
      changeset_details:
        created_at: "Created at:"
        closed_at: "Closed at:"
        relation_title: "Relation: %{relation_name}"
        download_xml: "Download XML"
        view_history: "View history"
-     start:
-       view_data: "View data for current map view"
-       manually_select: "Manually select a different area"
      start_rjs:
 +      notes_layer_name: "Browse Notes"
        data_layer_name: "Browse Map Data"
        data_frame_title: "Data"
        zoom_or_select: "Zoom in or select an area of the map to view"
-       drag_a_box: "Drag a box on the map to select an area"
+       view_data: "View data for current map view"
        manually_select: "Manually select a different area"
        hide_areas: "Hide areas"
        show_areas: "Show areas"
        download_xml: "Download XML"
        view_history: "View history"
        edit: "Edit way"
 +    note:
 +      open_title: "Unresolved issue: %{note_name}"
 +      closed_title: "Resolved issue: %{note_name}"
 +      opened: "Opened:"
 +      last_modified: "Last modified:"
 +      closed: "Closed:"
 +      at_by_html: "%{when} ago by %{user}"
 +      description: "Description:"
 +      comments: "Comments:"
    changeset:
      changeset_paging_nav:
        showing_page: "Showing page %{page}"
        greeting: "Hi,"
        hopefully_you: "Someone (possibly you) has asked for the password to be reset on this email address's openstreetmap.org account."
        click_the_link: "If this is you, please click the link below to reset your password."
 +    note_comment_notification:
 +      subject_own: "[OpenStreetMap] %{commenter} has commented on one of your notes"
 +      subject_other: "[OpenStreetMap] %{commenter} has commented on a note you are interested in"
 +      greeting: "Hi,"
 +      your_note: "%{commenter} has left a comment on one of your map notes near %{place}."
 +      commented_note: "%{commenter} has left a comment on a map note you have commented on. The note is near %{place}."
 +      details: "More details about the note can be found at %{url}."
    message:
      inbox:
        title: "Inbox"
        js_2: "OpenStreetMap uses JavaScript for its slippy map."
        permalink: Permalink
        shortlink: Shortlink
 +      createnote: Add a note
        license:
          copyright: "Copyright OpenStreetMap and contributors, under an open license"
          license_url: "http://openstreetmap.org/copyright"
        new diary entry: new diary entry
        my edits: my edits
        my traces: my traces
 +      my notes: my map notes
        my settings: my settings
        my comments: my comments
        oauth settings: oauth settings
        diary: diary
        edits: edits
        traces: traces
 +      notes: map notes
        remove as friend: remove as friend
        add as friend: add as friend
        mapper since: "Mapper since:"
        back: "View all blocks"
        revoker: "Revoker:"
        needs_view: "The user needs to log in before this block will be cleared."
 +  note:
 +    description:
 +      opened_at_by: "Created %{when} ago by %{user}"
 +      commented_at_by: "Updated %{when} ago by %{user}"
 +      closed_at_by: "Resolved %{when} ago by %{user}"
 +      reopened_at_by: "Reactivated %{when} ago by %{user}"
 +    rss:
 +      title: "OpenStreetMap Notes"
 +      description_area: "A list of notes, reported, commented on or closed in your area [(%{min_lat}|%{min_lon}) -- (%{max_lat}|%{max_lon})]"
 +      description_item: "An rss feed for note %{id}"
 +      closed: "closed note (near %{place})"
 +      new: "new note (near %{place})"
 +      comment: "new comment (near %{place})"
 +    mine:
 +      title: "Notes submitted or commented on by %{user}"
 +      heading: "%{user}'s notes"
 +      description: "Notes submitted or commented on by %{user}"
 +      id: "Id"
 +      last_changed: "Last changed"
    javascripts:
      map:
        base:
        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
 +      createnote_tooltip: Add a note to the map
 +      createnote_disabled_tooltip: Zoom in to add a note to the map
 +      createnote_zoom_alert: You must zoom in to add a note to the map
 +    notes:
 +      new:
 +        intro_1: Move the marker to the correct position and
 +        intro_2: "add your comment in the box below:"
 +        add: Add Note
 +      show:
 +        title: Note %{id}
 +        event: "%{action} by %{user} at %{time}"
 +        close: Close
 +        comment_and_close: Comment & Close
 +        comment: Comment
    redaction:
      edit:
        description: "Description"
diff --combined config/routes.rb
index cec2c3e3f4412e378ff2b4728da0b3080b8f5e37,1cdaaea4068ec15ef2ca584c94c810f60c86634f..a4a8faf43d423e50fdb929867d39623f8ab4cc84
@@@ -75,31 -75,11 +75,31 @@@ OpenStreetMap::Application.routes.draw 
    match 'api/0.6/gpx/:id/data' => 'trace#api_data', :via => :get
    
    # AMF (ActionScript) API
 -
    match 'api/0.6/amf/read' => 'amf#amf_read', :via => :post
    match 'api/0.6/amf/write' => 'amf#amf_write', :via => :post
    match 'api/0.6/swf/trackpoints' => 'swf#trackpoints', :via => :get
  
 +  # Map notes API
 +  scope "api/0.6" do
 +    resources :notes, :except => [ :new, :edit, :update ], :constraints => { :id => /\d+/ }, :defaults => { :format => "xml" } do
 +      collection do
 +        get 'search'
 +        get 'feed', :defaults => { :format => "rss" }
 +      end
 +
 +      member do
 +        post 'comment'
 +        post 'close'
 +      end
 +    end
 +
 +    match 'notes/addPOIexec' => 'notes#create', :via => :post
 +    match 'notes/closePOIexec' => 'notes#close', :via => :post
 +    match 'notes/editPOIexec' => 'notes#comment', :via => :post
 +    match 'notes/getGPX' => 'notes#index', :via => :get, :format => "gpx"
 +    match 'notes/getRSSfeed' => 'notes#feed', :via => :get, :format => "rss"
 +  end
 +
    # Data browsing
    match '/browse/start' => 'browse#start', :via => :get
    match '/browse/way/:id' => 'browse#way', :via => :get, :id => /\d+/
    match '/browse/relation/:id' => 'browse#relation', :via => :get, :id => /\d+/
    match '/browse/relation/:id/history' => 'browse#relation_history', :via => :get, :id => /\d+/
    match '/browse/changeset/:id' => 'browse#changeset', :via => :get, :as => :changeset, :id => /\d+/
 +  match '/browse/note/:id' => 'browse#note', :via => :get, :id => /\d+/, :as => "browse_note"
    match '/user/:display_name/edits' => 'changeset#list', :via => :get
    match '/user/:display_name/edits/feed' => 'changeset#feed', :via => :get, :format => :atom
 +  match '/user/:display_name/notes' => 'notes#mine', :via => :get
    match '/browse/friends' => 'changeset#list', :via => :get, :friends => true, :as => "friend_changesets"
    match '/browse/nearby' => 'changeset#list', :via => :get, :nearby => true, :as => "nearby_changesets"
    match '/browse/changesets' => 'changeset#list', :via => :get
    # export
    match '/export/start' => 'export#start', :via => :get
    match '/export/finish' => 'export#finish', :via => :post
+   match '/export/embed' => 'export#embed', :via => :get
  
    # messages
    match '/user/:display_name/inbox' => 'message#inbox', :via => :get, :as => "inbox"