From: Tom Hughes Date: Fri, 19 Jul 2013 10:18:12 +0000 (+0100) Subject: Merge remote-tracking branch 'osmlab/map-ui' X-Git-Tag: live~4900 X-Git-Url: https://git.openstreetmap.org/rails.git/commitdiff_plain/c8fb5ad24c5751bd2d43b86e4359381d200af066?hp=3880ac5de8150eef3cc5b26eb9814f5c1d681afa Merge remote-tracking branch 'osmlab/map-ui' --- diff --git a/Vendorfile b/Vendorfile index 3eee989d3..cc590e8bf 100644 --- a/Vendorfile +++ b/Vendorfile @@ -16,12 +16,8 @@ folder 'vendor/assets' do folder 'img', 'src/img' end - from 'git://github.com/kartena/Leaflet.Pancontrol.git' do - file 'leaflet.pan.js', 'src/L.Control.Pan.js' - end - - from 'git://github.com/kartena/Leaflet.zoomslider.git' do - file 'leaflet.zoom.js', 'src/L.Control.Zoomslider.js' + from 'git://github.com/domoritz/leaflet-locatecontrol.git' do + file 'leaflet.locate.js', 'src/L.Control.Locate.js' end from 'git://github.com/jfirebaugh/leaflet-osm.git' do @@ -32,7 +28,7 @@ folder 'vendor/assets' do folder 'jquery' do from 'git://github.com/jevin/Autogrow-Textarea.git' do file 'jquery.autogrowtextarea.js', 'jquery.autogrowtextarea.js' - end + end end folder 'ohauth' do @@ -42,7 +38,7 @@ folder 'vendor/assets' do end folder 'iD' do - from 'git://github.com/systemed/iD', :branch => '1-0-stable' do + from 'git://github.com/systemed/iD', :branch => 'release' do folder 'iD/img', 'dist/img' folder 'iD/locales', 'dist/locales' file 'iD.css.erb', 'dist/iD.css' do |path| diff --git a/app/assets/images/sprite.png b/app/assets/images/sprite.png index 7b6c6a73f..9f857f852 100644 Binary files a/app/assets/images/sprite.png and b/app/assets/images/sprite.png differ diff --git a/app/assets/images/sprite.svg b/app/assets/images/sprite.svg index bf65021fa..2e1d309e4 100644 --- a/app/assets/images/sprite.svg +++ b/app/assets/images/sprite.svg @@ -27,17 +27,21 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="4.7683716" - inkscape:cx="8.5527915" - inkscape:cy="148.78096" + inkscape:zoom="5" + inkscape:cx="159.62972" + inkscape:cy="181.16738" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - inkscape:window-width="1289" - inkscape:window-height="904" + inkscape:window-width="1280" + inkscape:window-height="756" inkscape:window-x="0" inkscape:window-y="0" - inkscape:window-maximized="0"> + inkscape:window-maximized="0" + showguides="true" + inkscape:guide-bbox="true" + inkscape:object-paths="true" + inkscape:object-nodes="true"> + + + + + + + + + + + + + + + + @@ -58,45 +126,137 @@ + - - - + + + + + + + + + + + + + id="path6918-2" + d="m 84,882.36218 0,-2.00001 10,-3.99999 2,1e-5 0,1.99998 -4,10 -2,10e-6 0,-6 z" + style="color:#000000;fill:#70cd8f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter6591-2);enable-background:accumulate" /> diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index f8a8c4520..cb670da34 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -5,9 +5,9 @@ //= require augment //= require leaflet //= require leaflet.osm -//= require leaflet.locationfilter -//= require leaflet.pan //= require leaflet.zoom +//= require leaflet.extend +//= require leaflet.locationfilter //= require i18n/translations //= require oauth //= require osm @@ -16,8 +16,10 @@ //= require menu //= require sidebar //= require richtext -//= require resize //= require geocoder +//= require querystring + +var querystring = require('querystring-component'); function zoomPrecision(zoom) { var decimals = Math.pow(10, Math.floor(zoom/3)); @@ -26,188 +28,164 @@ function zoomPrecision(zoom) { }; } +function normalBounds(bounds) { + if (bounds instanceof L.LatLngBounds) return bounds; + return new L.LatLngBounds( + new L.LatLng(bounds[0][0], bounds[0][1]), + new L.LatLng(bounds[1][0], bounds[1][1])); +} + +function remoteEditHandler(bbox, select) { + var loaded = false, + query = { + left: bbox.getWest() - 0.0001, + top: bbox.getNorth() + 0.0001, + right: bbox.getEast() + 0.0001, + bottom: bbox.getSouth() - 0.0001 + }; + + if (select) query.select = select; + $("#linkloader") + .attr("src", "http://127.0.0.1:8111/load_and_zoom?" + querystring.stringify(query)) + .load(function() { loaded = true; }); + + setTimeout(function () { + if (!loaded) alert(I18n.t('site.index.remote_failed')); + }, 1000); + + return false; +} + /* - * Called as the user scrolls/zooms around to aniplate hrefs of the + * Called as the user scrolls/zooms around to maniplate hrefs of the * view tab and various other links */ -function updatelinks(lon,lat,zoom,layers,minlon,minlat,maxlon,maxlat,object) { +function updatelinks(loc, zoom, layers, bounds, object) { var toPrecision = zoomPrecision(zoom); + bounds = normalBounds(bounds); var node; - lat = toPrecision(lat); - lon = toPrecision(lon); + var lat = toPrecision(loc.lat), + lon = toPrecision(loc.lon || loc.lng); - if (minlon) { - minlon = toPrecision(minlon); - minlat = toPrecision(minlat); - maxlon = toPrecision(maxlon); - maxlat = toPrecision(maxlat); + if (bounds) { + var minlon = toPrecision(bounds.getWest()), + minlat = toPrecision(bounds.getSouth()), + maxlon = toPrecision(bounds.getEast()), + maxlat = toPrecision(bounds.getNorth()); } - $(".geolink").each(function (index, link) { - var args = getArgs(link.href); + $(".geolink").each(setGeolink); + + function setGeolink(index, link) { + var base = link.href.split('?')[0], + qs = link.href.split('?')[1], + args = querystring.parse(qs); if ($(link).hasClass("llz")) { - args.lat = lat; - args.lon = lon; - args.zoom = zoom; + $.extend(args, { + lat: lat, + lon: lon, + zoom: zoom + }); } else if (minlon && $(link).hasClass("bbox")) { - args.bbox = minlon + "," + minlat + "," + maxlon + "," + maxlat; + $.extend(args, { + bbox: minlon + "," + minlat + "," + maxlon + "," + maxlat + }); } - if (layers && $(link).hasClass("layers")) { - args.layers = layers; - } - - if (object && $(link).hasClass("object")) { - args[object.type] = object.id; - } + if (layers && $(link).hasClass("layers")) args.layers = layers; + if (object && $(link).hasClass("object")) args[object.type] = object.id; var minzoom = $(link).data("minzoom"); if (minzoom) { - var name = link.id.replace(/anchor$/, ""); - - $(link).off("click.minzoom"); - - if (zoom >= minzoom) { - $(link).attr("title", I18n.t("javascripts.site." + name + "_tooltip")); - $(link).removeClass("disabled"); - } else { - $(link).on("click.minzoom", function () { alert(I18n.t("javascripts.site." + name + "_zoom_alert")); return false; }); - $(link).attr("title", I18n.t("javascripts.site." + name + "_disabled_tooltip")); - $(link).addClass("disabled"); - } - } - - link.href = setArgs(link.href, args); - }); - - $("#shortlinkanchor").each(function () { - var args = getArgs(this.href); - var code = makeShortCode(lat, lon, zoom); - var prefix = shortlinkPrefix(); - - // Add ?{node,way,relation}=id to the arguments - if (object) { - args[object.type] = object.id; - } - - // This is a hack to omit the default mapnik layer from the shortlink. - if (layers && layers != "M") { - args.layers = layers; - } - else { - delete args.layers; - } - - // Here we're assuming that all parameters but ?layers= and - // ?{node,way,relation}= can be safely omitted from the shortlink - // which encodes lat/lon/zoom. If new URL parameters are added to - // the main slippy map this needs to be changed. - if (args.layers || object) { - this.href = setArgs(prefix + "/go/" + code, args); - } else { - this.href = prefix + "/go/" + code; + var name = link.id.replace(/anchor$/, ""); + $(link).off("click.minzoom"); + if (zoom >= minzoom) { + $(link) + .attr("title", I18n.t("javascripts.site." + name + "_tooltip")) + .removeClass("disabled"); + } else { + $(link) + .attr("title", I18n.t("javascripts.site." + name + "_disabled_tooltip")) + .addClass("disabled") + .on("click.minzoom", function () { + alert(I18n.t("javascripts.site." + name + "_zoom_alert")); + return false; + }); + } } - }); -} - -/* - * Get the URL prefix to use for a short link - */ -function shortlinkPrefix() { - if (window.location.hostname.match(/^www\.openstreetmap\.org/i)) { - return "http://osm.org"; - } else { - return ""; + link.href = base + '?' + querystring.stringify(args); } } -/* - * Called to get the arguments from a URL as a hash. - */ -function getArgs(url) { - var args = {}; - var querystart = url.indexOf("?"); - - if (querystart >= 0) { - var querystring = url.substring(querystart + 1); - var queryitems = querystring.split("&"); - - for (var i = 0; i < queryitems.length; i++) { - if (match = queryitems[i].match(/^(.*)=(.*)$/)) { - args[unescape(match[1])] = unescape(match[2]); - } else { - args[unescape(queryitems[i])] = null; - } - } - } - - return args; +function getShortUrl(map) { + return (window.location.hostname.match(/^www\.openstreetmap\.org/i) ? + 'http://osm.org/go/' : 'http://' + window.location.hostname + '/go/') + + makeShortCode(map); } -/* - * Called to set the arguments on a URL from the given hash. - */ -function setArgs(url, args) { - var queryitems = []; - - for (arg in args) { - if (args[arg] == null) { - queryitems.push(escape(arg)); - } else { - queryitems.push(escape(arg) + "=" + escape(args[arg])); - } - } - - return url.replace(/\?.*$/, "") + "?" + queryitems.join("&"); +function getUrl(map) { + var center = map.getCenter(), + zoom = map.getZoom(), + toZoom = zoomPrecision(zoom); + + return (window.location.hostname.match(/^www\.openstreetmap\.org/i) ? + 'http://openstreetmap.org/?' : 'http://' + window.location.hostname + '/?') + + querystring.stringify({ + lat: toZoom(center.lat), + lon: toZoom(center.lng), + zoom: zoom, + layers: map.getLayersCode() + }); } -/* - * Called to interlace the bits in x and y, making a Morton code. - */ -function interlace(x, y) { - x = (x | (x << 8)) & 0x00ff00ff; - x = (x | (x << 4)) & 0x0f0f0f0f; - x = (x | (x << 2)) & 0x33333333; - x = (x | (x << 1)) & 0x55555555; - - y = (y | (y << 8)) & 0x00ff00ff; - y = (y | (y << 4)) & 0x0f0f0f0f; - y = (y | (y << 2)) & 0x33333333; - y = (y | (y << 1)) & 0x55555555; - - return (x << 1) | y; -} +// Called to create a short code for the short link. +function makeShortCode(map) { + var zoom = map.getZoom(), + str = '', + char_array = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~", + x = Math.round((map.getCenter().lng + 180.0) * ((1 << 30) / 90.0)), + y = Math.round((map.getCenter().lat + 90.0) * ((1 << 30) / 45.0)), + // JavaScript only has to keep 32 bits of bitwise operators, so this has to be + // done in two parts. each of the parts c1/c2 has 30 bits of the total in it + // and drops the last 4 bits of the full 64 bit Morton code. + c1 = interlace(x >>> 17, y >>> 17), c2 = interlace((x >>> 2) & 0x7fff, (y >>> 2) & 0x7fff); -/* - * Called to create a short code for the short link. - */ -function makeShortCode(lat, lon, zoom) { - char_array = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~"; - var x = Math.round((lon + 180.0) * ((1 << 30) / 90.0)); - var y = Math.round((lat + 90.0) * ((1 << 30) / 45.0)); - // JavaScript only has to keep 32 bits of bitwise operators, so this has to be - // done in two parts. each of the parts c1/c2 has 30 bits of the total in it - // and drops the last 4 bits of the full 64 bit Morton code. - var str = ""; - var c1 = interlace(x >>> 17, y >>> 17), c2 = interlace((x >>> 2) & 0x7fff, (y >>> 2) & 0x7fff); for (var i = 0; i < Math.ceil((zoom + 8) / 3.0) && i < 5; ++i) { digit = (c1 >> (24 - 6 * i)) & 0x3f; str += char_array.charAt(digit); } - for (var i = 5; i < Math.ceil((zoom + 8) / 3.0); ++i) { + for (i = 5; i < Math.ceil((zoom + 8) / 3.0); ++i) { digit = (c2 >> (24 - 6 * (i - 5))) & 0x3f; str += char_array.charAt(digit); } - for (var i = 0; i < ((zoom + 8) % 3); ++i) { - str += "-"; + for (i = 0; i < ((zoom + 8) % 3); ++i) str += "-"; + + // Called to interlace the bits in x and y, making a Morton code. + function interlace(x, y) { + x = (x | (x << 8)) & 0x00ff00ff; + x = (x | (x << 4)) & 0x0f0f0f0f; + x = (x | (x << 2)) & 0x33333333; + x = (x | (x << 1)) & 0x55555555; + y = (y | (y << 8)) & 0x00ff00ff; + y = (y | (y << 4)) & 0x0f0f0f0f; + y = (y | (y << 2)) & 0x33333333; + y = (y | (y << 1)) & 0x55555555; + return (x << 1) | y; } + return str; } +// generate a cookie-safe string of map state +function cookieContent(map) { + var center = map.getCenter().wrap(); + return [center.lng, center.lat, map.getZoom(), map.getLayersCode()].join('|'); +} + /* - * Forms which have been cached by rails may have he wrong + * Forms which have been cached by rails may have the wrong * authenticity token, so patch up any forms with the correct * token taken from the page header. */ diff --git a/app/assets/javascripts/browse.js b/app/assets/javascripts/browse.js index edfb4643a..b20e4516e 100644 --- a/app/assets/javascripts/browse.js +++ b/app/assets/javascripts/browse.js @@ -1,39 +1,26 @@ $(document).ready(function () { - function remoteEditHandler(bbox, select) { - var left = bbox.getWest() - 0.0001; - var top = bbox.getNorth() + 0.0001; - var right = bbox.getEast() + 0.0001; - var bottom = bbox.getSouth() - 0.0001; - var loaded = false; - - $("#linkloader").load(function () { loaded = true; }); - - if (select) { - $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + left + "&top=" + top + "&right=" + right + "&bottom=" + bottom + "&select=" + select); - } else { - $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + left + "&top=" + top + "&right=" + right + "&bottom=" + bottom); - } - - setTimeout(function () { - if (!loaded) alert(I18n.t('site.index.remote_failed')); - }, 1000); - return false; - } + var map = L.map("small_map", { + attributionControl: false, + zoomControl: false + }).addLayer(new L.OSM.Mapnik()); - var map = createMap("small_map", { - layerControl: false, - panZoomControl: false, - attributionControl: false - }); + L.OSM.zoom() + .addTo(map); var params = $("#small_map").data(); + var object, bbox; if (params.type == "changeset") { - var bbox = L.latLngBounds([params.minlat, params.minlon], - [params.maxlat, params.maxlon]); + bbox = L.latLngBounds([params.minlat, params.minlon], + [params.maxlat, params.maxlon]); map.fitBounds(bbox); - addBoxToMap(bbox); + + L.rectangle(bbox, { + weight: 2, + color: '#e90', + fillOpacity: 0 + }).addTo(map); $("#loading").hide(); $("#browse_map .geolink").show(); @@ -42,16 +29,16 @@ $(document).ready(function () { return remoteEditHandler(bbox); }); - var centre = bbox.getCenter(); - updatelinks(centre.lng, centre.lat, 16, null, params.minlon, params.minlat, params.maxlon, params.maxlat); + updatelinks(map.getCenter(), 16, null, [[params.minlat, params.minlon], + [params.maxlat, params.maxlon]]); } else if (params.type == "note") { - var object = {type: params.type, id: params.id}; + object = {type: params.type, id: params.id}; map.setView([params.lat, params.lon], 16); L.marker([params.lat, params.lon], { icon: getUserIcon() }).addTo(map); - var bbox = map.getBounds(); + bbox = map.getBounds(); $("#loading").hide(); $("#browse_map .geolink").show(); @@ -60,21 +47,20 @@ $(document).ready(function () { return remoteEditHandler(bbox); }); - updatelinks(params.lon, params.lat, 16, null, + updatelinks(params, 16, null, bbox.getWest(), bbox.getSouth(), bbox.getEast(), bbox.getNorth(), object); } else { - $("#object_larger_map").hide(); - $("#object_edit").hide(); + $("#object_larger_map, #object_edit").hide(); - var object = {type: params.type, id: params.id}; + object = {type: params.type, id: params.id}; if (!params.visible) { object.version = params.version - 1; } - addObjectToMap(object, { + addObjectToMap(object, map, { zoom: true, callback: function(extent) { $("#loading").hide(); @@ -92,15 +78,7 @@ $(document).ready(function () { $("#object_larger_map").show(); $("#object_edit").show(); - var centre = extent.getCenter(); - updatelinks(centre.lng, - centre.lat, - 16, null, - extent.getWest(), - extent.getSouth(), - extent.getEast(), - extent.getNorth(), - object); + updatelinks(map.getCenter(), 16, null, extent, object); } else { $("#small_map").hide(); } diff --git a/app/assets/javascripts/changeset.js b/app/assets/javascripts/changeset.js index 1010fbac9..6d4881547 100644 --- a/app/assets/javascripts/changeset.js +++ b/app/assets/javascripts/changeset.js @@ -1,6 +1,14 @@ $(document).ready(function () { var changesets = [], rects = {}; - var map = createMap("changeset_list_map"); + + var map = L.map("changeset_list_map", { + attributionControl: false, + zoomControl: false + }).addLayer(new L.OSM.Mapnik()); + + L.OSM.zoom() + .addTo(map); + var group = L.featureGroup().addTo(map); $("[data-changeset]").each(function () { diff --git a/app/assets/javascripts/diary_entry.js b/app/assets/javascripts/diary_entry.js index 291c86523..1aa728ea0 100644 --- a/app/assets/javascripts/diary_entry.js +++ b/app/assets/javascripts/diary_entry.js @@ -1,5 +1,5 @@ $(document).ready(function () { - var marker; + var marker, map; function setLocation(e) { $("#latitude").val(e.latlng.lat); @@ -21,7 +21,14 @@ $(document).ready(function () { var params = $("#map").data(); var centre = [params.lat, params.lon]; - var map = createMap("map"); + + map = L.map("map", { + attributionControl: false, + zoomControl: false + }).addLayer(new L.OSM.Mapnik()); + + L.OSM.zoom() + .addTo(map); map.setView(centre, params.zoom); diff --git a/app/assets/javascripts/edit.js b/app/assets/javascripts/edit.js index f13e2d481..b9aba25d3 100644 --- a/app/assets/javascripts/edit.js +++ b/app/assets/javascripts/edit.js @@ -1,19 +1,12 @@ function maximiseMap() { $("#content").addClass("maximised"); - - handleResize(); } function minimiseMap() { $("#content").removeClass("maximised"); - - handleResize(); } $(document).ready(function () { - $(window).resize(handleResize); - handleResize(); - $("#search_form").submit(function () { $("#sidebar_title").html(I18n.t('site.sidebar.search_results')); $("#sidebar_content").load($(this).attr("action"), { diff --git a/app/assets/javascripts/embed.js.erb b/app/assets/javascripts/embed.js.erb index 742061fa6..57572ca48 100644 --- a/app/assets/javascripts/embed.js.erb +++ b/app/assets/javascripts/embed.js.erb @@ -40,5 +40,5 @@ window.onload = function () { L.latLng(args.bbox[3], args.bbox[2])]) } else { map.fitWorld(); - } + } }; diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index 9f0c86493..029c0bfd1 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -1,20 +1,101 @@ //= require_self +//= require leaflet.sidebar +//= require leaflet.locate +//= require leaflet.layers +//= require leaflet.key +//= require leaflet.note +//= require leaflet.share //= require index/browse //= require index/export -//= require index/key //= require index/notes $(document).ready(function () { - var permalinks = $("#permalink").detach().html(); - var marker; var params = OSM.mapParams(); - var map = createMap("map"); - L.control.scale().addTo(map); + var map = L.map("map", { + zoomControl: false, + layerControl: false + }); + + map.attributionControl.setPrefix(''); + + var layers = [ + new L.OSM.Mapnik({ + attribution: '', + code: "M", + keyid: "mapnik", + name: I18n.t("javascripts.map.base.standard") + }), + new L.OSM.CycleMap({ + attribution: "Tiles courtesy of Andy Allan", + code: "C", + keyid: "cyclemap", + name: I18n.t("javascripts.map.base.cycle_map") + }), + new L.OSM.TransportMap({ + attribution: "Tiles courtesy of Andy Allan", + code: "T", + keyid: "transportmap", + name: I18n.t("javascripts.map.base.transport_map") + }), + new L.OSM.MapQuestOpen({ + attribution: "Tiles courtesy of MapQuest ", + code: "Q", + keyid: "mapquest", + name: I18n.t("javascripts.map.base.mapquest") + }) + ]; + + layers[0].addTo(map); + + map.noteLayer = new L.LayerGroup({code: 'N'}); + map.dataLayer = new L.OSM.DataLayer(null); + + $("#sidebar").on("opened closed", function () { + map.invalidateSize(); + }); + + var position = $('html').attr('dir') === 'rtl' ? 'topleft' : 'topright'; + + L.OSM.zoom({position: position}) + .addTo(map); + + L.control.locate({position: position}) + .addTo(map); + + var sidebar = L.OSM.sidebar('#map-ui') + .addTo(map); - map.attributionControl.setPrefix(permalinks); + L.OSM.layers({ + position: position, + layers: layers, + sidebar: sidebar + }).addTo(map); - map.on("moveend layeradd layerremove", updateLocation); + L.OSM.key({ + position: position, + sidebar: sidebar + }).addTo(map); + + L.OSM.share({ + position: position, + getShortUrl: getShortUrl, + getUrl: getUrl, + sidebar: sidebar, + short: true + }).addTo(map); + + L.OSM.note({ + position: position, + sidebar: sidebar + }).addTo(map); + + L.control.scale() + .addTo(map); + + map.on('moveend layeradd layerremove', updateLocation); + + map.markerLayer = L.layerGroup().addTo(map); if (!params.object_zoom) { if (params.bbox) { @@ -24,7 +105,11 @@ $(document).ready(function () { map.fitBounds(bbox); if (params.box) { - addBoxToMap(bbox); + L.rectangle(bbox, { + weight: 2, + color: '#e90', + fillOpacity: 0 + }).addTo(map); } } else { map.setView([params.lat, params.lon], params.zoom); @@ -32,90 +117,93 @@ $(document).ready(function () { } if (params.layers) { - setMapLayers(params.layers); + var foundLayer = false; + for (var i = 0; i < layers.length; i++) { + if (params.layers.indexOf(layers[i].options.code) >= 0) { + map.addLayer(layers[i]); + foundLayer = true; + } else { + map.removeLayer(layers[i]); + } + } + if (!foundLayer) { + map.addLayer(layers[0]); + } } if (params.marker) { - marker = L.marker([params.mlat, params.mlon], {icon: getUserIcon()}).addTo(map); + L.marker([params.mlat, params.mlon], {icon: getUserIcon()}).addTo(map.markerLayer); } if (params.object) { - addObjectToMap(params.object, { zoom: params.object_zoom }); + addObjectToMap(params.object, map, { zoom: params.object_zoom }); } - handleResize(); - - $("body").on("click", "a.set_position", function (e) { - e.preventDefault(); - - var data = $(this).data(); - var centre = L.latLng(data.lat, data.lon); - - if (data.minLon && data.minLat && data.maxLon && data.maxLat) { - map.fitBounds([[data.minLat, data.minLon], - [data.maxLat, data.maxLon]]); - } else { - map.setView(centre, data.zoom); - } + $("body").on("click", "a.set_position", setPositionLink(map)); - if (data.type && data.id) { - addObjectToMap(data, { zoom: true, style: { opacity: 0.2, fill: false } }); - } - - if (marker) { - map.removeLayer(marker); - } - - marker = L.marker(centre, {icon: getUserIcon()}).addTo(map); + $("a[data-editor=remote]").click(function(e) { + remoteEditHandler(map.getBounds()); + e.preventDefault(); }); - function updateLocation() { - var center = map.getCenter().wrap(); - var zoom = map.getZoom(); - var layers = getMapLayers(); - var extents = map.getBounds().wrap(); - - updatelinks(center.lng, - center.lat, - zoom, - layers, - extents.getWest(), - extents.getSouth(), - extents.getEast(), - extents.getNorth(), - params.object); - - var expiry = new Date(); - expiry.setYear(expiry.getFullYear() + 10); - $.cookie("_osm_location", [center.lng, center.lat, zoom, layers].join("|"), {expires: expiry}); + if (OSM.preferred_editor == "remote" && $('body').hasClass("site-edit")) { + remoteEditHandler(map.getBounds()); } - function remoteEditHandler() { - var extent = map.getBounds(); - var loaded = false; + $("#search_form").submit(submitSearch(map)); - $("#linkloader").load(function () { loaded = true; }); - $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + extent.getWest() - + "&bottom=" + extent.getSouth() - + "&right=" + extent.getEast() - + "&top=" + extent.getNorth()); - setTimeout(function () { - if (!loaded) alert(I18n.t('site.index.remote_failed')); - }, 1000); + if ($("#query").val()) { + $("#search_form").submit(); + } - return false; + // Focus the search field for browsers that don't support + // the HTML5 'autofocus' attribute + if (!("autofocus" in document.createElement("input"))) { + $("#query").focus(); } - $("a[data-editor=remote]").click(remoteEditHandler); + initializeExport(map); + initializeBrowse(map); + initializeNotes(map); +}); - if (OSM.preferred_editor == "remote" && $('body').hasClass("site-edit")) { - remoteEditHandler(); - } +function updateLocation() { + updatelinks(this.getCenter().wrap(), + this.getZoom(), + this.getLayersCode(), + this.getBounds().wrap()); + + var expiry = new Date(); + expiry.setYear(expiry.getFullYear() + 10); + $.cookie("_osm_location", cookieContent(this), { expires: expiry }); +} + +function setPositionLink(map) { + return function(e) { + var data = $(this).data(), + center = L.latLng(data.lat, data.lon); + + if (data.minLon && data.minLat && data.maxLon && data.maxLat) { + map.fitBounds([[data.minLat, data.minLon], + [data.maxLat, data.maxLon]]); + } else { + map.setView(center, data.zoom); + } + + if (data.type && data.id) { + addObjectToMap(data, map, { zoom: true, style: { opacity: 0.2, fill: false } }); + } + + map.markerLayer.clearLayers(); + L.marker(center, {icon: getUserIcon()}).addTo(map.markerLayer); - $(window).resize(handleResize); + return e.preventDefault(); + }; +} - $("#search_form").submit(function () { +function submitSearch(map) { + return function(e) { var bounds = map.getBounds(); $("#sidebar_title").html(I18n.t('site.sidebar.search_results')); @@ -127,16 +215,6 @@ $(document).ready(function () { maxlat: bounds.getNorth() }, openSidebar); - return false; - }); - - if ($("#query").val()) { - $("#search_form").submit(); - } - - // Focus the search field for browsers that don't support - // the HTML5 'autofocus' attribute - if (!("autofocus" in document.createElement("input"))) { - $("#query").focus(); - } -}); + return e.preventDefault(); + }; +} diff --git a/app/assets/javascripts/index/browse.js b/app/assets/javascripts/index/browse.js index 228a5a411..e04a864f4 100644 --- a/app/assets/javascripts/index/browse.js +++ b/app/assets/javascripts/index/browse.js @@ -2,7 +2,7 @@ //= require templates/browse/feature_list //= require templates/browse/feature_history -$(document).ready(function () { +function initializeBrowse(map) { var browseBounds; var layersById; var selectedLayer; @@ -10,20 +10,20 @@ $(document).ready(function () { var areasHidden = false; var locationFilter; - var dataLayer = new L.OSM.DataLayer(null, { - styles: { - way: { - weight: 3, - color: "#000000", - opacity: 0.4 - }, - area: { - weight: 3, - color: "#ff0000" - }, - node: { - color: "#00ff00" - } + var dataLayer = map.dataLayer; + + dataLayer.setStyle({ + way: { + weight: 3, + color: "#000000", + opacity: 0.4 + }, + area: { + weight: 3, + color: "#ff0000" + }, + node: { + color: "#00ff00" } }); @@ -35,10 +35,6 @@ $(document).ready(function () { onSelect(e.layer); }); - if (OSM.STATUS != 'api_offline' && OSM.STATUS != 'database_offline') { - map.layersControl.addOverlay(dataLayer, I18n.t("browse.start_rjs.data_layer_name")); - } - map.on('layeradd', function (e) { if (e.layer === dataLayer) { $.ajax({ url: "/browse/start", success: function (sidebarHtml) { @@ -327,4 +323,4 @@ $(document).ready(function () { $("#browse_status").html(""); $("#browse_status").hide(); } -}); +} diff --git a/app/assets/javascripts/index/export.js b/app/assets/javascripts/index/export.js index 52af96ebb..417dfabd3 100644 --- a/app/assets/javascripts/index/export.js +++ b/app/assets/javascripts/index/export.js @@ -1,4 +1,4 @@ -$(document).ready(function () { +function initializeExport(map) { $("#exportanchor").click(function (e) { $.ajax({ url: $(this).data('url'), success: function (sidebarHtml) { startExport(sidebarHtml); @@ -38,7 +38,7 @@ $(document).ready(function () { openSidebar(); - if (getMapBaseLayer().keyid == "mapnik") { + if (map.getMapBaseLayerId() == "mapnik") { $("#format_mapnik").prop("checked", true); } @@ -186,7 +186,7 @@ $(document).ready(function () { function htmlUrlChanged() { var bounds = getBounds(); - var layerName = getMapBaseLayer().keyid; + var layerName = map.getMapBaseLayerId(); var url = "http://" + OSM.SERVER_URL + "/export/embed.html?bbox=" + bounds.toBBoxString() + "&layer=" + layerName; var markerUrl = ""; @@ -203,7 +203,7 @@ $(document).ready(function () { var zoom = map.getBoundsZoom(bounds); - var layers = getMapLayers(); + var layers = map.getLayersCode(); var text = I18n.t('export.start_rjs.view_larger_map'); var escaped = []; @@ -281,4 +281,4 @@ $(document).ready(function () { validateControls(); } } -}); +} diff --git a/app/assets/javascripts/index/key.js b/app/assets/javascripts/index/key.js deleted file mode 100644 index 9722cf4cf..000000000 --- a/app/assets/javascripts/index/key.js +++ /dev/null @@ -1,34 +0,0 @@ -$(document).ready(function () { - $("#open_map_key").click(function (e) { - e.preventDefault(); - - var url = $(this).attr('href'), - title = $(this).text(); - - function updateMapKey() { - var mapLayer = getMapBaseLayer().keyid, - mapZoom = map.getZoom(); - - $(".mapkey-table-entry").each(function () { - var data = $(this).data(); - - if (mapLayer == data.layer && - mapZoom >= data.zoomMin && mapZoom <= data.zoomMax) { - $(this).show(); - } else { - $(this).hide(); - } - }); - } - - $("#sidebar_content").load(url, updateMapKey); - - openSidebar({ title: title }); - - $("#sidebar").one("closed", function () { - map.off("zoomend baselayerchange", updateMapKey); - }); - - map.on("zoomend baselayerchange", updateMapKey); - }); -}); diff --git a/app/assets/javascripts/index/notes.js.erb b/app/assets/javascripts/index/notes.js.erb index 6a7c50373..2d807eb92 100644 --- a/app/assets/javascripts/index/notes.js.erb +++ b/app/assets/javascripts/index/notes.js.erb @@ -1,8 +1,11 @@ //= require templates/notes/show //= require templates/notes/new -$(document).ready(function () { - var params = OSM.mapParams(); +function initializeNotes(map) { + var params = OSM.mapParams(), + noteLayer = map.noteLayer, + notes = {}, + newNote; var noteIcons = { "new": L.icon({ @@ -22,60 +25,38 @@ $(document).ready(function () { }) }; - var noteLayer = new L.LayerGroup(); - var notes = {}; - var newNote; - - layers.push({ - layer: noteLayer, - layerCode: "N" - }); - map.on("layeradd", function (e) { if (e.layer == noteLayer) { loadNotes(); map.on("moveend", loadNotes); } - }); - - map.on("layerremove", function (e) { + }).on("layerremove", function (e) { if (e.layer == noteLayer) { map.off("moveend", loadNotes); noteLayer.clearLayers(); notes = {}; } - }); - - // Don't focus the text area on touch devices to avoid flashing the keyboard - if (!('ontouchstart' in document.documentElement)) { - map.on("popupopen", function (e) { - $(e.popup._container).find(".comment").focus(); - }); - } - - map.on("popupclose", function (e) { + }).on("popupclose", function (e) { if (newNote && e.popup == newNote._popup) { $(newNote).oneTime(10, "removenote", function () { map.removeLayer(newNote); newNote = null; }); } + }).on("popupopen", function (e) { + if (!('ontouchstart' in document.documentElement)) { + $(e.popup._container).find(".comment").focus(); + } }); if (OSM.STATUS != 'api_offline' && OSM.STATUS != 'database_offline') { - map.layersControl.addOverlay(noteLayer, I18n.t("browse.start_rjs.notes_layer_name")); - - if (params.layers) setMapLayers(params.layers); - if (params.notes) map.addLayer(noteLayer); - + if (params.notes || params.layers.indexOf('N') >= 0) map.addLayer(noteLayer); if (params.note) { $.ajax({ url: "/api/" + OSM.API_VERSION + "/notes/" + params.note + ".json", success: function (feature) { var marker = updateMarker(notes[feature.properties.id], feature); - notes[feature.properties.id] = marker; - map.addLayer(noteLayer); marker.openPopup(); } @@ -84,27 +65,22 @@ $(document).ready(function () { } function updateMarker(marker, feature) { - if (marker) - { + if (marker) { marker.setIcon(noteIcons[feature.properties.status]); marker.setPopupContent(createPopupContent( - marker, feature.properties, + marker, feature.properties, $(marker._popup._content).find("textarea").val() )); - } - else - { + } else { marker = L.marker(feature.geometry.coordinates.reverse(), { icon: noteIcons[feature.properties.status], opacity: 0.9 }); - marker.addTo(noteLayer).bindPopup( createPopupContent(marker, feature.properties), popupOptions() ); } - return marker; } @@ -121,26 +97,26 @@ $(document).ready(function () { noteLoader = $.ajax({ url: url, - success: function (json) { - var oldNotes = notes; - - notes = {}; - - json.features.forEach(function (feature) { - var marker = oldNotes[feature.properties.id]; + success: success + }); + } - delete oldNotes[feature.properties.id]; + function success(json) { + var oldNotes = notes; + notes = {}; + json.features.forEach(updateMarkers); - notes[feature.properties.id] = updateMarker(marker, feature); - }); + function updateMarkers(feature) { + var marker = oldNotes[feature.properties.id]; + delete oldNotes[feature.properties.id]; + notes[feature.properties.id] = updateMarker(marker, feature); + } - for (id in oldNotes) { - noteLayer.removeLayer(oldNotes[id]); - } + for (id in oldNotes) { + noteLayer.removeLayer(oldNotes[id]); + } - noteLoader = null; - } - }); + noteLoader = null; } }; @@ -184,6 +160,8 @@ $(document).ready(function () { return content[0]; } + var addNoteButton = $(".control-note .control-button"); + function createNote(marker, form, url) { var location = marker.getLatLng(); @@ -201,15 +179,17 @@ $(document).ready(function () { lon: location.lng, text: $(form.text).val() }, - success: function (feature) { - $(marker._popup._content).find("textarea").val(""); + success: noteCreated + }); - notes[feature.properties.id] = updateMarker(marker, feature); - newNote = null; + function noteCreated(feature) { + $(marker._popup._content).find("textarea").val(""); - $("#createnoteanchor").removeClass("disabled").addClass("geolink"); - } - }); + notes[feature.properties.id] = updateMarker(marker, feature); + newNote = null; + + addNoteButton.removeClass("disabled"); + } } function updateNote(marker, form, method, url) { @@ -237,28 +217,24 @@ $(document).ready(function () { }); } - $(".leaflet-control-attribution").on("click", "#createnoteanchor", function (e) { + addNoteButton.on("click", function (e) { e.preventDefault(); + e.stopPropagation(); - if ($(e.target).hasClass("disabled")) return; + if (addNoteButton.hasClass("disabled")) return; - $(e.target).removeClass("geolink").addClass("disabled"); + addNoteButton.addClass("disabled"); map.addLayer(noteLayer); var mapSize = map.getSize(); var markerPosition; - if (mapSize.y > 800) - { + if (mapSize.y > 800) { markerPosition = [mapSize.x / 2, mapSize.y / 2]; - } - else if (mapSize.y > 400) - { + } else if (mapSize.y > 400) { markerPosition = [mapSize.x / 2, 400]; - } - else - { + } else { markerPosition = [mapSize.x / 2, mapSize.y]; } @@ -268,35 +244,27 @@ $(document).ready(function () { draggable: true }); - var popupContent = $(JST["templates/notes/new"]({ create_url: $(e.target).attr("href") })); + var popupContent = $(JST["templates/notes/new"]()); - popupContent.find("textarea").on("input", function (e) { - var form = e.target.form; + popupContent.find("textarea").on("input", disableWhenBlank); - if ($(e.target).val() == "") { - $(form.add).prop("disabled", true); - } else { - $(form.add).prop("disabled", false); - } - }); + function disableWhenBlank(e) { + $(e.target.form.add).prop("disabled", $(e.target).val() === ""); + } popupContent.find("input[type=submit]").on("click", function (e) { e.preventDefault(); - createNote(newNote, e.target.form, $(e.target).data("url")); + createNote(newNote, e.target.form, '/api/0.6/notes.json'); }); newNote.addTo(noteLayer).bindPopup(popupContent[0], popupOptions()).openPopup(); newNote.on("remove", function (e) { - $("#createnoteanchor").removeClass("disabled").addClass("geolink"); - }); - - newNote.on("dragstart", function (e) { + addNoteButton.removeClass("disabled"); + }).on("dragstart", function (e) { $(newNote).stopTime("removenote"); - }); - - newNote.on("dragend", function (e) { + }).on("dragend", function (e) { e.target.openPopup(); }); }); -}); +} diff --git a/app/assets/javascripts/leaflet.extend.js.erb b/app/assets/javascripts/leaflet.extend.js.erb new file mode 100644 index 000000000..3b505302f --- /dev/null +++ b/app/assets/javascripts/leaflet.extend.js.erb @@ -0,0 +1,31 @@ +L.extend(L.LatLngBounds.prototype, { + getSize: function () { + return (this._northEast.lat - this._southWest.lat) * + (this._northEast.lng - this._southWest.lng); + }, + + wrap: function () { + return new L.LatLngBounds(this._southWest.wrap(), this._northEast.wrap()); + } +}); + +L.extend(L.Map.prototype, { + getLayersCode: function() { + var layerConfig = ''; + for (var i in this._layers) { // TODO: map.eachLayer + var layer = this._layers[i]; + if (layer.options && layer.options.code) { + layerConfig += layer.options.code; + } + } + return layerConfig; + }, + getMapBaseLayerId: function() { + for (var i in this._layers) { // TODO: map.eachLayer + var layer = this._layers[i]; + if (layer.options && layer.options.keyid) return layer.options.keyid; + } + } +}); + +L.Icon.Default.imagePath = <%= "#{asset_prefix}/images".to_json %>; diff --git a/app/assets/javascripts/leaflet.key.js b/app/assets/javascripts/leaflet.key.js new file mode 100644 index 000000000..c5124e39d --- /dev/null +++ b/app/assets/javascripts/leaflet.key.js @@ -0,0 +1,75 @@ +L.OSM.key = function (options) { + var control = L.control(options); + + control.onAdd = function (map) { + var $container = $('
') + .attr('class', 'control-key'); + + $('') + .attr('class', 'control-button') + .attr('href', '#') + .attr('title', I18n.t('javascripts.key.tooltip')) + .html('') + .on('click', toggle) + .appendTo($container); + + var $ui = $('
') + .attr('class', 'key-ui'); + + $('
') + .attr('class', 'sidebar_heading') + .appendTo($ui) + .append( + $('') + .text(I18n.t('javascripts.close')) + .attr('class', 'sidebar_close') + .attr('href', '#') + .bind('click', toggle)) + .append( + $('

