Merge branch 'master' into openstreetbugs
Conflicts: Gemfile.lock app/views/browse/_map.html.erb app/views/user/view.html.erb config/locales/en.yml config/openlayers.cfg db/structure.sql vendor/assets/openlayers/OpenLayers.js
1
.gitignore
vendored
|
@ -3,3 +3,4 @@ public/assets
|
|||
public/attachments
|
||||
tmp
|
||||
.DS_Store
|
||||
*~
|
||||
|
|
24
Gemfile
|
@ -2,7 +2,10 @@
|
|||
source 'http://rubygems.org'
|
||||
|
||||
# Require rails
|
||||
gem 'rails', '3.2.2'
|
||||
gem 'rails', '3.2.8'
|
||||
|
||||
# Require things which have moved to gems in ruby 1.9
|
||||
gem 'bigdecimal', :platforms => :ruby_19
|
||||
|
||||
# Require the postgres database driver
|
||||
gem 'pg'
|
||||
|
@ -11,26 +14,36 @@ gem 'pg'
|
|||
gem 'jquery-rails'
|
||||
|
||||
# Load rails plugins
|
||||
gem 'rails-i18n', ">= 0.5.1"
|
||||
gem 'rails-i18n', ">= 0.6.3"
|
||||
gem 'dynamic_form'
|
||||
gem 'rinku', '>= 1.2.2', :require => 'rails_rinku'
|
||||
gem 'oauth-plugin', '>= 0.4.0.pre7'
|
||||
gem 'oauth-plugin', '>= 0.4.1', :require => 'oauth-plugin'
|
||||
gem 'open_id_authentication', '>= 1.1.0'
|
||||
gem 'validates_email_format_of', '>= 1.5.1'
|
||||
gem 'composite_primary_keys', '>= 5.0.0'
|
||||
gem 'composite_primary_keys', '>= 5.0.8'
|
||||
gem 'http_accept_language', '>= 1.0.2'
|
||||
gem 'paperclip', '~> 2.0'
|
||||
gem 'deadlock_retry', '>= 1.2.0'
|
||||
gem 'jsonify-rails'
|
||||
|
||||
# We need ruby-openid 2.2.0 or later for ruby 1.9 support
|
||||
gem 'ruby-openid', '>= 2.2.0'
|
||||
|
||||
# Browser detection support
|
||||
gem 'browser'
|
||||
|
||||
# Markdown formatting support
|
||||
gem 'redcarpet'
|
||||
|
||||
# Character conversion support for ruby 1.8
|
||||
gem 'iconv', :platforms => :ruby_18
|
||||
|
||||
# Load libxml support for XML parsing and generation
|
||||
gem 'libxml-ruby', '>= 2.0.5', :require => 'libxml'
|
||||
|
||||
# Load HTML sanitizer
|
||||
# Use for HTML sanitisation
|
||||
gem 'sanitize'
|
||||
gem 'htmlentities'
|
||||
|
||||
# Load SystemTimer for implementing request timeouts
|
||||
gem 'SystemTimer', '>= 1.1.3', :require => 'system_timer', :platforms => :ruby_18
|
||||
|
@ -44,6 +57,7 @@ gem 'memcached', '>= 1.4.1'
|
|||
# Gems needed for running tests
|
||||
group :test do
|
||||
gem 'timecop'
|
||||
gem 'minitest', :platforms => :ruby_19
|
||||
end
|
||||
|
||||
# Gems needed for compiling assets
|
||||
|
|
156
Gemfile.lock
|
@ -2,35 +2,36 @@ GEM
|
|||
remote: http://rubygems.org/
|
||||
specs:
|
||||
SystemTimer (1.2.3)
|
||||
actionmailer (3.2.2)
|
||||
actionpack (= 3.2.2)
|
||||
mail (~> 2.4.0)
|
||||
actionpack (3.2.2)
|
||||
activemodel (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
actionmailer (3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
mail (~> 2.4.4)
|
||||
actionpack (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.1)
|
||||
journey (~> 1.0.4)
|
||||
rack (~> 1.4.0)
|
||||
rack-cache (~> 1.1)
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.1.2)
|
||||
activemodel (3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
sprockets (~> 2.1.3)
|
||||
activemodel (3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.2)
|
||||
activemodel (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
activerecord (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.2)
|
||||
activemodel (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
activesupport (3.2.2)
|
||||
activeresource (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
activesupport (3.2.8)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
addressable (2.2.7)
|
||||
arel (3.0.2)
|
||||
bigdecimal (1.1.0)
|
||||
browser (0.1.4)
|
||||
builder (3.0.0)
|
||||
cocaine (0.2.1)
|
||||
coffee-rails (3.2.2)
|
||||
|
@ -39,53 +40,59 @@ GEM
|
|||
coffee-script (2.2.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.2.0)
|
||||
composite_primary_keys (5.0.1)
|
||||
coffee-script-source (1.3.3)
|
||||
composite_primary_keys (5.0.8)
|
||||
activerecord (~> 3.2.0)
|
||||
deadlock_retry (1.2.0)
|
||||
dynamic_form (1.1.4)
|
||||
erubis (2.7.0)
|
||||
execjs (1.3.0)
|
||||
execjs (1.4.0)
|
||||
multi_json (~> 1.0)
|
||||
faraday (0.7.6)
|
||||
addressable (~> 2.2)
|
||||
faraday (0.8.4)
|
||||
multipart-post (~> 1.1)
|
||||
rack (~> 1.1)
|
||||
hike (1.2.1)
|
||||
htmlentities (4.3.1)
|
||||
http_accept_language (1.0.2)
|
||||
httpclient (2.2.4)
|
||||
httpauth (0.1)
|
||||
httpclient (2.2.7)
|
||||
i18n (0.6.0)
|
||||
iconv (0.1)
|
||||
journey (1.0.3)
|
||||
jquery-rails (2.0.1)
|
||||
railties (>= 3.2.0, < 5.0)
|
||||
journey (1.0.4)
|
||||
jquery-rails (2.1.1)
|
||||
railties (>= 3.1.0, < 5.0)
|
||||
thor (~> 0.14)
|
||||
json (1.6.5)
|
||||
json (1.7.5)
|
||||
jsonify (0.3.1)
|
||||
multi_json (~> 1.0)
|
||||
jsonify-rails (0.3.1)
|
||||
jsonify-rails (0.3.2)
|
||||
actionpack
|
||||
jsonify (>= 0.3.1)
|
||||
jsonify (< 0.4.0)
|
||||
jwt (0.1.5)
|
||||
multi_json (>= 1.0)
|
||||
libv8 (3.3.10.4)
|
||||
libxml-ruby (2.2.2)
|
||||
mail (2.4.3)
|
||||
libxml-ruby (2.3.3)
|
||||
mail (2.4.4)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
memcached (1.4.1)
|
||||
mime-types (1.17.2)
|
||||
multi_json (1.1.0)
|
||||
memcached (1.4.3)
|
||||
mime-types (1.19)
|
||||
minitest (3.3.0)
|
||||
multi_json (1.3.6)
|
||||
multipart-post (1.1.5)
|
||||
nokogiri (1.5.0)
|
||||
oauth (0.4.5)
|
||||
oauth-plugin (0.4.0.rc2)
|
||||
nokogiri (1.5.5)
|
||||
oauth (0.4.6)
|
||||
oauth-plugin (0.4.1)
|
||||
multi_json
|
||||
oauth (~> 0.4.4)
|
||||
oauth2
|
||||
oauth2 (>= 0.5.0)
|
||||
rack
|
||||
oauth2 (0.5.2)
|
||||
faraday (~> 0.7)
|
||||
oauth2 (0.8.0)
|
||||
faraday (~> 0.8)
|
||||
httpauth (~> 0.1)
|
||||
jwt (~> 0.1.4)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.2)
|
||||
open_id_authentication (1.1.0)
|
||||
rack-openid (~> 1.3)
|
||||
paperclip (2.7.0)
|
||||
|
@ -93,7 +100,7 @@ GEM
|
|||
activesupport (>= 2.3.2)
|
||||
cocaine (>= 0.0.2)
|
||||
mime-types
|
||||
pg (0.13.2)
|
||||
pg (0.14.0)
|
||||
polyglot (0.3.3)
|
||||
rack (1.4.1)
|
||||
rack-cache (1.2)
|
||||
|
@ -105,51 +112,52 @@ GEM
|
|||
rack
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.2)
|
||||
actionmailer (= 3.2.2)
|
||||
actionpack (= 3.2.2)
|
||||
activerecord (= 3.2.2)
|
||||
activeresource (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
rails (3.2.8)
|
||||
actionmailer (= 3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
activerecord (= 3.2.8)
|
||||
activeresource (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.2)
|
||||
rails-i18n (0.5.1)
|
||||
railties (= 3.2.8)
|
||||
rails-i18n (0.6.5)
|
||||
i18n (~> 0.5)
|
||||
railties (3.2.2)
|
||||
actionpack (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
railties (3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (~> 0.14.6)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rake (0.9.2.2)
|
||||
rdoc (3.12)
|
||||
json (~> 1.4)
|
||||
rinku (1.5.1)
|
||||
ruby-openid (2.1.8)
|
||||
redcarpet (2.1.1)
|
||||
rinku (1.7.0)
|
||||
ruby-openid (2.2.0)
|
||||
sanitize (2.0.3)
|
||||
nokogiri (>= 1.4.4, < 1.6)
|
||||
sass (3.1.15)
|
||||
sass-rails (3.2.4)
|
||||
sass (3.2.1)
|
||||
sass-rails (3.2.5)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
sprockets (2.1.2)
|
||||
sprockets (2.1.3)
|
||||
hike (~> 1.2)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
therubyracer (0.9.10)
|
||||
therubyracer (0.10.2)
|
||||
libv8 (~> 3.3.10)
|
||||
thor (0.14.6)
|
||||
thor (0.16.0)
|
||||
tilt (1.3.3)
|
||||
timecop (0.3.5)
|
||||
timecop (0.4.5)
|
||||
treetop (1.4.10)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.32)
|
||||
uglifier (1.2.3)
|
||||
tzinfo (0.3.33)
|
||||
uglifier (1.2.7)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
multi_json (~> 1.3)
|
||||
validates_email_format_of (1.5.3)
|
||||
|
||||
PLATFORMS
|
||||
|
@ -157,10 +165,13 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
SystemTimer (>= 1.1.3)
|
||||
bigdecimal
|
||||
browser
|
||||
coffee-rails (~> 3.2.1)
|
||||
composite_primary_keys (>= 5.0.0)
|
||||
composite_primary_keys (>= 5.0.8)
|
||||
deadlock_retry (>= 1.2.0)
|
||||
dynamic_form
|
||||
htmlentities
|
||||
http_accept_language (>= 1.0.2)
|
||||
httpclient
|
||||
iconv
|
||||
|
@ -168,13 +179,16 @@ DEPENDENCIES
|
|||
jsonify-rails
|
||||
libxml-ruby (>= 2.0.5)
|
||||
memcached (>= 1.4.1)
|
||||
oauth-plugin (>= 0.4.0.pre7)
|
||||
minitest
|
||||
oauth-plugin (>= 0.4.1)
|
||||
open_id_authentication (>= 1.1.0)
|
||||
paperclip (~> 2.0)
|
||||
pg
|
||||
rails (= 3.2.2)
|
||||
rails-i18n (>= 0.5.1)
|
||||
rails (= 3.2.8)
|
||||
rails-i18n (>= 0.6.3)
|
||||
redcarpet
|
||||
rinku (>= 1.2.2)
|
||||
ruby-openid (>= 2.2.0)
|
||||
sanitize
|
||||
sass-rails (~> 3.2.3)
|
||||
therubyracer
|
||||
|
|
|
@ -41,7 +41,10 @@ will be a better place to start.
|
|||
Anybody hacking on the code is welcome to join the
|
||||
[rails-dev](http://lists.openstreetmap.org/listinfo/rails-dev) mailing
|
||||
list where other people hacking on the code hang out and will be happy
|
||||
to help with any problems you may encounter.
|
||||
to help with any problems you may encounter. If you are looking for a
|
||||
project to help out with, please take a look at the list of
|
||||
[Top Ten Tasks](http://wiki.openstreetmap.org/wiki/Top_Ten_Tasks) that
|
||||
EWG maintains on the wiki.
|
||||
|
||||
There are also weekly IRC meetings, at 1800 GMT on Mondays in #osm-ewg on
|
||||
the OFTC network where questions can be asked and ideas discussed. For more
|
||||
|
|
BIN
app/assets/images/loading.gif
Normal file
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 13 KiB |
BIN
app/assets/images/sprite.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
75
app/assets/images/sprite.svg
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="300"
|
||||
height="200"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
inkscape:export-filename="/Users/tmcw/src/openstreetmap-website/app/assets/images/sprite.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"
|
||||
sodipodi:docname="New document 1">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="28.421709"
|
||||
inkscape:cx="7.0037552"
|
||||
inkscape:cy="187.29226"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2985"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-852.36218)">
|
||||
<path
|
||||
style="color:#000000;fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.55720866px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 8.4000012,852.36218 c -3.3137081,0 -5.9999994,2.68629 -5.9999994,6 0,3.31371 2.6862913,6 5.9999994,6 3.3137078,0 5.9999988,-2.68629 5.9999988,-6 0,-3.31371 -2.686291,-6 -5.9999988,-6 z m 0,2.4 c 1.9882248,0 3.5999988,1.61178 3.5999988,3.6 0,1.98822 -1.611774,3.6 -3.5999988,3.6 -1.9882249,0 -3.5999997,-1.61178 -3.5999997,-3.6 0,-1.98822 1.6117748,-3.6 3.5999997,-3.6 z"
|
||||
id="path2987"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.55720866px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3033"
|
||||
width="7"
|
||||
height="3"
|
||||
x="679.2984"
|
||||
y="-530.39673"
|
||||
transform="matrix(-0.60876143,0.79335334,-0.79335334,-0.60876143,0,0)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
|
@ -11,17 +11,15 @@ function createMap(divName, options) {
|
|||
controls: options.controls || [
|
||||
new OpenLayers.Control.ArgParser(),
|
||||
new OpenLayers.Control.Attribution(),
|
||||
new OpenLayers.Control.LayerSwitcher(),
|
||||
new SimpleLayerSwitcher(),
|
||||
new OpenLayers.Control.Navigation(),
|
||||
new OpenLayers.Control.PanZoom(),
|
||||
new OpenLayers.Control.PanZoomBar(),
|
||||
new OpenLayers.Control.Zoom(),
|
||||
new OpenLayers.Control.SimplePanZoom(),
|
||||
new OpenLayers.Control.ScaleLine({geodesic: true})
|
||||
],
|
||||
units: "m",
|
||||
maxResolution: 156543.0339,
|
||||
numZoomLevels: 20,
|
||||
displayProjection: new OpenLayers.Projection("EPSG:4326"),
|
||||
theme: "<%= asset_path 'theme/default/style.css' %>"
|
||||
theme: "<%= asset_path 'theme/openstreetmap/style.css' %>"
|
||||
});
|
||||
|
||||
var mapnik = new OpenLayers.Layer.OSM.Mapnik(i18n("javascripts.map.base.standard"), {
|
||||
|
@ -69,9 +67,6 @@ function createMap(divName, options) {
|
|||
markers = new OpenLayers.Layer.Markers("Markers", {
|
||||
displayInLayerSwitcher: false,
|
||||
numZoomLevels: 20,
|
||||
maxExtent: new OpenLayers.Bounds(-20037508,-20037508,20037508,20037508),
|
||||
maxResolution: 156543,
|
||||
units: "m",
|
||||
projection: "EPSG:900913"
|
||||
});
|
||||
map.addLayer(markers);
|
||||
|
@ -81,27 +76,35 @@ function createMap(divName, options) {
|
|||
|
||||
function getArrowIcon() {
|
||||
var size = new OpenLayers.Size(25, 22);
|
||||
var offset = new OpenLayers.Pixel(-30, -27);
|
||||
var offset = new OpenLayers.Pixel(-22, -20);
|
||||
var icon = new OpenLayers.Icon("<%= asset_path 'arrow.png' %>", size, offset);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
function addMarkerToMap(position, icon, description) {
|
||||
var marker = new OpenLayers.Marker(position.clone().transform(epsg4326, map.getProjectionObject()), icon);
|
||||
var marker = new OpenLayers.Marker(proj(position), icon);
|
||||
|
||||
markers.addMarker(marker);
|
||||
|
||||
if (description) {
|
||||
marker.events.register("mouseover", marker, function() { openMapPopup(marker, description) });
|
||||
marker.events.register("mouseover", marker, function() {
|
||||
openMapPopup(marker, description);
|
||||
});
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
function addObjectToMap(url, zoom, callback) {
|
||||
var layer = new OpenLayers.Layer.GML("Objects", url, {
|
||||
format: OpenLayers.Format.OSM,
|
||||
var layer = new OpenLayers.Layer.Vector("Objects", {
|
||||
strategies: [
|
||||
new OpenLayers.Strategy.Fixed()
|
||||
],
|
||||
protocol: new OpenLayers.Protocol.HTTP({
|
||||
url: url,
|
||||
format: new OpenLayers.Format.OSM()
|
||||
}),
|
||||
style: {
|
||||
strokeColor: "blue",
|
||||
strokeWidth: 3,
|
||||
|
@ -139,8 +142,6 @@ function addObjectToMap(url, zoom, callback) {
|
|||
});
|
||||
|
||||
map.addLayer(layer);
|
||||
|
||||
layer.loadGML();
|
||||
}
|
||||
|
||||
function addBoxToMap(boxbounds, id, outline) {
|
||||
|
@ -155,9 +156,9 @@ function addBoxToMap(boxbounds, id, outline) {
|
|||
if (outline) {
|
||||
vertices = boxbounds.toGeometry().getVertices();
|
||||
vertices.push(new OpenLayers.Geometry.Point(vertices[0].x, vertices[0].y));
|
||||
geometry = new OpenLayers.Geometry.LineString(vertices).transform(epsg4326, map.getProjectionObject());
|
||||
geometry = proj(new OpenLayers.Geometry.LineString(vertices));
|
||||
} else {
|
||||
geometry = boxbounds.toGeometry().transform(epsg4326, map.getProjectionObject());
|
||||
geometry = proj(boxbounds.toGeometry());
|
||||
}
|
||||
var box = new OpenLayers.Feature.Vector(geometry, {}, {
|
||||
strokeWidth: 2,
|
||||
|
@ -197,27 +198,19 @@ function removeBoxFromMap(box){
|
|||
vectors.removeFeature(box);
|
||||
}
|
||||
|
||||
function getMapCenter() {
|
||||
return map.getCenter().clone().transform(map.getProjectionObject(), epsg4326);
|
||||
function proj(x) {
|
||||
return x.clone().transform(epsg4326, map.getProjectionObject());
|
||||
}
|
||||
|
||||
function unproj(x) {
|
||||
return x.clone().transform(map.getProjectionObject(), epsg4326);
|
||||
}
|
||||
|
||||
function setMapCenter(center, zoom) {
|
||||
zoom = parseInt(zoom);
|
||||
zoom = parseInt(zoom, 10);
|
||||
var numzoom = map.getNumZoomLevels();
|
||||
if (zoom >= numzoom) zoom = numzoom - 1;
|
||||
map.setCenter(center.clone().transform(epsg4326, map.getProjectionObject()), zoom);
|
||||
}
|
||||
|
||||
function setMapExtent(extent) {
|
||||
map.zoomToExtent(extent.clone().transform(epsg4326, map.getProjectionObject()));
|
||||
}
|
||||
|
||||
function getMapExtent() {
|
||||
return map.getExtent().clone().transform(map.getProjectionObject(), epsg4326);
|
||||
}
|
||||
|
||||
function getMapZoom() {
|
||||
return map.getZoom();
|
||||
map.setCenter(proj(center), zoom);
|
||||
}
|
||||
|
||||
function getEventPosition(event) {
|
||||
|
@ -265,7 +258,3 @@ function setMapLayers(layerConfig) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function scaleToZoom(scale) {
|
||||
return Math.log(360.0/(scale * 512.0)) / Math.log(2.0);
|
||||
}
|
||||
|
|
|
@ -19,65 +19,31 @@ function openMenu(anchor, menu, align) {
|
|||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a menu.
|
||||
*/
|
||||
function closeMenu(menu) {
|
||||
clearTimeout(menu.timer);
|
||||
menu.hide();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback called when the mouse enters a menu anchor.
|
||||
*/
|
||||
function enterMenuAnchor(event, anchor, menu, delay, align) {
|
||||
if (!anchor.hasClass("disabled")) {
|
||||
clearTimeout(menu.timer);
|
||||
|
||||
if (delay > 0) {
|
||||
menu.timer = setTimeout(function () { openMenu(anchor, menu, align); }, delay);
|
||||
} else {
|
||||
openMenu(event, menu, align);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback called when the mouse leaves a menu anchor.
|
||||
*/
|
||||
function leaveMenuAnchor(event, anchor, menu) {
|
||||
var to = event.relatedTarget;
|
||||
|
||||
if (!menu.is(to) && menu.has(to).length === 0) {
|
||||
menu.hide();
|
||||
}
|
||||
|
||||
clearTimeout(menu.timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback called when the mouse leaves a menu.
|
||||
*/
|
||||
function leaveMenu(event, anchor, menu) {
|
||||
var to = event.relatedTarget;
|
||||
|
||||
if (!anchor.is(to) && menu.has(to).length === 0) {
|
||||
menu.hide();
|
||||
}
|
||||
|
||||
clearTimeout(menu.timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup a menu, triggered by hovering over an anchor for a given time.
|
||||
*/
|
||||
function createMenu(anchorid, menuid, delay, align) {
|
||||
var anchor = $("#" + anchorid);
|
||||
var menu = $("#" + menuid);
|
||||
function createMenu(anchorid, menuid, align) {
|
||||
var $anchor = $("#" + anchorid);
|
||||
var $arrow = $("#" + anchorid + " .menuicon");
|
||||
var $menu = $("#" + menuid);
|
||||
var $page = $(":not(#" + menuid + ", #" + anchorid + ")");
|
||||
|
||||
anchor.mouseup(function (event) { closeMenu(menu); });
|
||||
anchor.mouseover(function (event) { enterMenuAnchor(anchor, anchor, menu, delay, align); });
|
||||
anchor.mouseout(function (event) { leaveMenuAnchor(event, anchor, menu); });
|
||||
menu.mouseup(function (event) { closeMenu(menu); });
|
||||
menu.mouseout(function (event) { leaveMenu(event, anchor, menu); });
|
||||
function hide() {
|
||||
$menu.hide();
|
||||
$page.off("click", hide);
|
||||
}
|
||||
|
||||
$arrow.click(function(e) {
|
||||
if ($anchor.is(":not(.disabled)")) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if ($menu.is(":visible")) {
|
||||
$menu.hide();
|
||||
$page.off("click", hide);
|
||||
} else {
|
||||
openMenu($anchor, $menu.show(), align);
|
||||
$page.on("click", hide);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//= require OpenLayers
|
||||
//= require OpenStreetMap
|
||||
//= require SimpleLayerSwitcher
|
||||
//= require SimplePanZoom
|
||||
|
||||
OpenLayers.Util.imageURLs = {
|
||||
"404.png": "<%= asset_path 'img/404.png' %>",
|
||||
|
@ -28,8 +30,6 @@ OpenLayers.Util.imageURLs = {
|
|||
"zoom-world-mini.png": "<%= asset_path 'img/zoom-world-mini.png' %>"
|
||||
};
|
||||
|
||||
OpenLayers.Util.OSM.MISSING_TILE_URL = "<%= asset_path 'img/404.png' %>";
|
||||
|
||||
OpenLayers.Util.origGetImageLocation = OpenLayers.Util.getImageLocation;
|
||||
|
||||
OpenLayers.Util.getImageLocation = function(image) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery.autogrowtextarea
|
||||
//= require jquery.timers
|
||||
|
||||
/*
|
||||
* Called as the user scrolls/zooms around to aniplate hrefs of the
|
||||
|
@ -142,23 +144,6 @@ function setArgs(url, args) {
|
|||
return url.replace(/\?.*$/, "") + "?" + queryitems.join("&");
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to get a CSS property for an element.
|
||||
*/
|
||||
function getStyle(el, property) {
|
||||
var style;
|
||||
|
||||
if (el.currentStyle) {
|
||||
style = el.currentStyle[property];
|
||||
} else if( window.getComputedStyle ) {
|
||||
style = document.defaultView.getComputedStyle(el,null).getPropertyValue(property);
|
||||
} else {
|
||||
style = el.style[property];
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to interpolate JavaScript variables in strings using a
|
||||
* similar syntax to rails I18n string interpolation - the only
|
||||
|
@ -221,3 +206,64 @@ function makeShortCode(lat, lon, zoom) {
|
|||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Click handler to switch a rich text control to preview mode
|
||||
*/
|
||||
function previewRichtext(event) {
|
||||
var editor = $(this).parents(".richtext_container").find("textarea");
|
||||
var preview = $(this).parents(".richtext_container").find(".richtext_preview");
|
||||
var width = editor.outerWidth() - preview.outerWidth() + preview.innerWidth();
|
||||
var minHeight = editor.outerHeight() - preview.outerHeight() + preview.innerHeight();
|
||||
|
||||
if (preview.contents().length == 0) {
|
||||
preview.oneTime(500, "loading", function () {
|
||||
preview.addClass("loading");
|
||||
});
|
||||
|
||||
preview.load(editor.attr("data-preview-url"), { text: editor.val() }, function () {
|
||||
preview.stopTime("loading");
|
||||
preview.removeClass("loading");
|
||||
});
|
||||
}
|
||||
|
||||
editor.hide();
|
||||
preview.width(width);
|
||||
preview.css("min-height", minHeight + "px");
|
||||
preview.show();
|
||||
|
||||
$(this).siblings(".richtext_doedit").prop("disabled", false);
|
||||
$(this).prop("disabled", true);
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
/*
|
||||
* Click handler to switch a rich text control to edit mode
|
||||
*/
|
||||
function editRichtext(event) {
|
||||
var editor = $(this).parents(".richtext_container").find("textarea");
|
||||
var preview = $(this).parents(".richtext_container").find(".richtext_preview");
|
||||
|
||||
preview.hide();
|
||||
editor.show();
|
||||
|
||||
$(this).siblings(".richtext_dopreview").prop("disabled", false);
|
||||
$(this).prop("disabled", true);
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup any rich text controls
|
||||
*/
|
||||
$(document).ready(function () {
|
||||
$(".richtext_preview").hide();
|
||||
$(".richtext_content textarea").change(function () {
|
||||
$(this).parents(".richtext_container").find(".richtext_preview").empty();
|
||||
});
|
||||
$(".richtext_doedit").prop("disabled", true);
|
||||
$(".richtext_dopreview").prop("disabled", false);
|
||||
$(".richtext_doedit").click(editRichtext);
|
||||
$(".richtext_dopreview").click(previewRichtext);
|
||||
});
|
||||
|
|
175
app/assets/openlayers/SimpleLayerSwitcher.js
Normal file
|
@ -0,0 +1,175 @@
|
|||
var SimpleLayerSwitcher = OpenLayers.Class(OpenLayers.Control, {
|
||||
layerStates: null,
|
||||
layersDiv: null,
|
||||
ascending: true,
|
||||
|
||||
initialize: function(options) {
|
||||
OpenLayers.Control.prototype.initialize.apply(this, arguments);
|
||||
this.layerStates = [];
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
OpenLayers.Event.stopObservingElement(this.div);
|
||||
|
||||
//clear out layers info and unregister their events
|
||||
this.map.events.un({
|
||||
"addlayer": this.redraw,
|
||||
"changelayer": this.redraw,
|
||||
"removelayer": this.redraw,
|
||||
"changebaselayer": this.redraw,
|
||||
scope: this
|
||||
});
|
||||
OpenLayers.Control.prototype.destroy.apply(this, arguments);
|
||||
},
|
||||
|
||||
setMap: function(map) {
|
||||
OpenLayers.Control.prototype.setMap.apply(this, arguments);
|
||||
|
||||
this.map.events.on({
|
||||
"addlayer": this.redraw,
|
||||
"changelayer": this.redraw,
|
||||
"removelayer": this.redraw,
|
||||
"changebaselayer": this.redraw,
|
||||
scope: this
|
||||
});
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
OpenLayers.Control.prototype.draw.apply(this);
|
||||
this.loadContents();
|
||||
this.redraw();
|
||||
return this.div;
|
||||
},
|
||||
|
||||
checkRedraw: function() {
|
||||
var redraw = false;
|
||||
if ( !this.layerStates.length ||
|
||||
(this.map.layers.length != this.layerStates.length) ) {
|
||||
redraw = true;
|
||||
} else {
|
||||
for (var i=0, len=this.layerStates.length; i<len; i++) {
|
||||
var layerState = this.layerStates[i];
|
||||
var layer = this.map.layers[i];
|
||||
if ( (layerState.name != layer.name) ||
|
||||
(layerState.inRange != layer.inRange) ||
|
||||
(layerState.id != layer.id) ||
|
||||
(layerState.visibility != layer.visibility) ) {
|
||||
redraw = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return redraw;
|
||||
},
|
||||
|
||||
redraw: function() {
|
||||
if (!this.checkRedraw()) {
|
||||
return this.div;
|
||||
}
|
||||
|
||||
this.div.innerHTML = '';
|
||||
var len = this.map.layers.length;
|
||||
this.layerStates = [];
|
||||
for (var i = 0; i < this.map.layers.length; i++) {
|
||||
var layer = this.map.layers[i];
|
||||
this.layerStates[i] = {
|
||||
'name': layer.name,
|
||||
'visibility': layer.visibility,
|
||||
'inRange': layer.inRange,
|
||||
'id': layer.id
|
||||
};
|
||||
}
|
||||
|
||||
var layers = this.map.layers.slice();
|
||||
if (!this.ascending) { layers.reverse(); }
|
||||
for (var i = 0; i < layers.length; i++) {
|
||||
var layer = layers[i];
|
||||
var baseLayer = layer.isBaseLayer;
|
||||
|
||||
if (layer.displayInLayerSwitcher && baseLayer) {
|
||||
var on = (baseLayer) ? (layer == this.map.baseLayer)
|
||||
: layer.getVisibility();
|
||||
var layerElem = document.createElement('a');
|
||||
layerElem.id = this.id + '_input_' + layer.name;
|
||||
layerElem.innerHTML = layer.name;
|
||||
layerElem.href = '#';
|
||||
|
||||
OpenLayers.Element.addClass(layerElem, 'basey');
|
||||
OpenLayers.Element.addClass(layerElem,
|
||||
'basey-' + (on ? 'on' : 'off'));
|
||||
|
||||
if (!baseLayer && !layer.inRange) {
|
||||
layerElem.disabled = true;
|
||||
}
|
||||
var context = {
|
||||
'layer': layer
|
||||
};
|
||||
OpenLayers.Event.observe(layerElem, 'mouseup',
|
||||
OpenLayers.Function.bindAsEventListener(
|
||||
this.onInputClick,
|
||||
context)
|
||||
);
|
||||
|
||||
this.div.appendChild(layerElem);
|
||||
}
|
||||
}
|
||||
|
||||
return this.div;
|
||||
},
|
||||
|
||||
onInputClick: function(e) {
|
||||
if (this.layer.isBaseLayer) {
|
||||
this.layer.map.setBaseLayer(this.layer);
|
||||
} else {
|
||||
this.layer.setVisibility(!this.layer.getVisibility());
|
||||
}
|
||||
OpenLayers.Event.stop(e);
|
||||
},
|
||||
|
||||
updateMap: function() {
|
||||
|
||||
// set the newly selected base layer
|
||||
for(var i=0, len=this.baseLayers.length; i<len; i++) {
|
||||
var layerEntry = this.baseLayers[i];
|
||||
if (layerEntry.inputElem.checked) {
|
||||
this.map.setBaseLayer(layerEntry.layer, false);
|
||||
}
|
||||
}
|
||||
|
||||
// set the correct visibilities for the overlays
|
||||
for(var i=0, len=this.dataLayers.length; i<len; i++) {
|
||||
var layerEntry = this.dataLayers[i];
|
||||
layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
loadContents: function() {
|
||||
//configure main div
|
||||
OpenLayers.Event.observe(this.div, 'mouseup',
|
||||
OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
|
||||
OpenLayers.Event.observe(this.div, 'click',
|
||||
this.ignoreEvent);
|
||||
OpenLayers.Event.observe(this.div, 'mousedown',
|
||||
OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
|
||||
OpenLayers.Event.observe(this.div, 'dblclick', this.ignoreEvent);
|
||||
},
|
||||
|
||||
ignoreEvent: function(evt) {
|
||||
OpenLayers.Event.stop(evt);
|
||||
},
|
||||
|
||||
mouseDown: function(evt) {
|
||||
this.isMouseDown = true;
|
||||
this.ignoreEvent(evt);
|
||||
},
|
||||
|
||||
mouseUp: function(evt) {
|
||||
if (this.isMouseDown) {
|
||||
this.isMouseDown = false;
|
||||
this.ignoreEvent(evt);
|
||||
}
|
||||
},
|
||||
|
||||
CLASS_NAME: "SimpleLayerSwitcher"
|
||||
});
|
356
app/assets/openlayers/SimplePanZoom.js
Normal file
|
@ -0,0 +1,356 @@
|
|||
/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
|
||||
* full list of contributors). Published under the 2-clause BSD license.
|
||||
* See license.txt in the OpenLayers distribution or repository for the
|
||||
* full text of the license. */
|
||||
|
||||
|
||||
/**
|
||||
* @requires OpenLayers/Control/PanZoom.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Control.PanZoomBar
|
||||
* The PanZoomBar is a visible control composed of a
|
||||
* <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>.
|
||||
* By default it is displayed in the upper left corner of the map as 4
|
||||
* directional arrows above a vertical slider.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Control.PanZoom>
|
||||
*/
|
||||
OpenLayers.Control.SimplePanZoom = OpenLayers.Class(OpenLayers.Control.PanZoom, {
|
||||
|
||||
/**
|
||||
* APIProperty: zoomStopWidth
|
||||
*/
|
||||
zoomStopWidth: 18,
|
||||
|
||||
/**
|
||||
* APIProperty: zoomStopHeight
|
||||
*/
|
||||
zoomStopHeight: 7,
|
||||
|
||||
/**
|
||||
* Property: slider
|
||||
*/
|
||||
slider: null,
|
||||
|
||||
/**
|
||||
* Property: sliderEvents
|
||||
* {<OpenLayers.Events>}
|
||||
*/
|
||||
sliderEvents: null,
|
||||
|
||||
/**
|
||||
* Property: zoombarDiv
|
||||
* {DOMElement}
|
||||
*/
|
||||
zoombarDiv: null,
|
||||
|
||||
/**
|
||||
* APIProperty: zoomWorldIcon
|
||||
* {Boolean}
|
||||
*/
|
||||
zoomWorldIcon: false,
|
||||
|
||||
/**
|
||||
* APIProperty: panIcons
|
||||
* {Boolean} Set this property to false not to display the pan icons. If
|
||||
* false the zoom world icon is placed under the zoom bar. Defaults to
|
||||
* true.
|
||||
*/
|
||||
panIcons: true,
|
||||
|
||||
/**
|
||||
* APIProperty: forceFixedZoomLevel
|
||||
* {Boolean} Force a fixed zoom level even though the map has
|
||||
* fractionalZoom
|
||||
*/
|
||||
forceFixedZoomLevel: false,
|
||||
|
||||
/**
|
||||
* Property: mouseDragStart
|
||||
* {<OpenLayers.Pixel>}
|
||||
*/
|
||||
mouseDragStart: null,
|
||||
|
||||
/**
|
||||
* Property: deltaY
|
||||
* {Number} The cumulative vertical pixel offset during a zoom bar drag.
|
||||
*/
|
||||
deltaY: null,
|
||||
|
||||
/**
|
||||
* Property: zoomStart
|
||||
* {<OpenLayers.Pixel>}
|
||||
*/
|
||||
zoomStart: null,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Control.PanZoomBar
|
||||
*/
|
||||
buttons: null,
|
||||
|
||||
/**
|
||||
* APIMethod: destroy
|
||||
*/
|
||||
destroy: function() {
|
||||
|
||||
this._removeZoomBar();
|
||||
|
||||
this.map.events.un({
|
||||
"changebaselayer": this.redraw,
|
||||
"updatesize": this.redraw,
|
||||
scope: this
|
||||
});
|
||||
|
||||
OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments);
|
||||
|
||||
delete this.mouseDragStart;
|
||||
delete this.zoomStart;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: setMap
|
||||
*
|
||||
* Parameters:
|
||||
* map - {<OpenLayers.Map>}
|
||||
*/
|
||||
setMap: function(map) {
|
||||
OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments);
|
||||
this.map.events.on({
|
||||
"changebaselayer": this.redraw,
|
||||
"updatesize": this.redraw,
|
||||
scope: this
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: redraw
|
||||
* clear the div and start over.
|
||||
*/
|
||||
redraw: function() {
|
||||
if (this.div !== null) {
|
||||
this.removeButtons();
|
||||
this._removeZoomBar();
|
||||
}
|
||||
this.draw();
|
||||
this.moveZoomBar();
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: draw
|
||||
*
|
||||
* Parameters:
|
||||
* px - {<OpenLayers.Pixel>}
|
||||
*/
|
||||
draw: function(px) {
|
||||
// initialize our internal div
|
||||
OpenLayers.Control.prototype.draw.apply(this, arguments);
|
||||
px = this.position.clone();
|
||||
|
||||
// place the controls
|
||||
this.buttons = [];
|
||||
var ids = ['panup', 'panleft', 'panright', 'pandown', 'zoomout', 'zoomin'];
|
||||
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
var b = document.createElement('div');
|
||||
b.id = ids[i];
|
||||
b.action = ids[i];
|
||||
b.className = 'button olButton';
|
||||
this.div.appendChild(b);
|
||||
this.buttons.push(b);
|
||||
}
|
||||
|
||||
this._addZoomBar();
|
||||
return this.div;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: _addZoomBar
|
||||
*
|
||||
* Parameters:
|
||||
* centered - {<OpenLayers.Pixel>} where zoombar drawing is to start.
|
||||
*/
|
||||
_addZoomBar:function() {
|
||||
var id = this.id + "_" + this.map.id;
|
||||
var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom();
|
||||
var slider = document.createElement('div');
|
||||
slider.id = 'slider';
|
||||
slider.className = 'button';
|
||||
slider.style.cursor = 'move';
|
||||
this.slider = slider;
|
||||
|
||||
this.sliderEvents = new OpenLayers.Events(this, slider, null, true,
|
||||
{ includeXY: true });
|
||||
this.sliderEvents.on({
|
||||
"touchstart": this.zoomBarDown,
|
||||
"touchmove": this.zoomBarDrag,
|
||||
"touchend": this.zoomBarUp,
|
||||
"mousedown": this.zoomBarDown,
|
||||
"mousemove": this.zoomBarDrag,
|
||||
"mouseup": this.zoomBarUp
|
||||
});
|
||||
|
||||
var height = this.zoomStopHeight * (this.map.getNumZoomLevels());
|
||||
|
||||
// this is the background image
|
||||
var div = document.createElement('div');
|
||||
div.className = 'button olButton';
|
||||
div.id = 'zoombar';
|
||||
this.zoombarDiv = div;
|
||||
|
||||
this.div.appendChild(div);
|
||||
this.startTop = 75;
|
||||
this.div.appendChild(slider);
|
||||
|
||||
this.map.events.register("zoomend", this, this.moveZoomBar);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: _removeZoomBar
|
||||
*/
|
||||
_removeZoomBar: function() {
|
||||
this.sliderEvents.un({
|
||||
"touchstart": this.zoomBarDown,
|
||||
"touchmove": this.zoomBarDrag,
|
||||
"touchend": this.zoomBarUp,
|
||||
"mousedown": this.zoomBarDown,
|
||||
"mousemove": this.zoomBarDrag,
|
||||
"mouseup": this.zoomBarUp
|
||||
});
|
||||
this.sliderEvents.destroy();
|
||||
|
||||
this.div.removeChild(this.zoombarDiv);
|
||||
this.zoombarDiv = null;
|
||||
this.div.removeChild(this.slider);
|
||||
this.slider = null;
|
||||
|
||||
this.map.events.unregister("zoomend", this, this.moveZoomBar);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: onButtonClick
|
||||
*
|
||||
* Parameters:
|
||||
* evt - {Event}
|
||||
*/
|
||||
onButtonClick: function(evt) {
|
||||
OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments);
|
||||
if (evt.buttonElement === this.zoombarDiv) {
|
||||
var levels = evt.buttonXY.y / this.zoomStopHeight;
|
||||
if (this.forceFixedZoomLevel || !this.map.fractionalZoom) {
|
||||
levels = Math.floor(levels);
|
||||
}
|
||||
var zoom = (this.map.getNumZoomLevels() - 1) - levels;
|
||||
zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1);
|
||||
this.map.zoomTo(zoom);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: passEventToSlider
|
||||
* This function is used to pass events that happen on the div, or the map,
|
||||
* through to the slider, which then does its moving thing.
|
||||
*
|
||||
* Parameters:
|
||||
* evt - {<OpenLayers.Event>}
|
||||
*/
|
||||
passEventToSlider:function(evt) {
|
||||
this.sliderEvents.handleBrowserEvent(evt);
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: zoomBarDown
|
||||
* event listener for clicks on the slider
|
||||
*
|
||||
* Parameters:
|
||||
* evt - {<OpenLayers.Event>}
|
||||
*/
|
||||
zoomBarDown:function(evt) {
|
||||
if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) {
|
||||
return;
|
||||
}
|
||||
this.map.events.on({
|
||||
"touchmove": this.passEventToSlider,
|
||||
"mousemove": this.passEventToSlider,
|
||||
"mouseup": this.passEventToSlider,
|
||||
scope: this
|
||||
});
|
||||
this.mouseDragStart = evt.xy.clone();
|
||||
this.zoomStart = evt.xy.clone();
|
||||
this.div.style.cursor = "move";
|
||||
// reset the div offsets just in case the div moved
|
||||
this.zoombarDiv.offsets = null;
|
||||
OpenLayers.Event.stop(evt);
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: zoomBarDrag
|
||||
* This is what happens when a click has occurred, and the client is
|
||||
* dragging. Here we must ensure that the slider doesn't go beyond the
|
||||
* bottom/top of the zoombar div, as well as moving the slider to its new
|
||||
* visual location
|
||||
*
|
||||
* Parameters:
|
||||
* evt - {<OpenLayers.Event>}
|
||||
*/
|
||||
zoomBarDrag: function(evt) {
|
||||
if (this.mouseDragStart !== null) {
|
||||
var deltaY = this.mouseDragStart.y - evt.xy.y;
|
||||
var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv);
|
||||
if ((evt.clientY - offsets[1]) > 0 &&
|
||||
(evt.clientY - offsets[1]) < 140) {
|
||||
var newTop = parseInt(this.slider.style.top, 10) - deltaY;
|
||||
this.slider.style.top = newTop + "px";
|
||||
this.mouseDragStart = evt.xy.clone();
|
||||
}
|
||||
// set cumulative displacement
|
||||
this.deltaY = this.zoomStart.y - evt.xy.y;
|
||||
OpenLayers.Event.stop(evt);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: zoomBarUp
|
||||
* Perform cleanup when a mouseup event is received -- discover new zoom
|
||||
* level and switch to it.
|
||||
*
|
||||
* Parameters:
|
||||
* evt - {<OpenLayers.Event>}
|
||||
*/
|
||||
zoomBarUp: function(evt) {
|
||||
if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") {
|
||||
return;
|
||||
}
|
||||
if (this.mouseDragStart) {
|
||||
this.div.style.cursor = "";
|
||||
this.map.events.un({
|
||||
"touchmove": this.passEventToSlider,
|
||||
"mouseup": this.passEventToSlider,
|
||||
"mousemove": this.passEventToSlider,
|
||||
scope: this
|
||||
});
|
||||
var zoomLevel = this.map.zoom;
|
||||
zoomLevel += this.deltaY/this.zoomStopHeight;
|
||||
zoomLevel = Math.max(Math.round(zoomLevel), 0);
|
||||
this.map.zoomTo(zoomLevel);
|
||||
this.mouseDragStart = null;
|
||||
this.zoomStart = null;
|
||||
this.deltaY = 0;
|
||||
OpenLayers.Event.stop(evt);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: moveZoomBar
|
||||
* Change the location of the slider to match the current zoom level.
|
||||
*/
|
||||
moveZoomBar:function() {
|
||||
var newTop =
|
||||
((this.map.getNumZoomLevels()-1) - this.map.getZoom()) *
|
||||
this.zoomStopHeight + this.startTop;
|
||||
this.slider.style.top = newTop + "px";
|
||||
},
|
||||
CLASS_NAME: "OpenLayers.Control.SimplePanZoom"
|
||||
});
|
|
@ -1,433 +0,0 @@
|
|||
div.olMap {
|
||||
z-index: 0;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
div.olMapViewport {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.olLayerDiv {
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
}
|
||||
|
||||
.olLayerGoogleCopyright {
|
||||
left: 2px;
|
||||
bottom: 2px;
|
||||
}
|
||||
.olLayerGoogleV3.olLayerGoogleCopyright {
|
||||
right: auto !important;
|
||||
}
|
||||
.olLayerGooglePoweredBy {
|
||||
left: 2px;
|
||||
bottom: 15px;
|
||||
}
|
||||
.olLayerGoogleV3.olLayerGooglePoweredBy {
|
||||
bottom: 15px !important;
|
||||
}
|
||||
.olControlAttribution {
|
||||
font-size: smaller;
|
||||
right: 3px;
|
||||
bottom: 4.5em;
|
||||
position: absolute;
|
||||
display: block;
|
||||
}
|
||||
.olControlScale {
|
||||
right: 3px;
|
||||
bottom: 3em;
|
||||
display: block;
|
||||
position: absolute;
|
||||
font-size: smaller;
|
||||
}
|
||||
.olControlScaleLine {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
bottom: 15px;
|
||||
font-size: xx-small;
|
||||
}
|
||||
.olControlScaleLineBottom {
|
||||
border: solid 2px black;
|
||||
border-bottom: none;
|
||||
margin-top:-2px;
|
||||
text-align: center;
|
||||
}
|
||||
.olControlScaleLineTop {
|
||||
border: solid 2px black;
|
||||
border-top: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.olControlPermalink {
|
||||
right: 3px;
|
||||
bottom: 1.5em;
|
||||
display: block;
|
||||
position: absolute;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
div.olControlMousePosition {
|
||||
bottom: 0em;
|
||||
right: 3px;
|
||||
display: block;
|
||||
position: absolute;
|
||||
font-family: Arial;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.olControlOverviewMapContainer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.olControlOverviewMapElement {
|
||||
padding: 10px 18px 10px 10px;
|
||||
background-color: #00008B;
|
||||
-moz-border-radius: 1em 0 0 0;
|
||||
}
|
||||
|
||||
.olControlOverviewMapMinimizeButton {
|
||||
right: 0;
|
||||
bottom: 80px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.olControlOverviewMapMaximizeButton {
|
||||
right: 0;
|
||||
bottom: 80px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.olControlOverviewMapExtentRectangle {
|
||||
overflow: hidden;
|
||||
background-image: image-url("theme/default/img/blank.gif");
|
||||
cursor: move;
|
||||
border: 2px dotted red;
|
||||
}
|
||||
.olControlOverviewMapRectReplacement {
|
||||
overflow: hidden;
|
||||
cursor: move;
|
||||
background-image: image-url("theme/default/img/overview_replacement.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.olLayerGeoRSSDescription {
|
||||
float:left;
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
font-size:1.0em;
|
||||
}
|
||||
.olLayerGeoRSSClose {
|
||||
float:right;
|
||||
color:gray;
|
||||
font-size:1.2em;
|
||||
margin-right:6px;
|
||||
font-family:sans-serif;
|
||||
}
|
||||
.olLayerGeoRSSTitle {
|
||||
float:left;font-size:1.2em;
|
||||
}
|
||||
|
||||
.olPopupContent {
|
||||
padding:5px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.olControlNavigationHistory {
|
||||
background-image: image-url("theme/default/img/navigation_history.png");
|
||||
background-repeat: no-repeat;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
}
|
||||
.olControlNavigationHistoryPreviousItemActive {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.olControlNavigationHistoryPreviousItemInactive {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
.olControlNavigationHistoryNextItemActive {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
.olControlNavigationHistoryNextItemInactive {
|
||||
background-position: -24px -24px;
|
||||
}
|
||||
|
||||
div.olControlSaveFeaturesItemActive {
|
||||
background-image: image-url("theme/default/img/save_features_on.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 1px;
|
||||
}
|
||||
div.olControlSaveFeaturesItemInactive {
|
||||
background-image: image-url("theme/default/img/save_features_off.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 1px;
|
||||
}
|
||||
|
||||
.olHandlerBoxZoomBox {
|
||||
border: 2px solid red;
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
opacity: 0.50;
|
||||
font-size: 1px;
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
.olHandlerBoxSelectFeature {
|
||||
border: 2px solid blue;
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
opacity: 0.50;
|
||||
font-size: 1px;
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
|
||||
.olControlPanPanel {
|
||||
top: 10px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.olControlPanPanel div {
|
||||
background-image: image-url("theme/default/img/pan-panel.png");
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.olControlPanPanel .olControlPanNorthItemInactive {
|
||||
top: 0;
|
||||
left: 9px;
|
||||
background-position: 0 0;
|
||||
}
|
||||
.olControlPanPanel .olControlPanSouthItemInactive {
|
||||
top: 36px;
|
||||
left: 9px;
|
||||
background-position: 18px 0;
|
||||
}
|
||||
.olControlPanPanel .olControlPanWestItemInactive {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
left: 0;
|
||||
background-position: 0 18px;
|
||||
}
|
||||
.olControlPanPanel .olControlPanEastItemInactive {
|
||||
top: 18px;
|
||||
left: 18px;
|
||||
background-position: 18px 18px;
|
||||
}
|
||||
|
||||
.olControlZoomPanel {
|
||||
top: 71px;
|
||||
left: 14px;
|
||||
}
|
||||
|
||||
.olControlZoomPanel div {
|
||||
background-image: image-url("theme/default/img/zoom-panel.png");
|
||||
position: absolute;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.olControlZoomPanel .olControlZoomInItemInactive {
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.olControlZoomPanel .olControlZoomToMaxExtentItemInactive {
|
||||
top: 18px;
|
||||
left: 0;
|
||||
background-position: 0 -18px;
|
||||
}
|
||||
|
||||
.olControlZoomPanel .olControlZoomOutItemInactive {
|
||||
top: 36px;
|
||||
left: 0;
|
||||
background-position: 0 18px;
|
||||
}
|
||||
|
||||
/*
|
||||
* When a potential text is bigger than the image it move the image
|
||||
* with some headers (closes #3154)
|
||||
*/
|
||||
.olControlPanZoomBar div {
|
||||
font-size: 1px;
|
||||
}
|
||||
|
||||
.olPopupCloseBox {
|
||||
background: image-url("theme/default/img/close.gif") no-repeat;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.olFramedCloudPopupContent {
|
||||
padding: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.olControlNoSelect {
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
}
|
||||
|
||||
.olImageLoadError {
|
||||
background-color: pink;
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50); /* IE */
|
||||
}
|
||||
|
||||
/**
|
||||
* Cursor styles
|
||||
*/
|
||||
|
||||
.olCursorWait {
|
||||
cursor: wait;
|
||||
}
|
||||
.olDragDown {
|
||||
cursor: move;
|
||||
}
|
||||
.olDrawBox {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.olControlDragFeatureOver {
|
||||
cursor: move;
|
||||
}
|
||||
.olControlDragFeatureActive.olControlDragFeatureOver.olDragDown {
|
||||
cursor: -moz-grabbing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layer switcher
|
||||
*/
|
||||
.olControlLayerSwitcher {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
right: 0;
|
||||
width: 20em;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
margin-top: 3px;
|
||||
margin-left: 3px;
|
||||
margin-bottom: 3px;
|
||||
font-size: smaller;
|
||||
color: white;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.olControlLayerSwitcher .layersDiv {
|
||||
padding-top: 5px;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 5px;
|
||||
padding-right: 75px;
|
||||
background-color: darkblue;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.olControlLayerSwitcher .layersDiv .baseLbl,
|
||||
.olControlLayerSwitcher .layersDiv .dataLbl {
|
||||
margin-top: 3px;
|
||||
margin-left: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.olControlLayerSwitcher .layersDiv .baseLayersDiv,
|
||||
.olControlLayerSwitcher .layersDiv .dataLayersDiv {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.olControlLayerSwitcher .maximizeDiv,
|
||||
.olControlLayerSwitcher .minimizeDiv {
|
||||
top: 5px;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.olBingAttribution {
|
||||
color: #DDD;
|
||||
}
|
||||
.olBingAttribution.road {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.olGoogleAttribution.hybrid, .olGoogleAttribution.satellite {
|
||||
color: #EEE;
|
||||
}
|
||||
.olGoogleAttribution {
|
||||
color: #333;
|
||||
}
|
||||
span.olGoogleAttribution a {
|
||||
color: #77C;
|
||||
}
|
||||
span.olGoogleAttribution.hybrid a, span.olGoogleAttribution.satellite a {
|
||||
color: #EEE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Editing and navigation icons.
|
||||
* (using the editing_tool_bar.png sprint image)
|
||||
*/
|
||||
.olControlNavToolbar ,
|
||||
.olControlEditingToolbar {
|
||||
margin: 5px 5px 0 0;
|
||||
}
|
||||
.olControlNavToolbar div,
|
||||
.olControlEditingToolbar div {
|
||||
background-image: image-url("theme/default/img/editing_tool_bar.png");
|
||||
background-repeat: no-repeat;
|
||||
margin: 0 0 5px 5px;
|
||||
width: 24px;
|
||||
height: 22px;
|
||||
cursor: pointer
|
||||
}
|
||||
/* positions */
|
||||
.olControlEditingToolbar {
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.olControlNavToolbar {
|
||||
top: 295px;
|
||||
left: 9px;
|
||||
}
|
||||
/* layouts */
|
||||
.olControlEditingToolbar div {
|
||||
float: right;
|
||||
}
|
||||
/* individual controls */
|
||||
.olControlNavToolbar .olControlNavigationItemInactive,
|
||||
.olControlEditingToolbar .olControlNavigationItemInactive {
|
||||
background-position: -103px -1px;
|
||||
}
|
||||
.olControlNavToolbar .olControlNavigationItemActive ,
|
||||
.olControlEditingToolbar .olControlNavigationItemActive {
|
||||
background-position: -103px -24px;
|
||||
}
|
||||
.olControlNavToolbar .olControlZoomBoxItemInactive {
|
||||
background-position: -128px -1px;
|
||||
}
|
||||
.olControlNavToolbar .olControlZoomBoxItemActive {
|
||||
background-position: -128px -24px;
|
||||
}
|
||||
.olControlEditingToolbar .olControlDrawFeaturePointItemInactive {
|
||||
background-position: -77px -1px;
|
||||
}
|
||||
.olControlEditingToolbar .olControlDrawFeaturePointItemActive {
|
||||
background-position: -77px -24px;
|
||||
}
|
||||
.olControlEditingToolbar .olControlDrawFeaturePathItemInactive {
|
||||
background-position: -51px -1px;
|
||||
}
|
||||
.olControlEditingToolbar .olControlDrawFeaturePathItemActive {
|
||||
background-position: -51px -24px;
|
||||
}
|
||||
.olControlEditingToolbar .olControlDrawFeaturePolygonItemInactive{
|
||||
background-position: -26px -1px;
|
||||
}
|
||||
.olControlEditingToolbar .olControlDrawFeaturePolygonItemActive {
|
||||
background-position: -26px -24px;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
.SimpleLayerSwitcher {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
min-width: 150px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.SimpleLayerSwitcher a.basey {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: #838383;
|
||||
padding: 2px 5px 2px 20px;
|
||||
}
|
||||
|
||||
.SimpleLayerSwitcher a.basey-on {
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
background-image: image-url("theme/openstreetmap/img/carat.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 7px 9px;
|
||||
}
|
||||
|
||||
.SimpleLayerSwitcher a.basey-off {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.SimpleLayerSwitcher:hover a {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.SimpleLayerSwitcher a:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.SimpleLayerSwitcher:hover a:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.SimpleLayerSwitcher:hover a.basey-off {
|
||||
display: block;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
.olControlSimplePanZoom {
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom .button {
|
||||
background-image: image-url("theme/openstreetmap/img/map_sprite.png");
|
||||
position: absolute;
|
||||
background-repeat: no-repeat;
|
||||
cursor: hand;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #panup {
|
||||
left: 10px;
|
||||
width: 25px;
|
||||
height: 13px;
|
||||
background-position: -15px -5px;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #pandown {
|
||||
left: 10px;
|
||||
top: 36px;
|
||||
width: 25px;
|
||||
height: 15px;
|
||||
background-position: -15px -40px;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #panleft {
|
||||
top: 13px;
|
||||
width: 25px;
|
||||
height: 24px;
|
||||
background-position: -5px -17px;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #panright {
|
||||
top: 13px;
|
||||
width: 25px;
|
||||
height: 24px;
|
||||
left: 25px;
|
||||
background-position: -30px -17px;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #zoomin {
|
||||
top: 50px;
|
||||
width: 26px;
|
||||
height: 20px;
|
||||
left: 10px;
|
||||
background-position: -15px -61px;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #zoomout {
|
||||
top: 210px;
|
||||
width: 26px;
|
||||
height: 20px;
|
||||
left: 10px;
|
||||
background-position: -15px -220px;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #slider {
|
||||
top: 75px;
|
||||
width: 25px;
|
||||
height: 10px;
|
||||
left: 10px;
|
||||
-webkit-transition: top 100ms linear;
|
||||
-moz-transition: top 100ms linear;
|
||||
-o-transition: top 100ms linear;
|
||||
background-position: -77px -58px;
|
||||
pointer: move;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.olControlSimplePanZoom #zoombar {
|
||||
top: 70px;
|
||||
width: 26px;
|
||||
height: 140px;
|
||||
left: 10px;
|
||||
background-position: -15px -80px;
|
||||
}
|
BIN
app/assets/openlayers/theme/openstreetmap/img/carat.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
app/assets/openlayers/theme/openstreetmap/img/map_sprite.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
61
app/assets/openlayers/theme/openstreetmap/style.css.scss
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
*= require theme/default/style
|
||||
*= require theme/openstreetmap/SimpleLayerSwitcher
|
||||
*= require theme/openstreetmap/SimplePanZoom
|
||||
*/
|
||||
|
||||
.olControlOverviewMapExtentRectangle {
|
||||
background-image: image-url("theme/default/img/blank.gif");
|
||||
}
|
||||
|
||||
.olControlOverviewMapRectReplacement {
|
||||
background-image: image-url("theme/default/img/overview_replacement.gif");
|
||||
}
|
||||
|
||||
.olControlNavigationHistory {
|
||||
background-image: image-url("theme/default/img/navigation_history.png");
|
||||
}
|
||||
|
||||
div.olControlSaveFeaturesItemActive {
|
||||
background-image: image-url("theme/default/img/save_features_on.png");
|
||||
}
|
||||
|
||||
div.olControlSaveFeaturesItemInactive {
|
||||
background-image: image-url("theme/default/img/save_features_off.png");
|
||||
}
|
||||
|
||||
.olControlPanPanel div {
|
||||
background-image: image-url("theme/default/img/pan-panel.png");
|
||||
}
|
||||
|
||||
.olControlZoomPanel div {
|
||||
background-image: image-url("theme/default/img/zoom-panel.png");
|
||||
}
|
||||
|
||||
.olPopupCloseBox {
|
||||
background: image-url("theme/default/img/close.gif") no-repeat;
|
||||
}
|
||||
|
||||
.olImageLoadError {
|
||||
// remove opacity?
|
||||
// remove filter?
|
||||
background: image-url("theme/openstreetmap/img/missing-tile.png") no-repeat;
|
||||
}
|
||||
|
||||
.olControlNavToolbar div,
|
||||
.olControlEditingToolbar div {
|
||||
background-image: image-url("theme/default/img/editing_tool_bar.png");
|
||||
}
|
||||
|
||||
div.olControlZoom a {
|
||||
color: black;
|
||||
background: #ffffff;
|
||||
border: 1px solid #cccccc;
|
||||
// remove filter
|
||||
}
|
||||
|
||||
div.olControlZoom a:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
// remove max-width hover?
|
|
@ -85,12 +85,17 @@ h2 {
|
|||
|
||||
/* Rules for the introductory text displayed in the left sidebar to new users */
|
||||
|
||||
#intro {
|
||||
border-top: 1px solid #ccc;
|
||||
.sidebar-copy {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
#intro p {
|
||||
margin: 5px;
|
||||
.sidebar-copy p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.sidebar-copy.intro {
|
||||
margin-top: -1px;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -99,16 +104,19 @@ h2 {
|
|||
* undergoing maintenance.
|
||||
*/
|
||||
|
||||
#alert {
|
||||
width: 170px;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border: 1px solid #ccc;
|
||||
background: #d00;
|
||||
line-height: 1.2em;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
.sidebar-alert {
|
||||
padding: 4px 5px 4px 5px;
|
||||
border-top: 1px solid #ccc;
|
||||
margin-top: 4px;
|
||||
margin-bottom: -4px;
|
||||
background: #e00;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 17px;
|
||||
|
||||
p {
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -117,25 +125,26 @@ h2 {
|
|||
* donation drives.
|
||||
*/
|
||||
|
||||
.notice {
|
||||
width: 170px;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border: 1px solid #ccc;
|
||||
.sidebar-notice {
|
||||
padding: 4px 5px 4px 5px;
|
||||
border-top: 1px solid #ccc;
|
||||
margin-top: 4px;
|
||||
margin-bottom: -4px;
|
||||
background: #ea0;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
font-size: 13px;
|
||||
line-height: 17px;
|
||||
|
||||
p {
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Rules for the menu displayed in the left sidebar */
|
||||
|
||||
.left_menu {
|
||||
padding: 5px;
|
||||
padding: 5px 10px;
|
||||
margin: 4px 0;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
|
@ -156,6 +165,13 @@ h2 {
|
|||
padding: 0px;
|
||||
}
|
||||
|
||||
/* submenus */
|
||||
.left_menu ul li ul {
|
||||
font-weight: normal;
|
||||
line-height: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.left_menu a {
|
||||
color: #000;
|
||||
}
|
||||
|
@ -163,14 +179,17 @@ h2 {
|
|||
/* Rules for SOTM advert */
|
||||
|
||||
#sotm {
|
||||
width: 180px;
|
||||
min-width: 180px;
|
||||
margin: 5px;
|
||||
width: 165px;
|
||||
margin: 10px;
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#sotm img {
|
||||
width: 165px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules for "optional boxes" which appear in the left sidebar on
|
||||
* certain pages. Current users are the seach box on the main page
|
||||
|
@ -178,9 +197,8 @@ h2 {
|
|||
*/
|
||||
|
||||
.optionalbox {
|
||||
padding: 5px;
|
||||
padding: 5px 10px;
|
||||
margin: 4px 0;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.optionalbox h1 {
|
||||
|
@ -194,13 +212,6 @@ h2 {
|
|||
/* Rules for the search box */
|
||||
|
||||
.whereami {
|
||||
line-height: 20px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.search_container {
|
||||
height: 15px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#search_field form {
|
||||
|
@ -209,34 +220,71 @@ h2 {
|
|||
padding: 0px;
|
||||
}
|
||||
|
||||
#search_field {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
#search_field input[type="text"] {
|
||||
width: 136px;
|
||||
width: 165px;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
line-height: 15px;
|
||||
height: 25px;
|
||||
box-shadow: inset #DDD 0px 1px 3px;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
}
|
||||
|
||||
#search_field input[type="text"]:focus {
|
||||
outline: none;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
#search_field input[type="submit"] {
|
||||
width: 26px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border:0;
|
||||
text-indent:-1000px;
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
background: url(sprite.png);
|
||||
position:absolute;
|
||||
right:2px;
|
||||
top:5px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.search_help {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 0px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.deemphasize {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.deemphasize a {
|
||||
color: #7092FF;
|
||||
}
|
||||
|
||||
/* Rules for donation request box */
|
||||
|
||||
.donate {
|
||||
width: 155px;
|
||||
margin: 10px 5px;
|
||||
width: 153px;
|
||||
margin: 10px 10px;
|
||||
padding: 5px;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid #AED1A0;
|
||||
background: #cbeea7;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
}
|
||||
|
||||
.donate a {
|
||||
color:#222;
|
||||
}
|
||||
|
||||
/* Rules for Creative Commons logo button */
|
||||
|
@ -290,7 +338,24 @@ h2 {
|
|||
#tabnav a:visited.disabled,
|
||||
#tabnav a:link:hover.disabled,
|
||||
#tabnav a:visited:hover.disabled {
|
||||
color: #888;
|
||||
color: #ccc;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#tabnav a:link.disabled:hover,
|
||||
#tabnav a:visited.disabled:hover,
|
||||
#tabnav a:link:hover.disabled:hover,
|
||||
#tabnav a:visited:hover.disabled:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.count-number {
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
background: #eee;
|
||||
margin: 0 2px;
|
||||
font-size: 11px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Rules for greeting bar in the top right corner */
|
||||
|
@ -345,23 +410,34 @@ h2 {
|
|||
|
||||
/* Rules for edit menu */
|
||||
|
||||
.menuicon {
|
||||
padding: 5px;
|
||||
|
||||
&:hover {
|
||||
background: #eee;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: none;
|
||||
z-index: 10000;
|
||||
position: absolute;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid black;
|
||||
border: 1px solid #cccccc;
|
||||
border-top: 0px;
|
||||
}
|
||||
|
||||
.menu ul {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.menu li {
|
||||
padding: 2px 5px;
|
||||
margin: 0px;
|
||||
list-style-type: none;
|
||||
border-top: 1px solid #eee;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
@ -828,6 +904,10 @@ p#contributorGuidance {
|
|||
|
||||
/* Rules for the account settings page */
|
||||
|
||||
#accountForm {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#accountForm td {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
@ -879,11 +959,11 @@ p#contributorGuidance {
|
|||
|
||||
/* Rules for the user map */
|
||||
|
||||
.user_map .olControlPanZoomBar {
|
||||
.user_map .olControlSimplePanZoom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.user_map .olControlPanZoom {
|
||||
.user_map .olControlZoom {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
@ -912,6 +992,14 @@ p#contributorGuidance {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.inbox-row .inbox-mark-read {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inbox-row-unread .inbox-mark-unread {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Rules for "flash" notice boxes shown at the top of the content area */
|
||||
|
||||
#error {
|
||||
|
@ -997,7 +1085,7 @@ input[type="email"],
|
|||
input[type="url"],
|
||||
input[type="password"],
|
||||
textarea {
|
||||
border: 1px solid #888;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* Rules for user images */
|
||||
|
@ -1049,3 +1137,63 @@ abbr.geo {
|
|||
vertical-align: text-bottom;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Rules for rich text editors */
|
||||
|
||||
.richtext_container {
|
||||
white-space: nowrap;
|
||||
|
||||
.richtext_content {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
.richtext_preview {
|
||||
display: inline-block;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 1px;
|
||||
border: 4px solid #eee;
|
||||
background-color: #eee;
|
||||
white-space: normal;
|
||||
|
||||
&.loading {
|
||||
background-image: image-url("loading.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.richtext_help {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
background-color: #ddd;
|
||||
padding: 5px 10px 10px 10px;
|
||||
font-size: 12px;
|
||||
|
||||
p {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
th {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
td {
|
||||
font-family: fixed;
|
||||
line-height: 16px;
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
input.richtext_doedit {
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
|
||||
input.richtext_dopreview {
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
/* Rules for OpenLayers maps */
|
||||
|
||||
.olControlPanZoom {
|
||||
.olControlZoom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,26 +6,6 @@ html body {
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules for alert boxes shown in the left sidebar when important
|
||||
* information needs to be conveyed such as when the site is
|
||||
* undergoing maintenance.
|
||||
*/
|
||||
|
||||
#alert {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules for notice boxes shown in the left sidebar when important, but
|
||||
* non-critical information needs to be conveyed such as notices about
|
||||
* donation drives.
|
||||
*/
|
||||
|
||||
.notice {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Rules for the menu displayed in the left sidebar */
|
||||
|
||||
.left_menu {
|
||||
|
@ -60,12 +40,6 @@ html body {
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
/* Rules for the search box */
|
||||
|
||||
.whereami {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* Rules for tabbed navigation bar */
|
||||
|
||||
#top-bar {
|
||||
|
@ -235,3 +209,28 @@ input.openid_url {
|
|||
background: image-url('openid_input.png') repeat-y left white;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
/* Rules for rich text editors */
|
||||
|
||||
.richtext_container {
|
||||
.richtext_help {
|
||||
margin-left: 15px;
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 0px 15px 0px 0px !important;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input.richtext_doedit {
|
||||
margin-right: 10px !important;
|
||||
}
|
||||
|
||||
input.richtext_dopreview {
|
||||
margin-left: 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,15 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.olControlPanZoom {
|
||||
.olControlZoom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.olControlPanZoomBar {
|
||||
.olControlSimplePanZoom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.olControlLayerSwitcher {
|
||||
.SimpleLayerSwitcher {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,26 +6,6 @@ html body {
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules for alert boxes shown in the left sidebar when important
|
||||
* information needs to be conveyed such as when the site is
|
||||
* undergoing maintenance.
|
||||
*/
|
||||
|
||||
#alert {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules for notice boxes shown in the left sidebar when important, but
|
||||
* non-critical information needs to be conveyed such as notices about
|
||||
* donation drives.
|
||||
*/
|
||||
|
||||
.notice {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Rules for the menu displayed in the left sidebar */
|
||||
|
||||
.left_menu {
|
||||
|
@ -60,12 +40,6 @@ html body {
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
/* Rules for the search box */
|
||||
|
||||
.whereami {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* Rules for tabbed navigation bar */
|
||||
|
||||
#top-bar {
|
||||
|
@ -235,3 +209,28 @@ input.openid_url {
|
|||
background: image-url('openid_input.png') repeat-y right white;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
/* Rules for rich text editors */
|
||||
|
||||
.richtext_container {
|
||||
.richtext_help {
|
||||
margin-right: 15px;
|
||||
|
||||
th {
|
||||
text-align: right;
|
||||
padding: 0px 0px 0px 15px !important;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
input.richtext_doedit {
|
||||
margin-left: 10px !important;
|
||||
}
|
||||
|
||||
input.richtext_dopreview {
|
||||
margin-right: 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ h1 {
|
|||
|
||||
/* Rules for tabbed navigation bar */
|
||||
#top-bar {
|
||||
margin: 0;
|
||||
margin: 0px;
|
||||
height: 19px;
|
||||
}
|
||||
|
||||
#tabnav {
|
||||
|
@ -90,18 +91,20 @@ h1 {
|
|||
border: 0;
|
||||
}
|
||||
|
||||
.olControlPanZoomBar {
|
||||
.olControlSimplePanZoom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Rules for the main content area */
|
||||
|
||||
#content {
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
top: 47px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 38px;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
border-left: 0px;
|
||||
border-right: 0px;
|
||||
}
|
||||
|
||||
#content.site_index {
|
||||
|
|
|
@ -133,7 +133,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'startchangeset'",nil,nil) do
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so Potlatch can't write any changes to the database." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if user.blocks.active.exists? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
|
||||
|
||||
if cstags
|
||||
|
@ -359,13 +359,13 @@ class AmfController < ApplicationController
|
|||
amf_handle_error_with_timeout("'getway_old' #{id}, #{timestamp}", 'way',id) do
|
||||
if timestamp == ''
|
||||
# undelete
|
||||
old_way = OldWay.where(:visible => true, :way_id => id).order("version DESC").first
|
||||
old_way = OldWay.where(:visible => true, :way_id => id).unredacted.order("version DESC").first
|
||||
points = old_way.get_nodes_undelete unless old_way.nil?
|
||||
else
|
||||
begin
|
||||
# revert
|
||||
timestamp = DateTime.strptime(timestamp.to_s, "%d %b %Y, %H:%M:%S")
|
||||
old_way = OldWay.where("way_id = ? AND timestamp <= ?", id, timestamp).order("timestamp DESC").first
|
||||
old_way = OldWay.where("way_id = ? AND timestamp <= ?", id, timestamp).unredacted.order("timestamp DESC").first
|
||||
unless old_way.nil?
|
||||
points = old_way.get_nodes_revert(timestamp)
|
||||
if !old_way.visible
|
||||
|
@ -403,11 +403,11 @@ class AmfController < ApplicationController
|
|||
# Find list of revision dates for way and all constituent nodes
|
||||
revdates=[]
|
||||
revusers={}
|
||||
Way.find(wayid).old_ways.collect do |a|
|
||||
Way.find(wayid).old_ways.unredacted.collect do |a|
|
||||
revdates.push(a.timestamp)
|
||||
unless revusers.has_key?(a.timestamp.to_i) then revusers[a.timestamp.to_i]=change_user(a) end
|
||||
a.nds.each do |n|
|
||||
Node.find(n).old_nodes.collect do |o|
|
||||
Node.find(n).old_nodes.unredacted.collect do |o|
|
||||
revdates.push(o.timestamp)
|
||||
unless revusers.has_key?(o.timestamp.to_i) then revusers[o.timestamp.to_i]=change_user(o) end
|
||||
end
|
||||
|
@ -423,7 +423,7 @@ class AmfController < ApplicationController
|
|||
# Remove any elements where 2 seconds doesn't elapse before next one
|
||||
revdates.delete_if { |d| revdates.include?(d+1) or revdates.include?(d+2) }
|
||||
# Collect all in one nested array
|
||||
revdates.collect! {|d| [d.succ.strftime("%d %b %Y, %H:%M:%S")] + revusers[d.to_i] }
|
||||
revdates.collect! {|d| [(d + 1).strftime("%d %b %Y, %H:%M:%S")] + revusers[d.to_i] }
|
||||
revdates.uniq!
|
||||
|
||||
return ['way', wayid, revdates]
|
||||
|
@ -436,8 +436,8 @@ class AmfController < ApplicationController
|
|||
|
||||
def getnode_history(nodeid) #:doc:
|
||||
begin
|
||||
history = Node.find(nodeid).old_nodes.reverse.collect do |old_node|
|
||||
[old_node.timestamp.succ.strftime("%d %b %Y, %H:%M:%S")] + change_user(old_node)
|
||||
history = Node.find(nodeid).old_nodes.unredacted.reverse.collect do |old_node|
|
||||
[(old_node.timestamp + 1).strftime("%d %b %Y, %H:%M:%S")] + change_user(old_node)
|
||||
end
|
||||
return ['node', nodeid, history]
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
|
@ -459,7 +459,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error_with_timeout("'findgpx'" ,nil,nil) do
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You must be logged in to search for GPX traces." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if user.blocks.active.exists? then return -1,t('application.setup_user_auth.blocked') end
|
||||
|
||||
query = Trace.visible_to(user)
|
||||
if searchterm.to_i > 0 then
|
||||
|
@ -523,7 +523,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'putrelation' #{relid}" ,'relation',relid) do
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so the relation could not be saved." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if user.blocks.active.exists? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
|
||||
|
||||
if !tags_ok(tags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end
|
||||
|
@ -613,7 +613,7 @@ class AmfController < ApplicationController
|
|||
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so the way could not be saved." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if user.blocks.active.exists? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
|
||||
|
||||
if pointlist.length < 2 then return -2,"Server error - way is only #{points.length} points long." end
|
||||
|
@ -722,7 +722,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'putpoi' #{id}", 'node',id) do
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so the point could not be saved." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if user.blocks.active.exists? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
|
||||
|
||||
if !tags_ok(tags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end
|
||||
|
@ -782,7 +782,7 @@ class AmfController < ApplicationController
|
|||
n = Node.find(id)
|
||||
v = n.version
|
||||
unless timestamp == ''
|
||||
n = OldNode.where("id = ? AND timestamp <= ?", id, timestamp).order("timestamp DESC").first
|
||||
n = OldNode.where("node_id = ? AND timestamp <= ?", id, timestamp).unredacted.order("timestamp DESC").first
|
||||
end
|
||||
|
||||
if n
|
||||
|
@ -807,7 +807,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'deleteway' #{way_id}" ,'way', way_id) do
|
||||
user = getuser(usertoken)
|
||||
unless user then return -1,"You are not logged in, so the way could not be deleted." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if user.blocks.active.exists? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
|
||||
|
||||
way_id = way_id.to_i
|
||||
|
|
|
@ -2,6 +2,7 @@ class ApiController < ApplicationController
|
|||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
before_filter :check_api_readable, :except => [:capabilities]
|
||||
before_filter :setup_user_auth, :only => [:permissions]
|
||||
after_filter :compress_output
|
||||
around_filter :api_call_handle_error, :api_call_timeout
|
||||
|
||||
|
@ -289,4 +290,20 @@ class ApiController < ApplicationController
|
|||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
end
|
||||
|
||||
# External apps that use the api are able to query which permissions
|
||||
# they have. This currently returns a list of permissions granted to the current user:
|
||||
# * if authenticated via OAuth, this list will contain all permissions granted by the user to the access_token.
|
||||
# * if authenticated via basic auth all permissions are granted, so the list will contain all permissions.
|
||||
# * unauthenticated users have no permissions, so the list will be empty.
|
||||
def permissions
|
||||
@permissions = case
|
||||
when current_token.present?
|
||||
ClientApplication.all_permissions.select { |p| current_token.read_attribute(p) }
|
||||
when @user
|
||||
ClientApplication.all_permissions
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,13 +4,6 @@ class ApplicationController < ActionController::Base
|
|||
protect_from_forgery
|
||||
|
||||
if STATUS == :database_readonly or STATUS == :database_offline
|
||||
after_filter :clear_session
|
||||
wrap_parameters false
|
||||
|
||||
def clear_session
|
||||
session.clear
|
||||
end
|
||||
|
||||
def self.cache_sweeper(*sweepers)
|
||||
end
|
||||
end
|
||||
|
@ -51,7 +44,13 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def require_user
|
||||
redirect_to :controller => 'user', :action => 'login', :referer => request.fullpath unless @user
|
||||
unless @user
|
||||
if request.get?
|
||||
redirect_to :controller => 'user', :action => 'login', :referer => request.fullpath
|
||||
else
|
||||
render :nothing => true, :status => :forbidden
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -112,6 +111,20 @@ class ApplicationController < ActionController::Base
|
|||
require_capability(:allow_write_gpx)
|
||||
end
|
||||
|
||||
##
|
||||
# require that the user is a moderator, or fill out a helpful error message
|
||||
# and return them to the index for the controller this is wrapped from.
|
||||
def require_moderator
|
||||
unless @user.moderator?
|
||||
if request.get?
|
||||
flash[:error] = t('application.require_moderator.not_a_moderator')
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :nothing => true, :status => :forbidden
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# sets up the @user object for use by other methods. this is mostly called
|
||||
# from the authorize method, but can be called elsewhere if authorisation
|
||||
|
@ -133,7 +146,7 @@ class ApplicationController < ActionController::Base
|
|||
# have we identified the user?
|
||||
if @user
|
||||
# check if the user has been banned
|
||||
if not @user.active_blocks.empty?
|
||||
if @user.blocks.active.exists?
|
||||
# NOTE: need slightly more helpful message than this.
|
||||
report_error t('application.setup_user_auth.blocked'), :forbidden
|
||||
end
|
||||
|
@ -161,6 +174,22 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# to be used as a before_filter *after* authorize. this checks that
|
||||
# the user is a moderator and, if not, returns a forbidden error.
|
||||
#
|
||||
# NOTE: this isn't a very good way of doing it - it duplicates logic
|
||||
# from require_moderator - but what we really need to do is a fairly
|
||||
# drastic refactoring based on :format and respond_to? but not a
|
||||
# good idea to do that in this branch.
|
||||
def authorize_moderator(errormessage="Access restricted to moderators")
|
||||
# check user is a moderator
|
||||
unless @user.moderator?
|
||||
render :text => errormessage, :status => :forbidden
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def check_database_readable(need_api = false)
|
||||
if STATUS == :database_offline or (need_api and STATUS == :api_offline)
|
||||
redirect_to :controller => 'site', :action => 'offline'
|
||||
|
@ -356,6 +385,26 @@ class ApplicationController < ActionController::Base
|
|||
!@user.nil?
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "this_user" instance variable
|
||||
def lookup_this_user
|
||||
unless @this_user = User.active.find_by_display_name(params[:display_name])
|
||||
render_unknown_user params[:display_name]
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# render a "no such user" page
|
||||
def render_unknown_user(name)
|
||||
@title = t "user.no_such_user.title"
|
||||
@not_found_user = name
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :template => "user/no_such_user", :status => :not_found }
|
||||
format.all { render :nothing => true, :status => :not_found }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# extract authorisation credentials from headers, returns user = nil if none
|
||||
|
|
|
@ -7,6 +7,11 @@ class BrowseController < ApplicationController
|
|||
around_filter :web_timeout, :except => [:start]
|
||||
|
||||
def start
|
||||
@max_features = case
|
||||
when browser.ie? && browser.version.to_i < 8 then 100
|
||||
when browser.ie? && browser.version.to_i < 9 then 500
|
||||
else 2000
|
||||
end
|
||||
end
|
||||
|
||||
def relation
|
||||
|
|
|
@ -143,10 +143,11 @@ class ChangesetController < ApplicationController
|
|||
def download
|
||||
changeset = Changeset.find(params[:id])
|
||||
|
||||
# get all the elements in the changeset and stick them in a big array.
|
||||
elements = [changeset.old_nodes,
|
||||
changeset.old_ways,
|
||||
changeset.old_relations].flatten
|
||||
# get all the elements in the changeset which haven't been redacted
|
||||
# and stick them in a big array.
|
||||
elements = [changeset.old_nodes.unredacted,
|
||||
changeset.old_ways.unredacted,
|
||||
changeset.old_relations.unredacted].flatten
|
||||
|
||||
# sort the elements by timestamp and version number, as this is the
|
||||
# almost sensible ordering available. this would be much nicer if
|
||||
|
@ -259,10 +260,8 @@ class ChangesetController < ApplicationController
|
|||
else
|
||||
changesets = changesets.where("false")
|
||||
end
|
||||
elsif request.format == :html
|
||||
@title = t 'user.no_such_user.title'
|
||||
@not_found_user = params[:display_name]
|
||||
render :template => 'user/no_such_user', :status => :not_found
|
||||
else
|
||||
render_unknown_user params[:display_name]
|
||||
return
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ class DiaryEntryController < ApplicationController
|
|||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
before_filter :require_user, :only => [:new, :edit, :comment, :hide, :hidecomment]
|
||||
before_filter :lookup_this_user, :only => [:view, :comments]
|
||||
before_filter :check_database_readable
|
||||
before_filter :check_database_writable, :only => [:new, :edit]
|
||||
before_filter :require_administrator, :only => [:hide, :hidecomment]
|
||||
|
@ -84,10 +85,7 @@ class DiaryEntryController < ApplicationController
|
|||
:order => 'created_at DESC',
|
||||
:per_page => 20)
|
||||
else
|
||||
@title = t'diary_entry.no_such_user.title'
|
||||
@not_found_user = params[:display_name]
|
||||
|
||||
render :action => 'no_such_user', :status => :not_found
|
||||
render_unknown_user params[:display_name]
|
||||
end
|
||||
elsif params[:language]
|
||||
@title = t 'diary_entry.list.in_language_title', :language => Language.find(params[:language]).english_name
|
||||
|
@ -167,49 +165,36 @@ class DiaryEntryController < ApplicationController
|
|||
end
|
||||
|
||||
def view
|
||||
user = User.active.find_by_display_name(params[:display_name])
|
||||
|
||||
if user
|
||||
@entry = user.diary_entries.visible.where(:id => params[:id]).first
|
||||
if @entry
|
||||
@title = t 'diary_entry.view.title', :user => params[:display_name], :title => @entry.title
|
||||
else
|
||||
@title = t 'diary_entry.no_such_entry.title', :id => params[:id]
|
||||
render :action => 'no_such_entry', :status => :not_found
|
||||
end
|
||||
@entry = @this_user.diary_entries.visible.where(:id => params[:id]).first
|
||||
if @entry
|
||||
@title = t 'diary_entry.view.title', :user => params[:display_name], :title => @entry.title
|
||||
else
|
||||
@not_found_user = params[:display_name]
|
||||
|
||||
render :action => 'no_such_user', :status => :not_found
|
||||
@title = t 'diary_entry.no_such_entry.title', :id => params[:id]
|
||||
render :action => 'no_such_entry', :status => :not_found
|
||||
end
|
||||
end
|
||||
|
||||
def hide
|
||||
entry = DiaryEntry.find(params[:id])
|
||||
entry.update_attributes(:visible => false)
|
||||
entry.update_attributes({:visible => false}, :without_protection => true)
|
||||
redirect_to :action => "list", :display_name => entry.user.display_name
|
||||
end
|
||||
|
||||
def hidecomment
|
||||
comment = DiaryComment.find(params[:comment])
|
||||
comment.update_attributes(:visible => false)
|
||||
comment.update_attributes({:visible => false}, :without_protection => true)
|
||||
redirect_to :action => "view", :display_name => comment.diary_entry.user.display_name, :id => comment.diary_entry.id
|
||||
end
|
||||
|
||||
def comments
|
||||
@this_user = User.active.find_by_display_name(params[:display_name])
|
||||
|
||||
if @this_user
|
||||
@comment_pages, @comments = paginate(:diary_comments,
|
||||
:conditions => { :user_id => @this_user },
|
||||
:order => 'created_at DESC',
|
||||
:per_page => 20)
|
||||
@page = (params[:page] || 1).to_i
|
||||
else
|
||||
@title = t'diary_entry.no_such_user.title'
|
||||
@not_found_user = params[:display_name]
|
||||
render :action => 'no_such_user', :status => :not_found
|
||||
end
|
||||
@comment_pages, @comments = paginate(:diary_comments,
|
||||
:conditions => {
|
||||
:user_id => @this_user,
|
||||
:visible => true
|
||||
},
|
||||
:order => 'created_at DESC',
|
||||
:per_page => 20)
|
||||
@page = (params[:page] || 1).to_i
|
||||
end
|
||||
private
|
||||
##
|
||||
|
|
|
@ -21,15 +21,6 @@ class ExportController < ApplicationController
|
|||
scale = params[:mapnik_scale]
|
||||
|
||||
redirect_to "http://parent.tile.openstreetmap.org/cgi-bin/export?bbox=#{bbox}&scale=#{scale}&format=#{format}"
|
||||
|
||||
elsif format == "osmarender"
|
||||
#redirect to the t@h 'MapOf' service
|
||||
format = params[:osmarender_format]
|
||||
zoom = params[:osmarender_zoom].to_i
|
||||
width = bbox.slippy_width(zoom).to_i
|
||||
height = bbox.slippy_height(zoom).to_i
|
||||
|
||||
redirect_to "http://tah.openstreetmap.org/MapOf/index.php?long=#{bbox.centre_lon}&lat=#{bbox.centre_lat}&z=#{zoom}&w=#{width}&h=#{height}&format=#{format}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,7 +26,7 @@ class GeocoderController < ApplicationController
|
|||
@sources.push "osm_nominatim"
|
||||
else
|
||||
@sources.push "osm_nominatim"
|
||||
@sources.push "geonames"
|
||||
@sources.push "geonames" if defined?(GEONAMES_USERNAME)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -272,7 +272,7 @@ class GeocoderController < ApplicationController
|
|||
@results = Array.new
|
||||
|
||||
# ask geonames.org
|
||||
response = fetch_xml("http://ws.geonames.org/search?q=#{escape_query(query)}&maxRows=20")
|
||||
response = fetch_xml("http://api.geonames.org/search?q=#{escape_query(query)}&maxRows=20&username=#{GEONAMES_USERNAME}")
|
||||
|
||||
# parse the response
|
||||
response.elements.each("geonames/geoname") do |geoname|
|
||||
|
|
|
@ -4,44 +4,32 @@ class MessageController < ApplicationController
|
|||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
before_filter :require_user
|
||||
before_filter :lookup_this_user, :only => [:new]
|
||||
before_filter :check_database_readable
|
||||
before_filter :check_database_writable, :only => [:new, :reply, :mark]
|
||||
|
||||
# Allow the user to write a new message to another user. This action also
|
||||
# Allow the user to write a new message to another user. This action also
|
||||
# deals with the sending of that message to the other user when the user
|
||||
# clicks send.
|
||||
# The display_name param is the display name of the user that the message is being sent to.
|
||||
def new
|
||||
@to_user = User.find_by_display_name(params[:display_name])
|
||||
if @to_user
|
||||
if params[:message]
|
||||
if @user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= MAX_MESSAGES_PER_HOUR
|
||||
flash[:error] = t 'message.new.limit_exceeded'
|
||||
else
|
||||
@message = Message.new(params[:message])
|
||||
@message.to_user_id = @to_user.id
|
||||
@message.from_user_id = @user.id
|
||||
@message.sent_on = Time.now.getutc
|
||||
|
||||
if @message.save
|
||||
flash[:notice] = t 'message.new.message_sent'
|
||||
Notifier.message_notification(@message).deliver
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
end
|
||||
end
|
||||
if params[:message]
|
||||
if @user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= MAX_MESSAGES_PER_HOUR
|
||||
flash[:error] = t 'message.new.limit_exceeded'
|
||||
else
|
||||
if params[:title]
|
||||
# ?title= is set when someone reponds to this user's diary
|
||||
# entry. Then we pre-fill out the subject and the <title>
|
||||
@title = @subject = params[:title]
|
||||
else
|
||||
# The default /message/new/$user view
|
||||
@title = t 'message.new.title'
|
||||
@message = Message.new(params[:message])
|
||||
@message.to_user_id = @this_user.id
|
||||
@message.from_user_id = @user.id
|
||||
@message.sent_on = Time.now.getutc
|
||||
|
||||
if @message.save
|
||||
flash[:notice] = t 'message.new.message_sent'
|
||||
Notifier.message_notification(@message).deliver
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
end
|
||||
end
|
||||
else
|
||||
@title = t'message.no_such_user.title'
|
||||
render :action => 'no_such_user', :status => :not_found
|
||||
@title = t 'message.new.title'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -50,9 +38,9 @@ class MessageController < ApplicationController
|
|||
message = Message.find(params[:message_id])
|
||||
|
||||
if message.to_user_id == @user.id then
|
||||
@body = "On #{message.sent_on} #{message.sender.display_name} wrote:\n\n#{message.body.gsub(/^/, '> ')}"
|
||||
@body = "On #{message.sent_on} #{message.sender.display_name} wrote:\n\n#{message.body.gsub(/^/, '> ')}"
|
||||
@title = @subject = "Re: #{message.title.sub(/^Re:\s*/, '')}"
|
||||
@to_user = User.find(message.from_user_id)
|
||||
@this_user = User.find(message.from_user_id)
|
||||
|
||||
render :action => 'new'
|
||||
else
|
||||
|
@ -101,22 +89,19 @@ class MessageController < ApplicationController
|
|||
|
||||
# Set the message as being read or unread.
|
||||
def mark
|
||||
if params[:message_id]
|
||||
id = params[:message_id]
|
||||
@message = Message.where(:id => id).where("to_user_id = ? OR from_user_id = ?", @user.id, @user.id).first
|
||||
if params[:mark] == 'unread'
|
||||
message_read = false
|
||||
notice = t 'message.mark.as_unread'
|
||||
else
|
||||
message_read = true
|
||||
notice = t 'message.mark.as_read'
|
||||
end
|
||||
@message.message_read = message_read
|
||||
if @message.save
|
||||
if not request.xhr?
|
||||
flash[:notice] = notice
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
end
|
||||
@message = Message.where("to_user_id = ? OR from_user_id = ?", @user.id, @user.id).find(params[:message_id])
|
||||
if params[:mark] == 'unread'
|
||||
message_read = false
|
||||
notice = t 'message.mark.as_unread'
|
||||
else
|
||||
message_read = true
|
||||
notice = t 'message.mark.as_read'
|
||||
end
|
||||
@message.message_read = message_read
|
||||
if @message.save
|
||||
if not request.xhr?
|
||||
flash[:notice] = notice
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
|
@ -126,19 +111,16 @@ class MessageController < ApplicationController
|
|||
|
||||
# Delete the message.
|
||||
def delete
|
||||
if params[:message_id]
|
||||
id = params[:message_id]
|
||||
message = Message.where(:id => id).where("to_user_id = ? OR from_user_id = ?", @user.id, @user.id).first
|
||||
message.from_user_visible = false if message.sender == @user
|
||||
message.to_user_visible = false if message.recipient == @user
|
||||
if message.save
|
||||
flash[:notice] = t 'message.delete.deleted'
|
||||
message = Message.where("to_user_id = ? OR from_user_id = ?", @user.id, @user.id).find(params[:message_id])
|
||||
message.from_user_visible = false if message.sender == @user
|
||||
message.to_user_visible = false if message.recipient == @user
|
||||
if message.save
|
||||
flash[:notice] = t 'message.delete.deleted'
|
||||
|
||||
if params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
end
|
||||
if params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
|
|
|
@ -32,7 +32,7 @@ class OauthController < ApplicationController
|
|||
@token.invalidate!
|
||||
flash[:notice] = t('oauth.revoke.flash', :application => @token.client_application.name)
|
||||
end
|
||||
redirect_to :controller => 'oauth_clients', :action => 'index'
|
||||
redirect_to oauth_clients_url(:display_name => @token.user.display_name)
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
77
app/controllers/old_controller.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
# this class pulls together the logic for all the old_* controllers
|
||||
# into one place. as it turns out, the API methods for historical
|
||||
# nodes, ways and relations are basically identical.
|
||||
class OldController < ApplicationController
|
||||
require 'xml/libxml'
|
||||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
before_filter :setup_user_auth, :only => [ :history, :version ]
|
||||
before_filter :authorize, :only => [ :redact ]
|
||||
before_filter :authorize_moderator, :only => [ :redact ]
|
||||
before_filter :require_allow_write_api, :only => [ :redact ]
|
||||
before_filter :check_api_readable
|
||||
before_filter :check_api_writable, :only => [ :redact ]
|
||||
after_filter :compress_output
|
||||
around_filter :api_call_handle_error, :api_call_timeout
|
||||
before_filter :lookup_old_element, :except => [ :history ]
|
||||
before_filter :lookup_old_element_versions, :only => [ :history ]
|
||||
|
||||
def history
|
||||
# the .where() method used in the lookup_old_element_versions
|
||||
# call won't throw an error if no records are found, so we have
|
||||
# to do that ourselves.
|
||||
raise OSM::APINotFoundError.new if @elements.empty?
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
|
||||
visible_elements = if show_redactions?
|
||||
@elements
|
||||
else
|
||||
@elements.unredacted
|
||||
end
|
||||
|
||||
visible_elements.each do |element|
|
||||
doc.root << element.to_xml_node
|
||||
end
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
end
|
||||
|
||||
def version
|
||||
if @old_element.redacted? and not show_redactions?
|
||||
render :nothing => true, :status => :forbidden
|
||||
|
||||
else
|
||||
response.last_modified = @old_element.timestamp
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << @old_element.to_xml_node
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
end
|
||||
end
|
||||
|
||||
def redact
|
||||
redaction_id = params['redaction']
|
||||
unless redaction_id.nil?
|
||||
# if a redaction ID was specified, then set this element to
|
||||
# be redacted in that redaction.
|
||||
redaction = Redaction.find(redaction_id.to_i)
|
||||
@old_element.redact!(redaction)
|
||||
|
||||
else
|
||||
# if no redaction ID was provided, then this is an unredact
|
||||
# operation.
|
||||
@old_element.redact!(nil)
|
||||
end
|
||||
|
||||
# just return an empty 200 OK for success
|
||||
render :nothing => true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def show_redactions?
|
||||
@user and @user.moderator? and params[:show_redactions] == "true"
|
||||
end
|
||||
end
|
|
@ -1,33 +1,12 @@
|
|||
class OldNodeController < ApplicationController
|
||||
require 'xml/libxml'
|
||||
class OldNodeController < OldController
|
||||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
before_filter :check_api_readable
|
||||
after_filter :compress_output
|
||||
around_filter :api_call_handle_error, :api_call_timeout
|
||||
|
||||
def history
|
||||
node = Node.find(params[:id])
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
|
||||
node.old_nodes.each do |old_node|
|
||||
doc.root << old_node.to_xml_node
|
||||
end
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
end
|
||||
private
|
||||
|
||||
def version
|
||||
if old_node = OldNode.where(:node_id => params[:id], :version => params[:version]).first
|
||||
response.last_modified = old_node.timestamp
|
||||
def lookup_old_element
|
||||
@old_element = OldNode.find([params[:id], params[:version]])
|
||||
end
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << old_node.to_xml_node
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
else
|
||||
render :nothing => true, :status => :not_found
|
||||
end
|
||||
def lookup_old_element_versions
|
||||
@elements = OldNode.where(:node_id => params[:id]).order(:version)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,32 +1,12 @@
|
|||
class OldRelationController < ApplicationController
|
||||
require 'xml/libxml'
|
||||
class OldRelationController < OldController
|
||||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
before_filter :check_api_readable
|
||||
after_filter :compress_output
|
||||
around_filter :api_call_handle_error, :api_call_timeout
|
||||
|
||||
def history
|
||||
relation = Relation.find(params[:id])
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
|
||||
relation.old_relations.each do |old_relation|
|
||||
doc.root << old_relation.to_xml_node
|
||||
end
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
end
|
||||
private
|
||||
|
||||
def version
|
||||
if old_relation = OldRelation.where(:relation_id => params[:id], :version => params[:version]).first
|
||||
response.last_modified = old_relation.timestamp
|
||||
def lookup_old_element
|
||||
@old_element = OldRelation.find([params[:id], params[:version]])
|
||||
end
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << old_relation.to_xml_node
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
else
|
||||
render :nothing => true, :status => :not_found
|
||||
end
|
||||
def lookup_old_element_versions
|
||||
@elements = OldRelation.where(:relation_id => params[:id]).order(:version)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,33 +1,12 @@
|
|||
class OldWayController < ApplicationController
|
||||
require 'xml/libxml'
|
||||
class OldWayController < OldController
|
||||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
before_filter :check_api_readable
|
||||
after_filter :compress_output
|
||||
around_filter :api_call_handle_error, :api_call_timeout
|
||||
|
||||
def history
|
||||
way = Way.find(params[:id])
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
|
||||
way.old_ways.each do |old_way|
|
||||
doc.root << old_way.to_xml_node
|
||||
end
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
end
|
||||
private
|
||||
|
||||
def version
|
||||
if old_way = OldWay.where(:way_id => params[:id], :version => params[:version]).first
|
||||
response.last_modified = old_way.timestamp
|
||||
def lookup_old_element
|
||||
@old_element = OldWay.find([params[:id], params[:version]])
|
||||
end
|
||||
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << old_way.to_xml_node
|
||||
|
||||
render :text => doc.to_s, :content_type => "text/xml"
|
||||
else
|
||||
render :nothing => true, :status => :not_found
|
||||
end
|
||||
def lookup_old_element_versions
|
||||
@elements = OldWay.where(:way_id => params[:id]).order(:version)
|
||||
end
|
||||
end
|
||||
|
|
76
app/controllers/redactions_controller.rb
Normal file
|
@ -0,0 +1,76 @@
|
|||
class RedactionsController < ApplicationController
|
||||
layout 'site'
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
before_filter :require_user, :only => [:new, :create, :edit, :update, :destroy]
|
||||
before_filter :require_moderator, :only => [:new, :create, :edit, :update, :destroy]
|
||||
before_filter :lookup_redaction, :only => [:show, :edit, :update, :destroy]
|
||||
before_filter :check_database_readable
|
||||
before_filter :check_database_writable, :only => [:create, :update, :destroy]
|
||||
|
||||
def index
|
||||
@redactions_pages, @redactions = paginate(:redactions, :order => :id, :per_page => 10)
|
||||
end
|
||||
|
||||
def new
|
||||
@redaction = Redaction.new
|
||||
end
|
||||
|
||||
def create
|
||||
@redaction = Redaction.new
|
||||
@redaction.user = @user
|
||||
@redaction.title = params[:redaction][:title]
|
||||
@redaction.description = params[:redaction][:description]
|
||||
# note that the description format will default to 'markdown'
|
||||
|
||||
if @redaction.save
|
||||
flash[:notice] = t('redaction.create.flash')
|
||||
redirect_to @redaction
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
# note - don't update the user ID
|
||||
@redaction.title = params[:redaction][:title]
|
||||
@redaction.description = params[:redaction][:description]
|
||||
|
||||
if @redaction.save
|
||||
flash[:notice] = t('redaction.update.flash')
|
||||
redirect_to @redaction
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
unless @redaction.old_nodes.empty? and
|
||||
@redaction.old_ways.empty? and
|
||||
@redaction.old_relations.empty?
|
||||
flash[:error] = t('redaction.destroy.not_empty')
|
||||
redirect_to @redaction
|
||||
else
|
||||
if @redaction.destroy
|
||||
flash[:notice] = t('redaction.destroy.flash')
|
||||
redirect_to :redactions
|
||||
else
|
||||
flash[:error] = t('redaction.destroy.error')
|
||||
redirect_to @redaction
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lookup_redaction
|
||||
@redaction = Redaction.find(params[:id])
|
||||
end
|
||||
end
|
|
@ -85,4 +85,8 @@ class SiteController < ApplicationController
|
|||
def copyright
|
||||
@locale = params[:copyright_locale] || I18n.locale
|
||||
end
|
||||
|
||||
def preview
|
||||
render :text => RichText.new(params[:format], params[:text]).to_html
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,9 +30,7 @@ class TraceController < ApplicationController
|
|||
if !display_name.blank?
|
||||
target_user = User.active.where(:display_name => display_name).first
|
||||
if target_user.nil?
|
||||
@title = t'trace.no_such_user.title'
|
||||
@not_found_user = display_name
|
||||
render :action => 'no_such_user', :status => :not_found
|
||||
render_unknown_user display_name
|
||||
return
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ class UserBlocksController < ApplicationController
|
|||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
before_filter :require_user, :only => [:new, :create, :edit, :update, :revoke]
|
||||
before_filter :require_moderator, :only => [:create, :update, :revoke]
|
||||
before_filter :require_moderator, :only => [:new, :create, :edit, :update, :revoke]
|
||||
before_filter :lookup_this_user, :only => [:new, :create, :blocks_on, :blocks_by]
|
||||
before_filter :lookup_user_block, :only => [:show, :edit, :update, :revoke]
|
||||
before_filter :require_valid_params, :only => [:create, :update]
|
||||
|
@ -34,46 +34,43 @@ class UserBlocksController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
unless @valid_params
|
||||
redirect_to :action => "new"
|
||||
return
|
||||
end
|
||||
|
||||
@user_block = UserBlock.new({
|
||||
:user_id => @this_user.id,
|
||||
:creator_id => @user.id,
|
||||
:reason => params[:user_block][:reason],
|
||||
:ends_at => Time.now.getutc() + @block_period.hours,
|
||||
:needs_view => params[:user_block][:needs_view]
|
||||
}, :without_protection => true)
|
||||
if @valid_params
|
||||
@user_block = UserBlock.new({
|
||||
:user_id => @this_user.id,
|
||||
:creator_id => @user.id,
|
||||
:reason => params[:user_block][:reason],
|
||||
:ends_at => Time.now.getutc() + @block_period.hours,
|
||||
:needs_view => params[:user_block][:needs_view]
|
||||
}, :without_protection => true)
|
||||
|
||||
if @user_block.save
|
||||
flash[:notice] = t('user_block.create.flash', :name => @this_user.display_name)
|
||||
redirect_to @user_block
|
||||
if @user_block.save
|
||||
flash[:notice] = t('user_block.create.flash', :name => @this_user.display_name)
|
||||
redirect_to @user_block
|
||||
else
|
||||
render :action => "new"
|
||||
end
|
||||
else
|
||||
render :action => "new"
|
||||
redirect_to new_user_block_path(:display_name => params[:display_name])
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
unless @valid_params
|
||||
redirect_to :action => "edit"
|
||||
return
|
||||
end
|
||||
|
||||
if @user_block.creator_id != @user.id
|
||||
flash[:error] = t('user_block.update.only_creator_can_edit')
|
||||
redirect_to :action => "edit"
|
||||
return
|
||||
end
|
||||
|
||||
if @user_block.update_attributes({ :ends_at => Time.now.getutc() + @block_period.hours,
|
||||
:reason => params[:user_block][:reason],
|
||||
:needs_view => params[:user_block][:needs_view] }, :without_protection => true)
|
||||
flash[:notice] = t('user_block.update.success')
|
||||
redirect_to(@user_block)
|
||||
if @valid_params
|
||||
if @user_block.creator_id != @user.id
|
||||
flash[:error] = t('user_block.update.only_creator_can_edit')
|
||||
redirect_to :action => "edit"
|
||||
elsif @user_block.update_attributes({
|
||||
:ends_at => Time.now.getutc() + @block_period.hours,
|
||||
:reason => params[:user_block][:reason],
|
||||
:needs_view => params[:user_block][:needs_view]
|
||||
}, :without_protection => true)
|
||||
flash[:notice] = t('user_block.update.success')
|
||||
redirect_to(@user_block)
|
||||
else
|
||||
render :action => "edit"
|
||||
end
|
||||
else
|
||||
render :action => "edit"
|
||||
redirect_to edit_user_block_path(:id => params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -109,24 +106,6 @@ class UserBlocksController < ApplicationController
|
|||
end
|
||||
|
||||
private
|
||||
##
|
||||
# require that the user is a moderator, or fill out a helpful error message
|
||||
# and return them to the blocks index.
|
||||
def require_moderator
|
||||
unless @user.moderator?
|
||||
flash[:error] = t('user_block.filter.not_a_moderator')
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "this_user" instance variable
|
||||
def lookup_this_user
|
||||
@this_user = User.find_by_display_name(params[:display_name])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] unless @this_user
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "user_block" instance variable
|
||||
def lookup_user_block
|
||||
|
|
|
@ -7,8 +7,8 @@ class UserController < ApplicationController
|
|||
before_filter :authorize_web, :except => [:api_details, :api_gpx_files]
|
||||
before_filter :set_locale, :except => [:api_details, :api_gpx_files]
|
||||
before_filter :require_user, :only => [:account, :go_public, :make_friend, :remove_friend]
|
||||
before_filter :check_database_readable, :except => [:api_details, :api_gpx_files]
|
||||
before_filter :check_database_writable, :only => [:login, :new, :account, :go_public, :make_friend, :remove_friend]
|
||||
before_filter :check_database_readable, :except => [:login, :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_details, :api_gpx_files]
|
||||
before_filter :require_allow_read_prefs, :only => [:api_details]
|
||||
before_filter :require_allow_read_gpx, :only => [:api_gpx_files]
|
||||
|
@ -143,51 +143,24 @@ class UserController < ApplicationController
|
|||
@tokens = @user.oauth_tokens.authorized
|
||||
|
||||
if params[:user] and params[:user][:display_name] and params[:user][:description]
|
||||
@user.display_name = params[:user][:display_name]
|
||||
@user.new_email = params[:user][:new_email]
|
||||
|
||||
if params[:user][:pass_crypt].length > 0 or params[:user][:pass_crypt_confirmation].length > 0
|
||||
@user.pass_crypt = params[:user][:pass_crypt]
|
||||
@user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
|
||||
end
|
||||
|
||||
@user.description = params[:user][:description]
|
||||
@user.languages = params[:user][:languages].split(",")
|
||||
|
||||
case params[:image_action]
|
||||
when "new" then @user.image = params[:user][:image]
|
||||
when "delete" then @user.image = nil
|
||||
end
|
||||
|
||||
@user.home_lat = params[:user][:home_lat]
|
||||
@user.home_lon = params[:user][:home_lon]
|
||||
|
||||
if params[:user][:preferred_editor] == "default"
|
||||
@user.preferred_editor = nil
|
||||
else
|
||||
@user.preferred_editor = params[:user][:preferred_editor]
|
||||
end
|
||||
|
||||
@user.openid_url = nil if params[:user][:openid_url].blank?
|
||||
|
||||
if params[:user][:openid_url] and
|
||||
params[:user][:openid_url].length > 0 and
|
||||
params[:user][:openid_url] != @user.openid_url
|
||||
# If the OpenID has changed, we want to check that it is a
|
||||
# valid OpenID and one the user has control over before saving
|
||||
# it as a password equivalent for the user.
|
||||
session[:new_user] = @user
|
||||
session[:new_user_settings] = params
|
||||
openid_verify(params[:user][:openid_url], @user)
|
||||
else
|
||||
update_user(@user)
|
||||
update_user(@user, params)
|
||||
end
|
||||
elsif using_open_id?
|
||||
# The redirect from the OpenID provider reenters here
|
||||
# again and we need to pass the parameters through to
|
||||
# the open_id_authentication function
|
||||
@user = session.delete(:new_user)
|
||||
settings = session.delete(:new_user_settings)
|
||||
openid_verify(nil, @user) do |user|
|
||||
update_user(user)
|
||||
update_user(user, settings)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -419,54 +392,60 @@ class UserController < ApplicationController
|
|||
(@this_user.visible? or (@user and @user.administrator?))
|
||||
@title = @this_user.display_name
|
||||
else
|
||||
@title = t 'user.no_such_user.title'
|
||||
@not_found_user = params[:display_name]
|
||||
render :action => 'no_such_user', :status => :not_found
|
||||
render_unknown_user params[:display_name]
|
||||
end
|
||||
end
|
||||
|
||||
def make_friend
|
||||
if params[:display_name]
|
||||
name = params[:display_name]
|
||||
new_friend = User.active.where(:display_name => name).first
|
||||
friend = Friend.new
|
||||
friend.user_id = @user.id
|
||||
friend.friend_user_id = new_friend.id
|
||||
unless @user.is_friends_with?(new_friend)
|
||||
if friend.save
|
||||
flash[:notice] = t 'user.make_friend.success', :name => name
|
||||
Notifier.friend_notification(friend).deliver
|
||||
else
|
||||
friend.add_error(t('user.make_friend.failed', :name => name))
|
||||
end
|
||||
else
|
||||
flash[:warning] = t 'user.make_friend.already_a_friend', :name => name
|
||||
end
|
||||
@new_friend = User.find_by_display_name(params[:display_name])
|
||||
|
||||
if params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'user', :action => 'view'
|
||||
if @new_friend
|
||||
if request.post?
|
||||
friend = Friend.new
|
||||
friend.user_id = @user.id
|
||||
friend.friend_user_id = @new_friend.id
|
||||
unless @user.is_friends_with?(@new_friend)
|
||||
if friend.save
|
||||
flash[:notice] = t 'user.make_friend.success', :name => @new_friend.display_name
|
||||
Notifier.friend_notification(friend).deliver
|
||||
else
|
||||
friend.add_error(t('user.make_friend.failed', :name => @new_friend.display_name))
|
||||
end
|
||||
else
|
||||
flash[:warning] = t 'user.make_friend.already_a_friend', :name => @new_friend.display_name
|
||||
end
|
||||
|
||||
if params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'user', :action => 'view'
|
||||
end
|
||||
end
|
||||
else
|
||||
render_unknown_user params[:display_name]
|
||||
end
|
||||
end
|
||||
|
||||
def remove_friend
|
||||
if params[:display_name]
|
||||
name = params[:display_name]
|
||||
friend = User.active.where(:display_name => name).first
|
||||
if @user.is_friends_with?(friend)
|
||||
Friend.delete_all "user_id = #{@user.id} AND friend_user_id = #{friend.id}"
|
||||
flash[:notice] = t 'user.remove_friend.success', :name => friend.display_name
|
||||
else
|
||||
flash[:error] = t 'user.remove_friend.not_a_friend', :name => friend.display_name
|
||||
end
|
||||
@friend = User.find_by_display_name(params[:display_name])
|
||||
|
||||
if params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'user', :action => 'view'
|
||||
if @friend
|
||||
if request.post?
|
||||
if @user.is_friends_with?(@friend)
|
||||
Friend.delete_all "user_id = #{@user.id} AND friend_user_id = #{@friend.id}"
|
||||
flash[:notice] = t 'user.remove_friend.success', :name => @friend.display_name
|
||||
else
|
||||
flash[:error] = t 'user.remove_friend.not_a_friend', :name => @friend.display_name
|
||||
end
|
||||
|
||||
if params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'user', :action => 'view'
|
||||
end
|
||||
end
|
||||
else
|
||||
render_unknown_user params[:display_name]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -546,7 +525,7 @@ private
|
|||
if user = User.find_by_openid_url(identity_url)
|
||||
case user.status
|
||||
when "pending" then
|
||||
failed_login t('user.login.account not active')
|
||||
failed_login t('user.login.account not active', :reconfirm => url_for(:action => 'confirm_resend', :display_name => user.display_name))
|
||||
when "active", "confirmed" then
|
||||
successful_login(user)
|
||||
when "suspended" then
|
||||
|
@ -563,8 +542,8 @@ private
|
|||
# to the create account page with username and email filled
|
||||
# in if they have been given by the OpenID provider through
|
||||
# the simple registration protocol.
|
||||
nickname = sreg["nickname"] || ax["http://axschema.org/namePerson/friendly"]
|
||||
email = sreg["email"] || ax["http://axschema.org/contact/email"]
|
||||
nickname = sreg["nickname"] || ax["http://axschema.org/namePerson/friendly"].first
|
||||
email = sreg["email"] || ax["http://axschema.org/contact/email"].first
|
||||
redirect_to :controller => 'user', :action => 'new', :nickname => nickname, :email => email, :openid => identity_url
|
||||
end
|
||||
elsif result.missing?
|
||||
|
@ -660,7 +639,38 @@ private
|
|||
|
||||
##
|
||||
# update a user's details
|
||||
def update_user(user)
|
||||
def update_user(user, params)
|
||||
user.display_name = params[:user][:display_name]
|
||||
user.new_email = params[:user][:new_email]
|
||||
|
||||
if params[:user][:pass_crypt].length > 0 or params[:user][:pass_crypt_confirmation].length > 0
|
||||
user.pass_crypt = params[:user][:pass_crypt]
|
||||
user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
|
||||
end
|
||||
|
||||
if params[:user][:description] != user.description
|
||||
user.description = params[:user][:description]
|
||||
user.description_format = "markdown"
|
||||
end
|
||||
|
||||
user.languages = params[:user][:languages].split(",")
|
||||
|
||||
case params[:image_action]
|
||||
when "new" then user.image = params[:user][:image]
|
||||
when "delete" then user.image = nil
|
||||
end
|
||||
|
||||
user.home_lat = params[:user][:home_lat]
|
||||
user.home_lon = params[:user][:home_lon]
|
||||
|
||||
if params[:user][:preferred_editor] == "default"
|
||||
user.preferred_editor = nil
|
||||
else
|
||||
user.preferred_editor = params[:user][:preferred_editor]
|
||||
end
|
||||
|
||||
user.openid_url = nil if params[:user][:openid_url].blank?
|
||||
|
||||
if user.save
|
||||
set_locale
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ class UserRolesController < ApplicationController
|
|||
before_filter :require_valid_role
|
||||
before_filter :not_in_role, :only => [:grant]
|
||||
before_filter :in_role, :only => [:revoke]
|
||||
around_filter :setup_nonce
|
||||
|
||||
def grant
|
||||
@this_user.roles.create({
|
||||
|
@ -23,6 +22,9 @@ class UserRolesController < ApplicationController
|
|||
end
|
||||
|
||||
private
|
||||
##
|
||||
# require that the user is an administrator, or fill out a helpful error message
|
||||
# and return them to theuser page.
|
||||
def require_administrator
|
||||
unless @user.administrator?
|
||||
flash[:error] = t'user_role.filter.not_an_administrator'
|
||||
|
@ -30,30 +32,6 @@ class UserRolesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "this_user" instance variable
|
||||
def lookup_this_user
|
||||
@this_user = User.find_by_display_name(params[:display_name])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] unless @this_user
|
||||
end
|
||||
|
||||
##
|
||||
# the random nonce here which isn't predictable, making an CSRF
|
||||
# procedure much, much more difficult. setup the nonce. if the given
|
||||
# nonce matches the session nonce then yield into the actual method.
|
||||
# otherwise, just sets up the nonce for the form.
|
||||
def setup_nonce
|
||||
if params[:nonce] and params[:nonce] == session[:nonce]
|
||||
@nonce = params[:nonce]
|
||||
yield
|
||||
else
|
||||
@nonce = OAuth::Helper.generate_nonce
|
||||
session[:nonce] = @nonce
|
||||
render
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# require that the given role is valid. the role is a URL
|
||||
# parameter, so should always be present.
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
module AmfHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module ApiHelper
|
||||
end
|
|
@ -1,14 +1,6 @@
|
|||
module ApplicationHelper
|
||||
require 'rexml/document'
|
||||
|
||||
def sanitize(text)
|
||||
Sanitize.clean(text, Sanitize::Config::OSM).html_safe
|
||||
end
|
||||
|
||||
def htmlize(text)
|
||||
return linkify(sanitize(simple_format(text)))
|
||||
end
|
||||
|
||||
def linkify(text)
|
||||
if text.html_safe?
|
||||
Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow")).html_safe
|
||||
|
@ -83,38 +75,6 @@ module ApplicationHelper
|
|||
content_tag(tag, capture(&block), :class => "hide_unless_administrator")
|
||||
end
|
||||
|
||||
def describe_location(lat, lon, zoom = nil, language = nil)
|
||||
zoom = zoom || 14
|
||||
language = language || request.user_preferred_languages.join(',')
|
||||
url = "http://nominatim.openstreetmap.org/reverse?lat=#{lat}&lon=#{lon}&zoom=#{zoom}&accept-language=#{language}"
|
||||
|
||||
begin
|
||||
response = OSM::Timer.timeout(4) do
|
||||
REXML::Document.new(Net::HTTP.get(URI.parse(url)))
|
||||
end
|
||||
rescue Exception
|
||||
response = nil
|
||||
end
|
||||
|
||||
if response and result = response.get_text("reversegeocode/result")
|
||||
result.to_s
|
||||
else
|
||||
"#{number_with_precision(lat, :precision => 3)}, #{number_with_precision(lon, :precision => 3)}"
|
||||
end
|
||||
end
|
||||
|
||||
def user_image(user, options = {})
|
||||
options[:class] ||= "user_image"
|
||||
|
||||
image_tag user.image.url(:large), options
|
||||
end
|
||||
|
||||
def user_thumbnail(user, options = {})
|
||||
options[:class] ||= "user_thumbnail"
|
||||
|
||||
image_tag user.image.url(:small), options
|
||||
end
|
||||
|
||||
def preferred_editor
|
||||
if params[:editor]
|
||||
params[:editor]
|
||||
|
@ -125,6 +85,28 @@ module ApplicationHelper
|
|||
end
|
||||
end
|
||||
|
||||
def scale_to_zoom(scale)
|
||||
Math.log(360.0 / (scale.to_f * 512.0)) / Math.log(2.0)
|
||||
end
|
||||
|
||||
def richtext_area(object_name, method, options = {})
|
||||
id = "#{object_name.to_s}_#{method.to_s}"
|
||||
format = options.delete(:format) || "markdown"
|
||||
|
||||
content_tag(:div, :id => "#{id}_container", :class => "richtext_container") do
|
||||
output_buffer << content_tag(:div, :id => "#{id}_content", :class => "richtext_content") do
|
||||
output_buffer << text_area(object_name, method, options.merge("data-preview-url" => preview_url(:format => format)))
|
||||
output_buffer << content_tag(:div, "", :id => "#{id}_preview", :class => "richtext_preview")
|
||||
end
|
||||
|
||||
output_buffer << content_tag(:div, :id => "#{id}_help", :class => "richtext_help") do
|
||||
output_buffer << render("site/#{format}_help")
|
||||
output_buffer << submit_tag(I18n.t("site.richtext_area.edit"), :id => "#{id}_doedit", :class => "richtext_doedit", :disabled => true)
|
||||
output_buffer << submit_tag(I18n.t("site.richtext_area.preview"), :id => "#{id}_dopreview", :class => "richtext_dopreview")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def friendly_date(date)
|
||||
content_tag(:span, time_ago_in_words(date), :title => l(date, :format => :friendly))
|
||||
end
|
||||
|
|
|
@ -13,20 +13,34 @@ module BrowseHelper
|
|||
if version
|
||||
name = t 'printable_name.with_version', :id => name, :version => object.version.to_s
|
||||
end
|
||||
if object.tags.include? "name:#{I18n.locale}"
|
||||
name = t 'printable_name.with_name', :name => object.tags["name:#{I18n.locale}"].to_s, :id => name
|
||||
elsif object.tags.include? 'name'
|
||||
name = t 'printable_name.with_name', :name => object.tags['name'].to_s, :id => name
|
||||
|
||||
# don't look at object tags if redacted, so as to avoid giving
|
||||
# away redacted version tag information.
|
||||
unless object.redacted?
|
||||
if object.tags.include? "name:#{I18n.locale}"
|
||||
name = t 'printable_name.with_name', :name => object.tags["name:#{I18n.locale}"].to_s, :id => name
|
||||
elsif object.tags.include? 'name'
|
||||
name = t 'printable_name.with_name', :name => object.tags['name'].to_s, :id => name
|
||||
end
|
||||
end
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
def link_class(type, object)
|
||||
return type + " " + h(icon_tags(object).join(' ')) + (object.visible == false ? ' deleted' : '')
|
||||
if object.redacted?
|
||||
type + " deleted"
|
||||
else
|
||||
type + " " + h(icon_tags(object).join(' ')) + (object.visible == false ? ' deleted' : '')
|
||||
end
|
||||
end
|
||||
|
||||
def link_title(object)
|
||||
return h(icon_tags(object).map { |k,v| k + '=' + v }.to_sentence)
|
||||
if object.redacted?
|
||||
""
|
||||
else
|
||||
h(icon_tags(object).map { |k,v| k + '=' + v }.to_sentence)
|
||||
end
|
||||
end
|
||||
|
||||
def format_key(key)
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
module DiaryEntryHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module ExportHelper
|
||||
end
|
|
@ -1,25 +1,43 @@
|
|||
module GeocoderHelper
|
||||
def result_to_html(result)
|
||||
html_options = {}
|
||||
#html_options[:title] = strip_tags(result[:description]) if result[:description]
|
||||
html_options = { :class => "set_position", :data => {} }
|
||||
|
||||
if result[:min_lon] and result[:min_lat] and result[:max_lon] and result[:max_lat]
|
||||
html_options[:href] = raw("?minlon=#{result[:min_lon]}&minlat=#{result[:min_lat]}&maxlon=#{result[:max_lon]}&maxlat=#{result[:max_lat]}")
|
||||
url = "?minlon=#{result[:min_lon]}&minlat=#{result[:min_lat]}&maxlon=#{result[:max_lon]}&maxlat=#{result[:max_lat]}"
|
||||
else
|
||||
html_options[:href] = raw("?mlat=#{result[:lat]}&mlon=#{result[:lon]}&zoom=#{result[:zoom]}")
|
||||
url = "?mlat=#{result[:lat]}&mlon=#{result[:lon]}&zoom=#{result[:zoom]}"
|
||||
end
|
||||
|
||||
result.each do |key,value|
|
||||
html_options[:data][key.to_s.tr('_', '-')] = value
|
||||
end
|
||||
|
||||
html = ""
|
||||
html << result[:prefix] if result[:prefix]
|
||||
html << " " if result[:prefix] and result[:name]
|
||||
|
||||
if result[:min_lon] and result[:min_lat] and result[:max_lon] and result[:max_lat]
|
||||
html << link_to_function(result[:name],"setPosition(#{result[:lat]}, #{result[:lon]}, null, #{result[:min_lon]}, #{result[:min_lat]}, #{result[:max_lon]}, #{result[:max_lat]})", html_options) if result[:name]
|
||||
else
|
||||
html << link_to_function(result[:name],"setPosition(#{result[:lat]}, #{result[:lon]}, #{result[:zoom]})", html_options) if result[:name]
|
||||
end
|
||||
|
||||
html << link_to(result[:name], url, html_options) if result[:name]
|
||||
html << result[:suffix] if result[:suffix]
|
||||
|
||||
return raw(html)
|
||||
end
|
||||
|
||||
def describe_location(lat, lon, zoom = nil, language = nil)
|
||||
zoom = zoom || 14
|
||||
language = language || request.user_preferred_languages.join(',')
|
||||
url = "http://nominatim.openstreetmap.org/reverse?lat=#{lat}&lon=#{lon}&zoom=#{zoom}&accept-language=#{language}"
|
||||
|
||||
begin
|
||||
response = OSM::Timer.timeout(4) do
|
||||
REXML::Document.new(Net::HTTP.get(URI.parse(url)))
|
||||
end
|
||||
rescue Exception
|
||||
response = nil
|
||||
end
|
||||
|
||||
if response and result = response.get_text("reversegeocode/result")
|
||||
result.to_s
|
||||
else
|
||||
"#{number_with_precision(lat, :precision => 3)}, #{number_with_precision(lon, :precision => 3)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
module NodeHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module OauthClientsHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module OauthHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module OldNodeHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module OldWayHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module OldWayNodeHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module OldWayTagHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module SiteHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module SwfHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module TracePointsHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module TracepointHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module TracetagHelper
|
||||
end
|
|
@ -1,12 +1,25 @@
|
|||
module UserHelper
|
||||
def user_image(user, options = {})
|
||||
options[:class] ||= "user_image"
|
||||
|
||||
image_tag user.image.url(:large), options
|
||||
end
|
||||
|
||||
def user_thumbnail(user, options = {})
|
||||
options[:class] ||= "user_thumbnail"
|
||||
|
||||
image_tag user.image.url(:small), options
|
||||
end
|
||||
|
||||
def openid_logo
|
||||
image_tag "openid_small.png", :alt => t('user.login.openid_logo_alt'), :class => "openid_logo"
|
||||
end
|
||||
|
||||
def openid_button(name, url)
|
||||
link_to_function(
|
||||
link_to(
|
||||
image_tag("#{name}.png", :alt => t("user.login.openid_providers.#{name}.alt")),
|
||||
"submitOpenidUrl('#{url}')",
|
||||
"#",
|
||||
:class => "openid_button", :data => { :url => url },
|
||||
:title => t("user.login.openid_providers.#{name}.title")
|
||||
)
|
||||
end
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
module UserPreferenceHelper
|
||||
end
|
37
app/helpers/user_roles_helper.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
module UserRolesHelper
|
||||
def role_icons(user)
|
||||
UserRole::ALL_ROLES.reduce("".html_safe) { |s,r| s + " " + role_icon(user, r) }
|
||||
end
|
||||
|
||||
def role_icon(user, role)
|
||||
if @user and @user.administrator?
|
||||
if user.has_role?(role)
|
||||
image = "roles/#{role}.png"
|
||||
alt = t("user.view.role.revoke.#{role}")
|
||||
title = t("user.view.role.revoke.#{role}")
|
||||
url = revoke_role_path(:display_name => user.display_name, :role => role)
|
||||
confirm = t("user_role.revoke.are_you_sure", :name => user.display_name, :role => role)
|
||||
else
|
||||
image = "roles/blank_#{role}.png"
|
||||
alt = t("user.view.role.grant.#{role}")
|
||||
title = t("user.view.role.grant.#{role}")
|
||||
url = grant_role_path(:display_name => user.display_name, :role => role)
|
||||
confirm = t("user_role.grant.are_you_sure", :name => user.display_name, :role => role)
|
||||
end
|
||||
elsif user.has_role?(role)
|
||||
image = "roles/#{role}.png"
|
||||
alt = t("user.view.role.#{role}")
|
||||
title = t("user.view.role.#{role}")
|
||||
end
|
||||
|
||||
if image
|
||||
icon = image_tag(image, :size => "20x20", :border => 0, :alt => alt, :title => title)
|
||||
|
||||
if url
|
||||
icon = link_to(icon, url, :method => :post, :confirm => confirm)
|
||||
end
|
||||
end
|
||||
|
||||
icon
|
||||
end
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module WayHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module WayNodeHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module WayTagHelper
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
class Changeset < ActiveRecord::Base
|
||||
require 'xml/libxml'
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :user, :counter_cache => true
|
||||
|
||||
has_many :changeset_tags
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ require 'oauth'
|
|||
|
||||
class ClientApplication < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
has_many :tokens, :class_name => "OauthToken"
|
||||
has_many :tokens, :class_name => "OauthToken", :dependent => :delete_all
|
||||
has_many :access_tokens
|
||||
has_many :oauth2_verifiers
|
||||
has_many :oauth_tokens
|
||||
|
|
|
@ -7,6 +7,12 @@ class DiaryComment < ActiveRecord::Base
|
|||
|
||||
attr_accessible :body
|
||||
|
||||
after_initialize :set_defaults
|
||||
|
||||
def body
|
||||
RichText.new(read_attribute(:body_format), read_attribute(:body))
|
||||
end
|
||||
|
||||
def digest
|
||||
md5 = Digest::MD5.new
|
||||
md5 << diary_entry_id.to_s
|
||||
|
@ -15,4 +21,10 @@ class DiaryComment < ActiveRecord::Base
|
|||
md5 << body
|
||||
md5.hexdigest
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
self.body_format = "markdown" unless self.attribute_present?(:body_format)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,4 +25,16 @@ class DiaryEntry < ActiveRecord::Base
|
|||
validates_associated :language
|
||||
|
||||
attr_accessible :title, :body, :language_code, :latitude, :longitude
|
||||
|
||||
after_initialize :set_defaults
|
||||
|
||||
def body
|
||||
RichText.new(read_attribute(:body_format), read_attribute(:body))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
self.body_format = "markdown" unless self.attribute_present?(:body_format)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,35 @@ class Message < ActiveRecord::Base
|
|||
|
||||
attr_accessible :title, :body
|
||||
|
||||
after_initialize :set_defaults
|
||||
|
||||
def self.from_mail(mail, from, to)
|
||||
if mail.multipart?
|
||||
if mail.text_part
|
||||
body = mail.text_part.decoded
|
||||
elsif mail.html_part
|
||||
body = HTMLEntities.new.decode(Sanitize.clean(mail.html_part.decoded))
|
||||
end
|
||||
elsif mail.text? and mail.sub_type == "html"
|
||||
body = HTMLEntities.new.decode(Sanitize.clean(mail.decoded))
|
||||
else
|
||||
body = mail.decoded
|
||||
end
|
||||
|
||||
message = Message.new({
|
||||
:sender => from,
|
||||
:recipient => to,
|
||||
:sent_on => mail.date.new_offset(0),
|
||||
:title => mail.subject.sub(/\[OpenStreetMap\] */, ""),
|
||||
:body => body,
|
||||
:body_format => "text"
|
||||
}, :without_protection => true)
|
||||
end
|
||||
|
||||
def body
|
||||
RichText.new(read_attribute(:body_format), read_attribute(:body))
|
||||
end
|
||||
|
||||
def digest
|
||||
md5 = Digest::MD5.new
|
||||
md5 << from_user_id.to_s
|
||||
|
@ -20,4 +49,10 @@ class Message < ActiveRecord::Base
|
|||
md5 << body
|
||||
md5.hexdigest
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
self.body_format = "markdown" unless self.attribute_present?(:body_format)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ class Node < ActiveRecord::Base
|
|||
|
||||
include GeoRecord
|
||||
include ConsistencyValidations
|
||||
include NotRedactable
|
||||
|
||||
self.table_name = "current_nodes"
|
||||
|
||||
|
@ -200,11 +201,14 @@ class Node < ActiveRecord::Base
|
|||
def to_xml_node(changeset_cache = {}, user_display_name_cache = {})
|
||||
el1 = XML::Node.new 'node'
|
||||
el1['id'] = self.id.to_s
|
||||
el1['lat'] = self.lat.to_s
|
||||
el1['lon'] = self.lon.to_s
|
||||
el1['version'] = self.version.to_s
|
||||
el1['changeset'] = self.changeset_id.to_s
|
||||
|
||||
if self.visible?
|
||||
el1['lat'] = self.lat.to_s
|
||||
el1['lon'] = self.lon.to_s
|
||||
end
|
||||
|
||||
if changeset_cache.key?(self.changeset_id)
|
||||
# use the cache if available
|
||||
else
|
||||
|
|
|
@ -14,7 +14,9 @@ class OauthToken < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def invalidate!
|
||||
update_attribute(:invalidated_at, Time.now)
|
||||
update_attributes({
|
||||
:invalidated_at => Time.now
|
||||
}, :without_protection => true)
|
||||
end
|
||||
|
||||
def authorized?
|
||||
|
|
|
@ -5,6 +5,10 @@ class OldNode < ActiveRecord::Base
|
|||
self.table_name = "nodes"
|
||||
self.primary_keys = "node_id", "version"
|
||||
|
||||
# note this needs to be included after the table name changes, or
|
||||
# the queries generated by Redactable will use the wrong table name.
|
||||
include Redactable
|
||||
|
||||
validates_presence_of :changeset_id, :timestamp
|
||||
validates_inclusion_of :visible, :in => [ true, false ]
|
||||
validates_numericality_of :latitude, :longitude
|
||||
|
@ -12,7 +16,9 @@ class OldNode < ActiveRecord::Base
|
|||
validates_associated :changeset
|
||||
|
||||
belongs_to :changeset
|
||||
|
||||
belongs_to :redaction
|
||||
belongs_to :current_node, :class_name => "Node", :foreign_key => "node_id"
|
||||
|
||||
def validate_position
|
||||
errors.add(:base, "Node is not in the world") unless in_world?
|
||||
end
|
||||
|
@ -39,13 +45,6 @@ class OldNode < ActiveRecord::Base
|
|||
def to_xml_node
|
||||
el1 = XML::Node.new 'node'
|
||||
el1['id'] = self.node_id.to_s
|
||||
el1['lat'] = self.lat.to_s
|
||||
el1['lon'] = self.lon.to_s
|
||||
el1['changeset'] = self.changeset.id.to_s
|
||||
if self.changeset.user.data_public?
|
||||
el1['user'] = self.changeset.user.display_name
|
||||
el1['uid'] = self.changeset.user.id.to_s
|
||||
end
|
||||
|
||||
self.tags.each do |k,v|
|
||||
el2 = XML::Node.new('tag')
|
||||
|
@ -54,9 +53,23 @@ class OldNode < ActiveRecord::Base
|
|||
el1 << el2
|
||||
end
|
||||
|
||||
if self.visible?
|
||||
el1['lat'] = self.lat.to_s
|
||||
el1['lon'] = self.lon.to_s
|
||||
end
|
||||
|
||||
el1['changeset'] = self.changeset.id.to_s
|
||||
if self.changeset.user.data_public?
|
||||
el1['user'] = self.changeset.user.display_name
|
||||
el1['uid'] = self.changeset.user.id.to_s
|
||||
end
|
||||
|
||||
el1['visible'] = self.visible.to_s
|
||||
el1['timestamp'] = self.timestamp.xmlschema
|
||||
el1['version'] = self.version.to_s
|
||||
|
||||
el1['redacted'] = self.redaction.id.to_s if self.redacted?
|
||||
|
||||
return el1
|
||||
end
|
||||
|
||||
|
@ -106,4 +119,10 @@ class OldNode < ActiveRecord::Base
|
|||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
|
||||
# check whether this element is the latest version - that is,
|
||||
# has the same version as its "current" counterpart.
|
||||
def is_latest_version?
|
||||
current_node.version == self.version
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,13 @@ class OldRelation < ActiveRecord::Base
|
|||
self.table_name = "relations"
|
||||
self.primary_keys = "relation_id", "version"
|
||||
|
||||
# note this needs to be included after the table name changes, or
|
||||
# the queries generated by Redactable will use the wrong table name.
|
||||
include Redactable
|
||||
|
||||
belongs_to :changeset
|
||||
belongs_to :redaction
|
||||
belongs_to :current_relation, :class_name => "Relation", :foreign_key => "relation_id"
|
||||
|
||||
has_many :old_members, :class_name => 'OldRelationMember', :foreign_key => [:relation_id, :version], :order => :sequence_id
|
||||
has_many :old_tags, :class_name => 'OldRelationTag', :foreign_key => [:relation_id, :version]
|
||||
|
@ -99,6 +105,8 @@ class OldRelation < ActiveRecord::Base
|
|||
el1['version'] = self.version.to_s
|
||||
el1['changeset'] = self.changeset_id.to_s
|
||||
|
||||
el1['redacted'] = self.redaction.id.to_s if self.redacted?
|
||||
|
||||
self.old_members.each do |member|
|
||||
e = XML::Node.new 'member'
|
||||
e['type'] = member.member_type.to_s.downcase
|
||||
|
@ -106,13 +114,14 @@ class OldRelation < ActiveRecord::Base
|
|||
e['role'] = member.member_role.to_s
|
||||
el1 << e
|
||||
end
|
||||
|
||||
|
||||
self.old_tags.each do |tag|
|
||||
e = XML::Node.new 'tag'
|
||||
e['k'] = tag.k
|
||||
e['v'] = tag.v
|
||||
el1 << e
|
||||
end
|
||||
|
||||
return el1
|
||||
end
|
||||
|
||||
|
@ -130,4 +139,10 @@ class OldRelation < ActiveRecord::Base
|
|||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
|
||||
# check whether this element is the latest version - that is,
|
||||
# has the same version as its "current" counterpart.
|
||||
def is_latest_version?
|
||||
current_relation.version == self.version
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
class OldWay < ActiveRecord::Base
|
||||
include ConsistencyValidations
|
||||
|
||||
|
||||
self.table_name = "ways"
|
||||
self.primary_keys = "way_id", "version"
|
||||
|
||||
# note this needs to be included after the table name changes, or
|
||||
# the queries generated by Redactable will use the wrong table name.
|
||||
include Redactable
|
||||
|
||||
belongs_to :changeset
|
||||
belongs_to :redaction
|
||||
belongs_to :current_way, :class_name => "Way", :foreign_key => "way_id"
|
||||
|
||||
has_many :old_nodes, :class_name => 'OldWayNode', :foreign_key => [:way_id, :version]
|
||||
has_many :old_tags, :class_name => 'OldWayTag', :foreign_key => [:way_id, :version]
|
||||
|
@ -97,19 +103,22 @@ class OldWay < ActiveRecord::Base
|
|||
end
|
||||
el1['version'] = self.version.to_s
|
||||
el1['changeset'] = self.changeset.id.to_s
|
||||
|
||||
el1['redacted'] = self.redaction.id.to_s if self.redacted?
|
||||
|
||||
self.old_nodes.each do |nd| # FIXME need to make sure they come back in the right order
|
||||
e = XML::Node.new 'nd'
|
||||
e['ref'] = nd.node_id.to_s
|
||||
el1 << e
|
||||
end
|
||||
|
||||
|
||||
self.old_tags.each do |tag|
|
||||
e = XML::Node.new 'tag'
|
||||
e['k'] = tag.k
|
||||
e['v'] = tag.v
|
||||
el1 << e
|
||||
end
|
||||
|
||||
return el1
|
||||
end
|
||||
|
||||
|
@ -132,7 +141,7 @@ class OldWay < ActiveRecord::Base
|
|||
def get_nodes_revert(timestamp)
|
||||
points=[]
|
||||
self.nds.each do |n|
|
||||
oldnode = OldNode.where('node_id = ? AND timestamp <= ?', n, timestamp).order("timestamp DESC").first
|
||||
oldnode = OldNode.where('node_id = ? AND timestamp <= ?', n, timestamp).unredacted.order("timestamp DESC").first
|
||||
curnode = Node.find(n)
|
||||
id = n; reuse = curnode.visible
|
||||
if oldnode.lat != curnode.lat or oldnode.lon != curnode.lon or oldnode.tags != curnode.tags then
|
||||
|
@ -158,4 +167,10 @@ class OldWay < ActiveRecord::Base
|
|||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
|
||||
# check whether this element is the latest version - that is,
|
||||
# has the same version as its "current" counterpart.
|
||||
def is_latest_version?
|
||||
current_way.version == self.version
|
||||
end
|
||||
end
|
||||
|
|
32
app/models/redaction.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
##
|
||||
# Redaction represents a record associated with a particular
|
||||
# action on the database to hide revisions from the history
|
||||
# which are not appropriate to redistribute any more.
|
||||
#
|
||||
# The circumstances of the redaction can be recorded in the
|
||||
# record's title and description fields, which can be
|
||||
# displayed linked from the redacted records.
|
||||
#
|
||||
class Redaction < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
|
||||
has_many :old_nodes
|
||||
has_many :old_ways
|
||||
has_many :old_relations
|
||||
|
||||
after_initialize :set_defaults
|
||||
|
||||
# this method overrides the AR default to provide the rich
|
||||
# text object for the description field.
|
||||
def description
|
||||
RichText.new(read_attribute(:description_format), read_attribute(:description))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# set the default format to be markdown, in the absence of
|
||||
# any other setting.
|
||||
def set_defaults
|
||||
self.description_format = "markdown" unless self.attribute_present?(:description_format)
|
||||
end
|
||||
end
|
|
@ -2,7 +2,8 @@ class Relation < ActiveRecord::Base
|
|||
require 'xml/libxml'
|
||||
|
||||
include ConsistencyValidations
|
||||
|
||||
include NotRedactable
|
||||
|
||||
self.table_name = "current_relations"
|
||||
|
||||
belongs_to :changeset
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Trace < ActiveRecord::Base
|
||||
self.table_name = "gpx_files"
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :user, :counter_cache => true
|
||||
has_many :tags, :class_name => 'Tracetag', :foreign_key => 'gpx_id', :dependent => :delete_all
|
||||
has_many :points, :class_name => 'Tracepoint', :foreign_key => 'gpx_id', :dependent => :delete_all
|
||||
|
||||
|
|
|
@ -18,7 +18,10 @@ class User < ActiveRecord::Base
|
|||
has_many :client_applications
|
||||
has_many :oauth_tokens, :class_name => "OauthToken", :order => "authorized_at desc", :include => [:client_application]
|
||||
|
||||
has_many :active_blocks, :class_name => "UserBlock", :conditions => proc { [ "user_blocks.ends_at > :ends_at or user_blocks.needs_view", { :ends_at => Time.now.getutc } ] }
|
||||
has_many :blocks, :class_name => "UserBlock"
|
||||
has_many :blocks_created, :class_name => "UserBlock", :foreign_key => :creator_id
|
||||
has_many :blocks_revoked, :class_name => "UserBlock", :foreign_key => :revoker_id
|
||||
|
||||
has_many :roles, :class_name => "UserRole"
|
||||
|
||||
scope :visible, where(:status => ["pending", "active", "confirmed"])
|
||||
|
@ -35,7 +38,7 @@ class User < ActiveRecord::Base
|
|||
validates_length_of :display_name, :within => 3..255, :allow_nil => true
|
||||
validates_email_format_of :email, :if => Proc.new { |u| u.email_changed? }
|
||||
validates_email_format_of :new_email, :allow_blank => true, :if => Proc.new { |u| u.new_email_changed? }
|
||||
validates_format_of :display_name, :with => /^[^\/;.,?]*$/, :if => Proc.new { |u| u.display_name_changed? }
|
||||
validates_format_of :display_name, :with => /^[^\/;.,?%#]*$/, :if => Proc.new { |u| u.display_name_changed? }
|
||||
validates_format_of :display_name, :with => /^\S/, :message => "has leading whitespace", :if => Proc.new { |u| u.display_name_changed? }
|
||||
validates_format_of :display_name, :with => /\S$/, :message => "has trailing whitespace", :if => Proc.new { |u| u.display_name_changed? }
|
||||
validates_numericality_of :home_lat, :allow_nil => true
|
||||
|
@ -46,7 +49,7 @@ class User < ActiveRecord::Base
|
|||
attr_accessible :display_name, :email, :email_confirmation, :openid_url,
|
||||
:pass_crypt, :pass_crypt_confirmation, :consider_pd
|
||||
|
||||
after_initialize :set_creation_time
|
||||
after_initialize :set_defaults
|
||||
before_save :encrypt_password
|
||||
|
||||
has_attached_file :image,
|
||||
|
@ -78,7 +81,7 @@ class User < ActiveRecord::Base
|
|||
user = nil
|
||||
end
|
||||
|
||||
token.update_attribute(:expiry, 1.week.from_now) if token and user
|
||||
token.update_column(:expiry, 1.week.from_now) if token and user
|
||||
|
||||
return user
|
||||
end
|
||||
|
@ -103,6 +106,10 @@ class User < ActiveRecord::Base
|
|||
return el1
|
||||
end
|
||||
|
||||
def description
|
||||
RichText.new(read_attribute(:description_format), read_attribute(:description))
|
||||
end
|
||||
|
||||
def languages
|
||||
attribute_present?(:languages) ? read_attribute(:languages).split(/ *, */) : []
|
||||
end
|
||||
|
@ -180,7 +187,7 @@ class User < ActiveRecord::Base
|
|||
# returns the first active block which would require users to view
|
||||
# a message, or nil if there are none.
|
||||
def blocked_on_view
|
||||
active_blocks.detect { |b| b.needs_view? }
|
||||
blocks.active.detect { |b| b.needs_view? }
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -202,10 +209,10 @@ class User < ActiveRecord::Base
|
|||
def spam_score
|
||||
changeset_score = self.changesets.limit(10).length * 50
|
||||
trace_score = self.traces.limit(10).length * 50
|
||||
diary_entry_score = self.diary_entries.inject(0) { |s,e| s += OSM.spam_score(e.body) }
|
||||
diary_comment_score = self.diary_comments.inject(0) { |s,e| s += OSM.spam_score(e.body) }
|
||||
diary_entry_score = self.diary_entries.inject(0) { |s,e| s += e.body.spam_score }
|
||||
diary_comment_score = self.diary_comments.inject(0) { |s,c| s += c.body.spam_score }
|
||||
|
||||
score = OSM.spam_score(self.description)
|
||||
score = self.description.spam_score / 4.0
|
||||
score += diary_entry_score / self.diary_entries.length if self.diary_entries.length > 0
|
||||
score += diary_comment_score / self.diary_comments.length if self.diary_comments.length > 0
|
||||
score -= changeset_score
|
||||
|
@ -222,14 +229,16 @@ class User < ActiveRecord::Base
|
|||
|
||||
private
|
||||
|
||||
def set_creation_time
|
||||
def set_defaults
|
||||
self.creation_time = Time.now.getutc unless self.attribute_present?(:creation_time)
|
||||
self.description_format = "markdown" unless self.attribute_present?(:description_format)
|
||||
end
|
||||
|
||||
def encrypt_password
|
||||
if pass_crypt_confirmation
|
||||
self.pass_salt = OSM::make_token(8)
|
||||
self.pass_crypt = OSM::encrypt_password(pass_crypt, pass_salt)
|
||||
self.pass_crypt_confirmation = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,8 +5,22 @@ class UserBlock < ActiveRecord::Base
|
|||
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
|
||||
belongs_to :revoker, :class_name => "User", :foreign_key => :revoker_id
|
||||
|
||||
after_initialize :set_defaults
|
||||
|
||||
PERIODS = USER_BLOCK_PERIODS
|
||||
|
||||
##
|
||||
# scope to match active blocks
|
||||
def self.active
|
||||
self.where("needs_view or ends_at > ?", Time.now.getutc)
|
||||
end
|
||||
|
||||
##
|
||||
# return a renderable version of the reason text.
|
||||
def reason
|
||||
RichText.new(read_attribute(:reason_format), read_attribute(:reason))
|
||||
end
|
||||
|
||||
##
|
||||
# returns true if the block is currently active (i.e: the user can't
|
||||
# use the API).
|
||||
|
@ -25,7 +39,14 @@ class UserBlock < ActiveRecord::Base
|
|||
}, :without_protection => true)
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
##
|
||||
# set default values for new records.
|
||||
def set_defaults
|
||||
self.reason_format = "markdown" unless self.attribute_present?(:reason_format)
|
||||
end
|
||||
|
||||
##
|
||||
# validate that only moderators are allowed to change the
|
||||
# block. this should be caught and dealt with in the controller,
|
||||
|
|
|
@ -2,6 +2,7 @@ class Way < ActiveRecord::Base
|
|||
require 'xml/libxml'
|
||||
|
||||
include ConsistencyValidations
|
||||
include NotRedactable
|
||||
|
||||
self.table_name = "current_ways"
|
||||
|
||||
|
|
9
app/views/api/permissions.builder
Normal file
|
@ -0,0 +1,9 @@
|
|||
# create list of permissions
|
||||
xml.instruct! :xml, :version=>"1.0"
|
||||
xml.osm("version" => "#{API_VERSION}", "generator" => "OpenStreetMap Server") do
|
||||
xml.permissions do
|
||||
@permissions.each do |permission|
|
||||
xml.permission :name => permission
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,12 +15,12 @@
|
|||
<%= link_to(t("browse.map.larger.area"), { :controller => :site, :action => :index, :box => "yes" }, { :id => "area_larger_map", :class => "geolink bbox" }) %>
|
||||
<% end -%>
|
||||
<br />
|
||||
<%= link_to(t("browse.map.edit.area"), { :controller => :site, :action => :edit }, { :id => "area_edit", :class => "geolink bbox" }) %>
|
||||
<%= link_to(h(t("browse.map.edit.area")) + content_tag(:span, "▾", :class => "menuicon"), { :controller => :site, :action => :edit }, { :id => "area_edit", :class => "geolink bbox" }) %>
|
||||
<% unless map.instance_of? Changeset or map.instance_of? Note %>
|
||||
<br />
|
||||
<%= link_to("", { :controller => :site, :action => :index }, { :id => "object_larger_map", :class => "geolink object" }) %>
|
||||
<%= link_to(t("browse.map.larger." + map.class.to_s.downcase), { :controller => :site, :action => :index }, { :id => "object_larger_map", :class => "geolink object" }) %>
|
||||
<br />
|
||||
<%= link_to("", { :controller => :site, :action => :edit }, { :id => "object_edit", :class => "geolink object" }) %>
|
||||
<%= link_to(h(t("browse.map.edit." + map.class.to_s.downcase)) + content_tag(:span, "▾", :class => "menuicon"), { :controller => :site, :action => :edit }, { :id => "object_edit", :class => "geolink object" }) %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= t 'browse.map.deleted' %>
|
||||
|
@ -83,7 +83,7 @@
|
|||
var bbox = new OpenLayers.Bounds(minlon, minlat, maxlon, maxlat);
|
||||
var centre = bbox.getCenterLonLat();
|
||||
|
||||
setMapExtent(bbox);
|
||||
map.zoomToExtent(proj(bbox));
|
||||
addBoxToMap(bbox);
|
||||
|
||||
$("#loading").hide();
|
||||
|
@ -136,6 +136,9 @@
|
|||
url += "/" + previous_version;
|
||||
}
|
||||
|
||||
$("#object_larger_map").hide();
|
||||
$("#object_edit").hide();
|
||||
|
||||
addObjectToMap(url, true, function(extent) {
|
||||
$("#loading").hide();
|
||||
$("#browse_map .geolink").show();
|
||||
|
@ -155,7 +158,6 @@
|
|||
});
|
||||
<% end -%>
|
||||
|
||||
<% unless map.instance_of? Changeset -%>
|
||||
$("#remote_object_edit").click(function (event) {
|
||||
return remoteEditHandler(event, extent, "<%= map.class.to_s.downcase + map.id.to_s %>");
|
||||
});
|
||||
|
@ -166,9 +168,8 @@
|
|||
});
|
||||
<% end -%>
|
||||
|
||||
$("#object_larger_map").html("<%=j t('browse.map.larger.' + map.class.to_s.downcase) %>");
|
||||
$("#object_edit").html("<%=j t('browse.map.edit.' + map.class.to_s.downcase) %>");
|
||||
<% end -%>
|
||||
$("#object_larger_map").show();
|
||||
$("#object_edit").show();
|
||||
|
||||
updatelinks(centre.lon, centre.lat, 16, null, extent.left, extent.bottom, extent.right, extent.top, "<%= map.class.to_s.downcase %>", <%= map.id %>);
|
||||
} else {
|
||||
|
@ -177,8 +178,8 @@
|
|||
});
|
||||
<% end -%>
|
||||
|
||||
createMenu("area_edit", "area_edit_menu", 1000, "right");
|
||||
createMenu("object_edit", "object_edit_menu", 1000, "right");
|
||||
createMenu("area_edit", "area_edit_menu", "right");
|
||||
createMenu("object_edit", "object_edit_menu", "right");
|
||||
}
|
||||
|
||||
window.onload = init;
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
<% if node_details.redacted? %>
|
||||
<p><%= t 'browse.redacted.message_html', :type => t('browse.redacted.type.node'), :redaction_link => link_to(t('browse.redacted.redaction', :id => node_details.redaction.id), node_details.redaction), :version => node_details.version %></p>
|
||||
<% else %>
|
||||
<table class="browse_details" id="<%= node_details.version %>">
|
||||
|
||||
<%= render :partial => "common_details", :object => node_details %>
|
||||
|
||||
<% if node_details.visible -%>
|
||||
<tr>
|
||||
<th><%= t 'browse.node_details.coordinates' %></th>
|
||||
<td><div class="geo"><%= link_to(content_tag(:span, number_with_delimiter(node_details.lat), :class => "latitude") + ", " + content_tag(:span, number_with_delimiter(node_details.lon), :class => "longitude"), {:controller => 'site', :action => 'index', :lat => h(node_details.lat), :lon => h(node_details.lon), :zoom => "18"}) %></div></td>
|
||||
</tr>
|
||||
<% end -%>
|
||||
|
||||
<% unless node_details.ways.empty? and node_details.containing_relation_members.empty? %>
|
||||
<tr valign="top">
|
||||
|
@ -22,3 +27,4 @@
|
|||
<% end %>
|
||||
|
||||
</table>
|
||||
<% end %>
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<% if relation_details.redacted? %>
|
||||
<p><%= t 'browse.redacted.message_html', :type => t('browse.redacted.type.relation'), :redaction_link => link_to(t('browse.redacted.redaction', :id => relation_details.redaction.id), relation_details.redaction), :version => relation_details.version %></p>
|
||||
<% else %>
|
||||
<table class="browse_details" id="<%= relation_details.version %>">
|
||||
|
||||
<%= render :partial => "common_details", :object => relation_details %>
|
||||
|
@ -25,3 +28,4 @@
|
|||
<% end %>
|
||||
|
||||
</table>
|
||||
<% end %>
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<% if way_details.redacted? %>
|
||||
<p><%= t 'browse.redacted.message_html', :type => t('browse.redacted.type.way'), :redaction_link => link_to(t('browse.redacted.redaction', :id => way_details.redaction.id), way_details.redaction), :version => way_details.version %></p>
|
||||
<% else %>
|
||||
<table class="browse_details" id="<%= way_details.version %>">
|
||||
|
||||
<%= render :partial => "common_details", :object => way_details %>
|
||||
|
@ -33,3 +36,4 @@
|
|||
<% end %>
|
||||
|
||||
</table>
|
||||
<% end %>
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
<% end %>
|
||||
<%= render :partial => "changeset_details", :object => @changeset %>
|
||||
<hr />
|
||||
<%= raw t 'browse.changeset.download', :changeset_xml_link => link_to(t('browse.changeset.changesetxml'), :controller => "changeset", :action => "read"),
|
||||
:osmchange_xml_link => link_to(t('browse.changeset.osmchangexml'), :controller => "changeset", :action => "download") %>
|
||||
<%= link_to(t('browse.changeset.changesetxml'), :controller => "changeset", :action => "read") %>
|
||||
| <%= link_to(t('browse.changeset.osmchangexml'), :controller => "changeset", :action => "download") %>
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
<% end %>
|
||||
<%= render :partial => "navigation" %>
|
||||
<h2><%= t'browse.node.node_title', :node_name => @name %></h2>
|
||||
<% if @node.visible -%>
|
||||
<%= render :partial => "map", :object => @node %>
|
||||
<% end -%>
|
||||
<%= render :partial => "node_details", :object => @node %>
|
||||
<hr />
|
||||
<%= raw t'browse.node.download', :download_xml_link => link_to(t('browse.node.download_xml'), :controller => "old_node", :action => "version", :version => @node.version),
|
||||
:view_history_link => link_to(t('browse.node.view_history'), :action => "node_history"),
|
||||
:edit_link => link_to(t('browse.node.edit'), :controller => "site", :action => "edit", :lat => @node.lat, :lon => @node.lon, :zoom => 18, :node => @node.id)
|
||||
%>
|
||||
<%= link_to(t('browse.node.download_xml'), :controller => "node", :action => "read") %>
|
||||
| <%= link_to(t('browse.node.view_history'), :action => "node_history") %>
|
||||
<% if @node.visible -%>
|
||||
| <%= link_to(t('browse.node.edit'), :controller => "site", :action => "edit", :lat => @node.lat, :lon => @node.lon, :zoom => 18, :node => @node.id) %>
|
||||
<% end -%>
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
@title = t('browse.node_history.node_history') + ' | ' + @name
|
||||
%>
|
||||
<h2><%= raw t'browse.node_history.node_history_title', :node_name => link_to(h(@name), :action => "node", :id => @node.id) %></h2>
|
||||
<% if @node.visible -%>
|
||||
<%= render :partial => "map", :object => @node %>
|
||||
<% end -%>
|
||||
<% @node.old_nodes.reverse.each do |node| %>
|
||||
<%= render :partial => "node_details", :object => node %>
|
||||
<hr />
|
||||
<% end %>
|
||||
<%= raw t 'browse.node_history.download', :download_xml_link => link_to(t('browse.node_history.download_xml'), :controller => "old_node", :action => "history"),
|
||||
:view_details_link => link_to(t('browse.node_history.view_details'), :action => "node") %>
|
||||
<%= link_to(t('browse.node_history.download_xml'), :controller => "old_node", :action => "history") %>
|
||||
| <%= link_to(t('browse.node_history.view_details'), :action => "node") %>
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
<%= render :partial => "map", :object => @relation %>
|
||||
<%= render :partial => "relation_details", :object => @relation %>
|
||||
<hr />
|
||||
<%= raw t'browse.relation.download', :download_xml_link => link_to(t('browse.relation.download_xml'), :controller => "relation", :action => "read"),
|
||||
:view_history_link => link_to(t('browse.relation.view_history'), :action => "relation_history") %>
|
||||
<%= link_to(t('browse.relation.download_xml'), :controller => "relation", :action => "read") %>
|
||||
| <%= link_to(t('browse.relation.view_history'), :action => "relation_history") %>
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
<%= render :partial => "relation_details", :object => relation %>
|
||||
<hr />
|
||||
<% end %>
|
||||
<%= raw t'browse.relation_history.download', :download_xml_link => link_to(t('browse.relation_history.download_xml'), :controller => "old_relation", :action => "history"),
|
||||
:view_details_link => link_to(t('browse.relation_history.view_details'), :action => "relation") %>
|
||||
<%= link_to(t('browse.relation_history.download_xml'), :controller => "old_relation", :action => "history") %>
|
||||
| <%= link_to(t('browse.relation_history.view_details'), :action => "relation") %>
|
||||
|
|
|
@ -32,9 +32,11 @@ function startBrowse() {
|
|||
browseBoxControl.handler.callbacks.done = endDrag;
|
||||
map.addControl(browseBoxControl);
|
||||
|
||||
map.events.register("moveend", map, showData);
|
||||
map.events.register("moveend", map, updateData);
|
||||
map.events.triggerEvent("moveend");
|
||||
|
||||
$("#browse_select_view").click(useMap);
|
||||
|
||||
$("#browse_select_box").click(startDrag);
|
||||
|
||||
$("#browse_hide_areas_box").html("<%=j t 'browse.start_rjs.hide_areas' %>");
|
||||
|
@ -42,7 +44,7 @@ function startBrowse() {
|
|||
$("#browse_hide_areas_box").click(hideAreas);
|
||||
}
|
||||
|
||||
function showData() {
|
||||
function updateData() {
|
||||
if (browseMode == "auto") {
|
||||
if (map.getZoom() >= 15) {
|
||||
useMap(false);
|
||||
|
@ -77,7 +79,7 @@ function stopBrowse() {
|
|||
}
|
||||
|
||||
map.dataLayer.setVisibility(false);
|
||||
map.events.unregister("moveend", map, showData);
|
||||
map.events.unregister("moveend", map, updateData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,8 +135,6 @@ function showAreas() {
|
|||
useMap(true);
|
||||
}
|
||||
|
||||
$("#browse_select_view").click(useMap);
|
||||
|
||||
function endDrag(bbox) {
|
||||
var bounds = bbox.getBounds();
|
||||
var projected = bounds.clone().transform(map.getProjectionObject(), epsg4326);
|
||||
|
@ -149,59 +149,42 @@ function endDrag(bbox) {
|
|||
$("#browse_select_view").show();
|
||||
}
|
||||
|
||||
function displayFeatureWarning() {
|
||||
function displayFeatureWarning(count, limit, callback) {
|
||||
clearStatus();
|
||||
|
||||
var div = document.createElement("div");
|
||||
|
||||
var p = document.createElement("p");
|
||||
p.appendChild(document.createTextNode(i18n("<%=j t 'browse.start_rjs.loaded_an_area_with_num_features' %>", { num_features: browseFeatureList.length })));
|
||||
p.appendChild(document.createTextNode(i18n("<%=j t 'browse.start_rjs.loaded_an_area_with_num_features' %>", { num_features: count, max_features: limit })));
|
||||
div.appendChild(p);
|
||||
|
||||
var input = document.createElement("input");
|
||||
input.type = "submit";
|
||||
input.value = "<%=j t 'browse.start_rjs.load_data' %>";
|
||||
input.onclick = loadFeatureList;
|
||||
input.onclick = callback;
|
||||
div.appendChild(input);
|
||||
|
||||
$("#browse_content").html("");
|
||||
$("#browse_content").append(div);
|
||||
}
|
||||
|
||||
function loadFeatureList() {
|
||||
browseDataLayer.addFeatures(browseFeatureList);
|
||||
browseDataLayer.events.triggerEvent("loadend");
|
||||
|
||||
browseFeatureList = [];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function customDataLoader(request) {
|
||||
if (this.map.dataLayer.active) {
|
||||
function customDataLoader(resp, options) {
|
||||
if (map.dataLayer.active) {
|
||||
var request = resp.priv;
|
||||
var doc = request.responseXML;
|
||||
|
||||
if (!doc || !doc.documentElement) {
|
||||
doc = request.responseText;
|
||||
}
|
||||
|
||||
var options = {};
|
||||
resp.features = this.format.read(doc);
|
||||
|
||||
OpenLayers.Util.extend(options, this.formatOptions);
|
||||
|
||||
if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
|
||||
options.externalProjection = this.projection;
|
||||
options.internalProjection = this.map.getProjectionObject();
|
||||
}
|
||||
|
||||
var gml = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
|
||||
|
||||
browseFeatureList = gml.read(doc);
|
||||
|
||||
if (!this.maxFeatures || browseFeatureList.length <= this.maxFeatures) {
|
||||
loadFeatureList();
|
||||
if (!this.maxFeatures || resp.features.length <= this.maxFeatures) {
|
||||
options.callback.call(options.scope, resp);
|
||||
} else {
|
||||
displayFeatureWarning();
|
||||
displayFeatureWarning(resp.features.length, this.maxFeatures, function () {
|
||||
options.callback.call(options.scope, resp);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,11 +196,11 @@ function getData(bounds, reload) {
|
|||
if (size > <%= MAX_REQUEST_AREA %>) {
|
||||
setStatus(i18n("<%=j t 'browse.start_rjs.unable_to_load_size', :max_bbox_size => MAX_REQUEST_AREA %>", { bbox_size: size }));
|
||||
} else {
|
||||
loadGML("/api/<%= API_VERSION %>/map?bbox=" + projected.toBBOX(), reload);
|
||||
loadData("/api/<%= API_VERSION %>/map?bbox=" + projected.toBBOX(), reload);
|
||||
}
|
||||
}
|
||||
|
||||
function loadGML(url, reload) {
|
||||
function loadData(url, reload) {
|
||||
setStatus("<%=j t 'browse.start_rjs.loading' %>");
|
||||
|
||||
$("#browse_content").empty();
|
||||
|
@ -242,11 +225,17 @@ function loadGML(url, reload) {
|
|||
|
||||
if (browseDataLayer) browseDataLayer.destroyFeatures();
|
||||
|
||||
browseDataLayer = new OpenLayers.Layer.GML("Data", url, {
|
||||
format: OpenLayers.Format.OSM,
|
||||
formatOptions: formatOptions,
|
||||
maxFeatures: 100,
|
||||
requestSuccess: customDataLoader,
|
||||
browseDataLayer = new OpenLayers.Layer.Vector("Data", {
|
||||
strategies: [
|
||||
new OpenLayers.Strategy.Fixed()
|
||||
],
|
||||
protocol: new OpenLayers.Protocol.HTTP({
|
||||
url: url,
|
||||
format: new OpenLayers.Format.OSM(formatOptions),
|
||||
maxFeatures: <%= @max_features %>,
|
||||
handleRead: customDataLoader
|
||||
}),
|
||||
projection: new OpenLayers.Projection("EPSG:4326"),
|
||||
displayInLayerSwitcher: false,
|
||||
styleMap: new OpenLayers.StyleMap({
|
||||
'default': style,
|
||||
|
@ -263,8 +252,7 @@ function loadGML(url, reload) {
|
|||
browseSelectControl.activate();
|
||||
} else {
|
||||
browseDataLayer.destroyFeatures();
|
||||
browseDataLayer.format(formatOptions);
|
||||
browseDataLayer.setUrl(url);
|
||||
browseDataLayer.refresh({ url: url });
|
||||
}
|
||||
|
||||
browseActiveFeature = null;
|
||||
|
@ -307,7 +295,7 @@ function dataLoaded() {
|
|||
browseObjectList.appendChild(list);
|
||||
|
||||
var link = document.createElement("a");
|
||||
link.href = this.url;
|
||||
link.href = this.protocol.url;
|
||||
link.appendChild(document.createTextNode("<%=j t 'browse.start_rjs.object_list.api' %>"));
|
||||
browseObjectList.appendChild(link);
|
||||
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
<hr />
|
||||
<%= link_to(t('browse.way.download_xml'), :controller => "way", :action => "read") %>
|
||||
| <%= link_to(t('browse.way.view_history'), :action => "way_history") %>
|
||||
<% unless @midnode.nil? %>
|
||||
| <%= link_to(t('browse.way.edit'), :controller => "site", :action => "edit", :way => @way.id, :lat => @midnode.lat, :lon => @midnode.lon, :zoom => 16) %>
|
||||
<% end %>
|
||||
<% unless @midnode.nil? -%>
|
||||
| <%= link_to(t('browse.way.edit'), :controller => "site", :action => "edit", :way => @way.id, :lat => @midnode.lat, :lon => @midnode.lon, :zoom => 16) %>
|
||||
<% end -%>
|
||||
|
|