- .rubocop.yml
Layout/InitialIndentation:
Enabled: false
- Layout/TrailingBlankLines:
+ Layout/LineLength:
+ Enabled: false
+ Layout/TrailingEmptyLines:
Enabled: false
Layout/TrailingWhitespace:
Enabled: false
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
- Metrics/LineLength:
- Enabled: false
Lint/UselessAssignment:
Enabled: false
Rails/OutputSafety:
- 'script/locale/reload-languages'
- 'script/update-spam-blocks'
-Naming/UncommunicativeMethodParamName:
- Enabled: false
-
-Rails/ApplicationRecord:
+Naming/MethodParameterName:
Enabled: false
Rails/CreateTableWithTimestamps:
Style/BracesAroundHashParameters:
EnforcedStyle: context_dependent
+Style/Documentation:
+ Enabled: false
+
Style/FormatStringToken:
EnforcedStyle: template
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-08-14 19:26:21 +0100 using RuboCop version 0.74.0.
+# on 2019-10-19 16:05:52 +0000 using RuboCop version 0.75.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 33
+# Work around erblint issues.
+# https://github.com/openstreetmap/openstreetmap-website/issues/2472
+require:
+ - rubocop-performance
+ - rubocop-rails
+
+# Offense count: 3338
+# Cop supports --auto-correct.
+# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
+# URISchemes: http, https
+Layout/LineLength:
+ Max: 260
+
+# Offense count: 35
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Exclude:
# Offense count: 4
# Configuration parameters: AllowComments.
-Lint/HandleExceptions:
+Lint/SuppressedException:
Exclude:
- 'app/controllers/api/amf_controller.rb'
- 'app/controllers/users_controller.rb'
+ - 'app/controllers/site_controller.rb'
-# Offense count: 699
+# Offense count: 701
Metrics/AbcSize:
- Max: 279
+ Max: 189
# Offense count: 39
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/ClassLength:
Max: 645
-# Offense count: 73
+# Offense count: 74
Metrics/CyclomaticComplexity:
Max: 22
-# Offense count: 719
+# Offense count: 722
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/MethodLength:
Max: 179
-# Offense count: 1
+# Offense count: 2
# Configuration parameters: CountComments.
Metrics/ModuleLength:
- Max: 107
+ Max: 117
# Offense count: 4
# Configuration parameters: CountKeywordArgs.
Metrics/ParameterLists:
Max: 9
-# Offense count: 71
+# Offense count: 72
Metrics/PerceivedComplexity:
Max: 25
Exclude:
- 'test/models/message_test.rb'
-# Offense count: 263
-Style/Documentation:
- Enabled: false
+# Offense count: 27
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: annotated, template, unannotated
+Style/FormatStringToken:
+ Exclude:
+ - 'app/models/concerns/geo_record.rb'
+ - 'app/views/api/map/_bounds.xml.builder'
+ - 'lib/bounding_box.rb'
+ - 'test/controllers/api/map_controller_test.rb'
+ - 'test/controllers/api/relations_controller_test.rb'
+ - 'test/controllers/api/ways_controller_test.rb'
+ - 'test/lib/bounding_box_test.rb'
# Offense count: 539
# Cop supports --auto-correct.
# Configuration parameters: Strict.
Style/NumericLiterals:
MinDigits: 11
-
-# Offense count: 3322
-# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
-# URISchemes: http, https
-Metrics/LineLength:
- Max: 307
-dist: xenial
+dist: bionic
language: ruby
rvm:
- 2.5.3
postgresql: 9.5
apt:
packages:
- - postgresql-server-dev-9.5
- libarchive-dev
+ - libgd-dev
+ - libffi-dev
+ - libbz2-dev
services:
- memcached
-env:
- global:
- - OSM_MEMCACHE_SERVERS="127.0.0.1"
before_script:
- - sed -e "/idle_in_transaction_session_timeout/d" -e 's/ IMMUTABLE / /' -e "s/AS '.*libpgosm.*',/AS 'libpgosm',/" -e "/^--/d" db/structure.sql > db/structure.expected
+ - sed -e 's/ IMMUTABLE / /' -e "/^--/d" db/structure.sql > db/structure.expected
- psql -U postgres -c "CREATE DATABASE openstreetmap"
- psql -U postgres -c "CREATE EXTENSION btree_gist" openstreetmap
- - make -C db/functions libpgosm.so
- - ln db/functions/libpgosm.so /tmp
- - psql -U postgres -c "CREATE FUNCTION maptile_for_point(int8, int8, int4) RETURNS int4 AS '/tmp/libpgosm', 'maptile_for_point' LANGUAGE C STRICT" openstreetmap
- - psql -U postgres -c "CREATE FUNCTION tile_for_point(int4, int4) RETURNS int8 AS '/tmp/libpgosm', 'tile_for_point' LANGUAGE C STRICT" openstreetmap
- - psql -U postgres -c "CREATE FUNCTION xid_to_int4(xid) RETURNS int4 AS '/tmp/libpgosm', 'xid_to_int4' LANGUAGE C STRICT" openstreetmap
+ - psql -U postgres -f db/functions/functions.sql openstreetmap
- cp config/travis.database.yml config/database.yml
- cp config/example.storage.yml config/storage.yml
- touch config/settings.local.yml
+ - echo -e "---\nmemcache_servers:\n - 127.0.0.1" > config/settings/test.local.yml
- bundle exec rake db:migrate
- bundle exec rake i18n:js:export
- bundle exec rake yarn:install
- bundle exec rake eslint
- bundle exec erblint .
- bundle exec rake db:structure:dump
- - sed -e "/idle_in_transaction_session_timeout/d" -e 's/ IMMUTABLE / /' -e "s/AS '.*libpgosm.*',/AS 'libpgosm',/" -e "/^--/d" db/structure.sql > db/structure.actual
+ - sed -e "/idle_in_transaction_session_timeout/d" -e 's/ IMMUTABLE / /' -e "/^--/d" db/structure.sql > db/structure.actual
- diff -uw db/structure.expected db/structure.actual
- bundle exec rake test:db
* Passenger will, by design, use the Production environment and therefore the production database - make sure it contains the appropriate data and user accounts.
* 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](https://git.openstreetmap.org/gpx-import.git/).
* Make sure you generate the i18n files and precompile the production assets: `RAILS_ENV=production rake i18n:js:export assets:precompile`
* Make sure the web server user as well as the rails user can read, write and create directories in `tmp/`.
+* If you want to use diff replication then you might want to consider installing the shared library special SQL functions for the `xid_to_int4` function. A pure SQL version is available, but may become a performance issue on large databases with a high rate of changes. Note that you will need a version of PostgreSQL < 9.6 (yes, _less than_) to use `xid` indexing, whether pure SQL or shared library.
+* If you expect to serve a lot of `/changes` API calls, then you might also want to install the shared library versions of the SQL functions.
[Translatewiki](https://translatewiki.net/wiki/Translating:OpenStreetMap) and should
not be included in your pull request.
+### Nominatim prefixes
+
+I18n keys under the `geocoder.search_osm_nominatim` keyspace are managed by the
+Nominatim maintainers. From time to time they run stats over the Nominatim
+database, and update the list of available keys manually.
+
+Adding or removing keys to this list is therefore discouraged, but contributions
+to the descriptive texts are welcome.
+
## Code Documentation
To generate the HTML documentation of the API/rails code, run the command
source "https://rubygems.org"
# Require rails
-gem "rails", "5.2.3"
+gem "rails", "6.0.2.1"
# Require things which have moved to gems in ruby 1.9
gem "bigdecimal", "~> 1.1.0", :platforms => :ruby_19
# Use Uglifier as compressor for JavaScript assets
gem "uglifier", ">= 1.3.0"
-# Use CoffeeScript for .js.coffee assets and views
-gem "coffee-rails", "~> 4.2"
-
# Use jquery as the JavaScript library
gem "jquery-rails"
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
-# gem 'jbuilder', '~> 2.0'
-gem "jsonify-rails"
+gem "jbuilder", "~> 2.7"
# Reduces boot times through caching; required in config/boot.rb
-gem "bootsnap", ">= 1.1.0", :require => false
+gem "bootsnap", ">= 1.4.2", :require => false
# Use R2 for RTL conversion
gem "r2", "~> 0.2.7"
# Use autoprefixer to generate CSS prefixes
-gem "autoprefixer-rails", "~> 8.6.3"
+gem "autoprefixer-rails"
# Use image_optim to optimise images
gem "image_optim_rails"
# Load rails plugins
-gem "actionpack-page_caching"
+gem "actionpack-page_caching", ">= 1.2.0"
gem "active_record_union"
gem "activerecord-import"
+gem "bootstrap", "~> 4.3.1"
gem "cancancan"
-gem "composite_primary_keys", "~> 11.1.0"
+gem "composite_primary_keys", "~> 12.0.0"
gem "config"
gem "delayed_job_active_record"
gem "dynamic_form"
gem "openstreetmap-deadlock_retry", ">= 1.3.0", :require => "deadlock_retry"
gem "rack-cors"
gem "rails-i18n", "~> 4.0.0"
-gem "record_tag_helper"
gem "rinku", ">= 2.0.6", :require => "rails_rinku"
gem "strong_migrations"
gem "validates_email_format_of", ">= 1.5.1"
# Load faraday for mockable HTTP client
gem "faraday"
-# Load geoip for querying Maxmind GeoIP database
-gem "geoip"
+# Load maxminddb for querying Maxmind GeoIP database
+gem "maxminddb"
# Load rotp to generate TOTP tokens
gem "rotp"
# Needed in development as well so rake can see konacha tasks
group :development, :test do
- gem "capybara", "~> 2.13"
+ gem "capybara", ">= 2.15"
gem "coveralls", :require => false
gem "erb_lint", :require => false
gem "factory_bot_rails"
gem "poltergeist"
- gem "puma", "~> 3.7"
+ gem "puma", "~> 3.11"
+ gem "selenium-webdriver"
end
remote: https://rubygems.org/
specs:
SystemTimer (1.2.3)
- aasm (5.0.5)
+ aasm (5.0.6)
concurrent-ruby (~> 1.0)
- actioncable (5.2.3)
- actionpack (= 5.2.3)
+ actioncable (6.0.2.1)
+ actionpack (= 6.0.2.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailer (5.2.3)
- actionpack (= 5.2.3)
- actionview (= 5.2.3)
- activejob (= 5.2.3)
+ actionmailbox (6.0.2.1)
+ actionpack (= 6.0.2.1)
+ activejob (= 6.0.2.1)
+ activerecord (= 6.0.2.1)
+ activestorage (= 6.0.2.1)
+ activesupport (= 6.0.2.1)
+ mail (>= 2.7.1)
+ actionmailer (6.0.2.1)
+ actionpack (= 6.0.2.1)
+ actionview (= 6.0.2.1)
+ activejob (= 6.0.2.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (5.2.3)
- actionview (= 5.2.3)
- activesupport (= 5.2.3)
- rack (~> 2.0)
+ actionpack (6.0.2.1)
+ actionview (= 6.0.2.1)
+ activesupport (= 6.0.2.1)
+ rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionpack-page_caching (1.1.1)
- actionpack (>= 4.0.0, < 6)
- actionview (5.2.3)
- activesupport (= 5.2.3)
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
+ actionpack-page_caching (1.2.0)
+ actionpack (>= 5.0.0)
+ actiontext (6.0.2.1)
+ actionpack (= 6.0.2.1)
+ activerecord (= 6.0.2.1)
+ activestorage (= 6.0.2.1)
+ activesupport (= 6.0.2.1)
+ nokogiri (>= 1.8.5)
+ actionview (6.0.2.1)
+ activesupport (= 6.0.2.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_record_union (1.3.0)
activerecord (>= 4.0)
- activejob (5.2.3)
- activesupport (= 5.2.3)
+ activejob (6.0.2.1)
+ activesupport (= 6.0.2.1)
globalid (>= 0.3.6)
- activemodel (5.2.3)
- activesupport (= 5.2.3)
- activerecord (5.2.3)
- activemodel (= 5.2.3)
- activesupport (= 5.2.3)
- arel (>= 9.0)
- activerecord-import (1.0.2)
+ activemodel (6.0.2.1)
+ activesupport (= 6.0.2.1)
+ activerecord (6.0.2.1)
+ activemodel (= 6.0.2.1)
+ activesupport (= 6.0.2.1)
+ activerecord-import (1.0.4)
activerecord (>= 3.2)
- activestorage (5.2.3)
- actionpack (= 5.2.3)
- activerecord (= 5.2.3)
+ activestorage (6.0.2.1)
+ actionpack (= 6.0.2.1)
+ activejob (= 6.0.2.1)
+ activerecord (= 6.0.2.1)
marcel (~> 0.3.1)
- activesupport (5.2.3)
+ activesupport (6.0.2.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
- addressable (2.6.0)
- public_suffix (>= 2.0.2, < 4.0)
- annotate (2.7.5)
+ zeitwerk (~> 2.2)
+ addressable (2.7.0)
+ public_suffix (>= 2.0.2, < 5.0)
+ annotate (3.0.3)
activerecord (>= 3.2, < 7.0)
- rake (>= 10.4, < 13.0)
- arel (9.0.0)
+ rake (>= 10.4, < 14.0)
ast (2.4.0)
- autoprefixer-rails (8.6.5)
+ autoprefixer-rails (9.7.4)
execjs
aws-eventstream (1.0.3)
- aws-partitions (1.206.0)
- aws-sdk-core (3.64.0)
+ aws-partitions (1.272.0)
+ aws-sdk-core (3.90.0)
aws-eventstream (~> 1.0, >= 1.0.2)
- aws-partitions (~> 1.0)
+ aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
- aws-sdk-kms (1.24.0)
- aws-sdk-core (~> 3, >= 3.61.1)
+ aws-sdk-kms (1.29.0)
+ aws-sdk-core (~> 3, >= 3.71.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.46.0)
- aws-sdk-core (~> 3, >= 3.61.1)
+ aws-sdk-s3 (1.60.2)
+ aws-sdk-core (~> 3, >= 3.83.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.0)
bigdecimal (1.1.0)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
- bootsnap (1.4.4)
+ bootsnap (1.4.5)
msgpack (~> 1.0)
- browser (2.6.1)
- builder (3.2.3)
+ bootstrap (4.3.1)
+ autoprefixer-rails (>= 9.1.0)
+ popper_js (>= 1.14.3, < 2)
+ sassc-rails (>= 2.0.0)
+ browser (3.0.3)
+ builder (3.2.4)
bzip2-ffi (1.0.0)
ffi (~> 1.0)
- cancancan (3.0.1)
+ cancancan (3.0.2)
canonical-rails (0.2.6)
rails (>= 4.1, < 6.1)
- capybara (2.18.0)
+ capybara (3.31.0)
addressable
mini_mime (>= 0.1.3)
- nokogiri (>= 1.3.3)
- rack (>= 1.0.0)
- rack-test (>= 0.5.4)
- xpath (>= 2.0, < 4.0)
+ nokogiri (~> 1.8)
+ rack (>= 1.6.0)
+ rack-test (>= 0.6.3)
+ regexp_parser (~> 1.5)
+ xpath (~> 3.2)
+ childprocess (3.0.0)
cliver (0.3.2)
coderay (1.1.2)
- coffee-rails (4.2.2)
- coffee-script (>= 2.2.0)
- railties (>= 4.0.0)
- coffee-script (2.4.1)
- coffee-script-source
- execjs
- coffee-script-source (1.12.2)
- composite_primary_keys (11.1.0)
- activerecord (~> 5.2.1)
- concurrent-ruby (1.1.5)
- config (2.0.0)
- activesupport (>= 4.2)
+ composite_primary_keys (12.0.1)
+ activerecord (~> 6.0.0)
+ concurrent-ruby (1.1.6)
+ config (2.2.1)
deep_merge (~> 1.2, >= 1.2.1)
- dry-schema (~> 1.0)
+ dry-validation (~> 1.0, >= 1.0.0)
coveralls (0.8.23)
json (>= 1.8, < 3)
simplecov (~> 0.16.1)
tins (~> 1.6)
crack (0.4.3)
safe_yaml (~> 1.0.0)
- crass (1.0.4)
+ crass (1.0.6)
dalli (2.7.10)
debug_inspector (0.0.3)
deep_merge (1.2.1)
activerecord (>= 3.0, < 6.1)
delayed_job (>= 3.0, < 5)
docile (1.3.2)
- dry-configurable (0.8.3)
+ dry-configurable (0.9.0)
concurrent-ruby (~> 1.0)
dry-core (~> 0.4, >= 0.4.7)
dry-container (0.7.2)
dry-configurable (~> 0.1, >= 0.1.3)
dry-core (0.4.9)
concurrent-ruby (~> 1.0)
- dry-equalizer (0.2.2)
- dry-inflector (0.1.2)
- dry-initializer (3.0.1)
- dry-logic (1.0.3)
+ dry-equalizer (0.3.0)
+ dry-inflector (0.2.0)
+ dry-initializer (3.0.3)
+ dry-logic (1.0.6)
concurrent-ruby (~> 1.0)
dry-core (~> 0.2)
dry-equalizer (~> 0.2)
- dry-schema (1.3.3)
+ dry-schema (1.4.3)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.8, >= 0.8.3)
dry-core (~> 0.4)
dry-equalizer (~> 0.2)
dry-initializer (~> 3.0)
dry-logic (~> 1.0)
- dry-types (~> 1.0)
- dry-types (1.1.1)
+ dry-types (~> 1.2)
+ dry-types (1.3.0)
concurrent-ruby (~> 1.0)
dry-container (~> 0.3)
dry-core (~> 0.4, >= 0.4.4)
- dry-equalizer (~> 0.2, >= 0.2.2)
+ dry-equalizer (~> 0.3)
dry-inflector (~> 0.1, >= 0.1.2)
dry-logic (~> 1.0, >= 1.0.2)
+ dry-validation (1.4.2)
+ concurrent-ruby (~> 1.0)
+ dry-container (~> 0.7, >= 0.7.1)
+ dry-core (~> 0.4)
+ dry-equalizer (~> 0.2)
+ dry-initializer (~> 3.0)
+ dry-schema (~> 1.4, >= 1.4.3)
dynamic_form (1.1.4)
- erb_lint (0.0.29)
+ erb_lint (0.0.31)
activesupport
better_html (~> 1.0.7)
html_tokenizer
rainbow
- rubocop (~> 0.51)
+ rubocop (~> 0.79.0)
smart_properties
- erubi (1.8.0)
+ erubi (1.9.0)
execjs (2.7.0)
exifr (1.3.6)
- factory_bot (5.0.2)
+ factory_bot (5.1.1)
activesupport (>= 4.2.0)
- factory_bot_rails (5.0.2)
- factory_bot (~> 5.0.2)
+ factory_bot_rails (5.1.1)
+ factory_bot (~> 5.1.0)
railties (>= 4.2.0)
- fakefs (0.20.1)
- faraday (0.15.4)
+ fakefs (1.0.0)
+ faraday (1.0.0)
multipart-post (>= 1.2, < 3)
- ffi (1.11.1)
- ffi-libarchive (0.4.10)
+ ffi (1.12.2)
+ ffi-libarchive (1.0.0)
ffi (~> 1.0)
fspath (3.1.2)
gd2-ffij (0.4.0)
ffi (>= 1.0.0)
- geoip (1.6.4)
globalid (0.4.2)
activesupport (>= 4.2.0)
hashdiff (1.0.0)
http_accept_language (2.0.5)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
- i18n-js (3.3.0)
+ i18n-js (3.5.1)
i18n (>= 0.6.6)
image_optim (0.26.5)
exifr (~> 1.2, >= 1.2.2)
rails
sprockets
image_size (2.0.2)
- in_threads (1.5.3)
- jaro_winkler (1.5.3)
+ in_threads (1.5.4)
+ jaro_winkler (1.5.4)
+ jbuilder (2.10.0)
+ activesupport (>= 5.0.0)
jmespath (1.4.0)
jquery-rails (4.3.5)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
- json (2.2.0)
- jsonify (0.3.1)
- multi_json (~> 1.0)
- jsonify-rails (0.3.2)
- actionpack
- jsonify (< 0.4.0)
+ json (2.3.0)
jwt (2.2.1)
- kgio (2.11.2)
+ kgio (2.11.3)
kramdown (2.1.0)
libxml-ruby (3.1.0)
- listen (3.1.5)
- rb-fsevent (~> 0.9, >= 0.9.4)
- rb-inotify (~> 0.9, >= 0.9.7)
- ruby_dep (~> 1.2)
+ listen (3.2.1)
+ rb-fsevent (~> 0.10, >= 0.10.3)
+ rb-inotify (~> 0.9, >= 0.9.10)
logstash-event (1.2.02)
logstasher (1.3.0)
activesupport (>= 4.0)
logstash-event (~> 1.2.0)
request_store
- loofah (2.2.3)
+ loofah (2.4.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
+ maxminddb (0.1.22)
method_source (0.9.2)
- mimemagic (0.3.3)
- mini_magick (4.9.5)
+ mimemagic (0.3.4)
+ mini_magick (4.10.1)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
- minitest (5.11.3)
- msgpack (1.3.1)
- multi_json (1.13.1)
+ minitest (5.14.0)
+ msgpack (1.3.3)
+ multi_json (1.14.1)
multi_xml (0.6.0)
multipart-post (2.1.1)
- nio4r (2.4.0)
- nokogiri (1.10.4)
+ nio4r (2.5.2)
+ nokogiri (1.10.8)
mini_portile2 (~> 2.4.0)
- nokogumbo (2.0.1)
+ nokogumbo (2.0.2)
nokogiri (~> 1.8, >= 1.8.4)
oauth (0.4.7)
oauth-plugin (0.5.1)
oauth (~> 0.4.4)
oauth2 (>= 0.5.0)
rack
- oauth2 (1.4.1)
- faraday (>= 0.8, < 0.16.0)
+ oauth2 (1.4.4)
+ faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
- omniauth-facebook (5.0.0)
+ omniauth-facebook (6.0.0)
omniauth-oauth2 (~> 1.2)
- omniauth-github (1.3.0)
+ omniauth-github (1.4.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-google-oauth2 (0.8.0)
multi_json (~> 1.12)
omniauth-oauth2 (~> 1.4)
openstreetmap-deadlock_retry (1.3.0)
- parallel (1.17.0)
- parser (2.6.3.0)
+ parallel (1.19.1)
+ parser (2.7.0.2)
ast (~> 2.4.0)
- pg (1.1.4)
+ pg (1.2.2)
poltergeist (1.18.1)
capybara (>= 2.1, < 4)
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
+ popper_js (1.16.0)
progress (3.5.2)
psych (3.1.0)
- public_suffix (3.1.1)
- puma (3.12.1)
+ public_suffix (4.0.3)
+ puma (3.12.2)
quad_tile (1.0.1)
r2 (0.2.7)
- rack (2.0.7)
- rack-cors (1.0.3)
+ rack (2.2.2)
+ rack-cors (1.1.1)
+ rack (>= 2.0.0)
rack-openid (1.3.1)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rack-uri_sanitizer (0.0.2)
- rails (5.2.3)
- actioncable (= 5.2.3)
- actionmailer (= 5.2.3)
- actionpack (= 5.2.3)
- actionview (= 5.2.3)
- activejob (= 5.2.3)
- activemodel (= 5.2.3)
- activerecord (= 5.2.3)
- activestorage (= 5.2.3)
- activesupport (= 5.2.3)
+ rails (6.0.2.1)
+ actioncable (= 6.0.2.1)
+ actionmailbox (= 6.0.2.1)
+ actionmailer (= 6.0.2.1)
+ actionpack (= 6.0.2.1)
+ actiontext (= 6.0.2.1)
+ actionview (= 6.0.2.1)
+ activejob (= 6.0.2.1)
+ activemodel (= 6.0.2.1)
+ activerecord (= 6.0.2.1)
+ activestorage (= 6.0.2.1)
+ activesupport (= 6.0.2.1)
bundler (>= 1.3.0)
- railties (= 5.2.3)
+ railties (= 6.0.2.1)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.4)
actionpack (>= 5.0.1.x)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
- rails-html-sanitizer (1.2.0)
- loofah (~> 2.2, >= 2.2.2)
+ rails-html-sanitizer (1.3.0)
+ loofah (~> 2.3)
rails-i18n (4.0.2)
i18n (~> 0.6)
rails (>= 4.0)
- railties (5.2.3)
- actionpack (= 5.2.3)
- activesupport (= 5.2.3)
+ railties (6.0.2.1)
+ actionpack (= 6.0.2.1)
+ activesupport (= 6.0.2.1)
method_source
rake (>= 0.8.7)
- thor (>= 0.19.0, < 2.0)
+ thor (>= 0.20.3, < 2.0)
rainbow (3.0.0)
- rake (12.3.3)
+ rake (13.0.1)
rb-fsevent (0.10.3)
- rb-inotify (0.10.0)
+ rb-inotify (0.10.1)
ffi (~> 1.0)
- record_tag_helper (1.0.0)
- actionview (~> 5.x)
- request_store (1.4.1)
+ regexp_parser (1.6.0)
+ request_store (1.5.0)
rack (>= 1.4)
rinku (2.0.6)
rotp (5.1.0)
addressable (~> 2.5)
- rubocop (0.74.0)
+ rubocop (0.79.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
- parser (>= 2.6)
+ parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
- rubocop-performance (1.4.1)
+ rubocop-performance (1.5.2)
rubocop (>= 0.71.0)
- rubocop-rails (2.3.1)
+ rubocop-rails (2.4.2)
rack (>= 1.1)
rubocop (>= 0.72.0)
- ruby-openid (2.7.0)
+ ruby-openid (2.9.2)
ruby-progressbar (1.10.1)
- ruby_dep (1.5.0)
+ rubyzip (2.2.0)
safe_yaml (1.0.5)
- sanitize (5.0.0)
+ sanitize (5.1.0)
crass (~> 1.0.2)
nokogiri (>= 1.8.0)
nokogumbo (~> 2.0)
- sassc (2.0.1)
+ sassc (2.2.1)
ffi (~> 1.9)
- rake
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
- secure_headers (6.1.1)
+ secure_headers (6.3.0)
+ selenium-webdriver (3.142.7)
+ childprocess (>= 0.5, < 4.0)
+ rubyzip (>= 1.2.2)
simplecov (0.16.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
smart_properties (1.15.0)
- sprockets (3.7.2)
+ sprockets (4.0.0)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
- strong_migrations (0.4.1)
+ strong_migrations (0.6.2)
activerecord (>= 5)
+ sync (0.5.0)
term-ansicolor (1.7.1)
tins (~> 1.0)
- thor (0.20.3)
+ thor (1.0.1)
thread_safe (0.3.6)
- tilt (2.0.9)
- tins (1.21.1)
- tzinfo (1.2.5)
+ tilt (2.0.10)
+ tins (1.24.1)
+ sync
+ tzinfo (1.2.6)
thread_safe (~> 0.1)
- uglifier (4.1.20)
+ uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
- unicode-display_width (1.6.0)
+ unicode-display_width (1.6.1)
validates_email_format_of (1.6.3)
i18n
vendorer (0.2.0)
- webmock (3.6.2)
+ webmock (3.8.2)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
websocket-extensions (0.1.4)
xpath (3.2.0)
nokogiri (~> 1.8)
+ zeitwerk (2.2.2)
PLATFORMS
ruby
DEPENDENCIES
SystemTimer (>= 1.1.3)
aasm
- actionpack-page_caching
+ actionpack-page_caching (>= 1.2.0)
active_record_union
activerecord-import
annotate
- autoprefixer-rails (~> 8.6.3)
+ autoprefixer-rails
aws-sdk-s3
better_errors
bigdecimal (~> 1.1.0)
binding_of_caller
- bootsnap (>= 1.1.0)
+ bootsnap (>= 1.4.2)
+ bootstrap (~> 4.3.1)
browser
bzip2-ffi
cancancan
canonical-rails
- capybara (~> 2.13)
- coffee-rails (~> 4.2)
- composite_primary_keys (~> 11.1.0)
+ capybara (>= 2.15)
+ composite_primary_keys (~> 12.0.0)
config
coveralls
dalli
faraday
ffi-libarchive
gd2-ffij (>= 0.4.0)
- geoip
htmlentities
http_accept_language (~> 2.0.0)
i18n-js (>= 3.0.0)
image_optim_rails
+ jbuilder (~> 2.7)
jquery-rails
json
- jsonify-rails
kgio
kramdown
libxml-ruby (>= 2.0.5)
listen
logstasher
+ maxminddb
mimemagic
mini_magick
minitest (~> 5.1)
pg
poltergeist
psych
- puma (~> 3.7)
+ puma (~> 3.11)
quad_tile (~> 1.0.1)
r2 (~> 0.2.7)
rack-cors
rack-uri_sanitizer
- rails (= 5.2.3)
+ rails (= 6.0.2.1)
rails-controller-testing
rails-i18n (~> 4.0.0)
- record_tag_helper
rinku (>= 2.0.6)
rotp
rubocop
sanitize
sassc-rails
secure_headers
+ selenium-webdriver
strong_migrations
uglifier (>= 1.3.0)
validates_email_format_of (>= 1.5.1)
* Ruby 2.5+
* PostgreSQL 9.1+
* ImageMagick
-* Bundler
+* Bundler (see note below about [developer Ruby setup](#rbenv))
* Javascript Runtime
These can be installed on Ubuntu 18.04 or later with:
sudo apt-get install ruby2.5 libruby2.5 ruby2.5-dev bundler \
libmagickwand-dev libxml2-dev libxslt1-dev nodejs \
apache2 apache2-dev build-essential git-core phantomjs \
- postgresql postgresql-contrib libpq-dev postgresql-server-dev-all \
- libsasl2-dev imagemagick libffi-dev libgd-dev libarchive-dev libbz2-dev
+ postgresql postgresql-contrib libpq-dev libsasl2-dev \
+ imagemagick libffi-dev libgd-dev libarchive-dev libbz2-dev
sudo gem2.5 install bundler
```
sudo dnf install ruby ruby-devel rubygem-rdoc rubygem-bundler rubygems \
libxml2-devel js \
gcc gcc-c++ git \
- postgresql postgresql-server postgresql-contrib postgresql-devel \
+ postgresql postgresql-server postgresql-contrib \
perl-podlators ImageMagick libffi-devel gd-devel libarchive-devel \
bzip2-devel nodejs-yarn
```
Installing PostgreSQL:
* Install Postgres.app from https://postgresapp.com/
+* Make sure that you've initialized and started Postgresql from the app (there should be a little elephant icon in your systray).
* Add PostgreSQL to your path, by editing your profile:
`nano ~/.profile`
`export PATH=/Applications/Postgres.app/Contents/MacOS/bin:$PATH`
+After this, you may need to start a new shell window, or source the profile again by running `. ~/.profile`.
+
Installing other dependencies:
* Install Homebrew from https://brew.sh/
* Install the latest version of Ruby: `brew install ruby`
-* Install ImageMagick: `brew install imagemagick`
-* Install libxml2: `brew install libxml2 --with-xml2-config`
-* If you want to run the tests, you need `phantomjs` as well: `brew install phantomjs`
-* Install Bundler: `gem install bundler`
+* Install other dependencies: `brew install imagemagick libxml2 gd yarn pngcrush optipng pngquant jhead jpegoptim gifsicle svgo`
+* Install Bundler: `gem install bundler` (you might need to `sudo gem install bundler` if you get an error about permissions - or see note below about [developer Ruby setup](#rbenv))
+
+You will need to tell `bundler` that `libxml2` is installed in a Homebrew location. If it uses the system-installed one then you will get errors installing the `libxml-ruby` gem later on<a name="macosx-bundle-config"></a>.
+
+```
+bundle config build.libxml-ruby --with-xml2-config=/usr/local/opt/libxml2/bin/xml2-config
+```
+
+If you want to run the tests, you need `phantomjs` as well:
+
+```
+brew tap homebrew/cask
+brew cask install phantomjs
+```
Note that OS X does not have a /home directory by default, so if you are using the GPX functions, you will need to change the directories specified in config/application.yml.
bundle exec rake yarn:install
```
+## Prepare local settings file
+
+This is a workaround. [See issues/2185 for details](https://github.com/openstreetmap/openstreetmap-website/issues/2185#issuecomment-508676026).
+
+```
+touch config/settings.local.yml
+```
+
## Storage setup
The Rails port needs to be configured with an object storage facility - for
### PostgreSQL Functions
-We need to install special functions into the PostgreSQL databases, and these are provided by a library that needs compiling first.
-
-```
-cd db/functions
-make libpgosm.so
-cd ../..
-```
-
-Then we create the functions within each database. We're using `pwd` to substitute in the current working directory, since PostgreSQL needs the full path.
+We need to install some special functions into the PostgreSQL database:
```
-psql -d openstreetmap -c "CREATE FUNCTION maptile_for_point(int8, int8, int4) RETURNS int4 AS '`pwd`/db/functions/libpgosm', 'maptile_for_point' LANGUAGE C STRICT"
-psql -d openstreetmap -c "CREATE FUNCTION tile_for_point(int4, int4) RETURNS int8 AS '`pwd`/db/functions/libpgosm', 'tile_for_point' LANGUAGE C STRICT"
-psql -d openstreetmap -c "CREATE FUNCTION xid_to_int4(xid) RETURNS int4 AS '`pwd`/db/functions/libpgosm', 'xid_to_int4' LANGUAGE C STRICT"
+psql -d openstreetmap -f db/functions/functions.sql
```
### Database structure
# Configuration
After installing this software, you may need to carry out some [configuration steps](CONFIGURE.md), depending on your tasks.
+
+# Installing compiled shared library database functions (optional)
+
+There are special database functions required by a (little-used) API call, the migrations and diff replication. The former two are provided as *either* pure SQL functions or a compiled shared library. The SQL versions are installed as part of the recommended install procedure above and the shared library versions are recommended only if you are running a production server making a lot of `/changes` API calls or need the diff replication functionality.
+
+If you aren't sure which you need, stick with the SQL versions.
+
+Before installing the functions, it's necessary to install the PostgreSQL server development packages. On Ubuntu this means:
+
+```
+sudo apt-get install postgresql-server-dev-all
+```
+
+On Fedora:
+
+```
+sudo dnf install postgresql-devel
+```
+
+The library then needs compiling.
+
+```
+cd db/functions
+make libpgosm.so
+cd ../..
+```
+
+If you previously installed the SQL versions of these functions, we'll need to delete those before adding the new ones:
+
+```
+psql -d openstreetmap -c "DROP FUNCTION IF EXISTS maptile_for_point"
+psql -d openstreetmap -c "DROP FUNCTION IF EXISTS tile_for_point"
+```
+
+Then we create the functions within each database. We're using `pwd` to substitute in the current working directory, since PostgreSQL needs the full path.
+
+```
+psql -d openstreetmap -c "CREATE FUNCTION maptile_for_point(int8, int8, int4) RETURNS int4 AS '`pwd`/db/functions/libpgosm', 'maptile_for_point' LANGUAGE C STRICT"
+psql -d openstreetmap -c "CREATE FUNCTION tile_for_point(int4, int4) RETURNS int8 AS '`pwd`/db/functions/libpgosm', 'tile_for_point' LANGUAGE C STRICT"
+psql -d openstreetmap -c "CREATE FUNCTION xid_to_int4(xid) RETURNS int4 AS '`pwd`/db/functions/libpgosm', 'xid_to_int4' LANGUAGE C STRICT"
+```
+
+# Ruby development install and versions<a name="rbenv"></a> (optional)
+
+For simplicity, this document explains how to install all the website dependencies as "system" dependencies. While this is simpler, and usually faster, you might want more control over the process or the ability to install multiple different versions of software alongside eachother. For many developers, [`rbenv`](https://github.com/rbenv/rbenv) is the easiest way to manage multiple different Ruby versions on the same computer - with the added advantage that the installs are all in your home directory, so you don't need administrator permissions.
+
+If you choose to install Ruby and Bundler via `rbenv`, then you do not need to install the system libraries for Ruby:
+
+* For Ubuntu, you do not need to install the following packages: `ruby2.5 libruby2.5 ruby2.5-dev bundler`,
+* For Fedora, you do not need to install the following packages: `ruby ruby-devel rubygem-rdoc rubygem-bundler rubygems`
+* For MacOSX, you do not need to `brew install ruby` - but make sure you've installed a version of Ruby using `rbenv` before running `gem install bundler`!
+
+After installing a version of Ruby with `rbenv` (the latest stable version is a good place to start), you will need to make that the default. From inside the `openstreetmap-website` directory, run:
+
+```
+rbenv local $VERSION
+```
+
+Where `$VERSION` is the version you installed. Then install bundler:
+
+```
+gem install bundler
+```
+
+You should now be able to proceed with the rest of the installation. If you're on MacOSX, make sure you set up the [config override for the libxml2 location](#macosx-bundle-config) _after_ installing bundler.
Installers are available for Mac OS X and Windows, please see the [Vagrant project download page](https://www.vagrantup.com/downloads.html) for more information.
-Note than until there are suitable _xenial64_ [vagrant boxes](https://atlas.hashicorp.com/boxes/search?utf8=%E2%9C%93&sort=&provider=&q=xenial64) for other providers,
-the only virtualization provider supported is virtualbox. You might need to install it and specify `--provider virtualbox` when setting up your environment.
+We currently support three Vagrant providers, namely `virtualbox`, `lxc` and `libvirt`. You might need to install one of these, for example virtualbox, and specify the provider, e.g. `--provider virtualbox`, when setting up your environment.
# Setting up openstreetmap-website
folder 'javascripts' do
file 'html5shiv.js', 'https://raw.githubusercontent.com/aFarkas/html5shiv/master/src/html5shiv.js'
- file 'bowser.js', 'https://github.com/lancedikson/bowser/releases/download/1.9.4/bowser.js'
end
folder 'swfobject' do
can [:new, :create, :reply, :show, :inbox, :outbox, :mark, :destroy], Message
can [:close, :reopen], Note
can [:new, :create], Report
- can [:mine, :new, :create, :edit, :update, :delete], Trace
+ can [:mine, :new, :create, :edit, :update, :destroy], Trace
can [:account, :go_public, :make_friend, :remove_friend], User
if user.moderator?
can :index, :change
can :index, :map
can :show, :permission
- can [:search_all, :search_nodes, :search_ways, :search_relations], :search
can :show, :version
if Settings.status != "database_offline"
can [:new, :create], Report
can [:create, :show, :update, :destroy, :data], Trace
can [:details, :gpx_files], User
- can [:read, :read_one, :update, :update_one, :delete_one], UserPreference
+ can [:index, :show, :update, :update_all, :destroy], UserPreference
if user.terms_agreed?
- can [:create, :update, :upload, :close, :subscribe, :unsubscribe, :expand_bbox], Changeset
+ can [:create, :update, :upload, :close, :subscribe, :unsubscribe], Changeset
can :create, ChangesetComment
can [:create, :update, :delete], Node
can [:create, :update, :delete], Way
can [:create, :update, :destroy], Trace if capability?(token, :allow_write_gpx)
can [:details], User if capability?(token, :allow_read_prefs)
can [:gpx_files], User if capability?(token, :allow_read_gpx)
- can [:read, :read_one], UserPreference if capability?(token, :allow_read_prefs)
- can [:update, :update_one, :delete_one], UserPreference if capability?(token, :allow_write_prefs)
+ can [:index, :show], UserPreference if capability?(token, :allow_read_prefs)
+ can [:update, :update_all, :destroy], UserPreference if capability?(token, :allow_write_prefs)
if token&.user&.terms_agreed?
- can [:create, :update, :upload, :close, :subscribe, :unsubscribe, :expand_bbox], Changeset if capability?(token, :allow_write_api)
+ can [:create, :update, :upload, :close, :subscribe, :unsubscribe], Changeset if capability?(token, :allow_write_api)
can :create, ChangesetComment if capability?(token, :allow_write_api)
can [:create, :update, :delete], Node if capability?(token, :allow_write_api)
can [:create, :update, :delete], Way if capability?(token, :allow_write_api)
--- /dev/null
+//= link browserconfig.xml
+//= link manifest.json
+
+//= link_tree ../favicons
+//= link_tree ../images
+//= link_tree ../javascripts .js
+//= link_tree ../opensearch .xml
+//= link_directory ../stylesheets .css
+
+//= link_tree ../../../vendor/assets/iD/iD/img
+//= link_directory ../../../vendor/assets/iD/iD/locales .json
+
+//= link_directory ../../../vendor/assets/javascripts .js
+
+//= link_tree ../../../vendor/assets/leaflet .png
+
+//= link_directory ../../../vendor/assets/polyfill .js
+
+//= link_directory ../../../vendor/assets/potlatch2/help
+//= link_tree ../../../vendor/assets/potlatch2 .swf
+//= link_tree ../../../vendor/assets/potlatch2 .zip
+
+//= link_directory ../../../vendor/assets/swfobject
//= require jquery.timers
//= require jquery.cookie
//= require jquery.throttle-debounce
-//= require bootstrap.tooltip
-//= require bootstrap.dropdown
+//= require popper
+//= require bootstrap-sprockets
//= require osm
//= require leaflet
//= require leaflet.osm
//= require index/changeset
//= require index/query
//= require router
-//= require bowser
//= require querystring
$(document).ready(function () {
iconLoading: "icon geolocate",
strings: {
title: I18n.t("javascripts.map.locate.title"),
+ metersUnit: I18n.t("javascripts.map.locate.metersUnit"),
+ feetUnit: I18n.t("javascripts.map.locate.feetUnit"),
popup: I18n.t("javascripts.map.locate.popup")
}
}).addTo(map);
bottom: bbox.getSouth() - 0.0001
};
- if (location.protocol === "http" ||
- bowser.check({ chrome: "53", firefox: "55" })) {
- url = "http://127.0.0.1:8111/load_and_zoom?";
- } else {
- url = "https://127.0.0.1:8112/load_and_zoom?";
- }
+ url = "http://127.0.0.1:8111/load_and_zoom?";
if (object) query.select = object.type + object.id;
$(".directions_form .reverse_directions").on("click", function () {
var from = endpoints[0].latlng,
- to = endpoints[1].latlng;
+ to = endpoints[1].latlng,
+ routeFrom = "",
+ routeTo = "";
+ if (from) {
+ routeFrom = from.lat + "," + from.lng;
+ }
+ if (to) {
+ routeTo = to.lat + "," + to.lng;
+ }
OSM.router.route("/directions?" + querystring.stringify({
from: $("#route_to").val(),
to: $("#route_from").val(),
- route: to.lat + "," + to.lng + ";" + from.lat + "," + from.lng
+ route: routeTo + ";" + routeFrom
}));
});
if (interestingFeature(element)) {
var $li = $("<li>")
- .addClass("query-result")
+ .addClass("query-result list-group-item")
.data("geometry", featureGeometry(element))
- .appendTo($ul);
- var $p = $("<p>")
.text(featurePrefix(element) + " ")
- .appendTo($li);
+ .appendTo($ul);
$("<a>")
.attr("href", "/" + element.type + "/" + element.id)
.text(featureName(element))
- .appendTo($p);
+ .appendTo($li);
}
}
if (results.remark) {
$("<li>")
+ .addClass("query-result list-group-item")
.text(I18n.t("javascripts.query.error", { server: url, error: results.remark }))
.appendTo($ul);
}
if ($ul.find("li").length === 0) {
$("<li>")
+ .addClass("query-result list-group-item")
.text(I18n.t("javascripts.query.nothing_found"))
.appendTo($ul);
}
$section.find(".loader").stopTime("loading").hide();
$("<li>")
+ .addClass("query-result list-group-item")
.text(I18n.t("javascripts.query." + status, { server: url, error: error }))
.appendTo($ul);
}
function queryOverpass(lat, lng) {
var latlng = L.latLng(lat, lng).wrap(),
bounds = map.getBounds().wrap(),
- bbox = bounds.getSouth() + "," + bounds.getWest() + "," + bounds.getNorth() + "," + bounds.getEast(),
+ precision = OSM.zoomPrecision(map.getZoom()),
+ bbox = bounds.getSouth().toFixed(precision) + "," +
+ bounds.getWest().toFixed(precision) + "," +
+ bounds.getNorth().toFixed(precision) + "," +
+ bounds.getEast().toFixed(precision),
radius = 10 * Math.pow(1.5, 19 - map.getZoom()),
around = "around:" + radius + "," + lat + "," + lng,
nodes = "node(" + around + ")",
$("#sidebar_content")
.on("click", ".search_more a", clickSearchMore)
.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 () {
+ .on("mouseover", "li.search_results_entry:has(a.set_position)", showSearchResult)
+ .on("mouseout", "li.search_results_entry:has(a.set_position)", hideSearchResult)
+ .on("mousedown", "li.search_results_entry:has(a.set_position)", function () {
var moved = false;
$(this).one("click", function (e) {
if (!moved && !$(e.target).is("a")) {
.attr("class", "section base-layers")
.appendTo($ui);
- var baseLayers = $("<ul>")
+ var baseLayers = $("<ul class='list-unstyled'>")
.appendTo(baseSection);
layers.forEach(function (layer) {
.attr("class", "deemphasize")
.appendTo(overlaySection);
- var overlays = $("<ul>")
+ var overlays = $("<ul class='list-unstyled'>")
.appendTo(overlaySection);
var addOverlay = function (layer, name, maxArea) {
.appendTo($linkSection);
$("<div>")
- .attr("class", "form-row")
+ .attr("class", "standard-form-row")
.appendTo($form)
.append(
$("<label>")
});
$("<div>")
- .attr("class", "form-row share-tab")
+ .attr("class", "standard-form-row share-tab")
.css("display", "block")
.appendTo($form)
.append($("<input>")
.on("click", select));
$("<div>")
- .attr("class", "form-row share-tab")
+ .attr("class", "standard-form-row share-tab")
.appendTo($form)
.append($("<input>")
.attr("id", "short_input")
.on("click", select));
$("<div>")
- .attr("class", "form-row share-tab")
+ .attr("class", "standard-form-row share-tab")
.appendTo($form)
.append(
$("<textarea>")
.appendTo($imageSection);
$("<div>")
- .attr("class", "form-row")
+ .attr("class", "standard-form-row")
.appendTo($form)
.append(
$("<label>")
.append(I18n.t("javascripts.share.custom_dimensions")));
$("<div>")
- .attr("class", "form-row")
+ .attr("class", "standard-form-row")
.appendTo($form)
.append(
$("<label>")
.append($("<option>").val("pdf").text("PDF")));
$("<div>")
- .attr("class", "form-row")
+ .attr("class", "standard-form-row")
.appendTo($form)
.append($("<label>")
.attr("for", "mapnik_scale")
iconLoading: "icon geolocate",
strings: {
title: I18n.t("javascripts.map.locate.title"),
+ metersUnit: I18n.t("javascripts.map.locate.metersUnit"),
+ feetUnit: I18n.t("javascripts.map.locate.feetUnit"),
popup: I18n.t("javascripts.map.locate.popup")
}
}).addTo(map);
--- /dev/null
+/*!
+ * Bootstrap v4.3.1 (https://getbootstrap.com/)
+ * Copyright 2011-2019 The Bootstrap Authors
+ * Copyright 2011-2019 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+@import "bootstrap/functions";
+@import "bootstrap/variables";
+@import "bootstrap/mixins";
+@import "bootstrap/root";
+@import "bootstrap/reboot";
+@import "bootstrap/type";
+// @import "bootstrap/images";
+// @import "bootstrap/code";
+@import "bootstrap/grid";
+// @import "bootstrap/tables";
+// @import "bootstrap/forms";
+@import "bootstrap/buttons";
+// @import "bootstrap/transitions";
+@import "bootstrap/dropdown";
+@import "bootstrap/button-group";
+// @import "bootstrap/input-group";
+// @import "bootstrap/custom-forms";
+@import "bootstrap/nav";
+@import "bootstrap/navbar";
+@import "bootstrap/card";
+// @import "bootstrap/breadcrumb";
+// @import "bootstrap/pagination";
+@import "bootstrap/badge";
+// @import "bootstrap/jumbotron";
+@import "bootstrap/alert";
+// @import "bootstrap/progress";
+// @import "bootstrap/media";
+@import "bootstrap/list-group";
+// @import "bootstrap/close";
+// @import "bootstrap/toasts";
+// @import "bootstrap/modal";
+@import "bootstrap/tooltip";
+// @import "bootstrap/popover";
+// @import "bootstrap/carousel";
+// @import "bootstrap/spinners";
+@import "bootstrap/utilities";
+// @import "bootstrap/print";
+++ /dev/null
-/* Rules for bootstrap tooltips */
-
-.tooltip {
- position: absolute;
- display: none;
- color: #333;
- text-align: left;
- font-size: 12px;
- max-width: 250px;
-}
-
-.tooltip.in {
- opacity: 0.8;
- z-index: 1030;
- height: auto;
- display: block;
-}
-
-.tooltip.top {
- margin-top: -10px;
- text-align: center;
-}
-
-.tooltip.right {
- margin-left: 10px;
-}
-
-.tooltip.bottom {
- margin-top: 10px;
- text-align: center;
-}
-
-.tooltip.left {
- margin-left: -10px;
- text-align: right;
-}
-
-.tooltip-inner {
- display: inline-block;
- padding: 10px;
- font-weight: normal;
- background-color: white;
-}
-
-.tooltip-arrow {
- position: absolute;
- width: 0;
- height: 0;
- border-color: transparent;
- border-style: solid;
-}
-
-.tooltip.top .tooltip-arrow {
- bottom: -5px;
- left: 50%;
- margin-left: -5px;
- border-top-color: white;
- border-width: 5px 5px 0;
-}
-
-.tooltip.right .tooltip-arrow {
- top: 50%;
- left: -5px;
- margin-top: -5px;
- border-right-color: white;
- border-width: 5px 5px 5px 0;
-}
-
-.tooltip.left .tooltip-arrow {
- top: 50%;
- right: -5px;
- margin-top: -5px;
- border-left-color: white;
- border-width: 5px 0 5px 5px;
-}
-
-.tooltip.bottom .tooltip-arrow {
- top: -5px;
- left: 50%;
- margin-left: -5px;
- border-bottom-color: white;
- border-width: 0 5px 5px;
-}
.shop.shoes::before { content: image-url('browse/shop_shoes.16.png'); }
.shop.supermarket::before { content: image-url('browse/shop_supermarket.p.16.png'); }
- .tourism.alpine_hut::before { content: image-url('browse/alpinehut.p.16.png'); }
+ .tourism.alpine_hut::before { content: image-url('browse/tourism_alpine_hut.16.png'); }
.tourism.camp_site::before { content: image-url('browse/tourism_camp_site.16.png'); }
.tourism.caravan_site::before { content: image-url('browse/tourism_caravan_site.16.png'); }
.tourism.hostel::before { content: image-url('browse/tourism_hostel.16.png'); }
.tourism.museum::before { content: image-url('browse/tourism_museum.16.png'); }
.tourism.picnic_site::before { content: image-url('browse/tourism_picnic_site.16.png'); }
.tourism.viewpoint::before { content: image-url('browse/view_point.p.16.png'); }
+ .tourism.wilderness_hut::before { content: image-url('browse/tourism_wilderness_hut.16.png'); }
/* Ways */
.landuse.brownfield::before { content: image-url('browse/brownfield.png'); }
.landuse.cemetery::before { content: image-url('browse/cemetery.png'); }
.landuse.commercial::before { content: image-url('browse/commercial.png'); }
- .landuse.farm::before { content: image-url('browse/farm.png'); }
+ .landuse.farmland::before { content: image-url('browse/farmland.png'); }
+ .landuse.farmyard::before { content: image-url('browse/farmyard.png'); }
.landuse.forest::before { content: image-url('browse/forest.png'); }
+ .landuse.grass::before { content: image-url('browse/grass.png'); }
.landuse.industrial::before { content: image-url('browse/industrial.png'); }
+ .landuse.meadow::before { content: image-url('browse/meadow.png'); }
.landuse.military::before { content: image-url('browse/military.png'); }
.landuse.residential::before { content: image-url('browse/residential.png'); }
.landuse.retail::before { content: image-url('browse/retail.png'); }
.landuse.tourism::before { content: image-url('browse/tourism.png'); }
- .landuse.wood::before { content: image-url('browse/wood.png'); }
.leisure.golf_course::before { content: image-url('browse/golf.png'); }
.leisure.park::before { content: image-url('browse/park.png'); }
.leisure.nature_reserve::before { content: image-url('browse/reserve.png'); }
.leisure.water_park::before { content: image-url('browse/leisure_water_park.16.png'); }
+ .natural.grassland::before { content: image-url('browse/grassland.png'); }
.natural.heath::before { content: image-url('browse/heathland.png'); }
+ .natural.scrub::before { content: image-url('browse/scrub.png'); }
.natural.water::before { content: image-url('browse/lake.png'); }
+ .natural.wood::before { content: image-url('browse/wood.png'); }
.railway.light_rail::before { content: image-url('browse/light_rail.20.png'); }
.railway.rail::before { content: image-url('browse/rail.20.png'); }
@import "parameters";
+@import "bootstrap-custom";
/* Styles common to large and small screens */
-/* Minimal CSS reset */
-
-html, body, ul, ol, li, form, fieldset, legend, h1, h2, h3, h4, h5, h6, p, input {
- margin: 0;
- padding: 0;
- border: 0;
- font-size:100%;
-}
-
-fieldset,img { border: 0; }
-
-legend { color: #000; }
-
-sup {
- vertical-align: super;
- font-size: smaller;
-}
-
-sub {
- vertical-align: sub;
- font-size: smaller;
-}
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-li { list-style: none; }
-
-input,
-select,
-textarea,
-body { font: #{$typeheight}/#{$lineheight} "Helvetica Neue",Arial,sans-serif; }
-
-abbr, acronym {
- text-decoration: underline dotted;
- cursor: help;
-}
-
-strong {
- font-weight: bold;
-}
-
-/* Micro Clearfix | Details: http://nicolasgallagher.com/micro-clearfix-hack/ */
-
-.clearfix:before,
-.clearfix:after {
- content: " ";
- display: table;
-}
-
-.clearfix:after {
- clear: both;
-}
-
-/* Basic grid */
-
-.col0 { float:left; width:04.1666%; }
-.col1 { float:left; width:08.3333%; }
-.col2 { float:left; width:16.6666%; }
-.col3 { float:left; width:25.0000%; }
-.col4 { float:left; width:33.3333%; }
-.col5 { float:left; width:41.6666%; }
-.col6 { float:left; width:50.0000%; }
-.col7 { float:left; width:58.3333%; }
-.col8 { float:left; width:66.6666%; }
-.col9 { float:left; width:75.0000%; }
-.col10 { float:left; width:83.3333%; }
-.col11 { float:left; width:91.6666%; }
-.col12 { width:100%; }
-
-.margin0 { margin-left:04.1666%; }
-.margin1 { margin-left:08.3333%; }
-.margin2 { margin-left:16.6666%; }
-.margin3 { margin-left:25.0000%; }
-.margin4 { margin-left:33.3333%; }
-.margin5 { margin-left:41.6666%; }
-.margin6 { margin-left:50.0000%; }
-.margin7 { margin-left:58.3333%; }
-.margin8 { margin-left:66.6666%; }
-.margin9 { margin-left:75.0000%; }
-.margin10 { margin-left:83.3333%; }
-.margin11 { margin-left:91.6666%; }
-.margin12 { margin-left:100.0000%; }
-
.fillL { background-color: white; }
/* Default rules for the body of every page */
-* {
- box-sizing: border-box;
-}
-
body {
font-family: 'Helvetica Neue',Arial,sans-serif;
font-size: $typeheight;
height: 100%;
}
-h1, h2, h3 {
- font-weight: 600;
- line-height: 1.2;
-}
-
-h4, h5 {
- font-weight: 500;
-}
-
-h1 {
- font-size: 18px;
-}
-
-h2, h3 {
- font-size: 16px;
-}
-
p > img {
width: auto;
max-width: 100%;
}
}
-/* Rules for horizontal lines */
-
-hr {
- border: none;
- background-color: #ccc;
- color: #ccc;
- height: 1px;
-}
-
/* General styles for tables */
table {
/* Utility for de-emphasizing content */
.deemphasize {
- color: #999;
+ color: $darkgrey;
a {
color: $blue;
}
z-index: 1001;
font-size: 14px;
- h1, nav, nav > ul, nav > ul > li, .dropdown {
+ h1, nav, nav > ul, nav > ul > li {
display: inline-block;
}
}
h1 {
+ font-size: 18px;
+ font-weight: 600;
+ line-height: 1.2;
margin: 0;
padding-top: 15px;
a {
color: #000;
}
- }
-}
-
-nav.primary {
- > ul {
- $border: 1px solid $green;
-
- border: $border;
- border-radius: $border-radius;
- > li {
- border-right: $border;
- float: left;
- &:last-child {
- border-right: 0;
- }
- > a:hover { background: lighten($green, 30%); }
- &.current > a:hover { background: $green; }
- &.disabled > a:hover { background: lighten($green, 38%); }
- &.dropdown {
- > a.tab { border-right: 1px solid lighten($green, 30%); }
- &.current > a.tab { border-right: 1px solid lighten($green, 10%); }
- }
+ a:hover {
+ color: #000;
}
}
- a.tab,
- .dropdown-toggle {
- display: inline-block;
- font-weight: 500;
- color: $green;
- padding: 5px 15px;
+ .btn {
+ font-size: 14px;
}
+}
- .dropdown-toggle {
- padding: 5px 6px;
- }
- .caret {
- border-top-color: $green;
- margin-top: 10px;
+nav.primary {
+ .btn-outline-primary {
+ @include button-outline-variant($green, $white);
}
- .disabled a {
- color: #ccc;
- cursor: default;
+ .disabled {
+ .btn-outline-primary {
+ color: $grey;
+ cursor: default;
+
+ .caret {
+ border-top-color: $grey;
+ }
- .caret {
- border-top-color: #ccc;
+ &:hover {
+ background-color: lighten($green, 30%);
+ }
}
}
- > ul li.current {
+ // Small tweaks to the toggle to stop the primary colour showing through
+ // when the menu is shown
+ .show > .btn-outline-primary.dropdown-toggle {
background-color: $green;
+ border-color: $green;
- .tab {
- color: #fff;
- }
-
- .caret {
- border-top-color: #fff;
+ &:focus {
+ box-shadow: 0 0 0 0.2rem fade-out($green, 0.5);
}
}
}
position: absolute;
right: 0;
- > ul {
- vertical-align: middle;
- a, .dropdown-toggle {
- display: inline-block;
- text-decoration: none;
- color: $darkgrey;
- padding: 5px;
-
- &:hover { color: darken($darkgrey, 25%); }
- }
+ .nav-link {
+ padding: 0.2rem;
+ color: $darkgrey;
}
> ul li.current a {
color: darken($darkgrey, 25%);
}
- .user-menu {
- $border: 1px solid $grey;
- border: $border;
- border-radius: $border-radius;
- margin-left: 10px;
-
- > li {
- border-right: $border;
- float: left;
- &:last-child {
- border-right: 0;
-
- > a {
- border-radius: 0 $border-radius $border-radius 0;
- }
- }
- &:first-child > a { border-radius: $border-radius 0 0 $border-radius; }
- &:hover a { background: lighten($darkgrey, 30%); }
+ .login-menu {
+ .btn-outline-secondary {
+ @include button-outline-variant($darkgrey);
}
+ }
- a {
- padding: 5px 15px;
-
+ .user-menu {
+ .btn-outline-secondary {
+ @include button-outline-variant($darkgrey, $darkgrey, white, $darkgrey);
+ border-color: $grey;
+ &:hover {
+ border-color: $grey;
+ }
+ &:focus {
+ background-color: white;
+ box-shadow: none;
+ }
}
-
- &.logged-in > a {
- padding: 0;
- > .user-button {
- line-height: 1.8;
- padding: 5px 10px 3px 6px;
- display: inline-block;
- color: $darkgrey;
+ &.show .btn-outline-secondary {
+ background-color: white;
+ &:focus {
+ box-shadow: none;
}
- &:hover > .user-button { color: darken($darkgrey, 5%); }
}
}
- .caret {
- border-top-color: $grey;
- margin-top: 9px;
- }
-
img.user_thumbnail_tiny {
border: 0;
- vertical-align: top;
- margin-top: 0px;
- margin: 4px 0 0 4px;
- border-radius: 2px;
+ border-radius: 3px;
}
#inboxanchor {
display: inline-block;
- vertical-align: top;
height: 25px;
margin: 3px 0 3px 3px;
background-color: lighten($grey, 10%);
line-height: 20px;
- border-radius: 2;
+ border-radius: 3;
}
.dropdown-menu {
- left: auto;
- right: -1px;
- border-radius: 3px 0 3px 3px;
-
.count-number {
- float: right;
- padding: 0 5px;
- margin: 0;
+ font-size: 14px;
+ }
+ }
+}
+
+nav.primary, nav.secondary {
+ .dropdown-item {
+ &:hover, &:active {
+ background-color: $green;
+ color: white;
}
}
}
#compact-secondary-nav {
display: none;
- ul li a {
- width: 100%;
- color: #333;
- &:hover { color: #fff; }
- }
}
body.compact {
}
&.active {
- background-color: #9ed485;
+ background-color: $vibrant-green;
}
.icon {
float: left;
width: $sidebarWidth;
background: #fff;
- font-size: 12px;
#sidebar_loader {
display: none;
h2 {
padding: $lineheight $lineheight $lineheight/2;
+ font-size: 1.5rem;
}
h3, h4 {
margin-top: $lineheight;
margin-bottom: $lineheight/2;
- font-size: 13px;
+ font-size: 1.25rem;
}
.close-wrap {
overflow: auto;
.section {
- border-bottom: 1px solid #DDD;
+ border-bottom: 1px solid $grey;
padding: 10px 20px;
}
font-size:20px;
line-height:10px;
color:#222;
- border:1px solid #ddd;
+ border:1px solid $grey;
}
.tooltip {
opacity: 1;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
.tooltip-arrow {
- border-top-color: #ccc;
+ border-top-color: $grey;
}
}
}
font-size: 13px;
margin-bottom: 8px;
}
- li.disabled { color: #999; }
+ li.disabled { color: $darkgrey; }
}
}
position: relative;
padding: $lineheight/2 $lineheight;
// background: $offwhite;
- // border-bottom: 1px solid #ccc;
+ // border-bottom: 1px solid $grey;
> .close {
float: right;
margin-top: 2px;
input:focus {
outline: none;
- box-shadow: 0px 0px 7px #9ED485;
+ box-shadow: 0px 0px 7px $vibrant-green;
}
input[type=submit].float {
#sidebar .search_results_entry {
ul li {
- border-bottom: $keyline;
cursor: pointer;
- &:first-child { border-top: $keyline; }
&.selected { background: $list-highlight; }
}
padding: 5px 20px 10px 15px;
width: 100%;
border-collapse: separate;
+ border-spacing: 0;
}
div.direction {
td.instruction, td.distance {
padding-top: $lineheight/5;
padding-bottom: $lineheight/5;
- border-bottom: 1px solid #DDD;
+ border-bottom: 1px solid $grey;
}
td.distance {
- color: #BBB;
+ color: $darkgrey;
text-align: right;
font-size: x-small;
}
#sidebar .changesets {
li {
- padding: 15px 20px;
- border-bottom: 1px solid #ddd;
cursor: pointer;
&.selected { background: $list-highlight; }
/* color is derived from changeset bbox fillColor in history.js */
}
- h4 {
- margin: 0;
- a {
- color: #000;
- }
- }
-
.comments {
float: right;
- color: #999;
+ color: $darkgrey;
}
.comments-0 {
#sidebar_content {
.browse-section {
padding: $lineheight/2 $lineheight;
- border-bottom: 1px solid #ddd;
+ border-bottom: 1px solid $grey;
h4:first-child {
margin-top: 0;
.paginate {
float: right;
padding: 1px 6px;
- border: 1px solid #eee;
+ border: 1px solid $lightgrey;
border-radius: 3px;
}
- .paginate ul {
- padding-left: 20px;
- }
-
.browse-field {
margin-bottom: 10px;
h4 {
padding: 5px 0 5px 10px;
font-size: 12px;
- border: 1px solid #CCC;
+ border: 1px solid $grey;
border-radius: 4px 4px 0 0;
- background-color: #F6F6F6;
+ background-color: $offwhite;
}
p {
padding: 7px 10px;
font-size: 12px;
background-color: #FFF;
- border: 1px solid #CCC;
+ border: 1px solid $grey;
border-top: 0;
border-radius: 0 0 4px 4px;
}
}
.browse-tag-list {
- background-color: #F6F6F6;
- border: 1px solid #ddd;
+ background-color: $offwhite;
+ border: 1px solid $grey;
border-radius: 3px;
- font-size: 12px;
table-layout: fixed;
border-collapse: separate;
+ border-spacing: 0;
th, td {
- border-bottom: 1px solid #ddd;
+ border-bottom: 1px solid $grey;
}
tr:last-child th, tr:last-child td {
.browse-tag-k {
font-weight: 500;
- background-color: #F6F6F6;
+ background-color: $offwhite;
}
.browse-tag-v {
- border-left: 1px solid #ddd;
+ border-left: 1px solid $grey;
background-color: #fff;
}
.colour-preview-box {
float: right;
- width: 12px;
- height: 12px;
+ width: 14px;
+ height: 14px;
margin: 4px 0px;
- border: 1px solid rgba(0, 0, 0, .1);
+ border: 1px solid rgba(0, 0, 0, .1);
// add color via inline css on element: background-color: <tag value>;
}
}
.query-results {
display: none;
+ padding-bottom: $lineheight/2;
h3 {
- padding: $lineheight $lineheight $lineheight/2;
- margin: 0;
+ padding: 0 $lineheight;
}
ul {
li {
- padding: 15px 20px;
- border-bottom: 1px solid #ddd;
-
&.query-result {
cursor: pointer;
}
}
.export_boxy {
- background: #eee;
- border: 1px solid #ccc;
+ background: $lightgrey;
+ border: 1px solid $grey;
border-radius: 3px;
#maxlat { margin-top: -1px; }
.content-heading {
background: $lightgrey;
-
- h1 { font-size: 22px; }
}
.content-body {
/* Overrides for pages that use new layout conventions */
-.users-new,
-.users-create,
-.users-terms {
- .content-body .content-inner {
- padding: 0;
-
- .message {
- margin-top: 80px;
- padding: 20px;
- }
- }
-}
-
.users-new,
.users-create,
.users-terms,
position: relative;
width: 45%;
height: 400px;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
margin-bottom: $lineheight;
float: right;
}
/* Rules for the trace list shown by the traces tab etc */
#trace_list {
- font-size: $lineheight/2;
border-width: 0px;
text-align: right;
font-size: 12px;
color: gray;
}
-
- .trace_pending {
- color: red;
- }
-
- .trace_public {
- color: green;
- }
-
- .trace_identifiable {
- color: green;
- }
-
- .trace_trackable {
- color: red;
- }
-
- .trace_private {
- color: red;
- }
-}
-
-/* Rules for the trace view */
-
-.trace-show {
- .trace_pending {
- color: red;
- }
-
- .geo {
- display: inline;
- }
}
/* Rules for the new trace form */
/* Rules for the edit trace form */
.edit_trace {
- .form-row p {
+ .standard-form-row p {
margin-bottom: 0px;
}
.activity-block {
clear: left;
- border-bottom: 1px solid #ccc;
+ border-bottom: 1px solid $grey;
padding-bottom: $lineheight;
float: left;
h3 {
margin-bottom: 0;
}
-#friends-container .contact-activity ul {
- margin-left: 70px;
-}
-
.users-show {
// Silly exception; remove when user page is redesigned.
.content-inner {
/* Rules for the user list */
#user_list {
- font-size: $lineheight/2;
width: 100%;
tr {
position: relative;
padding-top: $lineheight;
padding-bottom: $lineheight/2;
- border-top: 1px solid #ccc;
+ border-top: 1px solid $grey;
&:first-of-type {
margin-top: $lineheight/2;
h2 {
margin-top: 0;
margin-bottom: $lineheight/2;
- font-size: 24px;
}
}
position: relative;
width: 90%;
height: 400px;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
display: none;
margin-bottom: $lineheight;
}
#newcomment {
- border-top: 1px solid #ccc;
+ border-top: 1px solid $grey;
padding-top: $lineheight;
margin-top: $lineheight/2;
}
max-width: 740px;
}
.diary-comment {
- border-top: 1px dashed #ccc;
+ border-top: 1px dashed $grey;
padding-top: $lineheight/2;
padding-bottom: $lineheight/2;
&:first-child {
margin-top: $lineheight/2;
padding-top: $lineheight;
- border-top: 1px solid #ccc;
+ border-top: 1px solid $grey;
}
&.deemphasize {
background-color: #fee;
.users-terms {
.legale {
- border: 1px solid #ccc;
+ border: 1px solid $grey;
padding: $lineheight;
margin-bottom: $lineheight;
overflow: auto;
position: relative;
width: 500px;
height: 400px;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
}
#accountForm .user_image {
.messages {
width: 100%;
- border: 1px solid #ddd;
+ border: 1px solid $grey;
input[type="submit"] {
margin: auto;
}
tbody tr {
- border-top: 1px solid #ccc;
+ border-top: 1px solid $grey;
}
.inbox-row {
- background: #f8f8ff;
+ background: $offwhite;
}
.inbox-row-unread {
.info-line {
margin-bottom: $lineheight;
padding: $lineheight/4 0px 4px 0px;
- border-bottom: 1px solid #ccc;
+ border-bottom: 1px solid $grey;
form, form div {
display: inline;
margin-bottom: 0px;
padding: $lineheight/4;
}
-
- ul {
- padding-left: $lineheight;
-
- li {
- font-size: 12px;
- list-style: disc;
- }
- }
}
/* Rules for forms */
padding-top: $lineheight;
border-top: 1px solid $lightgrey;
}
- .horizontal-list .form-row {
+ .horizontal-list .standard-form-row {
float: left;
padding-right: 10px;
}
- .form-row {
+ .standard-form-row {
margin-bottom: $lineheight/2;
}
.form-list {
}
.form-list li {
margin-bottom: 5px;
- }
+ list-style-type: none;
+ }
input[type="checkbox"],
input[type="radio"] {
float: left;
textarea {
color: #222;
background-color: #fff;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
+ border-radius: 3px;
padding: 2px 5px;
margin: 0;
width: 200px;
textarea {
padding: 5px;
width: 100%;
+ min-height: 50px;
+ resize: vertical;
}
/* Rules for user images */
img.user_image {
max-width: 100px;
max-height: 100px;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
margin-bottom: $lineheight;
float: left;
margin-right: $lineheight;
img.user_thumbnail {
max-width: 50px;
max-height: 50px;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
margin-right: $lineheight;
}
height: auto;
max-width: 25px;
max-height: 25px;
- border: 1px solid #ccc;
+ border: 1px solid $grey;
}
/* Rules for geo microformats */
border-bottom: none;
}
-/* Rules for RSS buttons */
-
-.rsssmall {
- position: relative;
- top: 3px;
-}
-
/* General styles for action lists / subnavs / pager navs */
ul.secondary-actions {
font-style: normal;
margin-bottom: 0;
margin-left: 0;
+ padding: 0;
&.pager {
display: inline-block;
margin-right: 60px;
display: block;
float: left;
list-style: none;
- border-left: 1px solid #ccc;
+ border-left: 1px solid $grey;
padding-left: $lineheight/2;
margin-right: $lineheight/2;
&:first-child {
.richtext,
.prose {
- h1, h2 {
- padding-bottom: $lineheight/2;
- border-bottom: 1px dashed #cccccc;
- margin-bottom: $lineheight/2;
- }
-
- h1 {
- font-size: 24px;
- }
-
- h2 {
- font-size: 18px;
- }
-
- h3 {
- font-size: $typeheight;
- }
-
code {
font-size: 13px;
- background: #e8e8e8;
+ background: $lightgrey;
padding: 2px 3px;
}
pre {
font-size: 13px;
- background: #e8e8e8;
+ background: $lightgrey;
padding: 2px 3px;
white-space: pre-wrap;
border-left: $lineheight solid $offwhite;
padding-left: $lineheight;
margin: 0;
- color: #7E7E7E;
- }
-
- ul, ol {
- padding-left: $lineheight;
- margin-bottom: $lineheight;
- margin-left: $lineheight;
- }
-
- ul > li {
- list-style: disc;
- }
-
- ol > li {
- list-style: decimal;
+ color: $darkgrey;
}
}
display: inline-block;
vertical-align: top;
margin-left: 15px;
- background-color: #f8f8ff;
+ background-color: $offwhite;
padding: $lineheight/2;
width: 220px;
}
h4.heading, li {
- border-bottom: 1px solid #ccc;
+ border-bottom: 1px solid $grey;
margin-bottom: $lineheight/4;
padding-bottom: $lineheight/4;
}
.note_list {
tr.creator {
- background-color: #eeeeee;
+ background-color: $lightgrey;
}
td {
height: 100%;
}
-/* Rules for dropdown menus */
-
-.dropdown {
- position: relative;
-}
-
-.dropdown-toggle {
- *margin-bottom: -3px;
-}
-
-.dropdown-toggle:active,
-.open .dropdown-toggle {
- outline: 0;
-}
-
-.caret {
- display: inline-block;
- width: 0;
- height: 0;
- vertical-align: top;
- border-top: 4px solid #000000;
- border-right: 4px solid transparent;
- border-left: 4px solid transparent;
- content: "";
-}
-
-.dropdown .caret {
- margin-top: 8px;
- margin-left: 2px;
-}
-
-.dropdown-menu {
- position: absolute;
- top: 100%;
- left: -1px;
- z-index: 1000;
- display: none;
- float: left;
- min-width: 160px;
- padding: 5px 0;
- margin: 0;
- list-style: none;
- background-color: #ffffff;
- border: 1px solid #ccc;
- border-radius: 0 3px 3px;
- *border-right-width: 2px;
- *border-bottom-width: 2px;
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- background-clip: padding-box;
-}
-
-.dropdown-menu.pull-right {
- right: 0;
- left: auto;
-}
-
-.dropdown-menu .divider {
- *width: 100%;
- height: 1px;
- margin: 9px 1px;
- *margin: -5px 0 5px;
- overflow: hidden;
- background-color: #e5e5e5;
- border-bottom: 1px solid #ffffff;
-}
-
-.dropdown-menu > li > a {
- display: block;
- padding: 3px 10px;
- clear: both;
- font-weight: normal;
- line-height: 20px;
- color: #333333;
- white-space: nowrap;
-}
-
-.dropdown-menu > li > a:hover,
-.dropdown-menu > li > a:focus,
-.dropdown-submenu:hover > a,
-.dropdown-submenu:focus > a {
- color: #ffffff;
- text-decoration: none;
- background-color: $green;
-}
-
-.dropdown-menu > .active > a,
-.dropdown-menu > .active > a:hover,
-.dropdown-menu > .active > a:focus {
- color: #ffffff;
- text-decoration: none;
- background-color: $green;
- outline: 0;
-}
-
-.dropdown-menu > .disabled > a,
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
- color: #999999;
-}
-
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
- text-decoration: none;
- cursor: default;
- background-color: transparent;
- background-image: none;
-}
-
-.open {
- *z-index: 1000;
-}
-
-.open > .dropdown-menu {
- display: block;
-}
-
-.dropdown-backdrop {
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: 990;
-}
-
/* Rules for the "Welcome" page */
.site-welcome, .site-fixthemap {
.center {
text-decoration: none;
}
- .note-box {
- margin-top: 20px;
- background-color: $offwhite;
- }
-
.icon.note {
background-color: #333;
border-radius: 4px;
}
.site-about #content {
- //background-color: #000;
- background-color: #eee;
+ background-color: $lightgrey;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: cover;
background-attachment: fixed;
- .caption {
- max-width: 200px;
- font: 13px/20px Helvetica, Arial, sans-serif;
- position: fixed;
- text-align: right;
- right: 20px;
- bottom: 60px;
- text-shadow: #000 0px 1px 5px;
- color: #eee;
- opacity: 0.8;
- display: none;
- }
-
- .caption a {
- color: white;
- white-space: nowrap;
- text-decoration: none;
- }
-
- a.next {
- display: block;
- position: fixed;
- right: 10px;
- bottom: 10px;
- width: 40px;
- height: 40px;
- border-radius: 5px;
- text-indent: -9999px;
- overflow: hidden;
- background: image-url('about/sprite.png') -120px 0px no-repeat;
- background-color: #000;
- background-color: rgba(0, 0, 0, 0.5);
- }
.content-inner {
position: relative;
color: #333;
min-width: 320px;
max-width: 640px;
-
- .section {
- margin-bottom: 30px;
- }
-
- .section:last-child {
- margin-bottom: 0;
- }
}
.text {
font-weight: 300;
font-size: 34px;
span {
- color: #76c551;
+ color: $vibrant-green;
}
}
background-repeat: no-repeat;
background-image: image-url('about/osm.png');
background-size: cover;
- background-color: #76c551;
+ background-color: $vibrant-green;
}
.byosm {
font: 500 20px/24px Helvetica, Arial, sans-serif;
white-space: nowrap;
color: #fff;
- background: #76c551;
+ background: $vibrant-green;
}
.byosm span {
}
}
- h2 {
- margin-bottom: 10px;
- }
-
.icon {
width: 30px;
height: 30px;
}
.read-reports {
- background: #eee;
+ background: $lightgrey;
opacity: 0.7;
}
-.report-related-block {
- display:inline-block;
-}
-
-.report-block {
- width:475px;
- float:left;
- margin-right:100px;
-}
-
-.related-reports {
- width: 280px;
- float: right;
-
- ul {
- padding-left: $lineheight;
- margin-bottom: 0;
-
- li {
- list-style: disc;
- }
- }
-}
-
-.issue-comments {
- width:475px;
-}
-
.issues-list {
td:nth-child(2) {
white-space: nowrap;
}
}
-
-.report-disclaimer {
- background: #fff1f0;
- color: #d85030;
- border-color: rgba(216, 80, 48, 0.3);
- padding: 10px 20px;
- margin-bottom: $lineheight;
-
- ul {
- padding-left: $lineheight;
- margin-bottom: 0;
-
- li {
- list-style: disc;
- }
- }
-}
$lineheight: 20px;
$typeheight: 14px;
-$offwhite: #f4f4ff;
+$offwhite: #f8f8ff;
$blue: #7092FF;
$lightblue: #B8C5F0;
$green: #7ebc6f;
+$vibrant-green: #76c551;
$grey: #CCC;
$red: red;
$lightgrey: #EEE;
/*
*= require ltr/common
- *= require bootstrap
*= require ltr/small
*/
/*
*= require rtl/common
- *= require bootstrap
*= require rtl/small
*/
}
}
}
+
+ .btn-group {
+ width: 100%;
+ padding: 10px;
+ }
}
nav.secondary {
- border-bottom: 1px solid #eee;
-
.user-menu {
- display: block;
width: 100%;
- margin-left: 0;
- > li {
- width: 49%;
- > a {
- width: 100%;
- text-align: center;
- }
- }
}
}
top: auto;
}
- /* Rules for the sign-up page */
-
- &.user-new,
- &.user-create {
- .col6 {
- width: 100%;
- }
-
- .aside {
- display: none;
- }
- }
-
&.site-about #content .attr h1 {
font-size: 28px;
}
loaded_lang = "en"
# Load English defaults
- en = YAML.safe_load(File.open(Rails.root.join("config", "potlatch", "locales", "en.yml")))["en"]
+ en = YAML.safe_load(File.open(Rails.root.join("config/potlatch/locales/en.yml")))["en"]
if lang == "en"
- return [loaded_lang, en]
+ [loaded_lang, en]
else
# Use English as a fallback
begin
- other = YAML.safe_load(File.open(Rails.root.join("config", "potlatch", "locales", "#{lang}.yml")))[lang]
+ other = YAML.safe_load(File.open(Rails.root.join("config/potlatch/locales/#{lang}.yml")))[lang]
loaded_lang = lang
rescue StandardError
other = en
# We have to return a flat list and some of the keys won't be
# translated (probably)
- return [loaded_lang, en.merge(other)]
+ [loaded_lang, en.merge(other)]
end
end
end
def getlocales
- @getlocales ||= Locale.list(Dir.glob(Rails.root.join("config", "potlatch", "locales", "*")).collect { |f| File.basename(f, ".yml") })
+ @getlocales ||= Locale.list(Dir.glob(Rails.root.join("config/potlatch/locales/*")).collect { |f| File.basename(f, ".yml") })
end
##
# Alternative SQL queries for getway/whichways
def sql_find_ways_in_area(bbox)
- sql = <<-SQL
- SELECT DISTINCT current_ways.id AS wayid,current_ways.version AS version
- FROM current_way_nodes
- INNER JOIN current_nodes ON current_nodes.id=current_way_nodes.node_id
- INNER JOIN current_ways ON current_ways.id =current_way_nodes.id
- WHERE current_nodes.visible=TRUE
- AND current_ways.visible=TRUE
- AND #{OSM.sql_for_area(bbox, 'current_nodes.')}
+ sql = <<~SQL
+ SELECT DISTINCT current_ways.id AS wayid,current_ways.version AS version
+ FROM current_way_nodes
+ INNER JOIN current_nodes ON current_nodes.id=current_way_nodes.node_id
+ INNER JOIN current_ways ON current_ways.id =current_way_nodes.id
+ WHERE current_nodes.visible=TRUE
+ AND current_ways.visible=TRUE
+ AND #{OSM.sql_for_area(bbox, 'current_nodes.')}
SQL
ActiveRecord::Base.connection.select_all(sql).collect { |a| [a["wayid"].to_i, a["version"].to_i] }
end
def sql_find_pois_in_area(bbox)
pois = []
- sql = <<-SQL
+ sql = <<~SQL
SELECT current_nodes.id,current_nodes.latitude*0.0000001 AS lat,current_nodes.longitude*0.0000001 AS lon,current_nodes.version
FROM current_nodes
LEFT OUTER JOIN current_way_nodes cwn ON cwn.node_id=current_nodes.id
def sql_find_relations_in_area_and_ways(bbox, way_ids)
# ** It would be more Potlatchy to get relations for nodes within ways
# during 'getway', not here
- sql = <<-SQL
+ sql = <<~SQL
SELECT DISTINCT cr.id AS relid,cr.version AS version
FROM current_relations cr
INNER JOIN current_relation_members crm ON crm.id=cr.id
WHERE #{OSM.sql_for_area(bbox, 'cn.')}
SQL
unless way_ids.empty?
- sql += <<-SQL
- UNION
- SELECT DISTINCT cr.id AS relid,cr.version AS version
- FROM current_relations cr
- INNER JOIN current_relation_members crm ON crm.id=cr.id
- WHERE crm.member_type='Way'
- AND crm.member_id IN (#{way_ids.join(',')})
+ sql += <<~SQL
+ UNION
+ SELECT DISTINCT cr.id AS relid,cr.version AS version
+ FROM current_relations cr
+ INNER JOIN current_relation_members crm ON crm.id=cr.id
+ WHERE crm.member_type='Way'
+ AND crm.member_id IN (#{way_ids.join(',')})
SQL
end
ActiveRecord::Base.connection.select_all(sql).collect { |a| [a["relid"].to_i, a["version"].to_i] }
def sql_get_nodes_in_way(wayid)
points = []
- sql = <<-SQL
+ sql = <<~SQL
SELECT latitude*0.0000001 AS lat,longitude*0.0000001 AS lon,current_nodes.id,current_nodes.version
FROM current_way_nodes,current_nodes
WHERE current_way_nodes.id=#{wayid.to_i}
head :ok
end
- ##
- # insert a (set of) points into a changeset bounding box. this can only
- # increase the size of the bounding box. this is a hint that clients can
- # set either before uploading a large number of changes, or changes that
- # the client (but not the server) knows will affect areas further away.
- def expand_bbox
- # only allow POST requests, because although this method is
- # idempotent, there is no "document" to PUT really...
- assert_method :post
-
- cs = Changeset.find(params[:id])
- check_changeset_consistency(cs, current_user)
-
- # keep an array of lons and lats
- lon = []
- lat = []
-
- # the request is in pseudo-osm format... this is kind-of an
- # abuse, maybe should change to some other format?
- doc = XML::Parser.string(request.raw_post, :options => XML::Parser::Options::NOERROR).parse
- doc.find("//osm/node").each do |n|
- lon << n["lon"].to_f * GeoRecord::SCALE
- lat << n["lat"].to_f * GeoRecord::SCALE
- end
-
- # add the existing bounding box to the lon-lat array
- lon << cs.min_lon unless cs.min_lon.nil?
- lat << cs.min_lat unless cs.min_lat.nil?
- lon << cs.max_lon unless cs.max_lon.nil?
- lat << cs.max_lat unless cs.max_lat.nil?
-
- # collapse the arrays to minimum and maximum
- cs.min_lon = lon.min.round
- cs.min_lat = lat.min.round
- cs.max_lon = lon.max.round
- cs.max_lat = lat.max.round
-
- # save the larger bounding box and return the changeset, which
- # will include the bigger bounding box.
- cs.save!
- @changeset = cs
- render "changeset"
- end
-
##
# Upload a diff in a single transaction.
#
+++ /dev/null
-module Api
- class SearchController < ApiController
- # Support searching for nodes, ways, or all
- # Can search by tag k, v, or both (type->k,value->v)
- # Can search by name (k=name,v=....)
- authorize_resource :class => false
-
- def search_all
- do_search(true, true, true)
- end
-
- def search_ways
- do_search(true, false, false)
- end
-
- def search_nodes
- do_search(false, true, false)
- end
-
- def search_relations
- do_search(false, false, true)
- end
-
- def do_search(do_ways, do_nodes, do_relations)
- type = params["type"]
- value = params["value"]
- unless type || value
- name = params["name"]
- if name
- type = "name"
- value = name
- end
- end
-
- if do_nodes
- response.headers["Error"] = "Searching of nodes is currently unavailable"
- head :service_unavailable
- return false
- end
-
- unless value
- response.headers["Error"] = "Searching for a key without value is currently unavailable"
- head :service_unavailable
- return false
- end
-
- # Matching for node tags table
- if do_nodes
- nodes = Node.joins(:node_tags)
- nodes = nodes.where(:current_node_tags => { :k => type }) if type
- nodes = nodes.where(:current_node_tags => { :v => value }) if value
- nodes = nodes.limit(100)
- else
- nodes = []
- end
-
- # Matching for way tags table
- if do_ways
- ways = Way.joins(:way_tags)
- ways = ways.where(:current_way_tags => { :k => type }) if type
- ways = ways.where(:current_way_tags => { :v => value }) if value
- ways = ways.limit(100)
- else
- ways = []
- end
-
- # Matching for relation tags table
- if do_relations
- relations = Relation.joins(:relation_tags)
- relations = relations.where(:current_relation_tags => { :k => type }) if type
- relations = relations.where(:current_relation_tags => { :v => value }) if value
- relations = relations.limit(2000)
- else
- relations = []
- end
-
- # Fetch any node needed for our ways (only have matching nodes so far)
- nodes += Node.find(ways.collect(&:nds).uniq)
-
- # Print
- visible_nodes = {}
- changeset_cache = {}
- user_display_name_cache = {}
- doc = OSM::API.new.get_xml_doc
- nodes.each do |node|
- doc.root << node.to_xml_node(changeset_cache, user_display_name_cache)
- visible_nodes[node.id] = node
- end
-
- ways.each do |way|
- doc.root << way.to_xml_node(visible_nodes, changeset_cache, user_display_name_cache)
- end
-
- relations.each do |rel|
- doc.root << rel.to_xml_node(changeset_cache, user_display_name_cache)
- end
-
- render :xml => doc.to_s
- end
- end
-end
##
# return all the preferences as an XML document
- def read
- doc = OSM::API.new.get_xml_doc
+ def index
+ @user_preferences = current_user.preferences
- prefs = current_user.preferences
-
- el1 = XML::Node.new "preferences"
-
- prefs.each do |pref|
- el1 << pref.to_xml_node
- end
-
- doc.root << el1
- render :xml => doc.to_s
+ render :formats => [:xml]
end
##
# return the value for a single preference
- def read_one
+ def show
pref = UserPreference.find([current_user.id, params[:preference_key]])
render :plain => pref.v.to_s
end
# update the entire set of preferences
- def update
+ def update_all
old_preferences = current_user.preferences.each_with_object({}) do |preference, preferences|
preferences[preference.k] = preference
end
##
# update the value of a single preference
- def update_one
+ def update
begin
pref = UserPreference.find([current_user.id, params[:preference_key]])
rescue ActiveRecord::RecordNotFound
##
# delete a single preference
- def delete_one
+ def destroy
UserPreference.find([current_user.id, params[:preference_key]]).delete
render :plain => ""
# no auth, the user does not exist or the password was wrong
response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
render :plain => errormessage, :status => :unauthorized
- return false
+ false
end
end
@page = (params[:page] || 1).to_i
@page_size = 20
- @entries = @entries.visible unless current_user&.administrator?
+ @entries = @entries.visible unless can? :unhide, DiaryEntry
@entries = @entries.order("created_at DESC")
@entries = @entries.offset((@page - 1) * @page_size)
@entries = @entries.limit(@page_size)
@entry = @user.diary_entries.visible.where(:id => params[:id]).first
if @entry
@title = t "diary_entries.show.title", :user => params[:display_name], :title => @entry.title
- @comments = current_user&.administrator? ? @entry.comments : @entry.visible_comments
+ @comments = can?(:unhidecomment, DiaryEntry) ? @entry.comments : @entry.visible_comments
else
@title = t "diary_entries.no_such_entry.title", :id => params[:id]
render :action => "no_such_entry", :status => :not_found
end
def comments
+ conditions = { :user_id => @user }
+
+ conditions[:visible] = true unless can? :unhidecomment, DiaryEntry
+
@comment_pages, @comments = paginate(:diary_comments,
- :conditions => {
- :user_id => @user,
- :visible => true
- },
+ :conditions => conditions,
:order => "created_at DESC",
:per_page => 20)
@page = (params[:page] || 1).to_i
end
end
- def embed; end
+ def embed
+ append_content_security_policy_directives(
+ :frame_ancestors => %w[*]
+ )
+ end
end
)
end
- if params[:node]
- bbox = Node.find(params[:node]).bbox.to_unscaled
- @lat = bbox.centre_lat
- @lon = bbox.centre_lon
- @zoom = 18
- elsif params[:way]
- bbox = Way.find(params[:way]).bbox.to_unscaled
- @lat = bbox.centre_lat
- @lon = bbox.centre_lon
- @zoom = 17
- elsif params[:note]
- note = Note.find(params[:note])
- @lat = note.lat
- @lon = note.lon
- @zoom = 17
- elsif params[:gpx] && current_user
- trace = Trace.visible_to(current_user).find(params[:gpx])
- @lat = trace.latitude
- @lon = trace.longitude
- @zoom = 16
+ begin
+ if params[:node]
+ bbox = Node.visible.find(params[:node]).bbox.to_unscaled
+ @lat = bbox.centre_lat
+ @lon = bbox.centre_lon
+ @zoom = 18
+ elsif params[:way]
+ bbox = Way.visible.find(params[:way]).bbox.to_unscaled
+ @lat = bbox.centre_lat
+ @lon = bbox.centre_lon
+ @zoom = 17
+ elsif params[:note]
+ note = Note.visible.find(params[:note])
+ @lat = note.lat
+ @lon = note.lon
+ @zoom = 17
+ elsif params[:gpx] && current_user
+ trace = Trace.visible_to(current_user).find(params[:gpx])
+ @lat = trace.latitude
+ @lon = trace.longitude
+ @zoom = 16
+ end
+ rescue ActiveRecord::RecordNotFound
+ # don't try and derive a location from a missing/deleted object
end
end
def help; end
- def about; end
+ def about
+ @locale = params[:about_locale] || I18n.locale
+ end
def export; end
authorize_resource
- before_action :check_database_writable, :only => [:new, :create, :edit, :delete]
+ before_action :check_database_writable, :only => [:new, :create, :edit, :destroy]
before_action :offline_warning, :only => [:mine, :show]
- before_action :offline_redirect, :only => [:new, :create, :edit, :delete, :data]
+ before_action :offline_redirect, :only => [:new, :create, :edit, :destroy, :data]
# Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
# target_user - if set, specifies the user to fetch traces for. if not set will fetch all traces
@traces = @traces.limit(@page_size)
@traces = @traces.includes(:user, :tags)
- # put together SET of tags across traces, for related links
- tagset = {}
- @traces.each do |trace|
- trace.tags.reload if params[:tag] # if searched by tag, ActiveRecord won't bring back other tags, so do explicitly here
- trace.tags.each do |tag|
- tagset[tag.tag] = tag.tag
- end
- end
-
# final helper vars for view
@target_user = target_user
@display_name = target_user.display_name if target_user
- @all_tags = tagset.values
end
def mine
head :not_found
end
- def delete
+ def destroy
trace = Trace.find(params[:id])
if !trace.visible?
def logout
@title = t "users.logout.title"
- if params[:session] == session.id
+ if request.post?
if session[:token]
token = UserToken.find_by(:token => session[:token])
token&.destroy
@user = User.find_by(:display_name => params[:display_name])
if @user &&
- (@user.visible? || (current_user&.administrator?))
+ (@user.visible? || current_user&.administrator?)
@title = @user.display_name
else
render_unknown_user params[:display_name]
link_to(w[:title], w[:url], :title => t("browse.tag_details.wikidata_link", :page => w[:title].strip))
end
safe_join(wdt, ";")
+ elsif wmc = wikimedia_commons_link(key, value)
+ link_to h(wmc[:title]), wmc[:url], :title => t("browse.tag_details.wikimedia_commons_link", :page => wmc[: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 phones = telephone_links(key, value)
nil
end
+ def wikimedia_commons_link(key, value)
+ if key == "wikimedia_commons" && value =~ /^(?:file|category):/i
+ return {
+ :url => "//commons.wikimedia.org/wiki/#{value}?uselang=#{I18n.locale}",
+ :title => value
+ }
+ end
+ nil
+ end
+
def telephone_links(_key, value)
# Does it look like a global phone number? eg "+1 (234) 567-8901 "
# or a list of alternate numbers separated by ;
--- /dev/null
+class ApplicationMailer < ActionMailer::Base
+end
-class Notifier < ActionMailer::Base
+class Notifier < ApplicationMailer
include ActionView::Helpers::AssetUrlHelper
+ self.delivery_job = ActionMailer::MailDeliveryJob
+
default :from => Settings.email_from,
:return_path => Settings.email_return_path,
:auto_submitted => "auto-generated"
@readurl = diary_entry_url(comment.diary_entry.user, comment.diary_entry, :anchor => "comment#{comment.id}")
@commenturl = diary_entry_url(comment.diary_entry.user, comment.diary_entry, :anchor => "newcomment")
@replyurl = new_message_url(comment.user, :message => { :title => "Re: #{comment.diary_entry.title}" })
-
@author = @from_user
attach_user_avatar(comment.user)
+ set_references("diary", comment.diary_entry)
+
mail :from => from_address(comment.user.display_name, "c", comment.id, comment.digest, recipient.id),
:to => recipient.email,
:subject => I18n.t("notifier.diary_comment_notification.subject", :user => comment.user.display_name)
@author = @commenter
attach_user_avatar(comment.author)
+ set_references("note", comment.note)
+
subject = if @owner
I18n.t("notifier.note_comment_notification.#{@event}.subject_own", :commenter => @commenter)
else
attach_user_avatar(comment.author)
+ set_references("changeset", comment.changeset)
+
mail :to => recipient.email, :subject => subject
end
end
end
def attach_project_logo
- attachments.inline["logo.png"] = File.read(Rails.root.join("app", "assets", "images", "osm_logo_30.png"))
+ attachments.inline["logo.png"] = File.read(Rails.root.join("app/assets/images/osm_logo_30.png"))
end
def attach_user_avatar(user)
def user_avatar_file(user)
avatar = user&.avatar
if avatar&.attached?
- return avatar.variant(:resize => "50x50>").blob.download
+ avatar.variant(:resize => "50x50>").blob.download
else
- return File.read(Rails.root.join("app", "assets", "images", "avatar_small.png"))
+ File.read(Rails.root.join("app/assets/images/avatar_small.png"))
end
end
Settings.email_from
end
end
+
+ def set_references(scope, reference_object)
+ ref = "osm-#{scope}-#{reference_object.id}@#{Settings.server_url}"
+
+ headers["X-Entity-Ref-ID"] = ref
+ headers["In-Reply-To"] = ref
+ headers["References"] = ref
+ end
end
# index_acls_on_mx (mx)
#
-class Acl < ActiveRecord::Base
+class Acl < ApplicationRecord
validates :k, :presence => true
def self.match(address, options = {})
--- /dev/null
+class ApplicationRecord < ActiveRecord::Base
+ self.abstract_class = true
+end
# changesets_user_id_fkey (user_id => users.id)
#
-class Changeset < ActiveRecord::Base
+class Changeset < ApplicationRecord
require "xml/libxml"
belongs_to :user, :counter_cache => true
# changeset_comments_changeset_id_fkey (changeset_id => changesets.id)
#
-class ChangesetComment < ActiveRecord::Base
+class ChangesetComment < ApplicationRecord
belongs_to :changeset
belongs_to :author, :class_name => "User"
# changeset_tags_id_fkey (changeset_id => changesets.id)
#
-class ChangesetTag < ActiveRecord::Base
+class ChangesetTag < ApplicationRecord
self.primary_keys = "changeset_id", "k"
belongs_to :changeset
# client_applications_user_id_fkey (user_id => users.id)
#
-class ClientApplication < ActiveRecord::Base
+class ClientApplication < ApplicationRecord
belongs_to :user
has_many :tokens, :class_name => "OauthToken", :dependent => :delete_all
has_many :access_tokens
# diary_comments_user_id_fkey (user_id => users.id)
#
-class DiaryComment < ActiveRecord::Base
+class DiaryComment < ApplicationRecord
belongs_to :user
belongs_to :diary_entry
# diary_entries_user_id_fkey (user_id => users.id)
#
-class DiaryEntry < ActiveRecord::Base
+class DiaryEntry < ApplicationRecord
belongs_to :user, :counter_cache => true
belongs_to :language, :foreign_key => "language_code"
# diary_entry_subscriptions_user_id_fkey (user_id => users.id)
#
-class DiaryEntrySubscription < ActiveRecord::Base
+class DiaryEntrySubscription < ApplicationRecord
self.primary_keys = "user_id", "diary_entry_id"
belongs_to :user
# friends_user_id_fkey (user_id => users.id)
#
-class Friendship < ActiveRecord::Base
+class Friendship < ApplicationRecord
self.table_name = "friends"
belongs_to :befriender, :class_name => "User", :foreign_key => :user_id
# issues_updated_by_fkey (updated_by => users.id)
#
-class Issue < ActiveRecord::Base
+class Issue < ApplicationRecord
belongs_to :reportable, :polymorphic => true
belongs_to :reported_user, :class_name => "User", :foreign_key => :reported_user_id
belongs_to :user_resolved, :class_name => "User", :foreign_key => :resolved_by
# issue_comments_user_id_fkey (user_id => users.id)
#
-class IssueComment < ActiveRecord::Base
+class IssueComment < ApplicationRecord
belongs_to :issue
belongs_to :user
# native_name :string
#
-class Language < ActiveRecord::Base
+class Language < ApplicationRecord
self.primary_key = "code"
has_many :diary_entries, :foreign_key => "language"
# messages_to_user_id_fkey (to_user_id => users.id)
#
-class Message < ActiveRecord::Base
+class Message < ApplicationRecord
belongs_to :sender, :class_name => "User", :foreign_key => :from_user_id
belongs_to :recipient, :class_name => "User", :foreign_key => :to_user_id
# current_nodes_changeset_id_fkey (changeset_id => changesets.id)
#
-class Node < ActiveRecord::Base
+class Node < ApplicationRecord
require "xml/libxml"
include GeoRecord
save_with_history!
end
- def to_xml
- doc = OSM::API.new.get_xml_doc
- doc.root << to_xml_node
- doc
- end
-
- def to_xml_node(changeset_cache = {}, user_display_name_cache = {})
- el = XML::Node.new "node"
- el["id"] = id.to_s
-
- add_metadata_to_xml_node(el, self, changeset_cache, user_display_name_cache)
-
- if visible?
- el["lat"] = lat.to_s
- el["lon"] = lon.to_s
- end
-
- add_tags_to_xml_node(el, node_tags)
-
- el
- end
-
def tags_as_hash
tags
end
# current_node_tags_id_fkey (node_id => current_nodes.id)
#
-class NodeTag < ActiveRecord::Base
+class NodeTag < ApplicationRecord
self.table_name = "current_node_tags"
self.primary_keys = "node_id", "k"
# notes_updated_at_idx (updated_at)
#
-class Note < ActiveRecord::Base
+class Note < ApplicationRecord
include GeoRecord
has_many :comments, -> { left_joins(:author).where(:visible => true, :users => { :status => [nil, "active", "confirmed"] }).order(:created_at) }, :class_name => "NoteComment", :foreign_key => :note_id
# note_comments_note_id_fkey (note_id => notes.id)
#
-class NoteComment < ActiveRecord::Base
+class NoteComment < ApplicationRecord
belongs_to :note, :foreign_key => :note_id, :touch => true
belongs_to :author, :class_name => "User", :foreign_key => :author_id
# Simple store of nonces. The OAuth Spec requires that any given pair of nonce and timestamps are unique.
# Thus you can use the same nonce with a different timestamp and viceversa.
-class OauthNonce < ActiveRecord::Base
+class OauthNonce < ApplicationRecord
validates :timestamp, :presence => true
validates :nonce, :presence => true, :uniqueness => { :scope => :timestamp }
# oauth_tokens_user_id_fkey (user_id => users.id)
#
-class OauthToken < ActiveRecord::Base
+class OauthToken < ApplicationRecord
belongs_to :client_application
belongs_to :user
# nodes_redaction_id_fkey (redaction_id => redactions.id)
#
-class OldNode < ActiveRecord::Base
+class OldNode < ApplicationRecord
include GeoRecord
include ConsistencyValidations
include ObjectMetadata
# node_tags_id_fkey (node_id => nodes.node_id)
#
-class OldNodeTag < ActiveRecord::Base
+class OldNodeTag < ApplicationRecord
self.table_name = "node_tags"
self.primary_keys = "node_id", "version", "k"
# relations_redaction_id_fkey (redaction_id => redactions.id)
#
-class OldRelation < ActiveRecord::Base
+class OldRelation < ApplicationRecord
include ConsistencyValidations
include ObjectMetadata
# relation_members_id_fkey (relation_id => relations.relation_id)
#
-class OldRelationMember < ActiveRecord::Base
+class OldRelationMember < ApplicationRecord
self.table_name = "relation_members"
self.primary_keys = "relation_id", "version", "sequence_id"
# relation_tags_id_fkey (relation_id => relations.relation_id)
#
-class OldRelationTag < ActiveRecord::Base
+class OldRelationTag < ApplicationRecord
self.table_name = "relation_tags"
self.primary_keys = "relation_id", "version", "k"
# ways_redaction_id_fkey (redaction_id => redactions.id)
#
-class OldWay < ActiveRecord::Base
+class OldWay < ApplicationRecord
include ConsistencyValidations
include ObjectMetadata
# way_nodes_id_fkey (way_id => ways.way_id)
#
-class OldWayNode < ActiveRecord::Base
+class OldWayNode < ApplicationRecord
self.table_name = "way_nodes"
self.primary_keys = "way_id", "version", "sequence_id"
# way_tags_id_fkey (way_id => ways.way_id)
#
-class OldWayTag < ActiveRecord::Base
+class OldWayTag < ApplicationRecord
self.table_name = "way_tags"
self.primary_keys = "way_id", "version", "k"
# record's title and description fields, which can be
# displayed linked from the redacted records.
#
-class Redaction < ActiveRecord::Base
+class Redaction < ApplicationRecord
belongs_to :user
has_many :old_nodes
# current_relations_changeset_id_fkey (changeset_id => changesets.id)
#
-class Relation < ActiveRecord::Base
+class Relation < ApplicationRecord
require "xml/libxml"
include ConsistencyValidations
relation
end
- def to_xml
- doc = OSM::API.new.get_xml_doc
- doc.root << to_xml_node
- doc
- end
-
- def to_xml_node(changeset_cache = {}, user_display_name_cache = {})
- el = XML::Node.new "relation"
- el["id"] = id.to_s
-
- add_metadata_to_xml_node(el, self, changeset_cache, user_display_name_cache)
-
- relation_members.each do |member|
- member_el = XML::Node.new "member"
- member_el["type"] = member.member_type.downcase
- member_el["ref"] = member.member_id.to_s
- member_el["role"] = member.member_role
- el << member_el
- end
-
- add_tags_to_xml_node(el, relation_tags)
-
- el
- end
-
# FIXME: is this really needed?
def members
@members ||= relation_members.map do |member|
# current_relation_members_id_fkey (relation_id => current_relations.id)
#
-class RelationMember < ActiveRecord::Base
+class RelationMember < ApplicationRecord
self.table_name = "current_relation_members"
self.primary_keys = "relation_id", "sequence_id"
# current_relation_tags_id_fkey (relation_id => current_relations.id)
#
-class RelationTag < ActiveRecord::Base
+class RelationTag < ApplicationRecord
self.table_name = "current_relation_tags"
self.primary_keys = "relation_id", "k"
# reports_user_id_fkey (user_id => users.id)
#
-class Report < ActiveRecord::Base
+class Report < ApplicationRecord
belongs_to :issue, :counter_cache => true
belongs_to :user
# gpx_files_user_id_fkey (user_id => users.id)
#
-class Trace < ActiveRecord::Base
+class Trace < ApplicationRecord
self.table_name = "gpx_files"
belongs_to :user, :counter_cache => true
# gps_points_gpx_id_fkey (gpx_id => gpx_files.id)
#
-class Tracepoint < ActiveRecord::Base
+class Tracepoint < ApplicationRecord
include GeoRecord
self.table_name = "gps_points"
# gpx_file_tags_gpx_id_fkey (gpx_id => gpx_files.id)
#
-class Tracetag < ActiveRecord::Base
+class Tracetag < ApplicationRecord
self.table_name = "gpx_file_tags"
belongs_to :trace, :foreign_key => "gpx_id"
# users_home_idx (home_tile)
#
-class User < ActiveRecord::Base
+class User < ApplicationRecord
require "xml/libxml"
has_many :traces, -> { where(:visible => true) }
# user_blocks_user_id_fkey (user_id => users.id)
#
-class UserBlock < ActiveRecord::Base
+class UserBlock < ApplicationRecord
validate :moderator_permissions
validates :reason, :characters => true
# block. this should be caught and dealt with in the controller,
# but i've also included it here just in case.
def moderator_permissions
- errors.add(:base, I18n.t("user_block.model.non_moderator_update")) if creator_id_changed? && !creator.moderator?
- errors.add(:base, I18n.t("user_block.model.non_moderator_revoke")) unless revoker_id.nil? || revoker.moderator?
+ errors.add(:base, I18n.t("user_blocks.model.non_moderator_update")) if creator_id_changed? && !creator.moderator?
+ errors.add(:base, I18n.t("user_blocks.model.non_moderator_revoke")) if revoker_id_changed? && !revoker_id.nil? && !revoker.moderator?
end
end
# user_preferences_user_id_fkey (user_id => users.id)
#
-class UserPreference < ActiveRecord::Base
+class UserPreference < ApplicationRecord
self.primary_keys = "user_id", "k"
belongs_to :user
validates :user, :presence => true, :associated => true
validates :k, :v, :length => 1..255, :characters => true
-
- # Turn this Node in to an XML Node without the <osm> wrapper.
- def to_xml_node
- el1 = XML::Node.new "preference"
- el1["k"] = k
- el1["v"] = v
-
- el1
- end
end
# user_roles_user_id_fkey (user_id => users.id)
#
-class UserRole < ActiveRecord::Base
+class UserRole < ApplicationRecord
belongs_to :user
belongs_to :granter, :class_name => "User"
# user_tokens_user_id_fkey (user_id => users.id)
#
-class UserToken < ActiveRecord::Base
+class UserToken < ApplicationRecord
belongs_to :user
after_initialize :set_defaults
# current_ways_changeset_id_fkey (changeset_id => changesets.id)
#
-class Way < ActiveRecord::Base
+class Way < ApplicationRecord
require "xml/libxml"
include ConsistencyValidations
way
end
- # Find a way given it's ID, and in a single SQL call also grab its nodes and tags
- def to_xml
- doc = OSM::API.new.get_xml_doc
- doc.root << to_xml_node
- doc
- end
-
- def to_xml_node(visible_nodes = nil, changeset_cache = {}, user_display_name_cache = {})
- el = XML::Node.new "way"
- el["id"] = id.to_s
-
- add_metadata_to_xml_node(el, self, changeset_cache, user_display_name_cache)
-
- # make sure nodes are output in sequence_id order
- ordered_nodes = []
- way_nodes.each do |nd|
- if visible_nodes
- # if there is a list of visible nodes then use that to weed out deleted nodes
- ordered_nodes[nd.sequence_id] = nd.node_id.to_s if visible_nodes[nd.node_id]
- else
- # otherwise, manually go to the db to check things
- ordered_nodes[nd.sequence_id] = nd.node_id.to_s if nd.node&.visible?
- end
- end
-
- ordered_nodes.each do |nd_id|
- next unless nd_id && nd_id != "0"
-
- node_el = XML::Node.new "nd"
- node_el["ref"] = nd_id
- el << node_el
- end
-
- add_tags_to_xml_node(el, way_tags)
-
- el
- end
-
def nds
@nds ||= way_nodes.collect(&:node_id)
end
# current_way_nodes_node_id_fkey (node_id => current_nodes.id)
#
-class WayNode < ActiveRecord::Base
+class WayNode < ApplicationRecord
self.table_name = "current_way_nodes"
self.primary_keys = "way_id", "sequence_id"
# current_way_tags_id_fkey (way_id => current_ways.id)
#
-class WayTag < ActiveRecord::Base
+class WayTag < ApplicationRecord
self.table_name = "current_way_tags"
self.primary_keys = "way_id", "k"
json.geometry do
json.type "Point"
- json.coordinates [ note.lon.to_f, note.lat.to_f ]
+ json.coordinates [note.lon.to_f, note.lat.to_f]
end
json.properties do
json.close_url close_note_url(note, :format => params[:format])
end
- json.date_created note.created_at
+ json.date_created note.created_at.to_s
json.status note.status
- json.closed_at note.closed_at if note.closed?
+ json.closed_at note.closed_at.to_s if note.closed?
json.comments(note.comments) do |comment|
- json.date comment.created_at
+ json.date comment.created_at.to_s
if comment.author
json.uid comment.author.id
json.type "FeatureCollection"
json.features(@notes) do |note|
- json.ingest! render(note)
+ json.partial! note
end
--- /dev/null
+json.partial! @note
+++ /dev/null
-json.ingest! render(@note)
--- /dev/null
+attrs = {
+ "k" => user_preference.k,
+ "v" => user_preference.v
+}
+
+xml.preference(attrs)
--- /dev/null
+xml.instruct!
+
+xml.osm(OSM::API.new.xml_root_attributes) do |osm|
+ osm.preferences do |preferences|
+ preferences << (render(@user_preferences) || "")
+ end
+end
<li><%= linked_name = link_to h(printable_name(containing_relation.relation)), :action => "relation", :id => containing_relation.relation.id.to_s
if containing_relation.member_role.blank?
- raw t ".entry", :relation_name => linked_name
+ t ".entry_html", :relation_name => linked_name
else
- raw t ".entry_role", :relation_name => linked_name, :relation_role => h(containing_relation.member_role)
+ t ".entry_role_html", :relation_name => linked_name, :relation_role => h(containing_relation.member_role)
end %>
</li>
<% unless node.ways.empty? and node.containing_relation_members.empty? %>
<h4><%= t "browse.part_of" %></h4>
- <ul>
+ <ul class="list-unstyled">
<% node.ways.uniq.each do |way| %>
<li><%= link_to printable_name(way), { :action => "way", :id => way.id.to_s }, { :class => link_class("way", way), :title => link_title(way) } %></li>
<% end %>
<% unless relation.containing_relation_members.empty? %>
<h4><%= t "browse.part_of" %></h4>
- <ul><%= render :partial => "containing_relation", :collection => relation.containing_relation_members.uniq %></ul>
+ <ul class="list-unstyled"><%= render :partial => "containing_relation", :collection => relation.containing_relation_members.uniq %></ul>
<% end %>
<% unless relation.relation_members.empty? %>
<h4><%= t ".members" %></h4>
- <ul><%= render :partial => "relation_member", :collection => relation.relation_members %></ul>
+ <ul class="list-unstyled"><%= render :partial => "relation_member", :collection => relation.relation_members %></ul>
<% end %>
</div>
<% end %>
type_str = t ".type." + relation_member.member_type.downcase %>
<li class="<%= member_class %>">
<%= if relation_member.member_role.blank?
- raw t ".entry", :type => type_str, :name => linked_name
+ t ".entry_html", :type => type_str, :name => linked_name
else
- raw t ".entry_role", :type => type_str, :name => linked_name, :role => h(relation_member.member_role)
+ t ".entry_role_html", :type => type_str, :name => linked_name, :role => h(relation_member.member_role)
end %>
</li>
<% unless way.containing_relation_members.empty? %>
<h4><%= t "browse.part_of" %></h4>
- <ul>
+ <ul class="list-unstyled">
<%= render :partial => "containing_relation", :collection => way.containing_relation_members.uniq %>
</ul>
<% end %>
<% unless way.way_nodes.empty? %>
<h4><%= t ".nodes" %></h4>
- <ul>
+ <ul class="list-unstyled">
<% way.way_nodes.each do |wn| %>
<li>
<%= 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), :rel => link_follow(wn.node) } %>
<% related_ways = wn.node.ways.reject { |w| w.id == wn.way_id } %>
<% if related_ways.size > 0 then %>
- (<%= raw t ".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 %>)
+ (<%= t ".also_part_of_html", :count => related_ways.size, :related_ways => to_sentence(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) }) }) %>)
<% end %>
</li>
<% end %>
</h2>
<div class="browse-section">
- <h4><%= linkify(h(@changeset.tags["comment"].to_s.presence || t("browse.no_comment"))) %></h4>
+ <h6><%= linkify(h(@changeset.tags["comment"].to_s.presence || t("browse.no_comment"))) %></h6>
<div class="details"><%= changeset_details(@changeset) %></div>
<%= render :partial => "tag_details", :object => @changeset.tags.except("comment") %>
<% if @comments.length > 0 %>
<div class='changeset-comments'>
<form action="#">
- <ul>
+ <ul class="list-unstyled">
<% @comments.each do |comment| %>
<% if comment.visible %>
<li id="c<%= comment.id %>">
<%= type_and_paginated_count("way", @way_pages) %>
<%= render :partial => "paging_nav", :locals => { :pages => @way_pages, :page_param => "way_page" } %>
</h4>
- <ul>
+ <ul class="list-unstyled">
<% @ways.each do |way| %>
<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 %>
<%= type_and_paginated_count("relation", @relation_pages) %>
<%= render :partial => "paging_nav", :locals => { :pages => @relation_pages, :page_param => "relation_page" } %>
</h4>
- <ul>
+ <ul class="list-unstyled">
<% @relations.each do |relation| %>
<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 %>
<%= type_and_paginated_count("node", @node_pages) %>
<%= render :partial => "paging_nav", :locals => { :pages => @node_pages, :page_param => "node_page" } %>
</h4>
- <ul>
+ <ul class="list-unstyled">
<% @nodes.each do |node| %>
<li><%= link_to printable_name(node, true), { :action => "node", :id => node.node_id.to_s }, { :class => link_class("node", node), :title => link_title(node), :rel => link_follow(node) } %></li>
<% end %>
-<% set_title(t("browse.#{@type}.title", :name => printable_name(@feature))) %>
+<% set_title(t("browse.#{@type}.title_html", :name => printable_name(@feature))) %>
<h2>
<a class="geolink" href="<%= root_path %>"><span class="icon close"></span></a>
- <%= raw t("browse.#{@type}.title", :name => printable_name(@feature)) %>
+ <%= t("browse.#{@type}.title_html", :name => printable_name(@feature)) %>
</h2>
<%= render :partial => @type, :object => @feature %>
-<% set_title(t("browse.#{@type}.history_title", :name => printable_name(@feature))) %>
+<% set_title(t("browse.#{@type}.history_title_html", :name => printable_name(@feature))) %>
<h2>
<a class="geolink" href="<%= root_path %>"><span class="icon close"></span></a>
- <%= raw t("browse.#{@type}.history_title", :name => printable_name(@feature)) %>
+ <%= t("browse.#{@type}.history_title_html", :name => printable_name(@feature)) %>
</h2>
<%= render :partial => @type, :collection => @feature.send("old_#{@type}s").reverse %>
</div>
<div class="details" data-coordinates="<%= @note.lat %>,<%= @note.lon %>" data-status="<%= @note.status %>">
- <%= note_event("open", @note.created_at, @note.author) %>
+ <%= note_event("opened", @note.created_at, @note.author) %>
<% if @note.status == "closed" %>
<br />
<%= note_event(@note.status, @note.closed_at, @note_comments.last.author) %>
<% if @note_comments.length > 1 %>
<div class='note-comments'>
- <ul>
+ <ul class="list-unstyled">
<% @note_comments[1..-1].each do |comment| %>
<li id="c<%= comment.id %>">
<small class='deemphasize'><%= note_event(comment.event, comment.created_at, comment.author) %></small>
<div id="query-nearby" class="query-results">
<h3><%= t(".nearby") %></h3>
<%= image_tag "searching.gif", :class => "loader" %>
- <ul class="query-results-list"></ul>
+ <div>
+ <ul class="query-results-list list-group list-group-flush"></ul>
+ </div>
</div>
<div id="query-isin" class="query-results">
<h3><%= t(".enclosing") %></h3>
<%= image_tag "searching.gif", :class => "loader" %>
- <ul class="query-results-list"></ul>
+ <div>
+ <ul class="query-results-list list-group list-group-flush"></ul>
+ </div>
</div>
}
end %>
-<%= content_tag "li", :id => "changeset_#{changeset.id}", :data => { :changeset => changeset_data } do %>
- <h4>
- <a class="changeset_id" href="<%= changeset_path(changeset) %>">
+<%= content_tag "li", :id => "changeset_#{changeset.id}", :data => { :changeset => changeset_data }, :class => "list-group-item" do %>
+ <h6>
+ <a class="changeset_id text-dark" href="<%= changeset_path(changeset) %>">
<%= changeset.tags["comment"].to_s.presence || t("browse.no_comment") %>
</a>
- </h4>
+ </h6>
<div class="comments comments-<%= changeset.comments.length %>">
<%= changeset.comments.length %>
<span class="icon note grey"></span>
<% if @changesets.present? %>
- <ol class="changesets">
+ <ol class="changesets list-group list-group-flush">
<%= render @changesets %>
</ol>
<% if @changesets.size == 20 -%>
<div class="clearfix diary-comment<%= " deemphasize" unless diary_comment.visible? %>">
<%= user_thumbnail diary_comment.user %>
- <p class="deemphasize comment-heading" id="comment<%= diary_comment.id %>"><%= raw(t(".comment_from", :link_user => (link_to h(diary_comment.user.display_name), user_path(diary_comment.user)), :comment_created_at => link_to(l(diary_comment.created_at, :format => :friendly), :anchor => "comment#{diary_comment.id}"))) %>
+ <p class="deemphasize comment-heading" id="comment<%= diary_comment.id %>"><%= t(".comment_from_html", :link_user => (link_to h(diary_comment.user.display_name), user_path(diary_comment.user)), :comment_created_at => link_to(l(diary_comment.created_at, :format => :friendly), :anchor => "comment#{diary_comment.id}")) %>
<% if current_user and diary_comment.user.id != current_user.id %>
| <%= report_link(t(".report"), diary_comment) %>
<% end %>
<h2><%= link_to h(diary_entry.title), diary_entry_path(diary_entry.user, diary_entry) %></h2>
<small class='deemphasize'>
- <%= raw(t(".posted_by", :link_user => (link_to h(diary_entry.user.display_name), user_path(diary_entry.user)), :created => l(diary_entry.created_at, :format => :blog), :language_link => (link_to h(diary_entry.language.name), :controller => "diary_entries", :action => "index", :display_name => nil, :language => diary_entry.language_code))) %>
+ <%= t(".posted_by_html", :link_user => (link_to h(diary_entry.user.display_name), user_path(diary_entry.user)), :created => l(diary_entry.created_at, :format => :blog), :language_link => (link_to diary_entry.language.name, :controller => "diary_entries", :action => "index", :display_name => nil, :language => diary_entry.language_code)) %>
</small>
</div>
<div class="diary_entry standard-form">
<fieldset>
- <div class='form-row'>
+ <div class='standard-form-row'>
<label class="standard-label"><%= t ".subject" -%></label>
<%= f.text_field :title, :class => "richtext_title" %>
</div>
- <div class='form-row'>
+ <div class='standard-form-row'>
<label class="standard-label"><%= t ".body" -%></label>
<%= richtext_area :diary_entry, :body, :cols => 80, :rows => 20, :format => @diary_entry.body_format %>
</div>
- <div class='form-row'>
+ <div class='standard-form-row'>
<label class="standard-label"><%= t ".language" -%></label>
<%= f.collection_select :language_code, Language.order(:english_name), :code, :name %>
</div>
<fieldset class='location'>
<label class="standard-label"><%= t ".location" -%></label>
<%= content_tag "div", "", :id => "map", :data => { :lat => @lat, :lon => @lon, :zoom => @zoom } %>
- <div class='form-row clearfix'>
+ <div class='standard-form-row clearfix'>
<div class='form-column'>
<label class="secondary standard-label"><%= t ".latitude" -%></label>
<%= f.text_field :latitude, :size => 20, :id => "latitude" %>
<% end %>
<table class="messages" width="100%">
- <tr>
- <th width="25%"><%= t ".post" %></th>
- <th width="25%"><%= t ".when" %></th>
- <th width="50%"><%= t ".comment" %></th>
- </tr>
+ <thead>
+ <tr>
+ <th width="25%"><%= t ".post" %></th>
+ <th width="25%"><%= t ".when" %></th>
+ <th width="50%"><%= t ".comment" %></th>
+ </tr>
+ </thead>
<% @comments.each do |comment| -%>
<% cl = cycle("table0", "table1") %>
- <tr class="<%= cl %>">
+ <tr class="<%= cl %><%= " deemphasize" unless comment.visible? %>">
<td width="25%"><%= link_to comment.diary_entry.title, diary_entry_path(comment.diary_entry.user, comment.diary_entry) %></td>
<td width="25%"><span title="<%= l comment.created_at, :format => :friendly %>"><%= time_ago_in_words(comment.created_at, :scope => :'datetime.distance_in_words_ago') %></span></td>
<td width="50%" class="richtext"><%= comment.body.to_html %></td>
<% if @user %>
<% if @user == current_user %>
- <div>
- <li><%= link_to image_tag("new.png", :class => "small_icon", :border => 0) + t(".new"), new_diary_entry_path, :title => t(".new_title") %></li>
- </div>
+ <li><%= link_to image_tag("new.png", :class => "small_icon") + t(".new"), new_diary_entry_path, :title => t(".new_title") %></li>
<% end %>
<% else %>
<% if current_user %>
- <div>
- <li><%= link_to image_tag("new.png", :class => "small_icon", :border => 0) + t(".new"), new_diary_entry_path, :title => t(".new_title") %></li>
- </div>
+ <li><%= link_to image_tag("new.png", :class => "small_icon") + t(".new"), new_diary_entry_path, :title => t(".new_title") %></li>
<% end %>
<% end %>
</ul>
<% content_for :heading do %>
<div id="userinformation">
<%= user_image @entry.user %>
- <h2><%= link_to t(".user_title", :user => h(@entry.user.display_name)), :action => :index %></h2>
+ <h2><%= link_to t(".user_title", :user => @entry.user.display_name), :action => :index %></h2>
<p><%= rss_link_to :action => :rss, :display_name => @entry.user.display_name %></p>
</div>
<% end %>
<div class="diary-subscribe-buttons"><%= link_to t("javascripts.changesets.show.subscribe"), diary_entry_subscribe_path(:display_name => @entry.user.display_name, :id => @entry.id), :method => :post, :class => :button %></div>
<% end %>
<% else %>
- <h3 id="newcomment"><%= raw t(".login_to_leave_a_comment", :login_link => link_to(t(".login"), :controller => "users", :action => "login", :referer => request.fullpath)) %></h3>
+ <h3 id="newcomment"><%= t(".login_to_leave_a_comment_html", :login_link => link_to(t(".login"), :controller => "users", :action => "login", :referer => request.fullpath)) %></h3>
<% end %>
</div>
<% if @results.empty? %>
- <p class="search_results_entry inner12"><%= t ".no_results" %></p>
+ <ul class="list-group list-group-flush">
+ <li class="list-group-item">
+ <%= t ".no_results" %>
+ </li>
+ </ul>
<% else %>
- <ul class='results-list'>
+ <ul class='results-list list-group list-group-flush'>
<% @results.each do |result| %>
- <li><p class="inner12 search_results_entry clearfix"><%= result_to_html(result) %></p></li>
+ <li class="list-group-item search_results_entry"><%= result_to_html(result) %></li>
<% end %>
</ul>
<% if @more_params %>
<%= t("site.sidebar.search_results") %>
</h2>
<% @sources.each do |source| %>
- <h4 class="inner12"><%= raw(t(".title.#{source}")) %></h4>
+ <h4 class="inner12"><%= t(".title.#{source}_html") %></h4>
<div class="search_results_entry" data-href="<%= url_for @params.merge(:action => "search_#{source}") %>">
<%= image_tag "searching.gif", :class => "loader" %>
</div>
<div class="issue-comments">
<% comments.each do |comment| %>
<div class="comment">
- <div style="float:left">
+ <div class="float-left">
<%= link_to user_thumbnail(comment.user), user_path(comment.user) %>
</div>
- <b> <%= link_to comment.user.display_name, user_path(comment.user) %> </b> <br />
- <%= comment.body %>
+ <p class="text-muted mb-0">
+ <%= t ".comment_from_html", :user_link => link_to(comment.user.display_name, user_path(comment.user)),
+ :comment_created_at => l(comment.created_at.to_datetime, :format => :friendly) %>
+ </p>
+ <p><%= comment.body %></p>
</div>
- <span class="deemphasize">
- <%= t(".created_at", :datetime => l(comment.created_at.to_datetime, :format => :friendly)) %>
- </span>
<hr>
<% end %>
</div>
<% reports.each do |report| %>
<div class="report">
- <div style="float:left">
+ <div class="float-left">
<%= link_to user_thumbnail(report.user), user_path(report.user) %>
</div>
- <%= t ".reported_by_html", :category => report.category, :user => link_to(report.user.display_name, user_path(report.user)) %>
- <br />
- <span class="deemphasize">
- <%= t(".updated_at", :datetime => l(report.updated_at.to_datetime, :format => :friendly)) %>
- </span>
- <br />
- <%= report.details %>
- <br />
+ <p class="text-muted mb-0">
+ <%= t ".reported_by_html", :category => report.category,
+ :user => link_to(report.user.display_name, user_path(report.user)),
+ :updated_at => l(report.updated_at.to_datetime, :format => :friendly) %>
+ </p>
+ <p><%= report.details %></p>
</div>
<hr>
<% end %>
<p><%= link_to t(".reopen"), reopen_issue_url(@issue), :method => :post if @issue.may_reopen? %></p>
<% end %>
-<div class="report-related-block">
-
- <div class="report-block">
+<div class="row">
+ <div class="col-md-8">
<h3><%= t ".reports_of_this_issue" %></h3>
<% if @read_reports.present? %>
<%= render "reports", :reports => @unread_reports %>
</div>
<% end %>
- <br />
</div>
<% if @issue.reported_user %>
- <div class="related-reports">
+ <div class="col-md-4">
<h3><%= t ".other_issues_against_this_user" %></h3>
<% if @related_issues.count > 1 %>
<ul>
<% if flash[:error] %>
<div class="flash error">
<picture>
- <source srcset="<%= image_path "notice.svg" %>" type="image/svg+xml"></source>
+ <source srcset="<%= image_path "notice.svg" %>" type="image/svg+xml" />
<%= image_tag("notice.png", :srcset => image_path("notice.svg"), :class => "small_icon", :border => 0) %>
</picture>
<div class="message"><%= flash[:error] %></div>
<h1>
<a href="<%= root_path %>" class="geolink">
<picture>
- <source srcset="<%= image_path "osm_logo.svg" %>" type="image/svg+xml"></source>
+ <source srcset="<%= image_path "osm_logo.svg" %>" type="image/svg+xml" />
<%= image_tag "osm_logo.png", :srcset => image_path("osm_logo.svg"), :alt => t("layouts.logo.alt_text"), :class => "logo" %>
</picture>
<%= t "layouts.project_name.h1" %>
<a href="#" id="menu-icon"></a>
<nav class='primary'>
<%= content_for :header %>
- <ul>
- <li id="edit_tab" class="dropdown <%= current_page_class(edit_path) %>">
+ <div class="btn-group">
+ <div id="edit_tab" class="btn-group <%= current_page_class(edit_path) %>">
<%= link_to t("layouts.edit"),
edit_path,
- :class => "tab geolink editlink",
+ :class => "btn btn-outline-primary geolink editlink",
:id => "editanchor",
:data => { :editor => preferred_editor } %>
- <a class='dropdown-toggle' data-toggle='dropdown' href='#'><b class="caret"></b></a>
+ <a class='btn btn-outline-primary dropdown-toggle dropdown-toggle-split' data-toggle='dropdown' href='#'></a>
<ul class='dropdown-menu'>
<% Editors::RECOMMENDED_EDITORS.each do |editor| %>
<li>
<%= link_to t("layouts.edit_with", :editor => t("editor.#{editor}.description")),
edit_path(:editor => editor),
:data => { :editor => editor },
- :class => "geolink editlink" %>
+ :class => "geolink editlink dropdown-item" %>
</li>
<% end %>
</ul>
- </li>
- <li id="history_tab" class="<%= current_page_class(history_path) %>">
- <%= link_to t("layouts.history"), history_path, :class => "tab geolink" %>
- </li>
- <li id="export_tab" class="<%= current_page_class(export_path) %>">
- <%= link_to t("layouts.export"), export_path, :class => "tab geolink" %>
- </li>
- </ul>
+ </div>
+ <%= link_to t("layouts.history"), history_path, :class => "btn btn-outline-primary geolink flex-grow-1 current_page_class(history_path)", :id => "history_tab" %>
+ <%= link_to t("layouts.export"), export_path, :class => "btn btn-outline-primary geolink current_page_class(export_path)", :id => "export_tab" %>
+ </div>
</nav>
<nav class='secondary'>
- <ul>
- <% if current_user and ( current_user.administrator? or current_user.moderator? ) %>
- <li class="compact-hide <%= current_page_class(issues_path) %>">
- <%= link_to issues_path(:status => "open") do %>
+ <ul class='mx-1 px-0'>
+ <% if can? :index, Issue %>
+ <li class="compact-hide nav-item <%= current_page_class(issues_path) %>">
+ <%= link_to issues_path(:status => "open"), :class => "nav-link" do %>
<%= t("layouts.issues") %>
<%= open_issues_count %>
<% end -%>
</li>
<% end %>
- <li class="compact-hide <%= current_page_class(traces_path) %>"><%= link_to t("layouts.gps_traces"), traces_path %></li>
- <li class="compact-hide <%= current_page_class(diary_entries_path) %>"><%= link_to t("layouts.user_diaries"), diary_entries_path %></li>
- <li class="compact-hide <%= current_page_class(copyright_path) %>"><%= link_to t("layouts.copyright"), copyright_path %></li>
- <li class="compact-hide <%= current_page_class(help_path) %>"><%= link_to t("layouts.help"), help_path %></li>
- <li class="compact-hide <%= current_page_class(about_path) %>"><%= link_to t("layouts.about"), about_path %></li>
- <li id="compact-secondary-nav" class="dropdown">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#"><%= t "layouts.more" %> <b class="caret"></b></a>
+ <li class="compact-hide nav-item <%= current_page_class(traces_path) %>">
+ <%= link_to t("layouts.gps_traces"), traces_path, :class => "nav-link" %>
+ </li>
+ <li class="compact-hide nav-item <%= current_page_class(diary_entries_path) %>">
+ <%= link_to t("layouts.user_diaries"), diary_entries_path, :class => "nav-link" %>
+ </li>
+ <li class="compact-hide nav-item <%= current_page_class(copyright_path) %>">
+ <%= link_to t("layouts.copyright"), copyright_path, :class => "nav-link" %>
+ </li>
+ <li class="compact-hide nav-item <%= current_page_class(help_path) %>">
+ <%= link_to t("layouts.help"), help_path, :class => "nav-link" %>
+ </li>
+ <li class="compact-hide nav-item <%= current_page_class(about_path) %>">
+ <%= link_to t("layouts.about"), about_path, :class => "nav-link" %>
+ </li>
+ <li id="compact-secondary-nav" class="dropdown nav-item">
+ <a class="dropdown-toggle nav-link" data-toggle="dropdown" href="#"><%= t "layouts.more" %></a>
<ul class="dropdown-menu">
<% if Settings.status != "database_offline" && can?(:index, Issue) %>
<li class="<%= current_page_class(issues_path) %>">
- <%= link_to issues_path(:status => "open") do %>
- <%= open_issues_count %>
+ <%= link_to issues_path(:status => "open"), :class => "dropdown-item" do %>
<%= t("layouts.issues") %>
+ <%= open_issues_count %>
<% end -%>
</li>
<% end %>
- <li class="<%= current_page_class(traces_path) %>"><%= link_to t("layouts.gps_traces"), traces_path %></li>
- <li class="<%= current_page_class(diary_entries_path) %>"><%= link_to t("layouts.user_diaries"), diary_entries_path %></li>
- <li class="<%= current_page_class(copyright_path) %>"><%= link_to t("layouts.copyright"), copyright_path %></li>
- <li class="<%= current_page_class(help_path) %>"><%= link_to t("layouts.help"), help_path %></li>
- <li class="<%= current_page_class(about_path) %>"><%= link_to t("layouts.about"), about_path %></li>
+ <li class="<%= current_page_class(traces_path) %>"><%= link_to t("layouts.gps_traces"), traces_path, :class => "dropdown-item" %></li>
+ <li class="<%= current_page_class(diary_entries_path) %>"><%= link_to t("layouts.user_diaries"), diary_entries_path, :class => "dropdown-item" %></li>
+ <li class="<%= current_page_class(copyright_path) %>"><%= link_to t("layouts.copyright"), copyright_path, :class => "dropdown-item" %></li>
+ <li class="<%= current_page_class(help_path) %>"><%= link_to t("layouts.help"), help_path, :class => "dropdown-item" %></li>
+ <li class="<%= current_page_class(about_path) %>"><%= link_to t("layouts.about"), about_path, :class => "dropdown-item" %></li>
</ul>
</li>
</ul>
<% if current_user && current_user.id %>
- <div class='dropdown user-menu logged-in'>
- <a class='dropdown-toggle' data-toggle='dropdown' href="#">
+ <div class='d-inline-flex dropdown user-menu logged-in clearfix'>
+ <a class='dropdown-toggle btn btn-outline-secondary pl-2 py-1 flex-grow-1' data-toggle='dropdown' href="#">
<%= user_thumbnail_tiny(current_user, :width => 25, :height => 25) %>
<%= render :partial => "layouts/inbox" %>
<span class="user-button">
<span class='username'>
<%= current_user.display_name %>
</span>
- <b class="caret"></b>
</span>
</a>
- <ul class='dropdown-menu'>
- <li>
- <%= link_to inbox_messages_path do %>
- <span class='count-number'><%= number_with_delimiter(current_user.new_messages.size) %></span>
- <%= t("users.show.my messages") %>
- <% end %>
- </li>
- <li>
- <%= link_to t("users.show.my profile"), user_path(current_user) %>
- </li>
- <li>
- <%= link_to t("users.show.my settings"), :controller => "users", :action => "account", :display_name => current_user.display_name %>
- </li>
- <li class="divider"></li>
- <li>
- <%= yield :greeting %>
- </li>
- <li>
- <%= link_to t("layouts.logout"), logout_path(:session => session.id, :referer => request.fullpath), :class => "geolink" %>
- </li>
- </ul>
+ <div class='dropdown-menu dropdown-menu-right'>
+ <%= link_to inbox_messages_path, :class => "dropdown-item" do %>
+ <%= t("users.show.my messages") %>
+ <span class='count-number'><%= number_with_delimiter(current_user.new_messages.size) %></span>
+ <% end %>
+ <%= link_to t("users.show.my profile"), user_path(current_user), :class => "dropdown-item" %>
+ <%= link_to t("users.show.my settings"), { :controller => "users", :action => "account", :display_name => current_user.display_name }, { :class => "dropdown-item" } %>
+ <div class="dropdown-divider"></div>
+ <%= yield :greeting %>
+ <%= link_to t("layouts.logout"), logout_path(:referer => request.fullpath), :method => "post", :class => "geolink dropdown-item" %>
+ </div>
</div>
<% else %>
- <ul class="user-menu clearfix">
- <li><%= link_to t("layouts.log_in"), login_path(:referer => request.fullpath), :class => "geolink" %></li>
- <li><%= link_to t("layouts.sign_up"), user_new_path %></li>
+ <div class="d-inline-flex btn-group login-menu" role="">
+ <%= link_to t("layouts.log_in"), login_path(:referer => request.fullpath), :class => "geolink btn btn-outline-secondary" %>
+ <%= link_to t("layouts.sign_up"), user_new_path, :class => "btn btn-outline-secondary" %>
</ul>
<% end %>
</nav>
<body>
<a href="<%= root_path %>">
<picture>
- <source srcset="<%= image_path "osm_logo.svg" %>" type="image/svg+xml"></source>
+ <source srcset="<%= image_path "osm_logo.svg" %>" type="image/svg+xml" />
<%= image_tag "osm_logo.png", :srcset => image_path("osm_logo.svg"), :alt => t("layouts.logo.alt_text"), :class => "logo" %>
</picture>
</a>
<%= link_to t("layouts.home"),
"#",
:id => "homeanchor",
- :class => "set_position",
+ :class => "set_position dropdown-item",
:data => { :lat => current_user.home_lat,
:lon => current_user.home_lon,
:zoom => 15 } %>
</tbody>
</table>
<% else %>
- <div><%= raw(t(".no_messages_yet", :people_mapping_nearby_link => link_to(t(".people_mapping_nearby"), user_path(current_user)))) %></div>
+ <div><%= t(".no_messages_yet_html", :people_mapping_nearby_link => link_to(t(".people_mapping_nearby"), user_path(current_user))) %></div>
<% end %>
<% content_for :heading do %>
- <h2><%= raw(t(".send_message_to", :name => link_to(h(@message.recipient.display_name), user_path(@message.recipient)))) %></h2>
+ <h2><%= t(".send_message_to_html", :name => link_to(@message.recipient.display_name, user_path(@message.recipient))) %></h2>
<% end %>
<%= error_messages_for "message" %>
<%= form_for @message, :html => { :class => "standard-form" } do |f| %>
<%= hidden_field_tag :display_name, @message.recipient.display_name %>
<fieldset>
- <div class='form-row'>
+ <div class='standard-form-row'>
<label class="standard-label" for="message_title"><%= t ".subject" %></label>
<%= f.text_field :title, :size => 60, :class => "richtext_title" %>
</div>
- <div class='form-row'>
+ <div class='standard-form-row'>
<label class="standard-label" for="message_body"><%= t ".body" %></label>
<%= richtext_area :message, :body, :cols => 80, :rows => 20 %>
</div>
<% end %>
<% content_for :heading do %>
- <h2><%= raw(t(".my_inbox", :inbox_link => link_to(t(".inbox"), inbox_messages_path))) %>/<%= t ".outbox" %></h2>
+ <h2><%= t(".my_inbox_html", :inbox_link => link_to(t(".inbox"), inbox_messages_path)) %>/<%= t ".outbox" %></h2>
<% end %>
<h4><%= t ".messages", :count => current_user.sent_messages.size %></h4>
</tbody>
</table>
<% else %>
- <div class="messages"><%= raw(t(".no_sent_messages", :people_mapping_nearby_link => link_to(t(".people_mapping_nearby"), user_path(current_user)))) %></div>
+ <div class="messages"><%= t(".no_sent_messages_html", :people_mapping_nearby_link => link_to(t(".people_mapping_nearby"), user_path(current_user))) %></div>
<% end %>
<%= button_to t(".reply_button"), message_reply_path(@message), :class => "reply-button" %>
<%= button_to t(".unread_button"), message_mark_path(@message, :mark => "unread"), :class => "mark-unread-button" %>
<%= button_to t(".destroy_button"), message_path(@message), :method => "delete", :class => "destroy-button" %>
+ <%= link_to t(".back"), inbox_messages_path, :class => "button deemphasize" %>
+ </div>
<% else %>
<div class="richtext"><%= @message.body.to_html %></div>
<div class='message-buttons buttons'>
+ <%= link_to t(".back"), outbox_messages_path, :class => "button deemphasize" %>
+ </div>
<% end %>
-
- <%= link_to t(".back"), outbox_messages_path, :class => "button deemphasize" %>
- </div>
<%= render :partial => "notes_paging_nav" %>
<table class="note_list">
- <tr>
- <th></th>
- <th><%= t ".id" %></th>
- <th><%= t ".creator" %></th>
- <th><%= t ".description" %></th>
- <th><%= t ".created_at" %></th>
- <th><%= t ".last_changed" %></th>
- </tr>
+ <thead>
+ <tr>
+ <th></th>
+ <th><%= t ".id" %></th>
+ <th><%= t ".creator" %></th>
+ <th><%= t ".description" %></th>
+ <th><%= t ".created_at" %></th>
+ <th><%= t ".last_changed" %></th>
+ </tr>
+ </thead>
<% @notes.each do |note| -%>
<tr<% if note.author == @user %> class="creator"<% end %>>
<td>
<h1><%= t ".title" %></h1>
<% end %>
-<p><%= raw t(".request_access", :app_name => link_to(@token.client_application.name, @token.client_application.url), :user => link_to(current_user.display_name, user_path(current_user))) %></p>
+<p><%= t(".request_access_html", :app_name => link_to(@token.client_application.name, @token.client_application.url), :user => link_to(current_user.display_name, user_path(current_user))) %></p>
<%= form_tag authorize_url do %>
<%= hidden_field_tag "oauth_token", @token.token %>
<h1><%= t ".title" %></h1>
<% end %>
-<p><%= raw t(".allowed", :app_name => link_to(@token.client_application.name, @token.client_application.url)) %></p>
+<p><%= t(".allowed_html", :app_name => link_to(@token.client_application.name, @token.client_application.url)) %></p>
<% if @token.oob? and not @token.oauth10? %>
<p><%= t ".verification", :code => @token.verifier %></p>
<div class='standard-form'>
<fieldset>
- <div class="form-row">
+ <div class="standard-form-row">
<label class='standard-label' for="client_application_name"><%= t ".name" %> (<%= t ".required" %>)</label>
<%= f.text_field :name %>
</div>
- <div class="form-row">
+ <div class="standard-form-row">
<label class='standard-label' for="client_application_url"><%= t ".url" %> (<%= t ".required" %>)</label>
<%= f.text_field :url %>
</div>
- <div class="form-row">
+ <div class="standard-form-row">
<label class='standard-label' for="client_application_callback_url"><%= t ".callback_url" %></label>
<%= f.text_field :callback_url %>
</div>
- <div class="form-row">
+ <div class="standard-form-row">
<label class='standard-label' for="client_application_support_url"><%= t ".support_url" %></label>
<%= f.text_field :support_url %>
</div>
<fieldset class='form-divider'>
<p><%= t ".requests" %></p>
<% ClientApplication.all_permissions.each do |perm| %>
- <div class="form-row">
+ <div class="standard-form-row">
<%= f.check_box perm %>
<label class='standard-label' for="client_application_<%= perm.to_s %>"><%= t("." + perm.to_s) %></label>
</div>
<h3><%= t ".my_tokens" %></h3>
<p><%= t ".list_tokens" %></p>
<table>
- <tr><th><%= t ".application" %></th>
- <th><%= t ".issued_at" %></th><th> </th></tr>
+ <thead>
+ <tr>
+ <th><%= t ".application" %></th>
+ <th><%= t ".issued_at" %></th>
+ <th> </th>
+ </tr>
+ </thead>
<% @tokens.each do |token| %>
- <%= content_tag_for :tr, token do %>
+ <tr>
<td><%= link_to token.client_application.name, token.client_application.url %></td>
<td><%= token.authorized_at %></td>
<td>
- <%= form_tag :controller => "oauth", :action => "revoke" do %>
- <%= hidden_field_tag "token", token.token %>
- <%= submit_tag t(".revoke") %>
- <% end %>
+ <%= form_tag :controller => "oauth", :action => "revoke" do %>
+ <%= hidden_field_tag "token", token.token %>
+ <%= submit_tag t(".revoke") %>
+ <% end %>
</td>
- <% end %>
+ </tr>
<% end %>
</table>
<% end %>
<h3><%= t ".my_apps" %></h3>
<% if @client_applications.empty? %>
-<p><%= raw(t(".no_apps", :oauth => "<a href=\"https://oauth.net\">OAuth</a>")) %></p>
+<p><%= t(".no_apps_html", :oauth => link_to(t(".oauth"), "https://oauth.net")) %></p>
<% else %>
<p><%= t ".registered_apps" %></p>
<% @client_applications.each do |client| %>
- <%= div_for client do %>
+ <div class="client_application">
<%= link_to client.name, :action => :show, :id => client.id %>
- <% end %>
+ </div>
<% end %>
<% end %>
<h3><%= link_to t(".register_new"), :action => :new %></h3>
<%= @redaction.description.to_html %>
</div>
-<% if current_user and current_user.moderator? %>
+<% if can?(:edit, Redaction) || can?(:destroy, Redaction) %>
<div class="buttons">
- <%= button_to t(".edit"), edit_redaction_path(@redaction), :method => :get %></td>
- <%= button_to t(".destroy"), @redaction, :method => "delete", :remote => true, :data => { :confirm => t(".confirm") } %>
+ <% if can?(:edit, Redaction) %>
+ <%= button_to t(".edit"), edit_redaction_path(@redaction), :method => :get %></td>
+ <% end %>
+ <% if can?(:destroy, Redaction) %>
+ <%= button_to t(".destroy"), @redaction, :method => "delete", :remote => true, :data => { :confirm => t(".confirm") } %>
+ <% end %>
</div>
<% end %>
<h1><%= t ".title_html", :link => link_to(reportable_title(@report.issue.reportable), reportable_url(@report.issue.reportable)) %></h1>
<% end %>
-<div class="report-disclaimer">
+<div class="alert alert-warning">
<%= t(".disclaimer.intro") %>
- <ul>
+ <ul class="mb-0">
<li> <%= t(".disclaimer.not_just_mistake") %> </li>
<li> <%= t(".disclaimer.unable_to_fix") %> </li>
<li> <%= t(".disclaimer.resolve_with_user") %> </li>
<%= form_for(@report) do |f| %>
<%= f.error_messages %>
- <fieldset>
+ <fieldset class="standard-form">
<%= f.fields_for @report.issue do |issue_form| %>
<%= issue_form.hidden_field :reportable_id %>
<%= issue_form.hidden_field :reportable_type %>
<% end %>
- <div class='form-row'>
+ <div class='standard-form-row'>
<p><%= t(".select") %></p>
- <ul>
+ <ul class="form-list">
<% Report.categories_for(@report.issue.reportable).each do |c| %>
<li>
<%= radio_button :report, :category, c, :required => true %>
- <%= label_tag "report_category_#{c}", t(".categories.#{@report.issue.reportable.class.name.underscore}.#{c}_label") %> <br />
+ <%= label_tag "report_category_#{c}", t(".categories.#{@report.issue.reportable.class.name.underscore}.#{c}_label") %>
</li>
<% end %>
</ul>
</div>
- <div class='form-row'>
+ <div class='standard-form-row'>
<%= text_area :report, :details, :cols => 20, :rows => 5, :placeholder => t(".details") %>
</div>
<% data[:lat] = @lat if @lat -%>
<% data[:lon] = @lon if @lon -%>
<% data[:zoom] = @zoom if @zoom -%>
- <%= content_tag :div, raw(t("site.edit.flash_player_required")), :id => "potlatch", :data => data %>
+ <%= content_tag :div, t("site.edit.flash_player_required_html"), :id => "potlatch", :data => data %>
</div>
<% end %>
<% data[:locale] = Locale.list(Potlatch2::LOCALES.keys).preferred(preferred_languages).to_s -%>
<% data[:locale_path] = asset_path("potlatch2/locales/#{Potlatch2::LOCALES[data[:locale]]}.swf") -%>
- <%= content_tag :div, raw(t("site.edit.flash_player_required")), :id => "potlatch", :data => data %>
+ <%= content_tag :div, t("site.edit.flash_player_required_html"), :id => "potlatch", :data => data %>
</div>
-<div class='attr'>
- <div class='byosm'>
- <%= t ".copyright_html" %>
- </div>
-
- <div class='user-image'></div>
+<%= tag.div :lang => @locale, :dir => t("html.dir", :locale => @locale) do %>
+ <div class='attr'>
+ <div class='byosm'>
+ <%= t ".copyright_html", :locale => @locale %>
+ </div>
- <h1><%= raw t ".used_by", :name => "<span class='user-name'>OpenStreetMap</span>" %></h1>
-</div>
+ <div class='user-image'></div>
-<div class='text'>
- <div class='section'>
- <p><strong><%= t ".lede_text" %></strong></p>
- <h2><div class='icon local'></div><%= t ".local_knowledge_title" %></h2>
- <p><%= t ".local_knowledge_html" %></p>
+ <h1><%= t ".used_by_html", :name => content_tag(:span, "OpenStreetMap", :class => "user-name"), :locale => @locale %></h1>
</div>
- <div class='section'>
- <h2><div class='icon community'></div><%= t ".community_driven_title" %></h2>
- <p><%= t ".community_driven_html", :diary_path => diary_entries_path %></p>
- </div>
+ <div class='text'>
+ <div class='section'>
+ <p><strong><%= t ".lede_text", :locale => @locale %></strong></p>
+ <h2><div class='icon local'></div><%= t ".local_knowledge_title", :locale => @locale %></h2>
+ <p><%= t ".local_knowledge_html", :locale => @locale %></p>
+ </div>
- <div class='section' id='open-data'>
- <h2><div class='icon open'></div><%= t ".open_data_title" %></h2>
- <p><%= t ".open_data_html", :copyright_path => copyright_path %></p>
- </div>
+ <div class='section'>
+ <h2><div class='icon community'></div><%= t ".community_driven_title", :locale => @locale %></h2>
+ <p><%= t ".community_driven_html", :locale => @locale, :diary_path => diary_entries_path %></p>
+ </div>
- <div class='section' id='legal'>
- <h2><div class='icon legal'></div><%= t ".legal_title" %></h2>
- <p><%= t ".legal_html" %></p>
- </div>
+ <div class='section' id='open-data'>
+ <h2><div class='icon open'></div><%= t ".open_data_title", :locale => @locale %></h2>
+ <p><%= t ".open_data_html", :locale => @locale, :copyright_path => copyright_path %></p>
+ </div>
+
+ <div class='section' id='legal'>
+ <h2><div class='icon legal'></div><%= t ".legal_title", :locale => @locale %></h2>
+ <p><%= t ".legal_1_html", :locale => @locale %></p>
+ <p><%= t ".legal_2_html", :locale => @locale %></p>
+ </div>
- <div class='section' id='partners'>
- <h2><div class='icon partners'></div><%= t ".partners_title" %></h2>
- <p><%= t "layouts.hosting_partners_html",
- :ucl => link_to(t("layouts.partners_ucl"), "https://www.ucl.ac.uk"),
- :bytemark => link_to(t("layouts.partners_bytemark"), "https://www.bytemark.co.uk"),
- :partners => link_to(t("layouts.partners_partners"), "https://hardware.openstreetmap.org/thanks/") %>
- </p>
+ <div class='section' id='partners'>
+ <h2><div class='icon partners'></div><%= t ".partners_title", :locale => @locale %></h2>
+ <p><%= t "layouts.hosting_partners_html", :locale => @locale,
+ :ucl => link_to(t("layouts.partners_ucl", :locale => @locale), "https://www.ucl.ac.uk"),
+ :bytemark => link_to(t("layouts.partners_bytemark", :locale => @locale), "https://www.bytemark.co.uk"),
+ :partners => link_to(t("layouts.partners_partners", :locale => @locale), "https://hardware.openstreetmap.org/thanks/") %>
+ </p>
+ </div>
</div>
-</div>
+<% end %>
<!-- Maybe ease foreigners back to their native page -->
<% if t(".legal_babble", :locale => I18n.locale) != t(".legal_babble", :locale => :en) %>
- <%= tag.h1 :lang => @locale, :dir => t("html.dir", :locale => @locale) do %>
+ <%= tag.div :lang => @locale, :dir => t("html.dir", :locale => @locale) do %>
<h1><%= t ".native.title" %></h1>
<p>
- <%= raw t ".native.text",
- :native_link => link_to(t(".native.native_link"),
- :controller => "site",
- :action => "copyright",
- :copyright_locale => nil),
- :mapping_link => link_to(t(".native.mapping_link"),
- :controller => "site",
- :action => "index") %>
+ <%= t ".native.html",
+ :native_link => link_to(t(".native.native_link"),
+ :controller => "site",
+ :action => "copyright",
+ :copyright_locale => nil),
+ :mapping_link => link_to(t(".native.mapping_link"),
+ :controller => "site",
+ :action => "index") %>
</p>
<% end %>
<hr />
<% end %>
<% else %>
<!-- Maybe note that this page has been translated -->
- <%= tag.div :lang => "en", :dir => t("html.dir", :locale => "en") do %>
- <% if t(".legal_babble", :locale => @locale) != t(".legal_babble", :locale => :en) %>
+ <% if t(".legal_babble", :locale => @locale) != t(".legal_babble", :locale => :en) %>
+ <%= tag.div :lang => "en", :dir => t("html.dir", :locale => "en") do %>
<h1><%= t ".foreign.title" %></h1>
<p>
- <%= raw t ".foreign.text",
- :english_original_link => link_to(t(".foreign.english_link"),
- :controller => "site",
- :action => "copyright",
- :copyright_locale => "en") %>
+ <%= t ".foreign.html",
+ :english_original_link => link_to(t(".foreign.english_link"),
+ :controller => "site",
+ :action => "copyright",
+ :copyright_locale => "en") %>
</p>
<% end %>
<hr />
<p><%= t "layouts.osm_read_only" %></p>
<% elsif !current_user.data_public? %>
<p><%= t ".not_public" %></p>
- <p><%= raw t ".not_public_description", :user_page => (link_to t(".user_page_link"), :controller => "user", :action => "account", :display_name => current_user.display_name, :anchor => "public") %></p>
- <p><%= raw t "site.edit.anon_edits", :link => link_to(t(".anon_edits_link_text"), t(".anon_edits_link")) %></p>
+ <p><%= t ".not_public_description_html", :user_page => (link_to t(".user_page_link"), :controller => "users", :action => "account", :display_name => current_user.display_name, :anchor => "public") %></p>
+ <p><%= t ".anon_edits_html", :link => link_to(t(".anon_edits_link_text"), t(".anon_edits_link")) %></p>
<% else %>
<%= render :partial => preferred_editor %>
<% end %>
</div>
<h4><%= t ".licence" %></h4>
- <p><%= raw t ".export_details" %></p>
+ <p><%= t ".export_details_html" %></p>
<div id="export_osm_too_large">
<p class="warning">
<% end %>
<h3><%= t "layouts.intro_header" %></h3>
-
<p><%= t "layouts.intro_text" %></p>
<h3><%= t ".how_to_help.title" %></h3>
-<div class='clearfix'>
- <div class='col6 inner11'>
- <h3><%= t ".how_to_help.join_the_community.title" %></h3>
- <%= t ".how_to_help.join_the_community.explanation_html" %>
- <div class='clearfix center'>
- <a class="button sign-up" href="<%= user_new_path %>"><%= t("layouts.start_mapping") %></a>
+<div class='container'>
+ <div class='row'>
+ <div class='col-sm'>
+ <h5><%= t ".how_to_help.join_the_community.title" %></h5>
+ <p><%= t ".how_to_help.join_the_community.explanation_html" %></p>
+ <p class='text-center'>
+ <a class="button sign-up" href="<%= user_new_path %>"><%= t("layouts.start_mapping") %></a>
+ </p>
+ </div>
+ <div class='col-sm'>
+ <h5><%= t "site.welcome.add_a_note.title" %></h5>
+ <p><%= t "site.welcome.add_a_note.paragraph_1_html" %></p>
+ <p><%= t ".how_to_help.add_a_note.instructions_html", :map_url => root_path %></p>
</div>
- </div>
- <div class='col6 inner11'>
- <h3><%= t "site.welcome.add_a_note.title" %></h3>
- <p><%= t "site.welcome.add_a_note.paragraph_1_html" %></p>
- <p><%= t ".how_to_help.add_a_note.instructions_html", :map_url => root_path %></p>
</div>
</div>
<h3><%= t ".other_concerns.title" %></h3>
<p><%= t ".other_concerns.explanation_html" %></p>
-<div class='col12 clearfix icon-list'>
- <h3><%= t "site.welcome.questions.title" %></h3>
- <span class='sprite small term question'></span>
- <p><%= t "site.welcome.questions.paragraph_1_html", :help_url => help_path %></p>
-</div>
+<h3><%= t "site.welcome.questions.title" %></h3>
+<span class='sprite small term question'></span>
+<p><%= t "site.welcome.questions.paragraph_1_html", :help_url => help_path %></p>
<p class='introduction'><%= t ".introduction" %></p>
-<% %w[welcome beginners_guide help mailing_lists forums irc switch2osm welcomemat wiki].each do |site| %>
- <% unless site == 'welcome' && !current_user %>
- <div class='<%= site %> help-item'>
- <h3>
- <a href='<%= t ".#{site}.url" %>'>
- <%= t ".#{site}.title" %>
- </a>
- </h3>
- <p><%= t ".#{site}.description" %></p>
+<% sites = %w[beginners_guide help mailing_lists forums irc switch2osm welcomemat wiki] %>
+<% sites.prepend("welcome") if current_user %>
+
+<% sites.in_groups_of(3, false) do |group| %>
+ <div class="card-deck mb-4">
+ <% group.each do |site| %>
+ <div class='<%= site %> help-item card'>
+ <div class='card-body'>
+ <h6 class='card-title'>
+ <a href='<%= t ".#{site}.url" %>'>
+ <%= t ".#{site}.title" %>
+ </a>
+ </h3>
+ <p class='card-text'><%= t ".#{site}.description" %></p>
+ </div>
+ <div class="card-footer">
+ <small>
+ <a href='<%= t ".#{site}.url" %>'>
+ <%= t ".#{site}.url" %>
+ </a>
+ </small>
+ </div>
+ </div>
+ <% end %>
</div>
- <% end %>
<% end %>
<div id="mapkey">
<table class="mapkey-table">
- <% YAML.load_file(Rails.root.join("config", "key.yml")).each do |name,data| %>
+ <% YAML.load_file(Rails.root.join("config/key.yml")).each do |name,data| %>
<% data.each do |entry| %>
<tr class="mapkey-table-entry" data-layer="<%= name %>" data-zoom-min="<%= entry["min_zoom"] %>" data-zoom-max="<%= entry["max_zoom"] %>">
<td class="mapkey-table-key">
<h3><%= t ".whats_on_the_map.title" %></h3>
-<div class=' clearfix'>
- <div class='col6 inner11'>
- <div class='center clearfix inner11'>
+<div class='row'>
+ <div class='col'>
+ <div class='center'>
<span class='sprite small check'></span>
</div>
<p><%= t ".whats_on_the_map.on_html" %></p>
</div>
- <div class='col6 inner11'>
- <div class='center clearfix inner11'>
+ <div class='col'>
+ <div class='center'>
<span class='sprite small x'></span>
</div>
<p><%= t ".whats_on_the_map.off_html" %></p>
<p><%= t ".basic_terms.paragraph_1_html" %></p>
-<div class='col12 clearfix icon-list'>
+<div class='clearfix icon-list'>
<div class='clearfix'>
<span class='sprite small term editor'></span>
<p><%= t ".basic_terms.editor_html" %></p>