') + .text(I18n.t('javascripts.key.title'))); + + var $section = $('
') + .attr('class', 'section') + .appendTo($ui); + + options.sidebar.addPane($ui); + + $ui + .on('show', shown) + .on('hide', hidden); + + function shown() { + map.on('zoomend baselayerchange', update); + $section.load('/key', update); + } + + function hidden() { + map.off('zoomend baselayerchange', update); + } + + function toggle(e) { + e.stopPropagation(); + e.preventDefault(); + options.sidebar.togglePane($ui); + } + + function update() { + var layer = map.getMapBaseLayerId(), + zoom = map.getZoom(); + + $('.mapkey-table-entry').each(function () { + var data = $(this).data(); + if (layer == data.layer && zoom >= data.zoomMin && zoom <= data.zoomMax) { + $(this).show(); + } else { + $(this).hide(); + } + }); + } + + return $container[0]; + }; + + return control; +}; diff --git a/app/assets/javascripts/leaflet.layers.js b/app/assets/javascripts/leaflet.layers.js new file mode 100644 index 000000000..e8014ac47 --- /dev/null +++ b/app/assets/javascripts/leaflet.layers.js @@ -0,0 +1,162 @@ +L.OSM.layers = function(options) { + var control = L.control(options); + + control.onAdd = function (map) { + var layers = options.layers; + + var $container = $('
') + .attr('class', 'control-layers'); + + var link = $('') + .attr('class', 'control-button') + .attr('href', '#') + .attr('title', 'Layers') + .html('') + .on('click', toggle) + .appendTo($container); + + var $ui = $('
') + .attr('class', 'layers-ui'); + + $('
') + .attr('class', 'sidebar_heading') + .appendTo($ui) + .append( + $('') + .text(I18n.t('javascripts.close')) + .attr('class', 'sidebar_close') + .attr('href', '#') + .bind('click', toggle)) + .append( + $('

') + .text(I18n.t('javascripts.map.layers.header'))); + + var baseSection = $('
') + .attr('class', 'section base-layers') + .appendTo($ui); + + list = $('