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 oauth
|
||||||
//= require piwik
|
//= require piwik
|
||||||
//= require map
|
//= require map
|
||||||
//= require sidebar
|
|
||||||
//= require richtext
|
//= require richtext
|
||||||
//= require geocoder
|
//= require geocoder
|
||||||
//= require querystring
|
//= 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/browse
|
||||||
//= require index/export
|
//= require index/export
|
||||||
//= require index/notes
|
//= require index/notes
|
||||||
|
//= require index/changeset
|
||||||
|
//= require router
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var params = OSM.mapParams();
|
var params = OSM.mapParams();
|
||||||
|
@ -141,12 +143,12 @@ $(document).ready(function () {
|
||||||
map.getLayersCode(),
|
map.getLayersCode(),
|
||||||
map._object);
|
map._object);
|
||||||
|
|
||||||
var expiry = new Date();
|
var expiry = new Date();
|
||||||
expiry.setYear(expiry.getFullYear() + 10);
|
expiry.setYear(expiry.getFullYear() + 10);
|
||||||
$.cookie("_osm_location", cookieContent(map), { expires: expiry });
|
$.cookie("_osm_location", cookieContent(map), { expires: expiry });
|
||||||
|
|
||||||
// Trigger hash update on layer changes.
|
// Trigger hash update on layer changes.
|
||||||
map.hash.onMapMove();
|
map.hash.onMapMove();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (OSM.PIWIK) {
|
if (OSM.PIWIK) {
|
||||||
|
@ -175,10 +177,6 @@ $(document).ready(function () {
|
||||||
marker.setLatLng([params.mlat, params.mlon]).addTo(map);
|
marker.setLatLng([params.mlat, params.mlon]).addTo(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.object) {
|
|
||||||
map.addObject(params.object, { zoom: params.object_zoom });
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#homeanchor").on("click", function(e) {
|
$("#homeanchor").on("click", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -213,9 +211,50 @@ $(document).ready(function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeSearch(map);
|
initializeSearch(map);
|
||||||
initializeExport(map);
|
|
||||||
initializeBrowse(map, params);
|
initializeBrowse(map, params);
|
||||||
initializeNotes(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) {
|
OSM.Export = function(map) {
|
||||||
if (window.location.pathname == "/export") {
|
var page = {};
|
||||||
startExport();
|
|
||||||
|
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() {
|
function boundsChanged() {
|
||||||
var locationFilter = new L.LocationFilter({
|
var bounds = getBounds();
|
||||||
enableButton: false,
|
|
||||||
adjustButton: false
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
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);
|
$("#drag_box").click(enableFilter);
|
||||||
|
|
||||||
setBounds(map.getBounds());
|
update();
|
||||||
|
};
|
||||||
|
|
||||||
$("#sidebar").one("closed", function () {
|
page.unload = function() {
|
||||||
map.removeLayer(locationFilter);
|
map
|
||||||
map.off("moveend", update);
|
.removeLayer(locationFilter)
|
||||||
locationFilter.off("change", update);
|
.off("moveend", update);
|
||||||
});
|
|
||||||
|
|
||||||
function getBounds() {
|
$("#export_tab").removeClass("current");
|
||||||
return L.latLngBounds(L.latLng($("#minlat").val(), $("#minlon").val()),
|
};
|
||||||
L.latLng($("#maxlat").val(), $("#maxlon").val()));
|
|
||||||
}
|
|
||||||
|
|
||||||
function boundsChanged() {
|
return page;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
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
|
request.body.rewind
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def map_layout
|
||||||
|
request.xhr? ? false : 'map'
|
||||||
|
end
|
||||||
|
|
||||||
def preferred_editor
|
def preferred_editor
|
||||||
editor = if params[:editor]
|
editor = if params[:editor]
|
||||||
params[:editor]
|
params[:editor]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class BrowseController < ApplicationController
|
class BrowseController < ApplicationController
|
||||||
layout 'map'
|
layout :map_layout
|
||||||
|
|
||||||
before_filter :authorize_web
|
before_filter :authorize_web
|
||||||
before_filter :set_locale
|
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)
|
@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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class SiteController < ApplicationController
|
class SiteController < ApplicationController
|
||||||
layout 'site'
|
layout 'site'
|
||||||
layout 'map', :only => [:index, :export]
|
layout :map_layout, :only => [:index, :export]
|
||||||
|
|
||||||
before_filter :authorize_web
|
before_filter :authorize_web
|
||||||
before_filter :set_locale
|
before_filter :set_locale
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
<% content_for :head do -%>
|
<% content_for :head do -%>
|
||||||
<%= javascript_include_tag "changeset" %>
|
|
||||||
|
|
||||||
<% unless params[:friends] or params[:nearby] -%>
|
<% unless params[:friends] or params[:nearby] -%>
|
||||||
<%= auto_discovery_link_tag :atom, params.merge({ :page => nil, :action => :feed }) %>
|
<%= auto_discovery_link_tag :atom, params.merge({ :page => nil, :action => :feed }) %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
|
|
|
@ -69,7 +69,7 @@ OpenStreetMap::Application.configure do
|
||||||
|
|
||||||
# Precompile additional assets.
|
# Precompile additional assets.
|
||||||
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
# 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( 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-ltr.css small-ltr.css print-ltr.css )
|
||||||
config.assets.precompile += %w( large-rtl.css small-rtl.css print-rtl.css )
|
config.assets.precompile += %w( large-rtl.css small-rtl.css print-rtl.css )
|
||||||
|
|
Loading…
Add table
Reference in a new issue