]> git.openstreetmap.org Git - rails.git/commitdiff
Merge 7452:7744 from trunk.
authorTom Hughes <tom@compton.nu>
Fri, 9 May 2008 23:22:26 +0000 (23:22 +0000)
committerTom Hughes <tom@compton.nu>
Fri, 9 May 2008 23:22:26 +0000 (23:22 +0000)
25 files changed:
app/controllers/browse_controller.rb [new file with mode: 0644]
app/helpers/browse_helper.rb [new file with mode: 0644]
app/models/old_node.rb
app/views/browse/_common.rhtml [new file with mode: 0644]
app/views/browse/_common_editedby.rhtml [new file with mode: 0644]
app/views/browse/_map.rhtml [new file with mode: 0644]
app/views/browse/_member.rhtml [new file with mode: 0644]
app/views/browse/_navigation.rhtml [new file with mode: 0644]
app/views/browse/_relation_members.rhtml [new file with mode: 0644]
app/views/browse/_start.rhtml [new file with mode: 0644]
app/views/browse/_tag.rhtml [new file with mode: 0644]
app/views/browse/_tag_table.rhtml [new file with mode: 0644]
app/views/browse/index.rhtml [new file with mode: 0644]
app/views/browse/node.rhtml [new file with mode: 0644]
app/views/browse/node_history.rhtml [new file with mode: 0644]
app/views/browse/relation.rhtml [new file with mode: 0644]
app/views/browse/relation_history.rhtml [new file with mode: 0644]
app/views/browse/start.rjs [new file with mode: 0644]
app/views/browse/way.rhtml [new file with mode: 0644]
app/views/browse/way_history.rhtml [new file with mode: 0644]
config/database.yml
config/routes.rb
public/javascripts/map.js
public/openlayers/OpenStreetMap.js
public/stylesheets/site.css

diff --git a/app/controllers/browse_controller.rb b/app/controllers/browse_controller.rb
new file mode 100644 (file)
index 0000000..fd48211
--- /dev/null
@@ -0,0 +1,107 @@
+class BrowseController < ApplicationController
+  before_filter :authorize_web  
+  layout 'site'
+
+  def start 
+  end
+  
+  def index
+    @nodes = Node.find(:all, :order => "timestamp DESC", :limit=> 20)  
+  end
+  
+  def relation 
+    begin
+      @relation = Relation.find(params[:id])
+     
+      @name = @relation.tags['name'].to_s 
+      if @name.length == 0:
+       @name = "#" + @relation.id.to_s
+      end
+       
+      @title = 'Relation | ' + (@name)
+      @next = Relation.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @relation.id }] ) 
+      @prev = Relation.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @relation.id }] ) 
+    rescue ActiveRecord::RecordNotFound
+      render :nothing => true, :status => :not_found
+    end
+  end
+  
+  def relation_history
+    begin
+      @relation = Relation.find(params[:id])
+     
+      @name = @relation.tags['name'].to_s 
+      if @name.length == 0:
+       @name = "#" + @relation.id.to_s
+      end
+       
+      @title = 'Relation History | ' + (@name)
+    rescue ActiveRecord::RecordNotFound
+      render :nothing => true, :status => :not_found
+    end
+  end
+  
+  def way 
+    begin
+      @way = Way.find(params[:id])
+     
+      @name = @way.tags['name'].to_s 
+      if @name.length == 0:
+       @name = "#" + @way.id.to_s
+      end
+       
+      @title = 'Way | ' + (@name)
+      @next = Way.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @way.id }] ) 
+      @prev = Way.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @way.id }] ) 
+    rescue ActiveRecord::RecordNotFound
+      render :nothing => true, :status => :not_found
+    end
+  end
+  
+  def way_history 
+    begin
+      @way = Way.find(params[:id])
+     
+      @name = @way.tags['name'].to_s 
+      if @name.length == 0:
+       @name = "#" + @way.id.to_s
+      end
+       
+      @title = 'Way History | ' + (@name)
+    rescue ActiveRecord::RecordNotFound
+      render :nothing => true, :status => :not_found
+    end
+  end
+
+  def node 
+    begin
+      @node = Node.find(params[:id])
+     
+      @name = @node.tags_as_hash['name'].to_s 
+      if @name.length == 0:
+       @name = "#" + @node.id.to_s
+      end
+       
+      @title = 'Node | ' + (@name)
+      @next = Node.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @node.id }] ) 
+      @prev = Node.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @node.id }] ) 
+    rescue ActiveRecord::RecordNotFound
+      render :nothing => true, :status => :not_found
+    end
+  end
+  
+  def node_history 
+    begin
+      @node = Node.find(params[:id])
+     
+      @name = @node.tags_as_hash['name'].to_s 
+      if @name.length == 0:
+       @name = "#" + @node.id.to_s
+      end
+       
+      @title = 'Node History | ' + (@name)
+    rescue ActiveRecord::RecordNotFound
+      render :nothing => true, :status => :not_found
+    end
+  end
+end
diff --git a/app/helpers/browse_helper.rb b/app/helpers/browse_helper.rb
new file mode 100644 (file)
index 0000000..c86ad5b
--- /dev/null
@@ -0,0 +1,2 @@
+module BrowseHelper
+end
index 2c3e93b2075fc5de263923694f50221123734ec1..b6391a3d1b06c6921f835b2c0e5e57b5dc172592 100644 (file)
@@ -48,4 +48,12 @@ class OldNode < GeoRecord
     el1['timestamp'] = self.timestamp.xmlschema
     return el1
   end
