pushState based navigation between map-based layouts
This commit is contained in:
parent
64cb9b0a8b
commit
a56d1036d5
13 changed files with 275 additions and 143 deletions
|
@ -17,7 +17,6 @@
|
|||
//= require oauth
|
||||
//= require piwik
|
||||
//= require map
|
||||
//= require sidebar
|
||||
//= require richtext
|
||||
//= require geocoder
|
||||
//= require querystring
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
function initializeChangesets(map) {
|
||||
var changesets = [], rects = {};
|
||||
|
||||
var group = L.featureGroup().addTo(map);
|
||||
|
||||
$("[data-changeset]").each(function () {
|
||||
var changeset = $(this).data('changeset');
|
||||
if (changeset.bbox) {
|
||||
changeset.bounds = L.latLngBounds([changeset.bbox.minlat, changeset.bbox.minlon],
|
||||
[changeset.bbox.maxlat, changeset.bbox.maxlon]);
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
|
||||
changesets.sort(function (a, b) {
|
||||
return b.bounds.getSize() - a.bounds.getSize();
|
||||
});
|
||||
|
||||
for (var i = 0; i < changesets.length; ++i) {
|
||||
var changeset = changesets[i],
|
||||
rect = L.rectangle(changeset.bounds,
|
||||
{weight: 2, color: "#ee9900", fillColor: "#ffff55", fillOpacity: 0});
|
||||
rect.id = changeset.id;
|
||||
rects[changeset.id] = rect;
|
||||
rect.addTo(group);
|
||||
}
|
||||
|
||||
function highlightChangeset(id) {
|
||||
rects[id].setStyle({fillOpacity: 0.5});
|
||||
$("#changeset_" + id).addClass("selected");
|
||||
}
|
||||
|
||||
function unHighlightChangeset(id) {
|
||||
rects[id].setStyle({fillOpacity: 0});
|
||||
$("#changeset_" + id).removeClass("selected");
|
||||
}
|
||||
|
||||
group.on({
|
||||
mouseover: function (e) {
|
||||
highlightChangeset(e.layer.id);
|
||||
},
|
||||
mouseout: function (e) {
|
||||
unHighlightChangeset(e.layer.id);
|
||||
}
|
||||
});
|
||||
|
||||
$("[data-changeset]").on({
|
||||
mouseover: function () {
|
||||
highlightChangeset($(this).data("changeset").id);
|
||||
},
|
||||
mouseout: function () {
|
||||
unHighlightChangeset($(this).data("changeset").id);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -9,6 +9,8 @@
|
|||
//= require index/browse
|
||||
//= require index/export
|
||||
//= require index/notes
|
||||
//= require index/changeset
|
||||
//= require router
|
||||
|
||||
$(document).ready(function () {
|
||||
var params = OSM.mapParams();
|
||||
|
@ -141,12 +143,12 @@ $(document).ready(function () {
|
|||
map.getLayersCode(),
|
||||
map._object);
|
||||
|
||||
var expiry = new Date();
|
||||
expiry.setYear(expiry.getFullYear() + 10);
|
||||
$.cookie("_osm_location", cookieContent(map), { expires: expiry });
|
||||
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();
|
||||
// Trigger hash update on layer changes.
|
||||
map.hash.onMapMove();
|
||||
});
|
||||
|
||||
if (OSM.PIWIK) {
|
||||
|
@ -175,10 +177,6 @@ $(document).ready(function () {
|
|||
marker.setLatLng([params.mlat, params.mlon]).addTo(map);
|
||||
}
|
||||
|
||||
if (params.object) {
|
||||
map.addObject(params.object, { zoom: params.object_zoom });
|
||||
}
|
||||
|
||||
$("#homeanchor").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
@ -213,9 +211,50 @@ $(document).ready(function () {
|
|||
}
|
||||
|
||||
initializeSearch(map);
|
||||
initializeExport(map);
|
||||
initializeBrowse(map, params);
|
||||
initializeNotes(map, params);
|
||||
|
||||
if ('undefined' !== typeof initializeChangesets) initializeChangesets(map);
|
||||
OSM.Index = function(map) {
|
||||
var page = {};
|
||||
|
||||
page.pushstate = page.popstate = function(path) {
|
||||
$("#view_tab").addClass("current");
|
||||
$('#sidebar_content').load(path);
|
||||
};
|
||||
|
||||
page.unload = function() {
|
||||
$("#view_tab").removeClass("current");
|
||||
};
|
||||
|
||||
return page;
|
||||
};
|
||||
|
||||
OSM.Browse = function(map) {
|
||||
var page = {};
|
||||
|
||||
page.pushstate = page.popstate = function(path) {
|
||||
$('#sidebar_content').load(path, page.load);
|
||||
};
|
||||
|
||||
page.load = function() {
|
||||
map.addObject(OSM.mapParams().object, {zoom: true});
|
||||
};
|
||||
|
||||
page.unload = function() {
|
||||
map.removeObject();
|
||||
};
|
||||
|
||||
return page;
|
||||
};
|
||||
|
||||
var router = OSM.Router({
|
||||
"/": OSM.Index(map),
|
||||
"/export": OSM.Export(map),
|
||||
"/browse/changesets": OSM.ChangesetList(map),
|
||||
"/browse/:type/:id(/history)": OSM.Browse(map)
|
||||
});
|
||||
|
||||
$(document).on("click", "a", function(e) {
|
||||
if (router(this.pathname + this.search + this.hash)) e.preventDefault();
|
||||
});
|
||||
});
|
||||
|
|
75
app/assets/javascripts/index/changeset.js
Normal file
75
app/assets/javascripts/index/changeset.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
OSM.ChangesetList = function(map) {
|
||||
var page = {};
|
||||
|
||||
var group = L.featureGroup()
|
||||
.on({
|
||||
mouseover: function (e) {
|
||||
highlightChangeset(e.layer.id);
|
||||
},
|
||||
mouseout: function (e) {
|
||||
unHighlightChangeset(e.layer.id);
|
||||
}
|
||||
});
|
||||
|
||||
group.getLayerId = function(layer) {
|
||||
return layer.id;
|
||||
};
|
||||
|
||||
function highlightChangeset(id) {
|
||||
group.getLayer(id).setStyle({fillOpacity: 0.5});
|
||||
$("#changeset_" + id).addClass("selected");
|
||||
}
|
||||
|
||||
function unHighlightChangeset(id) {
|
||||
group.getLayer(id).setStyle({fillOpacity: 0});
|
||||
$("#changeset_" + id).removeClass("selected");
|
||||
}
|
||||
|
||||
page.pushstate = page.popstate = function(path) {
|
||||
$("#history_tab").addClass("current");
|
||||
$('#sidebar_content').load(path, page.load);
|
||||
};
|
||||
|
||||
page.load = function() {
|
||||
map.addLayer(group);
|
||||
|
||||
var changesets = [];
|
||||
$("[data-changeset]").each(function () {
|
||||
var changeset = $(this).data('changeset');
|
||||
if (changeset.bbox) {
|
||||
changeset.bounds = L.latLngBounds([changeset.bbox.minlat, changeset.bbox.minlon],
|
||||
[changeset.bbox.maxlat, changeset.bbox.maxlon]);
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
|
||||
changesets.sort(function (a, b) {
|
||||
return b.bounds.getSize() - a.bounds.getSize();
|
||||
});
|
||||
|
||||
for (var i = 0; i < changesets.length; ++i) {
|
||||
var changeset = changesets[i],
|
||||
rect = L.rectangle(changeset.bounds,
|
||||
{weight: 2, color: "#ee9900", fillColor: "#ffff55", fillOpacity: 0});
|
||||
rect.id = changeset.id;
|
||||
rect.addTo(group);
|
||||
}
|
||||
|
||||
$("[data-changeset]").on({
|
||||
mouseover: function () {
|
||||
highlightChangeset($(this).data("changeset").id);
|
||||
},
|
||||
mouseout: function () {
|
||||
unHighlightChangeset($(this).data("changeset").id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
page.unload = function() {
|
||||
map.removeLayer(group);
|
||||
group.clearLayers();
|
||||
$("#history_tab").removeClass("current");
|
||||
};
|
||||
|
||||
return page;
|
||||
};
|
|
@ -1,71 +1,76 @@
|
|||
function initializeExport(map) {
|
||||
if (window.location.pathname == "/export") {
|
||||
startExport();
|
||||
OSM.Export = function(map) {
|
||||
var page = {};
|
||||
|
||||
var locationFilter = new L.LocationFilter({
|
||||
enableButton: false,
|
||||
adjustButton: false
|
||||
}).on("change", update);
|
||||
|
||||
function getBounds() {
|
||||
return L.latLngBounds(
|
||||
L.latLng($("#minlat").val(), $("#minlon").val()),
|
||||
L.latLng($("#maxlat").val(), $("#maxlon").val()));
|
||||
}
|
||||
|
||||
function startExport() {
|
||||
var locationFilter = new L.LocationFilter({
|
||||
enableButton: false,
|
||||
adjustButton: false
|
||||
}).addTo(map);
|
||||
function boundsChanged() {
|
||||
var bounds = getBounds();
|
||||
|
||||
update();
|
||||
map.fitBounds(bounds);
|
||||
locationFilter.setBounds(bounds);
|
||||
|
||||
locationFilter.on("change", update);
|
||||
enableFilter();
|
||||
validateControls();
|
||||
}
|
||||
|
||||
map.on("moveend", update);
|
||||
function enableFilter() {
|
||||
if (!locationFilter.getBounds().isValid()) {
|
||||
locationFilter.setBounds(map.getBounds().pad(-0.2));
|
||||
}
|
||||
|
||||
$("#maxlat,#minlon,#maxlon,#minlat").change(boundsChanged);
|
||||
$("#drag_box").hide();
|
||||
locationFilter.enable();
|
||||
}
|
||||
|
||||
function update() {
|
||||
setBounds(locationFilter.isEnabled() ? locationFilter.getBounds() : map.getBounds());
|
||||
validateControls();
|
||||
}
|
||||
|
||||
function setBounds(bounds) {
|
||||
var precision = zoomPrecision(map.getZoom());
|
||||
$("#minlon").val(bounds.getWest().toFixed(precision));
|
||||
$("#minlat").val(bounds.getSouth().toFixed(precision));
|
||||
$("#maxlon").val(bounds.getEast().toFixed(precision));
|
||||
$("#maxlat").val(bounds.getNorth().toFixed(precision));
|
||||
}
|
||||
|
||||
function validateControls() {
|
||||
$("#export_osm_too_large").toggle(getBounds().getSize() > OSM.MAX_REQUEST_AREA);
|
||||
}
|
||||
|
||||
page.pushstate = page.popstate = function(path) {
|
||||
$("#export_tab").addClass("current");
|
||||
$('#sidebar_content').load(path, page.load);
|
||||
};
|
||||
|
||||
page.load = function() {
|
||||
map
|
||||
.addLayer(locationFilter)
|
||||
.on("moveend", update);
|
||||
|
||||
$("#maxlat, #minlon, #maxlon, #minlat").change(boundsChanged);
|
||||
$("#drag_box").click(enableFilter);
|
||||
|
||||
setBounds(map.getBounds());
|
||||
update();
|
||||
};
|
||||
|
||||
$("#sidebar").one("closed", function () {
|
||||
map.removeLayer(locationFilter);
|
||||
map.off("moveend", update);
|
||||
locationFilter.off("change", update);
|
||||
});
|
||||
page.unload = function() {
|
||||
map
|
||||
.removeLayer(locationFilter)
|
||||
.off("moveend", update);
|
||||
|
||||
function getBounds() {
|
||||
return L.latLngBounds(L.latLng($("#minlat").val(), $("#minlon").val()),
|
||||
L.latLng($("#maxlat").val(), $("#maxlon").val()));
|
||||
}
|
||||
$("#export_tab").removeClass("current");
|
||||
};
|
||||
|
||||
function boundsChanged() {
|
||||
var bounds = getBounds();
|
||||
|
||||
map.fitBounds(bounds);
|
||||
locationFilter.setBounds(bounds);
|
||||
|
||||
enableFilter();
|
||||
validateControls();
|
||||
}
|
||||
|
||||
function enableFilter() {
|
||||
if (!locationFilter.getBounds().isValid()) {
|
||||
locationFilter.setBounds(map.getBounds().pad(-0.2));
|
||||
}
|
||||
|
||||
$("#drag_box").hide();
|
||||
locationFilter.enable();
|
||||
}
|
||||
|
||||
function update() {
|
||||
setBounds(locationFilter.isEnabled() ? locationFilter.getBounds() : map.getBounds());
|
||||
validateControls();
|
||||
}
|
||||
|
||||
function setBounds(bounds) {
|
||||
var precision = zoomPrecision(map.getZoom());
|
||||
$("#minlon").val(bounds.getWest().toFixed(precision));
|
||||
$("#minlat").val(bounds.getSouth().toFixed(precision));
|
||||
$("#maxlon").val(bounds.getEast().toFixed(precision));
|
||||
$("#maxlat").val(bounds.getNorth().toFixed(precision));
|
||||
}
|
||||
|
||||
function validateControls() {
|
||||
$("#export_osm_too_large").toggle(getBounds().getSize() > OSM.MAX_REQUEST_AREA);
|
||||
}
|
||||
}
|
||||
}
|
||||
return page;
|
||||
};
|
||||
|
|
78
app/assets/javascripts/router.js
Normal file
78
app/assets/javascripts/router.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
OSM.Router = function(rts) {
|
||||
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
|
||||
var optionalParam = /\((.*?)\)/g;
|
||||
var namedParam = /(\(\?)?:\w+/g;
|
||||
var splatParam = /\*\w+/g;
|
||||
|
||||
function Route(path, controller) {
|
||||
var regexp = new RegExp('^' +
|
||||
path.replace(escapeRegExp, '\\$&')
|
||||
.replace(optionalParam, '(?:$1)?')
|
||||
.replace(namedParam, function(match, optional){
|
||||
return optional ? match : '([^\/]+)';
|
||||
})
|
||||
.replace(splatParam, '(.*?)') + '(?:$|[?#])');
|
||||
|
||||
var route = {};
|
||||
|
||||
route.match = function(path) {
|
||||
return regexp.test(path);
|
||||
};
|
||||
|
||||
route.run = function(action, path) {
|
||||
var params = [];
|
||||
|
||||
if (path) {
|
||||
params = regexp.exec(path).map(function(param, i) {
|
||||
return (i > 0 && param) ? decodeURIComponent(param) : param;
|
||||
});
|
||||
}
|
||||
|
||||
(controller[action] || $.noop).apply(controller, params);
|
||||
};
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
var routes = [];
|
||||
for (var r in rts)
|
||||
routes.push(Route(r, rts[r]));
|
||||
|
||||
routes.recognize = function(path) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i].match(path)) return this[i];
|
||||
}
|
||||
};
|
||||
|
||||
var currentPath = window.location.pathname,
|
||||
currentRoute = routes.recognize(currentPath);
|
||||
|
||||
currentRoute.run('load', currentPath);
|
||||
|
||||
if (window.history && window.history.pushState) {
|
||||
$(window).on('popstate', function() {
|
||||
var path = window.location.pathname;
|
||||
if (path === currentPath) return;
|
||||
currentRoute.run('unload');
|
||||
currentPath = path;
|
||||
currentRoute = routes.recognize(currentPath);
|
||||
currentRoute.run('popstate', currentPath);
|
||||
});
|
||||
|
||||
return function (url) {
|
||||
var path = url.replace(/#.*/, ''),
|
||||
route = routes.recognize(path);
|
||||
if (!route) return false;
|
||||
window.history.pushState({}, document.title, url);
|
||||
currentRoute.run('unload');
|
||||
currentPath = path;
|
||||
currentRoute = route;
|
||||
currentRoute.run('pushstate', currentPath);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return function (url) {
|
||||
window.location.assign(url);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
function closeSidebar() {
|
||||
$("#sidebar")
|
||||
.trigger("closed");
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$(".sidebar_close").click(function (e) {
|
||||
closeSidebar();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
|
@ -422,6 +422,10 @@ class ApplicationController < ActionController::Base
|
|||
request.body.rewind
|
||||
end
|
||||
|
||||
def map_layout
|
||||
request.xhr? ? false : 'map'
|
||||
end
|
||||
|
||||
def preferred_editor
|
||||
editor = if params[:editor]
|
||||
params[:editor]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class BrowseController < ApplicationController
|
||||
layout 'map'
|
||||
layout :map_layout
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
|
|
|
@ -321,7 +321,7 @@ class ChangesetController < ApplicationController
|
|||
|
||||
@edits = changesets.order("changesets.created_at DESC").offset((@page - 1) * @page_size).limit(@page_size).preload(:user, :changeset_tags)
|
||||
|
||||
render :action => :list, :layout => 'map'
|
||||
render :action => :list, :layout => map_layout
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class SiteController < ApplicationController
|
||||
layout 'site'
|
||||
layout 'map', :only => [:index, :export]
|
||||
layout :map_layout, :only => [:index, :export]
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
<% content_for :head do -%>
|
||||
<%= javascript_include_tag "changeset" %>
|
||||
|
||||
<% unless params[:friends] or params[:nearby] -%>
|
||||
<%= auto_discovery_link_tag :atom, params.merge({ :page => nil, :action => :feed }) %>
|
||||
<% end -%>
|
||||
|
|
|
@ -69,7 +69,7 @@ OpenStreetMap::Application.configure do
|
|||
|
||||
# Precompile additional assets.
|
||||
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
||||
config.assets.precompile += %w( index.js browse.js changeset.js welcome.js )
|
||||
config.assets.precompile += %w( index.js browse.js welcome.js )
|
||||
config.assets.precompile += %w( user.js diary_entry.js pngfix.js swfobject.js )
|
||||
config.assets.precompile += %w( large-ltr.css small-ltr.css print-ltr.css )
|
||||
config.assets.precompile += %w( large-rtl.css small-rtl.css print-rtl.css )
|
||||
|
|
Loading…
Add table
Reference in a new issue