pushState based navigation between map-based layouts

This commit is contained in:
John Firebaugh 2013-10-02 16:41:44 -07:00
parent 64cb9b0a8b
commit a56d1036d5
13 changed files with 275 additions and 143 deletions

View file

@ -17,7 +17,6 @@
//= require oauth
//= require piwik
//= require map
//= require sidebar
//= require richtext
//= require geocoder
//= require querystring

View file

@ -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);
}
});
}

View file

@ -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();
});
});

View 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;
};

View file

@ -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;
};

View 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);
}
}
};

View file

@ -1,11 +0,0 @@
function closeSidebar() {
$("#sidebar")
.trigger("closed");
}
$(document).ready(function () {
$(".sidebar_close").click(function (e) {
closeSidebar();
e.preventDefault();
});
});

View file

@ -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]

View file

@ -1,5 +1,5 @@
class BrowseController < ApplicationController
layout 'map'
layout :map_layout
before_filter :authorize_web
before_filter :set_locale

View file

@ -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

View file

@ -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

View file

@ -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 -%>

View file

@ -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 )