aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm15
-rw-r--r--perllib/FixMyStreet/App/Controller/Location.pm15
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm13
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm9
-rw-r--r--perllib/FixMyStreet/Map.pm18
-rw-r--r--templates/web/base/around/on_map_list_items.html31
-rwxr-xr-xtemplates/web/base/around/tabbed_lists.html12
-rw-r--r--templates/web/base/pagination.html2
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js9
-rw-r--r--web/js/map-OpenLayers.js100
11 files changed, 177 insertions, 48 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 419dff1d2..115761edf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,7 @@
- Always show pagination figures even if only one page. #1787
- Report pages list more updates to a report. #1806
- Clearer wording and more prominent email input on alert page. #1829
+ - Paginate reports on `/around`. #1805 #1577 #525
- Cobrands can implement `hide_areas_on_reports` to hide outline on map.
- Templates to allow extra messages through problem confirmation. #1837
- Optimised sprite file down from 97 KB to 36 KB. #1852
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index b870c1a19..d1bf2d950 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -49,7 +49,8 @@ sub index : Path : Args(0) {
my $partial_report = $c->forward('load_partial');
# Try to create a location for whatever we have
- my $ret = $c->forward('/location/determine_location_from_coords')
+ my $ret = $c->forward('/location/determine_location_from_bbox')
+ || $c->forward('/location/determine_location_from_coords')
|| $c->forward('/location/determine_location_from_pc');
unless ($ret) {
return $c->res->redirect('/') unless $c->get_param('pc') || $partial_report;
@@ -174,7 +175,11 @@ sub display_location : Private {
my $latitude = $c->stash->{latitude};
my $longitude = $c->stash->{longitude};
- $c->forward('map_features', [ { latitude => $latitude, longitude => $longitude } ] );
+ if (my $bbox = $c->stash->{bbox}) {
+ $c->forward('map_features', [ { bbox => $bbox } ]);
+ } else {
+ $c->forward('map_features', [ { latitude => $latitude, longitude => $longitude } ]);
+ }
FixMyStreet::Map::display_map(
$c,
@@ -285,8 +290,8 @@ the map.
sub ajax : Private {
my ( $self, $c ) = @_;
- my $bbox = $c->get_param('bbox');
- unless ($bbox) {
+ my $ret = $c->forward('/location/determine_location_from_bbox');
+ unless ($ret) {
$c->res->status(404);
$c->res->body('');
return;
@@ -295,7 +300,7 @@ sub ajax : Private {
my %valid_categories = map { $_ => 1 } $c->get_param_list('filter_category', 1);
$c->stash->{filter_category} = \%valid_categories;
- $c->forward('map_features', [ { bbox => $bbox } ]);
+ $c->forward('map_features', [ { bbox => $c->stash->{bbox} } ]);
$c->forward('/reports/ajax', [ 'around/on_map_list_items.html' ]);
}
diff --git a/perllib/FixMyStreet/App/Controller/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm
index cb2077ede..8d5b0b147 100644
--- a/perllib/FixMyStreet/App/Controller/Location.pm
+++ b/perllib/FixMyStreet/App/Controller/Location.pm
@@ -110,6 +110,21 @@ sub determine_location_from_pc : Private {
return;
}
+sub determine_location_from_bbox : Private {
+ my ( $self, $c ) = @_;
+
+ my $bbox = $c->get_param('bbox');
+ return unless $bbox;
+
+ my ($min_lon, $min_lat, $max_lon, $max_lat) = split /,/, $bbox;
+ my $longitude = ($max_lon + $min_lon ) / 2;
+ my $latitude = ($max_lat + $min_lat ) / 2;
+ $c->stash->{bbox} = $bbox;
+ $c->stash->{latitude} = $latitude;
+ $c->stash->{longitude} = $longitude;
+ return $c->forward('check_location');
+}
+
=head2 check_location
Just make sure that for UK installs, our co-ordinates are indeed in the UK.
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 3913f4906..da5420500 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -525,20 +525,19 @@ sub nearby_json : Private {
);
my @pins = map {
my $p = $_->problem;
- my $colour = $c->cobrand->pin_colour( $p, 'around' );
- [ $p->latitude, $p->longitude,
- $colour,
- $p->id, $p->title_safe, 'small', JSON->false
+ $p = $p->pin_data($c, 'around');
+ [ $p->{latitude}, $p->{longitude}, $p->{colour},
+ $p->{id}, $p->{title}, 'small', JSON->false
]
} @$nearby;
- my $on_map_list_html = $c->render_fragment(
+ my $list_html = $c->render_fragment(
'around/on_map_list_items.html',
- { on_map => [], around_map => $nearby }
+ { around_map => [], on_map => $nearby }
);
my $json = { pins => \@pins };
- $json->{reports_list} = $on_map_list_html if $on_map_list_html;
+ $json->{reports_list} = $list_html if $list_html;
my $body = encode_json($json);
$c->res->content_type('application/json; charset=utf-8');
$c->res->body($body);
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index 5cbf4e8f0..ae45351c4 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -140,10 +140,11 @@ sub _recent {
# Problems around a location
sub around_map {
- my ( $rs, %p) = @_;
+ my ( $rs, $c, %p) = @_;
my $attr = {
order_by => $p{order},
};
+ $attr->{rows} = $c->cobrand->reports_per_page;
unless ( $p{states} ) {
$p{states} = FixMyStreet::DB::Result::Problem->visible_states();
@@ -157,8 +158,10 @@ sub around_map {
};
$q->{category} = $p{categories} if $p{categories} && @{$p{categories}};
- my @problems = mySociety::Locale::in_gb_locale { $rs->search( $q, $attr )->include_comment_counts->all };
- return \@problems;
+ my $problems = mySociety::Locale::in_gb_locale {
+ $rs->search( $q, $attr )->include_comment_counts->page($p{page});
+ };
+ return $problems;
}
# Admin functions
diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm
index 46a098117..e0e3c3128 100644
--- a/perllib/FixMyStreet/Map.pm
+++ b/perllib/FixMyStreet/Map.pm
@@ -88,15 +88,21 @@ sub map_features {
$p{latitude} = ($p{max_lat} + $p{min_lat} ) / 2;
}
- my $on_map = $c->cobrand->problems_on_map->around_map( %p );
+ $p{page} = $c->get_param('p') || 1;
+ my $on_map = $c->cobrand->problems_on_map->around_map( $c, %p );
+ my $pager = $c->stash->{pager} = $on_map->pager;
+ $on_map = [ $on_map->all ];
my $dist = FixMyStreet::Gaze::get_radius_containing_population( $p{latitude}, $p{longitude} );
- my $limit = 20;
- my @ids = map { $_->id } @$on_map;
- my $nearby = $c->model('DB::Nearby')->nearby(
- $c, $dist, \@ids, $limit, @p{"latitude", "longitude", "categories", "states"}
- );
+ my $nearby;
+ if (@$on_map < $pager->entries_per_page && $pager->current_page == 1) {
+ my $limit = 20;
+ my @ids = map { $_->id } @$on_map;
+ $nearby = $c->model('DB::Nearby')->nearby(
+ $c, $dist, \@ids, $limit, @p{"latitude", "longitude", "categories", "states"}
+ );
+ }
return ( $on_map, $nearby, $dist );
}
diff --git a/templates/web/base/around/on_map_list_items.html b/templates/web/base/around/on_map_list_items.html
index b7257030d..fafe7f433 100644
--- a/templates/web/base/around/on_map_list_items.html
+++ b/templates/web/base/around/on_map_list_items.html
@@ -1,14 +1,31 @@
-[% all_reports = on_map.merge(around_map) %]
-[% IF all_reports.size %]
- [% FOREACH problem IN all_reports %]
- [% UNLESS problem.title;
- dist = tprintf("%.1f", (problem.distance || 0) );
- problem = problem.problem;
- END %]
+<ul class="item-list item-list--reports">
+[% IF on_map.size %]
+ [% FOREACH problem IN on_map %]
[% INCLUDE 'reports/_list-entry.html' %]
[% END %]
+ [% IF around_map.size %]
+ <li class="item-list__item item-list__item--empty">
+ <p>[% loc('Here are some other nearby reports:') %]</p>
+ </li>
+ [% END %]
+[% ELSIF around_map.size %]
+ <li class="item-list__item item-list__item--empty">
+ <p>[% loc('No reports to show on map, here are some nearby:') %]</p>
+ </li>
[% ELSE %]
<li class="item-list__item item-list__item--empty">
<p>[% loc('There are no reports to show.') %]</p>
</li>
[% END %]
+</ul>
+
+[% IF around_map.size %]
+<ul class="item-list item-list--reports">
+ [% FOREACH problem IN around_map %]
+ [% dist = tprintf("%.1f", (problem.distance || 0) );
+ problem = problem.problem;
+ %]
+ [% INCLUDE 'reports/_list-entry.html' %]
+ [% END %]
+</ul>
+[% END %]
diff --git a/templates/web/base/around/tabbed_lists.html b/templates/web/base/around/tabbed_lists.html
index 5418ef914..f135684b9 100755
--- a/templates/web/base/around/tabbed_lists.html
+++ b/templates/web/base/around/tabbed_lists.html
@@ -1,5 +1,13 @@
[% INCLUDE "reports/_list-filters.html" %]
-<ul id="js-reports-list" class="item-list item-list--reports">
+<div class="js-pagination">
+[% INCLUDE 'pagination.html' param = 'p' %]
+</div>
+
+<div id="js-reports-list">
[% INCLUDE "around/on_map_list_items.html" %]
-</ul>
+</div>
+
+<div class="js-pagination">
+[% INCLUDE 'pagination.html' param = 'p' %]
+</div>
diff --git a/templates/web/base/pagination.html b/templates/web/base/pagination.html
index a677b9d58..7c13ec9cb 100644
--- a/templates/web/base/pagination.html
+++ b/templates/web/base/pagination.html
@@ -1,5 +1,5 @@
[% IF pager.total_entries > 1 %]
- <p class="pagination">
+ <p class="pagination" data-page="[% pager.current_page %]">
[% IF pager.previous_page %]
<a class="prev" href="[% c.uri_with({ $param => pager.previous_page, ajax => undefined }) %][% '#' _ hash IF hash %]">[% loc('Previous') %]</a>
[% END %]
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index 6825ecbce..e5066b143 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -1238,11 +1238,20 @@ $(function() {
$('#filter_categories').add('#statuses').add('#sort').find('option')
.prop('selected', function() { return this.defaultSelected; })
.trigger('change.multiselect');
+ if (fixmystreet.utils && fixmystreet.utils.parse_query_string) {
+ var qs = fixmystreet.utils.parse_query_string();
+ var page = qs.p || 1;
+ $('.pagination').data('page', page)
+ .trigger('change.filters');
+ }
fixmystreet.display.reports_list(location.href);
} else if ('reportId' in e.state) {
fixmystreet.display.report(e.state.reportPageUrl, e.state.reportId);
} else if ('newReportAtLonlat' in e.state) {
fixmystreet.display.begin_report(e.state.newReportAtLonlat, false);
+ } else if ('page_change' in e.state) {
+ $('.pagination').data('page', e.state.page_change.page)
+ .trigger('change.filters');
} else if ('filter_change' in e.state) {
$('#filter_categories').val(e.state.filter_change.filter_categories);
$('#statuses').val(e.state.filter_change.statuses);
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js
index 004f0c3e2..d7e692a13 100644
--- a/web/js/map-OpenLayers.js
+++ b/web/js/map-OpenLayers.js
@@ -1,5 +1,23 @@
var fixmystreet = fixmystreet || {};
+fixmystreet.utils = fixmystreet.utils || {};
+
+$.extend(fixmystreet.utils, {
+ parse_query_string: function() {
+ var qs = {};
+ if (!location.search) {
+ return qs;
+ }
+ location.search.substring(1).split(/[;&]/).forEach(function(i) {
+ var s = i.split('='),
+ k = s[0],
+ v = s[1] && decodeURIComponent(s[1].replace(/\+/g, ' '));
+ qs[k] = v;
+ });
+ return qs;
+ }
+});
+
(function() {
fixmystreet.maps = fixmystreet.maps || {};
@@ -282,7 +300,7 @@ var fixmystreet = fixmystreet || {};
if (!location.search) {
return qs;
}
- location.search.substring(1).split('&').forEach(function(i) {
+ location.search.substring(1).split(/[&;]/).forEach(function(i) {
var s = i.split('='),
k = s[0],
v = s[1] && decodeURIComponent(s[1].replace(/\+/g, ' '));
@@ -301,15 +319,7 @@ var fixmystreet = fixmystreet || {};
return value;
}
- function categories_or_status_changed_history() {
- if (!('pushState' in history)) {
- return;
- }
- var qs = parse_query_string();
- var filter_categories = replace_query_parameter(qs, 'filter_categories', 'filter_category');
- var filter_statuses = replace_query_parameter(qs, 'statuses', 'status');
- var sort_key = replace_query_parameter(qs, 'sort', 'sort');
- delete qs.p;
+ function update_url(qs) {
var new_url;
if ($.isEmptyObject(qs)) {
new_url = location.href.replace(location.search, "");
@@ -318,6 +328,37 @@ var fixmystreet = fixmystreet || {};
} else {
new_url = location.href + '?' + $.param(qs);
}
+ return new_url;
+ }
+
+ function page_changed_history() {
+ if (!('pushState' in history)) {
+ return;
+ }
+ var qs = fixmystreet.utils.parse_query_string();
+
+ var page = $('.pagination').data('page');
+ if (page > 1) {
+ qs.p = page;
+ } else {
+ delete qs.p;
+ }
+ var new_url = update_url(qs);
+ history.pushState({
+ page_change: { 'page': page }
+ }, null, new_url);
+ }
+
+ function categories_or_status_changed_history() {
+ if (!('pushState' in history)) {
+ return;
+ }
+ var qs = fixmystreet.utils.parse_query_string();
+ var filter_categories = replace_query_parameter(qs, 'filter_categories', 'filter_category');
+ var filter_statuses = replace_query_parameter(qs, 'statuses', 'status');
+ var sort_key = replace_query_parameter(qs, 'sort', 'sort');
+ delete qs.p;
+ var new_url = update_url(qs);
history.pushState({
filter_change: { 'filter_categories': filter_categories, 'statuses': filter_statuses, 'sort': sort_key }
}, null, new_url);
@@ -387,7 +428,7 @@ var fixmystreet = fixmystreet || {};
f.geometry = new_geometry;
this.removeAllFeatures();
this.addFeatures([f]);
- var qs = parse_query_string();
+ var qs = fixmystreet.utils.parse_query_string();
if (!qs.bbox) {
zoomToBounds(extent);
}
@@ -484,7 +525,7 @@ var fixmystreet = fixmystreet || {};
pin_layer_options.strategies = [ fixmystreet.bbox_strategy ];
}
if (fixmystreet.page == 'reports') {
- pin_layer_options.strategies = [ new OpenLayers.Strategy.FixMyStreetRefreshOnZoom() ];
+ pin_layer_options.strategies = [ new OpenLayers.Strategy.FixMyStreetNoLoad() ];
}
if (fixmystreet.page == 'my') {
pin_layer_options.strategies = [ new OpenLayers.Strategy.FixMyStreetFixed() ];
@@ -544,9 +585,22 @@ var fixmystreet = fixmystreet || {};
$("#filter_categories").on("change.filters", categories_or_status_changed);
$("#statuses").on("change.filters", categories_or_status_changed);
$("#sort").on("change.filters", categories_or_status_changed);
+ $('.js-pagination').on('change.filters', categories_or_status_changed);
+ $('.js-pagination').on('click', 'a', function(e) {
+ e.preventDefault();
+ var page = $('.pagination').data('page');
+ if ($(this).hasClass('next')) {
+ $('.pagination').data('page', page + 1);
+ } else {
+ $('.pagination').data('page', page - 1);
+ }
+ fixmystreet.markers.protocol.use_page = true;
+ $(this).trigger('change');
+ });
$("#filter_categories").on("change.user", categories_or_status_changed_history);
$("#statuses").on("change.user", categories_or_status_changed_history);
$("#sort").on("change.user", categories_or_status_changed_history);
+ $('.js-pagination').on('click', 'a', page_changed_history);
} else if (fixmystreet.page == 'new') {
drag.activate();
}
@@ -725,6 +779,8 @@ OpenLayers.Control.PermalinkFMSz = OpenLayers.Class(OpenLayers.Control.Permalink
});
OpenLayers.Strategy.FixMyStreet = OpenLayers.Class(OpenLayers.Strategy.BBOX, {
+ // Update when the zoom changes, pagination means there might be new things
+ resFactor: 1.5,
ratio: 1,
// The transform in Strategy.BBOX's getMapBounds could mean you end up with
// co-ordinates too precise, which could then cause the Strategy to think
@@ -751,11 +807,8 @@ OpenLayers.Strategy.FixMyStreet = OpenLayers.Class(OpenLayers.Strategy.BBOX, {
}
});
-/* This strategy will call for updates whenever the zoom changes,
- * unlike the parent which only will if new area is included. It
- * also does not update on load, as we already have the data. */
-OpenLayers.Strategy.FixMyStreetRefreshOnZoom = OpenLayers.Class(OpenLayers.Strategy.FixMyStreet, {
- resFactor: 1.5,
+/* This strategy additionally does not update on load, as we already have the data. */
+OpenLayers.Strategy.FixMyStreetNoLoad = OpenLayers.Class(OpenLayers.Strategy.FixMyStreet, {
activate: function() {
var activated = OpenLayers.Strategy.prototype.activate.call(this);
if (activated) {
@@ -791,6 +844,9 @@ OpenLayers.Strategy.FixMyStreetFixed = OpenLayers.Class(OpenLayers.Strategy.Fixe
// This subclass is required so we can pass the 'filter_category' and 'status' query
// params to /around?ajax if the user has filtered the map.
OpenLayers.Protocol.FixMyStreet = OpenLayers.Class(OpenLayers.Protocol.HTTP, {
+ initial_page: null,
+ use_page: false,
+
read: function(options) {
// Show the loading indicator over the map
$('#loading-indicator').removeClass('hidden');
@@ -803,6 +859,16 @@ OpenLayers.Protocol.FixMyStreet = OpenLayers.Class(OpenLayers.Protocol.HTTP, {
options.params[key] = val;
}
});
+ if (this.use_page) {
+ var page = $('.pagination').data('page');
+ this.use_page = false;
+ } else if (this.initial_page) {
+ page = 1;
+ } else {
+ var qs = fixmystreet.utils.parse_query_string();
+ this.initial_page = page = qs.p || 1;
+ }
+ options.params.p = page;
return OpenLayers.Protocol.HTTP.prototype.read.apply(this, [options]);
},
CLASS_NAME: "OpenLayers.Protocol.FixMyStreet"