diff --git a/Vendorfile b/Vendorfile
index 136b47f72..2d728ab1e 100644
--- a/Vendorfile
+++ b/Vendorfile
@@ -9,14 +9,13 @@ folder 'vendor/assets' do
end
folder 'leaflet' do
- file 'leaflet.js', 'http://cdn.leafletjs.com/leaflet-0.6.3/leaflet-src.js'
- file 'leaflet.css', 'http://cdn.leafletjs.com/leaflet-0.6.3/leaflet.css'
- file 'leaflet.ie.css', 'http://cdn.leafletjs.com/leaflet-0.6.3/leaflet.ie.css'
+ file 'leaflet.js', 'http://cdn.leafletjs.com/leaflet-0.7/leaflet-src.js'
+ file 'leaflet.css', 'http://cdn.leafletjs.com/leaflet-0.7/leaflet.css'
[ 'layers.png', 'layers-2x.png',
'marker-icon.png', 'marker-icon-2x.png',
'marker-shadow.png' ].each do |image|
- file "images/#{image}", "http://cdn.leafletjs.com/leaflet-0.6.3/images/#{image}"
+ file "images/#{image}", "http://cdn.leafletjs.com/leaflet-0.7/images/#{image}"
end
from 'git://github.com/kajic/leaflet-locationfilter.git' do
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 97ab5abfc..67e25c6a7 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -9,11 +9,7 @@ class ApplicationController < ActionController::Base
if session[:user]
@user = User.where(:id => session[:user]).where("status IN ('active', 'confirmed', 'suspended')").first
- if @user.display_name != cookies["_osm_username"]
- logger.info "Session user '#{@user.display_name}' does not match cookie user '#{cookies['_osm_username']}'"
- reset_session
- @user = nil
- elsif @user.status == "suspended"
+ if @user.status == "suspended"
session.delete(:user)
session_expires_automatically
diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb
index a9006e82b..99777ca2d 100644
--- a/app/controllers/user_controller.rb
+++ b/app/controllers/user_controller.rb
@@ -7,6 +7,7 @@ class UserController < ApplicationController
before_filter :authorize_web, :except => [:api_read, :api_details, :api_gpx_files]
before_filter :set_locale, :except => [:api_read, :api_details, :api_gpx_files]
before_filter :require_user, :only => [:account, :go_public, :make_friend, :remove_friend]
+ before_filter :require_self, :only => [:account]
before_filter :check_database_readable, :except => [:login, :api_read, :api_details, :api_gpx_files]
before_filter :check_database_writable, :only => [:new, :account, :confirm, :confirm_email, :lost_password, :reset_password, :go_public, :make_friend, :remove_friend]
before_filter :check_api_readable, :only => [:api_read, :api_details, :api_gpx_files]
@@ -338,7 +339,6 @@ class UserController < ApplicationController
token.destroy
session[:user] = user.id
- cookies.permanent["_osm_username"] = user.display_name
redirect_to referer || welcome_path
end
@@ -377,7 +377,6 @@ class UserController < ApplicationController
end
token.destroy
session[:user] = @user.id
- cookies.permanent["_osm_username"] = @user.display_name
redirect_to :action => 'account', :display_name => @user.display_name
else
flash[:error] = t 'user.confirm_email.failure'
@@ -638,8 +637,6 @@ private
##
# process a successful login
def successful_login(user)
- cookies.permanent["_osm_username"] = user.display_name
-
session[:user] = user.id
session_expires_after 28.days if session[:remember_me]
@@ -727,8 +724,6 @@ private
if user.save
set_locale
- cookies.permanent["_osm_username"] = user.display_name
-
if user.new_email.blank? or user.new_email == user.email
flash.now[:notice] = t 'user.account.flash update success'
else
@@ -769,6 +764,14 @@ private
end
end
+ ##
+ # require that the user in the URL is the logged in user
+ def require_self
+ if params[:display_name] != @user.display_name
+ render :text => "", :status => :forbidden
+ end
+ end
+
##
# ensure that there is a "this_user" instance variable
def lookup_user_by_id
diff --git a/app/views/export/embed.html.erb b/app/views/export/embed.html.erb
index b683c2665..6c3ebdd16 100644
--- a/app/views/export/embed.html.erb
+++ b/app/views/export/embed.html.erb
@@ -4,9 +4,6 @@
OpenStreetMap Embedded
<%= stylesheet_link_tag "embed", :media=> "screen" %>
-
<%= javascript_include_tag "embed" %>
diff --git a/app/views/layouts/_head.html.erb b/app/views/layouts/_head.html.erb
index 9951737bc..1897cfff3 100644
--- a/app/views/layouts/_head.html.erb
+++ b/app/views/layouts/_head.html.erb
@@ -8,7 +8,6 @@
<%= stylesheet_link_tag "print-#{dir}", :media => "print" %>
<%= stylesheet_link_tag "leaflet-all", :media => "screen, print" %>
<%= favicon_link_tag "favicon.ico" %>
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 7647ac082..5e0662e9f 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -11,6 +11,7 @@
# Author: CygnusOlor
# Author: Daswaldhorn
# Author: Diebuche
+# Author: Dieterdreist
# Author: Fujnky
# Author: Grille chompa
# Author: Holger
@@ -2067,7 +2068,7 @@ de:
questions:
paragraph_1_html: "Falls Du zusätzliche Hilfe beim Mapping brauchst oder etwas nicht klar ist, gibt es zusätzliche\nHilfe auf der Hilfe-Seite."
title: Fragen?
- start_mapping: Beginne mit dem Berarbeiten der Karte
+ start_mapping: Beginne mit dem Bearbeiten der Karte
title: Willkommen!
whats_on_the_map:
off_html: "Was nicht in die Datenbank gehört sind subjektive Daten wie Bewertungen, nicht mehr aktuelle\nhistorische Fakten oder nicht real existierende Dinge. Ausserdem ist es wichtig, nichts von\nanderen Quellen (auch nicht aus Papierkarten) zu kopieren, da OpenStreetMap das Urheberrecht sehr ernst nimmt."
diff --git a/config/locales/diq.yml b/config/locales/diq.yml
index c5b6ed397..1f5db228d 100644
--- a/config/locales/diq.yml
+++ b/config/locales/diq.yml
@@ -3,6 +3,7 @@
# Export driver: syck-pecl
# Author: Erdemaslancan
# Author: Gorizon
+# Author: Marmase
# Author: Mirzali
diq:
activerecord:
@@ -572,7 +573,7 @@ diq:
community_blogs: Blogê Cemaeti
documentation: Dokumentasyon
edit: Timar ke
- help: Peşti
+ help: Desteg
history: Ravêrden
intro_1: OpenStreetMap yew xeritey dınyayo u merduma hemın rê belaso.
intro_2_download: ronayış
@@ -694,6 +695,7 @@ diq:
where_am_i: Edo kotideya?
sidebar:
close: Racnê
+ search_results: Neticeya geyrayışi
time:
formats:
friendly: "%e %B %Y seate %H:%M"
@@ -730,7 +732,7 @@ diq:
trackable: SEYRKERDENEN
view_map: Xeriti Bımocnê
trace_form:
- help: Peşti
+ help: Desteg
tags: "Etiketi:"
upload_button: Bar ke
visibility: Vinayîşî
diff --git a/config/locales/el.yml b/config/locales/el.yml
index 2bcb0dd9a..845de71f3 100644
--- a/config/locales/el.yml
+++ b/config/locales/el.yml
@@ -51,7 +51,7 @@ el:
languages: Γλώσσες
pass_crypt: Κωδικός
models:
- acl: Πρόσβαση στη λίστα ελέγχου
+ acl: Πρόσβαση στη Λίστα Ελέγχου
changeset: Ομάδα Αλλαγών
changeset_tag: Ετικέτα Ομάδας Αλλαγών
country: Χώρα
@@ -140,7 +140,7 @@ el:
note: Προβολή της σημείωσης σε μεγαλύτερο χάρτη.
relation: Προβολή της σχέσης σε μεγαλύτερο χάρτη
way: Προβολή της διαδρομής σε μεγαλύτερο χάρτη.
- loading: Φόρτωση...
+ loading: Φόρτωση σε εξέλιξη...
navigation:
all:
next_changeset_tooltip: Επόμενη ομάδα αλλαγών
@@ -213,11 +213,11 @@ el:
view_history: Προβολή ιστορικού
relation_details:
members: "Μέλη:"
- part_of: "Μέρος του:"
+ part_of: "Μέλος του:"
relation_history:
download_xml: Λήψη XML
relation_history: Ιστορικό Σχέσης
- relation_history_title: "Ιστορικό σχέσης: %{relation_name}"
+ relation_history_title: "Ιστορικό Σχέσης: %{relation_name}"
view_details: Προβολή λεπτομερειών
relation_member:
entry: "%{type} %{name}"
@@ -235,9 +235,9 @@ el:
history_for_feature: Ιστορικό για %{feature}
load_data: Φόρτωση δεδομένων
loaded_an_area_with_num_features: "Έχετε φορτώσει μια περιοχή που περιέχει %{num_features} χαρακτηριστικά. Γενικά, μερικοί browsers μπορεί να μην αντέχουν να δείξουν τόσα πολλά στοιχεία. Γενικά, οι browsers δουλεύουν καλύτερα δείχνοντας λιγότερα από %{max_features} χαρακτηριστικά τη φορά: με οτιδήποτε άλλο ο browser μπορεί να γίνει αργός ή να μην αντιδρά. Αν είστε σίγουρος ότι θέλετε να δείτε αυτά τα δεδομένα, κάντε κλικ στο παρακάτω κουμπί."
- loading: Φόρτωση...
+ loading: Φόρτωση σε εξέλιξη...
manually_select: Χειροκίνητη επιλογή διαφορετικής περιοχής
- notes_layer_name: Περιήγηση στις Σημειώσεις
+ notes_layer_name: Περιήγηση Σημειώσεων
object_list:
api: Ανάκτηση περιοχής από το API
back: Πίσω στον κατάλογο αντικειμένων
@@ -256,11 +256,11 @@ el:
way: Διαδρομή
private_user: ιδιωτικός χρήστης
show_areas: Εμφάνιση περιοχών
- show_history: Προβολή ιστορικού
+ show_history: Προβολή Ιστορικού
unable_to_load_size: "Δεν είναι δυνατή η φόρτωση: το μέγεθος %{bbox_size} του πλαισίου οριοθέτησης είναι πολύ μεγάλο (πρέπει να είναι μικρότερο από %{max_bbox_size})"
- view_data: Προβολή δεδομένων στην τρέχουσα προβολή του χάρτη
+ view_data: Δείτε δεδομένα σχετικά με την τρέχουσα προβολή του χάρτη
wait: Αναμονή...
- zoom_or_select: Μεγέθυνση ή επιλογή περιοχής του χάρτη προς εμφάνιση
+ zoom_or_select: Μεγεθυνθείτε ή επιλέξτε την περιοχή του χάρτη προς εμφάνιση
tag_details:
tags: "Ετικέτες:"
wiki_link:
@@ -493,9 +493,11 @@ el:
search:
title:
ca_postcode: Αποτελέσματα από Geocoder.CA
- geonames: Αποτελέσματα από GeoNames
- latlon: Εσωτερικά αποτελέσματα
- osm_nominatim: Αποτελέσματα από OpenStreetMap Nominatim
+ geonames: Αποτελέσματα από το GeoNames
+ geonames_reverse: Αποτελέσματα από το GeoNames
+ latlon: Αποτελέσματα από την εσωτερική βάση δεδομένων
+ osm_nominatim: Αποτελέσματα από το OpenStreetMap Nominatim
+ osm_nominatim_reverse: Αποτελέσματα από το OpenStreetMap Nominatim
uk_postcode: Αποτέλεσμα από NPEMap / FreeThe Postcode
us_postcode: Αποτελέσματα από Geocoder.us
search_osm_nominatim:
@@ -1081,7 +1083,7 @@ el:
alt_text: Λογότυπο OpenStreetMap
logout: Αποσύνδεση
make_a_donation:
- text: Κάντε μια Δωρεά
+ text: Στηρίξτε μας
title: Υποστήριξε το OpenStreetMap με δωρεά χρημάτων
osm_offline: Η βάση δεδομένων του OpenStreetMap είναι προσωρινά εκτός λειτουργίας λόγω εργασιών συντήρησης της βάσης δεδομένων.
osm_read_only: Η βάση δεδομένων του OpenStreetMap είναι προσωρινά σε λειτουργία "μόνο για ανάγνωση" λόγω εργασιών συντήρησης της βάσης δεδομένων.
@@ -1453,6 +1455,7 @@ el:
track: Χωματόδρομος
tram:
1: τραμ
+ trunk: Αυτοκινητόδρομος
tunnel: Διακεκομμένο περίβλημα = σήραγγα
unclassified: Αταξινόμητη Οδός
unsurfaced: Δρόμος χωρίς Επίστρωση
diff --git a/config/locales/et.yml b/config/locales/et.yml
index a0e2c17c2..f6d045da7 100644
--- a/config/locales/et.yml
+++ b/config/locales/et.yml
@@ -1026,7 +1026,7 @@ et:
confirm: "Enne kasutajakonto loomist peame saama kinnituse, et see taotlus tuli sinult ja selleks klõpsa alloleval lingil:"
created: Keegi (loodetavasti sina) lõi äsja %{site_url} kasutajakonto.
greeting: Tere!
- subject: "[OpenStreetMap] Tere tulemast OpenStreetMap-i"
+ subject: "[OpenStreetMap] Tere tulemast OpenStreetMap'i"
welcome: Peale seda, kui oled kinnitanud enda konto pakume sulle lisainfot, et saaksid kasutamist hõlpsalt alustada.
oauth:
oauthorize:
@@ -1352,16 +1352,22 @@ et:
failed: Vabandust, kasutaja %{name} sõbraks lisamine ebaõnnestus.
success: "%{name} on nüüd sinu sõber."
new:
+ about:
+ header: Vaba ja muudetav
+ html: "Erinevalt teistest kaartidest on OpenStreetMap loodud samade inimeste poolt nagu sina ja igaüks võib seda parandada, täiendada, alla laadida ja kasutada.
\nRegistreeru, et alustada kaardi täiendamist. Me saadama sulle meili, et saaksid kinnitada oma kasutajakonto.
"
confirm email address: "Kinnita e-posti aadress:"
confirm password: "Kinnita parool:"
continue: Registreeru
display name: "Kuvatav nimi:"
display name description: Avalikult kuvatud kasutajanimi. Seda saate muuta hiljem eelistustes.
email address: "E-posti aadress:"
+ license_agreement: Oma kasutajakonto kinnitamiseks pead nõustuma kaastöö tingimustega.
not displayed publicly: Ei näidata avalikult (vaata privaatsusreegleid)
openid: "%{logo} OpenID:"
openid no password: OpenID kasutamisel ei ole parool kohustuslik, kuid mõned eritööriistad või serverid nõuavad seda siiski.
password: "Uus parool:"
+ terms accepted: Täname, et nõustusid uute kaastöö tingimustega!
+ terms declined: Meil on kahju, et otsustasid mitte nõustuda uute kaastöö tingimustega. Lisateabe saamiseks vaata seda wiki lehte.
title: Registreerumine
use openid: Teise võimalusena kasuta %{logo} OpenID sisselogimist
no_such_user:
@@ -1481,3 +1487,6 @@ et:
confirm: Kinnita
revoke:
confirm: Kinnita
+ welcome_page:
+ introduction_html: Tere tulemast OpenStreetMap'i, vabasse ja muudetavasse maailmakaarti. Registreerumine on nüüd tehtud ja sa võid alustada kaardistamist. Siin on lühiülevaade kõige olulisematest asjadest, mida peaksid teadma.
+ title: Tere tulemast!
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index b527352cd..43f0a94d2 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -2042,7 +2042,7 @@ fi:
tag_html: Tagi sisältää tietoja, joilla kerrotaan pisteen, viivan tai alueen käyttötarkoitus. Tällaisia tietoja on esimerkiksi ravintolan nimi tai kadun nopeusrajoitus.
title: Käsitteitä ja termistöä
way_html: Avoin viiva (engl. way) on viivamainen kohde, kuten katu tai joki. Suljettu viiva eli alue (engl. area) kuvaa aluetta, kuten järveä tai rakennusta.
- introduction_html: Tervetuloa OpenStreetMapiin, ilmaiseen ja vapaasti muokattavaan maailmankarttaan. Rekisteröityminen on nyt tehty, joten voit eiköhän aloiteta kartan muokkaaminen. Tutustu ensin kuitenkin näihin perusasioihin.
+ introduction_html: Tervetuloa OpenStreetMapiin, ilmaiseen ja vapaasti muokattavaan maailmankarttaan. Rekisteröityminen on nyt tehty, joten olet valmis aloittamaan kartan muokkaamisen. Tutustu ensin kuitenkin näihin perusasioihin.
questions:
paragraph_1_html: Tarvitsetko apua OpenStreetMapin käytössä tai muokkaamisessa? Tutustu OpenStreetMapin ohjekeskukseen.
title: Kysyttävää?
@@ -2050,5 +2050,5 @@ fi:
title: Tervetuloa!
whats_on_the_map:
off_html: Se ei sisällä mielipiteitä, kuten arvioita, historiallisia tai hypoteettisia ominaisuuksia, eikä tietoja tekijänoikeuksin suojatuista lähteistä. Ellei sinulla ole erityistä lupaa, älä kopioi verkko- tai paperikarttoja.
- on_html: OpenStreetMap on paikka kartoittaa asioita, jotka ovat sekä todellisia että nykyisiä - se sisältää miljoonia rakennuksia, teitä ja muita yksityiskohtia paikoista. Voit kartoittaa mitä tahansa reaalimaailman piirteitä, jotka sinua kiinnostavat.
+ on_html: OpenStreetMapissä voi kartoittaa asioita, jotka ovat sekä todellisia että nykyisiä - se sisältää miljoonia rakennuksia, teitä ja muita yksityiskohtia paikoista. Voit kartoittaa mitä tahansa reaalimaailman piirteitä, jotka sinua kiinnostavat.
title: Mitä on kartalla
diff --git a/config/locales/ia.yml b/config/locales/ia.yml
index 38c80df20..cf37b41f9 100644
--- a/config/locales/ia.yml
+++ b/config/locales/ia.yml
@@ -426,8 +426,20 @@ ia:
paste_html: Colla HTML pro incorporar in sito web
scale: Scala
too_large:
- body: Iste area es troppo grande pro esser exportate como datos XML de OpenStreetMap. Per favor face zoom avante o selige un area minor.
+ body: "Iste area es troppo grande pro esser exportate como datos XML de OpenStreetMap. Per favor face zoom avante, o selige un area minor, o usa un del sequente fontes pro discargamento de datos in massa:"
+ geofabrik:
+ description: Extractos regularmente actualisate de continentes, paises, e citates seligite
+ title: Discargamentos de Geofabrik
heading: Area troppo grande
+ metro:
+ description: Extractos de metropoles e lor areas circumvicin
+ title: Extractos de Metro
+ other:
+ description: Fontes additional listate in le wiki de OpenStreetMap
+ title: Altere fontes
+ planet:
+ description: Copias regularmente actualisate del base de datos complete de OpenStreetMap
+ title: Planeta OSM
zoom: Zoom
start_rjs:
add_marker: Adder un marcator al carta
@@ -465,8 +477,10 @@ ia:
title:
ca_postcode: Resultatos de Geocoder.CA
geonames: Resultatos de GeoNames
+ geonames_reverse: Resultatos ab GeoNames
latlon: Resultatos interne
osm_nominatim: Resultatos de OpenStreetMap Nominatim
+ osm_nominatim_reverse: Resultatos ab OpenStreetMap Nominatim
uk_postcode: Resultatos de NPEMap / FreeThe Postcode
us_postcode: Resultatos de Geocoder.us
search_osm_nominatim:
@@ -479,6 +493,10 @@ ia:
level8: Limite de citate
level9: Limite de village
prefix:
+ aerialway:
+ chair_lift: Telesedia
+ drag_lift: Teleski
+ station: Station de telecabina
aeroway:
aerodrome: Aerodromo
apron: Pista
@@ -572,6 +590,7 @@ ia:
shower: Ducha
social_centre: Centro social
social_club: Club social
+ social_facility: Servicio social
studio: Appartamento de un camera
supermarket: Supermercato
swimming_pool: Piscina
@@ -600,6 +619,9 @@ ia:
"yes": Ponte
building:
"yes": Edificio
+ emergency:
+ fire_hydrant: Hydrante de incendio
+ phone: Telephono de emergentia
highway:
bridleway: Sentiero pro cavallos
bus_guideway: Via guidate de autobus
@@ -621,6 +643,7 @@ ia:
platform: Platteforma
primary: Via principal
primary_link: Via principal
+ proposed: Strata proponite
raceway: Circuito
residential: Residential
rest_area: Area de reposo
@@ -632,6 +655,7 @@ ia:
speed_camera: Detector de velocitate
steps: Scalones
stile: Scalon o apertura de passage
+ street_lamp: Lanterna de strata
tertiary: Via tertiari
tertiary_link: Via tertiari
track: Pista
@@ -647,6 +671,7 @@ ia:
building: Edificio
castle: Castello
church: Ecclesia
+ citywalls: Muro del citate
fort: Forte
house: Casa
icon: Icone
@@ -656,6 +681,7 @@ ia:
monument: Monumento
museum: Museo
ruins: Ruinas
+ tomb: Tumba
tower: Turre
wayside_cross: Cruce juxta le via
wayside_shrine: Reliquario juxta le via
@@ -794,6 +820,7 @@ ia:
locality: Localitate
moor: Landa
municipality: Municipalitate
+ neighbourhood: Quartiero
postcode: Codice postal
region: Region
sea: Mar
@@ -819,8 +846,10 @@ ia:
narrow_gauge: Ferrovia stricte
platform: Platteforma ferroviari
preserved: Ferrovia preservate
+ proposed: Ferrovia proponite
spur: Ramification de ferrovia
station: Station ferroviari
+ stop: Halto ferroviari
subway: Station de metro
subway_entrance: Entrata al metro
switch: Agulia
@@ -836,6 +865,7 @@ ia:
beverages: Boteca de bibitas
bicycle: Magazin de bicyclettas
books: Libreria
+ boutique: Boutique
butcher: Macelleria
car: Magazin de automobiles
car_parts: Partes de automobiles
@@ -849,6 +879,7 @@ ia:
convenience: Magazin de quartiero
copyshop: Centro de photocopias
cosmetics: Boteca de cosmetica
+ deli: Boteca de delicatessas fin
department_store: Grande magazin
discount: Boteca de disconto
doityourself: Magazin de bricolage
@@ -885,17 +916,21 @@ ia:
organic: Boteca de alimentos organic
outdoor: Magazin de sport al aere libere
pet: Boteca de animales
+ pharmacy: Pharmacia
photo: Magazin de photographia
salon: Salon
+ second_hand: Magazin de secunde mano
shoes: Scarperia
shopping_centre: Centro commercial
sports: Magazin de sport
stationery: Papireria
supermarket: Supermercato
+ tailor: Sartor
toys: Magazin de joculos
travel_agency: Agentia de viages
video: Magazin de video
wine: Magazin de vinos
+ "yes": Boteca
tourism:
alpine_hut: Cabana alpin
artwork: Obra de arte
@@ -918,6 +953,7 @@ ia:
viewpoint: Puncto de vista
zoo: Jardin zoologic
tunnel:
+ culvert: Tubo de aqua subterranee
"yes": Tunnel
waterway:
artificial: Via aquatic artificial
@@ -980,12 +1016,14 @@ ia:
community_blogs: Blogs del communitate
community_blogs_title: Blogs de membros del communitate de OpenStreetMap
copyright: Copyright & Licentia
+ data: Datos
documentation: Documentation
documentation_title: Documentation pro le projecto
donate: Supporta OpenStreetMap per %{link} al Fundo de Actualisation de Hardware.
donate_link_text: donation
edit: Modificar
edit_with: Modificar con %{editor}
+ export_data: Exportar datos
foundation: Fundation
foundation_title: Le fundation OpenStreetMap
gps_traces: Tracias GPS
@@ -994,7 +1032,7 @@ ia:
help_centre: Centro de adjuta
help_title: Sito de adjuta pro le projecto
history: Historia
- home: initio
+ home: Vader al position de initio
intro_1: OpenStreetMap es un carta libere e modificabile del mundo integre. Illo es facite per gente como tu.
intro_2_create_account: Crea un conto de usator
intro_2_download: discargar
@@ -1006,7 +1044,7 @@ ia:
log_in_tooltip: Aperir un session con un conto existente
logo:
alt_text: Logo de OpenStreetMap
- logout: clauder session
+ logout: Clauder session
make_a_donation:
text: Facer un donation
title: Supporta OpenStreetMap con un donation monetari
@@ -1924,3 +1962,19 @@ ia:
fail: Impossibile revocar le rolo `%{role}' del usator `%{name}'. Verifica que e le usator e le rolo es valide.
heading: Confirmar le revocation del rolo
title: Confirmar le revocation del rolo
+ welcome_page:
+ basic_terms:
+ editor_html: Un editor es un programma o sito web que tu pote usar pro modificar le carta.
+ node_html: Un nodo es un puncto sur le carta, como un restaurante o un arbore individual.
+ paragraph_1_html: OpenStreetMap ha un jargon proprie. Ecce alcun parolas clave que te essera utile.
+ tag_html: Un etiquetta es un unitate de information sur un nodo o via, como le nomine de un restaurante o le limite de velocitate de un strata.
+ title: Vocabulario de base pro le cartographia
+ way_html: Un via es un linea o area, como un strata, fluxo, laco o edificio.
+ introduction_html: Bevenite a OpenStreetMap, le carta libere e modificabile del mundo. Ora que tu te ha inscribite, tu es preste a comenciar a cartographiar. Ecce un guida curte con le cosas le plus importante a saper.
+ questions:
+ title: Questiones?
+ title: Benvenite!
+ whats_on_the_map:
+ off_html: Illo non include datos subjective como punctos de appreciation, elementos historic o hypothetic. Le datos ab fontes sub copyright es equalmente excludite; non copia cosas ab cartas in linea o de papiro sin permission special!
+ on_html: OpenStreetMap es un loco pro cartographiar cosas real e actual; illo include milliones de edificios, stratas e altere detalios sur locos. Tu pote cartographiar qualcunque elemento del mundo real que te interessa.
+ title: Que es sur le carta?
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 9b8b472bb..83eafa9f1 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -1111,7 +1111,7 @@ it:
partners_ucl: UCL VR Centre
sign_up: iscriviti
sign_up_tooltip: Crea un profilo utente per apportare modifiche
- tag_line: La wiki-mappa Libera del Mondo
+ tag_line: La wiki-mappa libera del mondo
user_diaries: Diari degli utenti
user_diaries_tooltip: Visualizza diari utente
view: Visualizza
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 917f77e2d..9a685238d 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -95,7 +95,7 @@ ja:
not_a_moderator: モデレーター権限が必要な操作です。
setup_user_auth:
blocked: APIへのアクセスがブロックされました。Web インターフェイスからログインし直して詳細を確認してください。
- need_to_see_terms: あなたは一時的に API の利用を停止されています。ウェブ インターフェイスにログインして投稿者規約をご覧ください。同意しなくてもかまいませんが、必ずご覧ください。
+ need_to_see_terms: あなたは一時的にAPIの利用を停止されています。ウェブインターフェイスにログインして協力者規約をご覧ください。同意しなくてもかまいませんが、必ずご覧ください。
browse:
changeset:
changeset: "変更セット: %{id}"
@@ -992,13 +992,14 @@ ja:
key:
title: 凡例
tooltip: 凡例
+ tooltip_disabled: 標準レイヤーのみで利用可能な地図キー
map:
base:
cycle_map: サイクリングマップ
hot: Humanitarian
standard: 標準
transport_map: 交通マップ
- copyright: © OpenStreetMap への貢献者
+ copyright: © OpenStreetMapへの協力者
layers:
data: 地図データ
header: 地図のレイヤー
@@ -1033,10 +1034,13 @@ ja:
resolve: 解決
share:
cancel: キャンセル
+ center_marker: マーカーを地図の中心にする
+ custom_dimensions: 独自の寸法を設定
download: ダウンロード
embed: HTML
format: "形式:"
image: 画像
+ image_size: イメージの表示は標準レイヤー上で
include_marker: マーカーを含める
link: リンクまたは HTML
long_link: リンク
@@ -1118,6 +1122,8 @@ ja:
title: 権利表示の例
contributors_at_html: "オーストリア: Stadt Wien (ライセンス CC BY)、Land Vorarlberg、Land Tirol (ライセンス CC BY AT with amendments) によるデータを含みます。"
contributors_ca_html: "カナダ: GeoBase®、GeoGratis (© Department of Natural Resources Canada)、CanVec (© Department of Natural Resources Canada)、StatCan (Geography Division, Statistics Canada) によるデータを含みます。"
+ contributors_footer_1_html: これらの詳細について、またOpenStreetMapの向上に使用されたその他のソースについては、OpenStreetMap Wikiの協力者ページをご覧ください。
+ contributors_footer_2_html: OpenStreetMapのデータに含めることは、元データの提供者がOpenStreetMapを支持したり、何かしらの保証を行ったり、何かしらの責任を負ったりすることを意味するものではありません。
contributors_fr_html: "フランス: Direction Générale des Impôts によるデータを含みます。"
contributors_gb_html: "イギリス: 陸地測量データ © Crown copyright and database right 2010-12 を含みます。"
contributors_intro_html: 協力者は数千人もの個人です。それに加え、国立の地図作成組織や、次のようなその他の情報源による公開できるライセンスによるデータを含みます。
@@ -1125,11 +1131,12 @@ ja:
contributors_nz_html: "ニュージーランド: Land Information New Zealand によるデータを含みます。Crown が著作権を保持します。"
contributors_title_html: 協力者
contributors_za_html: "南アフリカ: Chief Directorate: National Geo-Spatial Information, State によるデータを含み、著作権を保持します。"
- credit_1_html: 「© OpenStreetMap への貢献者」のクレジットを必ず使用してください。
+ credit_1_html: 「© OpenStreetMapへの協力者」のクレジットを必ず使用してください。
credit_2_html: あなたはデータが Open Database License に基づいて提供されていること、そして地図タイルを使用する場合は、地図製作が CC BY-SA としてライセンスされていることを明確にしなければなりません。著作権表示ページにリンクすることでこれを表現することができます。また、データの形式でOSMを配布する場合の要件として、名前を表示の上、ライセンスに直接リンクすることができます。リンクを張れないメディア(印刷など)の場合は、openstreetmap.org(OpenStreetMapをアドレスとして展開した形)、opendatacommons.org、あと関連があれば、creativecommons.orgに誘導することをお勧めします。
credit_3_html: "閲覧可能な電子地図の場合は、地図の隅にクレジットを表示してください。\n例:"
credit_title_html: OpenStreetMap のクレジット表記の仕方
- infringement_1_html: "OSM の協力者は、著作権者から明確な許諾を得ずに、著作権のある情報源 (例: Google マップや印刷された地図) からデータを持ち込まないよう注意するものとします。"
+ infringement_1_html: "OSMの協力者は、著作権者から明確な許諾を得ずに、著作権のある情報源 (例: Google マップや印刷された地図) からデータを持ち込まないよう注意するものとします。"
+ infringement_2_html: もし著作権のある素材がOpenStreetMapのデータベースや本サイトに不正に追加されたとお考えの場合は、却下手順をお読みになるか、on-line filing pageから直接申し立てを行ってください。
infringement_title_html: 著作権侵害
intro_1_html: "OpenStreetMap はオープンデータであり、Open Data Commons Open Database License (ODbL) の下にライセンスされています。"
intro_2_html: OpenStreetMapとその協力者をクレジットすれば、データを自由にコピー、配布、送信、利用することができます。変更したり翻案したりしたデータは、同じライセンスに従って提供することができます。あなたの権利と責任は、ライセンス契約の全文で説明しています。
@@ -1215,6 +1222,8 @@ ja:
commented_at_html: "%{when}前に更新"
opened_at_by_html: "%{when}前に%{user}が作成"
opened_at_html: "%{when}前に作成"
+ reopened_at_by_html: "%{user}さんが%{when}に再開"
+ reopened_at_html: "%{when}前に再開"
entry:
comment: コメント
full: メモ全文
@@ -1234,6 +1243,7 @@ ja:
description_area: あなたのエリア [(%{min_lat}|%{min_lon}) -- (%{max_lat}|%{max_lon})] でレポート、コメント、またはクローズされたメモの一覧
description_item: メモ %{id} の RSS フィード
opened: 新しいメモ (%{place} 付近)
+ reopened: 再開されたメモ(%{place}付近)
title: OpenStreetMap メモ
notifier:
diary_comment_notification:
@@ -1287,13 +1297,24 @@ ja:
note_comment_notification:
anonymous: 匿名ユーザー
closed:
+ commented_note: "%{commenter}さんが、あなたがコメントした地図上の%{place}付近にあるメモを解決しました。"
+ subject_other: "[OpenStreetMap] %{commenter}さんが、あなたが関心を持っているメモを解決しました"
subject_own: "[OpenStreetMap] %{commenter} さんがあなたのメモを解決しました"
- your_note: "%{commenter} さんが %{place} 付近のあなたの地図メモの 1 つにコメントしました。"
+ your_note: "%{commenter}さんが%{place}付近にあるあなたの地図メモの1つを解決しました。"
commented:
+ commented_note: "%{commenter}さんがあなたがコメントした地図上の%{place}付近にあるメモにコメントしました。"
+ subject_other: "[OpenStreetMap] %{commenter}さんがあなたが関心を持っているメモにコメントしました"
subject_own: "[OpenStreetMap] %{commenter} さんがあなたのメモにコメントしました"
+ your_note: "%{commenter}さんが%{place}付近にあるあなたの地図メモの1つにコメントを残しました。"
details: メモについての詳細は %{url} を参照。
greeting: こんにちは。
+ reopened:
+ commented_note: "%{commenter}さんが、%{place}付近にあるあなたがコメントした地図メモを再開しました。"
+ subject_other: "[OpenStreetMap] %{commenter}さんがあなたが関心を持っているメモを再開しました"
+ subject_own: "[OpenStreetMap] %{commenter}さんがあなたのメモの1つを再開しました"
+ your_note: "%{commenter}さんが%{place}付近にあるあなたの地図メモの1つを再開しました。"
signup_confirm:
+ confirm: 私たちが他に何かする前に、この要求があなたのものであることを確認する必要がありますので、その後であなたのアカウントを確認するために下のリンクをクリックしてください。
created: 誰か (おそらくあなた) が %{site_url} でアカウントを作成しました。
greeting: やあ、皆さん!
subject: "[OpenStreetMap] OpenStreetMapへようこそ"
@@ -1403,17 +1424,22 @@ ja:
flash: 変更を保存しました。
site:
edit:
+ anon_edits_link_text: なぜこれれが事例なのかを見る。
flash_player_required: Flash 版 OpenStreetMap エディターである Potlatch を使用するには、Flash Player が必要です。Flash Player はAdobe.com でダウンロードできます。OpenStreetMap を編集する他の方法もあります。
+ id_not_configured: iDが設定されていません。
no_iframe_support: あなたのブラウザーは、この機能に必須の HTML iframe に未対応です。
not_public: あなたの編集結果を公開できません。
+ not_public_description: このようなことをしない限り、あなたは地図を編集できます。あなたは%{user_page}から編集内容を公開できます。
potlatch2_not_configured: "Potlatch 2 が設定されていません - 詳細情報はこちらをご覧ください: http://wiki.openstreetmap.org/wiki/The_Rails_Port#Potlatch_2"
potlatch2_unsaved_changes: 保存していない変更があります。(Potlatch 2 では、保存をクリックして保存する必要があります。)
potlatch_unsaved_changes: 保存していない変更があります。(Potlatch では、一覧モードで編集している場合、ウェイや点の選択を解除する必要があります。または、保存ボタンをクリックして保存してください。)
- user_page_link: ユーザー ページ
+ user_page_link: ユーザーページ
index:
createnote: メモを追加
js_1: JavaScript に対応していないブラウザーを使用しているか、JavaScript を無効にしているかのどちらかです。
js_2: OpenStreetMap は地図の表示に JavaScript を使用します。
+ license:
+ copyright: Copyright OpenStreetMapおよび協力者、オープンライセンスの下で
permalink: 固定リンク
remote_failed: 編集に失敗しました - JOSM または Merkaartor が読み込まれていること、遠隔制御オプションが有効になっていることを確認してください
shortlink: 短縮リンク
@@ -1559,10 +1585,12 @@ ja:
message: GPX ファイルのアップロード システムは現在利用できません
trace:
ago: "%{time_in_words_ago}前"
+ by: "投稿者:"
count_points: "%{count} 個の点"
edit: 編集
edit_map: 地図を編集
identifiable: 識別可能
+ in: "タグ:"
map: 地図
more: 詳細
pending: 処理中
@@ -1621,12 +1649,12 @@ ja:
user:
account:
contributor terms:
- agreed: あなたは、新しい投稿規約を承諾しています。
+ agreed: あなたは、新しい協力者規約を承諾しています。
agreed_with_pd: また、あなたは、自分の編集結果がパブリックドメインにあるべきだと考えているということも宣言しています。
- heading: "投稿規約:"
+ heading: "協力者規約:"
link text: これは何ですか?
not yet agreed: あなたはまだ新しい投稿規約を承諾していません。
- review link text: ご都合の良い時にこのリンクをクリックして新しい投稿規約をレビューの上、同意してください。
+ review link text: ご都合の良い時にこのリンクをクリックして新しい協力者規約を確認の上、同意してください。
current email address: "現在のメール アドレス:"
delete image: 現在の画像を削除
email never displayed publicly: (非公開)
@@ -1674,6 +1702,7 @@ ja:
button: 確認
heading: メールを確認してください
introduction_1: 確認メールをお送りしました。
+ introduction_2: メール内のリンクをクリックしてアカウントの確認をすれば、マッピングを始められます。
press confirm button: アカウントを有効にして良ければ、以下の確認ボタンを押してください。
reconfirm_html: 確認メールを再送する必要がある場合は、ここをクリックしてください。
unknown token: この確認コードは期限切れ、または存在しません。
@@ -1763,6 +1792,7 @@ ja:
new:
about:
header: フリー、編集可能
+ html: "他の地図とは異なり、OpenStreetMapは完全にあなたのような人々によって作成され、だれでも自由に修正、更新、ダウンロード、利用することができます。
\n協力を始めるにはサインアップしてください。あなたのアカウントの確認メールが送信されます。
"
confirm email address: "メール アドレスの確認:"
confirm password: "パスワードの確認:"
contact_webmaster: アカウントを作成できるよう、webmasterに連絡してください。 できるだけ早期に、あなたの希望に対応するように努めます。
@@ -1770,15 +1800,15 @@ ja:
display name: "表示名:"
display name description: 自分の公開ユーザー名です。あとで設定ページで変更できます。
email address: "メール アドレス:"
- license_agreement: アカウントを確認するときには contributor terms に同意する必要があります。
+ license_agreement: アカウントを確認するときには協力者規約に同意する必要があります。
no_auto_account_create: 残念ながら、現在、自動ではアカウントを作成できません。
not displayed publicly: 非公開です (詳細は プライバシー ポリシーを参照してください)
openid: "%{logo} OpenID:"
openid association: "あなたの OpenID は、まだ OpenStreetMap のどのアカウントとも関連付けられていません。
\n\n - OpenStreetMap が初めての場合は、下のフォームで新規アカウントを作成してください。
\n - \n 既にアカウントを持っている場合は、あなたのユーザー名とパスワードでログインしてください。\n ログイン後、ユーザー設定であなたの OpenID と関連付けることができます。\n
\n
"
openid no password: OpenID ではパスワードは不要ですが、特殊なツール/サーバーでは必要な場合があります。
password: "パスワード:"
- terms accepted: 新しい投稿規約に同意いただき、ありがとうございます!
- terms declined: 新しい投稿規約に同意いただけず残念です。詳しい情報は、このウィキページをご覧ください。
+ terms accepted: 新しい協力者規約に同意いただき、ありがとうございます!
+ terms declined: 新しい協力者規約に同意いただけず残念です。詳しい情報は、このウィキページをご覧ください。
terms declined url: http://wiki.openstreetmap.org/wiki/JA:Contributor_Terms_Declined
title: ユーザー登録
use openid: 代わりに、%{logo} OpenID を使用してログイン
@@ -1817,15 +1847,15 @@ ja:
decline: 拒否
declined: http://wiki.openstreetmap.org/wiki/JA:Contributor_Terms_Declined
guidance: この規約の理解を助ける情報として、要約 (英語) や 非公式の翻訳 をご覧ください。
- heading: 投稿規約
+ heading: 協力者規約
legale_names:
france: フランス
italy: イタリア
rest_of_world: それ以外の国
legale_select: "お住まいの国:"
- read and accept: 同意書を読み、あなたの既存および将来の投稿のために本同意書の条項を承諾することを確認するために同意ボタンを押してください。
- title: 投稿規約
- you need to accept or decline: 続行するには新しい投稿規約を読んで同意または拒否してください。
+ read and accept: 同意書を読み、あなたの既存および将来の協力のために本同意書の条項を承諾することを確認するために同意ボタンを押してください。
+ title: 協力者規約
+ you need to accept or decline: 続行するには新しい協力者規約を読んで同意または拒否してください。
view:
activate_user: このユーザーを有効にする
add as friend: 友達として追加
@@ -1840,7 +1870,7 @@ ja:
created from: "作成日:"
ct accepted: "%{ago}前に承認"
ct declined: 拒否
- ct status: "投稿規約:"
+ ct status: "協力者規約:"
ct undecided: 未決定
deactivate_user: このユーザーを無効にする
delete_user: このユーザーを削除
@@ -1906,6 +1936,7 @@ ja:
edit:
back: すべてのブロックを閲覧
heading: "%{name} のブロックの編集"
+ needs_view: このブロックを解消する前に、ユーザーがログインする必要がありますか?
period: ユーザーが今からどれくらいの間、APIからブロックされるか。
reason: "%{name} さんがブロックされている理由です。できるだけ冷静かつ理性的になり、できるだけ丁寧に状況を説明するようにしてください。すべてのユーザーがコミュニティ内での隠語を理解しているわけではないため、分かりやすい用語を使うように努めてください。"
show: このブロックを閲覧
@@ -1934,6 +1965,7 @@ ja:
submit: ブロックを作成
title: "%{name} のブロックの作成"
tried_contacting: ユーザーに連絡して、それらをやめるよう依頼しました。
+ tried_waiting: 私はユーザーとの対話に応じるために、合理的な時間を費やしました。
not_found:
back: 索引に戻る
sorry: 申し訳ありませんが、ID %{id} のユーザー ブロックは見つかりませんでした。
@@ -1997,6 +2029,8 @@ ja:
title: 権限取り消しの確認
welcome_page:
add_a_note:
+ paragraph_1_html: "些細な修正だけをしたいが、サインアップしたり編集の仕方を勉強する時間がない場合は、\n簡単にメモを追加できます。"
+ paragraph_2_html: 地図に移動してメモアイコン()をクリックするだけです。これで地図上に印が追加され、ドラッグして移動させることができます。あなたのメッセージを追加し、保存をクリックすれば、他のマッパーが調査するでしょう。
title: 編集する時間がないためメモを残します
basic_terms:
editor_html: エディターは、地図を編集できるプログラムやウェブサイトです。
@@ -2005,9 +2039,13 @@ ja:
tag_html: タグはノードやウェイについて補足するデータです。レストランの名前、道路の制限速度などが該当します。
title: マッピングのための基本的な用語
way_html: ウェイは線または領域です。道路、水路、湖、建物などが該当します。
+ introduction_html: フリーで編集可能な世界地図、OpenStreetMapへようこそ。サインアップしたので、マッピングの準備はすべて整いました。知っておかなければならない重要事項を簡単に説明します。
questions:
+ paragraph_1_html: マッピングで分からないことがありますか?OpenStreetMapの使い方で不明な点はありますか?ヘルプのウェブサイトで疑問の回答を得てください。
title: 何か質問はありますか?
start_mapping: マッピングを開始
title: ようこそ!
whats_on_the_map:
+ off_html: 含めてはいけないものは、評価のような主観的なデータ、歴史的または仮想的なもの、著作権のある情報源からのデータです。特別な許可がない場合は、オンラインや紙の地図からコピーをしてはいけません。
+ on_html: OpenStreetMapは現実かつ現存のもの――数々の建物、道路、場所に関するその他の詳細をマッピングする場所です。あなたは関心のある現実世界のものを何でもマッピングできます。
title: 地図上にあるもの
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index 3dda0fa40..27327ff57 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -1069,7 +1069,7 @@ ko:
help_title: 프로젝트에 대한 도움말 사이트
history: 역사
home: 집 위치로 가기
- intro_1: OpenStreetMap은 여러분같은 사람에 의해 만들어진 우리 모두의 전세계 지도입니다.
+ intro_1: OpenStreetMap은 여러분 같은 사람에 의해 만들어진 자유로운 전세계 지도입니다.
intro_2_create_account: 사용자 계정을 만드세요
intro_2_download: 다운로드
intro_2_html: 데이터는 %{license}에 따라 자유롭게 %{download}와 %{use}할 수 있습니다. 지도를 개선하려면 %{create_account}.
diff --git a/config/locales/lv.yml b/config/locales/lv.yml
index fb49ebb0a..3ff4a9f5f 100644
--- a/config/locales/lv.yml
+++ b/config/locales/lv.yml
@@ -485,8 +485,10 @@ lv:
title:
ca_postcode: Rezultāti no Geocoder.CA
geonames: Rezultāti no GeoNames
+ geonames_reverse: Rezultāti no GeoNames
latlon: Rezultāti no Iekšējās meklēšanas
osm_nominatim: Rezultāti no OpenStreetMap Nominatim
+ osm_nominatim_reverse: Rezultāti no OpenStreetMap Nominatim
uk_postcode: Rezultāti no NPEMap / FreeThe Postcode
us_postcode: Rezultāti no Geocoder.us
search_osm_nominatim:
@@ -993,6 +995,7 @@ lv:
map:
base:
cycle_map: Velokarte
+ hot: Humanitārās
standard: Standarta
transport_map: Transporta karte
copyright: © OpenStreetMap ieguldītāji
@@ -1545,6 +1548,9 @@ lv:
delete:
scheduled_for_deletion: Trase atzīmēta dzēšanai
description:
+ description_with_count:
+ one: GPX fails ar %{count} punktu no %{user}
+ other: GPX fails ar %{count} punktiem no %{user}
description_without_count: GPX fails no %{user}
edit:
description: "Apraksts:"
@@ -1563,6 +1569,8 @@ lv:
uploaded_at: "Augšupielādēts:"
visibility: "Redzamība:"
visibility_help: ko tas nozīmē?
+ georss:
+ title: OpenStreetMap GPS Trases
list:
description: Pārlūkot jaunākas GPS trases augšupielādes.
empty_html: Pašlaik šeit nekā nav. Augšupielādē jaunu trasi vai uzzini vairāk par GPS trasēm iekš wiki lapas.
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index 450d9ae08..7fe24a9b3 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -486,8 +486,10 @@ sl:
title:
ca_postcode: Zadetki iz Geocoder.CA
geonames: Zadetki iz GeoNames
+ geonames_reverse: Zadetki iz GeoNames
latlon: Interni zadetki
osm_nominatim: Zadetki iz OpenStreetMap Nominatim
+ osm_nominatim_reverse: Zadetki iz OpenStreetMap Nominatim-a
uk_postcode: Zadetki iz NPEMap / FreeThe Postcode
us_postcode: Zadetki iz Geocoder.us
search_osm_nominatim:
@@ -687,6 +689,7 @@ sl:
monument: Spomenik
museum: Muzej
ruins: Ruševine
+ tomb: Grobnica
tower: Stolp
wayside_cross: Križ
wayside_shrine: Kapelica
@@ -999,6 +1002,7 @@ sl:
header: Plasti zemljevida
notes: Opombe na zemljevidu
overlays: Omogočite prekrivke za odpravljanje težav na zemljevidu
+ title: Plasti
locate:
popup: Ste v razdalji {distance} {unit} od te točke
title: Pokaži mojo lokacijo
@@ -1010,13 +1014,19 @@ sl:
add: Dodaj opombo
show:
anonymous_warning: To opomba vključuje pripombe anonimnih uporabnikov, ki bi morale biti posamezno preverjene.
+ closed_by: razrešil %{user} ob %{time}
+ closed_by_anonymous: razrešil anonimnež ob %{time}
comment: Komentar
comment_and_resolve: Komentiraj in razreši
+ commented_by: komentar uporabnika %{user} ob %{time}
+ commented_by_anonymous: Anonimni komentar ob %{time}
hide: Skrij
opened_by: ustvaril/-a %{user} ob %{time}
opened_by_anonymous: ustvaril anonimni uporabnik %{time}
permalink: Trajna povezava
reactivate: Znova aktiviraj
+ reopened_by: ponovno aktiviral %{user} ob %{time}
+ reopened_by_anonymous: ponovno aktiviral anonimnež ob %{time}
resolve: Razreši
share:
cancel: Prekliči
@@ -1857,6 +1867,7 @@ sl:
my diary: Moj dnevnik
my edits: Moji prispevki
my notes: Moje beležke
+ my profile: Moj profil
my settings: Moje nastavitve
my traces: Moje sledi
nearby users: Drugi bližnji uporabniki
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index 5c802bc74..ba874d1da 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -96,7 +96,7 @@ sv:
user_token: Användarnyckel
way: Sträcka
way_node: Sträcknod
- way_tag: Sträcktagg
+ way_tag: Vägtagg
application:
require_cookies:
cookies_needed: Du verkar ha inaktiverat cookies - aktivera cookies i din webbläsare innan du fortsätter.
diff --git a/test/functional/diary_entry_controller_test.rb b/test/functional/diary_entry_controller_test.rb
index 7e0f10790..8725def3d 100644
--- a/test/functional/diary_entry_controller_test.rb
+++ b/test/functional/diary_entry_controller_test.rb
@@ -86,8 +86,6 @@ class DiaryEntryControllerTest < ActionController::TestCase
end
def test_showing_new_diary_entry
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
get :new
assert_response :redirect
assert_redirected_to :controller => :user, :action => "login", :referer => "/diary/new"
@@ -125,7 +123,6 @@ class DiaryEntryControllerTest < ActionController::TestCase
end
def test_editing_diary_entry
- @request.cookies["_osm_username"] = users(:normal_user).display_name
entry = diary_entries(:normal_user_entry_1)
# Make sure that you are redirected to the login page when you are
@@ -217,8 +214,6 @@ class DiaryEntryControllerTest < ActionController::TestCase
end
end
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# and when not logged in as the user who wrote the entry
get :view, {:display_name => entry.user.display_name, :id => entry.id}, {'user' => entry.user.id}
assert_response :success
@@ -251,16 +246,12 @@ class DiaryEntryControllerTest < ActionController::TestCase
end
def test_edit_diary_entry_i18n
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
get :edit, {:display_name => users(:normal_user).display_name, :id => diary_entries(:normal_user_entry_1).id}, {'user' => users(:normal_user).id}
assert_response :success
assert_select "span[class=translation_missing]", false, "Missing translation in edit diary entry"
end
def test_create_diary_entry
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Make sure that you are redirected to the login page when you
# are not logged in
get :new
@@ -320,7 +311,6 @@ class DiaryEntryControllerTest < ActionController::TestCase
end
def test_creating_diary_comment
- @request.cookies["_osm_username"] = users(:public_user).display_name
entry = diary_entries(:normal_user_entry_1)
# Make sure that you are denied when you are not logged in
@@ -472,16 +462,12 @@ class DiaryEntryControllerTest < ActionController::TestCase
assert_response :forbidden
assert_equal true, DiaryEntry.find(diary_entries(:normal_user_entry_1).id).visible
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Now try as a normal user
post :hide, {:display_name => users(:normal_user).display_name, :id => diary_entries(:normal_user_entry_1).id}, {:user => users(:normal_user).id}
assert_response :redirect
assert_redirected_to :action => :view, :display_name => users(:normal_user).display_name, :id => diary_entries(:normal_user_entry_1).id
assert_equal true, DiaryEntry.find(diary_entries(:normal_user_entry_1).id).visible
- @request.cookies["_osm_username"] = users(:administrator_user).display_name
-
# Finally try as an administrator
post :hide, {:display_name => users(:normal_user).display_name, :id => diary_entries(:normal_user_entry_1).id}, {:user => users(:administrator_user).id}
assert_response :redirect
@@ -495,16 +481,12 @@ class DiaryEntryControllerTest < ActionController::TestCase
assert_response :forbidden
assert_equal true, DiaryComment.find(diary_comments(:comment_for_geo_post).id).visible
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Now try as a normal user
post :hidecomment, {:display_name => users(:normal_user).display_name, :id => diary_entries(:normal_user_geo_entry).id, :comment => diary_comments(:comment_for_geo_post).id}, {:user => users(:normal_user).id}
assert_response :redirect
assert_redirected_to :action => :view, :display_name => users(:normal_user).display_name, :id => diary_entries(:normal_user_geo_entry).id
assert_equal true, DiaryComment.find(diary_comments(:comment_for_geo_post).id).visible
- @request.cookies["_osm_username"] = users(:administrator_user).display_name
-
# Finally try as an administrator
post :hidecomment, {:display_name => users(:normal_user).display_name, :id => diary_entries(:normal_user_geo_entry).id, :comment => diary_comments(:comment_for_geo_post).id}, {:user => users(:administrator_user).id}
assert_response :redirect
diff --git a/test/functional/message_controller_test.rb b/test/functional/message_controller_test.rb
index f015b1ec3..77fdfbeb9 100644
--- a/test/functional/message_controller_test.rb
+++ b/test/functional/message_controller_test.rb
@@ -53,7 +53,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as a normal user
session[:user] = users(:normal_user).id
- cookies["_osm_username"] = users(:normal_user).display_name
# Check that the new message page loads
get :new, :display_name => users(:public_user).display_name
@@ -106,7 +105,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as the wrong user
session[:user] = users(:second_public_user).id
- cookies["_osm_username"] = users(:second_public_user).display_name
# Check that we can't reply to somebody else's message
get :reply, :message_id => messages(:unread_message).id
@@ -115,7 +113,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as the right user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that the message reply page loads
get :reply, :message_id => messages(:unread_message).id
@@ -149,7 +146,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as the wrong user
session[:user] = users(:second_public_user).id
- cookies["_osm_username"] = users(:second_public_user).display_name
# Check that we can't read the message
get :read, :message_id => messages(:unread_message).id
@@ -158,7 +154,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as the message sender
session[:user] = users(:normal_user).id
- cookies["_osm_username"] = users(:normal_user).display_name
# Check that the message sender can read the message
get :read, :message_id => messages(:unread_message).id
@@ -168,7 +163,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as the message recipient
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that the message recipient can read the message
get :read, :message_id => messages(:unread_message).id
@@ -196,7 +190,6 @@ class MessageControllerTest < ActionController::TestCase
# Login
session[:user] = users(:normal_user).id
- cookies["_osm_username"] = users(:normal_user).display_name
# Check that we can view our inbox when logged in
get :inbox, :display_name => users(:normal_user).display_name
@@ -221,7 +214,6 @@ class MessageControllerTest < ActionController::TestCase
# Login
session[:user] = users(:normal_user).id
- cookies["_osm_username"] = users(:normal_user).display_name
# Check that we can view our outbox when logged in
get :outbox, :display_name => users(:normal_user).display_name
@@ -246,7 +238,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as a user with no messages
session[:user] = users(:second_public_user).id
- cookies["_osm_username"] = users(:second_public_user).display_name
# Check that marking a message we didn't send or receive fails
post :mark, :message_id => messages(:read_message).id
@@ -255,7 +246,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as the message recipient
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that the marking a message read works
post :mark, :message_id => messages(:unread_message).id, :mark => "read"
@@ -299,7 +289,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as a user with no messages
session[:user] = users(:second_public_user).id
- cookies["_osm_username"] = users(:second_public_user).display_name
# Check that deleting a message we didn't send or receive fails
post :delete, :message_id => messages(:read_message).id
@@ -308,7 +297,6 @@ class MessageControllerTest < ActionController::TestCase
# Login as the message recipient
session[:user] = users(:normal_user).id
- cookies["_osm_username"] = users(:normal_user).display_name
# Check that the deleting a received message works
post :delete, :message_id => messages(:read_message).id
diff --git a/test/functional/redactions_controller_test.rb b/test/functional/redactions_controller_test.rb
index a2bd75b10..83bb3adc2 100644
--- a/test/functional/redactions_controller_test.rb
+++ b/test/functional/redactions_controller_test.rb
@@ -39,7 +39,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_moderators_can_create
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
post :create, :redaction => { :title => "Foo", :description => "Description here." }
assert_response :redirect
@@ -48,7 +47,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_non_moderators_cant_create
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
post :create, :redaction => { :title => "Foo", :description => "Description here." }
assert_response :forbidden
@@ -56,7 +54,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_moderators_can_delete_empty
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# remove all elements from the redaction
redaction = redactions(:example)
@@ -71,7 +68,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_moderators_cant_delete_nonempty
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# leave elements in the redaction
redaction = redactions(:example)
@@ -84,7 +80,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_non_moderators_cant_delete
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
delete :destroy, :id => redactions(:example).id
assert_response :forbidden
@@ -92,7 +87,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_moderators_can_edit
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
get :edit, :id => redactions(:example).id
assert_response :success
@@ -100,7 +94,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_non_moderators_cant_edit
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
get :edit, :id => redactions(:example).id
assert_response :redirect
@@ -109,7 +102,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_moderators_can_update
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
redaction = redactions(:example)
@@ -120,7 +112,6 @@ class RedactionsControllerTest < ActionController::TestCase
def test_non_moderators_cant_update
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
redaction = redactions(:example)
diff --git a/test/functional/site_controller_test.rb b/test/functional/site_controller_test.rb
index 00a184ba8..2db756ad1 100644
--- a/test/functional/site_controller_test.rb
+++ b/test/functional/site_controller_test.rb
@@ -132,8 +132,6 @@ class SiteControllerTest < ActionController::TestCase
# test the right editor gets used when the user hasn't set a preference
def test_edit_without_preference
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
get(:edit, nil, { 'user' => users(:public_user).id })
assert_response :success
assert_template :partial => "_#{DEFAULT_EDITOR}", :count => 1
@@ -141,8 +139,6 @@ class SiteControllerTest < ActionController::TestCase
# and when they have...
def test_edit_with_preference
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
user = users(:public_user)
user.preferred_editor = "potlatch"
user.save!
@@ -161,8 +157,6 @@ class SiteControllerTest < ActionController::TestCase
end
def test_edit_with_node
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
user = users(:public_user)
node = current_nodes(:visible_node)
@@ -172,8 +166,6 @@ class SiteControllerTest < ActionController::TestCase
end
def test_edit_with_way
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
user = users(:public_user)
way = current_ways(:visible_way)
@@ -183,8 +175,6 @@ class SiteControllerTest < ActionController::TestCase
end
def test_edit_with_gpx
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
user = users(:public_user)
gpx = gpx_files(:public_trace_file)
diff --git a/test/functional/trace_controller_test.rb b/test/functional/trace_controller_test.rb
index 57d6f4916..1a074082b 100644
--- a/test/functional/trace_controller_test.rb
+++ b/test/functional/trace_controller_test.rb
@@ -171,8 +171,6 @@ class TraceControllerTest < ActionController::TestCase
# Check that I can get mine
def test_list_mine
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# First try to get it when not logged in
get :mine
assert_redirected_to :controller => 'user', :action => 'login', :referer => '/traces/mine'
@@ -196,14 +194,10 @@ class TraceControllerTest < ActionController::TestCase
get :list, :display_name => users(:public_user).display_name
check_trace_list users(:public_user).traces.public
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Should still see only public ones when authenticated as another user
get :list, {:display_name => users(:public_user).display_name}, {:user => users(:normal_user).id}
check_trace_list users(:public_user).traces.public
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Should see all traces when authenticated as the target user
get :list, {:display_name => users(:public_user).display_name}, {:user => users(:public_user).id}
check_trace_list users(:public_user).traces
@@ -234,14 +228,10 @@ class TraceControllerTest < ActionController::TestCase
get :view, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}
check_trace_view gpx_files(:public_trace_file)
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Now with some other user, which should work since the trace is public
get :view, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
check_trace_view gpx_files(:public_trace_file)
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# And finally we should be able to do it with the owner of the trace
get :view, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
check_trace_view gpx_files(:public_trace_file)
@@ -254,15 +244,11 @@ class TraceControllerTest < ActionController::TestCase
assert_response :redirect
assert_redirected_to :action => :list
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Now with some other user, which should work since the trace is anon
get :view, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:normal_user).id}
assert_response :redirect
assert_redirected_to :action => :list
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# And finally we should be able to do it with the owner of the trace
get :view, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:public_user).id}
check_trace_view gpx_files(:anon_trace_file)
@@ -275,8 +261,6 @@ class TraceControllerTest < ActionController::TestCase
assert_response :redirect
assert_redirected_to :action => :list
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Now with some other user, which should work since the trace is public
get :view, {:display_name => users(:public_user).display_name, :id => 0}, {:user => users(:public_user).id}
assert_response :redirect
@@ -294,14 +278,10 @@ class TraceControllerTest < ActionController::TestCase
get :data, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}
check_trace_data gpx_files(:public_trace_file)
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Now with some other user, which should work since the trace is public
get :data, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
check_trace_data gpx_files(:public_trace_file)
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# And finally we should be able to do it with the owner of the trace
get :data, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
check_trace_data gpx_files(:public_trace_file)
@@ -328,14 +308,10 @@ class TraceControllerTest < ActionController::TestCase
get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}
assert_response :not_found
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Now with some other user, which should work since the trace is anon
get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:normal_user).id}
assert_response :not_found
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# And finally we should be able to do it with the owner of the trace
get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:public_user).id}
check_trace_data gpx_files(:anon_trace_file)
@@ -347,8 +323,6 @@ class TraceControllerTest < ActionController::TestCase
get :data, {:display_name => users(:public_user).display_name, :id => 0}
assert_response :not_found
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Now with some other user, which should work since the trace is public
get :data, {:display_name => users(:public_user).display_name, :id => 0}, {:user => users(:public_user).id}
assert_response :not_found
@@ -365,8 +339,6 @@ class TraceControllerTest < ActionController::TestCase
assert_response :redirect
assert_redirected_to :controller => :user, :action => :login, :referer => trace_edit_path(:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id)
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Now with some other user, which should fail
get :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
assert_response :forbidden
@@ -379,8 +351,6 @@ class TraceControllerTest < ActionController::TestCase
get :edit, {:display_name => users(:public_user).display_name, :id => gpx_files(:deleted_trace_file).id}, {:user => users(:public_user).id}
assert_response :not_found
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Finally with a trace that we are allowed to edit
get :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
assert_response :success
@@ -395,8 +365,6 @@ class TraceControllerTest < ActionController::TestCase
post :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id, :trace => new_details}
assert_response :forbidden
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Now with some other user, which should fail
post :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id, :trace => new_details}, {:user => users(:public_user).id}
assert_response :forbidden
@@ -409,8 +377,6 @@ class TraceControllerTest < ActionController::TestCase
post :edit, {:display_name => users(:public_user).display_name, :id => gpx_files(:deleted_trace_file).id, :trace => new_details}, {:user => users(:public_user).id}
assert_response :not_found
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Finally with a trace that we are allowed to edit
post :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id, :trace => new_details}, {:user => users(:normal_user).id}
assert_response :redirect
@@ -427,8 +393,6 @@ class TraceControllerTest < ActionController::TestCase
post :delete, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id,}
assert_response :forbidden
- @request.cookies["_osm_username"] = users(:public_user).display_name
-
# Now with some other user, which should fail
post :delete, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
assert_response :forbidden
@@ -441,8 +405,6 @@ class TraceControllerTest < ActionController::TestCase
post :delete, {:display_name => users(:public_user).display_name, :id => gpx_files(:deleted_trace_file).id}, {:user => users(:public_user).id}
assert_response :not_found
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Finally with a trace that we are allowed to delete
post :delete, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
assert_response :redirect
diff --git a/test/functional/user_blocks_controller_test.rb b/test/functional/user_blocks_controller_test.rb
index 39ebfd28e..49fb6552f 100644
--- a/test/functional/user_blocks_controller_test.rb
+++ b/test/functional/user_blocks_controller_test.rb
@@ -101,7 +101,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as the blocked user
session[:user] = users(:blocked_user).id
- cookies["_osm_username"] = users(:blocked_user).display_name
# Now viewing it should mark it as seen
get :show, :id => user_blocks(:active_block)
@@ -118,7 +117,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a normal user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that normal users can't load the block creation page
get :new, :display_name => users(:normal_user).display_name
@@ -127,7 +125,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a moderator
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# Check that the block creation page loads for moderators
get :new, :display_name => users(:normal_user).display_name
@@ -162,7 +159,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a normal user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that normal users can't load the block edit page
get :edit, :id => user_blocks(:active_block).id
@@ -171,7 +167,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a moderator
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# Check that the block edit page loads for moderators
get :edit, :id => user_blocks(:active_block).id
@@ -204,7 +199,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a normal user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that normal users can't create blocks
post :create
@@ -212,7 +206,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a moderator
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# A bogus block period should result in an error
assert_no_difference "UserBlock.count" do
@@ -263,7 +256,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a normal user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that normal users can't update blocks
put :update, :id => user_blocks(:active_block).id
@@ -271,7 +263,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as the wrong moderator
session[:user] = users(:second_moderator_user).id
- cookies["_osm_username"] = users(:second_moderator_user).display_name
# Check that only the person who created a block can update it
assert_no_difference "UserBlock.count" do
@@ -285,7 +276,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as the correct moderator
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# A bogus block period should result in an error
assert_no_difference "UserBlock.count" do
@@ -331,7 +321,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a normal user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Check that normal users can't load the block revoke page
get :revoke, :id => user_blocks(:active_block).id
@@ -340,7 +329,6 @@ class UserBlocksControllerTest < ActionController::TestCase
# Login as a moderator
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# Check that the block revoke page loads for moderators
get :revoke, :id => user_blocks(:active_block).id
diff --git a/test/functional/user_controller_test.rb b/test/functional/user_controller_test.rb
index cba27f852..66fcef785 100644
--- a/test/functional/user_controller_test.rb
+++ b/test/functional/user_controller_test.rb
@@ -351,17 +351,12 @@ class UserControllerTest < ActionController::TestCase
def test_user_terms_seen
user = users(:normal_user)
- # Set the username cookie
- @request.cookies["_osm_username"] = user.display_name
-
get :terms, {}, { "user" => user }
assert_response :redirect
assert_redirected_to :action => :account, :display_name => user.display_name
end
def test_user_go_public
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
post :go_public, {}, { :user => users(:normal_user) }
assert_response :redirect
assert_redirected_to :action => :account, :display_name => users(:normal_user).display_name
@@ -460,20 +455,15 @@ class UserControllerTest < ActionController::TestCase
# validation errors being reported
user = users(:normal_user)
- # Set the username cookie
- @request.cookies["_osm_username"] = user.display_name
-
# Make sure that you are redirected to the login page when
# you are not logged in
get :account, { :display_name => user.display_name }
assert_response :redirect
assert_redirected_to :controller => :user, :action => "login", :referer => "/user/test/account"
- # Make sure that you are redirected to the login page when
- # you are not logged in as the right user
+ # Make sure that you are blocked when not logged in as the right user
get :account, { :display_name => user.display_name }, { "user" => users(:public_user).id }
- assert_response :redirect
- assert_redirected_to :controller => :user, :action => "login", :referer => "/user/test/account"
+ assert_response :forbidden
# Make sure we get the page when we are logged in as the right user
get :account, { :display_name => user.display_name }, { "user" => user }
@@ -490,8 +480,8 @@ class UserControllerTest < ActionController::TestCase
assert_select "form#accountForm > fieldset > div.form-row > div#user_description_container > div#user_description_content > textarea#user_description", user.description
# Changing name to one that exists should fail
- user.display_name = users(:public_user).display_name
- post :account, { :display_name => user.display_name, :user => user.attributes }, { "user" => user.id }
+ new_attributes = user.attributes.dup.merge(:display_name => users(:public_user).display_name)
+ post :account, { :display_name => user.display_name, :user => new_attributes }, { "user" => user.id }
assert_response :success
assert_template :account
assert_select "div#notice", false
@@ -499,8 +489,8 @@ class UserControllerTest < ActionController::TestCase
assert_select "form#accountForm > fieldset > div.form-row > div.field_with_errors > input#user_display_name"
# Changing name to one that exists should fail, regardless of case
- user.display_name = users(:public_user).display_name.upcase
- post :account, { :display_name => user.display_name, :user => user.attributes }, { "user" => user.id }
+ new_attributes = user.attributes.dup.merge(:display_name => users(:public_user).display_name.upcase)
+ post :account, { :display_name => user.display_name, :user => new_attributes }, { "user" => user.id }
assert_response :success
assert_template :account
assert_select "div#notice", false
@@ -508,16 +498,16 @@ class UserControllerTest < ActionController::TestCase
assert_select "form#accountForm > fieldset > div.form-row > div.field_with_errors > input#user_display_name"
# Changing name to one that doesn't exist should work
- user.display_name = "new tester"
- post :account, { :display_name => user.display_name, :user => user.attributes }, { "user" => user.id }
+ new_attributes = user.attributes.dup.merge(:display_name => "new tester")
+ post :account, { :display_name => user.display_name, :user => new_attributes }, { "user" => user.id }
assert_response :success
assert_template :account
assert_select "div#errorExplanation", false
assert_select "div#notice", /^User information updated successfully/
- assert_select "form#accountForm > fieldset > div.form-row > input#user_display_name[value=?]", user.display_name
+ assert_select "form#accountForm > fieldset > div.form-row > input#user_display_name[value=?]", "new tester"
- # Need to update cookies now to stay valid
- @request.cookies["_osm_username"] = user.display_name
+ # Record the change of name
+ user.display_name = "new tester"
# Changing email to one that exists should fail
user.new_email = users(:public_user).email
@@ -598,7 +588,6 @@ class UserControllerTest < ActionController::TestCase
# Login as a normal user
session[:user] = users(:normal_user).id
- cookies["_osm_username"] = users(:normal_user).display_name
# Test the normal user
get :view, {:display_name => "test"}
@@ -616,7 +605,6 @@ class UserControllerTest < ActionController::TestCase
# Login as a moderator
session[:user] = users(:moderator_user).id
- cookies["_osm_username"] = users(:moderator_user).display_name
# Test the normal user
get :view, {:display_name => "test"}
@@ -734,9 +722,6 @@ class UserControllerTest < ActionController::TestCase
# Check that the users aren't already friends
assert_nil Friend.where(:user_id => user.id, :friend_user_id => friend.id).first
- # Set the username cookie
- @request.cookies["_osm_username"] = user.display_name
-
# When not logged in a GET should ask us to login
get :make_friend, {:display_name => friend.display_name}
assert_redirected_to :controller => :user, :action => "login", :referer => make_friend_path(:display_name => friend.display_name)
@@ -787,9 +772,6 @@ class UserControllerTest < ActionController::TestCase
# Check that the users are friends
assert Friend.where(:user_id => user.id, :friend_user_id => friend.id).first
- # Set the username cookie
- @request.cookies["_osm_username"] = user.display_name
-
# When not logged in a GET should ask us to login
get :remove_friend, {:display_name => friend.display_name}
assert_redirected_to :controller => :user, :action => "login", :referer => remove_friend_path(:display_name => friend.display_name)
@@ -838,15 +820,11 @@ class UserControllerTest < ActionController::TestCase
assert_response :redirect
assert_redirected_to :action => :login, :referer => set_status_user_path(:status => "suspended")
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Now try as a normal user
get :set_status, {:display_name => users(:normal_user).display_name, :status => "suspended"}, {:user => users(:normal_user).id}
assert_response :redirect
assert_redirected_to :action => :view, :display_name => users(:normal_user).display_name
- @request.cookies["_osm_username"] = users(:administrator_user).display_name
-
# Finally try as an administrator
get :set_status, {:display_name => users(:normal_user).display_name, :status => "suspended"}, {:user => users(:administrator_user).id}
assert_response :redirect
@@ -860,15 +838,11 @@ class UserControllerTest < ActionController::TestCase
assert_response :redirect
assert_redirected_to :action => :login, :referer => delete_user_path(:status => "suspended")
- @request.cookies["_osm_username"] = users(:normal_user).display_name
-
# Now try as a normal user
get :delete, {:display_name => users(:normal_user).display_name, :status => "suspended"}, {:user => users(:normal_user).id}
assert_response :redirect
assert_redirected_to :action => :view, :display_name => users(:normal_user).display_name
- @request.cookies["_osm_username"] = users(:administrator_user).display_name
-
# Finally try as an administrator
get :delete, {:display_name => users(:normal_user).display_name, :status => "suspended"}, {:user => users(:administrator_user).id}
assert_response :redirect
diff --git a/test/functional/user_roles_controller_test.rb b/test/functional/user_roles_controller_test.rb
index ed5d1a17d..e942cd0fa 100644
--- a/test/functional/user_roles_controller_test.rb
+++ b/test/functional/user_roles_controller_test.rb
@@ -25,7 +25,6 @@ class UserRolesControllerTest < ActionController::TestCase
# Login as an unprivileged user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Granting should still fail
post :grant, :display_name => users(:normal_user).display_name, :role => "moderator"
@@ -34,7 +33,6 @@ class UserRolesControllerTest < ActionController::TestCase
# Login as an administrator
session[:user] = users(:administrator_user).id
- cookies["_osm_username"] = users(:administrator_user).display_name
UserRole::ALL_ROLES.each do |role|
@@ -85,7 +83,6 @@ class UserRolesControllerTest < ActionController::TestCase
# Login as an unprivileged user
session[:user] = users(:public_user).id
- cookies["_osm_username"] = users(:public_user).display_name
# Revoking should still fail
post :revoke, :display_name => users(:normal_user).display_name, :role => "moderator"
@@ -94,7 +91,6 @@ class UserRolesControllerTest < ActionController::TestCase
# Login as an administrator
session[:user] = users(:administrator_user).id
- cookies["_osm_username"] = users(:administrator_user).display_name
UserRole::ALL_ROLES.each do |role|
diff --git a/vendor/assets/leaflet/leaflet.css b/vendor/assets/leaflet/leaflet.css
index e6fb4908e..ac0cd174d 100644
--- a/vendor/assets/leaflet/leaflet.css
+++ b/vendor/assets/leaflet/leaflet.css
@@ -65,6 +65,16 @@
.leaflet-marker-pane { z-index: 6; }
.leaflet-popup-pane { z-index: 7; }
+.leaflet-vml-shape {
+ width: 1px;
+ height: 1px;
+ }
+.lvml {
+ behavior: url(#default#VML);
+ display: inline-block;
+ position: absolute;
+ }
+
/* control positioning */
@@ -160,9 +170,8 @@
.leaflet-control {
cursor: auto;
}
-.leaflet-dragging,
-.leaflet-dragging .leaflet-clickable,
-.leaflet-dragging .leaflet-container {
+.leaflet-dragging .leaflet-container,
+.leaflet-dragging .leaflet-clickable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
@@ -182,9 +191,8 @@
outline: 2px solid orange;
}
.leaflet-zoom-box {
- border: 2px dotted #05f;
- background: white;
- opacity: 0.5;
+ border: 2px dotted #38f;
+ background: rgba(255,255,255,0.5);
}
@@ -197,11 +205,11 @@
/* general toolbar styles */
.leaflet-bar {
- box-shadow: 0 1px 7px rgba(0,0,0,0.65);
- -webkit-border-radius: 4px;
- border-radius: 4px;
+ box-shadow: 0 1px 5px rgba(0,0,0,0.65);
+ border-radius: 4px;
}
-.leaflet-bar a, .leaflet-bar a:hover {
+.leaflet-bar a,
+.leaflet-bar a:hover {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
@@ -222,16 +230,12 @@
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
- -webkit-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
- -webkit-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
- -webkit-border-bottom-left-radius: 4px;
- border-bottom-left-radius: 4px;
- -webkit-border-bottom-right-radius: 4px;
- border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
@@ -240,55 +244,38 @@
color: #bbb;
}
-.leaflet-touch .leaflet-bar {
- -webkit-border-radius: 10px;
- border-radius: 10px;
- }
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
- }
-.leaflet-touch .leaflet-bar a:first-child {
- -webkit-border-top-left-radius: 7px;
- border-top-left-radius: 7px;
- -webkit-border-top-right-radius: 7px;
- border-top-right-radius: 7px;
- }
-.leaflet-touch .leaflet-bar a:last-child {
- -webkit-border-bottom-left-radius: 7px;
- border-bottom-left-radius: 7px;
- -webkit-border-bottom-right-radius: 7px;
- border-bottom-right-radius: 7px;
- border-bottom: none;
+ line-height: 30px;
}
/* zoom control */
-.leaflet-control-zoom-in {
+.leaflet-control-zoom-in,
+.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
+ text-indent: 1px;
}
.leaflet-control-zoom-out {
- font: bold 22px 'Lucida Console', Monaco, monospace;
+ font-size: 20px;
}
.leaflet-touch .leaflet-control-zoom-in {
font-size: 22px;
- line-height: 30px;
}
.leaflet-touch .leaflet-control-zoom-out {
- font-size: 28px;
- line-height: 30px;
+ font-size: 24px;
}
/* layers control */
.leaflet-control-layers {
- box-shadow: 0 1px 7px rgba(0,0,0,0.4);
- background: #f8f8f9;
- -webkit-border-radius: 5px;
- border-radius: 5px;
+ box-shadow: 0 1px 5px rgba(0,0,0,0.4);
+ background: #fff;
+ border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
@@ -334,8 +321,8 @@
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
- background-color: rgba(255, 255, 255, 0.7);
- box-shadow: 0 0 5px #bbb;
+ background: #fff;
+ background: rgba(255, 255, 255, 0.7);
margin: 0;
}
.leaflet-control-attribution,
@@ -343,6 +330,12 @@
padding: 0 5px;
color: #333;
}
+.leaflet-control-attribution a {
+ text-decoration: none;
+ }
+.leaflet-control-attribution a:hover {
+ text-decoration: underline;
+ }
.leaflet-container .leaflet-control-attribution,
.leaflet-container .leaflet-control-scale {
font-size: 11px;
@@ -356,23 +349,21 @@
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
- color: black;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
- text-shadow: 1px 1px 1px #fff;
- background-color: rgba(255, 255, 255, 0.5);
- box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2);
white-space: nowrap;
overflow: hidden;
-moz-box-sizing: content-box;
box-sizing: content-box;
+
+ background: #fff;
+ background: rgba(255, 255, 255, 0.5);
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
@@ -385,7 +376,8 @@
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
- border: 4px solid rgba(0,0,0,0.3);
+ border: 2px solid rgba(0,0,0,0.2);
+ background-clip: padding-box;
}
@@ -398,8 +390,7 @@
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
- -webkit-border-radius: 12px;
- border-radius: 12px;
+ border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 19px;
@@ -428,7 +419,8 @@
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
-.leaflet-popup-content-wrapper, .leaflet-popup-tip {
+.leaflet-popup-content-wrapper,
+.leaflet-popup-tip {
background: white;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
@@ -456,6 +448,27 @@
border-top: 1px solid #ddd;
}
+.leaflet-oldie .leaflet-popup-content-wrapper {
+ zoom: 1;
+ }
+.leaflet-oldie .leaflet-popup-tip {
+ width: 24px;
+ margin: 0 auto;
+
+ -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
+ filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
+ }
+.leaflet-oldie .leaflet-popup-tip-container {
+ margin-top: -1px;
+ }
+
+.leaflet-oldie .leaflet-control-zoom,
+.leaflet-oldie .leaflet-control-layers,
+.leaflet-oldie .leaflet-popup-content-wrapper,
+.leaflet-oldie .leaflet-popup-tip {
+ border: 1px solid #999;
+ }
+
/* div icon */
@@ -463,7 +476,3 @@
background: #fff;
border: 1px solid #666;
}
-.leaflet-editing-icon {
- -webkit-border-radius: 2px;
- border-radius: 2px;
- }
diff --git a/vendor/assets/leaflet/leaflet.ie.css b/vendor/assets/leaflet/leaflet.ie.css
deleted file mode 100644
index 14b84b691..000000000
--- a/vendor/assets/leaflet/leaflet.ie.css
+++ /dev/null
@@ -1,51 +0,0 @@
-.leaflet-vml-shape {
- width: 1px;
- height: 1px;
- }
-.lvml {
- behavior: url(#default#VML);
- display: inline-block;
- position: absolute;
- }
-
-.leaflet-control {
- display: inline;
- }
-
-.leaflet-popup-tip {
- width: 21px;
- _width: 27px;
- margin: 0 auto;
- _margin-top: -3px;
-
- filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
- -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
- }
-.leaflet-popup-tip-container {
- margin-top: -1px;
- }
-.leaflet-popup-content-wrapper, .leaflet-popup-tip {
- border: 1px solid #999;
- }
-.leaflet-popup-content-wrapper {
- zoom: 1;
- }
-
-.leaflet-control-zoom,
-.leaflet-control-layers {
- border: 3px solid #999;
- }
-.leaflet-control-layers-toggle {
- }
-.leaflet-control-attribution,
-.leaflet-control-layers,
-.leaflet-control-scale-line {
- background: white;
- }
-.leaflet-zoom-box {
- filter: alpha(opacity=50);
- }
-.leaflet-control-attribution {
- border-top: 1px solid #bbb;
- border-left: 1px solid #bbb;
- }
diff --git a/vendor/assets/leaflet/leaflet.js b/vendor/assets/leaflet/leaflet.js
index 0f0b01be2..2b66295fc 100644
--- a/vendor/assets/leaflet/leaflet.js
+++ b/vendor/assets/leaflet/leaflet.js
@@ -7,7 +7,7 @@
var oldL = window.L,
L = {};
-L.version = '0.6.3';
+L.version = '0.7';
// define Leaflet for Node module pattern loaders, including Browserify
if (typeof module === 'object' && typeof module.exports === 'object') {
@@ -135,19 +135,23 @@ L.Util = {
return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
},
- template: function (str, data) {
- return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
- var value = data[key];
- if (value === undefined) {
- throw new Error('No value provided for variable ' + str);
- } else if (typeof value === 'function') {
- value = value(data);
- }
- return value;
+ compileTemplate: function (str, data) {
+ // based on https://gist.github.com/padolsey/6008842
+ str = str.replace(/"/g, '\\\"');
+ str = str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
+ return '" + o["' + key + '"]' + (typeof data[key] === 'function' ? '(o)' : '') + ' + "';
});
+ // jshint evil: true
+ return new Function('o', 'return "' + str + '";');
},
- isArray: function (obj) {
+ template: function (str, data) {
+ var cache = L.Util._templateCache = L.Util._templateCache || {};
+ cache[str] = cache[str] || L.Util.compileTemplate(str, data);
+ return cache[str](data);
+ },
+
+ isArray: Array.isArray || function (obj) {
return (Object.prototype.toString.call(obj) === '[object Array]');
},
@@ -337,7 +341,7 @@ L.Mixin.Events = {
if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; }
var events = this[eventsKey] = this[eventsKey] || {},
- contextId = context && L.stamp(context),
+ contextId = context && context !== this && L.stamp(context),
i, len, event, type, indexKey, indexLenKey, typeIndex;
// types can be a string of space-separated words
@@ -350,7 +354,7 @@ L.Mixin.Events = {
};
type = types[i];
- if (context) {
+ if (contextId) {
// store listeners of a particular context in a separate hash (if it has an id)
// gives a major performance boost when removing thousands of map layers
@@ -397,7 +401,7 @@ L.Mixin.Events = {
if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; }
var events = this[eventsKey],
- contextId = context && L.stamp(context),
+ contextId = context && context !== this && L.stamp(context),
i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed;
types = L.Util.splitWords(types);
@@ -413,9 +417,10 @@ L.Mixin.Events = {
// clear all listeners for a type if function isn't specified
delete events[type];
delete events[indexKey];
+ delete events[indexLenKey];
} else {
- listeners = context && typeIndex ? typeIndex[contextId] : events[type];
+ listeners = contextId && typeIndex ? typeIndex[contextId] : events[type];
if (listeners) {
for (j = listeners.length - 1; j >= 0; j--) {
@@ -458,7 +463,7 @@ L.Mixin.Events = {
listeners = events[type].slice();
for (i = 0, len = listeners.length; i < len; i++) {
- listeners[i].action.call(listeners[i].context || this, event);
+ listeners[i].action.call(listeners[i].context, event);
}
}
@@ -470,7 +475,7 @@ L.Mixin.Events = {
if (listeners) {
for (i = 0, len = listeners.length; i < len; i++) {
- listeners[i].action.call(listeners[i].context || this, event);
+ listeners[i].action.call(listeners[i].context, event);
}
}
}
@@ -506,9 +511,7 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
(function () {
- var ie = !!window.ActiveXObject,
- ie6 = ie && !window.XMLHttpRequest,
- ie7 = ie && !document.querySelector,
+ var ie = 'ActiveXObject' in window,
ielt9 = ie && !document.addEventListener,
// terrible browser detection to work around Safari / iOS / Android browser bugs
@@ -518,10 +521,13 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
phantomjs = ua.indexOf('phantom') !== -1,
android = ua.indexOf('android') !== -1,
android23 = ua.search('android [23]') !== -1,
+ gecko = ua.indexOf('gecko') !== -1,
mobile = typeof orientation !== undefined + '',
- msTouch = window.navigator && window.navigator.msPointerEnabled &&
- window.navigator.msMaxTouchPoints,
+ msPointer = window.navigator && window.navigator.msPointerEnabled &&
+ window.navigator.msMaxTouchPoints && !window.PointerEvent,
+ pointer = (window.PointerEvent && window.navigator.pointerEnabled && window.navigator.maxTouchPoints) ||
+ msPointer,
retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) ||
('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') &&
window.matchMedia('(min-resolution:144dpi)').matches),
@@ -541,8 +547,8 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
var startName = 'ontouchstart';
- // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.MsTouch) or WebKit, etc.
- if (msTouch || (startName in doc)) {
+ // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.Pointer) or WebKit, etc.
+ if (pointer || (startName in doc)) {
return true;
}
@@ -568,10 +574,9 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
L.Browser = {
ie: ie,
- ie6: ie6,
- ie7: ie7,
ielt9: ielt9,
webkit: webkit,
+ gecko: gecko && !webkit && !window.opera && !ie,
android: android,
android23: android23,
@@ -590,7 +595,8 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
mobileOpera: mobile && window.opera,
touch: touch,
- msTouch: msTouch,
+ msPointer: msPointer,
+ pointer: pointer,
retina: retina
};
@@ -881,8 +887,7 @@ L.DomUtil = {
el = element,
docBody = document.body,
docEl = document.documentElement,
- pos,
- ie7 = L.Browser.ie7;
+ pos;
do {
top += el.offsetTop || 0;
@@ -929,19 +934,6 @@ L.DomUtil = {
top -= el.scrollTop || 0;
left -= el.scrollLeft || 0;
- // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else
- // https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js
- if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) {
- left += el.scrollWidth - el.clientWidth;
-
- // ie7 shows the scrollbar by default and provides clientWidth counting it, so we
- // need to add it back in if it is visible; scrollbar is on the left as we are RTL
- if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' &&
- L.DomUtil.getStyle(el, 'overflow') !== 'hidden') {
- left += 17;
- }
- }
-
el = el.parentNode;
} while (el);
@@ -969,18 +961,44 @@ L.DomUtil = {
},
hasClass: function (el, name) {
- return (el.className.length > 0) &&
- new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className);
+ if (el.classList !== undefined) {
+ return el.classList.contains(name);
+ }
+ var className = L.DomUtil._getClass(el);
+ return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
},
addClass: function (el, name) {
- if (!L.DomUtil.hasClass(el, name)) {
- el.className += (el.className ? ' ' : '') + name;
+ if (el.classList !== undefined) {
+ var classes = L.Util.splitWords(name);
+ for (var i = 0, len = classes.length; i < len; i++) {
+ el.classList.add(classes[i]);
+ }
+ } else if (!L.DomUtil.hasClass(el, name)) {
+ var className = L.DomUtil._getClass(el);
+ L.DomUtil._setClass(el, (className ? className + ' ' : '') + name);
}
},
removeClass: function (el, name) {
- el.className = L.Util.trim((' ' + el.className + ' ').replace(' ' + name + ' ', ' '));
+ if (el.classList !== undefined) {
+ el.classList.remove(name);
+ } else {
+ L.DomUtil._setClass(el, L.Util.trim((' ' + L.DomUtil._getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
+ }
+ },
+
+ _setClass: function (el, name) {
+ if (el.className.baseVal === undefined) {
+ el.className = name;
+ } else {
+ // in case of SVG element
+ el.className.baseVal = name;
+ }
+ },
+
+ _getClass: function (el) {
+ return el.className.baseVal === undefined ? el.className : el.className.baseVal;
},
setOpacity: function (el, value) {
@@ -1089,27 +1107,39 @@ L.DomUtil.TRANSITION_END =
L.DomUtil.TRANSITION + 'End' : 'transitionend';
(function () {
- var userSelectProperty = L.DomUtil.testProp(
- ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
+ if ('onselectstart' in document) {
+ L.extend(L.DomUtil, {
+ disableTextSelection: function () {
+ L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
+ },
+
+ enableTextSelection: function () {
+ L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
+ }
+ });
+ } else {
+ var userSelectProperty = L.DomUtil.testProp(
+ ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
+
+ L.extend(L.DomUtil, {
+ disableTextSelection: function () {
+ if (userSelectProperty) {
+ var style = document.documentElement.style;
+ this._userSelect = style[userSelectProperty];
+ style[userSelectProperty] = 'none';
+ }
+ },
+
+ enableTextSelection: function () {
+ if (userSelectProperty) {
+ document.documentElement.style[userSelectProperty] = this._userSelect;
+ delete this._userSelect;
+ }
+ }
+ });
+ }
L.extend(L.DomUtil, {
- disableTextSelection: function () {
- L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
- if (userSelectProperty) {
- var style = document.documentElement.style;
- this._userSelect = style[userSelectProperty];
- style[userSelectProperty] = 'none';
- }
- },
-
- enableTextSelection: function () {
- L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
- if (userSelectProperty) {
- document.documentElement.style[userSelectProperty] = this._userSelect;
- delete this._userSelect;
- }
- },
-
disableImageDrag: function () {
L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
},
@@ -1125,16 +1155,20 @@ L.DomUtil.TRANSITION_END =
* L.LatLng represents a geographical point with latitude and longitude coordinates.
*/
-L.LatLng = function (rawLat, rawLng) { // (Number, Number)
- var lat = parseFloat(rawLat),
- lng = parseFloat(rawLng);
+L.LatLng = function (lat, lng, alt) { // (Number, Number, Number)
+ lat = parseFloat(lat);
+ lng = parseFloat(lng);
if (isNaN(lat) || isNaN(lng)) {
- throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')');
+ throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
}
this.lat = lat;
this.lng = lng;
+
+ if (alt !== undefined) {
+ this.alt = parseFloat(alt);
+ }
};
L.extend(L.LatLng, {
@@ -1198,7 +1232,11 @@ L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Numbe
return a;
}
if (L.Util.isArray(a)) {
- return new L.LatLng(a[0], a[1]);
+ if (typeof a[0] === 'number' || typeof a[0] === 'string') {
+ return new L.LatLng(a[0], a[1], a[2]);
+ } else {
+ return null;
+ }
}
if (a === undefined || a === null) {
return a;
@@ -1206,6 +1244,9 @@ L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Numbe
if (typeof a === 'object' && 'lat' in a) {
return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon);
}
+ if (b === undefined) {
+ return null;
+ }
return new L.LatLng(a, b);
};
@@ -1230,8 +1271,9 @@ L.LatLngBounds.prototype = {
extend: function (obj) { // (LatLng) or (LatLngBounds)
if (!obj) { return this; }
- if (typeof obj[0] === 'number' || typeof obj[0] === 'string' || obj instanceof L.LatLng) {
- obj = L.latLng(obj);
+ var latLng = L.latLng(obj);
+ if (latLng !== null) {
+ obj = latLng;
} else {
obj = L.latLngBounds(obj);
}
@@ -1444,6 +1486,11 @@ L.CRS = {
scale: function (zoom) {
return 256 * Math.pow(2, zoom);
+ },
+
+ getSize: function (zoom) {
+ var s = this.scale(zoom);
+ return L.point(s, s);
}
};
@@ -1522,8 +1569,13 @@ L.Map = L.Class.extend({
initialize: function (id, options) { // (HTMLElement or String, Object)
options = L.setOptions(this, options);
+
this._initContainer(id);
this._initLayout();
+
+ // hack for https://github.com/Leaflet/Leaflet/issues/1980
+ this._onResize = L.bind(this._onResize, this);
+
this._initEvents();
if (options.maxBounds) {
@@ -1550,11 +1602,16 @@ L.Map = L.Class.extend({
// replaced by animation-powered implementation in Map.PanAnimation.js
setView: function (center, zoom) {
+ zoom = zoom === undefined ? this.getZoom() : zoom;
this._resetView(L.latLng(center), this._limitZoom(zoom));
return this;
},
setZoom: function (zoom, options) {
+ if (!this._loaded) {
+ this._zoom = this._limitZoom(zoom);
+ return this;
+ }
return this.setView(this.getCenter(), zoom, {zoom: options});
},
@@ -1592,6 +1649,8 @@ L.Map = L.Class.extend({
nePoint = this.project(bounds.getNorthEast(), zoom),
center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
+ zoom = options && options.maxZoom ? Math.min(options.maxZoom, zoom) : zoom;
+
return this.setView(center, zoom, options);
},
@@ -1604,7 +1663,7 @@ L.Map = L.Class.extend({
},
panBy: function (offset) { // (Point)
- // replaced with animated panBy in Map.Animation.js
+ // replaced with animated panBy in Map.PanAnimation.js
this.fire('movestart');
this._rawPanBy(L.point(offset));
@@ -1613,63 +1672,29 @@ L.Map = L.Class.extend({
return this.fire('moveend');
},
- setMaxBounds: function (bounds, options) {
+ setMaxBounds: function (bounds) {
bounds = L.latLngBounds(bounds);
this.options.maxBounds = bounds;
if (!bounds) {
- this._boundsMinZoom = null;
- this.off('moveend', this._panInsideMaxBounds, this);
- return this;
+ return this.off('moveend', this._panInsideMaxBounds, this);
}
- var minZoom = this.getBoundsZoom(bounds, true);
-
- this._boundsMinZoom = minZoom;
-
if (this._loaded) {
- if (this._zoom < minZoom) {
- this.setView(bounds.getCenter(), minZoom, options);
- } else {
- this.panInsideBounds(bounds);
- }
+ this._panInsideMaxBounds();
}
- this.on('moveend', this._panInsideMaxBounds, this);
-
- return this;
+ return this.on('moveend', this._panInsideMaxBounds, this);
},
- panInsideBounds: function (bounds) {
- bounds = L.latLngBounds(bounds);
+ panInsideBounds: function (bounds, options) {
+ var center = this.getCenter(),
+ newCenter = this._limitCenter(center, this._zoom, bounds);
- var viewBounds = this.getPixelBounds(),
- viewSw = viewBounds.getBottomLeft(),
- viewNe = viewBounds.getTopRight(),
- sw = this.project(bounds.getSouthWest()),
- ne = this.project(bounds.getNorthEast()),
- dx = 0,
- dy = 0;
+ if (center.equals(newCenter)) { return this; }
- if (viewNe.y < ne.y) { // north
- dy = Math.ceil(ne.y - viewNe.y);
- }
- if (viewNe.x > ne.x) { // east
- dx = Math.floor(ne.x - viewNe.x);
- }
- if (viewSw.y > sw.y) { // south
- dy = Math.floor(sw.y - viewSw.y);
- }
- if (viewSw.x < sw.x) { // west
- dx = Math.ceil(sw.x - viewSw.x);
- }
-
- if (dx || dy) {
- return this.panBy([dx, dy]);
- }
-
- return this;
+ return this.panTo(newCenter, options);
},
addLayer: function (layer) {
@@ -1754,14 +1779,12 @@ L.Map = L.Class.extend({
this._sizeChanged = true;
this._initialCenter = null;
- if (this.options.maxBounds) {
- this.setMaxBounds(this.options.maxBounds);
- }
-
if (!this._loaded) { return this; }
var newSize = this.getSize(),
- offset = oldSize.subtract(newSize).divideBy(2).round();
+ oldCenter = oldSize.divideBy(2).round(),
+ newCenter = newSize.divideBy(2).round(),
+ offset = oldCenter.subtract(newCenter);
if (!offset.x && !offset.y) { return this; }
@@ -1773,7 +1796,14 @@ L.Map = L.Class.extend({
this._rawPanBy(offset);
}
- this.fire('move').fire('moveend');
+ this.fire('move');
+
+ if (options.debounceMoveend) {
+ clearTimeout(this._sizeTimer);
+ this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
+ } else {
+ this.fire('moveend');
+ }
}
return this.fire('resize', {
@@ -1784,7 +1814,7 @@ L.Map = L.Class.extend({
// TODO handler.addTo
addHandler: function (name, HandlerClass) {
- if (!HandlerClass) { return; }
+ if (!HandlerClass) { return this; }
var handler = this[name] = new HandlerClass(this);
@@ -1804,7 +1834,12 @@ L.Map = L.Class.extend({
this._initEvents('off');
- delete this._container._leaflet;
+ try {
+ // throws error in IE6-8
+ delete this._container._leaflet;
+ } catch (e) {
+ this._container._leaflet = undefined;
+ }
this._clearPanes();
if (this._clearControlPos) {
@@ -1841,9 +1876,9 @@ L.Map = L.Class.extend({
},
getMinZoom: function () {
- var z1 = this._layersMinZoom === undefined ? -Infinity : this._layersMinZoom,
- z2 = this._boundsMinZoom === undefined ? -Infinity : this._boundsMinZoom;
- return this.options.minZoom === undefined ? Math.max(z1, z2) : this.options.minZoom;
+ return this.options.minZoom === undefined ?
+ (this._layersMinZoom === undefined ? 0 : this._layersMinZoom) :
+ this.options.minZoom;
},
getMaxZoom: function () {
@@ -1995,6 +2030,7 @@ L.Map = L.Class.extend({
L.DomUtil.addClass(container, 'leaflet-container' +
(L.Browser.touch ? ' leaflet-touch' : '') +
(L.Browser.retina ? ' leaflet-retina' : '') +
+ (L.Browser.ielt9 ? ' leaflet-oldie' : '') +
(this.options.fadeAnimation ? ' leaflet-fade-anim' : ''));
var position = L.DomUtil.getStyle(container, 'position');
@@ -2165,12 +2201,14 @@ L.Map = L.Class.extend({
_onResize: function () {
L.Util.cancelAnimFrame(this._resizeRequest);
this._resizeRequest = L.Util.requestAnimFrame(
- this.invalidateSize, this, false, this._container);
+ function () { this.invalidateSize({debounceMoveend: true}); }, this, false, this._container);
},
_onMouseClick: function (e) {
- if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) ||
- L.DomEvent._skipped(e)) { return; }
+ if (!this._loaded || (!e._simulated &&
+ ((this.dragging && this.dragging.moved()) ||
+ (this.boxZoom && this.boxZoom.moved()))) ||
+ L.DomEvent._skipped(e)) { return; }
this.fire('preclick');
this._fireMouseEvent(e);
@@ -2265,6 +2303,46 @@ L.Map = L.Class.extend({
return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
},
+ // adjust center for view to get inside bounds
+ _limitCenter: function (center, zoom, bounds) {
+
+ if (!bounds) { return center; }
+
+ var centerPoint = this.project(center, zoom),
+ viewHalf = this.getSize().divideBy(2),
+ viewBounds = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
+ offset = this._getBoundsOffset(viewBounds, bounds, zoom);
+
+ return this.unproject(centerPoint.add(offset), zoom);
+ },
+
+ // adjust offset for view to get inside bounds
+ _limitOffset: function (offset, bounds) {
+ if (!bounds) { return offset; }
+
+ var viewBounds = this.getPixelBounds(),
+ newBounds = new L.Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
+
+ return offset.add(this._getBoundsOffset(newBounds, bounds));
+ },
+
+ // returns offset needed for pxBounds to get inside maxBounds at a specified zoom
+ _getBoundsOffset: function (pxBounds, maxBounds, zoom) {
+ var nwOffset = this.project(maxBounds.getNorthWest(), zoom).subtract(pxBounds.min),
+ seOffset = this.project(maxBounds.getSouthEast(), zoom).subtract(pxBounds.max),
+
+ dx = this._rebound(nwOffset.x, -seOffset.x),
+ dy = this._rebound(nwOffset.y, -seOffset.y);
+
+ return new L.Point(dx, dy);
+ },
+
+ _rebound: function (left, right) {
+ return left + right > 0 ?
+ Math.round(left - right) / 2 :
+ Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
+ },
+
_limitZoom: function (zoom) {
var min = this.getMinZoom(),
max = this.getMaxZoom();
@@ -2345,9 +2423,9 @@ L.CRS.EPSG3395 = L.extend({}, L.CRS, {
transformation: (function () {
var m = L.Projection.Mercator,
r = m.R_MAJOR,
- r2 = m.R_MINOR;
+ scale = 0.5 / (Math.PI * r);
- return new L.Transformation(0.5 / (Math.PI * r), 0.5, -0.5 / (Math.PI * r2), 0.5);
+ return new L.Transformation(scale, 0.5, -scale, 0.5);
}())
});
@@ -2368,7 +2446,8 @@ L.TileLayer = L.Class.extend({
attribution: '',
zoomOffset: 0,
opacity: 1,
- /* (undefined works too)
+ /*
+ maxNativeZoom: null,
zIndex: null,
tms: false,
continuousWorld: false,
@@ -2417,9 +2496,6 @@ L.TileLayer = L.Class.extend({
// create a container div for tiles
this._initContainer();
- // create an image to clone for tiles
- this._createTileProto();
-
// set up events
map.on({
'viewreset': this._reset,
@@ -2584,7 +2660,7 @@ L.TileLayer = L.Class.extend({
this._updateZIndex();
if (this._animated) {
- var className = 'leaflet-tile-container leaflet-zoom-animated';
+ var className = 'leaflet-tile-container';
this._bgBuffer = L.DomUtil.create('div', className, this._container);
this._tileContainer = L.DomUtil.create('div', className, this._container);
@@ -2622,13 +2698,27 @@ L.TileLayer = L.Class.extend({
this._initContainer();
},
+ _getTileSize: function () {
+ var map = this._map,
+ zoom = map.getZoom() + this.options.zoomOffset,
+ zoomN = this.options.maxNativeZoom,
+ tileSize = this.options.tileSize;
+
+ if (zoomN && zoom > zoomN) {
+ tileSize = Math.round(map.getZoomScale(zoom) / map.getZoomScale(zoomN) * tileSize);
+ }
+
+ return tileSize;
+ },
+
_update: function () {
if (!this._map) { return; }
- var bounds = this._map.getPixelBounds(),
- zoom = this._map.getZoom(),
- tileSize = this.options.tileSize;
+ var map = this._map,
+ bounds = map.getPixelBounds(),
+ zoom = map.getZoom(),
+ tileSize = this._getTileSize();
if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
return;
@@ -2697,8 +2787,8 @@ L.TileLayer = L.Class.extend({
var limit = this._getWrapTileNum();
// don't load if exceeds world bounds
- if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit)) ||
- tilePoint.y < 0 || tilePoint.y >= limit) { return false; }
+ if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit.x)) ||
+ tilePoint.y < 0 || tilePoint.y >= limit.y) { return false; }
}
if (options.bounds) {
@@ -2791,12 +2881,14 @@ L.TileLayer = L.Class.extend({
zoom = options.maxZoom - zoom;
}
- return zoom + options.zoomOffset;
+ zoom += options.zoomOffset;
+
+ return options.maxNativeZoom ? Math.min(zoom, options.maxNativeZoom) : zoom;
},
_getTilePos: function (tilePoint) {
var origin = this._map.getPixelOrigin(),
- tileSize = this.options.tileSize;
+ tileSize = this._getTileSize();
return tilePoint.multiplyBy(tileSize).subtract(origin);
},
@@ -2813,8 +2905,9 @@ L.TileLayer = L.Class.extend({
},
_getWrapTileNum: function () {
- // TODO refactor, limit is not valid for non-standard projections
- return Math.pow(2, this._getZoomForUrl());
+ var crs = this._map.options.crs,
+ size = crs.getSize(this._map.getZoom());
+ return size.divideBy(this.options.tileSize);
},
_adjustTilePoint: function (tilePoint) {
@@ -2823,11 +2916,11 @@ L.TileLayer = L.Class.extend({
// wrap tile coordinates
if (!this.options.continuousWorld && !this.options.noWrap) {
- tilePoint.x = ((tilePoint.x % limit) + limit) % limit;
+ tilePoint.x = ((tilePoint.x % limit.x) + limit.x) % limit.x;
}
if (this.options.tms) {
- tilePoint.y = limit - tilePoint.y - 1;
+ tilePoint.y = limit.y - tilePoint.y - 1;
}
tilePoint.z = this._getZoomForUrl();
@@ -2838,12 +2931,6 @@ L.TileLayer = L.Class.extend({
return this.options.subdomains[index];
},
- _createTileProto: function () {
- var img = this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
- img.style.width = img.style.height = this.options.tileSize + 'px';
- img.galleryimg = 'no';
- },
-
_getTile: function () {
if (this.options.reuseTiles && this._unusedTiles.length > 0) {
var tile = this._unusedTiles.pop();
@@ -2857,12 +2944,20 @@ L.TileLayer = L.Class.extend({
_resetTile: function (/*tile*/) {},
_createTile: function () {
- var tile = this._tileImg.cloneNode(false);
+ var tile = L.DomUtil.create('img', 'leaflet-tile');
+ tile.style.width = tile.style.height = this._getTileSize() + 'px';
+ tile.galleryimg = 'no';
+
tile.onselectstart = tile.onmousemove = L.Util.falseFn;
if (L.Browser.ielt9 && this.options.opacity !== undefined) {
L.DomUtil.setOpacity(tile, this.options.opacity);
}
+ // without this hack, tiles disappear after zoom on Chrome for Android
+ // https://github.com/Leaflet/Leaflet/issues/2078
+ if (L.Browser.mobileWebkit3d) {
+ tile.style.WebkitBackfaceVisibility = 'hidden';
+ }
return tile;
},
@@ -2873,10 +2968,20 @@ L.TileLayer = L.Class.extend({
this._adjustTilePoint(tilePoint);
tile.src = this.getTileUrl(tilePoint);
+
+ this.fire('tileloadstart', {
+ tile: tile,
+ url: tile.src
+ });
},
_tileLoaded: function () {
this._tilesToLoad--;
+
+ if (this._animated) {
+ L.DomUtil.addClass(this._tileContainer, 'leaflet-zoom-animated');
+ }
+
if (!this._tilesToLoad) {
this.fire('load');
@@ -2971,13 +3076,15 @@ L.TileLayer.WMS = L.TileLayer.extend({
this._crs = this.options.crs || map.options.crs;
- var projectionKey = parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs';
+ this._wmsVersion = parseFloat(this.wmsParams.version);
+
+ var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
this.wmsParams[projectionKey] = this._crs.code;
L.TileLayer.prototype.onAdd.call(this, map);
},
- getTileUrl: function (tilePoint, zoom) { // (Point, Number) -> String
+ getTileUrl: function (tilePoint) { // (Point, Number) -> String
var map = this._map,
tileSize = this.options.tileSize,
@@ -2985,10 +3092,11 @@ L.TileLayer.WMS = L.TileLayer.extend({
nwPoint = tilePoint.multiplyBy(tileSize),
sePoint = nwPoint.add([tileSize, tileSize]),
- nw = this._crs.project(map.unproject(nwPoint, zoom)),
- se = this._crs.project(map.unproject(sePoint, zoom)),
-
- bbox = [nw.x, se.y, se.x, nw.y].join(','),
+ nw = this._crs.project(map.unproject(nwPoint, tilePoint.z)),
+ se = this._crs.project(map.unproject(sePoint, tilePoint.z)),
+ bbox = this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?
+ [se.y, nw.x, nw.y, se.x].join(',') :
+ [nw.x, se.y, se.x, nw.y].join(','),
url = L.Util.template(this._url, {s: this._getSubdomain(tilePoint)});
@@ -3031,7 +3139,7 @@ L.TileLayer.Canvas = L.TileLayer.extend({
this._reset({hard: true});
this._update();
}
-
+
for (var i in this._tiles) {
this._redrawTile(this._tiles[i]);
}
@@ -3042,13 +3150,9 @@ L.TileLayer.Canvas = L.TileLayer.extend({
this.drawTile(tile, tile._tilePoint, this._map._zoom);
},
- _createTileProto: function () {
- var proto = this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
- proto.width = proto.height = this.options.tileSize;
- },
-
_createTile: function () {
- var tile = this._canvasProto.cloneNode(false);
+ var tile = L.DomUtil.create('canvas', 'leaflet-tile');
+ tile.width = tile.height = this.options.tileSize;
tile.onselectstart = tile.onmousemove = L.Util.falseFn;
return tile;
},
@@ -3152,6 +3256,15 @@ L.ImageOverlay = L.Class.extend({
return this;
},
+ setUrl: function (url) {
+ this._url = url;
+ this._image.src = this._url;
+ },
+
+ getAttribution: function () {
+ return this.options.attribution;
+ },
+
_initImage: function () {
this._image = L.DomUtil.create('img', 'leaflet-image-layer');
@@ -3295,19 +3408,8 @@ L.Icon = L.Class.extend({
},
_createImg: function (src, el) {
-
- if (!L.Browser.ie6) {
- if (!el) {
- el = document.createElement('img');
- }
- el.src = src;
- } else {
- if (!el) {
- el = document.createElement('div');
- }
- el.style.filter =
- 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")';
- }
+ el = el || document.createElement('img');
+ el.src = src;
return el;
},
@@ -3388,6 +3490,7 @@ L.Marker = L.Class.extend({
options: {
icon: new L.Icon.Default(),
title: '',
+ alt: '',
clickable: true,
draggable: false,
keyboard: true,
@@ -3409,6 +3512,7 @@ L.Marker = L.Class.extend({
this._initIcon();
this.update();
+ this.fire('add');
if (map.options.zoomAnimation && map.options.markerZoomAnimation) {
map.on('zoomanim', this._animateZoom, this);
@@ -3466,6 +3570,10 @@ L.Marker = L.Class.extend({
this.update();
}
+ if (this._popup) {
+ this.bindPopup(this._popup);
+ }
+
return this;
},
@@ -3497,6 +3605,10 @@ L.Marker = L.Class.extend({
if (options.title) {
icon.title = options.title;
}
+
+ if (options.alt) {
+ icon.alt = options.alt;
+ }
}
L.DomUtil.addClass(icon, classToAdd);
@@ -3581,7 +3693,7 @@ L.Marker = L.Class.extend({
},
_animateZoom: function (opt) {
- var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center);
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
this._setPos(pos);
},
@@ -3662,7 +3774,7 @@ L.Marker = L.Class.extend({
if (this._map) {
this._updateOpacity();
}
-
+
return this;
},
@@ -3748,11 +3860,13 @@ L.Popup = L.Class.extend({
options: {
minWidth: 50,
maxWidth: 300,
- maxHeight: null,
+ // maxHeight: null,
autoPan: true,
closeButton: true,
offset: [0, 7],
autoPanPadding: [5, 5],
+ // autoPanPaddingTopLeft: null,
+ // autoPanPaddingBottomRight: null,
keepInView: false,
className: '',
zoomAnimation: true
@@ -3772,7 +3886,6 @@ L.Popup = L.Class.extend({
if (!this._container) {
this._initLayout();
}
- this._updateContent();
var animFade = map.options.fadeAnimation;
@@ -3783,7 +3896,7 @@ L.Popup = L.Class.extend({
map.on(this._getEvents(), this);
- this._update();
+ this.update();
if (animFade) {
L.DomUtil.setOpacity(this._container, 1);
@@ -3830,18 +3943,43 @@ L.Popup = L.Class.extend({
}
},
+ getLatLng: function () {
+ return this._latlng;
+ },
+
setLatLng: function (latlng) {
this._latlng = L.latLng(latlng);
- this._update();
+ if (this._map) {
+ this._updatePosition();
+ this._adjustPan();
+ }
return this;
},
+ getContent: function () {
+ return this._content;
+ },
+
setContent: function (content) {
this._content = content;
- this._update();
+ this.update();
return this;
},
+ update: function () {
+ if (!this._map) { return; }
+
+ this._container.style.visibility = 'hidden';
+
+ this._updateContent();
+ this._updateLayout();
+ this._updatePosition();
+
+ this._container.style.visibility = '';
+
+ this._adjustPan();
+ },
+
_getEvents: function () {
var events = {
viewreset: this._updatePosition
@@ -3888,27 +4026,14 @@ L.Popup = L.Class.extend({
L.DomEvent.disableClickPropagation(wrapper);
this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
- L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation);
- L.DomEvent.on(this._contentNode, 'MozMousePixelScroll', L.DomEvent.stopPropagation);
+
+ L.DomEvent.disableScrollPropagation(this._contentNode);
L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);
+
this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);
},
- _update: function () {
- if (!this._map) { return; }
-
- this._container.style.visibility = 'hidden';
-
- this._updateContent();
- this._updateLayout();
- this._updatePosition();
-
- this._container.style.visibility = '';
-
- this._adjustPan();
- },
-
_updateContent: function () {
if (!this._content) { return; }
@@ -3993,21 +4118,23 @@ L.Popup = L.Class.extend({
var containerPos = map.layerPointToContainerPoint(layerPos),
padding = L.point(this.options.autoPanPadding),
+ paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
+ paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
size = map.getSize(),
dx = 0,
dy = 0;
- if (containerPos.x + containerWidth > size.x) { // right
- dx = containerPos.x + containerWidth - size.x + padding.x;
+ if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
+ dx = containerPos.x + containerWidth - size.x + paddingBR.x;
}
- if (containerPos.x - dx < 0) { // left
- dx = containerPos.x - padding.x;
+ if (containerPos.x - dx - paddingTL.x < 0) { // left
+ dx = containerPos.x - paddingTL.x;
}
- if (containerPos.y + containerHeight > size.y) { // bottom
- dy = containerPos.y + containerHeight - size.y + padding.y;
+ if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
+ dy = containerPos.y + containerHeight - size.y + paddingBR.y;
}
- if (containerPos.y - dy < 0) { // top
- dy = containerPos.y - padding.y;
+ if (containerPos.y - dy - paddingTL.y < 0) { // top
+ dy = containerPos.y - paddingTL.y;
}
if (dx || dy) {
@@ -4102,11 +4229,12 @@ L.Marker.include({
options = L.extend({offset: anchor}, options);
- if (!this._popup) {
+ if (!this._popupHandlersAdded) {
this
.on('click', this.togglePopup, this)
.on('remove', this.closePopup, this)
.on('move', this._movePopup, this);
+ this._popupHandlersAdded = true;
}
if (content instanceof L.Popup) {
@@ -4131,13 +4259,18 @@ L.Marker.include({
if (this._popup) {
this._popup = null;
this
- .off('click', this.togglePopup)
- .off('remove', this.closePopup)
- .off('move', this._movePopup);
+ .off('click', this.togglePopup, this)
+ .off('remove', this.closePopup, this)
+ .off('move', this._movePopup, this);
+ this._popupHandlersAdded = false;
}
return this;
},
+ getPopup: function () {
+ return this._popup;
+ },
+
_movePopup: function (e) {
this._popup.setLatLng(e.latlng);
}
@@ -4278,7 +4411,9 @@ L.FeatureGroup = L.LayerGroup.extend({
return this;
}
- layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
+ if ('on' in layer) {
+ layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
+ }
L.LayerGroup.prototype.addLayer.call(this, layer);
@@ -4314,6 +4449,15 @@ L.FeatureGroup = L.LayerGroup.extend({
return this.invoke('bindPopup', content, options);
},
+ openPopup: function (latlng) {
+ // open popup on the first layer
+ for (var id in this._layers) {
+ this._layers[id].openPopup(latlng);
+ break;
+ }
+ return this;
+ },
+
setStyle: function (style) {
return this.invoke('setStyle', style);
},
@@ -4337,11 +4481,10 @@ L.FeatureGroup = L.LayerGroup.extend({
},
_propagateEvent: function (e) {
- if (!e.layer) {
- e.layer = e.target;
- }
- e.target = this;
-
+ e = L.extend({}, e, {
+ layer: e.target,
+ target: this
+ });
this.fire(e.type, e);
}
});
@@ -4373,6 +4516,8 @@ L.Path = L.Class.extend({
stroke: true,
color: '#0033ff',
dashArray: null,
+ lineCap: null,
+ lineJoin: null,
weight: 5,
opacity: 0.5,
@@ -4522,6 +4667,11 @@ L.Path = L.Path.extend({
this._container = this._createElement('g');
this._path = this._createElement('path');
+
+ if (this.options.className) {
+ L.DomUtil.addClass(this._path, this.options.className);
+ }
+
this._container.appendChild(this._path);
},
@@ -4552,6 +4702,12 @@ L.Path = L.Path.extend({
} else {
this._path.removeAttribute('stroke-dasharray');
}
+ if (this.options.lineCap) {
+ this._path.setAttribute('stroke-linecap', this.options.lineCap);
+ }
+ if (this.options.lineJoin) {
+ this._path.setAttribute('stroke-linejoin', this.options.lineJoin);
+ }
} else {
this._path.setAttribute('stroke', 'none');
}
@@ -4576,7 +4732,7 @@ L.Path = L.Path.extend({
_initEvents: function () {
if (this.options.clickable) {
if (L.Browser.svg || !L.Browser.vml) {
- this._path.setAttribute('class', 'leaflet-clickable');
+ L.DomUtil.addClass(this._path, 'leaflet-clickable');
}
L.DomEvent.on(this._container, 'click', this._onMouseClick, this);
@@ -4626,14 +4782,14 @@ L.Map.include({
this._panes.overlayPane.appendChild(this._pathRoot);
if (this.options.zoomAnimation && L.Browser.any3d) {
- this._pathRoot.setAttribute('class', ' leaflet-zoom-animated');
+ L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-animated');
this.on({
'zoomanim': this._animatePathZoom,
'zoomend': this._endPathZoom
});
} else {
- this._pathRoot.setAttribute('class', ' leaflet-zoom-hide');
+ L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-hide');
}
this.on('moveend', this._updateSvgViewport);
@@ -4800,10 +4956,14 @@ L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({
_initPath: function () {
var container = this._container = this._createElement('shape');
- L.DomUtil.addClass(container, 'leaflet-vml-shape');
+
+ L.DomUtil.addClass(container, 'leaflet-vml-shape' +
+ (this.options.className ? ' ' + this.options.className : ''));
+
if (this.options.clickable) {
L.DomUtil.addClass(container, 'leaflet-clickable');
}
+
container.coordsize = '1 1';
this._path = this._createElement('path');
@@ -4836,12 +4996,18 @@ L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({
stroke.opacity = options.opacity;
if (options.dashArray) {
- stroke.dashStyle = options.dashArray instanceof Array ?
+ stroke.dashStyle = L.Util.isArray(options.dashArray) ?
options.dashArray.join(' ') :
options.dashArray.replace(/( *, *)/g, ' ');
} else {
stroke.dashStyle = '';
}
+ if (options.lineCap) {
+ stroke.endcap = options.lineCap.replace('butt', 'flat');
+ }
+ if (options.lineJoin) {
+ stroke.joinstyle = options.lineJoin;
+ }
} else if (stroke) {
container.removeChild(stroke);
@@ -5521,10 +5687,12 @@ L.Polygon = L.Polyline.extend({
},
initialize: function (latlngs, options) {
- var i, len, hole;
-
L.Polyline.prototype.initialize.call(this, latlngs, options);
+ this._initWithHoles(latlngs);
+ },
+ _initWithHoles: function (latlngs) {
+ var i, len, hole;
if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) {
this._latlngs = this._convertLatLngs(latlngs[0]);
this._holes = latlngs.slice(1);
@@ -5565,6 +5733,15 @@ L.Polygon = L.Polyline.extend({
}
},
+ setLatLngs: function (latlngs) {
+ if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) {
+ this._initWithHoles(latlngs);
+ return this.redraw();
+ } else {
+ return L.Polyline.prototype.setLatLngs.call(this, latlngs);
+ }
+ },
+
_clipPoints: function () {
var points = this._originalPoints,
newParts = [];
@@ -5806,9 +5983,20 @@ L.CircleMarker = L.Circle.extend({
this.setRadius(this.options.radius);
},
+ setLatLng: function (latlng) {
+ L.Circle.prototype.setLatLng.call(this, latlng);
+ if (this._popup && this._popup._isOpen) {
+ this._popup.setLatLng(latlng);
+ }
+ },
+
setRadius: function (radius) {
this.options.radius = this._radius = radius;
return this.redraw();
+ },
+
+ getRadius: function () {
+ return this._radius;
}
});
@@ -5954,7 +6142,7 @@ L.GeoJSON = L.FeatureGroup.extend({
if (options.filter && !options.filter(geojson)) { return; }
- var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng);
+ var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng, options);
layer.feature = L.GeoJSON.asFeature(geojson);
layer.defaultOptions = layer.options;
@@ -5994,11 +6182,11 @@ L.GeoJSON = L.FeatureGroup.extend({
});
L.extend(L.GeoJSON, {
- geometryToLayer: function (geojson, pointToLayer, coordsToLatLng) {
+ geometryToLayer: function (geojson, pointToLayer, coordsToLatLng, vectorOptions) {
var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
coords = geometry.coordinates,
layers = [],
- latlng, latlngs, i, len, layer;
+ latlng, latlngs, i, len;
coordsToLatLng = coordsToLatLng || this.coordsToLatLng;
@@ -6010,37 +6198,37 @@ L.extend(L.GeoJSON, {
case 'MultiPoint':
for (i = 0, len = coords.length; i < len; i++) {
latlng = coordsToLatLng(coords[i]);
- layer = pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng);
- layers.push(layer);
+ layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng));
}
return new L.FeatureGroup(layers);
case 'LineString':
latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng);
- return new L.Polyline(latlngs);
+ return new L.Polyline(latlngs, vectorOptions);
case 'Polygon':
+ if (coords.length === 2 && !coords[1].length) {
+ throw new Error('Invalid GeoJSON object.');
+ }
latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
- return new L.Polygon(latlngs);
+ return new L.Polygon(latlngs, vectorOptions);
case 'MultiLineString':
latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
- return new L.MultiPolyline(latlngs);
+ return new L.MultiPolyline(latlngs, vectorOptions);
case 'MultiPolygon':
latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng);
- return new L.MultiPolygon(latlngs);
+ return new L.MultiPolygon(latlngs, vectorOptions);
case 'GeometryCollection':
for (i = 0, len = geometry.geometries.length; i < len; i++) {
- layer = this.geometryToLayer({
+ layers.push(this.geometryToLayer({
geometry: geometry.geometries[i],
type: 'Feature',
properties: geojson.properties
- }, pointToLayer, coordsToLatLng);
-
- layers.push(layer);
+ }, pointToLayer, coordsToLatLng, vectorOptions));
}
return new L.FeatureGroup(layers);
@@ -6050,7 +6238,7 @@ L.extend(L.GeoJSON, {
},
coordsToLatLng: function (coords) { // (Array[, Boolean]) -> LatLng
- return new L.LatLng(coords[1], coords[0]);
+ return new L.LatLng(coords[1], coords[0], coords[2]);
},
coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) { // (Array[, Number, Function]) -> Array
@@ -6068,8 +6256,13 @@ L.extend(L.GeoJSON, {
return latlngs;
},
- latLngToCoords: function (latLng) {
- return [latLng.lng, latLng.lat];
+ latLngToCoords: function (latlng) {
+ var coords = [latlng.lng, latlng.lat];
+
+ if (latlng.alt !== undefined) {
+ coords.push(latlng.alt);
+ }
+ return coords;
},
latLngsToCoords: function (latLngs) {
@@ -6144,43 +6337,58 @@ L.Polygon.include({
});
(function () {
- function includeMulti(Klass, type) {
- Klass.include({
- toGeoJSON: function () {
- var coords = [];
+ function multiToGeoJSON(type) {
+ return function () {
+ var coords = [];
- this.eachLayer(function (layer) {
- coords.push(layer.toGeoJSON().geometry.coordinates);
- });
+ this.eachLayer(function (layer) {
+ coords.push(layer.toGeoJSON().geometry.coordinates);
+ });
- return L.GeoJSON.getFeature(this, {
- type: type,
- coordinates: coords
- });
- }
- });
- }
-
- includeMulti(L.MultiPolyline, 'MultiLineString');
- includeMulti(L.MultiPolygon, 'MultiPolygon');
-}());
-
-L.LayerGroup.include({
- toGeoJSON: function () {
- var features = [];
-
- this.eachLayer(function (layer) {
- if (layer.toGeoJSON) {
- features.push(L.GeoJSON.asFeature(layer.toGeoJSON()));
- }
- });
-
- return {
- type: 'FeatureCollection',
- features: features
+ return L.GeoJSON.getFeature(this, {
+ type: type,
+ coordinates: coords
+ });
};
}
-});
+
+ L.MultiPolyline.include({toGeoJSON: multiToGeoJSON('MultiLineString')});
+ L.MultiPolygon.include({toGeoJSON: multiToGeoJSON('MultiPolygon')});
+
+ L.LayerGroup.include({
+ toGeoJSON: function () {
+
+ var geometry = this.feature && this.feature.geometry,
+ jsons = [],
+ json;
+
+ if (geometry && geometry.type === 'MultiPoint') {
+ return multiToGeoJSON('MultiPoint').call(this);
+ }
+
+ var isGeometryCollection = geometry && geometry.type === 'GeometryCollection';
+
+ this.eachLayer(function (layer) {
+ if (layer.toGeoJSON) {
+ json = layer.toGeoJSON();
+ jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));
+ }
+ });
+
+ if (isGeometryCollection) {
+ return L.GeoJSON.getFeature(this, {
+ geometries: jsons,
+ type: 'GeometryCollection'
+ });
+ }
+
+ return {
+ type: 'FeatureCollection',
+ features: jsons
+ };
+ }
+ });
+}());
L.geoJson = function (geojson, options) {
return new L.GeoJSON(geojson, options);
@@ -6205,8 +6413,8 @@ L.DomEvent = {
return fn.call(context || obj, e || L.DomEvent._getEvent());
};
- if (L.Browser.msTouch && type.indexOf('touch') === 0) {
- return this.addMsTouchListener(obj, type, handler, id);
+ if (L.Browser.pointer && type.indexOf('touch') === 0) {
+ return this.addPointerListener(obj, type, handler, id);
}
if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) {
this.addDoubleTapListener(obj, handler, id);
@@ -6258,8 +6466,8 @@ L.DomEvent = {
if (!handler) { return this; }
- if (L.Browser.msTouch && type.indexOf('touch') === 0) {
- this.removeMsTouchListener(obj, type, id);
+ if (L.Browser.pointer && type.indexOf('touch') === 0) {
+ this.removePointerListener(obj, type, id);
} else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {
this.removeDoubleTapListener(obj, id);
@@ -6290,19 +6498,29 @@ L.DomEvent = {
} else {
e.cancelBubble = true;
}
+ L.DomEvent._skipped(e);
+
return this;
},
+ disableScrollPropagation: function (el) {
+ var stop = L.DomEvent.stopPropagation;
+
+ return L.DomEvent
+ .on(el, 'mousewheel', stop)
+ .on(el, 'MozMousePixelScroll', stop);
+ },
+
disableClickPropagation: function (el) {
var stop = L.DomEvent.stopPropagation;
for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
- L.DomEvent.addListener(el, L.Draggable.START[i], stop);
+ L.DomEvent.on(el, L.Draggable.START[i], stop);
}
return L.DomEvent
- .addListener(el, 'click', L.DomEvent._fakeStop)
- .addListener(el, 'dblclick', stop);
+ .on(el, 'click', L.DomEvent._fakeStop)
+ .on(el, 'dblclick', stop);
},
preventDefault: function (e) {
@@ -6316,34 +6534,31 @@ L.DomEvent = {
},
stop: function (e) {
- return L.DomEvent.preventDefault(e).stopPropagation(e);
+ return L.DomEvent
+ .preventDefault(e)
+ .stopPropagation(e);
},
getMousePosition: function (e, container) {
-
- var ie7 = L.Browser.ie7,
- body = document.body,
+ var body = document.body,
docEl = document.documentElement,
- x = e.pageX ? e.pageX - body.scrollLeft - docEl.scrollLeft: e.clientX,
+ //gecko makes scrollLeft more negative as you scroll in rtl, other browsers don't
+ //ref: https://code.google.com/p/closure-library/source/browse/closure/goog/style/bidi.js
+ x = L.DomUtil.documentIsLtr() ?
+ (e.pageX ? e.pageX - body.scrollLeft - docEl.scrollLeft : e.clientX) :
+ (L.Browser.gecko ? e.pageX - body.scrollLeft - docEl.scrollLeft :
+ e.pageX ? e.pageX - body.scrollLeft + docEl.scrollLeft : e.clientX),
y = e.pageY ? e.pageY - body.scrollTop - docEl.scrollTop: e.clientY,
- pos = new L.Point(x, y),
- rect = container.getBoundingClientRect(),
+ pos = new L.Point(x, y);
+
+ if (!container) {
+ return pos;
+ }
+
+ var rect = container.getBoundingClientRect(),
left = rect.left - container.clientLeft,
top = rect.top - container.clientTop;
- // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else
- // https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js
- if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) {
- left += container.scrollWidth - container.clientWidth;
-
- // ie7 shows the scrollbar by default and provides clientWidth counting it, so we
- // need to add it back in if it is visible; scrollbar is on the left as we are RTL
- if (ie7 && L.DomUtil.getStyle(container, 'overflow-y') !== 'hidden' &&
- L.DomUtil.getStyle(container, 'overflow') !== 'hidden') {
- left += 17;
- }
- }
-
return pos._subtract(new L.Point(left, top));
},
@@ -6443,11 +6658,13 @@ L.Draggable = L.Class.extend({
END: {
mousedown: 'mouseup',
touchstart: 'touchend',
+ pointerdown: 'touchend',
MSPointerDown: 'touchend'
},
MOVE: {
mousedown: 'mousemove',
touchstart: 'touchmove',
+ pointerdown: 'touchmove',
MSPointerDown: 'touchmove'
}
},
@@ -6479,28 +6696,21 @@ L.Draggable = L.Class.extend({
},
_onDown: function (e) {
+ this._moved = false;
+
if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
- L.DomEvent
- .stopPropagation(e);
+ L.DomEvent.stopPropagation(e);
if (L.Draggable._disabled) { return; }
L.DomUtil.disableImageDrag();
L.DomUtil.disableTextSelection();
- var first = e.touches ? e.touches[0] : e,
- el = first.target;
-
- // if touching a link, highlight it
- if (L.Browser.touch && el.tagName.toLowerCase() === 'a') {
- L.DomUtil.addClass(el, 'leaflet-active');
- }
-
- this._moved = false;
-
if (this._moving) { return; }
+ var first = e.touches ? e.touches[0] : e;
+
this._startPoint = new L.Point(first.clientX, first.clientY);
this._startPos = this._newPos = L.DomUtil.getPosition(this._element);
@@ -6510,7 +6720,10 @@ L.Draggable = L.Class.extend({
},
_onMove: function (e) {
- if (e.touches && e.touches.length > 1) { return; }
+ if (e.touches && e.touches.length > 1) {
+ this._moved = true;
+ return;
+ }
var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
newPoint = new L.Point(first.clientX, first.clientY),
@@ -6526,9 +6739,8 @@ L.Draggable = L.Class.extend({
this._moved = true;
this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);
- if (!L.Browser.touch) {
- L.DomUtil.addClass(document.body, 'leaflet-dragging');
- }
+ L.DomUtil.addClass(document.body, 'leaflet-dragging');
+ L.DomUtil.addClass((e.target || e.srcElement), 'leaflet-drag-target');
}
this._newPos = this._startPos.add(offset);
@@ -6544,10 +6756,9 @@ L.Draggable = L.Class.extend({
this.fire('drag');
},
- _onUp: function () {
- if (!L.Browser.touch) {
- L.DomUtil.removeClass(document.body, 'leaflet-dragging');
- }
+ _onUp: function (e) {
+ L.DomUtil.removeClass(document.body, 'leaflet-dragging');
+ L.DomUtil.removeClass((e.target || e.srcElement), 'leaflet-drag-target');
for (var i in L.Draggable.MOVE) {
L.DomEvent
@@ -6562,7 +6773,9 @@ L.Draggable = L.Class.extend({
// ensure drag is not fired after dragend
L.Util.cancelAnimFrame(this._animRequest);
- this.fire('dragend');
+ this.fire('dragend', {
+ distance: this._newPos.distanceTo(this._startPos)
+ });
}
this._moving = false;
@@ -6634,7 +6847,7 @@ L.Map.Drag = L.Handler.extend({
this._draggable.on('predrag', this._onPreDrag, this);
map.on('viewreset', this._onViewReset, this);
- this._onViewReset();
+ map.whenReady(this._onViewReset, this);
}
}
this._draggable.enable();
@@ -6706,14 +6919,14 @@ L.Map.Drag = L.Handler.extend({
this._draggable._newPos.x = newX;
},
- _onDragEnd: function () {
+ _onDragEnd: function (e) {
var map = this._map,
options = map.options,
delay = +new Date() - this._lastTime,
noInertia = !options.inertia || delay > options.inertiaThreshold || !this._positions[0];
- map.fire('dragend');
+ map.fire('dragend', e);
if (noInertia) {
map.fire('moveend');
@@ -6737,6 +6950,8 @@ L.Map.Drag = L.Handler.extend({
map.fire('moveend');
} else {
+ offset = map._limitOffset(offset, map.options.maxBounds);
+
L.Util.requestAnimFrame(function () {
map.panBy(offset, {
duration: decelerationDuration,
@@ -6771,7 +6986,7 @@ L.Map.DoubleClickZoom = L.Handler.extend({
_onDoubleClick: function (e) {
var map = this._map,
- zoom = map.getZoom() + 1;
+ zoom = map.getZoom() + (e.originalEvent.shiftKey ? -1 : 1);
if (map.options.doubleClickZoom === 'center') {
map.setZoom(zoom);
@@ -6854,8 +7069,8 @@ L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
L.extend(L.DomEvent, {
- _touchstart: L.Browser.msTouch ? 'MSPointerDown' : 'touchstart',
- _touchend: L.Browser.msTouch ? 'MSPointerUp' : 'touchend',
+ _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
+ _touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend',
// inspired by Zepto touch code by Thomas Fuchs
addDoubleTapListener: function (obj, handler, id) {
@@ -6871,7 +7086,7 @@ L.extend(L.DomEvent, {
function onTouchStart(e) {
var count;
- if (L.Browser.msTouch) {
+ if (L.Browser.pointer) {
trackedTouches.push(e.pointerId);
count = trackedTouches.length;
} else {
@@ -6890,7 +7105,7 @@ L.extend(L.DomEvent, {
}
function onTouchEnd(e) {
- if (L.Browser.msTouch) {
+ if (L.Browser.pointer) {
var idx = trackedTouches.indexOf(e.pointerId);
if (idx === -1) {
return;
@@ -6899,7 +7114,7 @@ L.extend(L.DomEvent, {
}
if (doubleTap) {
- if (L.Browser.msTouch) {
+ if (L.Browser.pointer) {
// work around .type being readonly with MSPointer* events
var newTouch = { },
prop;
@@ -6923,15 +7138,15 @@ L.extend(L.DomEvent, {
obj[pre + touchstart + id] = onTouchStart;
obj[pre + touchend + id] = onTouchEnd;
- // on msTouch we need to listen on the document, otherwise a drag starting on the map and moving off screen
+ // on pointer we need to listen on the document, otherwise a drag starting on the map and moving off screen
// will not come through to us, so we will lose track of how many touches are ongoing
- var endElement = L.Browser.msTouch ? document.documentElement : obj;
+ var endElement = L.Browser.pointer ? document.documentElement : obj;
obj.addEventListener(touchstart, onTouchStart, false);
endElement.addEventListener(touchend, onTouchEnd, false);
- if (L.Browser.msTouch) {
- endElement.addEventListener('MSPointerCancel', onTouchEnd, false);
+ if (L.Browser.pointer) {
+ endElement.addEventListener(L.DomEvent.POINTER_CANCEL, onTouchEnd, false);
}
return this;
@@ -6941,11 +7156,12 @@ L.extend(L.DomEvent, {
var pre = '_leaflet_';
obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false);
- (L.Browser.msTouch ? document.documentElement : obj).removeEventListener(
+ (L.Browser.pointer ? document.documentElement : obj).removeEventListener(
this._touchend, obj[pre + this._touchend + id], false);
- if (L.Browser.msTouch) {
- document.documentElement.removeEventListener('MSPointerCancel', obj[pre + this._touchend + id], false);
+ if (L.Browser.pointer) {
+ document.documentElement.removeEventListener(L.DomEvent.POINTER_CANCEL, obj[pre + this._touchend + id],
+ false);
}
return this;
@@ -6959,81 +7175,90 @@ L.extend(L.DomEvent, {
L.extend(L.DomEvent, {
- _msTouches: [],
- _msDocumentListener: false,
+ //static
+ POINTER_DOWN: L.Browser.msPointer ? 'MSPointerDown' : 'pointerdown',
+ POINTER_MOVE: L.Browser.msPointer ? 'MSPointerMove' : 'pointermove',
+ POINTER_UP: L.Browser.msPointer ? 'MSPointerUp' : 'pointerup',
+ POINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel',
- // Provides a touch events wrapper for msPointer events.
+ _pointers: [],
+ _pointerDocumentListener: false,
+
+ // Provides a touch events wrapper for (ms)pointer events.
// Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019
+ //ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
- addMsTouchListener: function (obj, type, handler, id) {
+ addPointerListener: function (obj, type, handler, id) {
switch (type) {
case 'touchstart':
- return this.addMsTouchListenerStart(obj, type, handler, id);
+ return this.addPointerListenerStart(obj, type, handler, id);
case 'touchend':
- return this.addMsTouchListenerEnd(obj, type, handler, id);
+ return this.addPointerListenerEnd(obj, type, handler, id);
case 'touchmove':
- return this.addMsTouchListenerMove(obj, type, handler, id);
+ return this.addPointerListenerMove(obj, type, handler, id);
default:
throw 'Unknown touch event type';
}
},
- addMsTouchListenerStart: function (obj, type, handler, id) {
+ addPointerListenerStart: function (obj, type, handler, id) {
var pre = '_leaflet_',
- touches = this._msTouches;
+ pointers = this._pointers;
var cb = function (e) {
+ L.DomEvent.preventDefault(e);
+
var alreadyInArray = false;
- for (var i = 0; i < touches.length; i++) {
- if (touches[i].pointerId === e.pointerId) {
+ for (var i = 0; i < pointers.length; i++) {
+ if (pointers[i].pointerId === e.pointerId) {
alreadyInArray = true;
break;
}
}
if (!alreadyInArray) {
- touches.push(e);
+ pointers.push(e);
}
- e.touches = touches.slice();
+ e.touches = pointers.slice();
e.changedTouches = [e];
handler(e);
};
obj[pre + 'touchstart' + id] = cb;
- obj.addEventListener('MSPointerDown', cb, false);
+ obj.addEventListener(this.POINTER_DOWN, cb, false);
- // need to also listen for end events to keep the _msTouches list accurate
+ // need to also listen for end events to keep the _pointers list accurate
// this needs to be on the body and never go away
- if (!this._msDocumentListener) {
+ if (!this._pointerDocumentListener) {
var internalCb = function (e) {
- for (var i = 0; i < touches.length; i++) {
- if (touches[i].pointerId === e.pointerId) {
- touches.splice(i, 1);
+ for (var i = 0; i < pointers.length; i++) {
+ if (pointers[i].pointerId === e.pointerId) {
+ pointers.splice(i, 1);
break;
}
}
};
//We listen on the documentElement as any drags that end by moving the touch off the screen get fired there
- document.documentElement.addEventListener('MSPointerUp', internalCb, false);
- document.documentElement.addEventListener('MSPointerCancel', internalCb, false);
+ document.documentElement.addEventListener(this.POINTER_UP, internalCb, false);
+ document.documentElement.addEventListener(this.POINTER_CANCEL, internalCb, false);
- this._msDocumentListener = true;
+ this._pointerDocumentListener = true;
}
return this;
},
- addMsTouchListenerMove: function (obj, type, handler, id) {
+ addPointerListenerMove: function (obj, type, handler, id) {
var pre = '_leaflet_',
- touches = this._msTouches;
+ touches = this._pointers;
function cb(e) {
// don't fire touch moves when mouse isn't down
- if (e.pointerType === e.MSPOINTER_TYPE_MOUSE && e.buttons === 0) { return; }
+ if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
for (var i = 0; i < touches.length; i++) {
if (touches[i].pointerId === e.pointerId) {
@@ -7049,14 +7274,14 @@ L.extend(L.DomEvent, {
}
obj[pre + 'touchmove' + id] = cb;
- obj.addEventListener('MSPointerMove', cb, false);
+ obj.addEventListener(this.POINTER_MOVE, cb, false);
return this;
},
- addMsTouchListenerEnd: function (obj, type, handler, id) {
+ addPointerListenerEnd: function (obj, type, handler, id) {
var pre = '_leaflet_',
- touches = this._msTouches;
+ touches = this._pointers;
var cb = function (e) {
for (var i = 0; i < touches.length; i++) {
@@ -7073,26 +7298,26 @@ L.extend(L.DomEvent, {
};
obj[pre + 'touchend' + id] = cb;
- obj.addEventListener('MSPointerUp', cb, false);
- obj.addEventListener('MSPointerCancel', cb, false);
+ obj.addEventListener(this.POINTER_UP, cb, false);
+ obj.addEventListener(this.POINTER_CANCEL, cb, false);
return this;
},
- removeMsTouchListener: function (obj, type, id) {
+ removePointerListener: function (obj, type, id) {
var pre = '_leaflet_',
cb = obj[pre + type + id];
switch (type) {
case 'touchstart':
- obj.removeEventListener('MSPointerDown', cb, false);
+ obj.removeEventListener(this.POINTER_DOWN, cb, false);
break;
case 'touchmove':
- obj.removeEventListener('MSPointerMove', cb, false);
+ obj.removeEventListener(this.POINTER_MOVE, cb, false);
break;
case 'touchend':
- obj.removeEventListener('MSPointerUp', cb, false);
- obj.removeEventListener('MSPointerCancel', cb, false);
+ obj.removeEventListener(this.POINTER_UP, cb, false);
+ obj.removeEventListener(this.POINTER_CANCEL, cb, false);
break;
}
@@ -7106,7 +7331,8 @@ L.extend(L.DomEvent, {
*/
L.Map.mergeOptions({
- touchZoom: L.Browser.touch && !L.Browser.android23
+ touchZoom: L.Browser.touch && !L.Browser.android23,
+ bounceAtZoomLimits: true
});
L.Map.TouchZoom = L.Handler.extend({
@@ -7159,6 +7385,11 @@ L.Map.TouchZoom = L.Handler.extend({
if (this._scale === 1) { return; }
+ if (!map.options.bounceAtZoomLimits) {
+ if ((map.getZoom() === map.getMinZoom() && this._scale < 1) ||
+ (map.getZoom() === map.getMaxZoom() && this._scale > 1)) { return; }
+ }
+
if (!this._moved) {
L.DomUtil.addClass(map._mapPane, 'leaflet-touching');
@@ -7262,7 +7493,7 @@ L.Map.Tap = L.Handler.extend({
this._startPos = this._newPos = new L.Point(first.clientX, first.clientY);
// if touching a link, highlight it
- if (el.tagName.toLowerCase() === 'a') {
+ if (el.tagName && el.tagName.toLowerCase() === 'a') {
L.DomUtil.addClass(el, 'leaflet-active');
}
@@ -7292,7 +7523,7 @@ L.Map.Tap = L.Handler.extend({
var first = e.changedTouches[0],
el = first.target;
- if (el.tagName.toLowerCase() === 'a') {
+ if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
L.DomUtil.removeClass(el, 'leaflet-active');
}
@@ -7328,7 +7559,7 @@ L.Map.Tap = L.Handler.extend({
}
});
-if (L.Browser.touch && !L.Browser.msTouch) {
+if (L.Browser.touch && !L.Browser.pointer) {
L.Map.addInitHook('addHandler', 'tap', L.Map.Tap);
}
@@ -7347,6 +7578,7 @@ L.Map.BoxZoom = L.Handler.extend({
this._map = map;
this._container = map._container;
this._pane = map._panes.overlayPane;
+ this._moved = false;
},
addHooks: function () {
@@ -7355,9 +7587,16 @@ L.Map.BoxZoom = L.Handler.extend({
removeHooks: function () {
L.DomEvent.off(this._container, 'mousedown', this._onMouseDown);
+ this._moved = false;
+ },
+
+ moved: function () {
+ return this._moved;
},
_onMouseDown: function (e) {
+ this._moved = false;
+
if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
L.DomUtil.disableTextSelection();
@@ -7365,21 +7604,22 @@ L.Map.BoxZoom = L.Handler.extend({
this._startLayerPoint = this._map.mouseEventToLayerPoint(e);
- this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane);
- L.DomUtil.setPosition(this._box, this._startLayerPoint);
-
- //TODO refactor: move cursor to styles
- this._container.style.cursor = 'crosshair';
-
L.DomEvent
.on(document, 'mousemove', this._onMouseMove, this)
.on(document, 'mouseup', this._onMouseUp, this)
.on(document, 'keydown', this._onKeyDown, this);
-
- this._map.fire('boxzoomstart');
},
_onMouseMove: function (e) {
+ if (!this._moved) {
+ this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane);
+ L.DomUtil.setPosition(this._box, this._startLayerPoint);
+
+ //TODO refactor: move cursor to styles
+ this._container.style.cursor = 'crosshair';
+ this._map.fire('boxzoomstart');
+ }
+
var startPoint = this._startLayerPoint,
box = this._box,
@@ -7392,14 +7632,18 @@ L.Map.BoxZoom = L.Handler.extend({
L.DomUtil.setPosition(box, newPos);
+ this._moved = true;
+
// TODO refactor: remove hardcoded 4 pixels
box.style.width = (Math.max(0, Math.abs(offset.x) - 4)) + 'px';
box.style.height = (Math.max(0, Math.abs(offset.y) - 4)) + 'px';
},
_finish: function () {
- this._pane.removeChild(this._box);
- this._container.style.cursor = '';
+ if (this._moved) {
+ this._pane.removeChild(this._box);
+ this._container.style.cursor = '';
+ }
L.DomUtil.enableTextSelection();
L.DomUtil.enableImageDrag();
@@ -7457,7 +7701,7 @@ L.Map.Keyboard = L.Handler.extend({
right: [39],
down: [40],
up: [38],
- zoomIn: [187, 107, 61],
+ zoomIn: [187, 107, 61, 171],
zoomOut: [189, 109, 173]
},
@@ -7507,7 +7751,7 @@ L.Map.Keyboard = L.Handler.extend({
var body = document.body,
docEl = document.documentElement,
top = body.scrollTop || docEl.scrollTop,
- left = body.scrollTop || docEl.scrollLeft;
+ left = body.scrollLeft || docEl.scrollLeft;
this._map._container.focus();
@@ -7612,6 +7856,7 @@ L.Handler.MarkerDrag = L.Handler.extend({
.on('drag', this._onDrag, this)
.on('dragend', this._onDragEnd, this);
this._draggable.enable();
+ L.DomUtil.addClass(this._marker._icon, 'leaflet-marker-draggable');
},
removeHooks: function () {
@@ -7621,6 +7866,7 @@ L.Handler.MarkerDrag = L.Handler.extend({
.off('dragend', this._onDragEnd, this);
this._draggable.disable();
+ L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');
},
moved: function () {
@@ -7652,10 +7898,10 @@ L.Handler.MarkerDrag = L.Handler.extend({
.fire('drag');
},
- _onDragEnd: function () {
+ _onDragEnd: function (e) {
this._marker
.fire('moveend')
- .fire('dragend');
+ .fire('dragend', e);
}
});
@@ -7728,6 +7974,12 @@ L.Control = L.Class.extend({
}
return this;
+ },
+
+ _refocusOnMap: function () {
+ if (this._map) {
+ this._map.getContainer().focus();
+ }
}
});
@@ -7779,7 +8031,11 @@ L.Map.include({
L.Control.Zoom = L.Control.extend({
options: {
- position: 'topleft'
+ position: 'topleft',
+ zoomInText: '+',
+ zoomInTitle: 'Zoom in',
+ zoomOutText: '-',
+ zoomOutTitle: 'Zoom out'
},
onAdd: function (map) {
@@ -7789,10 +8045,13 @@ L.Control.Zoom = L.Control.extend({
this._map = map;
this._zoomInButton = this._createButton(
- '+', 'Zoom in', zoomName + '-in', container, this._zoomIn, this);
+ this.options.zoomInText, this.options.zoomInTitle,
+ zoomName + '-in', container, this._zoomIn, this);
this._zoomOutButton = this._createButton(
- '-', 'Zoom out', zoomName + '-out', container, this._zoomOut, this);
+ this.options.zoomOutText, this.options.zoomOutTitle,
+ zoomName + '-out', container, this._zoomOut, this);
+ this._updateDisabled();
map.on('zoomend zoomlevelschange', this._updateDisabled, this);
return container;
@@ -7823,7 +8082,8 @@ L.Control.Zoom = L.Control.extend({
.on(link, 'mousedown', stop)
.on(link, 'dblclick', stop)
.on(link, 'click', L.DomEvent.preventDefault)
- .on(link, 'click', fn, context);
+ .on(link, 'click', fn, context)
+ .on(link, 'click', this._refocusOnMap, context);
return link;
},
@@ -7881,6 +8141,12 @@ L.Control.Attribution = L.Control.extend({
this._container = L.DomUtil.create('div', 'leaflet-control-attribution');
L.DomEvent.disableClickPropagation(this._container);
+ for (var i in map._layers) {
+ if (map._layers[i].getAttribution) {
+ this.addAttribution(map._layers[i].getAttribution());
+ }
+ }
+
map
.on('layeradd', this._onLayerAdd, this)
.on('layerremove', this._onLayerRemove, this);
@@ -8163,8 +8429,9 @@ L.Control.Layers = L.Control.extend({
container.setAttribute('aria-haspopup', true);
if (!L.Browser.touch) {
- L.DomEvent.disableClickPropagation(container);
- L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation);
+ L.DomEvent
+ .disableClickPropagation(container)
+ .disableScrollPropagation(container);
} else {
L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
}
@@ -8189,6 +8456,10 @@ L.Control.Layers = L.Control.extend({
else {
L.DomEvent.on(link, 'focus', this._expand, this);
}
+ //Work around for Firefox android issue https://github.com/Leaflet/Leaflet/issues/2033
+ L.DomEvent.on(form, 'click', function () {
+ setTimeout(L.bind(this._onInputClick, this), 0);
+ }, this);
this._map.on('click', this._collapse, this);
// TODO keyboard accessibility
@@ -8323,6 +8594,8 @@ L.Control.Layers = L.Control.extend({
}
this._handlingClick = false;
+
+ this._refocusOnMap();
},
_expand: function () {
@@ -8443,8 +8716,8 @@ L.Map.include({
setView: function (center, zoom, options) {
- zoom = this._limitZoom(zoom);
- center = L.latLng(center);
+ zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
+ center = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds);
options = options || {};
if (this._panAnim) {
@@ -8900,7 +9173,8 @@ L.Map.include({
var data = {
latlng: latlng,
- bounds: bounds
+ bounds: bounds,
+ timestamp: pos.timestamp
};
for (var i in pos.coords) {
@@ -8914,4 +9188,4 @@ L.Map.include({
});
-}(window, document));
\ No newline at end of file
+}(window, document));