+  
+  def tags_as_hash
+    hash = {}
+    Tags.split(self.tags) do |k,v|
+      hash[k] = v
+    end
+    hash
+  end
 end
diff --git a/app/views/browse/_common.rhtml b/app/views/browse/_common.rhtml
new file mode 100644 (file)
index 0000000..f237bfe
--- /dev/null
@@ -0,0 +1,13 @@
+<% if obj.visible %>
+<%= render :partial => 'map', :locals => { :type => type, :id => obj.id } %>
+<% else %>
+Deleted
+<% end %>
+<ul>
+<% if obj.visible %>
+<li><%= link_to h("API"), :controller => type, :action => "read", :id => obj.id %></li>
+<% end %>
+<li><%= link_to h("History"), :controller => "old_" + type, :action => "history", :id => obj.id %> 
+    (<%= link_to h("HTML"), :action => type+"_history", :id => obj.id %>)</li>
+</ul>
+<%= render :partial => 'common_editedby', :locals => { :obj => obj } %>
diff --git a/app/views/browse/_common_editedby.rhtml b/app/views/browse/_common_editedby.rhtml
new file mode 100644 (file)
index 0000000..0f00f3e
--- /dev/null
@@ -0,0 +1,4 @@
+Last edited: <%= h(obj.timestamp) %>
+<% if obj.user.data_public %>
+by <%= link_to h(obj.user.display_name), :controller => 'user', :action => 'view' , :display_name => obj.user.display_name %>
+<% end %>
diff --git a/app/views/browse/_map.rhtml b/app/views/browse/_map.rhtml
new file mode 100644 (file)
index 0000000..a0fcc06
--- /dev/null
@@ -0,0 +1,44 @@
+<%= javascript_include_tag '/openlayers/OpenLayers.js' %>
+<%= javascript_include_tag '/openlayers/OpenStreetMap.js' %>
+<%= javascript_include_tag 'map.js' %>
+<div style="float:right">
+<div id="small_map" style="width:250px; height: 300px; border: solid 1px black">
+</div>
+<script type="text/javascript">
+  function init() {
+  var obj_type = '<%= type %>';
+  var obj_id = <%= id %>;
+  var url = "/api/<%= "#{API_VERSION}" %>/<%= type %>/<%= id %>";
+  if (obj_type != "node") {
+    url += "/full";
+  }
+  var map = createMap('small_map', {controls: [new OpenLayers.Control.Navigation()]});
+  var osm_layer = new OpenLayers.Layer.GML("OSM", url, {format: OpenLayers.Format.OSM, projection: new OpenLayers.Projection("EPSG:4326")});
+  osm_layer.events.register("loadend", osm_layer, function() {
+    $("loading").innerHTML = "";
+    if (this.features.length) { 
+        var extent =  this.features[0].geometry.getBounds();
+        for (var i = 1; i < this.features.length; i++) {
+            extent.extend(this.features[i].geometry.getBounds());
+        }
+        if (extent) {
+               this.map.zoomToExtent(extent);
+        } else {
+               this.map.zoomToMaxExtent();
+       }
+       var center = getMapCenter();
+        $("larger_map").href = '/?lat='+center.lat+'&lon='+center.lon+'&zoom='+this.map.getZoom();
+        $("larger_map").innerHTML = "View Larger Map";
+    } else {
+        $("small_map").style.display = "none";
+    }
+  })   
+  map.addLayer(osm_layer);
+  osm_layer.loadGML();
+  osm_layer.loaded = true;
+}
+window.onload = init;
+</script>
+<span id="loading">Loading...</span>
+<a id="larger_map" href=""></a>
+</div>
diff --git a/app/views/browse/_member.rhtml b/app/views/browse/_member.rhtml
new file mode 100644 (file)
index 0000000..29a72b1
--- /dev/null
@@ -0,0 +1,5 @@
+<tr>
+  <td><%= link_to member.member_id.to_s, :action => member.member_type, :id => member.member_id %></td>
+  <td><%= h(member.member_type) %></td>
+  <td><%= h(member.member_role) %></td>
+</tr> 
diff --git a/app/views/browse/_navigation.rhtml b/app/views/browse/_navigation.rhtml
new file mode 100644 (file)
index 0000000..269184e
--- /dev/null
@@ -0,0 +1,13 @@
+<div style="float:right; text-align:center; width: 250px;">
+<% if @prev %>
+< 
+<%= link_to @prev.id.to_s, :action => type, :id => @prev.id %>
+<% end %>
+<% if @prev and @next %>
+| 
+<% end %>
+<% if @next %>
+<%= link_to @next.id.to_s, :action => type, :id => @next.id %>
+>
+<% end %>
+</div>
diff --git a/app/views/browse/_relation_members.rhtml b/app/views/browse/_relation_members.rhtml
new file mode 100644 (file)
index 0000000..ebe20ba
--- /dev/null
@@ -0,0 +1,11 @@
+<% if members.length != 0 %>
+<h3>Members</h3> 
+<table id="keyvalue" cellpadding="3">
+  <tr>
+    <th>ID</th>
+    <th>Type</th>
+    <th>Role</th>
+  </tr>
+  <%= render :partial => 'member', :collection => members  %>
+</table>
+<% end %>
diff --git a/app/views/browse/_start.rhtml b/app/views/browse/_start.rhtml
new file mode 100644 (file)
index 0000000..a6030a5
--- /dev/null
@@ -0,0 +1,12 @@
+<div style="padding:0px 10px">
+    <div style="text-align: center">
+    <p style="margin-top: 10px">
+      <a id="use_map" display="hidden" href="#">View Data For Current Map View</a>
+      <br />
+      <a id='drag_box' href="#">Manually select a different area</a>  
+    </p>
+</div>
+<div id="status"></div>
+<div id="object">
+</div>
+</div>
diff --git a/app/views/browse/_tag.rhtml b/app/views/browse/_tag.rhtml
new file mode 100644 (file)
index 0000000..009d39e
--- /dev/null
@@ -0,0 +1,4 @@
+<tr>
+  <td><%= h(tag[0]) %></td><td><%= h(tag[1]) %></td>
+</tr> 
+
diff --git a/app/views/browse/_tag_table.rhtml b/app/views/browse/_tag_table.rhtml
new file mode 100644 (file)
index 0000000..dca1c0a
--- /dev/null
@@ -0,0 +1,10 @@
+<% if tags.length != 0 %>
+<h3>Tags</h3>
+<table id="keyvalue" cellpadding="3">
+  <tr>
+    <th>Key</th>
+    <th>Value</th>
+  </tr>
+  <%= render :partial => 'tag', :collection => tags  %>
+</table>
+<% end %>
diff --git a/app/views/browse/index.rhtml b/app/views/browse/index.rhtml
new file mode 100644 (file)
index 0000000..2cd5cc9
--- /dev/null
@@ -0,0 +1,12 @@
+<h2><%= @nodes.length %> Recently Changed Nodes</h2> 
+<ul>
+<% @nodes.each do |node| 
+   name = node.tags_as_hash['name'].to_s 
+   if name.length == 0:
+     name = "(No name)"
+   end
+   name = name + " - " + node.id.to_s 
+%>
+   <li><%= link_to h(name), :action => "node", :id => node.id %></li>
+<% end %>
+</ul>
diff --git a/app/views/browse/node.rhtml b/app/views/browse/node.rhtml
new file mode 100644 (file)
index 0000000..c050cf0
--- /dev/null
@@ -0,0 +1,15 @@
+<%= render :partial => 'navigation', :locals => { :type => "node" } %>
+<h2>Node Browser: <%= h(@name) %></h2>
+<%= render :partial => 'common', :locals => { :obj => @node, :type => "node" } %>
+<%= render :partial => 'tag_table', :locals => { :tags => @node.tags_as_hash } %>
+<% if @node.ways.length != 0 %> 
+  <br style="clear:both" />
+  <div style="float:right; width: 250px;">
+  <h2>Part of:</h2>
+  <ul>
+    <% @node.ways.each do |way| %>
+    <li> <%= link_to "Way " + way.id.to_s, :action => "way", :id => way.id.to_s %> </li>
+    <% end %>
+  </ul>
+  </div>
+<% end %>
diff --git a/app/views/browse/node_history.rhtml b/app/views/browse/node_history.rhtml
new file mode 100644 (file)
index 0000000..ad46202
--- /dev/null
@@ -0,0 +1,8 @@
+<h2>Node History: <%= h(@name) %></h2>
+<%= render :partial => 'common', :locals => { :obj => @node, :type => "node" } %>
+<h2>Hisorical Versions</h2> 
+<% @node.old_nodes.reverse.each do |node| %>
+<%= render :partial => 'common_editedby', :locals => { :obj => node } %>
+<%= render :partial => 'tag_table', :locals => { :tags => node.tags_as_hash } %>
+<hr />
+<% end %>
diff --git a/app/views/browse/relation.rhtml b/app/views/browse/relation.rhtml
new file mode 100644 (file)
index 0000000..574a4ea
--- /dev/null
@@ -0,0 +1,5 @@
+<%= render :partial => 'navigation', :locals => { :type => "relation" } %>
+<h2>Relation Browser: <%= h(@name) %></h2>
+<%= render :partial => 'common', :locals => { :obj => @relation, :type => "relation" } %>
+<%= render :partial => 'tag_table', :locals => { :tags => @relation.tags } %>
+<%= render :partial => 'relation_members', :locals => { :members => @relation.relation_members } %>
diff --git a/app/views/browse/relation_history.rhtml b/app/views/browse/relation_history.rhtml
new file mode 100644 (file)
index 0000000..f3a75cd
--- /dev/null
@@ -0,0 +1,9 @@
+<h2>Relation History: <%= h(@name) %></h2>
+<%= render :partial => 'common', :locals => { :obj => @relation, :type => "relation" } %>
+<h2>Hisorical Versions</h2> 
+<% @relation.old_relations.reverse.each do |relation| %>
+<%= render :partial => 'common_editedby', :locals => { :obj => relation } %>
+<%= render :partial => 'tag_table', :locals => { :tags => relation.tags } %>
+<%= render :partial => 'relation_members', :locals => { :members => relation.old_members } %>
+<hr />
+<% end %>
diff --git a/app/views/browse/start.rjs b/app/views/browse/start.rjs
new file mode 100644 (file)
index 0000000..80a691b
--- /dev/null
@@ -0,0 +1,359 @@
+page.replace_html :sidebar_title, 'Data'
+page.replace_html :sidebar_content, :partial => 'start'
+page << <<EOJ
+    
+    var gml, sf, objList, currentFeature, featureList, mode = "auto", currentBounds, browsing;
+    OpenLayers.Feature.Vector.style['default'].strokeWidth = 3;
+    OpenLayers.Feature.Vector.style['default'].cursor = "pointer";
+    
+    function start() {
+        openSidebar({ onclose: stopBrowse });
+        var vectors = new OpenLayers.Layer.Vector();
+    
+        box = new OpenLayers.Control.DrawFeature(vectors, OpenLayers.Handler.RegularPolygon, { 
+          handlerOptions: {
+            sides: 4,
+            snapAngle: 90,
+            irregular: true,
+            persist: true,
+            callbacks: { done: endDrag }
+          }
+        });
+        map.addControl(box);
+        map.events.register("moveend", map, showData);
+        map.events.triggerEvent("moveend");
+        map.dataLayer.stopBrowse = stopBrowse;
+        browsing = true;
+    }
+
+    function showData() {
+        if (mode == "manual") { return; }
+        if (map.getZoom() >= 15) {
+            useMap();
+        } else {
+            $("status").innerHTML = "Zoom in or Select an area of the map to view.";
+        }    
+    }
+    
+    function stopBrowse() {
+        if (browsing) {
+            browsing = false; 
+            map.dataLayer.stopBrowse = null;
+            if (gml) {
+                gml.destroy();
+                gml = null; 
+            } 
+            if (sf) {   
+                sf.destroy();  
+                sf = null;
+            } 
+           if (box) {
+               box.destroy();
+               box = null;
+            }          
+            if (currentFeature) {
+                currentFeature.destroy(); 
+                currentFeature = null; 
+            }
+            map.dataLayer.setVisibility(false);
+            map.events.unregister("moveend", map, showData);
+        }    
+    }
+    
+    function startDrag() {
+      $("drag_box").innerHTML='Drag a box on the map to select an area';
+       box.activate(); 
+       return false;
+    };
+    $("drag_box").onclick = startDrag;
+    
+    function useMap() {
+        var bounds = map.getExtent();
+        var projected = bounds.clone().transform(map.getProjectionObject(), epsg4326);
+        if (!currentBounds || !currentBounds.containsBounds(projected)) {
+            var center = bounds.getCenterLonLat();
+            var tileWidth = bounds.getWidth() * 1.2;
+            var tileHeight = bounds.getHeight() * 1.2;
+            var tileBounds =
+                new OpenLayers.Bounds(center.lon - (tileWidth / 2),
+                                      center.lat - (tileHeight / 2),
+                                      center.lon + (tileWidth / 2),
+                                      center.lat + (tileHeight / 2));
+
+            currentBounds = tileBounds;
+            getData(tileBounds);
+            mode = "auto";
+            $("use_map").style.display="none";
+        }
+        return false;
+    }
+    $("use_map").onclick = useMap;
+    
+    function endDrag(bbox) {
+        var bounds = bbox.getBounds();
+        box.deactivate();
+        currentBounds = bounds;
+        getData(bounds);
+        $("drag_box").innerHTML = "Manually select a different area";
+        mode = "manual";  
+        $("use_map").style.display="inline";
+    }
+    
+    function displayFeatureWarning() {
+        $("status").innerHTML = "";
+        var div = document.createElement("div");
+        var p = document.createElement("p");
+        p.appendChild(document.createTextNode("You have loaded an area which contains " + featureList.length + " features. In general, some browsers may not cope well with displaying this quantity of data. Generally, browsers work best at displaying less than 100 features at a time: doing anything else may make your browser slow/unresponsive. If you are sure you want to display this data, you may do so by clicking the button below.")); 
+        div.appendChild(p);
+        var input = document.createElement("input");
+        input.type = "submit";
+        input.value = "Load Data";
+        input.onclick = loadFeatureList;
+        div.appendChild(input); 
+        $("object").innerHTML="";
+        $("object").appendChild(div);
+    }
+    
+    function loadFeatureList() {
+        gml.addFeatures(featureList);
+        gml.events.triggerEvent("loadend");
+        return false;
+    }    
+
+    function customDataLoader(request) { 
+        if (!browsing) { return; } 
+        var doc = request.responseXML;
+        
+        if (!doc || !doc.documentElement) {
+            doc = request.responseText;
+        }
+        
+        var options = {};
+        
+        OpenLayers.Util.extend(options, this.formatOptions);
+        if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
+            options.externalProjection = this.projection;
+            options.internalProjection = this.map.getProjectionObject();
+        }    
+        
+        var gml = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
+        var features = gml.read(doc);
+        if (!this.maxFeatures || features.length <= this.maxFeatures) {
+            this.addFeatures(features);
+            this.events.triggerEvent("loadend");
+            featureList = []; 
+        } else {
+            featureList = features;
+            displayFeatureWarning();
+        }
+    }
+
+    function getData(bounds) {
+        
+        bounds.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
+        var size = bounds.getWidth() * bounds.getHeight(); 
+        if (size > 0.25) {
+            $("status").innerHTML = "Unable to load: Bounding box size of " + size + " is too large. (Must be smaller than 0.25)<br />"; 
+            return;
+        }
+
+        var url = "/api/0.5/map?bbox="+bounds.toBBOX();
+        
+        loadGML(url);
+    }
+    function loadGML(url) {
+        $("status").innerHTML = "Loading...";
+        $("object").innerHTML = "";
+        if (!gml) {
+            var style = new OpenLayers.Style();
+            style.addRules([new OpenLayers.Rule( 
+              {'symbolizer': 
+                {"Polygon": {'fillColor': '#ff0000', 'strokeColor': '#ff0000'},
+                 "Line": {'fillColor': '#ffff00', 'strokeColor': '#000000', strokeOpacity: '0.4'},
+                 "Point": {'fillColor': '#00ff00', 'strokeColor': '#00ff00'}}
+              }
+            )]);
+            gml = new OpenLayers.Layer.GML("Data",url, 
+                    {format: OpenLayers.Format.OSM, formatOptions: {checkTags: true},
+                     maxFeatures: 100, requestSuccess: customDataLoader,
+                     displayInLayerSwitcher: false,
+                     styleMap: new OpenLayers.StyleMap({'default': style, 'select': {'strokeColor': '#0000ff', strokeWidth: 8}})
+                    }
+            );
+            gml.events.register("loadend", gml, dataLoaded );
+            map.addLayer(gml);
+            
+            sf = new OpenLayers.Control.SelectFeature(gml, {'onSelect': onFeatureSelect});
+            sf.handler.stopDown = false;
+            sf.handler.stopUp = false;
+            map.addControl(sf);
+            sf.activate();
+             
+        } else {
+            gml.setUrl(url);
+        }
+
+        currentFeature = null;
+    }
+    function dataLoaded() {
+        if (!browsing) { return; } 
+        $("status").innerHTML = "Loaded."
+        
+        objList = document.createElement("div")
+
+        list = document.createElement("ul");
+        for (var i = 0; i < this.features.length; i++) {
+            var feature = this.features[i]; 
+            
+            // Type, for linking
+            var type ="way";
+            if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+                type = "node";
+            }   
+            var nice_name = type.substr(0,1).toUpperCase() + type.substr(1,type.length); 
+            var li = document.createElement("li");
+            li.appendChild(document.createTextNode(nice_name + " "));
+            
+            // Link, for viewing in the tab
+            var link = document.createElement("a");
+            link.href =  "/browse/" + type + "/" + feature.osm_id; 
+            var name = feature.attributes.name || feature.osm_id;
+            link.appendChild(document.createTextNode(name));
+            link.feature = feature;
+            link.onclick = OpenLayers.Function.bind(viewFeatureLink, link);   
+            li.appendChild(link);
+
+            list.appendChild(li);
+        }
+        objList.appendChild(list)
+        var link = document.createElement("a");
+        link.href = this.url;
+        link.appendChild(document.createTextNode("API"));
+        objList.appendChild(link)
+        $("object").innerHTML = "";
+        $("object").appendChild(objList); 
+
+    }
+    
+    function viewFeatureLink() {
+        var layer = this.feature.layer;
+        for (var i = 0; i < layer.selectedFeatures.length; i++) {
+            var f = layer.selectedFeatures[i]; 
+            layer.drawFeature(f, layer.styleMap.createSymbolizer(f, "default"));
+        }
+        onFeatureSelect(this.feature);
+        if (mode != "auto") {
+            map.setCenter(this.feature.geometry.getBounds().getCenterLonLat()); 
+        }
+        return false;
+    }
+    
+    function loadObjList() {
+        $("object").innerHTML="";
+        $("object").appendChild(objList);
+        return false;
+    }
+      
+    function onFeatureSelect(feature) {
+        // Unselect previously selected feature
+        if (currentFeature) {
+          currentFeature.layer.drawFeature(
+            currentFeature, currentFeature.layer.styleMap.createSymbolizer(currentFeature, "default")
+          );
+        }
+
+        // Redraw in selected style
+        feature.layer.drawFeature(
+          feature, feature.layer.styleMap.createSymbolizer(feature, "select")
+        );
+
+        // If the current object is the list, don't innerHTML="", since that could clar it.   
+        if ($("object").firstChild == objList) { 
+            $("object").removeChild(objList);
+        } else { 
+            $("object").innerHTML = "";
+        }   
+        
+        // Create a link back to the object list
+        var div = document.createElement("div");
+        var link = document.createElement("a");
+        link.href="#";
+        link.onclick = loadObjList;
+        link.appendChild(document.createTextNode("Back to Object List"));
+        div.appendChild(link)
+        $("object").appendChild(div);    
+        
+        var type = "way";
+        if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+            type = "node";
+        }    
+        
+        var link = document.createElement("a");   
+        link.href =  "/browse/"+type+"/"+feature.osm_id;
+        link.appendChild(document.createTextNode("Database entry for " + feature.osm_id));
+        
+        var div = document.createElement("div");
+        div.style.marginTop = "20px"
+        div.appendChild(link);
+
+        $("object").appendChild(div);
+
+        // Now the list of attributes
+        var ul = document.createElement("ul");
+        for (var key in feature.attributes) {
+            var li = document.createElement("li");
+            var b = document.createElement("b");
+            b.appendChild(document.createTextNode(key));
+            li.appendChild(b);
+            li.appendChild(document.createTextNode(": " + feature.attributes[key]));
+            ul.appendChild(li);
+        }
+        
+        $("object").appendChild(ul);
+        
+        var link = document.createElement("a");   
+        link.href =  "/browse/"+type+"/"+feature.osm_id+"/history";
+        link.appendChild(document.createTextNode("History"));
+        ul.appendChild(li);
+        link.onclick = OpenLayers.Function.bind(loadHistory, {type: type, feature: feature, link: link});
+        
+        $("object").appendChild(link);
+
+        // Stash the currently drawn feature
+        currentFeature = feature; 
+    }   
+    function loadHistory() {
+        this.link.href = "";
+        this.link.innerHTML = "Wait...";
+        new Ajax.Request("/api/0.5/"+this.type+"/"+this.feature.osm_id+"/history", {onComplete: OpenLayers.Function.bind(displayHistory, this)});
+        return false;
+    }
+    function displayHistory(request) {
+        if (currentFeature.osm_id != this.feature.osm_id || $("object").firstChild == objList)  { 
+            return false;
+        } 
+        this.link.parentNode.removeChild(this.link);
+        var doc = request.responseXML;
+        var div = document.createElement("div");
+        var h3 = document.createElement("h3"); 
+        h3.appendChild(document.createTextNode("History"));
+        div.appendChild(h3);
+        var nodes = doc.getElementsByTagName(this.type);
+        var history = document.createElement("ul");  
+        for (var i = nodes.length - 1; i >= 0; i--) {
+            var user = nodes[i].getAttribute("user") || "private user";
+            var timestamp = nodes[i].getAttribute("timestamp");
+            var item = document.createElement("li");
+            item.appendChild(document.createTextNode("Edited by " + user + " at " + timestamp));
+            history.appendChild(item);
+        }
+        div.appendChild(history);
+        var link = document.createElement("a");
+        link.appendChild(document.createTextNode("History entry for " + this.feature.osm_id));
+        link.href = "/browse/"+this.type+"/"+this.feature.osm_id+"/history";
+        div.appendChild(link);
+        $("object").appendChild(div); 
+    }
+    
+    start();
+EOJ
diff --git a/app/views/browse/way.rhtml b/app/views/browse/way.rhtml
new file mode 100644 (file)
index 0000000..e1c3060
--- /dev/null
@@ -0,0 +1,16 @@
+<%= render :partial => 'navigation', :locals => { :type => "way" } %>
+<h2>Way Browser: <%= h(@name) %></h2>
+<%= render :partial => 'common', :locals => { :obj => @way, :type => "way" } %>
+<%= render :partial => 'tag_table', :locals => { :tags => @way.tags } %>
+
+<% if @way.nodes.length != 0 %> 
+  <br style="clear:both" />
+  <div style="float:right; width: 250px;">
+  <h2>Parts:</h2>
+  <ul>
+    <% @way.nodes.each do |node| %>
+    <li> <%= link_to "Node " + node.id.to_s, :action => "node", :id => node.id.to_s %> </li>
+    <% end %>
+  </ul>
+  </div>
+<% end %>
diff --git a/app/views/browse/way_history.rhtml b/app/views/browse/way_history.rhtml
new file mode 100644 (file)
index 0000000..32aadb3
--- /dev/null
@@ -0,0 +1,8 @@
+<h2>Way History: <%= h(@name) %></h2>
+<%= render :partial => 'common', :locals => { :obj => @way, :type => "way" } %>
+<h2>Hisorical Versions</h2> 
+<% @way.old_ways.reverse.each do |way| %>
+<%= render :partial => 'common_editedby', :locals => { :obj => way } %>
+<%= render :partial => 'tag_table', :locals => { :tags => way.tags } %>
+<hr />
+<% end %>
index b884f3b938fea8c5ea541e0d4af5fbbc16529dd7..19b5dd8d5227ae5c04720b61afd9a101661c9cbe 100644 (file)
@@ -12,9 +12,8 @@
 #   http://dev.mysql.com/doc/refman/5.0/en/old-client.html
 development:
   adapter: mysql
