diff options
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Around.pm | 15 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Location.pm | 15 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 13 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/ResultSet/Problem.pm | 9 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map.pm | 18 | ||||
-rw-r--r-- | templates/web/base/around/on_map_list_items.html | 31 | ||||
-rwxr-xr-x | templates/web/base/around/tabbed_lists.html | 12 | ||||
-rw-r--r-- | templates/web/base/pagination.html | 2 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/fixmystreet.js | 9 | ||||
-rw-r--r-- | web/js/map-OpenLayers.js | 100 |
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" |