Merge remote-tracking branch 'upstream/master' into routing

Conflicts:
	app/assets/javascripts/index.js
	app/assets/javascripts/leaflet.map.js.erb
	config/environments/production.rb
	config/locales/de.yml
This commit is contained in:
Matt Amos 2014-11-03 11:08:13 +00:00
commit a3eb48385b
350 changed files with 152983 additions and 97554 deletions

4
.gitignore vendored
View file

@ -7,3 +7,7 @@ tmp
.DS_Store
*~
doc
.vagrant
.ruby-gemset
.ruby-version
.idea

View file

@ -6,7 +6,17 @@ After [installing](INSTALL.md) this software, you may need to carry out some of
Your installation comes with no geographic data loaded. You can either create new data using one of the editors (Potlatch 2, iD, JOSM etc) or by loading an OSM extract.
* Use this [yet-to-be-written script](https://github.com/openstreetmap/openstreetmap-website/issues/282)
After installing but before creating any users or data, import an extract with [Osmosis](http://wiki.openstreetmap.org/wiki/Osmosis) and the [``--write-apidb``](http://wiki.openstreetmap.org/wiki/Osmosis/Detailed_Usage#--write-apidb_.28--wd.29) task.
```
osmosis --read-pbf greater-london-latest.osm.pbf \
--write-apidb host="localhost" database="openstreetmap" \
user="openstreetmap" password="" validateSchemaVersion="no"
```
Loading an apidb database with Osmosis is about **twenty** times slower than loading the equivalent data with osm2pgsql into a rendering database. [``--log-progress``](http://wiki.openstreetmap.org/wiki/Osmosis/Detailed_Usage#--log-progress_.28--lp.29) may be desirable for status updates.
To be able to edit the data you have loaded, you will need to use this [yet-to-be-written script](https://github.com/openstreetmap/openstreetmap-website/issues/282).
## Managing Users
@ -115,3 +125,5 @@ If you want to deploy The Rails Port for production use, you'll need to make a f
* Your production database will also need the extensions and functions installed - see [INSTALL.md](INSTALL.md)
* The included version of the map call is quite slow and eats a lot of memory. You should consider using [CGIMap](https://github.com/zerebubuth/openstreetmap-cgimap) instead.
* The included version of the GPX importer is slow and/or completely inoperable. You should consider using [the high-speed GPX importer](http://git.openstreetmap.org/gpx-import.git/).
* Make sure you precompile the production assets: `RAILS_ENV=production rake assets:precompile`
* Make sure the web server user as well as the rails user can read, write and create directories in `tmp/`.

13
Gemfile
View file

@ -1,7 +1,7 @@
source 'http://rubygems.org'
source 'https://rubygems.org'
# Require rails
gem 'rails', '4.0.3'
gem 'rails', '4.1.6'
# Require things which have moved to gems in ruby 1.9
gem 'bigdecimal', "~> 1.1.0", :platforms => :ruby_19
@ -16,7 +16,7 @@ gem 'json'
gem 'pg'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'
gem 'sass-rails', '~> 4.0.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
@ -34,6 +34,9 @@ gem 'jsonify-rails'
# Use R2 for RTL conversion
gem 'r2'
# Use autoprefixer to generate CSS prefixes
gem 'autoprefixer-rails'
# Load rails plugins
gem 'rails-i18n', "~> 4.0.0"
gem 'dynamic_form'
@ -41,7 +44,7 @@ gem 'rinku', '>= 1.2.2', :require => 'rails_rinku'
gem 'oauth-plugin', '>= 0.5.1'
gem 'open_id_authentication', '>= 1.1.0'
gem 'validates_email_format_of', '>= 1.5.1'
gem 'composite_primary_keys', '>= 6.0.1'
gem 'composite_primary_keys', '~> 7.0.11'
gem 'http_accept_language', '~> 2.0.0'
gem 'paperclip', '~> 4.0'
gem 'deadlock_retry', '>= 1.2.0'
@ -84,7 +87,7 @@ end
# Gems needed for running tests
group :test do
gem 'timecop'
gem 'minitest', '~> 4.7.0', :platforms => [:ruby_19, :ruby_20]
gem 'minitest', '~> 5.1', :platforms => [:ruby_19, :ruby_20]
end
# Needed in development as well so rake can see konacha tasks

View file

@ -1,38 +1,41 @@
GEM
remote: http://rubygems.org/
remote: https://rubygems.org/
specs:
SystemTimer (1.2.3)
actionmailer (4.0.3)
actionpack (= 4.0.3)
mail (~> 2.5.4)
actionpack (4.0.3)
activesupport (= 4.0.3)
builder (~> 3.1.0)
erubis (~> 2.7.0)
actionmailer (4.1.6)
actionpack (= 4.1.6)
actionview (= 4.1.6)
mail (~> 2.5, >= 2.5.4)
actionpack (4.1.6)
actionview (= 4.1.6)
activesupport (= 4.1.6)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
actionpack-page_caching (1.0.2)
actionpack (>= 4.0.0, < 5)
activemodel (4.0.3)
activesupport (= 4.0.3)
builder (~> 3.1.0)
activerecord (4.0.3)
activemodel (= 4.0.3)
activerecord-deprecated_finders (~> 1.0.2)
activesupport (= 4.0.3)
arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3)
activesupport (4.0.3)
i18n (~> 0.6, >= 0.6.4)
minitest (~> 4.2)
multi_json (~> 1.3)
actionview (4.1.6)
activesupport (= 4.1.6)
builder (~> 3.1)
erubis (~> 2.7.0)
activemodel (4.1.6)
activesupport (= 4.1.6)
builder (~> 3.1)
activerecord (4.1.6)
activemodel (= 4.1.6)
activesupport (= 4.1.6)
arel (~> 5.0.0)
activesupport (4.1.6)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
arel (4.0.2)
atomic (1.1.15)
tzinfo (~> 1.1)
arel (5.0.1.20140414130214)
autoprefixer-rails (3.1.1.20141001)
execjs
bigdecimal (1.1.0)
builder (3.1.4)
capybara (2.2.1)
builder (3.2.2)
capybara (2.4.3)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
@ -41,32 +44,33 @@ GEM
climate_control (0.0.3)
activesupport (>= 3.0)
cliver (0.3.2)
cocaine (0.5.3)
cocaine (0.5.4)
climate_control (>= 0.0.3, < 1.0)
coffee-rails (4.0.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0)
coffee-script (2.2.0)
coffee-script (2.3.0)
coffee-script-source
execjs
coffee-script-source (1.7.0)
colorize (0.6.0)
composite_primary_keys (6.0.1)
activerecord (>= 4.0.0)
dalli (2.7.0)
coffee-script-source (1.8.0)
colorize (0.7.3)
composite_primary_keys (7.0.11)
activerecord (= 4.1.6)
crass (0.2.1)
dalli (2.7.2)
deadlock_retry (1.2.0)
dynamic_form (1.1.4)
erubis (2.7.0)
execjs (2.0.2)
execjs (2.2.1)
faraday (0.9.0)
multipart-post (>= 1.2, < 3)
hike (1.2.3)
htmlentities (4.3.1)
http_accept_language (2.0.1)
httpclient (2.3.4.1)
i18n (0.6.9)
htmlentities (4.3.2)
http_accept_language (2.0.2)
httpclient (2.4.0)
i18n (0.6.11)
iconv (0.1)
jquery-rails (3.1.0)
jquery-rails (3.1.2)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
@ -75,36 +79,36 @@ GEM
jsonify-rails (0.3.2)
actionpack
jsonify (< 0.4.0)
jwt (0.1.11)
multi_json (>= 1.5)
jwt (1.0.0)
kgio (2.9.2)
konacha (3.1.0)
konacha (3.2.4)
actionpack (>= 3.1, < 5)
capybara
colorize
railties (>= 3.1, < 5)
sprockets
libxml-ruby (2.7.0)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.25.1)
mini_portile (0.5.2)
minitest (4.7.5)
multi_json (1.8.4)
mail (2.6.1)
mime-types (>= 1.16, < 3)
mime-types (2.4.1)
mini_portile (0.6.0)
minitest (5.4.2)
multi_json (1.10.1)
multi_xml (0.5.5)
multipart-post (2.0.0)
nokogiri (1.6.1)
mini_portile (~> 0.5.0)
nokogiri (1.6.3.1)
mini_portile (= 0.6.0)
nokogumbo (1.1.12)
nokogiri
oauth (0.4.7)
oauth-plugin (0.5.1)
multi_json
oauth (~> 0.4.4)
oauth2 (>= 0.5.0)
rack
oauth2 (0.9.3)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
jwt (~> 0.1.8)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
@ -112,20 +116,19 @@ GEM
rack-openid (~> 1.3)
openstreetmap-i18n-js (3.0.0.rc5.3)
i18n
paperclip (4.1.1)
paperclip (4.2.0)
activemodel (>= 3.0.0)
activesupport (>= 3.0.0)
cocaine (~> 0.5.3)
mime-types
pg (0.17.1)
poltergeist (1.5.0)
poltergeist (1.5.1)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
polyglot (0.3.4)
psych (2.0.4)
r2 (0.2.2)
psych (2.0.6)
r2 (0.2.5)
rack (1.5.2)
rack-cors (0.2.9)
rack-openid (1.4.2)
@ -133,58 +136,61 @@ GEM
ruby-openid (>= 2.1.8)
rack-test (0.6.2)
rack (>= 1.0)
rails (4.0.3)
actionmailer (= 4.0.3)
actionpack (= 4.0.3)
activerecord (= 4.0.3)
activesupport (= 4.0.3)
rails (4.1.6)
actionmailer (= 4.1.6)
actionpack (= 4.1.6)
actionview (= 4.1.6)
activemodel (= 4.1.6)
activerecord (= 4.1.6)
activesupport (= 4.1.6)
bundler (>= 1.3.0, < 2.0)
railties (= 4.0.3)
sprockets-rails (~> 2.0.0)
rails-i18n (4.0.1)
railties (= 4.1.6)
sprockets-rails (~> 2.0)
rails-i18n (4.0.3)
i18n (~> 0.6)
rails (~> 4.0)
railties (4.0.3)
actionpack (= 4.0.3)
activesupport (= 4.0.3)
railties (~> 4.0)
railties (4.1.6)
actionpack (= 4.1.6)
activesupport (= 4.1.6)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.1.1)
redcarpet (3.1.1)
rake (10.3.2)
redcarpet (3.1.2)
rinku (1.7.3)
ruby-openid (2.5.0)
sanitize (2.1.0)
sanitize (3.0.2)
crass (~> 0.2.0)
nokogiri (>= 1.4.4)
sass (3.2.14)
sass-rails (4.0.1)
nokogumbo (= 1.1.12)
sass (3.2.19)
sass-rails (4.0.3)
railties (>= 4.0.0, < 5.0)
sass (>= 3.1.10)
sprockets-rails (~> 2.0.0)
sass (~> 3.2.0)
sprockets (~> 2.8, <= 2.11.0)
sprockets-rails (~> 2.0)
soap4r-ruby1.9 (2.0.5)
sprockets (2.11.0)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.0.1)
sprockets-rails (2.1.4)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
thor (0.18.1)
thread_safe (0.2.0)
atomic (>= 1.1.7, < 2)
thor (0.19.1)
thread_safe (0.3.4)
tilt (1.4.1)
timecop (0.7.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.38)
uglifier (2.4.0)
tzinfo (1.2.2)
thread_safe (~> 0.1)
uglifier (2.5.3)
execjs (>= 0.3.0)
json (>= 1.8.0)
validates_email_format_of (1.5.3)
vendorer (0.1.14)
websocket-driver (0.3.2)
validates_email_format_of (1.6.1)
i18n
vendorer (0.1.16)
websocket-driver (0.3.5)
xpath (2.0.0)
nokogiri (~> 1.3)
@ -194,9 +200,10 @@ PLATFORMS
DEPENDENCIES
SystemTimer (>= 1.1.3)
actionpack-page_caching
autoprefixer-rails
bigdecimal (~> 1.1.0)
coffee-rails (~> 4.0.0)
composite_primary_keys (>= 6.0.1)
composite_primary_keys (~> 7.0.11)
dalli
deadlock_retry (>= 1.2.0)
dynamic_form
@ -210,7 +217,7 @@ DEPENDENCIES
kgio
konacha
libxml-ruby (>= 2.0.5)
minitest (~> 4.7.0)
minitest (~> 5.1)
oauth-plugin (>= 0.5.1)
open_id_authentication (>= 1.1.0)
openstreetmap-i18n-js (>= 3.0.0.rc5.3)
@ -220,13 +227,13 @@ DEPENDENCIES
psych
r2
rack-cors
rails (= 4.0.3)
rails (= 4.1.6)
rails-i18n (~> 4.0.0)
redcarpet
rinku (>= 1.2.2)
ruby-openid (>= 2.2.0)
sanitize
sass-rails (~> 4.0.0)
sass-rails (~> 4.0.3)
soap4r-ruby1.9
timecop
uglifier (>= 1.3.0)

View file

@ -3,11 +3,12 @@
These instructions are designed for setting up The Rails Port for development and testing.
If you want to deploy the software for your own project, then see the notes at the end.
You can install the software directly on your machine, which is the traditional and probably best-bupported approach. However, there is an alternative which may be easier: Vagrant. This installs the software into a virtual machine, which makes it easier to get a consistent development environment and may avoid installation difficulties. For Vagrant instructions, see [VAGRANT.md](VAGRANT.md).
These instructions are based on Ubuntu 12.04 LTS, which is the platform used by the OSMF servers.
The instructions also work, with only minor amendments, for all other current Ubuntu releases, Fedora and MacOSX
We don't recommend attempting to develop or deploy this software on Windows. If you need to use Windows, then
try developing this sofware using Ubuntu in a virtual machine.
We don't recommend attempting to develop or deploy this software on Windows. If you need to use Windows, then try developing this sofware using Ubuntu in a virtual machine, or use [Vagrant](VAGRANT.md).
## Dependencies
@ -32,7 +33,7 @@ sudo apt-get install ruby1.9.1 libruby1.9.1 ruby1.9.1-dev ri1.9.1 \
apache2 apache2-threaded-dev build-essential git-core \
postgresql postgresql-contrib libpq-dev postgresql-server-dev-all \
libsasl2-dev
gem1.9.1 install bundle
sudo gem1.9.1 install bundler
```
Note that the "1.9.1" Ubuntu packages do in fact contain ruby 1.9.3.

46
VAGRANT.md Normal file
View file

@ -0,0 +1,46 @@
# Installing Vagrant
On Ubuntu, it should be as simple as:
```
sudo apt-get install vagrant
```
Other Linux distributions should have similar installation instructions using `yum` or similar.
Installers are available for Mac OS X and Windows, please see the [Vagrant project download page](http://www.vagrantup.com/downloads) for more information.
# Setting up openstreetmap-website
Once Vagrant has been installed, you can start an environment by checking out the openstreetmap-website code if you haven't already, then changing to the directory which contains the Vagrantfile by typing:
```
git clone git@github.com:openstreetmap/openstreetmap-website.git
cd openstreetmap-website
vagrant up
```
This will take a few minutes to download required software from the internet and set it up as a running system. Once it is complete, you should be able to log into the running VM by typing:
```
vagrant ssh
```
Within this login shell, you can do development, run the server or the tests. For example, to run the tests:
```
cd /srv/openstreetmap-website/
rake test
```
To access the web pages you run the following commands then access the site in your [local browser](http://localhost:3000):
```
vagrant ssh
cd /srv/openstreetmap-website/
rails server
```
You edit the code on your computer using the code editor you are used to using, then through shared folders the code is updated on the VM instantly.
You should run the tests before submitting any patch or Pull Request back to the original repository. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more information.

16
Vagrantfile vendored Normal file
View file

@ -0,0 +1,16 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "precise64"
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
# port forward for webrick on 3000
config.vm.network :forwarded_port, guest: 3000, host: 3000
# set up synced folder to source in /srv/openstreetmap-website
config.vm.synced_folder ".", "/srv/openstreetmap-website"
# provision using a simple shell script
config.vm.provision :shell, :path => "script/vagrant/setup/provision.sh"
end

View file

@ -11,13 +11,13 @@ folder 'vendor/assets' do
end
folder 'leaflet' do
file 'leaflet.js', 'http://cdn.leafletjs.com/leaflet-0.7.2/leaflet-src.js'
file 'leaflet.css', 'http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css'
file 'leaflet.js', 'http://cdn.leafletjs.com/leaflet-0.7.3/leaflet-src.js'
file 'leaflet.css', 'http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css'
[ 'layers.png', 'layers-2x.png',
'marker-icon.png', 'marker-icon-2x.png',
'marker-shadow.png' ].each do |image|
file "images/#{image}", "http://cdn.leafletjs.com/leaflet-0.7.2/images/#{image}"
file "images/#{image}", "http://cdn.leafletjs.com/leaflet-0.7.3/images/#{image}"
end
from 'git://github.com/kajic/leaflet-locationfilter.git' do

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 222 B

Before After
Before After

BIN
app/assets/images/sotm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -22,19 +22,22 @@ var querystring = require('querystring-component');
function remoteEditHandler(bbox, object) {
var loaded = false,
query = {
left: bbox.getWest() - 0.0001,
top: bbox.getNorth() + 0.0001,
right: bbox.getEast() + 0.0001,
bottom: bbox.getSouth() - 0.0001
};
url = document.location.protocol === "https:" ?
"https://127.0.0.1:8112/load_and_zoom?" :
"http://127.0.0.1:8111/load_and_zoom?",
query = {
left: bbox.getWest() - 0.0001,
top: bbox.getNorth() + 0.0001,
right: bbox.getEast() + 0.0001,
bottom: bbox.getSouth() - 0.0001
};
if (object) query.select = object.type + object.id;
var iframe = $('<iframe>')
.hide()
.appendTo('body')
.attr("src", "http://127.0.0.1:8111/load_and_zoom?" + querystring.stringify(query))
.attr("src", url + querystring.stringify(query))
.on('load', function() {
$(this).remove();
loaded = true;

View file

@ -14,6 +14,7 @@
//= require index/note
//= require index/new_note
//= require index/directions
//= require index/changeset
//= require router
$(document).ready(function () {
@ -156,6 +157,15 @@ $(document).ready(function () {
$.cookie("_osm_location", OSM.locationCookie(map), { expires: expiry, path: "/" });
});
if ($.cookie('_osm_sotm') == 'hide') {
$('#sotm').hide();
}
$('#sotm .close').on('click', function() {
$('#sotm').hide();
$.cookie("_osm_sotm", 'hide', { expires: expiry });
});
if ($.cookie('_osm_welcome') == 'hide') {
$('.welcome').hide();
}
@ -252,10 +262,11 @@ $(document).ready(function () {
function addObject(type, id, center) {
var bounds = map.addObject({type: type, id: parseInt(id)}, function(bounds) {
if (!window.location.hash && bounds.isValid()) {
OSM.router.moveListenerOff();
map.once('moveend', OSM.router.moveListenerOn);
if (center || !map.getBounds().contains(bounds)) map.fitBounds(bounds);
if (!window.location.hash && bounds.isValid() &&
(center || !map.getBounds().contains(bounds))) {
OSM.router.withoutMoveListener(function () {
map.fitBounds(bounds);
});
}
});
}
@ -283,7 +294,7 @@ $(document).ready(function () {
"/node/:id(/history)": OSM.Browse(map, 'node'),
"/way/:id(/history)": OSM.Browse(map, 'way'),
"/relation/:id(/history)": OSM.Browse(map, 'relation'),
"/changeset/:id": OSM.Browse(map, 'changeset')
"/changeset/:id": OSM.Changeset(map)
});
if (OSM.preferred_editor == "remote" && document.location.pathname == "/edit") {
@ -308,4 +319,24 @@ $(document).ready(function () {
if (OSM.router.route(this.pathname + this.search + this.hash))
e.preventDefault();
});
$(".search_form").on("submit", function(e) {
e.preventDefault();
$("header").addClass("closed");
var query = $(this).find("input[name=query]").val();
if (query) {
OSM.router.route("/search?query=" + encodeURIComponent(query) + OSM.formatHash(map));
} else {
OSM.router.route("/");
}
});
$(".describe_location").on("click", function(e) {
e.preventDefault();
var center = map.getCenter().wrap(),
precision = OSM.zoomPrecision(map.getZoom());
OSM.router.route("/search?query=" + encodeURIComponent(
center.lat.toFixed(precision) + "," + center.lng.toFixed(precision)
));
});
});

View file

@ -0,0 +1,80 @@
OSM.Changeset = function (map) {
var page = {},
content = $('#sidebar_content'),
currentChangesetId;
page.pushstate = page.popstate = function(path, id) {
OSM.loadSidebarContent(path, function() {
page.load(path, id);
});
};
page.load = function(path, id) {
if(id)
currentChangesetId = id;
initialize();
addChangeset(currentChangesetId, true);
};
function addChangeset(id, center) {
var bounds = map.addObject({type: 'changeset', id: parseInt(id)}, function(bounds) {
if (!window.location.hash && bounds.isValid() &&
(center || !map.getBounds().contains(bounds))) {
OSM.router.withoutMoveListener(function () {
map.fitBounds(bounds);
});
}
});
}
function updateChangeset(form, method, url, include_data) {
$(form).find("input[type=submit]").prop("disabled", true);
if(include_data) {
data = {text: $(form.text).val()};
} else {
data = {};
}
$.ajax({
url: url,
type: method,
oauth: true,
data: data,
success: function () {
OSM.loadSidebarContent(window.location.pathname, page.load);
}
});
}
function initialize() {
content.find("input[name=comment]").on("click", function (e) {
e.preventDefault();
var data = $(e.target).data();
updateChangeset(e.target.form, data.method, data.url, true);
});
content.find(".action-button").on("click", function (e) {
e.preventDefault();
var data = $(e.target).data();
updateChangeset(e.target.form, data.method, data.url);
});
content.find("textarea").on("input", function (e) {
var form = e.target.form;
if ($(e.target).val() == "") {
$(form.comment).prop("disabled", true);
} else {
$(form.comment).prop("disabled", false);
}
});
content.find("textarea").val('').trigger("input");
};
page.unload = function() {
map.removeObject();
};
return page;
};

View file

@ -53,6 +53,10 @@ OSM.Export = function(map) {
$("#export_commit").toggle(getBounds().getSize() < OSM.MAX_REQUEST_AREA);
}
function checkSubmit(e) {
if (getBounds().getSize() > OSM.MAX_REQUEST_AREA) e.preventDefault();
}
page.pushstate = page.popstate = function(path) {
$("#export_tab").addClass("current");
OSM.loadSidebarContent(path, page.load);
@ -65,7 +69,7 @@ OSM.Export = function(map) {
$("#maxlat, #minlon, #maxlon, #minlat").change(boundsChanged);
$("#drag_box").click(enableFilter);
$("#sidebar_content .close").on("click", page.minimizeSidebar);
$(".export_form").on("submit", checkSubmit);
update();
return map.getState();

View file

@ -11,10 +11,15 @@ OSM.History = function(map) {
.on("mouseout", "[data-changeset]", function () {
unHighlightChangeset($(this).data("changeset").id);
})
.on("click", "[data-changeset]", function (e) {
if (!$(e.target).is('a')) {
clickChangeset($(this).data("changeset").id, e);
}
.on("mousedown", "[data-changeset]", function () {
var moved = false;
$(this).one("click", function (e) {
if (!moved && !$(e.target).is('a')) {
clickChangeset($(this).data("changeset").id, e);
}
}).one("mousemove", function () {
moved = true;
});
});
var group = L.featureGroup()

View file

@ -101,9 +101,9 @@ OSM.Note = function (map) {
latLng = L.latLng(data.coordinates.split(','));
if (!window.location.hash || window.location.hash.match(/^#?c[0-9]+$/)) {
OSM.router.moveListenerOff();
map.once('moveend', OSM.router.moveListenerOn);
map.setView(latLng, 15, {reset: true});
OSM.router.withoutMoveListener(function () {
map.setView(latLng, 15, {reset: true});
});
}
}

View file

@ -34,7 +34,9 @@ function initializeNotes(map) {
});
noteLayer.on('click', function(e) {
OSM.router.route('/note/' + e.layer.id);
if (e.layer.id) {
OSM.router.route('/note/' + e.layer.id);
}
});
function updateMarker(marker, feature) {

View file

@ -1,3 +1,5 @@
//= require jquery.simulate
OSM.Search = function(map) {
$(".search_form input[name=query]").on("input", function(e) {
if ($(e.target).val() == "") {
@ -28,7 +30,19 @@ OSM.Search = function(map) {
$("#sidebar_content")
.on("click", ".search_more a", clickSearchMore)
.on("click", ".search_results_entry a.set_position", clickSearchResult);
.on("click", ".search_results_entry a.set_position", clickSearchResult)
.on("mouseover", "p.search_results_entry:has(a.set_position)", showSearchResult)
.on("mouseout", "p.search_results_entry:has(a.set_position)", hideSearchResult)
.on("mousedown", "p.search_results_entry:has(a.set_position)", function () {
var moved = false;
$(this).one("click", function (e) {
if (!moved && !$(e.target).is('a')) {
$(this).find("a.set_position").simulate("click", e);
}
}).one("mousemove", function () {
moved = true;
});
});
function clickSearchMore(e) {
e.preventDefault();
@ -44,6 +58,32 @@ OSM.Search = function(map) {
});
}
function showSearchResult(e) {
var marker = $(this).data("marker");
if (!marker) {
var data = $(this).find("a.set_position").data();
marker = L.marker([data.lat, data.lon], {icon: getUserIcon()});
$(this).data("marker", marker);
}
markers.addLayer(marker);
$(this).closest("li").addClass("selected");
}
function hideSearchResult(e) {
var marker = $(this).data("marker");
if (marker) {
markers.removeLayer(marker);
}
$(this).closest("li").removeClass("selected");
}
function clickSearchResult(e) {
var data = $(this).data(),
center = L.latLng(data.lat, data.lon);
@ -57,13 +97,11 @@ OSM.Search = function(map) {
// Let clicks to object browser links propagate.
if (data.type && data.id) return;
marker.setLatLng(center).addTo(map);
e.preventDefault();
e.stopPropagation();
}
var marker = L.marker([0, 0], {icon: getUserIcon()});
var markers = L.layerGroup().addTo(map);
var page = {};
@ -96,8 +134,7 @@ OSM.Search = function(map) {
};
page.unload = function() {
map.removeLayer(marker);
map.removeObject();
markers.clearLayers();
$(".search_form input[name=query]").val("");
$(".describe_location").fadeIn(100);
};

View file

@ -24,13 +24,13 @@ L.OSM.Map = L.Map.extend({
name: I18n.t("javascripts.map.base.standard")
}),
new L.OSM.CycleMap({
attribution: copyright + ". Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
attribution: copyright + ". Tiles courtesy of <a href='http://www.thunderforest.com/' target='_blank'>Andy Allan</a>",
code: "C",
keyid: "cyclemap",
name: I18n.t("javascripts.map.base.cycle_map")
}),
new L.OSM.TransportMap({
attribution: copyright + ". Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
attribution: copyright + ". Tiles courtesy of <a href='http://www.thunderforest.com/' target='_blank'>Andy Allan</a>",
code: "T",
keyid: "transportmap",
name: I18n.t("javascripts.map.base.transport_map")
@ -241,7 +241,7 @@ L.OSM.Map = L.Map.extend({
setState: function(state, options) {
if (state.center) this.setView(state.center, state.zoom, options);
this.updateLayers(state.layers);
if (state.layers) this.updateLayers(state.layers);
},
setSidebarOverlaid: function(overlaid) {
@ -263,8 +263,7 @@ L.Icon.Default.imagePath = "/images";
L.Icon.Default.imageUrls = {
"/images/marker-icon.png": "<%= asset_path("images/marker-icon.png") %>",
"/images/marker-icon-2x.png": "<%= asset_path("images/marker-icon-2x.png") %>",
"/images/marker-shadow.png": "<%= asset_path("images/marker-shadow.png") %>",
"/images/marker-shadow-2x.png": "<%= asset_path("images/marker-shadow-2x.png") %>"
"/images/marker-shadow.png": "<%= asset_path("images/marker-shadow.png") %>"
};
L.extend(L.Icon.Default.prototype, {

View file

@ -42,8 +42,9 @@
OSM.Router also handles updating the hash portion of the URL containing transient
map state such as the position and zoom level. Some route controllers may wish to
temporarily suppress updating the hash (for example, to omit the hash on pages
such as `/way/1234` unless the map is moved). This can be done by calling
`OSM.router.moveListenerOff` and `OSM.router.moveListenerOn`.
such as `/way/1234` unless the map is moved). This can be done by using
`OSM.router.withoutMoveListener` to run a block of code that may update
move the map without the hash changing.
*/
OSM.Router = function(map, rts) {
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
@ -114,7 +115,9 @@ OSM.Router = function(map, rts) {
route = routes.recognize(path);
if (!route) return false;
currentRoute.run('unload');
window.history.pushState(OSM.parseHash(url), document.title, url);
var state = OSM.parseHash(url);
map.setState(state);
window.history.pushState(state, document.title, url);
currentPath = path;
currentRoute = route;
currentRoute.run('pushstate', currentPath);
@ -158,12 +161,17 @@ OSM.Router = function(map, rts) {
router.stateChange(state, hash);
};
router.moveListenerOn = function() {
map.on('moveend', router.updateHash);
};
router.withoutMoveListener = function (callback) {
function disableMoveListener() {
map.off('moveend', router.updateHash);
map.once('moveend', function () {
map.on('moveend', router.updateHash);
});
}
router.moveListenerOff = function() {
map.off('moveend', router.updateHash);
map.once('movestart', disableMoveListener);
callback();
map.off('movestart', disableMoveListener);
};
router.load = function() {

View file

@ -87,9 +87,7 @@ strong {
/* Default rules for the body of every page */
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
box-sizing: border-box;
}
body {
@ -464,9 +462,8 @@ nav.secondary {
#noscript {
z-index: 20000000;
position: absolute;
top: 15px;
left: 15px;
margin-left: 400px;
margin-top: 50px;
}
/* Rules for bootstrap tooltips */
@ -846,7 +843,6 @@ nav.secondary {
.leaflet-popup-content-wrapper {
border-radius: 4px !important;
-webkit-border-radius: 4px !important;
}
/* Rules for attribution text under the main map shown on printouts */
@ -929,8 +925,6 @@ header .search_forms,
border-right: none;
transition: 300ms linear;
-webkit-transition: 300ms linear;
-moz-transition: 300ms linear;
}
input:focus {
@ -970,7 +964,9 @@ header .search_forms,
.search_results_entry {
ul li {
border-bottom: $keyline;
cursor: pointer;
&:first-child { border-top: $keyline; }
&.selected { background: #FFFFE6; }
}
.search_details {
@ -1151,7 +1147,7 @@ tr.turn:hover {
font-size: 90%;
}
.note-comments li {
.note-comments li, .changeset-comments li {
margin: $lineheight/2 0;
p {
@ -1159,6 +1155,27 @@ tr.turn:hover {
}
}
.comments-header {
float: left;
}
.subscribe-buttons {
float: left;
margin: 18px 10px 10px;
min-width: 80px;
}
.subscribe-buttons input {
font-size: 90%;
line-height: 15px;
min-height: 20px;
}
span.action-button:hover {
cursor: pointer;
text-decoration: underline;
}
.note-description {
overflow: hidden;
margin: 0 0 10px 10px;
@ -1372,6 +1389,30 @@ tr.turn:hover {
}
}
/* Rules for the new trace form */
#new_trace {
input[type=text] {
width: 50%;
width: calc(100% - 150px);
max-width: 500px;
}
}
/* Rules for the edit trace form */
.edit_trace {
.form-row p {
margin-bottom: 0px;
}
input[type=text] {
width: 50%;
width: calc(100% - 150px);
max-width: 500px;
}
}
/* Rules for the user profile page */
#userinformation {
@ -1954,7 +1995,6 @@ a.button {
cursor: pointer;
border: 0;
display: inline-block;
line-height: 20px;
padding: $lineheight/4 $lineheight/2;
min-height: 20px + $lineheight/2;
min-width: 120px;
@ -1963,7 +2003,6 @@ a.button {
background: $blue;
text-align: center;
border-radius: 2px;
-moz-border-radius: 2px;
&:hover {
background: darken($blue, $hovercolor);
text-decoration: none;
@ -1985,6 +2024,16 @@ a.button {
}
}
input[type="button"],
input[type="submit"],
input[type="reset"] {
line-height: normal;
}
a.button {
line-height: 20px;
}
.buttons {
min-width: 200px;
input[type="submit"],
@ -2132,8 +2181,6 @@ a.button {
input.richtext_title[type="text"] {
width: 50%;
width: -moz-calc(100% - 235px);
width: -webkit-calc(100% - 235px);
width: calc(100% - 235px);
@media only screen and (max-width:768px) {
@ -2146,8 +2193,6 @@ input.richtext_title[type="text"] {
.richtext_content {
width: 50%;
width: -moz-calc(100% - 235px);
width: -webkit-calc(100% - 235px);
width: calc(100% - 235px);
display: inline-block;
vertical-align: top;
@ -2282,12 +2327,8 @@ input.richtext_title[type="text"] {
border-radius: 0 3px 3px;
*border-right-width: 2px;
*border-bottom-width: 2px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
background-clip: padding-box;
}
.dropdown-menu.pull-right {
@ -2452,13 +2493,6 @@ input.richtext_title[type="text"] {
background-size: cover;
background-attachment: fixed;
&.photo-0 { background-image: image-url('about/0.jpg'); .photo-0 { display: block; } }
&.photo-1 { background-image: image-url('about/1.jpg'); .photo-1 { display: block; } }
&.photo-2 { background-image: image-url('about/2.jpg'); .photo-2 { display: block; } }
&.photo-3 { background-image: image-url('about/4.jpg'); .photo-3 { display: block; } }
&.photo-4 { background-image: image-url('about/4.jpg'); .photo-4 { display: block; } }
&.photo-5 { background-image: image-url('about/5.jpg'); .photo-5 { display: block; } }
.caption {
max-width: 200px;
font: 13px/20px Helvetica, Arial, sans-serif;
@ -2584,6 +2618,36 @@ input.richtext_title[type="text"] {
}
}
#sidebar #sotm {
padding: 10px;
min-height: 120px;
img {
float: left;
width: 100px;
height: 100px;
}
h2 {
margin-left: 100px;
padding: 7px 10px 6px 15px;
}
p {
margin-left: 100px;
padding: 6px 10px 7px 15px;
}
a {
color: $darkgrey;
}
:hover {
text-decoration: none;
color: darken($darkgrey, 25%);
}
}
@import 'browse';
@media only screen and (max-width:960px) {

View file

@ -321,12 +321,12 @@ class AmfController < ApplicationController
# Ideally we would do ":include => :nodes" here but if we do that
# then rails only seems to return the first copy of a node when a
# way includes a node more than once
way = Way.where(:id => wayid).preload(:nodes => :node_tags).first
way = Way.where(:id => wayid).first
# check case where way has been deleted or doesn't exist
return [-4, 'way', wayid] if way.nil? or !way.visible
points = way.nodes.collect do |node|
points = way.nodes.preload(:node_tags).collect do |node|
nodetags=node.tags
nodetags.delete('created_by')
[node.lon, node.lat, node.id, nodetags, node.version]
@ -551,7 +551,7 @@ class AmfController < ApplicationController
mid = renumberedways[mid] if m[0] == 'Way'
end
if mid
typedmembers << [m[0], mid, m[2]]
typedmembers << [m[0], mid, m[2].delete("\000-\037\ufffe\uffff", "^\011\012\015")]
end
end
@ -886,8 +886,8 @@ class AmfController < ApplicationController
new_tags = Hash.new
unless tags.nil?
tags.each do |k, v|
new_k = k.delete "\000-\037", "^\011\012\015"
new_v = v.delete "\000-\037", "^\011\012\015"
new_k = k.delete "\000-\037\ufffe\uffff", "^\011\012\015"
new_v = v.delete "\000-\037\ufffe\uffff", "^\011\012\015"
new_tags[new_k] = new_v
end
end

View file

@ -287,8 +287,16 @@ class ApiController < ApplicationController
status['api'] = api_status.to_s
status['gpx'] = gpx_status.to_s
api << status
doc.root << api
policy = XML::Node.new 'policy'
blacklist = XML::Node.new 'imagery'
IMAGERY_BLACKLIST.each do |url_regex|
xnd = XML::Node.new 'blacklist'
xnd['regex'] = url_regex.to_s
blacklist << xnd
end
policy << blacklist
doc.root << policy
render :text => doc.to_s, :content_type => "text/xml"
end

View file

@ -73,7 +73,7 @@ class ApplicationController < ActionController::Base
if request.cookies["_osm_session"].to_s == ""
if params[:cookie_test].nil?
session[:cookie_test] = true
redirect_to params.merge(:cookie_test => "true")
redirect_to Hash[params].merge(:cookie_test => "true")
return false
else
flash.now[:warning] = t 'application.require_cookies.cookies_needed'

View file

@ -58,6 +58,11 @@ class BrowseController < ApplicationController
def changeset
@type = "changeset"
@changeset = Changeset.find(params[:id])
if @user and @user.moderator?
@comments = @changeset.comments.unscope(:where => :visible).includes(:author)
else
@comments = @changeset.comments.includes(:author)
end
@node_pages, @nodes = paginate(:old_nodes, :conditions => {:changeset_id => @changeset.id}, :per_page => 20, :parameter => 'node_page')
@way_pages, @ways = paginate(:old_ways, :conditions => {:changeset_id => @changeset.id}, :per_page => 20, :parameter => 'way_page')
@relation_pages, @relations = paginate(:old_relations, :conditions => {:changeset_id => @changeset.id}, :per_page => 20, :parameter => 'relation_page')

View file

@ -7,11 +7,12 @@ class ChangesetController < ApplicationController
skip_before_filter :verify_authenticity_token, :except => [:list]
before_filter :authorize_web, :only => [:list, :feed]
before_filter :set_locale, :only => [:list, :feed]
before_filter :authorize, :only => [:create, :update, :delete, :upload, :include, :close]
before_filter :require_allow_write_api, :only => [:create, :update, :delete, :upload, :include, :close]
before_filter :require_public_data, :only => [:create, :update, :delete, :upload, :include, :close]
before_filter :check_api_writable, :only => [:create, :update, :delete, :upload, :include]
before_filter :check_api_readable, :except => [:create, :update, :delete, :upload, :download, :query, :list, :feed]
before_filter :authorize, :only => [:create, :update, :delete, :upload, :include, :close, :comment, :subscribe, :unsubscribe, :hide_comment, :unhide_comment]
before_filter :require_moderator, :only => [:hide_comment, :unhide_comment]
before_filter :require_allow_write_api, :only => [:create, :update, :delete, :upload, :include, :close, :comment, :subscribe, :unsubscribe, :hide_comment, :unhide_comment]
before_filter :require_public_data, :only => [:create, :update, :delete, :upload, :include, :close, :comment, :subscribe, :unsubscribe]
before_filter :check_api_writable, :only => [:create, :update, :delete, :upload, :include, :comment, :subscribe, :unsubscribe, :hide_comment, :unhide_comment]
before_filter :check_api_readable, :except => [:create, :update, :delete, :upload, :download, :query, :list, :feed, :comment, :subscribe, :unsubscribe, :comments_feed]
before_filter(:only => [:list, :feed]) { |c| c.check_database_readable(true) }
after_filter :compress_output
around_filter :api_call_handle_error, :except => [:list, :feed]
@ -29,6 +30,10 @@ class ChangesetController < ApplicationController
# Assume that Changeset.from_xml has thrown an exception if there is an error parsing the xml
cs.user_id = @user.id
cs.save_with_tags!
# Subscribe user to changeset comments
cs.subscribers << @user
render :text => cs.id.to_s, :content_type => "text/plain"
end
@ -37,7 +42,8 @@ class ChangesetController < ApplicationController
# return anything about the nodes, ways and relations in the changeset.
def read
changeset = Changeset.find(params[:id])
render :text => changeset.to_xml.to_s, :content_type => "text/xml"
render :text => changeset.to_xml(params[:include_discussion].presence).to_s, :content_type => "text/xml"
end
##
@ -284,7 +290,7 @@ class ChangesetController < ApplicationController
elsif params[:bbox]
changesets = conditions_bbox(changesets, BoundingBox.from_bbox_params(params))
elsif params[:friends] && @user
changesets = changesets.where(:user_id => @user.friend_users.public)
changesets = changesets.where(:user_id => @user.friend_users.identifiable)
elsif params[:nearby] && @user
changesets = changesets.where(:user_id => @user.nearby)
end
@ -305,6 +311,145 @@ class ChangesetController < ApplicationController
list
end
##
# Add a comment to a changeset
def comment
# Check the arguments are sane
raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
raise OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
# Extract the arguments
id = params[:id].to_i
body = params[:text]
# Find the changeset and check it is valid
changeset = Changeset.find(id)
raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open?
# Add a comment to the changeset
comment = changeset.comments.create({
:changeset => changeset,
:body => body,
:author => @user
})
# Notify current subscribers of the new comment
changeset.subscribers.each do |user|
if @user != user
Notifier.changeset_comment_notification(comment, user).deliver
end
end
# Add the commenter to the subscribers if necessary
changeset.subscribers << @user unless changeset.subscribers.exists?(@user)
# Return a copy of the updated changeset
render :text => changeset.to_xml.to_s, :content_type => "text/xml"
end
##
# Adds a subscriber to the changeset
def subscribe
# Check the arguments are sane
raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
# Extract the arguments
id = params[:id].to_i
# Find the changeset and check it is valid
changeset = Changeset.find(id)
raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open?
raise OSM::APIChangesetAlreadySubscribedError.new(changeset) if changeset.subscribers.exists?(@user)
# Add the subscriber
changeset.subscribers << @user
# Return a copy of the updated changeset
render :text => changeset.to_xml.to_s, :content_type => "text/xml"
end
##
# Removes a subscriber from the changeset
def unsubscribe
# Check the arguments are sane
raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
# Extract the arguments
id = params[:id].to_i
# Find the changeset and check it is valid
changeset = Changeset.find(id)
raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open?
raise OSM::APIChangesetNotSubscribedError.new(changeset) unless changeset.subscribers.exists?(@user)
# Remove the subscriber
changeset.subscribers.delete(@user)
# Return a copy of the updated changeset
render :text => changeset.to_xml.to_s, :content_type => "text/xml"
end
##
# Sets visible flag on comment to false
def hide_comment
# Check the arguments are sane
raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
# Extract the arguments
id = params[:id].to_i
# Find the changeset
comment = ChangesetComment.find(id)
# Hide the comment
comment.update(:visible => false)
# Return a copy of the updated changeset
render :text => comment.changeset.to_xml.to_s, :content_type => "text/xml"
end
##
# Sets visible flag on comment to true
def unhide_comment
# Check the arguments are sane
raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
# Extract the arguments
id = params[:id].to_i
# Find the changeset
comment = ChangesetComment.find(id)
# Unhide the comment
comment.update(:visible => true)
# Return a copy of the updated changeset
render :text => comment.changeset.to_xml.to_s, :content_type => "text/xml"
end
##
# Get a feed of recent changeset comments
def comments_feed
if params[:id]
# Extract the arguments
id = params[:id].to_i
# Find the changeset
changeset = Changeset.find(id)
# Return comments for this changeset only
@comments = changeset.comments.includes(:author, :changeset).limit(comments_limit)
else
# Return comments
@comments = ChangesetComment.includes(:author, :changeset).where(:visible => :true).order("created_at DESC").limit(comments_limit).preload(:changeset)
end
# Render the result
respond_to do |format|
format.rss
end
end
private
#------------------------------------------------------------
# utility functions below.
@ -435,4 +580,17 @@ private
return changesets.where("num_changes > 0")
end
##
# Get the maximum number of comments to return
def comments_limit
if params[:limit]
if params[:limit].to_i > 0 and params[:limit].to_i <= 10000
params[:limit].to_i
else
raise OSM::APIBadUserInput.new("Comments limit must be between 1 and 10000")
end
else
100
end
end
end

View file

@ -1,6 +1,7 @@
# coding: utf-8
class GeocoderController < ApplicationController
require 'cgi'
require 'uri'
require 'net/http'
require 'rexml/document'
@ -140,20 +141,25 @@ class GeocoderController < ApplicationController
# get objects to excude
if params[:exclude]
exclude = "&exclude_place_ids=#{params[:exclude].join(',')}"
exclude = "&exclude_place_ids=#{params[:exclude]}"
end
# ask nominatim
response = fetch_xml("#{NOMINATIM_URL}search?format=xml&q=#{escape_query(query)}#{viewbox}#{exclude}&accept-language=#{http_accept_language.user_preferred_languages.join(',')}")
# extract the results from the response
results = response.elements["searchresults"]
# extract parameters from more_url
more_url_params = CGI.parse(URI.parse(results.attributes["more_url"]).query)
# create result array
@results = Array.new
# create parameter hash for "more results" link
@more_params = params.reverse_merge({ :exclude => [] })
# extract the results from the response
results = response.elements["searchresults"]
@more_params = params.merge({
:exclude => more_url_params["exclude_place_ids"].first
})
# parse the response
results.elements.each("place") do |place|
@ -181,7 +187,6 @@ class GeocoderController < ApplicationController
:min_lon => min_lon, :max_lon => max_lon,
:prefix => prefix, :name => name,
:type => object_type, :id => object_id})
@more_params[:exclude].push(place.attributes["place_id"].to_s)
end
render :action => "results"

View file

@ -53,6 +53,9 @@ class NotesController < ApplicationController
##
# Create a new note
def create
# Check the ACLs
raise OSM::APIAccessDenied if Acl.no_note_comment(request.remote_ip)
# Check the arguments are sane
raise OSM::APIBadUserInput.new("No lat was given") unless params[:lat]
raise OSM::APIBadUserInput.new("No lon was given") unless params[:lon]
@ -86,6 +89,9 @@ class NotesController < ApplicationController
##
# Add a comment to an existing note
def comment
# Check the ACLs
raise OSM::APIAccessDenied if Acl.no_note_comment(request.remote_ip)
# Check the arguments are sane
raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
raise OSM::APIBadUserInput.new("No text was given") if params[:text].blank?

View file

@ -6,7 +6,7 @@ class SiteController < ApplicationController
before_filter :set_locale
before_filter :redirect_browse_params, :only => :index
before_filter :redirect_map_params, :only => [:index, :edit, :export]
before_filter :require_user, :only => [:edit, :welcome]
before_filter :require_user, :only => [:welcome]
before_filter :require_oauth, :only => [:index]
def index
@ -17,7 +17,7 @@ class SiteController < ApplicationController
def permalink
lon, lat, zoom = ShortLink::decode(params[:code])
new_params = params.except(:code, :lon, :lat, :zoom, :node, :way, :relation, :changeset)
new_params = params.except(:code, :lon, :lat, :zoom, :layers, :node, :way, :relation, :changeset)
if new_params.has_key? :m
new_params.delete :m
@ -48,7 +48,11 @@ class SiteController < ApplicationController
new_params[:anchor] = "map=#{zoom}/#{lat}/#{lon}"
redirect_to new_params
if params.has_key? :layers
new_params[:anchor] += "&layers=#{params[:layers]}"
end
redirect_to Hash[new_params]
end
def key
@ -63,6 +67,8 @@ class SiteController < ApplicationController
require_oauth
render :action => :index, :layout => map_layout
return
else
require_user
end
if params[:node]
@ -145,7 +151,7 @@ class SiteController < ApplicationController
end
if anchor.present?
redirect_to params.merge(:anchor => anchor.join('&'))
redirect_to Hash[params].merge(:anchor => anchor.join('&'))
end
end
end

View file

@ -49,13 +49,13 @@ class TraceController < ApplicationController
if @user
@traces = Trace.visible_to(@user) #1
else
@traces = Trace.public #2
@traces = Trace.visible_to_all #2
end
else
if @user and @user == target_user
@traces = @user.traces #3 (check vs user id, so no join + can't pick up non-public traces by changing name)
else
@traces = target_user.traces.public #4
@traces = target_user.traces.visible_to_all #4
end
end
@ -206,7 +206,7 @@ class TraceController < ApplicationController
end
def georss
@traces = Trace.public.visible
@traces = Trace.visible_to_all.visible
if params[:display_name]
@traces = @traces.joins(:user).where(:users => {:display_name => params[:display_name]})

View file

@ -26,7 +26,7 @@ class UserPreferenceController < ApplicationController
##
# return the value for a single preference
def read_one
pref = UserPreference.find(@user.id, params[:preference_key])
pref = UserPreference.find([@user.id, params[:preference_key]])
render :text => pref.v.to_s, :content_type => "text/plain"
end
@ -69,7 +69,7 @@ class UserPreferenceController < ApplicationController
# update the value of a single preference
def update_one
begin
pref = UserPreference.find(@user.id, params[:preference_key])
pref = UserPreference.find([@user.id, params[:preference_key]])
rescue ActiveRecord::RecordNotFound
pref = UserPreference.new
pref.user = @user
@ -85,7 +85,7 @@ class UserPreferenceController < ApplicationController
##
# delete a single preference
def delete_one
UserPreference.find(@user.id, params[:preference_key]).delete
UserPreference.find([@user.id, params[:preference_key]]).delete
render :text => "", :content_type => "text/plain"
end

View file

@ -13,14 +13,20 @@ module BrowseHelper
# don't look at object tags if redacted, so as to avoid giving
# away redacted version tag information.
unless object.redacted?
if object.tags.include? "name:#{I18n.locale}"
name = t 'printable_name.with_name', :name => object.tags["name:#{I18n.locale}"].to_s, :id => name
locale = I18n.locale.to_s
while locale =~ /-[^-]+/ and not object.tags.include? "name:#{I18n.locale}"
locale = locale.sub(/-[^-]+/, "")
end
if object.tags.include? "name:#{locale}"
name = t 'printable_name.with_name_html', :name => content_tag(:bdi, object.tags["name:#{locale}"].to_s ), :id => content_tag(:bdi, name)
elsif object.tags.include? 'name'
name = t 'printable_name.with_name', :name => object.tags['name'].to_s, :id => name
name = t 'printable_name.with_name_html', :name => content_tag(:bdi, object.tags['name'].to_s ), :id => content_tag(:bdi, name)
end
end
return name
name
end
def link_class(type, object)
@ -55,8 +61,12 @@ module BrowseHelper
def format_value(key, value)
if wp = wikipedia_link(key, value)
link_to h(wp[:title]), wp[:url], :title => t('browse.tag_details.wikipedia_link', :page => wp[:title])
elsif wdt = wikidata_link(key, value)
link_to h(wdt[:title]), wdt[:url], :title => t('browse.tag_details.wikidata_link', :page => wdt[:title])
elsif url = wiki_link("tag", "#{key}=#{value}")
link_to h(value), url, :title => t('browse.tag_details.wiki_link.tag', :key => key, :value => value)
elsif url = telephone_link(key, value)
link_to h(value), url, :title => t('browse.tag_details.telephone_link', :phone_number => value)
else
linkify h(value)
end
@ -82,7 +92,7 @@ private
]
def icon_tags(object)
object.tags.find_all { |k,v| ICON_TAGS.include? k }
object.tags.find_all { |k,v| ICON_TAGS.include? k }.sort
end
def wiki_link(type, lookup)
@ -140,4 +150,25 @@ private
:title => value + section
}
end
def wikidata_link(key, value)
if key == "wikidata" and value =~ /^[Qq][1-9][0-9]*$/
return {
:url => "//www.wikidata.org/wiki/#{value}?uselang=#{I18n.locale}",
:title => value
}
end
return nil
end
def telephone_link(key, value)
# does it look like a phone number? eg "+1 (234) 567-8901 " ?
return nil unless value =~ /^\s*\+[\d\s\(\)\/\.-]{6,25}\s*$/
# remove all whitespace instead of encoding it http://tools.ietf.org/html/rfc3966#section-5.1.1
# "+1 (234) 567-8901 " -> "+1(234)567-8901"
valueNoWhitespace = value.gsub(/\s+/, '')
return "tel:#{valueNoWhitespace}"
end
end

View file

@ -1,6 +1,15 @@
require 'htmlentities'
module TitleHelper
@@coder = HTMLEntities.new
def set_title(title = false)
response.headers["X-Page-Title"] = t('layouts.project_name.title') + (title ? ' | ' + title : '')
@title = title
if title
@title = @@coder.decode(title.gsub("<bdi>", "\u202a").gsub("</bdi>", "\u202c"))
response.headers["X-Page-Title"] = t('layouts.project_name.title') + ' | ' + @title
else
@title = title
response.headers["X-Page-Title"] = t('layouts.project_name.title')
end
end
end

View file

@ -11,6 +11,10 @@ class Acl < ActiveRecord::Base
self.match(address, domain).where(:k => "no_account_creation").exists?
end
def self.no_note_comment(address, domain = nil)
self.match(address, domain).where(:k => "no_note_comment").exists?
end
def self.no_trace_download(address, domain = nil)
self.match(address, domain).where(:k => "no_trace_download").exists?
end

View file

@ -12,6 +12,9 @@ class Changeset < ActiveRecord::Base
has_many :old_ways
has_many :old_relations
has_many :comments, -> { where(:visible => true).order(:created_at) }, :class_name => "ChangesetComment"
has_and_belongs_to_many :subscribers, :class_name => 'User', :join_table => 'changesets_subscribers', :association_foreign_key => 'subscriber_id'
validates_presence_of :id, :on => :update
validates_presence_of :user_id, :created_at, :closed_at, :num_changes
validates_uniqueness_of :id
@ -179,13 +182,13 @@ class Changeset < ActiveRecord::Base
end
end
def to_xml
def to_xml(include_discussion = false)
doc = OSM::API.new.get_xml_doc
doc.root << to_xml_node()
doc.root << to_xml_node(nil, include_discussion)
return doc
end
def to_xml_node(user_display_name_cache = nil)
def to_xml_node(user_display_name_cache = nil, include_discussion = false)
el1 = XML::Node.new 'changeset'
el1['id'] = self.id.to_s
@ -217,6 +220,23 @@ class Changeset < ActiveRecord::Base
bbox.to_unscaled.add_bounds_to(el1, '_')
end
el1['comments_count'] = self.comments.count.to_s
if include_discussion
el2 = XML::Node.new('discussion')
self.comments.includes(:author).each do |comment|
el3 = XML::Node.new('comment')
el3['date'] = comment.created_at.xmlschema
el3['uid'] = comment.author.id.to_s if comment.author.data_public?
el3['user'] = comment.author.display_name.to_s if comment.author.data_public?
el4 = XML::Node.new('text')
el4.content = comment.body.to_s
el3 << el4
el2 << el3
end
el1 << el2
end
# NOTE: changesets don't include the XML of the changes within them,
# they are just structures for tagging. to get the osmChange of a
# changeset, see the download method of the controller.

View file

@ -0,0 +1,17 @@
class ChangesetComment < ActiveRecord::Base
belongs_to :changeset
belongs_to :author, :class_name => "User"
validates_presence_of :id, :on => :update # is it necessary?
validates_uniqueness_of :id
validates_presence_of :changeset
validates_associated :changeset
validates_presence_of :author
validates_associated :author
validates :visible, :inclusion => { :in => [true,false] }
# Return the comment text
def body
RichText.new("text", read_attribute(:body))
end
end

View file

@ -9,6 +9,7 @@ class NoteComment < ActiveRecord::Base
validates_presence_of :visible
validates_associated :author
validates_inclusion_of :event, :in => [ "opened", "closed", "reopened", "commented", "hidden" ]
validates_format_of :body, :with => /\A[^\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\ufffe\uffff]*\z/
# Return the comment text
def body

View file

@ -146,6 +146,26 @@ class Notifier < ActionMailer::Base
end
end
def changeset_comment_notification(comment, recipient)
with_recipient_locale recipient do
@changeset_url = changeset_url(comment.changeset, :host => SERVER_URL)
@comment = comment.body
@owner = recipient == comment.changeset.user
@commenter = comment.author.display_name
@changeset_comment = comment.changeset.tags['comment'].presence
@time = comment.created_at
@changeset_author = comment.changeset.user.display_name
if @owner
subject = I18n.t("notifier.changeset_comment_notification.commented.subject_own", :commenter => @commenter)
else
subject = I18n.t("notifier.changeset_comment_notification.commented.subject_other", :commenter => @commenter)
end
mail :to => recipient.email, :subject => subject
end
end
private
def with_recipient_locale(recipient)

View file

@ -2,6 +2,6 @@ class RelationMember < ActiveRecord::Base
self.table_name = "current_relation_members"
self.primary_keys = "relation_id", "sequence_id"
belongs_to :relation
belongs_to :relation, :foreign_key => :relation_id
belongs_to :member, :polymorphic => true
end

View file

@ -7,7 +7,7 @@ class Trace < ActiveRecord::Base
scope :visible, -> { where(:visible => true) }
scope :visible_to, ->(u) { visible.where("visibility IN ('public', 'identifiable') OR user_id = ?", u) }
scope :public, -> { where(:visibility => ["public", "identifiable"]) }
scope :visible_to_all, -> { where(:visibility => ["public", "identifiable"]) }
scope :tagged, ->(t) { joins(:tags).where(:gpx_file_tags => { :tag => t }) }
validates_presence_of :user_id, :name, :timestamp

View file

@ -12,6 +12,8 @@ class User < ActiveRecord::Base
has_many :tokens, :class_name => "UserToken"
has_many :preferences, :class_name => "UserPreference"
has_many :changesets, -> { order(:created_at => :desc) }
has_many :changeset_comments, :foreign_key => :author_id
has_and_belongs_to_many :changeset_subscriptions, :class_name => 'Changeset', :join_table => 'changesets_subscribers', :foreign_key => 'subscriber_id'
has_many :note_comments, :foreign_key => :author_id
has_many :notes, :through => :note_comments
@ -26,7 +28,7 @@ class User < ActiveRecord::Base
scope :visible, -> { where(:status => ["pending", "active", "confirmed"]) }
scope :active, -> { where(:status => ["active", "confirmed"]) }
scope :public, -> { where(:data_public => true) }
scope :identifiable, -> { where(:data_public => true) }
has_attached_file :image,
:default_url => "/assets/:class/:attachment/:style.png",
@ -42,9 +44,10 @@ class User < ActiveRecord::Base
validates_length_of :display_name, :within => 3..255, :allow_nil => true
validates_email_format_of :email, :if => Proc.new { |u| u.email_changed? }
validates_email_format_of :new_email, :allow_blank => true, :if => Proc.new { |u| u.new_email_changed? }
validates_format_of :display_name, :with => /\A[^\/;.,?%#]*\z/, :if => Proc.new { |u| u.display_name_changed? }
validates_format_of :display_name, :with => /\A[^\x00-\x1f\x7f\ufffe\uffff\/;.,?%#]*\z/, :if => Proc.new { |u| u.display_name_changed? }
validates_format_of :display_name, :with => /\A\S/, :message => "has leading whitespace", :if => Proc.new { |u| u.display_name_changed? }
validates_format_of :display_name, :with => /\S\z/, :message => "has trailing whitespace", :if => Proc.new { |u| u.display_name_changed? }
validates_exclusion_of :display_name, :in => %w(new terms save confirm confirm-email go_public reset-password forgot-password suspended)
validates_numericality_of :home_lat, :allow_nil => true
validates_numericality_of :home_lon, :allow_nil => true
validates_numericality_of :home_zoom, :only_integer => true, :allow_nil => true

View file

@ -12,7 +12,7 @@ class Way < ActiveRecord::Base
has_many :old_ways, -> { order(:version) }
has_many :way_nodes, -> { order(:sequence_id) }
has_many :nodes, -> { order("sequence_id") }, :through => :way_nodes
has_many :nodes, :through => :way_nodes
has_many :way_tags

View file

@ -1,32 +0,0 @@
# Note that this file is currently unused
# I (xin@zxv.ltd.uk) suspect this is slower than using OSM module, which in turn uses libxml
# it will be good to output xml this way eventually.
xml.instruct! :xml, :version=>"1.0"
xml.osm("version" => "0.5", "generator" => "OpenStreetMap Server") do
@nodes.each do |node|
xml.tag! "node",:id => node.id,
:lat => node.lat,
:lon => node.lon,
:user => node.user_display_name,
:visible => node.visible,
:timestamp => node.timestamp.xmlschema do
node.tags.each do |tag|
k,v = tag.split('=')
xml.tag! "tag",:k => k, :v => v
end
end
end
@ways.each do |way|
xml.tag! "way", :id => way.id,
:user => way.user_display_name,
:visible => way.visible,
:timestamp => way.timestamp.xmlschema do
way.nds.each do |nd|
xml.tag! "nd", :ref => nd
end
end
end
end

View file

@ -26,7 +26,7 @@
<% if @type == "node" and common_details.visible? %>
<div class="details geo">
<%= t 'browse.location' %>
<%= link_to(content_tag(:span, number_with_delimiter(common_details.lat), :class => "latitude") + ", " + content_tag(:span, number_with_delimiter(common_details.lon), :class => "longitude"), {:controller => 'site', :action => 'index', :lat => h(common_details.lat), :lon => h(common_details.lon), :zoom => "18"}) %>
<%= link_to(content_tag(:span, number_with_delimiter(common_details.lat), :class => "latitude") + ", " + content_tag(:span, number_with_delimiter(common_details.lon), :class => "longitude"), {:controller => 'site', :action => 'index', :anchor => "map=18/#{common_details.lat}/#{common_details.lon}"}) %>
</div>
<% end %>

View file

@ -14,7 +14,7 @@
<h4><%= t 'browse.part_of' %></h4>
<ul>
<% node.ways.uniq.each do |way| %>
<li><%= link_to h(printable_name(way)), { :action => "way", :id => way.id.to_s }, :class => link_class('way', way), :title => link_title(way) %></li>
<li><%= link_to printable_name(way), { :action => "way", :id => way.id.to_s }, :class => link_class('way', way), :title => link_title(way) %></li>
<% end %>
<%= render :partial => "containing_relation", :collection => node.containing_relation_members.uniq %>
</ul>

View file

@ -1,6 +1,6 @@
<%
member_class = link_class(relation_member.member_type.downcase, relation_member.member)
linked_name = link_to h(printable_name(relation_member.member)), { :action => relation_member.member_type.downcase, :id => relation_member.member_id.to_s }, :title => link_title(relation_member.member)
linked_name = link_to printable_name(relation_member.member), { :action => relation_member.member_type.downcase, :id => relation_member.member_id.to_s }, :title => link_title(relation_member.member)
type_str = t'browse.relation_member.type.' + relation_member.member_type.downcase
%>
<li class="<%= member_class %>"><%=

View file

@ -15,10 +15,10 @@
<ul>
<% way.way_nodes.each do |wn| %>
<li>
<%= link_to h(printable_name(wn.node)), { :action => "node", :id => wn.node_id.to_s }, :class => link_class('node', wn.node), :title => link_title(wn.node) %>
<%= link_to printable_name(wn.node), { :action => "node", :id => wn.node_id.to_s }, :class => link_class('node', wn.node), :title => link_title(wn.node) %>
<% related_ways = wn.node.ways.reject { |w| w.id == wn.way_id } %>
<% if related_ways.size > 0 then %>
(<%= raw t 'browse.way.also_part_of', :count => related_ways.size, :related_ways => related_ways.map { |w| link_to(h(printable_name(w)), { :action => "way", :id => w.id.to_s }, :class => link_class('way', w), :title => link_title(w) ) }.to_sentence %>)
(<%= raw t 'browse.way.also_part_of', :count => related_ways.size, :related_ways => related_ways.map { |w| link_to(printable_name(w), { :action => "way", :id => w.id.to_s }, :class => link_class('way', w), :title => link_title(w) ) }.to_sentence %>)
<% end %>
</li>
<% end %>

View file

@ -11,6 +11,69 @@
<%= render :partial => "tag_details", :object => @changeset.tags.except('comment') %>
<h4 class="comments-header"><%= t('browse.changeset.discussion') %></h4>
<div class="buttons clearfix subscribe-buttons">
<form action="#" class="hide_unless_logged_in">
<% if @changeset.subscribers.exists?(@user) %>
<input class="action-button" type="submit" name="unsubscribe" value="<%= t('javascripts.changesets.show.unsubscribe') %>" data-method="POST" data-url="<%= changeset_unsubscribe_url(@changeset) %>" />
<% else %>
<input class="action-button" type="submit" name="subscribe" value="<%= t('javascripts.changesets.show.subscribe') %>" data-method="POST" data-url="<%= changeset_subscribe_url(@changeset) %>" />
<% end %>
</form>
</div>
<div class="clearfix"></div>
<% if @comments.length > 0 %>
<div class='changeset-comments'>
<form action="#">
<ul>
<% @comments.each do |comment| %>
<% if comment.visible %>
<li id="c<%= comment.id %>">
<small class='deemphasize'>
<%= t("browse.changeset.commented_by",
:when => friendly_date(comment.created_at), :exact_time => l(comment.created_at),
:user => link_to(h(comment.author.display_name), {:controller => "user", :action => "view",
:display_name => comment.author.display_name})).html_safe %>
<% if @user and @user.moderator? %>
— <span class="action-button deemphasize" data-comment-id="<%= comment.id %>" data-method="POST" data-url="<%= changeset_comment_hide_url(comment.id) %>"><%= t('javascripts.changesets.show.hide_comment') %></span>
<% end %>
</small>
<%= comment.body.to_html %>
</li>
<% elsif @user and @user.moderator? %>
<li id="c<%= comment.id %>">
<small class='deemphasize'>
<%= t("browse.changeset.hidden_commented_by",
:when => friendly_date(comment.created_at), :exact_time => l(comment.created_at),
:user => link_to(h(comment.author.display_name), {:controller => "user", :action => "view",
:display_name => comment.author.display_name})).html_safe %>
— <span class="action-button deemphasize" data-comment-id="<%= comment.id %>" data-method="POST" data-url="<%= changeset_comment_unhide_url(comment.id) %>"><%= t('javascripts.changesets.show.unhide_comment') %></span>
</small>
<%= comment.body.to_html %>
</li>
<% end %>
<% end %>
</ul>
</form>
</div>
<% end %>
<div class="notice hide_if_logged_in">
<%= link_to(t("browse.changeset.join_discussion"), :controller => 'user', :action => 'login', :referer => request.fullpath) %>
</div>
<% unless @changeset.is_open? %>
<form action="#" class="hide_unless_logged_in">
<textarea class="comment" name="text" cols="40" rows="5"></textarea>
<div class="buttons clearfix">
<input type="submit" name="comment" value="<%= t('javascripts.changesets.show.comment') %>" data-changeset-id="<%= @changeset.id %>" data-method="POST" data-url="<%= changeset_comment_url(@changeset) %>" disabled="1"/>
</div>
</form>
<% end %>
<% unless @ways.empty? %>
<h4>
<%= type_and_paginated_count('way', @way_pages) %>
@ -18,7 +81,7 @@
</h4>
<ul>
<% @ways.each do |way| %>
<li><%= link_to h(printable_name(way, true)), { :action => "way", :id => way.way_id.to_s }, :class => link_class('way', way), :title => link_title(way) %></li>
<li><%= link_to printable_name(way, true), { :action => "way", :id => way.way_id.to_s }, :class => link_class('way', way), :title => link_title(way) %></li>
<% end %>
</ul>
<% end %>
@ -30,7 +93,7 @@
</h4>
<ul>
<% @relations.each do |relation| %>
<li><%= link_to h(printable_name(relation, true)), { :action => "relation", :id => relation.relation_id.to_s }, :class => link_class('relation', relation), :title => link_title(relation) %></li>
<li><%= link_to printable_name(relation, true), { :action => "relation", :id => relation.relation_id.to_s }, :class => link_class('relation', relation), :title => link_title(relation) %></li>
<% end %>
</ul>
<% end %>
@ -42,7 +105,7 @@
</h4>
<ul>
<% @nodes.each do |node| %>
<li><%= link_to h(printable_name(node, true)), { :action => "node", :id => node.node_id.to_s }, :class => link_class('node', node), :title => link_title(node) %></li>
<li><%= link_to printable_name(node, true), { :action => "node", :id => node.node_id.to_s }, :class => link_class('node', node), :title => link_title(node) %></li>
<% end %>
</ul>
<% end %>

View file

@ -2,7 +2,7 @@
<h2>
<a class="geolink" href="<%= root_path %>"><span class="icon close"></span></a>
<%= t("browse.#{@type}.title", :name => printable_name(@feature)) %>
<%= raw t("browse.#{@type}.title", :name => printable_name(@feature)) %>
</h2>
<%= render :partial => @type, :object => @feature %>

View file

@ -2,7 +2,7 @@
<h2>
<a class="geolink" href="<%= root_path %>"><span class="icon close"></span></a>
<%= t("browse.#{@type}.history_title", :name => printable_name(@feature)) %>
<%= raw t("browse.#{@type}.history_title", :name => printable_name(@feature)) %>
</h2>
<%= render :partial => @type, :collection => @feature.send("old_#{@type}s").reverse %>

View file

@ -0,0 +1,6 @@
<h2><%= t "changeset.rss.comment", :author => comment.author.display_name,
:changeset_id => comment.changeset.id.to_s %></h2>
<div class="changeset-comment" style="margin-top: 5px">
<div class="changeset-comment-description" style="font-size: smaller; color: #999999"><%= t "changeset.rss.commented_at_by_html", :when => friendly_date(comment.created_at), :user => comment.author.display_name %></div>
<div class="changeset-comment-text"><%= comment.body %></div>
</div>

View file

@ -0,0 +1,18 @@
comments.each do |comment|
xml.item do
xml.title t("changeset.rss.comment", :author => comment.author.display_name, :changeset_id => comment.changeset.id.to_s)
xml.link url_for(:controller => "browse", :action => "changeset", :id => comment.changeset.id, :anchor => "c#{comment.id}", :only_path => false)
xml.guid url_for(:controller => "browse", :action => "changeset", :id => comment.changeset.id, :anchor => "c#{comment.id}", :only_path => false)
xml.description do
xml.cdata! render(:partial => "comment", :object => comment, :formats => [ :html ])
end
if comment.author
xml.dc :creator, comment.author.display_name
end
xml.pubDate comment.created_at.to_s(:rfc822)
end
end

View file

@ -0,0 +1,14 @@
xml.rss("version" => "2.0",
"xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
xml.channel do
if @changeset
xml.title t('changeset.rss.title_particular', :changeset_id => @changeset.id)
else
xml.title t('changeset.rss.title_all')
end
xml.link url_for(:controller => "site", :action => "index", :only_path => false)
xml << render(:partial => "comments", :object => @comments)
end
end

View file

@ -1,6 +1,6 @@
<%= t 'diary_entry.location.location' %>
<a href="<%= url_for :controller => 'site', :action => 'index', :lat => location.latitude, :lon => location.longitude, :zoom => 14 %>">
<a href="<%= url_for :controller => 'site', :action => 'index', :anchor => "map=14/#{location.latitude}/#{location.longitude}" %>">
<abbr class="geo" title="<%= number_with_precision(location.latitude, :precision => 4) %>; <%= number_with_precision(location.longitude, :precision => 4) %>">
<%= describe_location location.latitude, location.longitude, 14, location.language_code %>
</abbr>

View file

@ -9,8 +9,8 @@
<%= stylesheet_link_tag "leaflet-all", :media => "screen, print" %>
<!--[if IE]>
<%= stylesheet_link_tag "large-#{dir}", :media => "screen" %>
<%= favicon_link_tag "favicon.ico" %>
<![endif]-->
<%= favicon_link_tag "favicon.ico" %>
<%= favicon_link_tag "osm_logo_57.png", :rel => "apple-touch-icon", :sizes => "57x57", :type => "image/png" %>
<%= favicon_link_tag "osm_logo_72.png", :rel => "apple-touch-icon", :sizes => "72x72", :type => "image/png" %>
<%= favicon_link_tag "osm_logo_114.png", :rel => "apple-touch-icon", :sizes => "114x114", :type => "image/png" %>

View file

@ -30,6 +30,21 @@
<p class="error"><%= t 'layouts.osm_read_only' %></p>
<% end %>
<div id="sotm">
<a href="http://www.stateofthemap.org/?l=en"><%= image_tag "sotm.png" %></a>
<h2>
<a><span class="icon close"></span></a>
<a href="http://www.stateofthemap.org/?l=en"><%= t 'layouts.sotm_header' %></a>
</h2>
<p><a href="http://www.stateofthemap.org/?l=en">
<%= t 'layouts.sotm_line_1' %>
<br />
<%= t 'layouts.sotm_line_2' %>
<br />
<%= t 'layouts.sotm_line_3' %>
</a></p>
</div>
<div id="flash">
<%= render :partial => "layouts/flash" %>
</div>

View file

@ -16,7 +16,7 @@
</div>
<div class='buttons'>
<%= submit_tag t('message.new.send_button') %>
<%= link_to t('message.new.back'), { :controller => 'message', :action => 'inbox', :display_name => @user.display_name }, :class => 'deemphasize button' %>
<%= link_to t('message.new.back_to_inbox'), { :controller => 'message', :action => 'inbox', :display_name => @user.display_name }, :class => 'deemphasize button' %>
</div>
</fieldset>
<% end %>

View file

@ -0,0 +1,20 @@
<p><%= t 'notifier.changeset_comment_notification.greeting' %></p>
<p>
<% if @owner %>
<%= t "notifier.changeset_comment_notification.commented.your_changeset", :commenter => @commenter, :time => @time %>
<% else %>
<%= t "notifier.changeset_comment_notification.commented.commented_changeset", :commenter => @commenter, :time => @time, :changeset_author => @changeset_author %>
<% end %>
<% if @changeset_comment %>
<%= t "notifier.changeset_comment_notification.commented.partial_changeset_with_comment", :changeset_comment => @changeset_comment %>
<% else %>
<%= t "notifier.changeset_comment_notification.commented.partial_changeset_without_comment" %>
<% end %>
</p>
==
<%= @comment.to_html %>
==
<p><%= raw t 'notifier.changeset_comment_notification.details', :url => link_to(@changeset_url, @changeset_url) %></p>

View file

@ -0,0 +1,18 @@
<%= t 'notifier.changeset_comment_notification.greeting' %>
<% if @owner %>
<%= t "notifier.changeset_comment_notification.commented.your_changeset", :commenter => @commenter, :time => @time %>
<% else %>
<%= t "notifier.changeset_comment_notification.commented.commented_changeset", :commenter => @commenter, :time => @time, :changeset_author => @changeset_author %>
<% end %>
<% if @changeset_comment %>
<%= t "notifier.changeset_comment_notification.commented.partial_changeset_with_comment", :changeset_comment => @changeset_comment %>
<% else %>
<%= t "notifier.changeset_comment_notification.commented.partial_changeset_without_comment" %>
<% end %>
==
<%= @comment.to_text %>
==
<%= t 'notifier.changeset_comment_notification.details', :url => @changeset_url %>

View file

@ -26,9 +26,17 @@
params.background = hashParams.background;
}
if (hashParams.comment) {
params.comment = hashParams.comment;
}
<% if params[:gpx] -%>
params.gpx = '<%= trace_data_url(params[:gpx]) %>';
<% else -%>
if (hashParams.gpx) {
params.gpx = hashParams.gpx;
}
<% end -%>
$('#id-embed').attr('src', '<%= id_url :locale => params[:locale] %>#' + querystring.stringify(params));
</script>

View file

@ -47,7 +47,7 @@
<dt><a href="http://download.geofabrik.de/"><%= t'export.start.too_large.geofabrik.title' %></a></dt>
<dd><%= t'export.start.too_large.geofabrik.description' %></dd>
<dt><a href="http://metro.teczno.com/"><%= t'export.start.too_large.metro.title' %></a></dt>
<dt><a href="https://mapzen.com/metro-extracts/"><%= t'export.start.too_large.metro.title' %></a></dt>
<dd><%= t'export.start.too_large.metro.description' %></dd>
<dt><a href="http://wiki.openstreetmap.org/wiki/Download"><%= t'export.start.too_large.other.title' %></a></dt>

View file

@ -16,7 +16,7 @@
<% end %>
... <%= t'trace.trace.ago', :time_in_words_ago => time_ago_in_words(trace.timestamp) %></span>
<%= link_to t('trace.trace.more'), {:controller => 'trace', :action => 'view', :display_name => trace.user.display_name, :id => trace.id}, {:title => t('trace.trace.trace_details')} %> /
<%= link_to_if trace.inserted?, t('trace.trace.map'), {:controller => 'site', :action => 'index', :lat => trace.latitude, :lon => trace.longitude, :zoom => 14}, {:title => t('trace.trace.view_map')} %> /
<%= link_to_if trace.inserted?, t('trace.trace.map'), {:controller => 'site', :action => 'index', :anchor => "map=14/#{trace.latitude}/#{trace.longitude}"}, {:title => t('trace.trace.view_map')} %> /
<%= link_to t('trace.trace.edit'), {:controller => 'site', :action => 'edit', :gpx => trace.id }, {:title => t('trace.trace.edit_map')} %>
<span class="trace_<%= trace.visibility %>"><%= t('trace.trace.' + trace.visibility) %></span>
<br />

View file

@ -9,49 +9,41 @@
<div id='edit-trace-form' class='standard-form'>
<fieldset>
<div class='form-row'>
<label><%= t'trace.edit.filename' %></label>
<label class='standard-label'><%= t'trace.edit.filename' %></label>
<p class='deemphasize'><%= @trace.name %> (<%= link_to t('trace.edit.download'), :controller => 'trace', :action => 'data', :id => @trace.id %>)</p>
</div>
<div class='form-row'>
<label><%= t'trace.edit.uploaded_at' %></label>
<label class='standard-label'><%= t'trace.edit.uploaded_at' %></label>
<p class='deemphasize'><%= l @trace.timestamp, :format => :friendly %></p>
</div>
</fieldset>
<% if @trace.inserted? %>
<fieldset>
<div class='form-row'>
<label><%= t'trace.edit.points' %></label>
<label class='standard-label'><%= t'trace.edit.points' %></label>
<p class='deemphasize'><%= @trace.size.to_s.gsub(/(\d)(?=(\d{3})+$)/,'\1,') %></p>
</div>
<div class='form-row'>
<label><%= t'trace.edit.start_coord' %></label>
<label class='standard-label'><%= t'trace.edit.start_coord' %></label>
</div>
<div class="geo">
<span class="latitude"><%= @trace.latitude %></span>;
<span class="longitude"><%= @trace.longitude %></span>
</div>
(<%=link_to t('trace.edit.map'), :controller => 'site', :action => 'index', :lat => @trace.latitude, :lon => @trace.longitude, :zoom => 14 %> / <%=link_to t('trace.edit.edit'), :controller => 'site', :action => 'edit', :lat => @trace.latitude, :lon => @trace.longitude, :gpx=> @trace.id, :zoom => 14 %>)
</fieldset>
(<%=link_to t('trace.edit.map'), :controller => 'site', :action => 'index', :anchor => "map=14/#{@trace.latitude}/#{@trace.longitude}" %> / <%=link_to t('trace.edit.edit'), :controller => 'site', :action => 'edit', :gpx=> @trace.id, :anchor => "map=14/#{@trace.latitude}/#{@trace.longitude}" %>)
<% end %>
<fieldset>
<div class='form-row'>
<label><%= t'trace.edit.owner' %></label>
<label class='standard-label'><%= t'trace.edit.owner' %></label>
<p class='deemphasize'><%= link_to h(@trace.user.display_name), {:controller => 'user', :action => 'view', :display_name => @trace.user.display_name} %></p>
</div>
<div class='form-row'>
<label><%= t'trace.edit.description' %></label>
<label class='standard-label'><%= t'trace.edit.description' %></label>
<%= f.text_field :description %>
</div>
<div class='form-row'>
<label><%= t'trace.edit.tags' %></label>
<label class='standard-label'><%= t'trace.edit.tags' %></label>
<%= f.text_field :tagstring %> (<%= t'trace.edit.tags_help' %>)
</div>
<div class='form-row'>
<label><%= t'trace.edit.visibility' %></label>
<label class='standard-label'><%= t'trace.edit.visibility' %></label>
<%= f.select :visibility, [[t('trace.visibility.private'),"private"],[t('trace.visibility.public'),"public"],[t('trace.visibility.trackable'),"trackable"],[t('trace.visibility.identifiable'),"identifiable"]] %> (<a href="<%= t'trace.edit.visibility_help_url' %>"><%= t'trace.edit.visibility_help' %></a>)
</div>
</fieldset>

View file

@ -25,7 +25,7 @@
<td><%= @trace.size.to_s.gsub(/(\d)(?=(\d{3})+$)/,'\1,') %></td></tr>
<tr>
<td><%= t'trace.view.start_coordinates' %></td>
<td><div class="geo" style="display: inline"><span class="latitude"><%= @trace.latitude %></span>; <span class="longitude"><%= @trace.longitude %></span></div> (<%=link_to t('trace.view.map'), :controller => 'site', :action => 'index', :lat => @trace.latitude, :lon => @trace.longitude, :zoom => 14 %> / <%=link_to t('trace.view.edit'), :controller => 'site', :action => 'edit', :lat => @trace.latitude, :lon => @trace.longitude, :gpx=> @trace.id, :zoom => 14 %>)</td>
<td><div class="geo" style="display: inline"><span class="latitude"><%= @trace.latitude %></span>; <span class="longitude"><%= @trace.longitude %></span></div> (<%=link_to t('trace.view.map'), :controller => 'site', :action => 'index', :anchor => "map=14/#{@trace.latitude}/#{@trace.longitude}" %> / <%=link_to t('trace.view.edit'), :controller => 'site', :action => 'edit', :gpx=> @trace.id, :anchor => "map=14/#{@trace.latitude}/#{@trace.longitude}" %>)</td>
</tr>
<% end %>
<tr>

View file

@ -44,7 +44,6 @@
<li><%= link_to image_tag("openid.png", :alt => t("user.login.openid_providers.openid.title")), "#", :id => "openid_open_url", :title => t("user.login.openid_providers.openid.title") %></li>
<li><%= openid_button "google", "gmail.com" %></li>
<li><%= openid_button "yahoo", "me.yahoo.com" %></li>
<li><%= openid_button "myopenid", "myopenid.com" %></li>
<li><%= openid_button "wordpress", "wordpress.com" %></li>
<li><%= openid_button "aol", "aol.com" %></li>
</ul>

View file

@ -1,4 +1,4 @@
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run OpenStreetMap::Application
run Rails.application

View file

@ -5,7 +5,7 @@ require File.expand_path('../preinitializer', __FILE__)
if STATUS == :database_offline
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "active_model/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
else
@ -14,7 +14,7 @@ end
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env)
Bundler.require(*Rails.groups)
module OpenStreetMap
class Application < Rails::Application
@ -33,9 +33,6 @@ module OpenStreetMap
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Use SQL instead of Active Record's schema dumper when creating the database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
@ -43,12 +40,6 @@ module OpenStreetMap
config.active_record.schema_format = :sql
end
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
# Don't eager load models when the database is offline
if STATUS == :database_offline
config.paths["app/models"].skip_eager_load!

View file

@ -1,6 +1,4 @@
require 'rubygems'
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

View file

@ -1,5 +1,5 @@
# Load the rails application
# Load the Rails application.
require File.expand_path('../application', __FILE__)
# Initialize the rails application
OpenStreetMap::Application.initialize!
# Initialize the Rails application.
Rails.application.initialize!

View file

@ -19,11 +19,19 @@ OpenStreetMap::Application.configure do
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end

View file

@ -5,7 +5,7 @@ OpenStreetMap::Application.configure do
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both thread web servers
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
@ -32,9 +32,6 @@ OpenStreetMap::Application.configure do
# Generate digests for assets URLs.
config.assets.digest = true
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
@ -67,24 +64,7 @@ OpenStreetMap::Application.configure do
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
config.assets.precompile += %w( index.js browse.js welcome.js fixthemap.js routing.js )
config.assets.precompile += %w( user.js diary_entry.js swfobject.js )
config.assets.precompile += %w( large-ltr.css small-ltr.css print-ltr.css )
config.assets.precompile += %w( large-rtl.css small-rtl.css print-rtl.css )
config.assets.precompile += %w( leaflet-all.css leaflet.ie.css )
config.assets.precompile += %w( embed.js embed.css )
config.assets.precompile += %w( html5shiv.js )
config.assets.precompile += %w( images/marker-*.png img/*-handle.png )
config.assets.precompile += %w( potlatch2.swf )
config.assets.precompile += %w( potlatch2/assets.zip )
config.assets.precompile += %w( potlatch2/FontLibrary.swf )
config.assets.precompile += %w( potlatch2/locales/*.swf )
config.assets.precompile += %w( help/introduction.* )
config.assets.precompile += %w( iD.js iD.css )
config.assets.precompile += %w( iD/img/*.svg iD/img/*.png iD/img/*.gif )
config.assets.precompile += %w( iD/img/pattern/*.png )
# `config.assets.precompile` has moved to config/initializers/assets.rb
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
@ -102,4 +82,9 @@ OpenStreetMap::Application.configure do
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Do not dump schema after migrations.
unless STATUS == :database_offline
config.active_record.dump_schema_after_migration = false
end
end

View file

@ -14,7 +14,7 @@ OpenStreetMap::Application.configure do
# Configure static asset server for tests with Cache-Control for performance.
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
config.static_cache_control = 'public, max-age=3600'
# Show full error reports and disable caching.
config.consider_all_requests_local = true
@ -33,4 +33,7 @@ OpenStreetMap::Application.configure do
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end

View file

@ -84,6 +84,11 @@ defaults: &defaults
require_terms_seen: false
# Whether to require users to agree to the CTs before editing
require_terms_agreed: false
# Imagery to return in capabilities as blacklisted
imagery_blacklist:
- ".*\\.googleapis\\.com/.*"
- ".*\\.google\\.com/.*"
- ".*\\.google\\.ru/.*"
development:
<<: *defaults

View file

@ -0,0 +1,26 @@
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
Rails.application.config.assets.precompile += %w( index.js browse.js welcome.js fixthemap.js )
Rails.application.config.assets.precompile += %w( user.js diary_entry.js )
Rails.application.config.assets.precompile += %w( routing.js )
Rails.application.config.assets.precompile += %w( large-ltr.css small-ltr.css print-ltr.css )
Rails.application.config.assets.precompile += %w( large-rtl.css small-rtl.css print-rtl.css )
Rails.application.config.assets.precompile += %w( leaflet-all.css leaflet.ie.css )
Rails.application.config.assets.precompile += %w( embed.js embed.css )
Rails.application.config.assets.precompile += %w( html5shiv.js )
Rails.application.config.assets.precompile += %w( images/marker-*.png img/*-handle.png )
Rails.application.config.assets.precompile += %w( swfobject.js expressInstall.swf )
Rails.application.config.assets.precompile += %w( potlatch2.swf )
Rails.application.config.assets.precompile += %w( potlatch2/assets.zip )
Rails.application.config.assets.precompile += %w( potlatch2/FontLibrary.swf )
Rails.application.config.assets.precompile += %w( potlatch2/locales/*.swf )
Rails.application.config.assets.precompile += %w( help/introduction.* )
Rails.application.config.assets.precompile += %w( iD.js iD.css )
Rails.application.config.assets.precompile += %w( iD/img/*.svg iD/img/*.png iD/img/*.gif )
Rails.application.config.assets.precompile += %w( iD/img/pattern/*.png )
Rails.application.config.assets.precompile += %w( iD/locales/*.json )

View file

@ -0,0 +1,3 @@
# Be sure to restart your server when you modify this file.
Rails.application.config.action_dispatch.cookies_serializer = :json

View file

@ -2,7 +2,7 @@ if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter
def initialize_type_map_with_enums
def initialize_type_map_with_enums(type_map)
OID.alias_type "format_enum", "text"
OID.alias_type "gpx_visibility_enum", "text"
OID.alias_type "note_status_enum", "text"
@ -11,7 +11,7 @@ if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
OID.alias_type "user_role_enum", "text"
OID.alias_type "user_status_enum", "text"
initialize_type_map_without_enums
initialize_type_map_without_enums(type_map)
end
alias_method_chain :initialize_type_map, :enums

View file

@ -0,0 +1,18 @@
# Some versions of ruby seem to accidentally force the encoding
# as part of normalize_path and some don't
module ActionDispatch
module Journey
class Router
class Utils
def self.normalize_path_with_encoding(path)
self.normalize_path_without_encoding(path).force_encoding("UTF-8")
end
class << self
alias_method_chain :normalize_path, :encoding
end
end
end
end
end

View file

@ -1,12 +0,0 @@
# Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.
# Make sure your secret_key_base is kept private
# if you're sharing your code publicly.
OpenStreetMap::Application.config.secret_key_base = '8be565e2e25831d88231f4bcfd83dfc3ab33957c4f33bb3cff7a279f7820ec4d0c1111f246bb347c68859c0b46b4e591be9179a53a5a7165a9936000d6d2be41'

View file

@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file.
if defined?(MEMCACHE_SERVERS)
OpenStreetMap::Application.config.session_store :mem_cache_store, :memcache_server => MEMCACHE_SERVERS, :namespace => "rails:session", :key => "_osm_session"
Rails.application.config.session_store :mem_cache_store, :memcache_server => MEMCACHE_SERVERS, :namespace => "rails:session", :key => "_osm_session"
else
OpenStreetMap::Application.config.session_store :cache_store, :key => '_osm_session'
Rails.application.config.session_store :cache_store, :key => '_osm_session'
end

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,155 +1,485 @@
# Messages for Bulgarian (Български)
# Messages for Bulgarian (български)
# Exported from translatewiki.net
# Export driver: syck-pecl
# Export driver: spyc
# Author: DCLXVI
# Author: MrPanyGoff
---
bg:
activerecord:
attributes:
diary_entry:
language: Език
user: Потребител
friend:
user: Потребител
trace:
name: Име
size: Размер
user: Потребител
user:
languages: Езици
pass_crypt: Парола
models:
language: Език
message: Съобщение
session: Сесия
user: Потребител
attributes:
diary_entry:
user: Потребител
language: Език
friend:
user: Потребител
friend: Приятел
trace:
user: Потребител
name: Име
size: Размер
user:
description: Описание
languages: Езици
pass_crypt: Парола
browse:
changeset_details:
belongs_to: "Принадлежи към:"
common_details:
changeset_comment: "Коментар:"
version: "Версия:"
containing_relation:
entry: Релация %{relation_name}
entry_role: Релация %{relation_name} (като %{relation_role})
map:
loading: Зареждане...
node:
download: "%{download_xml_link}, %{view_history_link} или %{edit_link}"
download_xml: Изтегляне на XML
edit: редактиране
node: Възел
node_title: "Възел: %{node_name}"
view_history: преглед на историята
node_details:
coordinates: "Координати:"
part_of: "Част от:"
node_history:
download: "%{download_xml_link} или %{view_details_link}"
download_xml: Изтегляне на XML
view_details: преглед на детайлите
not_found:
type:
node: възел
relation: релация
way: път
paging_nav:
of: от
showing_page: Показване на страница
relation:
download_xml: Изтегляне на XML
relation_details:
members: "Членове:"
relation_history:
download: "%{download_xml_link} или %{view_details_link}"
download_xml: Изтегляне на XML
view_details: преглед на детайлите
relation_member:
type:
node: Възел
relation: Релация
containing_relation:
entry: 'Релация %{relation_name}'
entry_role: 'Релация %{relation_name} (като %{relation_role})'
not_found:
type:
node: възел
way: път
relation: релация
redacted:
type:
node: възел
start_rjs:
details: Подробности
loading: Зареждане...
object_list:
details: Подробности
way:
download: "%{download_xml_link}, %{view_history_link} или %{edit_link}"
download_xml: Изтегляне на XML
edit: редактиране
view_history: преглед на историята
way: Път
way_details:
part_of: "Част от:"
way_history:
download: "%{download_xml_link} или %{view_details_link}"
download_xml: Изтегляне на XML
view_details: преглед на детайлите
note:
description: 'Описание:'
changeset:
changeset:
anonymous: Анонимен
changesets:
comment: Коментар
id: Номер
user: Потребител
comment: Коментар
diary_entry:
edit:
language: 'Език:'
location: 'Местоположение:'
latitude: 'Географска ширина:'
longitude: 'Географска дължина:'
save_button: Запази
view:
leave_a_comment: Оставете коментар
login: Влизане
save_button: Съхраняване
diary_entry:
comment_count:
one: 1 коментар
other: "%{count} коментара"
view:
login: Влизане
save_button: Съхраняване
other: '%{count} коментара'
confirm: Потвърди
comments:
newer_comments: По-нови коментари
older_comments: По-стари коментари
export:
start:
licence: Лиценз
too_large:
other:
title: Други източници
options: Настройки
message:
new:
send_button: Изпращане
read:
date: Дата
from: От
subject: Тема
to: До
unread_button: Отбелязване като непрочетено
geocoder:
search_osm_nominatim:
prefix:
amenity:
airport: Летище
arts_centre: Арт център
bank: Банка
bar: Бар
bbq: Барбекю
bench: Пейка
bicycle_parking: Паркинг за велосипеди
bus_station: Автобусна спирка
cafe: Кафене
car_rental: Коли под наем
car_wash: Автомивка
casino: Казино
cinema: Кино
clinic: Поликлиника
club: Клуб
college: Колеж
community_centre: Обществен център
courthouse: Съд
crematorium: Крематориум
dentist: Стоматолог
dormitory: Пансион
drinking_water: Питейна вода
embassy: Посолство
emergency_phone: >
Телефон за спешни
повиквания
fast_food: >
Заведения за бързо
хранене
fire_hydrant: Пожарен кран
fire_station: Пожарна станция
fountain: Фонтан
grave_yard: Гробище
gym: Фитнес зала
hall: Зала
hospital: Болница
hotel: Хотел
ice_cream: Сладолед
kindergarten: Детска градина
library: Библиотека
market: Пазар
marketplace: Пазар
mountain_rescue: >
Планинска спасителна
служба
nightclub: Нощен клуб
office: Офис
park: Парк
parking: Паркинг
pharmacy: Аптека
place_of_worship: Място за поклонение
police: Полиция
post_box: Пощенска кутия
post_office: Поща
prison: Затвор
pub: Кръчма
public_building: Обществена сграда
public_market: Общински пазар
reception_area: Рецепция
restaurant: Ресторант
sauna: Сауна
school: Училище
shelter: Подслон
shop: Магазин
shower: Душ
studio: Студио
supermarket: Супэрмаркет
swimming_pool: Плувен басейн
taxi: Такси
telephone: Телефон
theatre: Театър
toilets: Тоалетна
townhall: Кметство
university: Университет
veterinary: Ветеринарна клиника
village_hall: Кметство
wifi: Достъп до WiFi
WLAN: Достъп до WiFi
youth_centre: Младежки център
boundary:
administrative: >
Административна
граница
national_park: Национален парк
protected_area: Защитена зона
bridge:
aqueduct: Акведукт
suspension: Висящ мост
viaduct: Виадукт
yes: Мост
building:
yes: Сграда
emergency:
fire_hydrant: Пожарен кран
phone: >
Телефон за спешна
връзка
highway:
bus_stop: Автобусна спирка
construction: Магистрала в строеж
cycleway: Велосипедна пътека
footway: Пешеходна пътека
minor: Второстепенен път
motorway: Магистрала
motorway_link: Скоростен път
path: Пътека
pedestrian: Пешеходна пътека
platform: Платформа
primary: Главен път
primary_link: Главен път
raceway: Състезателна писта
residential: Жилищен
rest_area: Зона за почивка
road: Път
secondary: Второстепенен път
secondary_link: Второстепенен път
service: Сервизен път
speed_camera: >
Камера за контрол на
скоростта
steps: Стълбище
street_lamp: Улична лампа
unsurfaced: Път без настилка
historic:
archaeological_site: Археологическа зона
battlefield: Бойно поле
boundary_stone: Граничен камък
building: Сграда
castle: Замък
church: Църква
citywalls: Градски стени
fort: Форт
house: Къща
icon: Икона
mine: Мина
monument: Паметник
museum: Музей
ruins: Руини
tomb: Гробница
tower: Кула
landuse:
basin: Басейн
cemetery: Гробище
construction: Строителство
farm: Ферма
farmland: Обработваема земя
forest: Гора
grass: Трева
industrial: Промишлена зона
military: Военна зона
mine: Мина
orchard: Овощна градина
nature_reserve: Природен резерват
park: Парк
reservoir: Язовир
residential: Жилищна зона
vineyard: Лозя
leisure:
beach_resort: Морски курорт
fishing: Място за риболов
garden: Градина
golf_course: Голф игрище
ice_rink: Ледена пързалка
miniature_golf: Мини-голф
nature_reserve: Природен резерват
park: Парк
sauna: Сауна
sports_centre: Спортен център
stadium: Стадион
swimming_pool: Плувен басейн
water_park: Аква парк
military:
airfield: Военен летище
barracks: Казарма
bunker: Бункер
mountain_pass:
yes: Планински проход
natural:
bay: Залив
beach: Плаж
cape: Нос
channel: Канал
cliff: Скала
crater: Кратер
dune: Дюна
fjord: Фиорд
forest: Гора
geyser: Гейзер
glacier: Ледник
heath: Здраве
hill: Хълм
island: Остров
land: Земя
peak: Връх
river: Река
rock: Скала
tree: Дърво
valley: Долина
volcano: Вулкан
water: Вода
office:
accountant: Счетоводител
architect: Архитект
employment_agency: >
Агенцията по
заетостта
insurance: Застрахователно бюро
lawyer: Адвокат
travel_agent: Туристическа агенция
yes: Офис
place:
airport: Летище
city: Град
country: Страна
county: Област
farm: Ферма
hamlet: Селце
house: Къща
houses: Къщи
island: Остров
islet: островче
moor: тресавище
municipality: община
neighbourhood: квартал
postcode: пощенски код
region: Регион
sea: море
suburb: предградие
town: град
village: село
railway:
abandoned: >
изоставена
железопътна линия
construction: >
железопътна линия в
строеж
disused_station: изоставена гара
halt: железопътна спирка
historic_station: >
гара с историческо
значение
junction: железопътен възел
level_crossing: прелез
monorail: монорелсов
narrow_gauge: Теснолинейка
platform: >
Железопътната
платформа
station: Жп-гара
stop: Железопътна спирка
subway: Метростанция
subway_entrance: вход към метростанция
tram: Трамвай
tram_stop: Трамвайна спирка
shop:
antiques: Антики
art: Арт Магазин
bakery: пекарна
beauty: Салон за красота
beverages: Магазин за напитки
bicycle: Магазин за велосипеди
books: Книжарница
boutique: Бутик
butcher: месар
department_store: универсален магазин
dry_cleaning: химическо чистене
fish: рибен магазин
food: хранителни стоки
furniture: мебели
gallery: Галерия
garden_centre: градински център
gift: магазин за подаръци
greengrocer: плод и зеленчук
grocery: бакалия
hairdresser: фризьор
insurance: застраховане
jewelry: Бижутериен магазин
laundry: Пералня
mall: търговски център
market: Пазар
mobile_phone: >
Магазин за мобилни
телефони
music: Музикален магазин
optician: Оптика
pet: >
Магазин за домашни
любимци
pharmacy: Аптека
photo: Фотомагазин
shoes: Магазин за обувки
shopping_centre: Търговски център
sports: Спортен магазин
stationery: >
Канцеларски
материали
supermarket: Супермаркет
tailor: Шивач
toys: Магазин за играчки
travel_agency: Туристическа агенция
tourism:
guest_house: Къща за гости
hostel: Хостел
hotel: Хотел
information: Информация
motel: Мотел
museum: Музей
picnic_site: Място за пикник
theme_park: Увеселителен парк
valley: Долина
zoo: зологическа градина
tunnel:
yes: Тунел
waterway:
canal: Канал
dam: язовирна стена
mineral_spring: Минерален извор
river: Река
waterfall: Водопад
admin_levels:
level2: Държавна граница
level5: Граница на региона
level6: Държавна граница
level8: граница на града
level9: Граница на селото
level10: >
Граница на
предградията
results:
no_results: >
Не бяха открити
резултати
more_results: Повече резултати
direction:
south_west: югозапад
south: юг
south_east: югоизток
east: изток
north_east: североизток
north: север
north_west: северозапад
west: запад
layouts:
logout: Излизане
log_in: влизане
notifier:
diary_comment_notification:
hi: Здравейте ((to_user)),
email_confirm:
subject: "[OpenStreetMap] Потвърждаване на вашия адрес за е-поща"
subject: '[OpenStreetMap] Потвърждаване на вашия адрес за е-поща'
message:
new:
send_button: Изпращане
read:
from: От
subject: Тема
date: Дата
unread_button: >
Отбелязване като
непрочетено
to: До
trace:
edit:
filename: 'Име на файл:'
edit: редактиране
description: 'Описание:'
save_button: >
Съхраняване на
промените
trace_form:
help: Помощ
view:
filename: 'Име на файл:'
edit: редактиране
trace:
edit: редактиране
in: в
oauth_clients:
new:
submit: Регистриране
edit:
submit: Редактиране
form:
name: Име
new:
submit: Регистриране
trace:
edit:
description: "Описание:"
edit: редактиране
filename: "Име на файл:"
save_button: Съхраняване на промените
no_such_user:
title: Няма такъв потребител
trace:
edit: редактиране
in: в
trace_form:
help: Помощ
view:
edit: редактиране
filename: "Име на файл:"
user:
reset_password:
password: "Парола:"
user_block:
partial:
creator_name: Създател
display_name: Блокиран потребител
edit: Редактиране
reason: Причина за блокиране
status: Статут
password: 'Парола:'
user_role:
grant:
confirm: Потвърждаване
revoke:
confirm: Потвърждаване
user_block:
partial:
edit: Редактиране
display_name: Блокиран потребител
creator_name: Създател
reason: Причина за блокиране
status: Статут

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -79,7 +79,7 @@ en:
printable_name:
with_id: "%{id}"
with_version: "%{id}, v%{version}"
with_name: "%{name} (%{id})"
with_name_html: "%{name} (%{id})"
editor:
default: "Default (currently %{name})"
potlatch:
@ -121,11 +121,16 @@ en:
way_paginated: "Ways (%{x}-%{y} of %{count})"
relation: "Relations (%{count})"
relation_paginated: "Relations (%{x}-%{y} of %{count})"
comment: "Comments (%{count})"
hidden_commented_by: "Hidden comment from %{user} <abbr title='%{exact_time}'>%{when} ago</abbr>"
commented_by: "Comment from %{user} <abbr title='%{exact_time}'>%{when} ago</abbr>"
changesetxml: "Changeset XML"
osmchangexml: "osmChange XML"
feed:
title: "Changeset %{id}"
title_comment: "Changeset %{id} - %{comment}"
join_discussion: "Log in to join the discussion"
discussion: Discussion
node:
title: "Node: %{name}"
history_title: "Node History: %{name}"
@ -180,7 +185,9 @@ en:
wiki_link:
key: "The wiki description page for the %{key} tag"
tag: "The wiki description page for the %{key}=%{value} tag"
wikidata_link: "The %{page} item on Wikidata"
wikipedia_link: "The %{page} article on Wikipedia"
telephone_link: "Call %{phone_number}"
note:
title: "Note: %{id}"
new_note: "New Note"
@ -226,6 +233,13 @@ en:
load_more: "Load more"
timeout:
sorry: "Sorry, the list of changesets you requested took too long to retrieve."
rss:
title_all: OpenStreetMap changeset discussion
title_particular: "OpenStreetMap changeset #%{changeset_id} discussion"
comment: "New comment on changeset #%{changeset_id} by %{author}"
commented_at_html: "Updated %{when} ago"
commented_at_by_html: "Updated %{when} ago by %{user}"
full: Full discussion
diary_entry:
new:
title: New Diary Entry
@ -923,6 +937,10 @@ en:
text: Make a Donation
learn_more: "Learn More"
more: More
sotm_header: State of the Map 2014
sotm_line_1: 8th Annual Conference
sotm_line_2: November 7th-9th 2014
sotm_line_3: Buenos Aires, Argentina
license_page:
foreign:
title: About this translation
@ -1228,6 +1246,16 @@ en:
your_note: "%{commenter} has reactivated one of your map notes near %{place}."
commented_note: "%{commenter} has reactivated a map note you have commented on. The note is near %{place}."
details: "More details about the note can be found at %{url}."
changeset_comment_notification:
greeting: "Hi,"
commented:
subject_own: "[OpenStreetMap] %{commenter} has commented on one of your changesets"
subject_other: "[OpenStreetMap] %{commenter} has commented on a changeset you are interested in"
your_changeset: "%{commenter} has left a comment on one of your changesets created at %{time}"
commented_changeset: "%{commenter} has left a comment on a map changeset you are watching created by %{changeset_author} at %{time}"
partial_changeset_with_comment: "with comment '%{changeset_comment}'"
partial_changeset_without_comment: "without comment"
details: "More details about the changeset can be found at %{url}."
message:
inbox:
title: "Inbox"
@ -1649,9 +1677,6 @@ en:
yahoo:
title: Login with Yahoo
alt: Login with a Yahoo OpenID
myopenid:
title: Login with myOpenID
alt: Login with a myOpenID OpenID
wordpress:
title: Login with Wordpress
alt: Login with a Wordpress OpenID
@ -2107,9 +2132,16 @@ en:
createnote_disabled_tooltip: Zoom in to add a note to the map
map_notes_zoom_in_tooltip: Zoom in to see map notes
map_data_zoom_in_tooltip: Zoom in to see map data
changesets:
show:
comment: "Comment"
subscribe: "Subscribe"
unsubscribe: "Unsubscribe"
hide_comment: "hide"
unhide_comment: "unhide"
notes:
new:
intro: "Spotted a mistake or something missing? Let other mappers know so we can fix it. Move the marker to the correct position and type a note to explain the problem. (Please don't enter personal information here.)"
intro: "Spotted a mistake or something missing? Let other mappers know so we can fix it. Move the marker to the correct position and type a note to explain the problem. (Please don't enter personal information or information from copyrighted maps or directory listings.)"
add: Add Note
show:
anonymous_warning: This note includes comments from anonymous users which should be independently verified.

Some files were not shown because too many files have changed in this diff Show more