-  database: openstreetmap
-  username: openstreetmap
-  password: openstreetmap
+  database: osm
+  user: root  
   host: localhost
 
 # Warning: The database defined as 'test' will be erased and
index dc26259fa8ffb76ce8263b01d863e02c58f71710..c23509372c8a2c4c9ba761e433332729df242f43 100644 (file)
@@ -57,6 +57,16 @@ ActionController::Routing::Routes.draw do |map|
   map.connect "api/#{API_VERSION}/amf", :controller =>'amf', :action =>'talk'
   map.connect "api/#{API_VERSION}/swf/trackpoints", :controller =>'swf', :action =>'trackpoints'
   
+  # Data browsing
+  map.connect '/browse/start', :controller => 'browse', :action => 'start'
+  map.connect '/browse', :controller => 'browse', :action => 'index'
+  map.connect '/browse/way/:id', :controller => 'browse', :action => 'way', :id => /\d+/
+  map.connect '/browse/way/:id/history', :controller => 'browse', :action => 'way_history', :id => /\d+/
+  map.connect '/browse/node/:id', :controller => 'browse', :action => 'node', :id => /\d+/
+  map.connect '/browse/node/:id/history', :controller => 'browse', :action => 'node_history', :id => /\d+/
+  map.connect '/browse/relation/:id', :controller => 'browse', :action => 'relation', :id => /\d+/
+  map.connect '/browse/relation/:id/history', :controller => 'browse', :action => 'relation_history', :id => /\d+/
+  
   # web site
 
   map.connect '/', :controller => 'site', :action => 'index'
