Merge changes from trunk 7673:8632.
This commit is contained in:
commit
5f8ab9e924
62 changed files with 1456 additions and 373 deletions
|
@ -123,7 +123,9 @@ class AmfController < ApplicationController
|
|||
points = nodes_not_used_in_area.collect { |n| [n.id, n.lon_potlatch(baselong,masterscale), n.lat_potlatch(basey,masterscale), n.tags_as_hash] }
|
||||
|
||||
# find the relations used by those nodes and ways
|
||||
relation_ids = (Relation.find_for_nodes_and_ways(nodes_in_area.collect {|n| n.id}, way_ids)).collect {|n| n.id}.uniq
|
||||
relations = nodes_in_area.collect { |node| node.containing_relations.visible }.flatten +
|
||||
way_ids.collect { |id| Way.find(id).containing_relations.visible }.flatten
|
||||
relation_ids = relations.collect { |relation| relation.id }.uniq
|
||||
|
||||
[way_ids,points,relation_ids]
|
||||
end
|
||||
|
@ -376,10 +378,11 @@ class AmfController < ApplicationController
|
|||
|
||||
RAILS_DEFAULT_LOGGER.info(" Message: putway, id=#{originalway}")
|
||||
|
||||
# -- Check for null IDs or short ways
|
||||
# -- Check for null IDs, short ways or lats=90
|
||||
|
||||
points.each do |a|
|
||||
if a[2]==0 or a[2].nil? then return -2,"Server error - node with id 0 found in way #{originalway}." end
|
||||
if coord2lat(a[1],masterscale,basey)==90 then return -2,"Server error - node with lat -90 found in way #{originalway}." end
|
||||
end
|
||||
|
||||
if points.length<2 then return -2,"Server error - way is only #{points.length} points long." end
|
||||
|
@ -638,8 +641,8 @@ class AmfController < ApplicationController
|
|||
# which means the SWF needs to allocate new ids
|
||||
# - if it's an invisible node, we can reuse the old node id
|
||||
|
||||
# get node list from specified version of way,
|
||||
# and the _current_ lat/long/tags of each node
|
||||
# ----- get node list from specified version of way,
|
||||
# and the _current_ lat/long/tags of each node
|
||||
|
||||
row=ActiveRecord::Base.connection.select_one("SELECT timestamp FROM ways WHERE version=#{version} AND id=#{id}")
|
||||
waytime=row['timestamp']
|
||||
|
@ -654,31 +657,31 @@ class AmfController < ApplicationController
|
|||
EOF
|
||||
rows=ActiveRecord::Base.connection.select_all(sql)
|
||||
|
||||
# if historic (full revert), get the old version of each node
|
||||
# - if it's in another way now, generate a new id
|
||||
# - if it's not in another way, use the old ID
|
||||
# ----- if historic (full revert), get the old version of each node
|
||||
# - if it's in another way now, generate a new id
|
||||
# - if it's not in another way, use the old ID
|
||||
|
||||
if historic then
|
||||
rows.each_index do |i|
|
||||
sql=<<-EOF
|
||||
SELECT latitude*0.0000001 AS latitude,longitude*0.0000001 AS longitude,tags,cwn.id AS currentway
|
||||
FROM nodes n
|
||||
LEFT JOIN current_way_nodes cwn
|
||||
ON cwn.node_id=n.id
|
||||
LEFT JOIN current_way_nodes cwn
|
||||
ON cwn.node_id=n.id AND cwn.id!=#{id}
|
||||
WHERE n.id=#{rows[i]['id']}
|
||||
AND n.timestamp<="#{waytime}"
|
||||
AND cwn.id!=#{id}
|
||||
ORDER BY n.timestamp DESC
|
||||
ORDER BY n.timestamp DESC
|
||||
LIMIT 1
|
||||
EOF
|
||||
row=ActiveRecord::Base.connection.select_one(sql)
|
||||
unless row.nil? then
|
||||
nx=row['longitude'].to_f
|
||||
ny=row['latitude'].to_f
|
||||
nx=row['longitude'].to_f
|
||||
ny=row['latitude'].to_f
|
||||
if (!row.nil?)
|
||||
if (row['currentway'] && (nx!=rows[i]['longitude'].to_f or ny!=rows[i]['latitude'].to_f or row['tags']!=rows[i]['tags'])) then rows[i]['id']=-1 end
|
||||
rows[i]['longitude']=nx
|
||||
rows[i]['latitude' ]=ny
|
||||
rows[i]['tags' ]=row['tags']
|
||||
end
|
||||
end
|
||||
rows[i]['longitude']=nx
|
||||
rows[i]['latitude' ]=ny
|
||||
rows[i]['tags' ]=row['tags']
|
||||
end
|
||||
end
|
||||
rows
|
||||
|
|
|
@ -124,8 +124,6 @@ class ApiController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
relations = Array.new
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
|
||||
# get ways
|
||||
|
@ -170,19 +168,15 @@ class ApiController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
relations = Relation.find_for_nodes_and_ways(visible_nodes.keys, way_ids)
|
||||
relations = visible_nodes.values.collect { |node| node.containing_relations.visible }.flatten +
|
||||
way_ids.collect { |id| Way.find(id).containing_relations.visible }.flatten
|
||||
|
||||
# we do not normally return the "other" partners referenced by an relation,
|
||||
# e.g. if we return a way A that is referenced by relation X, and there's
|
||||
# another way B also referenced, that is not returned. But we do make
|
||||
# an exception for cases where an relation references another *relation*;
|
||||
# in that case we return that as well (but we don't go recursive here)
|
||||
relation_ids = relations.collect { |relation| relation.id }
|
||||
if relation_ids.length > 0
|
||||
relations += Relation.find_by_sql("select e.* from current_relations e,current_relation_members em where " +
|
||||
"e.visible=1 and " +
|
||||
"em.id = e.id and em.member_type='relation' and em.member_id in (#{relation_ids.join(',')})")
|
||||
end
|
||||
relations += relations.collect { |relation| relation.containing_relations.visible }.flatten
|
||||
|
||||
# this "uniq" may be slightly inefficient; it may be better to first collect and output
|
||||
# all node-related relations, then find the *not yet covered* way-related ones etc.
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
# Likewise, all the methods added will be available for all controllers.
|
||||
class ApplicationController < ActionController::Base
|
||||
|
||||
if OSM_STATUS == :database_offline
|
||||
session :off
|
||||
end
|
||||
|
||||
def authorize_web
|
||||
if session[:user]
|
||||
@user = User.find(session[:user])
|
||||
|
@ -39,8 +43,14 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def check_database_availability(need_api = false)
|
||||
if OSM_STATUS == :database_offline or (need_api and OSM_STATUS == :api_offline)
|
||||
redirect_to :controller => 'site', :action => 'offline'
|
||||
end
|
||||
end
|
||||
|
||||
def check_read_availability
|
||||
if API_STATUS == :offline
|
||||
if OSM_STATUS == :database_offline or OSM_STATUS == :api_offline
|
||||
response.headers['Error'] = "Database offline for maintenance"
|
||||
render :nothing => true, :status => :service_unavailable
|
||||
return false
|
||||
|
@ -48,7 +58,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def check_write_availability
|
||||
if API_STATUS == :offline or API_STATUS == :readonly
|
||||
if OSM_STATUS == :database_offline or OSM_STATUS == :api_offline or OSM_STATUS == :api_readonly
|
||||
response.headers['Error'] = "Database offline for maintenance"
|
||||
render :nothing => true, :status => :service_unavailable
|
||||
return false
|
||||
|
|
109
app/controllers/browse_controller.rb
Normal file
109
app/controllers/browse_controller.rb
Normal file
|
@ -0,0 +1,109 @@
|
|||
class BrowseController < ApplicationController
|
||||
layout 'site'
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter { |c| c.check_database_availability(true) }
|
||||
|
||||
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
|
|
@ -3,6 +3,7 @@ class DiaryEntryController < ApplicationController
|
|||
|
||||
before_filter :authorize_web
|
||||
before_filter :require_user, :only => [:new]
|
||||
before_filter :check_database_availability
|
||||
|
||||
def new
|
||||
@title = 'new diary entry'
|
||||
|
|
|
@ -17,25 +17,15 @@ class MessageController < ApplicationController
|
|||
Notifier::deliver_message_notification(@message)
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@message = Message.find(params[:message_id], :conditions => ["to_user_id = ? or from_user_id = ?", @user.id, @user.id ])
|
||||
if !@message.message_read
|
||||
flash[:notice] = 'Message not read and so not deleted'
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
else
|
||||
flash[:notice] = "Message '#{@message.title}' deleted"
|
||||
@message.destroy
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
@title = params[:title]
|
||||
end
|
||||
end
|
||||
|
||||
def reply
|
||||
message = Message.find(params[:message_id], :conditions => ["to_user_id = ? or from_user_id = ?", @user.id, @user.id ])
|
||||
@body = "\n\nOn #{message.sent_on} #{message.sender.display_name} wrote:\n #{message.body}"
|
||||
@title = "Re: #{message.title}"
|
||||
@body = "On #{message.sent_on} #{message.sender.display_name} wrote:\n\n#{message.body.gsub(/^/, '> ')}"
|
||||
@title = "Re: #{message.title.sub(/^Re:\s*/, '')}"
|
||||
@user_id = message.from_user_id
|
||||
render :action => 'new'
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
class TraceController < ApplicationController
|
||||
layout 'site'
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :authorize, :only => [:api_details, :api_data, :api_create]
|
||||
layout 'site'
|
||||
before_filter :check_database_availability, :except => [:api_details, :api_data, :api_create]
|
||||
before_filter :check_read_availability, :only => [:api_details, :api_data, :api_create]
|
||||
|
||||
# Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
|
||||
# target_user - if set, specifies the user to fetch traces for. if not set will fetch all traces
|
||||
|
@ -84,20 +87,15 @@ class TraceController < ApplicationController
|
|||
def view
|
||||
@trace = Trace.find(params[:id])
|
||||
|
||||
unless @trace
|
||||
flash[:notice] = "OH NOES! Trace not found!"
|
||||
if @trace and @trace.visible? and
|
||||
(@trace.public? or @trace.user.id == @user.id)
|
||||
@title = "Viewing trace #{@trace.name}"
|
||||
else
|
||||
flash[:notice] = "Trace not found!"
|
||||
redirect_to :controller => 'trace', :action => 'list'
|
||||
return
|
||||
end
|
||||
|
||||
@title = "Viewing trace #{@trace.name}"
|
||||
if !@trace.visible?
|
||||
render :nothing => true, :status => :not_found
|
||||
elsif !@trace.public? and @trace.user.id != @user.id
|
||||
render :nothing => true, :status => :forbidden
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
flash[:notice] = "GPX file not found"
|
||||
flash[:notice] = "Trace not found!"
|
||||
redirect_to :controller => 'trace', :action => 'list'
|
||||
end
|
||||
|
||||
|
@ -115,11 +113,11 @@ class TraceController < ApplicationController
|
|||
end
|
||||
else
|
||||
@trace = Trace.new({:name => "Dummy",
|
||||
:tagstring => params[:trace][:tagstring],
|
||||
:description => params[:trace][:description],
|
||||
:public => params[:trace][:public],
|
||||
:inserted => false, :user => @user,
|
||||
:timestamp => Time.now})
|
||||
:tagstring => params[:trace][:tagstring],
|
||||
:description => params[:trace][:description],
|
||||
:public => params[:trace][:public],
|
||||
:inserted => false, :user => @user,
|
||||
:timestamp => Time.now})
|
||||
@trace.valid?
|
||||
@trace.errors.add(:gpx_file, "can't be blank")
|
||||
end
|
||||
|
@ -294,7 +292,7 @@ class TraceController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def do_create(file, tags, description, public)
|
||||
name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, '_')
|
||||
|
@ -303,7 +301,7 @@ class TraceController < ApplicationController
|
|||
File.open(filename, "w") { |f| f.write(file.read) }
|
||||
|
||||
@trace = Trace.new({:name => name, :tagstring => tags,
|
||||
:description => description, :public => public})
|
||||
:description => description, :public => public})
|
||||
@trace.inserted = false
|
||||
@trace.user = @user
|
||||
@trace.timestamp = Time.now
|
||||
|
|
|
@ -4,6 +4,8 @@ class UserController < ApplicationController
|
|||
before_filter :authorize, :only => [:api_details, :api_gpx_files]
|
||||
before_filter :authorize_web, :only => [:account, :go_public, :view, :diary, :make_friend, :remove_friend, :upload_image]
|
||||
before_filter :require_user, :only => [:set_home, :account, :go_public, :make_friend, :remove_friend, :upload_image]
|
||||
before_filter :check_database_availability, :except => [:api_details, :api_gpx_files]
|
||||
before_filter :check_read_availability, :only => [:api_details, :api_gpx_files]
|
||||
|
||||
filter_parameter_logging :password, :pass_crypt, :pass_crypt_confirmation
|
||||
|
||||
|
@ -143,17 +145,19 @@ class UserController < ApplicationController
|
|||
end
|
||||
|
||||
def confirm
|
||||
token = UserToken.find_by_token(params[:confirm_string])
|
||||
if token and !token.user.active?
|
||||
@user = token.user
|
||||
@user.active = true
|
||||
@user.save!
|
||||
token.destroy
|
||||
flash[:notice] = 'Confirmed your account, thanks for signing up!'
|
||||
session[:user] = @user.id
|
||||
redirect_to :action => 'account', :display_name => @user.display_name
|
||||
else
|
||||
flash[:notice] = 'Something went wrong confirming that user.'
|
||||
if params[:confirm_action]
|
||||
token = UserToken.find_by_token(params[:confirm_string])
|
||||
if token and !token.user.active?
|
||||
@user = token.user
|
||||
@user.active = true
|
||||
@user.save!
|
||||
token.destroy
|
||||
flash[:notice] = 'Confirmed your account, thanks for signing up!'
|
||||
session[:user] = @user.id
|
||||
redirect_to :action => 'account', :display_name => @user.display_name
|
||||
else
|
||||
flash[:notice] = 'Something went wrong confirming that user.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
2
app/helpers/browse_helper.rb
Normal file
2
app/helpers/browse_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
module BrowseHelper
|
||||
end
|
|
@ -1,6 +1,8 @@
|
|||
class Node < GeoRecord
|
||||
class Node < ActiveRecord::Base
|
||||
require 'xml/libxml'
|
||||
|
||||
include GeoRecord
|
||||
|
||||
set_table_name 'current_nodes'
|
||||
|
||||
validates_presence_of :user_id, :timestamp
|
||||
|
@ -8,21 +10,21 @@ class Node < GeoRecord
|
|||
validates_numericality_of :latitude, :longitude
|
||||
validate :validate_position
|
||||
|
||||
has_many :old_nodes, :foreign_key => :id
|
||||
has_many :way_nodes
|
||||
has_many :node_tags, :foreign_key => :id
|
||||
belongs_to :user
|
||||
|
||||
|
||||
has_many :old_nodes, :foreign_key => :id
|
||||
|
||||
has_many :way_nodes
|
||||
has_many :ways, :through => :way_nodes
|
||||
|
||||
has_many :containing_relation_members, :class_name => "RelationMember", :as => :member
|
||||
has_many :containing_relations, :class_name => "Relation", :through => :containing_relation_members, :source => :relation, :extend => ObjectFinder
|
||||
|
||||
# Sanity check the latitude and longitude and add an error if it's broken
|
||||
def validate_position
|
||||
errors.add_to_base("Node is not in the world") unless in_world?
|
||||
end
|
||||
|
||||
def in_world?
|
||||
return false if self.lat < -90 or self.lat > 90
|
||||
return false if self.lon < -180 or self.lon > 180
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# Search for nodes matching tags within bounding_box
|
||||
#
|
||||
|
@ -55,109 +57,64 @@ class Node < GeoRecord
|
|||
p = XML::Parser.new
|
||||
p.string = xml
|
||||
doc = p.parse
|
||||
|
||||
node = Node.new
|
||||
|
||||
doc.find('//osm/node').each do |pt|
|
||||
return Node.from_xml_node(pt, create)
|
||||
node.lat = pt['lat'].to_f
|
||||
node.lon = pt['lon'].to_f
|
||||
|
||||
return nil unless node.in_world?
|
||||
|
||||
unless create
|
||||
if pt['id'] != '0'
|
||||
node.id = pt['id'].to_i
|
||||
end
|
||||
end
|
||||
|
||||
node.visible = pt['visible'] and pt['visible'] == 'true'
|
||||
|
||||
if create
|
||||
node.timestamp = Time.now
|
||||
else
|
||||
if pt['timestamp']
|
||||
node.timestamp = Time.parse(pt['timestamp'])
|
||||
end
|
||||
end
|
||||
|
||||
tags = []
|
||||
|
||||
pt.find('tag').each do |tag|
|
||||
tags << [tag['k'],tag['v']]
|
||||
end
|
||||
|
||||
node.tags = Tags.join(tags)
|
||||
end
|
||||
rescue
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_xml_node(pt, create=false)
|
||||
node = Node.new
|
||||
|
||||
node.version = pt['version']
|
||||
node.lat = pt['lat'].to_f
|
||||
node.lon = pt['lon'].to_f
|
||||
|
||||
return nil unless node.in_world?
|
||||
|
||||
unless create
|
||||
if pt['id'] != '0'
|
||||
node.id = pt['id'].to_i
|
||||
end
|
||||
end
|
||||
|
||||
node.visible = pt['visible'] and pt['visible'] == 'true'
|
||||
|
||||
if create
|
||||
node.timestamp = Time.now
|
||||
else
|
||||
if pt['timestamp']
|
||||
node.timestamp = Time.parse(pt['timestamp'])
|
||||
end
|
||||
end
|
||||
|
||||
tags = []
|
||||
|
||||
pt.find('tag').each do |tag|
|
||||
node.add_tag_key_val(tag['k'],tag['v'])
|
||||
node = nil
|
||||
end
|
||||
|
||||
return node
|
||||
end
|
||||
|
||||
# Save this node with the appropriate OldNode object to represent it's history.
|
||||
def save_with_history!
|
||||
t = Time.now
|
||||
Node.transaction do
|
||||
self.version += 1
|
||||
self.timestamp = t
|
||||
self.timestamp = Time.now
|
||||
self.save!
|
||||
|
||||
# Create a NodeTag
|
||||
tags = self.tags
|
||||
NodeTag.delete_all(['id = ?', self.id])
|
||||
tags.each do |k,v|
|
||||
tag = NodeTag.new
|
||||
tag.k = k
|
||||
tag.v = v
|
||||
tag.id = self.id
|
||||
tag.save!
|
||||
end
|
||||
|
||||
# Create an OldNode
|
||||
old_node = OldNode.from_node(self)
|
||||
old_node.timestamp = t
|
||||
old_node.save_with_dependencies!
|
||||
old_node.save!
|
||||
end
|
||||
end
|
||||
|
||||
def delete_with_history(user)
|
||||
if self.visible
|
||||
if WayNode.find(:first, :joins => "INNER JOIN current_ways ON current_ways.id = current_way_nodes.id", :conditions => [ "current_ways.visible = 1 AND current_way_nodes.node_id = ?", self.id ])
|
||||
raise OSM::APIPreconditionFailedError.new
|
||||
elsif RelationMember.find(:first, :joins => "INNER JOIN current_relations ON current_relations.id=current_relation_members.id", :conditions => [ "visible = 1 AND member_type='node' and member_id=?", self.id])
|
||||
raise OSM::APIPreconditionFailedError.new
|
||||
else
|
||||
self.user_id = user.id
|
||||
self.visible = 0
|
||||
save_with_history!
|
||||
end
|
||||
else
|
||||
raise OSM::APIAlreadyDeletedError.new
|
||||
end
|
||||
end
|
||||
|
||||
def update_from(new_node, user)
|
||||
if new_node.version != version
|
||||
raise OSM::APIVersionMismatchError.new(new_node.version, version)
|
||||
end
|
||||
|
||||
self.user_id = user.id
|
||||
self.latitude = new_node.latitude
|
||||
self.longitude = new_node.longitude
|
||||
self.tags = new_node.tags
|
||||
self.visible = true
|
||||
save_with_history!
|
||||
end
|
||||
|
||||
# Turn this Node in to a complete OSM XML object with <osm> wrapper
|
||||
def to_xml
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << to_xml_node()
|
||||
return doc
|
||||
end
|
||||
|
||||
# Turn this Node in to an XML Node without the <osm> wrapper.
|
||||
def to_xml_node(user_display_name_cache = nil)
|
||||
el1 = XML::Node.new 'node'
|
||||
el1['id'] = self.id.to_s
|
||||
|
@ -176,7 +133,7 @@ class Node < GeoRecord
|
|||
|
||||
el1['user'] = user_display_name_cache[self.user_id] unless user_display_name_cache[self.user_id].nil?
|
||||
|
||||
self.tags.each do |k,v|
|
||||
Tags.split(self.tags) do |k,v|
|
||||
el2 = XML::Node.new('tag')
|
||||
el2['k'] = k.to_s
|
||||
el2['v'] = v.to_s
|
||||
|
@ -185,33 +142,15 @@ class Node < GeoRecord
|
|||
|
||||
el1['visible'] = self.visible.to_s
|
||||
el1['timestamp'] = self.timestamp.xmlschema
|
||||
el1['version'] = self.version.to_s
|
||||
return el1
|
||||
end
|
||||
|
||||
# Return the node's tags as a Hash of keys and their values
|
||||
def tags_as_hash
|
||||
return tags
|
||||
end
|
||||
|
||||
def tags
|
||||
unless @tags
|
||||
@tags = {}
|
||||
self.node_tags.each do |tag|
|
||||
@tags[tag.k] = tag.v
|
||||
end
|
||||
hash = {}
|
||||
Tags.split(self.tags) do |k,v|
|
||||
hash[k] = v
|
||||
end
|
||||
@tags
|
||||
hash
|
||||
end
|
||||
|
||||
def tags=(t)
|
||||
@tags = t
|
||||
end
|
||||
|
||||
def add_tag_key_val(k,v)
|
||||
@tags = Hash.new unless @tags
|
||||
@tags[k] = v
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class OldNode < GeoRecord
|
||||
class OldNode < ActiveRecord::Base
|
||||
include GeoRecord
|
||||
|
||||
set_table_name 'nodes'
|
||||
|
||||
validates_presence_of :user_id, :timestamp
|
||||
|
@ -27,15 +29,8 @@ class OldNode < GeoRecord
|
|||
old_node.timestamp = node.timestamp
|
||||
old_node.user_id = node.user_id
|
||||
old_node.id = node.id
|
||||
old_node.version = node.version
|
||||
return old_node
|
||||
end
|
||||
|
||||
def to_xml
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << to_xml_node()
|
||||
return doc
|
||||
end
|
||||
|
||||
def to_xml_node
|
||||
el1 = XML::Node.new 'node'
|
||||
|
@ -44,7 +39,7 @@ class OldNode < GeoRecord
|
|||
el1['lon'] = self.lon.to_s
|
||||
el1['user'] = self.user.display_name if self.user.data_public?
|
||||
|
||||
self.tags.each do |k,v|
|
||||
Tags.split(self.tags) do |k,v|
|
||||
el2 = XML::Node.new('tag')
|
||||
el2['k'] = k.to_s
|
||||
el2['v'] = v.to_s
|
||||
|
@ -53,41 +48,24 @@ class OldNode < GeoRecord
|
|||
|
||||
el1['visible'] = self.visible.to_s
|
||||
el1['timestamp'] = self.timestamp.xmlschema
|
||||
el1['version'] = self.version.to_s
|
||||
return el1
|
||||
end
|
||||
|
||||
def save_with_dependencies!
|
||||
save!
|
||||
#not sure whats going on here
|
||||
clear_aggregation_cache
|
||||
clear_association_cache
|
||||
#ok from here
|
||||
@attributes.update(OldNode.find(:first, :conditions => ['id = ? AND timestamp = ?', self.id, self.timestamp]).instance_variable_get('@attributes'))
|
||||
|
||||
self.tags.each do |k,v|
|
||||
tag = OldNodeTag.new
|
||||
tag.k = k
|
||||
tag.v = v
|
||||
tag.id = self.id
|
||||
tag.version = self.version
|
||||
tag.save!
|
||||
|
||||
def tags_as_hash
|
||||
hash = {}
|
||||
Tags.split(self.tags) do |k,v|
|
||||
hash[k] = v
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
def tags
|
||||
unless @tags
|
||||
@tags = Hash.new
|
||||
OldNodeTag.find(:all, :conditions => ["id = ? AND version = ?", self.id, self.version]).each do |tag|
|
||||
@tags[tag.k] = tag.v
|
||||
end
|
||||
end
|
||||
@tags = Hash.new unless @tags
|
||||
@tags
|
||||
# Pretend we're not in any ways
|
||||
def ways
|
||||
return []
|
||||
end
|
||||
|
||||
def tags=(t)
|
||||
@tags = t
|
||||
end
|
||||
|
||||
# Pretend we're not in any relations
|
||||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -109,5 +109,20 @@ class OldRelation < ActiveRecord::Base
|
|||
el1 << e
|
||||
end
|
||||
return el1
|
||||
end
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
|
||||
# Temporary method to match interface to relations
|
||||
def relation_members
|
||||
return self.old_members
|
||||
end
|
||||
|
||||
# Pretend we're not in any relations
|
||||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
class OldRelationMember < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
|
||||
set_table_name 'relation_members'
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
class OldRelationTag < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
|
||||
set_table_name 'relation_tags'
|
||||
|
||||
end
|
||||
|
|
|
@ -110,5 +110,20 @@ class OldWay < ActiveRecord::Base
|
|||
el1 << e
|
||||
end
|
||||
return el1
|
||||
end
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
|
||||
# Temporary method to match interface to ways
|
||||
def way_nodes
|
||||
return self.old_nodes
|
||||
end
|
||||
|
||||
# Pretend we're not in any relations
|
||||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
class Relation < ActiveRecord::Base
|
||||
require 'xml/libxml'
|
||||
|
||||
set_table_name 'current_relations'
|
||||
|
||||
belongs_to :user
|
||||
|
||||
has_many :old_relations, :foreign_key => 'id', :order => 'version'
|
||||
|
||||
has_many :relation_members, :foreign_key => 'id'
|
||||
has_many :relation_tags, :foreign_key => 'id'
|
||||
|
||||
has_many :old_relations, :foreign_key => 'id', :order => 'version'
|
||||
|
||||
set_table_name 'current_relations'
|
||||
has_many :containing_relation_members, :class_name => "RelationMember", :as => :member
|
||||
has_many :containing_relations, :class_name => "Relation", :through => :containing_relation_members, :source => :relation, :extend => ObjectFinder
|
||||
|
||||
def self.from_xml(xml, create=false)
|
||||
begin
|
||||
|
@ -109,29 +112,6 @@ class Relation < ActiveRecord::Base
|
|||
return el1
|
||||
end
|
||||
|
||||
|
||||
# collect relationships. currently done in one big block at the end;
|
||||
# may need to move this upwards if people want automatic completion of
|
||||
# relationships, i.e. deliver referenced objects like we do with ways...
|
||||
# FIXME: rip out the fucking SQL
|
||||
def self.find_for_nodes_and_ways(node_ids, way_ids)
|
||||
relations = []
|
||||
|
||||
if node_ids.length > 0
|
||||
relations += Relation.find_by_sql("select e.* from current_relations e,current_relation_members em where " +
|
||||
"e.visible=1 and " +
|
||||
"em.id = e.id and em.member_type='node' and em.member_id in (#{node_ids.join(',')})")
|
||||
end
|
||||
if way_ids.length > 0
|
||||
relations += Relation.find_by_sql("select e.* from current_relations e,current_relation_members em where " +
|
||||
"e.visible=1 and " +
|
||||
"em.id = e.id and em.member_type='way' and em.member_id in (#{way_ids.join(',')})")
|
||||
end
|
||||
|
||||
relations # if you don't do this then it returns nil and not []
|
||||
end
|
||||
|
||||
|
||||
# FIXME is this really needed?
|
||||
def members
|
||||
unless @members
|
||||
|
@ -236,22 +216,49 @@ class Relation < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def preconditions_ok?
|
||||
# These are hastables that store an id in the index of all
|
||||
# the nodes/way/relations that have already been added.
|
||||
# Once we know the id of the node/way/relation exists
|
||||
# we check to see if it is already existing in the hashtable
|
||||
# if it does, then we return false. Otherwise
|
||||
# we add it to the relevant hash table, with the value true..
|
||||
# Thus if you have nodes with the ids of 50 and 1 already in the
|
||||
# relation, then the hash table nodes would contain:
|
||||
# => {50=>true, 1=>true}
|
||||
nodes = Hash.new
|
||||
ways = Hash.new
|
||||
relations = Hash.new
|
||||
self.members.each do |m|
|
||||
if (m[0] == "node")
|
||||
n = Node.find(:first, :conditions => ["id = ?", m[1]])
|
||||
unless n and n.visible
|
||||
return false
|
||||
end
|
||||
if nodes[m[1]]
|
||||
return false
|
||||
else
|
||||
nodes[m[1]] = true
|
||||
end
|
||||
elsif (m[0] == "way")
|
||||
w = Way.find(:first, :conditions => ["id = ?", m[1]])
|
||||
unless w and w.visible and w.preconditions_ok?
|
||||
return false
|
||||
end
|
||||
if ways[m[1]]
|
||||
return false
|
||||
else
|
||||
ways[m[1]] = true
|
||||
end
|
||||
elsif (m[0] == "relation")
|
||||
e = Relation.find(:first, :conditions => ["id = ?", m[1]])
|
||||
unless e and e.visible and e.preconditions_ok?
|
||||
return false
|
||||
end
|
||||
if relations[m[1]]
|
||||
return false
|
||||
else
|
||||
relations[m[1]] = true
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
@ -261,4 +268,8 @@ class Relation < ActiveRecord::Base
|
|||
return false
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,30 +1,23 @@
|
|||
class RelationMember < ActiveRecord::Base
|
||||
set_table_name 'current_relation_members'
|
||||
|
||||
# problem with RelationMember is that it may link to any one
|
||||
# object (a node, a way, another relation), and belongs_to is
|
||||
# not flexible enough for that. So we do this, which is ugly,
|
||||
# but fortunately rails won't actually run the SQL behind that
|
||||
# unless someone really accesses .node, .way, or
|
||||
# .relation - which is what we do below based on member_type.
|
||||
# (and no: the :condition on belongs_to doesn't work here as
|
||||
# it is a condition on the *referenced* object not the
|
||||
# *referencing* object!)
|
||||
|
||||
belongs_to :node, :foreign_key => "member_id"
|
||||
belongs_to :way, :foreign_key => "member_id"
|
||||
belongs_to :relation, :foreign_key => "member_id"
|
||||
belongs_to :member, :polymorphic => true, :foreign_type => :member_class
|
||||
belongs_to :relation, :foreign_key => :id
|
||||
|
||||
# so we define this "member" function that returns whatever it
|
||||
# is.
|
||||
|
||||
def member()
|
||||
return (member_type == "node") ? node : (member_type == "way") ? way : relation
|
||||
def after_find
|
||||
self[:member_class] = self.member_type.capitalize
|
||||
end
|
||||
|
||||
# NOTE - relations are SUBJECTS of memberships. The fact that nodes,
|
||||
# ways, and relations can be the OBJECT of a membership,
|
||||
# i.e. a node/way/relation can be referenced throgh a
|
||||
# RelationMember object, is NOT modelled in rails, i.e. these links
|
||||
# have to be resolved manually, on demand.
|
||||
def after_initialize
|
||||
self[:member_class] = self.member_type.capitalize
|
||||
end
|
||||
|
||||
def before_save
|
||||
self.member_type = self[:member_class].downcase
|
||||
end
|
||||
|
||||
def member_type=(type)
|
||||
self[:member_type] = type
|
||||
self[:member_class] = type.capitalize
|
||||
end
|
||||
end
|
||||
|
|
|
@ -183,7 +183,7 @@ class Trace < ActiveRecord::Base
|
|||
# If there are any existing points for this trace then delete
|
||||
# them - we check for existing points first to avoid locking
|
||||
# the table in the common case where there aren't any.
|
||||
if Tracepoint.exists?(['gpx_id = ?', self.id])
|
||||
if Tracepoint.find(:first, :conditions => ['gpx_id = ?', self.id])
|
||||
Tracepoint.delete_all(['gpx_id = ?', self.id])
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Tracepoint < GeoRecord
|
||||
class Tracepoint < ActiveRecord::Base
|
||||
include GeoRecord
|
||||
|
||||
set_table_name 'gps_points'
|
||||
|
||||
validates_numericality_of :trackid, :only_integer => true
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
class Way < ActiveRecord::Base
|
||||
require 'xml/libxml'
|
||||
|
||||
belongs_to :user
|
||||
set_table_name 'current_ways'
|
||||
|
||||
has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
|
||||
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
|
||||
has_many :way_tags, :foreign_key => 'id'
|
||||
belongs_to :user
|
||||
|
||||
has_many :old_ways, :foreign_key => 'id', :order => 'version'
|
||||
|
||||
set_table_name 'current_ways'
|
||||
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
|
||||
has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
|
||||
|
||||
has_many :way_tags, :foreign_key => 'id'
|
||||
|
||||
has_many :containing_relation_members, :class_name => "RelationMember", :as => :member
|
||||
has_many :containing_relations, :class_name => "Relation", :through => :containing_relation_members, :source => :relation, :extend => ObjectFinder
|
||||
|
||||
def self.from_xml(xml, create=false)
|
||||
begin
|
||||
|
@ -270,4 +274,9 @@ class Way < ActiveRecord::Base
|
|||
self.delete_with_history(user)
|
||||
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
end
|
||||
|
|
22
app/views/browse/_common_details.rhtml
Normal file
22
app/views/browse/_common_details.rhtml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<tr>
|
||||
<th>Edited at:</th>
|
||||
<td><%= h(common_details.timestamp) %></td>
|
||||
</tr>
|
||||
|
||||
<% if common_details.user.data_public %>
|
||||
<tr>
|
||||
<th>Edited by:</th>
|
||||
<td><%= link_to h(common_details.user.display_name), :controller => "user", :action => "view", :display_name => common_details.user.display_name %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
<% unless common_details.tags_as_hash.empty? %>
|
||||
<tr valign="top">
|
||||
<th>Tags:</th>
|
||||
<td>
|
||||
<table padding="0">
|
||||
<%= render :partial => "tag", :collection => common_details.tags_as_hash %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
8
app/views/browse/_containing_relation.rhtml
Normal file
8
app/views/browse/_containing_relation.rhtml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<tr>
|
||||
<td>
|
||||
<%= link_to "Relation " + containing_relation.id.to_s, :action => "relation", :id => containing_relation.id.to_s %>
|
||||
<% unless containing_relation.member_role.blank? %>
|
||||
(as <%= h(containing_relation.member_role) %>)
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
64
app/views/browse/_map.rhtml
Normal file
64
app/views/browse/_map.rhtml
Normal file
|
@ -0,0 +1,64 @@
|
|||
<%= javascript_include_tag '/openlayers/OpenLayers.js' %>
|
||||
<%= javascript_include_tag '/openlayers/OpenStreetMap.js' %>
|
||||
<%= javascript_include_tag 'map.js' %>
|
||||
<td align="right">
|
||||
<% if map.visible %>
|
||||
<div id="small_map" style="width:250px; height: 300px; border: solid 1px black">
|
||||
</div>
|
||||
<span id="loading">Loading...</span>
|
||||
<a id="larger_map" href=""></a>
|
||||
<% else %>
|
||||
Deleted
|
||||
<% end %>
|
||||
</td>
|
||||
<script type="text/javascript">
|
||||
function init() {
|
||||
var obj_type = "<%= map.class.name.downcase %>";
|
||||
var obj_id = <%= map.id %>;
|
||||
var url = "/api/<%= "#{API_VERSION}" %>/<%= map.class.name.downcase %>/<%= map.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>
|
13
app/views/browse/_navigation.rhtml
Normal file
13
app/views/browse/_navigation.rhtml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<div style="float:right; text-align:center; width: 250px;">
|
||||
<% if @prev %>
|
||||
<
|
||||
<%= link_to @prev.id.to_s, :id => @prev.id %>
|
||||
<% end %>
|
||||
<% if @prev and @next %>
|
||||
|
|
||||
<% end %>
|
||||
<% if @next %>
|
||||
<%= link_to @next.id.to_s, :id => @next.id %>
|
||||
>
|
||||
<% end %>
|
||||
</div>
|
19
app/views/browse/_node_details.rhtml
Normal file
19
app/views/browse/_node_details.rhtml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<table>
|
||||
|
||||
<%= render :partial => "common_details", :object => node_details %>
|
||||
|
||||
<% unless node_details.ways.empty? and node_details.containing_relation_members.empty? %>
|
||||
<tr valign="top">
|
||||
<th>Part of:</th>
|
||||
<td>
|
||||
<table padding="0">
|
||||
<% node_details.ways.each do |way| %>
|
||||
<tr><td><%= link_to "Way " + way.id.to_s, :action => "way", :id => way.id.to_s %></td></tr>
|
||||
<% end %>
|
||||
<%= render :partial => "containing_relation", :collection => node_details.containing_relation_members %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
</table>
|
27
app/views/browse/_relation_details.rhtml
Normal file
27
app/views/browse/_relation_details.rhtml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<table>
|
||||
|
||||
<%= render :partial => "common_details", :object => relation_details %>
|
||||
|
||||
<% unless relation_details.relation_members.empty? %>
|
||||
<tr valign="top">
|
||||
<th>Members:</th>
|
||||
<td>
|
||||
<table padding="0">
|
||||
<%= render :partial => "relation_member", :collection => relation_details.relation_members %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
<% unless relation_details.containing_relation_members.empty? %>
|
||||
<tr>
|
||||
<th>Part of:</th>
|
||||
<td>
|
||||
<table padding="0">
|
||||
<%= render :partial => "containing_relation", :collection => relation_details.containing_relation_members %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
</table>
|
10
app/views/browse/_relation_member.rhtml
Normal file
10
app/views/browse/_relation_member.rhtml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<tr>
|
||||
<td>
|
||||
<%= h(relation_member.member_type.capitalize) %>
|
||||
<%= link_to relation_member.member_id.to_s, :action => relation_member.member_type, :id => relation_member.member_id %>
|
||||
<% unless relation_member.member_role.blank? %>
|
||||
as
|
||||
<%= h(relation_member.member_role) %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
13
app/views/browse/_start.rhtml
Normal file
13
app/views/browse/_start.rhtml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<div>
|
||||
<div style="text-align: center">
|
||||
<p style="margin-top: 10px; margin-bottom: 20px">
|
||||
<a id="browse_select_view" href="#">View data for current map view</a>
|
||||
<br />
|
||||
<a id="browse_select_box" href="#">Manually select a different area</a>
|
||||
</p>
|
||||
</div>
|
||||
<div id="browse_status" style="text-align: center; display: none">
|
||||
</div>
|
||||
<div id="browse_content">
|
||||
</div>
|
||||
</div>
|
3
app/views/browse/_tag.rhtml
Normal file
3
app/views/browse/_tag.rhtml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<tr>
|
||||
<td><%= h(tag[0]) %> = <%= h(tag[1]) %></td>
|
||||
</tr>
|
27
app/views/browse/_way_details.rhtml
Normal file
27
app/views/browse/_way_details.rhtml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<table>
|
||||
|
||||
<%= render :partial => "common_details", :object => way_details %>
|
||||
|
||||
<tr valign="top">
|
||||
<th>Nodes:</th>
|
||||
<td>
|
||||
<table padding="0">
|
||||
<% way_details.way_nodes.each do |wn| %>
|
||||
<tr><td><%= link_to "Node " + wn.node_id.to_s, :action => "node", :id => wn.node_id.to_s %></td></tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<% unless way_details.containing_relation_members.empty? %>
|
||||
<tr>
|
||||
<th>Part of:</th>
|
||||
<td>
|
||||
<table padding="0">
|
||||
<%= render :partial => "containing_relation", :collection => way_details.containing_relation_members %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
</table>
|
12
app/views/browse/index.rhtml
Normal file
12
app/views/browse/index.rhtml
Normal file
|
@ -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>
|
20
app/views/browse/node.rhtml
Normal file
20
app/views/browse/node.rhtml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<table width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<h2>Node: <%= h(@name) %></h2>
|
||||
</td>
|
||||
<td>
|
||||
<%= render :partial => "navigation" %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<%= render :partial => "node_details", :object => @node %>
|
||||
<hr />
|
||||
<%= link_to "Download XML", :controller => "node", :action => "read" %>
|
||||
or
|
||||
<%= link_to "view history", :action => "node_history" %>
|
||||
</td>
|
||||
<%= render :partial => "map", :object => @node %>
|
||||
</tr>
|
||||
</table>
|
16
app/views/browse/node_history.rhtml
Normal file
16
app/views/browse/node_history.rhtml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<h2>Node History: <%= h(@name) %></h2>
|
||||
|
||||
<table width="100%">
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<% @node.old_nodes.reverse.each do |node| %>
|
||||
<%= render :partial => "node_details", :object => node %>
|
||||
<hr />
|
||||
<% end %>
|
||||
<%= link_to "Download XML", :controller => "old_node", :action => "history" %>
|
||||
or
|
||||
<%= link_to "view details", :action => "node" %>
|
||||
</td>
|
||||
<%= render :partial => "map", :object => @node %>
|
||||
</tr>
|
||||
</table>
|
20
app/views/browse/relation.rhtml
Normal file
20
app/views/browse/relation.rhtml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<table width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<h2>Relation: <%= h(@name) %></h2>
|
||||
</td>
|
||||
<td>
|
||||
<%= render :partial => "navigation" %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<%= render :partial => "relation_details", :object => @relation %>
|
||||
<hr />
|
||||
<%= link_to "Download XML", :controller => "relation", :action => "read" %>
|
||||
or
|
||||
<%= link_to "view history", :action => "relation_history" %>
|
||||
</td>
|
||||
<%= render :partial => "map", :object => @relation %>
|
||||
</tr>
|
||||
</table>
|
16
app/views/browse/relation_history.rhtml
Normal file
16
app/views/browse/relation_history.rhtml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<h2>Relation History: <%= h(@name) %></h2>
|
||||
|
||||
<table width="100%">
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<% @relation.old_relations.reverse.each do |relation| %>
|
||||
<%= render :partial => "relation_details", :object => relation %>
|
||||
<hr />
|
||||
<% end %>
|
||||
<%= link_to "Download XML", :controller => "old_relation", :action => "history" %>
|
||||
or
|
||||
<%= link_to "view details", :action => "relation" %>
|
||||
</td>
|
||||
<%= render :partial => "map", :object => @relation %>
|
||||
</tr>
|
||||
</table>
|
481
app/views/browse/start.rjs
Normal file
481
app/views/browse/start.rjs
Normal file
|
@ -0,0 +1,481 @@
|
|||
page.replace_html :sidebar_title, 'Data'
|
||||
page.replace_html :sidebar_content, :partial => 'start'
|
||||
page << <<EOJ
|
||||
var browseBoxControl;
|
||||
var browseActive;
|
||||
var browseMode = "auto";
|
||||
var browseBounds;
|
||||
var browseFeatureList;
|
||||
var browseActiveFeature;
|
||||
var browseDataLayer;
|
||||
var browseSelectControl;
|
||||
var browseObjectList;
|
||||
|
||||
OpenLayers.Feature.Vector.style['default'].strokeWidth = 3;
|
||||
OpenLayers.Feature.Vector.style['default'].cursor = "pointer";
|
||||
|
||||
function startBrowse() {
|
||||
openSidebar({ onclose: stopBrowse });
|
||||
|
||||
var vectors = new OpenLayers.Layer.Vector();
|
||||
|
||||
browseBoxControl = new OpenLayers.Control.DrawFeature(vectors, OpenLayers.Handler.RegularPolygon, {
|
||||
handlerOptions: {
|
||||
sides: 4,
|
||||
snapAngle: 90,
|
||||
irregular: true,
|
||||
persist: true,
|
||||
callbacks: { done: endDrag }
|
||||
}
|
||||
});
|
||||
map.addControl(browseBoxControl);
|
||||
|
||||
map.events.register("moveend", map, showData);
|
||||
map.events.triggerEvent("moveend");
|
||||
|
||||
browseActive = true;
|
||||
}
|
||||
|
||||
function showData() {
|
||||
if (browseMode == "auto") {
|
||||
if (map.getZoom() >= 15) {
|
||||
useMap();
|
||||
} else {
|
||||
setStatus("Zoom in or select an area of the map to view");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopBrowse() {
|
||||
if (browseActive) {
|
||||
browseActive = false;
|
||||
|
||||
if (browseDataLayer) {
|
||||
browseDataLayer.destroy();
|
||||
browseDataLayer = null;
|
||||
}
|
||||
|
||||
if (browseSelectControl) {
|
||||
browseSelectControl.destroy();
|
||||
browseSelectControl = null;
|
||||
}
|
||||
|
||||
if (browseBoxControl) {
|
||||
browseBoxControl.destroy();
|
||||
browseBoxControl = null;
|
||||
}
|
||||
|
||||
if (browseActiveFeature) {
|
||||
browseActiveFeature.destroy();
|
||||
browseActiveFeature = null;
|
||||
}
|
||||
|
||||
map.dataLayer.setVisibility(false);
|
||||
map.events.unregister("moveend", map, showData);
|
||||
}
|
||||
}
|
||||
|
||||
function startDrag() {
|
||||
$("browse_select_box").innerHTML='Drag a box on the map to select an area';
|
||||
|
||||
browseBoxControl.activate();
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$("browse_select_box").onclick = startDrag;
|
||||
|
||||
function useMap() {
|
||||
var bounds = map.getExtent();
|
||||
var projected = bounds.clone().transform(map.getProjectionObject(), epsg4326);
|
||||
|
||||
if (!browseBounds || !browseBounds.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));
|
||||
|
||||
browseBounds = tileBounds;
|
||||
getData(tileBounds);
|
||||
|
||||
browseMode = "auto";
|
||||
|
||||
$("browse_select_view").style.display = "none";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$("browse_select_view").onclick = useMap;
|
||||
|
||||
function endDrag(bbox) {
|
||||
var bounds = bbox.getBounds();
|
||||
var projected = bounds.clone().transform(map.getProjectionObject(), epsg4326);
|
||||
|
||||
browseBoxControl.deactivate();
|
||||
browseBounds = projected;
|
||||
getData(bounds);
|
||||
|
||||
browseMode = "manual";
|
||||
|
||||
$("browse_select_box").innerHTML = "Manually select a different area";
|
||||
$("browse_select_view").style.display = "inline";
|
||||
}
|
||||
|
||||
function displayFeatureWarning() {
|
||||
clearStatus();
|
||||
|
||||
var div = document.createElement("div");
|
||||
|
||||
var p = document.createElement("p");
|
||||
p.appendChild(document.createTextNode("You have loaded an area which contains " + browseFeatureList.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);
|
||||
|
||||
$("browse_content").innerHTML = "";
|
||||
$("browse_content").appendChild(div);
|
||||
}
|
||||
|
||||
function loadFeatureList() {
|
||||
browseDataLayer.addFeatures(browseFeatureList);
|
||||
browseDataLayer.events.triggerEvent("loadend");
|
||||
|
||||
browseFeatureList = [];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function customDataLoader(request) {
|
||||
if (browseActive) {
|
||||
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);
|
||||
|
||||
browseFeatureList = gml.read(doc);
|
||||
|
||||
if (!this.maxFeatures || browseFeatureList.length <= this.maxFeatures) {
|
||||
loadFeatureList();
|
||||
} else {
|
||||
displayFeatureWarning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getData(bounds) {
|
||||
var projected = bounds.clone().transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
|
||||
var size = projected.getWidth() * projected.getHeight();
|
||||
|
||||
if (size > 0.25) {
|
||||
setStatus("Unable to load: Bounding box size of " + size + " is too large (must be smaller than 0.25)");
|
||||
} else {
|
||||
loadGML("/api/0.5/map?bbox=" + projected.toBBOX());
|
||||
}
|
||||
}
|
||||
|
||||
function loadGML(url) {
|
||||
setStatus("Loading...");
|
||||
$("browse_content").innerHTML = "";
|
||||
|
||||
if (!browseDataLayer) {
|
||||
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' }
|
||||
}
|
||||
})]);
|
||||
|
||||
browseDataLayer = 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 }
|
||||
})
|
||||
});
|
||||
browseDataLayer.events.register("loadend", browseDataLayer, dataLoaded );
|
||||
map.addLayer(browseDataLayer);
|
||||
|
||||
browseSelectControl = new OpenLayers.Control.SelectFeature(browseDataLayer, { onSelect: onFeatureSelect });
|
||||
browseSelectControl.handler.stopDown = false;
|
||||
browseSelectControl.handler.stopUp = false;
|
||||
map.addControl(browseSelectControl);
|
||||
browseSelectControl.activate();
|
||||
} else {
|
||||
browseDataLayer.setUrl(url);
|
||||
}
|
||||
|
||||
browseActiveFeature = null;
|
||||
}
|
||||
|
||||
function dataLoaded() {
|
||||
if (browseActive) {
|
||||
clearStatus();
|
||||
|
||||
browseObjectList = document.createElement("div")
|
||||
|
||||
var heading = document.createElement("p");
|
||||
heading.className = "browse_heading";
|
||||
heading.appendChild(document.createTextNode("Object list"));
|
||||
browseObjectList.appendChild(heading);
|
||||
|
||||
var list = document.createElement("ul");
|
||||
|
||||
for (var i = 0; i < this.features.length; i++) {
|
||||
var feature = this.features[i];
|
||||
|
||||
// Type, for linking
|
||||
var type = featureType(feature);
|
||||
var typeName = ucFirst(type);
|
||||
var li = document.createElement("li");
|
||||
li.appendChild(document.createTextNode(typeName + " "));
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
browseObjectList.appendChild(list)
|
||||
|
||||
var link = document.createElement("a");
|
||||
link.href = this.url;
|
||||
link.appendChild(document.createTextNode("API"));
|
||||
browseObjectList.appendChild(link);
|
||||
|
||||
$("browse_content").innerHTML = "";
|
||||
$("browse_content").appendChild(browseObjectList);
|
||||
}
|
||||
}
|
||||
|
||||
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 (browseMode != "auto") {
|
||||
map.setCenter(this.feature.geometry.getBounds().getCenterLonLat());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function loadObjectList() {
|
||||
$("browse_content").innerHTML="";
|
||||
$("browse_content").appendChild(browseObjectList);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onFeatureSelect(feature) {
|
||||
// Unselect previously selected feature
|
||||
if (browseActiveFeature) {
|
||||
browseActiveFeature.layer.drawFeature(
|
||||
browseActiveFeature,
|
||||
browseActiveFeature.layer.styleMap.createSymbolizer(browseActiveFeature, "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 clear it.
|
||||
if ($("browse_content").firstChild == browseObjectList) {
|
||||
$("browse_content").removeChild(browseObjectList);
|
||||
} else {
|
||||
$("browse_content").innerHTML = "";
|
||||
}
|
||||
|
||||
// Create a link back to the object list
|
||||
var div = document.createElement("div");
|
||||
div.style.textAlign = "center";
|
||||
div.style.marginBottom = "20px";
|
||||
$("browse_content").appendChild(div);
|
||||
var link = document.createElement("a");
|
||||
link.href = "#";
|
||||
link.onclick = loadObjectList;
|
||||
link.appendChild(document.createTextNode("Display object list"));
|
||||
div.appendChild(link);
|
||||
|
||||
var table = document.createElement("table");
|
||||
table.width = "100%";
|
||||
table.className = "browse_heading";
|
||||
$("browse_content").appendChild(table);
|
||||
|
||||
var tr = document.createElement("tr");
|
||||
table.appendChild(tr);
|
||||
|
||||
var heading = document.createElement("td");
|
||||
heading.appendChild(document.createTextNode(featureName(feature)));
|
||||
tr.appendChild(heading);
|
||||
|
||||
var td = document.createElement("td");
|
||||
td.align = "right";
|
||||
tr.appendChild(td);
|
||||
|
||||
var type = featureType(feature);
|
||||
var link = document.createElement("a");
|
||||
link.href = "/browse/" + type + "/" + feature.osm_id;
|
||||
link.appendChild(document.createTextNode("Details"));
|
||||
td.appendChild(link);
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.className = "browse_details";
|
||||
|
||||
$("browse_content").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);
|
||||
}
|
||||
|
||||
div.appendChild(ul);
|
||||
|
||||
var link = document.createElement("a");
|
||||
link.href = "/browse/" + type + "/" + feature.osm_id + "/history";
|
||||
link.appendChild(document.createTextNode("Show history"));
|
||||
link.onclick = OpenLayers.Function.bind(loadHistory, {
|
||||
type: type, feature: feature, link: link
|
||||
});
|
||||
|
||||
div.appendChild(link);
|
||||
|
||||
// Stash the currently drawn feature
|
||||
browseActiveFeature = 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 (browseActiveFeature.osm_id != this.feature.osm_id || $("browse_content").firstChild == browseObjectList) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.link.parentNode.removeChild(this.link);
|
||||
|
||||
var doc = request.responseXML;
|
||||
|
||||
var table = document.createElement("table");
|
||||
table.width = "100%";
|
||||
table.className = "browse_heading";
|
||||
$("browse_content").appendChild(table);
|
||||
|
||||
var tr = document.createElement("tr");
|
||||
table.appendChild(tr);
|
||||
|
||||
var heading = document.createElement("td");
|
||||
heading.appendChild(document.createTextNode("History for " + featureName(this.feature)));
|
||||
tr.appendChild(heading);
|
||||
|
||||
var td = document.createElement("td");
|
||||
td.align = "right";
|
||||
tr.appendChild(td);
|
||||
|
||||
var link = document.createElement("a");
|
||||
link.href = "/browse/" + this.type + "/" + this.feature.osm_id + "/history";
|
||||
link.appendChild(document.createTextNode("Details"));
|
||||
td.appendChild(link);
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.className = "browse_details";
|
||||
|
||||
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);
|
||||
|
||||
$("browse_content").appendChild(div);
|
||||
}
|
||||
|
||||
function featureType(feature) {
|
||||
if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
|
||||
return "node";
|
||||
} else {
|
||||
return "way";
|
||||
}
|
||||
}
|
||||
|
||||
function featureName(feature) {
|
||||
if (feature.attributes.name) {
|
||||
return feature.attributes.name;
|
||||
} else {
|
||||
return ucFirst(featureType(feature)) + " " + feature.osm_id;
|
||||
}
|
||||
}
|
||||
|
||||
function setStatus(status) {
|
||||
$("browse_status").innerHTML = status;
|
||||
$("browse_status").style.display = "block";
|
||||
}
|
||||
|
||||
function clearStatus() {
|
||||
$("browse_status").innerHTML = "";
|
||||
$("browse_status").style.display = "none";
|
||||
}
|
||||
|
||||
function ucFirst(str) {
|
||||
return str.substr(0,1).toUpperCase() + str.substr(1,str.length);
|
||||
}
|
||||
|
||||
startBrowse();
|
||||
EOJ
|
20
app/views/browse/way.rhtml
Normal file
20
app/views/browse/way.rhtml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<table width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<h2>Way: <%= h(@name) %></h2>
|
||||
</td>
|
||||
<td>
|
||||
<%= render :partial => "navigation" %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<%= render :partial => "way_details", :object => @way %>
|
||||
<hr />
|
||||
<%= link_to "Download XML", :controller => "way", :action => "read" %>
|
||||
or
|
||||
<%= link_to "view history", :action => "way_history" %>
|
||||
</td>
|
||||
<%= render :partial => "map", :object => @way %>
|
||||
</tr>
|
||||
</table>
|
16
app/views/browse/way_history.rhtml
Normal file
16
app/views/browse/way_history.rhtml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<h2>Way History: <%= h(@name) %></h2>
|
||||
|
||||
<table width="100%">
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<% @way.old_ways.reverse.each do |way| %>
|
||||
<%= render :partial => "way_details", :object => way %>
|
||||
<hr />
|
||||
<% end %>
|
||||
<%= link_to "Download XML", :controller => "old_way", :action => "history" %>
|
||||
or
|
||||
<%= link_to "view details", :action => "way" %>
|
||||
</td>
|
||||
<%= render :partial => "map", :object => @way %>
|
||||
</tr>
|
||||
</table>
|
|
@ -66,7 +66,7 @@
|
|||
removeMarkerFromMap(marker);
|
||||
}
|
||||
|
||||
marker = addMarkerToMap(merc, null, "Diary entry location");
|
||||
marker = addMarkerToMap(lonlat, null, "Diary entry location");
|
||||
}
|
||||
|
||||
function openMap() {
|
||||
|
|
|
@ -246,7 +246,9 @@ page << <<EOJ
|
|||
bounds.transform(epsg4326, epsg900913);
|
||||
var zoom = map.getZoomForExtent(bounds);
|
||||
|
||||
html += '<br /><small><a href="http://#{SERVER_URL}/?lat='+center.lat+'&lon='+center.lon+'&zoom='+zoom+markerUrl+'">View Larger Map</a></small>';
|
||||
var layers = getMapLayers();
|
||||
|
||||
html += '<br /><small><a href="http://#{SERVER_URL}/?lat='+center.lat+'&lon='+center.lon+'&zoom='+zoom+'&layers='+layers+markerUrl+'">View Larger Map</a></small>';
|
||||
|
||||
$("export_html_text").value = html;
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<li><%= link_to 'Export', {:controller => 'site', :action => 'export'}, {:id => 'exportanchor', :title => 'export map data', :class => exportclass} %></li>
|
||||
<% end %>
|
||||
<li><%= link_to 'GPS Traces', {:controller => 'trace', :action => 'list'}, {:id => 'traceanchor', :title => 'manage traces', :class => traceclass} %></li>
|
||||
<li><%= link_to 'User Diaries', {:controller => 'diary_entry', :action => 'list'}, {:id => 'diaryanchor', :title => 'view user diaries', :class => diaryclass} %></li>
|
||||
<li><%= link_to 'User Diaries', {:controller => 'diary_entry', :action => 'list', :display_name => nil}, {:id => 'diaryanchor', :title => 'view user diaries', :class => diaryclass} %></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -76,12 +76,12 @@
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if API_STATUS == :offline %>
|
||||
<% if OSM_STATUS == :database_offline or OSM_STATUS == :api_offline %>
|
||||
<div id="alert">
|
||||
The OpenStreetMap database is currently offline while
|
||||
essential database maintenance work is carried out.
|
||||
</div>
|
||||
<% elsif API_STATUS == :readonly %>
|
||||
<% elsif OSM_STATUS == :api_readonly %>
|
||||
<div id="alert">
|
||||
The OpenStreetMap database is currently in read-only mode while
|
||||
essential database maintenance work is carried out.
|
||||
|
|
|
@ -10,6 +10,4 @@
|
|||
<td><%= button_to 'Mark as read', :controller => 'message', :action => 'mark', :message_id => message_summary.id, :mark => 'read' %></td>
|
||||
<% end %>
|
||||
<td><%= button_to 'Reply', :controller => 'message', :action => 'reply', :message_id => message_summary.id %></td>
|
||||
<td><%= button_to 'Delete', :controller => 'message', :action => 'destroy', :message_id => message_summary.id %></td>
|
||||
|
||||
</tr>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<% display_name = User.find_by_id(params[:user_id] || @user_id).display_name %>
|
||||
<% title = params[:message] ? params[:message][:title] : params[:title] %>
|
||||
<% user_id = params[:user_id] || @user_id %>
|
||||
<% display_name = User.find_by_id(user_id).display_name %>
|
||||
|
||||
<h2>Send a new message to <%= h(display_name) %></h2>
|
||||
|
||||
|
@ -10,11 +10,11 @@
|
|||
|
||||
<%= error_messages_for 'message' %>
|
||||
|
||||
<% form_for :message, :url => {:user_id => params[:user_id] || @user_id, :action => "new" } do |f| %>
|
||||
<% form_for :message, :url => { :action => "new", :user_id => user_id } do |f| %>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<th>Subject</th>
|
||||
<td><%= text_field_tag 'message[title]', title, :size => 60, :value => @title %></td>
|
||||
<td><%= f.text_field :title, :size => 60, :value => @title %></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th>Body</th>
|
||||
|
@ -22,7 +22,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td><%= submit_tag 'Send', :action => 'new' %></td>
|
||||
<td><%= submit_tag 'Send' %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<% end %>
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
<tr>
|
||||
<td><%= button_to 'Reply', :controller => 'message', :action => 'reply', :message_id => @message.id %></td>
|
||||
<td><%= button_to 'Mark as unread', :controller => 'message', :action => 'mark', :message_id => @message.id, :mark => 'unread' %></td>
|
||||
<td><%= button_to 'Delete', :controller => 'message', :action => 'destroy', :message_id => @message.id %></td>
|
||||
<td><%= link_to 'Back to inbox', :controller => 'message', :action => 'inbox', :display_name => @user.display_name %></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
***************************************************************************
|
||||
Please do not reply to this email. Use the OpenStreetMap web site to reply.
|
||||
* *
|
||||
* Please do not reply to this email. *
|
||||
* Use the OpenStreetMap web site to reply. *
|
||||
* *
|
||||
* Bitte antworten Sie nicht auf diese E-Mail. *
|
||||
* Verwenden Sie die OpenStreetMap Website zum antworten. *
|
||||
* *
|
||||
* Por favor, no responda a este mensaje. *
|
||||
* Utilice el OpenStreetMap sitio web para responder. *
|
||||
* *
|
||||
* S’il vous plaît de ne pas répondre à ce message. *
|
||||
* Utilisez le OpenStreetMap site Web pour y répondre. *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
Hi <%= @to_user %>,
|
||||
|
@ -16,5 +28,17 @@ and you can comment at <%= @commenturl %>
|
|||
or reply at <%= @replyurl %>
|
||||
|
||||
***************************************************************************
|
||||
Please do not reply to this email. Use the OpenStreetMap web site to reply.
|
||||
* *
|
||||
* Please do not reply to this email. *
|
||||
* Use the OpenStreetMap web site to reply. *
|
||||
* *
|
||||
* Bitte antworten Sie nicht auf diese E-Mail. *
|
||||
* Verwenden Sie die OpenStreetMap Website zum antworten. *
|
||||
* *
|
||||
* Por favor, no responda a este mensaje. *
|
||||
* Utilice el OpenStreetMap sitio web para responder. *
|
||||
* *
|
||||
* S’il vous plaît de ne pas répondre à ce message. *
|
||||
* Utilisez le OpenStreetMap site Web pour y répondre. *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
***************************************************************************
|
||||
Please do not reply to this email. Use the OpenStreetMap web site to reply.
|
||||
* *
|
||||
* Please do not reply to this email. *
|
||||
* Use the OpenStreetMap web site to reply. *
|
||||
* *
|
||||
* Bitte antworten Sie nicht auf diese E-Mail. *
|
||||
* Verwenden Sie die OpenStreetMap Website zum antworten. *
|
||||
* *
|
||||
* Por favor, no responda a este mensaje. *
|
||||
* Utilice el OpenStreetMap sitio web para responder. *
|
||||
* *
|
||||
* S’il vous plaît de ne pas répondre à ce message. *
|
||||
* Utilisez le OpenStreetMap site Web pour y répondre. *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
Hi <%= @to_user %>,
|
||||
|
@ -14,5 +26,17 @@ You can also read the message at <%= @readurl %>
|
|||
and you can reply at <%= @replyurl %>
|
||||
|
||||
***************************************************************************
|
||||
Please do not reply to this email. Use the OpenStreetMap web site to reply.
|
||||
* *
|
||||
* Please do not reply to this email. *
|
||||
* Use the OpenStreetMap web site to reply. *
|
||||
* *
|
||||
* Bitte antworten Sie nicht auf diese E-Mail. *
|
||||
* Verwenden Sie die OpenStreetMap Website zum antworten. *
|
||||
* *
|
||||
* Por favor, no responda a este mensaje. *
|
||||
* Utilice el OpenStreetMap sitio web para responder. *
|
||||
* *
|
||||
* S’il vous plaît de ne pas répondre à ce message. *
|
||||
* Utilisez le OpenStreetMap site Web pour y répondre. *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
|
|
@ -39,9 +39,8 @@
|
|||
:complete => "endSearch()",
|
||||
:url => { :controller => :geocoder, :action => :search }) do %>
|
||||
<%= text_field_tag :query, h(params[:query]) %>
|
||||
|
||||
<%= submit_tag 'Go' %></td>
|
||||
<% end %>
|
||||
<%= submit_tag "Go" %>
|
||||
<% end %>
|
||||
</span>
|
||||
<p id="search_active">Searching...</p>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<% if API_STATUS == :offline %>
|
||||
<% if OSM_STATUS == :database_offline or OSM_STATUS == :api_offline %>
|
||||
<p>The OpenStreetMap database is currently offline while
|
||||
essential database maintenance work is carried out.
|
||||
</p>
|
||||
<% elsif API_STATUS == :readonly %>
|
||||
<% elsif OSM_STATUS == :api_readonly %>
|
||||
<p>The OpenStreetMap database is currently in read-only mode while
|
||||
essential database maintenance work is carried out.
|
||||
</p>
|
||||
|
@ -105,7 +105,29 @@
|
|||
|
||||
resizeMap();
|
||||
}
|
||||
|
||||
function maximiseMap() {
|
||||
$("left").style.display = "none";
|
||||
$("greeting").style.display = "none";
|
||||
$("tabnav").style.display = "none";
|
||||
|
||||
$("content").style.top = "10px";
|
||||
$("content").style.left = "10px";
|
||||
|
||||
handleResize();
|
||||
}
|
||||
|
||||
function minimiseMap() {
|
||||
$("left").style.display = "";
|
||||
$("greeting").style.display = "";
|
||||
$("tabnav").style.display = "";
|
||||
|
||||
$("content").style.top = "35px";
|
||||
$("content").style.left = "192px";
|
||||
|
||||
handleResize();
|
||||
}
|
||||
|
||||
handleResize();
|
||||
|
||||
window.onload = handleResize;
|
||||
|
|
|
@ -8,6 +8,14 @@
|
|||
<%= render :partial => 'key' %>
|
||||
<%= render :partial => 'search' %>
|
||||
|
||||
<noscript>
|
||||
<div id="noscript">
|
||||
<p>You are either using a browser that doesn't support javascript, or you have disabled javascript.</p>
|
||||
<p>OpenStreetMap uses javascript for its slippy map.</p>
|
||||
<p>You may want to try the <a href="http://tah.openstreetmap.org/Browse/">Tiles@Home static tile browser</a> if you are unable to enable javascript.</p>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<div id="map">
|
||||
<div id="permalink"><a href="/" id="permalinkanchor">Permalink</a></div>
|
||||
</div>
|
||||
|
@ -21,7 +29,7 @@
|
|||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
Licensed under the Creative Commons Attribution-Share Alike 2.0 license
|
||||
by the OpenStreetMap project and it's contributors.
|
||||
by the OpenStreetMap project and its contributors.
|
||||
</td>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -50,8 +58,8 @@ by the OpenStreetMap project and it's contributors.
|
|||
<% lat = h(params['mlat']) %>
|
||||
<% zoom = h(params['zoom'] || '12') %>
|
||||
<% layers = h(params['layers']) %>
|
||||
<% elsif cookies.key?("location") %>
|
||||
<% lon,lat,zoom,layers = cookies["location"].split(",") %>
|
||||
<% elsif cookies.key?("_osm_location") %>
|
||||
<% lon,lat,zoom,layers = cookies["_osm_location"].split("|") %>
|
||||
<% elsif @user and !@user.home_lon.nil? and !@user.home_lat.nil? %>
|
||||
<% lon = @user.home_lon %>
|
||||
<% lat = @user.home_lat %>
|
||||
|
@ -68,8 +76,8 @@ by the OpenStreetMap project and it's contributors.
|
|||
<% lon = '-0.1' %>
|
||||
<% lat = '51.5' %>
|
||||
<% zoom = h(params['zoom'] || '5') %>
|
||||
<% layers = h(params['layers']) %>
|
||||
<% end %>
|
||||
<% layers = h(params['layers']) %>
|
||||
<% end %>
|
||||
|
||||
<%= javascript_include_tag '/openlayers/OpenLayers.js' %>
|
||||
|
@ -86,6 +94,12 @@ by the OpenStreetMap project and it's contributors.
|
|||
function mapInit(){
|
||||
map = createMap("map");
|
||||
|
||||
<% unless OSM_STATUS == :api_offline or OSM_STATUS == :database_offline %>
|
||||
map.dataLayer = new OpenLayers.Layer("Data", { "visibility": false });
|
||||
map.dataLayer.events.register("visibilitychanged", map.dataLayer, toggleData);
|
||||
map.addLayer(map.dataLayer);
|
||||
<% end %>
|
||||
|
||||
<% if bbox %>
|
||||
var bbox = new OpenLayers.Bounds(<%= minlon %>, <%= minlat %>, <%= maxlon %>, <%= maxlat %>);
|
||||
|
||||
|
@ -101,7 +115,7 @@ by the OpenStreetMap project and it's contributors.
|
|||
setMapCenter(centre, zoom);
|
||||
<% end %>
|
||||
|
||||
<% if layers %>
|
||||
<% if !layers.nil? and !layers.empty? %>
|
||||
setMapLayers("<%= layers %>");
|
||||
<% end %>
|
||||
|
||||
|
@ -118,6 +132,14 @@ by the OpenStreetMap project and it's contributors.
|
|||
handleResize();
|
||||
}
|
||||
|
||||
function toggleData() {
|
||||
if (map.dataLayer.visibility) {
|
||||
<%= remote_function :url => { :controller => 'browse', :action => 'start' } %>
|
||||
} else {
|
||||
closeSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
function getPosition() {
|
||||
return getMapCenter();
|
||||
}
|
||||
|
@ -140,7 +162,7 @@ by the OpenStreetMap project and it's contributors.
|
|||
|
||||
updatelinks(lonlat.lon, lonlat.lat, zoom, layers);
|
||||
|
||||
document.cookie = "location=" + lonlat.lon + "," + lonlat.lat + "," + zoom + "," + layers;
|
||||
document.cookie = "_osm_location=" + lonlat.lon + "|" + lonlat.lat + "|" + zoom + "|" + layers;
|
||||
}
|
||||
|
||||
function resizeContent() {
|
||||
|
|
3
app/views/site/offline.rhtml
Normal file
3
app/views/site/offline.rhtml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<p>The OpenStreetMap database is currently offline while
|
||||
essential database maintenance work is carried out.
|
||||
</p>
|
|
@ -1,6 +1,10 @@
|
|||
<h2><%= h(@title) %></h2>
|
||||
|
||||
<img src="<%= url_for :controller => 'trace', :action => 'picture', :id => @trace.id, :display_name => @trace.user.display_name %>">
|
||||
<% if @trace.inserted %>
|
||||
<img src="<%= url_for :controller => 'trace', :action => 'picture', :id => @trace.id, :display_name => @trace.user.display_name %>">
|
||||
<% else %>
|
||||
<span style="color:red">PENDING</span>
|
||||
<% end %>
|
||||
|
||||
<table border="0">
|
||||
<tr>
|
||||
|
|
|
@ -1 +1,10 @@
|
|||
<h1>Confirm a user account</h1>
|
||||
|
||||
<p>Press the confirm button below to activate your account.</p>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="confirm_string" value="<%= params[:confirm_string] %>">
|
||||
<input type="submit" name="confirm_action" value="Confrm">
|
||||
</form>
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
ENV['RAILS_ENV'] ||= 'production'
|
||||
|
||||
# Specifies gem version of Rails to use when vendor/rails is not present
|
||||
# DO NOT BUMP THIS TO 2.0.2 AS THE LIVE SERVERS CAN'T RUN THAT
|
||||
RAILS_GEM_VERSION = '2.0.1' unless defined? RAILS_GEM_VERSION
|
||||
RAILS_GEM_VERSION = '2.0.2' unless defined? RAILS_GEM_VERSION
|
||||
|
||||
# Set the server URL
|
||||
SERVER_URL = ENV['OSM_SERVER_URL'] || 'www.openstreetmap.org'
|
||||
|
@ -14,9 +13,14 @@ SERVER_URL = ENV['OSM_SERVER_URL'] || 'www.openstreetmap.org'
|
|||
# Application constants needed for routes.rb - must go before Initializer call
|
||||
API_VERSION = ENV['OSM_API_VERSION'] || '0.6'
|
||||
|
||||
# Set to :readonly to put the API in read-only mode or :offline to
|
||||
# take it completely offline
|
||||
API_STATUS = :online
|
||||
# Set application status - possible settings are:
|
||||
#
|
||||
# :online - online and operating normally
|
||||
# :api_readonly - site online but API in read-only mode
|
||||
# :api_offline - site online but API offline
|
||||
# :database_offline - database offline with site in emergency mode
|
||||
#
|
||||
OSM_STATUS = :online
|
||||
|
||||
# Bootstrap the Rails environment, frameworks, and default configuration
|
||||
require File.join(File.dirname(__FILE__), 'boot')
|
||||
|
@ -29,7 +33,9 @@ Rails::Initializer.run do |config|
|
|||
|
||||
# Skip frameworks you're not going to use (only works if using vendor/rails).
|
||||
# To use Rails without a database, you must remove the Active Record framework
|
||||
# config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
|
||||
if OSM_STATUS == :database_offline
|
||||
config.frameworks -= [ :active_record ]
|
||||
end
|
||||
|
||||
# Only load the plugins named here, in the order given. By default, all plugins
|
||||
# in vendor/plugins are loaded in alphabetical order.
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
require 'rubygems'
|
||||
gem 'composite_primary_keys', '= 0.9.93'
|
||||
require 'composite_primary_keys'
|
||||
|
|
|
@ -63,6 +63,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', :controller => 'browse', :action => 'index'
|
||||
map.connect '/browse/start', :controller => 'browse', :action => 'start'
|
||||
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'
|
||||
|
@ -70,6 +80,7 @@ ActionController::Routing::Routes.draw do |map|
|
|||
map.connect '/export', :controller => 'site', :action => 'export'
|
||||
map.connect '/login', :controller => 'user', :action => 'login'
|
||||
map.connect '/logout', :controller => 'user', :action => 'logout'
|
||||
map.connect '/offline', :controller => 'site', :action => 'offline'
|
||||
map.connect '/user/new', :controller => 'user', :action => 'new'
|
||||
map.connect '/user/save', :controller => 'user', :action => 'save'
|
||||
map.connect '/user/confirm', :controller => 'user', :action => 'confirm'
|
||||
|
@ -150,7 +161,6 @@ ActionController::Routing::Routes.draw do |map|
|
|||
map.connect '/message/read/:message_id', :controller => 'message', :action => 'read'
|
||||
map.connect '/message/mark/:message_id', :controller => 'message', :action => 'mark'
|
||||
map.connect '/message/reply/:message_id', :controller => 'message', :action => 'reply'
|
||||
map.connect '/message/delete/:message_id', :controller => 'message', :action => 'destroy'
|
||||
|
||||
# fall through
|
||||
map.connect ':controller/:id/:action'
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
class GeoRecord < ActiveRecord::Base
|
||||
before_save :update_tile
|
||||
module GeoRecord
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
# This is a scaling factor for going between the lat and lon via the API
|
||||
# and the longitude and latitude that is stored in the database
|
||||
SCALE = 10000000
|
||||
def before_save
|
||||
self.update_tile
|
||||
end
|
||||
|
||||
# Is this node within -90 <= latitude <= 90 and -180 <= longitude <= 180
|
||||
# Is this node within -90 >= latitude >= 90 and -180 >= longitude >= 180
|
||||
# * returns true/false
|
||||
def in_world?
|
||||
return false if self.lat < -90 or self.lat > 90
|
||||
|
@ -13,32 +15,26 @@ class GeoRecord < ActiveRecord::Base
|
|||
return true
|
||||
end
|
||||
|
||||
def self.find_by_area(minlat, minlon, maxlat, maxlon, options)
|
||||
self.with_scope(:find => {:conditions => OSM.sql_for_area(minlat, minlon, maxlat, maxlon)}) do
|
||||
return self.find(:all, options)
|
||||
end
|
||||
end
|
||||
|
||||
def update_tile
|
||||
self.tile = QuadTile.tile_for_point(lat, lon)
|
||||
end
|
||||
|
||||
def lat=(l)
|
||||
self.latitude = (l * SCALE).round
|
||||
self.latitude = (l * 10000000).round
|
||||
end
|
||||
|
||||
def lon=(l)
|
||||
self.longitude = (l * SCALE).round
|
||||
self.longitude = (l * 10000000).round
|
||||
end
|
||||
|
||||
# Return WGS84 latitude
|
||||
def lat
|
||||
return self.latitude.to_f / SCALE
|
||||
return self.latitude.to_f / 10000000
|
||||
end
|
||||
|
||||
# Return WGS84 longitude
|
||||
def lon
|
||||
return self.longitude.to_f / SCALE
|
||||
return self.longitude.to_f / 10000000
|
||||
end
|
||||
|
||||
# Potlatch projections
|
||||
|
@ -50,11 +46,18 @@ class GeoRecord < ActiveRecord::Base
|
|||
-(lat2y(self.lat)-basey)*masterscale
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def lat2y(a)
|
||||
180/Math::PI * Math.log(Math.tan(Math::PI/4+a*(Math::PI/180)/2))
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def find_by_area(minlat, minlon, maxlat, maxlon, options)
|
||||
self.with_scope(:find => {:conditions => OSM.sql_for_area(minlat, minlon, maxlat, maxlon)}) do
|
||||
return self.find(:all, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
5
lib/object_finder.rb
Normal file
5
lib/object_finder.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
module ObjectFinder
|
||||
def visible
|
||||
find :all, :conditions => "#{proxy_reflection.table_name}.visible = 1"
|
||||
end
|
||||
end
|
|
@ -37,13 +37,20 @@
|
|||
attribution: attribution
|
||||
});
|
||||
map.addLayer(mapnik);
|
||||
} else {
|
||||
} else if (args.layer == "osmarender") {
|
||||
var osmarender = new OpenLayers.Layer.OSM.Osmarender("Osmarender", {
|
||||
displayOutsideMaxExtent: true,
|
||||
wrapDateLine: true,
|
||||
attribution: attribution
|
||||
});
|
||||
map.addLayer(osmarender);
|
||||
} else if (args.layer == "cycle map") {
|
||||
var cyclemap = new OpenLayers.Layer.OSM.CycleMap("Cycle Map", {
|
||||
displayOutsideMaxExtent: true,
|
||||
wrapDateLine: true,
|
||||
attribution: attribution
|
||||
});
|
||||
map.addLayer(cyclemap);
|
||||
}
|
||||
|
||||
if (args.marker) {
|
||||
|
|
|
@ -7,9 +7,11 @@ OpenLayers._getScriptLocation = function () {
|
|||
return "/openlayers/";
|
||||
}
|
||||
|
||||
function createMap(divName) {
|
||||
function createMap(divName, options) {
|
||||
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 +20,7 @@ function createMap(divName) {
|
|||
new OpenLayers.Control.ScaleLine()
|
||||
],
|
||||
units: "m",
|
||||
maxResolution: 156543,
|
||||
maxResolution: 156543.0339,
|
||||
numZoomLevels: 20
|
||||
});
|
||||
|
||||
|
@ -34,6 +36,12 @@ function createMap(divName) {
|
|||
});
|
||||
map.addLayer(osmarender);
|
||||
|
||||
var cyclemap = new OpenLayers.Layer.OSM.CycleMap("Cycle Map", {
|
||||
displayOutsideMaxExtent: true,
|
||||
wrapDateLine: true
|
||||
});
|
||||
map.addLayer(cyclemap);
|
||||
|
||||
var maplint = new OpenLayers.Layer.OSM.Maplint("Maplint", {
|
||||
displayOutsideMaxExtent: true,
|
||||
wrapDateLine: true
|
||||
|
@ -118,33 +126,41 @@ function getEventPosition(event) {
|
|||
}
|
||||
|
||||
function getMapLayers() {
|
||||
var layers = "";
|
||||
var layerConfig = "";
|
||||
|
||||
for (var i=0; i< this.map.layers.length; i++) {
|
||||
var layer = this.map.layers[i];
|
||||
for (var layers = map.getLayersBy("isBaseLayer", true), i = 0; i < layers.length; i++) {
|
||||
layerConfig += layers[i] == map.baseLayer ? "B" : "0";
|
||||
}
|
||||
|
||||
if (layer.isBaseLayer) {
|
||||
layers += (layer == this.map.baseLayer) ? "B" : "0";
|
||||
} else {
|
||||
layers += (layer.getVisibility()) ? "T" : "F";
|
||||
for (var layers = map.getLayersBy("isBaseLayer", false), i = 0; i < layers.length; i++) {
|
||||
layerConfig += layers[i].getVisibility() ? "T" : "F";
|
||||
}
|
||||
|
||||
return layerConfig;
|
||||
}
|
||||
|
||||
function setMapLayers(layerConfig) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
while (layerConfig.charAt(l) == "B" || layerConfig.charAt(l) == "0") {
|
||||
l++;
|
||||
}
|
||||
|
||||
function setMapLayers(layers) {
|
||||
for (var i=0; i < layers.length; i++) {
|
||||
var layer = map.layers[i];
|
||||
for (var layers = map.getLayersBy("isBaseLayer", false), i = 0; i < layers.length; i++) {
|
||||
var c = layerConfig.charAt(l++);
|
||||
|
||||
if (layer) {
|
||||
var c = layers.charAt(i);
|
||||
|
||||
if (c == "B") {
|
||||
map.setBaseLayer(layer);
|
||||
} else if ( (c == "T") || (c == "F") ) {
|
||||
layer.setVisibility(c == "T");
|
||||
}
|
||||
if (c == "T") {
|
||||
layers[i].setVisibility(true);
|
||||
} else if(c == "F") {
|
||||
layers[i].setVisibility(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
@ -155,6 +155,34 @@ OpenLayers.Layer.OSM.Osmarender = OpenLayers.Class(OpenLayers.Layer.OSM, {
|
|||
CLASS_NAME: "OpenLayers.Layer.OSM.Osmarender"
|
||||
});
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Layer.OSM.CycleMap
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Layer.OSM>
|
||||
*/
|
||||
OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
|
||||
/**
|
||||
* Constructor: OpenLayers.Layer.OSM.CycleMap
|
||||
*
|
||||
* Parameters:
|
||||
* name - {String}
|
||||
* options - {Object} Hashtable of extra options to tag onto the layer
|
||||
*/
|
||||
initialize: function(name, options) {
|
||||
var url = [
|
||||
"http://a.thunderflames.org/tiles/cycle/",
|
||||
"http://b.thunderflames.org/tiles/cycle/",
|
||||
"http://c.thunderflames.org/tiles/cycle/"
|
||||
];
|
||||
options = OpenLayers.Util.extend({ numZoomLevels: 17 }, options);
|
||||
var newArguments = [name, url, options];
|
||||
OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Layer.OSM.CycleMap"
|
||||
});
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Layer.OSM.Maplint
|
||||
*
|
||||
|
|
Binary file not shown.
|
@ -354,14 +354,21 @@ hides rule from IE5-Mac \*/
|
|||
padding: 0px;
|
||||
}
|
||||
|
||||
#search_field form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.optionalbox input[type="text"] {
|
||||
width: 110px;
|
||||
#search_field input[type="text"] {
|
||||
width: 116px;
|
||||
}
|
||||
|
||||
#search_field input[type="submit"] {
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.search_form {
|
||||
height: 16px;
|
||||
padding-bottom: 2px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
#search_active {
|
||||
|
@ -447,6 +454,18 @@ hides rule from IE5-Mac \*/
|
|||
background: #bbb;
|
||||
}
|
||||
|
||||
.browse_heading {
|
||||
margin: 0px;
|
||||
padding: 3px 6px 3px 6px;
|
||||
border: 1px solid #ccc;
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.browse_details {
|
||||
margin: 0px;
|
||||
padding: 0px 6px 0px 6px;
|
||||
}
|
||||
|
||||
.search_results_heading {
|
||||
margin: 0px;
|
||||
padding: 3px 6px 3px 6px;
|
||||
|
@ -635,3 +654,10 @@ input[type="submit"] {
|
|||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#noscript {
|
||||
z-index:20000000;
|
||||
position:absolute;
|
||||
top:15px;
|
||||
left:15px
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue