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
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
# 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']
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
return
end
- relations = Array.new
-
doc = OSM::API.new.get_xml_doc
# get ways
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.
# 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])
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
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
--- /dev/null
+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
before_filter :authorize_web
before_filter :require_user, :only => [:new]
+ before_filter :check_database_availability
def new
@title = 'new diary entry'
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
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
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
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
end
end
- private
+private
def do_create(file, tags, description, public)
name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, '_')
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
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
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
--- /dev/null
+module BrowseHelper
+end
-class Node < GeoRecord
+class Node < ActiveRecord::Base
require 'xml/libxml'
+ include GeoRecord
+
set_table_name 'current_nodes'
validates_presence_of :user_id, :timestamp
validates_numericality_of :latitude, :longitude
validate :validate_position
+ belongs_to :user
+
has_many :old_nodes, :foreign_key => :id
+
has_many :way_nodes
- has_many :node_tags, :foreign_key => :id
- belongs_to :user
-
+ 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
#
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)
- end
- rescue
- return nil
- end
- end
+ node.lat = pt['lat'].to_f
+ node.lon = pt['lon'].to_f
- 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?
- return nil unless node.in_world?
+ unless create
+ if pt['id'] != '0'
+ node.id = pt['id'].to_i
+ end
+ end
- unless create
- if pt['id'] != '0'
- node.id = pt['id'].to_i
- end
- end
+ node.visible = pt['visible'] and pt['visible'] == 'true'
- 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
- if create
- node.timestamp = Time.now
- else
- if pt['timestamp']
- node.timestamp = Time.parse(pt['timestamp'])
- end
- end
+ tags = []
- tags = []
+ pt.find('tag').each do |tag|
+ tags << [tag['k'],tag['v']]
+ end
- pt.find('tag').each do |tag|
- node.add_tag_key_val(tag['k'],tag['v'])
+ node.tags = Tags.join(tags)
+ end
+ rescue
+ 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!
- 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)
+ old_node.save!
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
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
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
- end
-
- def tags=(t)
- @tags = t
- end
-
- def add_tag_key_val(k,v)
- @tags = Hash.new unless @tags
- @tags[k] = v
+ hash
end
-
-
-
end
-class OldNode < GeoRecord
+class OldNode < ActiveRecord::Base
+ include GeoRecord
+
set_table_name 'nodes'
validates_presence_of :user_id, :timestamp
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'
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
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
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
class OldRelationMember < ActiveRecord::Base
- belongs_to :user
-
set_table_name 'relation_members'
-
end
class OldRelationTag < ActiveRecord::Base
- belongs_to :user
-
set_table_name 'relation_tags'
-
end
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
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
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
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
return false
end
+ # Temporary method to match interface to nodes
+ def tags_as_hash
+ return self.tags
+ end
end
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
+
+ def after_find
+ self[:member_class] = self.member_type.capitalize
+ end
- # 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_initialize
+ 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 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
# 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
-class Tracepoint < GeoRecord
+class Tracepoint < ActiveRecord::Base
+ include GeoRecord
+
set_table_name 'gps_points'
validates_numericality_of :trackid, :only_integer => true
class Way < ActiveRecord::Base
require 'xml/libxml'
+ set_table_name 'current_ways'
+
belongs_to :user
- has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
+ has_many :old_ways, :foreign_key => 'id', :order => 'version'
+
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
- has_many :way_tags, :foreign_key => 'id'
+ has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
- has_many :old_ways, :foreign_key => 'id', :order => 'version'
+ has_many :way_tags, :foreign_key => 'id'
- set_table_name 'current_ways'
+ 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
self.delete_with_history(user)
end
+
+ # Temporary method to match interface to nodes
+ def tags_as_hash
+ return self.tags
+ end
end
--- /dev/null
+<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 %>
--- /dev/null
+<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>
--- /dev/null
+<%= 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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<tr>
+ <td><%= h(tag[0]) %> = <%= h(tag[1]) %></td>
+</tr>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+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
--- /dev/null
+<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>
--- /dev/null
+<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>
removeMarkerFromMap(marker);
}
- marker = addMarkerToMap(merc, null, "Diary entry location");
+ marker = addMarkerToMap(lonlat, null, "Diary entry location");
}
function openMap() {
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;
<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>
</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.
<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>
-<% 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>
<%= 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>
</tr>
<tr>
<th></th>
- <td><%= submit_tag 'Send', :action => 'new' %></td>
+ <td><%= submit_tag 'Send' %></td>
</tr>
</table>
<% end %>
<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>
***************************************************************************
-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 %>,
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. *
+* *
***************************************************************************
***************************************************************************
-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 %>,
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. *
+* *
***************************************************************************
: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>
-<% 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>
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;
<%= 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>
<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>
<% 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 %>
<% 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' %>
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 %>);
setMapCenter(centre, zoom);
<% end %>
- <% if layers %>
+ <% if !layers.nil? and !layers.empty? %>
setMapLayers("<%= layers %>");
<% end %>
handleResize();
}
+ function toggleData() {
+ if (map.dataLayer.visibility) {
+ <%= remote_function :url => { :controller => 'browse', :action => 'start' } %>
+ } else {
+ closeSidebar();
+ }
+ }
+
function getPosition() {
return getMapCenter();
}
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() {
--- /dev/null
+<p>The OpenStreetMap database is currently offline while
+ essential database maintenance work is carried out.
+</p>
<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>
+<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>
+
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'
# 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')
# 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.
+require 'rubygems'
+gem 'composite_primary_keys', '= 0.9.93'
require 'composite_primary_keys'
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'
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'
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'
-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
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
-(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
--- /dev/null
+module ObjectFinder
+ def visible
+ find :all, :conditions => "#{proxy_reflection.table_name}.visible = 1"
+ end
+end
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) {
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(),
new OpenLayers.Control.ScaleLine()
],
units: "m",
- maxResolution: 156543,
+ maxResolution: 156543.0339,
numZoomLevels: 20
});
});
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
}
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 layers;
+ return layerConfig;
}
-function setMapLayers(layers) {
- for (var i=0; i < layers.length; i++) {
- var layer = map.layers[i];
+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]);
+ }
+ }
+
+ while (layerConfig.charAt(l) == "B" || layerConfig.charAt(l) == "0") {
+ l++;
+ }
- if (layer) {
- var c = layers.charAt(i);
+ for (var layers = map.getLayersBy("isBaseLayer", false), i = 0; i < layers.length; i++) {
+ var c = layerConfig.charAt(l++);
- 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);
}
}
}
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"
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
*
padding: 0px;
}
+#search_field form {
+ width: 100%;
+}
+
+#search_field input[type="text"] {
+ width: 116px;
+}
-.optionalbox input[type="text"] {
- width: 110px;
+#search_field input[type="submit"] {
+ width: 26px;
}
.search_form {
height: 16px;
- padding-bottom: 2px;
+ padding-bottom: 6px;
}
#search_active {
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;
width: 100%;
text-align: center;
}
+
+#noscript {
+ z-index:20000000;
+ position:absolute;
+ top:15px;
+ left:15px
+}