index db5b8561638afd45ba4fa403c881b11196ddcf9f..c7f381d846df32e1b68863968d4ea9b3d5c566b3 100644 (file)
@@ -7,9 +7,10 @@ OpenLayers._getScriptLocation = function () {
    return "/openlayers/";
 }
 
-function createMap(divName) {
+function createMap(divName, options) {
+   if (!options) { options = {} }
    map = new OpenLayers.Map(divName, {
-      controls: [
+      controls: options.controls || [
          new OpenLayers.Control.ArgParser(),
          new OpenLayers.Control.Attribution(),
          new OpenLayers.Control.LayerSwitcher(),
@@ -18,7 +19,7 @@ function createMap(divName) {
          new OpenLayers.Control.ScaleLine()
       ],
       units: "m",
-      maxResolution: 156543,
+      maxResolution: 156543.0339,
       numZoomLevels: 20
    });
 
@@ -39,6 +40,9 @@ function createMap(divName) {
       wrapDateLine: true
    });
    map.addLayer(maplint);
+   var data = new OpenLayers.Layer.Data("Data", {'visibility': false});
+   map.addLayer(data); 
+   map.dataLayer = data;
 
    var numZoomLevels = Math.max(mapnik.numZoomLevels, osmarender.numZoomLevels);
    markers = new OpenLayers.Layer.Markers("Markers", {
index c2acf2e0c8ef7035fe6d25cc20ca9265e6e28fc3..f472d3fc14631d543fd4215b8448b9cb71f78e0d 100644 (file)
@@ -48,8 +48,8 @@ OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.TMS, {
     initialize: function(name, url, options) {
         options = OpenLayers.Util.extend({
             attribution: "Data by <a href='http://openstreetmap.org/'>OpenStreetMap</a>",
-            maxExtent: new OpenLayers.Bounds(-20037508,-20037508,20037508,20037508),
-            maxResolution: 156543,
+            maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
+            maxResolution: 156543.0339,
             units: "m",
             projection: "EPSG:900913",
             transitionEffect: "resize"
@@ -182,3 +182,19 @@ OpenLayers.Layer.OSM.Maplint = OpenLayers.Class(OpenLayers.Layer.OSM, {
 
     CLASS_NAME: "OpenLayers.Layer.OSM.Maplint"
 });
+
+OpenLayers.Layer.Data = OpenLayers.Class(OpenLayers.Layer, { 
+    setVisibility: function(vis) {
+        var oldvis = this.visibility;
+        OpenLayers.Layer.prototype.setVisibility.apply(this, arguments);
+        if (!this.map) { return; }
+        if (vis && !oldvis) {
+            new Ajax.Request('/browse/start', {asynchronous:true, evalScripts:true}); 
+        } else {
+            if (this.stopBrowse) {
+                this.stopBrowse();
+                closeSidebar(); 
+            }    
+        }    
+    }
+});    
index 2ede490efc557377171b7deecc156fa285495741..801654877261033a8a79ca37b694de3162181576 100644 (file)
@@ -1,4 +1,4 @@
-a {
+a m
   color: #0000ff;
   text-decoration: none;
 }