From: John Firebaugh Date: Mon, 11 Nov 2013 18:27:37 +0000 (-0800) Subject: Use our own hash implementation X-Git-Tag: live~5234^2~122 X-Git-Url: https://git.openstreetmap.org./rails.git/commitdiff_plain/a805e0b545a37b19a4162e71850bef9aba9d6628 Use our own hash implementation We need more flexibility than L.Hash provides. --- diff --git a/Vendorfile b/Vendorfile index c1242beb7..ec3ea6a14 100644 --- a/Vendorfile +++ b/Vendorfile @@ -32,10 +32,6 @@ folder 'vendor/assets' do from 'git://github.com/jfirebaugh/leaflet-osm.git' do file 'leaflet.osm.js', 'leaflet-osm.js' end - - from 'git://github.com/mlevans/leaflet-hash.git' do - file 'leaflet.hash.js', 'leaflet-hash.js' - end end folder 'ohauth' do diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index f66f231ef..2c186c909 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -9,7 +9,6 @@ //= require osm //= require leaflet //= require leaflet.osm -//= require leaflet.hash //= require leaflet.map //= require leaflet.zoom //= require leaflet.locationfilter diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index 6c1c1610f..2d9300247 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -23,21 +23,7 @@ $(document).ready(function () { map.attributionControl.setPrefix(''); - map.hash = L.hash(map); - - $(window).on('popstate', function(e) { - // popstate is triggered when the hash changes as well as on actual navigation - // events. We want to update the hash on the latter and not the former. - if (e.originalEvent.state) { - map.hash.update(); - } - }); - - map.updateLayers(params); - - $(window).on("hashchange", function () { - map.updateLayers(OSM.mapParams()); - }); + map.updateLayers(params.layers); map.on("baselayerchange", function (e) { if (map.getZoom() > e.layer.options.maxZoom) { @@ -110,9 +96,6 @@ $(document).ready(function () { var expiry = new Date(); expiry.setYear(expiry.getFullYear() + 10); $.cookie("_osm_location", cookieContent(map), { expires: expiry }); - - // Trigger hash update on layer changes. - map.hash.onMapMove(); }); if (OSM.PIWIK) { @@ -225,7 +208,7 @@ $(document).ready(function () { var history = OSM.History(map), note = OSM.Note(map); - OSM.route = OSM.Router({ + OSM.route = OSM.Router(map, { "/": OSM.Index(map), "/search": OSM.Search(map), "/export": OSM.Export(map), diff --git a/app/assets/javascripts/leaflet.layers.js b/app/assets/javascripts/leaflet.layers.js index fd493ee32..2bb4c5c1b 100644 --- a/app/assets/javascripts/leaflet.layers.js +++ b/app/assets/javascripts/leaflet.layers.js @@ -140,6 +140,7 @@ L.OSM.layers = function(options) { } else { map.removeLayer(layer); } + map.fire('overlaylayerchange', {layer: layer}); }); map.on('layeradd layerremove', function() { diff --git a/app/assets/javascripts/leaflet.map.js.erb b/app/assets/javascripts/leaflet.map.js.erb index 8a0d537b5..63fab5306 100644 --- a/app/assets/javascripts/leaflet.map.js.erb +++ b/app/assets/javascripts/leaflet.map.js.erb @@ -56,8 +56,8 @@ L.OSM.Map = L.Map.extend({ this.dataLayer.options.code = 'D'; }, - updateLayers: function(params) { - var layerParam = params.layers || "M"; + updateLayers: function(layerParam) { + layerParam = layerParam || "M"; var layersAdded = ""; for (var i = this.baseLayers.length - 1; i >= 0; i--) { @@ -243,9 +243,6 @@ L.extend(L.Icon.Default.prototype, { } }); -L.Hash.prototype.parseHash = OSM.parseHash; -L.Hash.prototype.formatHash = OSM.formatHash; - function getUserIcon(url) { return L.icon({ iconUrl: url || <%= asset_path('marker-red.png').to_json %>, diff --git a/app/assets/javascripts/osm.js.erb b/app/assets/javascripts/osm.js.erb index ad6d5cb9c..cb3737351 100644 --- a/app/assets/javascripts/osm.js.erb +++ b/app/assets/javascripts/osm.js.erb @@ -101,15 +101,41 @@ OSM = { }, parseHash: function(hash) { - if (hash.indexOf('#') === 0) { - hash = hash.substr(1); + var i = hash.indexOf('#'); + if (i < 0) { + return false; } + + hash = hash.substr(i + 1); + if (hash === '') { return false; } + hash = querystring.parse(hash); - var args = L.Hash.parseHash(hash.map || '') || {}; - if (hash.layers) args.layers = hash.layers; + + var args = hash.map.split("/"); + if (args.length !== 3) { + return false; + } + + var zoom = parseInt(args[0], 10), + lat = parseFloat(args[1]), + lon = parseFloat(args[2]); + + if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) { + return false; + } + + args = { + center: new L.LatLng(lat, lon), + zoom: zoom + }; + + if (hash.layers) { + args.layers = hash.layers; + } + return args; }, diff --git a/app/assets/javascripts/router.js b/app/assets/javascripts/router.js index 7a61af106..606308982 100644 --- a/app/assets/javascripts/router.js +++ b/app/assets/javascripts/router.js @@ -1,4 +1,4 @@ -OSM.Router = function(rts) { +OSM.Router = function(map, rts) { var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; var optionalParam = /\((.*?)\)/g; var namedParam = /(\(\?)?:\w+/g; @@ -45,14 +45,39 @@ OSM.Router = function(rts) { }; var currentPath = window.location.pathname + window.location.search, - currentRoute = routes.recognize(currentPath); + currentRoute = routes.recognize(currentPath), + currentHash = location.hash || OSM.formatHash(map); currentRoute.run('load', currentPath); + var stateChange; + + map.on('moveend baselayerchange overlaylayerchange', function() { + var hash = OSM.formatHash(map); + if (hash === currentHash) return; + currentHash = hash; + stateChange(OSM.parseHash(hash), hash); + }); + + $(window).on('hashchange', function() { + var hash = location.hash; + if (hash === currentHash) return; + currentHash = hash; + var state = OSM.parseHash(hash); + if (!state) return; + map.setView(state.center, state.zoom); + map.updateLayers(state.layers); + stateChange(state, hash); + }); + if (window.history && window.history.pushState) { + stateChange = function(state, hash) { + window.history.replaceState(state, document.title, hash); + }; + // Set a non-null initial state, so that the e.originalEvent.state // check below works correctly when going back to the initial page. - window.history.replaceState({}, document.title, window.location); + stateChange(OSM.parseHash(currentHash), currentPath + currentHash); $(window).on('popstate', function(e) { if (!e.originalEvent.state) return; // Is it a real popstate event or just a hash change? @@ -62,13 +87,16 @@ OSM.Router = function(rts) { currentPath = path; currentRoute = routes.recognize(currentPath); currentRoute.run('popstate', currentPath); + var state = e.originalEvent.state; + map.setView(state.center, state.zoom); + map.updateLayers(state.layers); }); return function (url) { var path = url.replace(/#.*/, ''), route = routes.recognize(path); if (!route) return false; - window.history.pushState({}, document.title, url); + window.history.pushState(OSM.parseHash(url) || {}, document.title, url); currentRoute.run('unload'); currentPath = path; currentRoute = route; @@ -76,6 +104,10 @@ OSM.Router = function(rts) { return true; } } else { + stateChange = function(state, hash) { + window.location.replace(hash); + }; + return function (url) { window.location.assign(url); } diff --git a/vendor/assets/leaflet/leaflet.hash.js b/vendor/assets/leaflet/leaflet.hash.js deleted file mode 100644 index 26bb8abf6..000000000 --- a/vendor/assets/leaflet/leaflet.hash.js +++ /dev/null @@ -1,162 +0,0 @@ -(function(window) { - var HAS_HASHCHANGE = (function() { - var doc_mode = window.documentMode; - return ('onhashchange' in window) && - (doc_mode === undefined || doc_mode > 7); - })(); - - L.Hash = function(map) { - this.onHashChange = L.Util.bind(this.onHashChange, this); - - if (map) { - this.init(map); - } - }; - - L.Hash.parseHash = function(hash) { - if(hash.indexOf('#') === 0) { - hash = hash.substr(1); - } - var args = hash.split("/"); - if (args.length == 3) { - var zoom = parseInt(args[0], 10), - lat = parseFloat(args[1]), - lon = parseFloat(args[2]); - if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) { - return false; - } else { - return { - center: new L.LatLng(lat, lon), - zoom: zoom - }; - } - } else { - return false; - } - }; - - L.Hash.formatHash = function(map) { - var center = map.getCenter(), - zoom = map.getZoom(), - precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)); - - return "#" + [zoom, - center.lat.toFixed(precision), - center.lng.toFixed(precision) - ].join("/"); - }, - - L.Hash.prototype = { - map: null, - lastHash: null, - - parseHash: L.Hash.parseHash, - formatHash: L.Hash.formatHash, - - init: function(map) { - this.map = map; - - // reset the hash - this.lastHash = null; - this.onHashChange(); - - if (!this.isListening) { - this.startListening(); - } - }, - - remove: function() { - if (this.changeTimeout) { - clearTimeout(this.changeTimeout); - } - - if (this.isListening) { - this.stopListening(); - } - - this.map = null; - }, - - onMapMove: function() { - // bail if we're moving the map (updating from a hash), - // or if the map is not yet loaded - - if (this.movingMap || !this.map._loaded) { - return false; - } - - var hash = this.formatHash(this.map); - if (this.lastHash != hash) { - location.replace(hash); - this.lastHash = hash; - } - }, - - movingMap: false, - update: function() { - var hash = location.hash; - if (hash === this.lastHash) { - return; - } - var parsed = this.parseHash(hash); - if (parsed) { - this.movingMap = true; - - this.map.setView(parsed.center, parsed.zoom); - - this.movingMap = false; - } else { - this.onMapMove(this.map); - } - }, - - // defer hash change updates every 100ms - changeDefer: 100, - changeTimeout: null, - onHashChange: function() { - // throttle calls to update() so that they only happen every - // `changeDefer` ms - if (!this.changeTimeout) { - var that = this; - this.changeTimeout = setTimeout(function() { - that.update(); - that.changeTimeout = null; - }, this.changeDefer); - } - }, - - isListening: false, - hashChangeInterval: null, - startListening: function() { - this.map.on("moveend", this.onMapMove, this); - - if (HAS_HASHCHANGE) { - L.DomEvent.addListener(window, "hashchange", this.onHashChange); - } else { - clearInterval(this.hashChangeInterval); - this.hashChangeInterval = setInterval(this.onHashChange, 50); - } - this.isListening = true; - }, - - stopListening: function() { - this.map.off("moveend", this.onMapMove, this); - - if (HAS_HASHCHANGE) { - L.DomEvent.removeListener(window, "hashchange", this.onHashChange); - } else { - clearInterval(this.hashChangeInterval); - } - this.isListening = false; - } - }; - L.hash = function(map) { - return new L.Hash(map); - }; - L.Map.prototype.addHash = function() { - this._hash = L.hash(this); - }; - L.Map.prototype.removeHash = function() { - this._hash.remove(); - }; -})(window);