diff options
author | Dave Arter <davea@mysociety.org> | 2016-07-19 15:56:26 +0100 |
---|---|---|
committer | Dave Arter <davea@mysociety.org> | 2016-09-06 15:05:09 +0100 |
commit | 6f82bb9e094d679d24a6286259e7652fd1304639 (patch) | |
tree | 82e1375a50daacd03750328a1bdaef7568a48d38 | |
parent | d3ce66d0add6754dd54624f1d35efc922054ce9b (diff) |
Add inspector report detail view
Users with the `report_inspect` permission can click a new 'inspect' button on a
report page to input more detailed problem information into a new form that
appears in a column alongside the report detail.
- Inspector data is stored in problem's 'extra' field
- Report category/state can be edited
- Location can be changed by dragging the pin or HTML5 geolocation
(Factored out Zurich admin pin drag into own function)
For mysociety/fixmystreetforcouncils#22
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin.pm | 71 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Location.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 98 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Oxfordshire.pm | 9 | ||||
-rw-r--r-- | templates/web/base/js/translation_strings.html | 2 | ||||
-rw-r--r-- | templates/web/base/report/_inspect.html | 82 | ||||
-rw-r--r-- | templates/web/base/report/_main.html | 27 | ||||
-rw-r--r-- | templates/web/base/report/display.html | 4 | ||||
-rw-r--r-- | templates/web/base/report/inspect.html | 5 | ||||
-rw-r--r-- | templates/web/fixmystreet-uk-councils/maps/fms.html | 10 | ||||
-rw-r--r-- | templates/web/fixmystreet.com/maps/fms.html | 10 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/fixmystreet.js | 47 | ||||
-rw-r--r-- | web/cobrands/oxfordshire/_oxon.scss | 2 | ||||
-rw-r--r-- | web/cobrands/oxfordshire/layout.scss | 13 | ||||
-rw-r--r-- | web/cobrands/sass/_base.scss | 34 | ||||
-rw-r--r-- | web/cobrands/sass/_layout.scss | 23 | ||||
-rw-r--r-- | web/cobrands/sass/_mixins.scss | 6 | ||||
-rw-r--r-- | web/js/map-OpenLayers.js | 55 | ||||
-rw-r--r-- | web/js/map-wmts-zurich.js | 34 |
19 files changed, 465 insertions, 69 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 63414b555..652113734 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -764,12 +764,7 @@ sub report_edit : Path('report_edit') : Args(1) { } $problem->set_inflated_columns(\%columns); - if ((my $category = $c->get_param('category')) ne $problem->category) { - $problem->category($category); - my @contacts = grep { $_->category eq $problem->category } @{$c->stash->{contacts}}; - my $bs = join( ',', map { $_->body_id } @contacts ); - $problem->bodies_str($bs); - } + $c->forward( '/admin/report_edit_category', [ $problem ] ); if ( $c->get_param('email') ne $problem->user->email ) { my $user = $c->model('DB::User')->find_or_create( @@ -813,6 +808,70 @@ sub report_edit : Path('report_edit') : Args(1) { return 1; } +=head2 report_edit_category + +Handles changing a problem's category and the complexity that comes with it. + +=cut + +sub report_edit_category : Private { + my ($self, $c, $problem) = @_; + + # TODO: It's possible to assign a category belonging to a district + # council, meaning a 404 when the page is reloaded because the + # problem is no longer included in the current cobrand's + # problem_restriction. + # See mysociety/fixmystreetforcouncils#44 + # We could + # a) only allow the current body's categories to be chosen, + # b) show a warning about the impending change of body + # c) bounce the user to the report page on fms.com + # Not too worried about this right now, as it forms part of a bigger + # concern outlined in the above ticket and + # mysociety/fixmystreetforcouncils#17 + if ((my $category = $c->get_param('category')) ne $problem->category) { + $problem->category($category); + my @contacts = grep { $_->category eq $problem->category } @{$c->stash->{contacts}}; + my $bs = join( ',', map { $_->body_id } @contacts ); + $problem->bodies_str($bs); + } +} + +=head2 report_edit_location + +Handles changing a problem's location and the complexity that comes with it. +For now, we reject the new location if the new location and old locations aren't +covered by the same body. + +Returns 1 if the new position (if any) is acceptable, undef otherwise. + +NB: This must be called before report_edit_category, as that might modify +$problem->bodies_str. + +=cut + +sub report_edit_location : Private { + my ($self, $c, $problem) = @_; + + return 1 unless $c->forward('/report/new/determine_location'); + + if ( $c->stash->{latitude} != $problem->latitude || $c->stash->{longitude} != $problem->longitude ) { + delete $c->stash->{prefetched_all_areas}; + delete $c->stash->{all_areas}; + delete $c->stash->{fetch_all_areas}; + delete $c->stash->{all_areas_mapit}; + $c->forward('/council/load_and_check_areas'); + $c->forward('/report/new/setup_categories_and_bodies'); + my %allowed_bodies = map { $_ => 1 } @{$problem->bodies_str_ids}; + my @new_bodies = @{$c->stash->{bodies_to_list}}; + my $bodies_match = grep { exists( $allowed_bodies{$_} ) } @new_bodies; + return unless $bodies_match; + $problem->latitude($c->stash->{latitude}); + $problem->longitude($c->stash->{longitude}); + } + return 1; +} + sub categories_for_point : Private { my ($self, $c) = @_; diff --git a/perllib/FixMyStreet/App/Controller/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm index c457c8fce..6a0f2c0ec 100644 --- a/perllib/FixMyStreet/App/Controller/Location.pm +++ b/perllib/FixMyStreet/App/Controller/Location.pm @@ -31,6 +31,8 @@ sub determine_location_from_coords : Private { my $latitude = $c->get_param('latitude') || $c->get_param('lat'); my $longitude = $c->get_param('longitude') || $c->get_param('lon'); + $c->log->debug($longitude); + $c->log->debug($latitude); if ( defined $latitude && defined $longitude ) { ($c->stash->{latitude}, $c->stash->{longitude}) = diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 6ac3c8ea1..2f6418886 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -278,10 +278,85 @@ sub delete :Local :Args(1) { return $c->res->redirect($uri); } -sub map : Path('') : Args(2) { - my ( $self, $c, $id, $map ) = @_; +=head2 action_router + +A router for dispatching handlers for sub-actions on a particular report, +e.g. /report/1/inspect + +=cut + +sub action_router : Path('') : Args(2) { + my ( $self, $c, $id, $action ) = @_; + + $c->go( 'inspect', [ $id ] ) if $action eq 'inspect'; + $c->go( 'map', [ $id ] ) if $action eq 'map'; + + $c->detach( '/page_error_404_not_found', [] ); +} + +sub inspect : Private { + my ( $self, $c, $id ) = @_; + + $c->forward('/auth/get_csrf_token'); + $c->forward( 'load_problem_or_display_error', [ $id ] ); + $c->forward( 'check_has_permission_to', [ 'report_inspect' ] ); + $c->forward( 'load_updates' ); + $c->forward( 'format_problem_for_display' ); + + my $problem = $c->stash->{problem}; + + $c->stash->{categories} = $c->forward('/admin/categories_for_point'); + + # The available priorities for this problem are dependent on the cobrand it + # was reported to, not necessarily the active cobrand (e.g. inspecting a + # report on fms.com that was sent to Oxfordshire), so make sure the correct + # priorities are available for selection. + if ( $c->cobrand->can('get_body_handler_for_problem') ) { + my $handler = $c->cobrand->get_body_handler_for_problem($c->stash->{problem}); + if ( $handler->can('problem_response_priorities') ) { + $c->stash->{priorities} = $handler->problem_response_priorities; + } + } + + if ( $c->get_param('save') ) { + $c->forward('/auth/check_csrf_token'); + + foreach (qw/priority detailed_location detailed_information traffic_information/) { + $problem->set_extra_metadata( $_ => $c->get_param($_) ); + } + + # Handle the state changing + my $old_state = $problem->state; + $problem->state($c->get_param('state')); + if ( $problem->is_visible() and $old_state eq 'unconfirmed' ) { + $problem->confirmed( \'current_timestamp' ); + } + if ( $problem->state eq 'hidden' ) { + $problem->get_photoset->delete_cached; + } + if ( $problem->state ne $old_state ) { + $c->forward( '/admin/log_edit', [ $id, 'problem', 'state_change' ] ); + } + + my $valid = 1; + if ( !$c->forward( '/admin/report_edit_location', [ $problem ] ) ) { + # New lat/lon isn't valid, show an error + $valid = 0; + $c->stash->{errors} = [ _('Invalid location. New location must be covered by the same council.') ]; + } + + $c->forward( '/admin/report_edit_category', [ $problem ] ); + + if ($valid) { + $problem->update; + $c->res->redirect( $c->uri_for( '/report', $problem->id, 'inspect' ) ); + } + } +}; + +sub map : Private { + my ( $self, $c, $id ) = @_; - $c->detach( '/page_error_404_not_found', [] ) unless $map eq 'map'; $c->forward( 'load_problem_or_display_error', [ $id ] ); my $image = $c->stash->{problem}->static_map; @@ -289,6 +364,23 @@ sub map : Path('') : Args(2) { $c->res->body($image->{data}); } + +=head2 check_has_permission_to + +Ensure the currently logged-in user has a particular permission that applies +to the current Problem in $c->stash->{problem}. Shows the 403 page if not. + +=cut + +sub check_has_permission_to : Private { + my ( $self, $c, $permission ) = @_; + + my $bodies = $c->stash->{problem}->bodies_str; + + $c->detach('/page_error_403_access_denied', [ _("Sorry, you don't have permission to do that.") ] ) + unless $c->user_exists && $c->user->has_permission_to($permission, $bodies); +}; + __PACKAGE__->meta->make_immutable; 1; diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm index d127f5e13..8def4fb06 100644 --- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm +++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm @@ -92,6 +92,15 @@ sub problem_response_days { return undef; } +sub problem_response_priorities { + return { + cat1a => 'Cat 1A (4 hours)', + cat1b => 'Cat 1B (24 hours)', + cat2 => 'Cat 2 (2 days)', + cat3 => 'Cat 3 (10 days)', + }; +} + sub reports_ordering { return { -desc => 'confirmed' }; } diff --git a/templates/web/base/js/translation_strings.html b/templates/web/base/js/translation_strings.html index d006442af..d6aca9ccb 100644 --- a/templates/web/base/js/translation_strings.html +++ b/templates/web/base/js/translation_strings.html @@ -37,6 +37,8 @@ geolocation_no_result: '[% loc('No result returned') | replace("'", "\\'") %]', geolocation_unknown: '[% loc('Unknown error') | replace("'", "\\'") %]', + correct_position: '[% loc('Right place?') | replace("'", "\\'") %]', + reporting_a_problem: '[% loc('Reporting a problem') | replace("'", "\\'") %]', ok: '[% loc('OK') | replace("'", "\\'") %]', map: '[% loc('MAP') | replace("'", "\\'") %]', diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html new file mode 100644 index 000000000..6f81cc04a --- /dev/null +++ b/templates/web/base/report/_inspect.html @@ -0,0 +1,82 @@ +[% PROCESS 'admin/report_blocks.html'; # For the report state dropdown %] +[% second_column = BLOCK -%] + <div id="side-report-secondary"> + <div class="problem-inspector-fields clearfix"> + <form id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id, 'inspect' ) %]"> + <p class="left"> + <label for="problem_id">[% loc('Report ID:') %]</label> + <input type="text" readonly id="problem_id" value="[% problem.id %]"> + </p> + <p class="right"> + <label for="problem_priority">[% loc('Priority:') %]</label> + <select name="priority" id="problem_priority"> + <option value="" [% 'selected' UNLESS problem.get_extra_metadata('priority') %]>-</option> + [% FOREACH priority IN priorities %] + <option value="[% priority.key %]" [% 'selected' IF problem.get_extra_metadata('priority') == priority.key %]>[% priority.value %]</option> + [% END %] + </select> + </p> + <p class="left"> + <label for="state">[% loc('State:') %]</label> + [%# XXX this is duplicated from admin/report_edit.html, should be refactored %] + <select name="state" id="state"> + [% FOREACH group IN state_groups %] + <optgroup label="[% group.0 %]"> + [% FOREACH state IN group.1 %] + <option [% 'selected ' IF state == problem.state %] value="[% state %]">[% state_pretty.$state %]</option> + [% END %] + </optgroup> + [% END %] + </select> + </p> + <p class="right"> + <label for="category">[% loc('Category:') %]</label> + [%# XXX this is duplicated from admin/report_edit.html, should be refactored %] + <select name="category" id="category"> + [% IF NOT problem.category OR NOT categories.grep(problem.category).size %] + <optgroup label="[% loc('Existing category') %]"> + <option selected value="[% problem.category | html %]">[% (problem.category OR '-') | html %]</option> + </optgroup> + [% END %] + [% IF categories.size %] + <optgroup label="[% loc('Available categories') %]"> + [% FOREACH cat IN categories %] + <option[% ' selected' IF problem.category == cat %]>[% cat | html %]</option> + [% END %] + </optgroup> + [% END %] + </select> + </p> + <p> + [% SET local_coords = problem.local_coords; %] + <strong>[% loc('Easting/Northing:') %]</strong> + <span id="problem_easting">[% local_coords.0 IF local_coords %]</span>, + <span id="problem_northing">[% local_coords.1 IF local_coords %]</span> + <input type="hidden" name="longitude" value="[% problem.longitude %]"> + <input type="hidden" name="latitude" value="[% problem.latitude %]"> + </p> + <p style="clear:both;"> + <a href="#" id="geolocate_link">[% loc('Use my current location') %]</a>, + [% loc('or drag the pin on the map') %] » + </p> + <p> + <label for="detailed_information">[% loc('Detailed problem location:') %]</label> + <textarea rows="2" name="detailed_location">[% problem.get_extra_metadata('detailed_location') | html %]</textarea> + </p> + <p> + <label for="detailed_information">[% loc('Detailed problem information:') %]</label> + <textarea rows="2" name="detailed_information">[% problem.get_extra_metadata('detailed_information') | html %]</textarea> + </p> + <p> + <label for="traffic_information">[% loc('Traffic management information:') %]</label> + <textarea rows="2" name="traffic_information">[% problem.get_extra_metadata('traffic_information') | html %]</textarea> + </p> + <p> + <input type="hidden" name="token" value="[% csrf_token %]"> + <a href="[% c.uri_for( '/report', problem.id ) %]" class="btn">[% loc('Cancel') %]</a> + <input type="submit" value="[% loc('Save changes') %]" name="save" /> + </p> + </form> + </div> + </div> +[%- END %]
\ No newline at end of file diff --git a/templates/web/base/report/_main.html b/templates/web/base/report/_main.html index 585200ac3..1b1a6e29e 100644 --- a/templates/web/base/report/_main.html +++ b/templates/web/base/report/_main.html @@ -1,4 +1,5 @@ -[% moderating = c.user && c.user.has_permission_to('moderate', problem.bodies_str) %] +[% can_moderate = c.user && c.user.has_permission_to('moderate', problem.bodies_str) %] +[% can_inspect = c.user && c.user.has_permission_to('report_inspect', problem.bodies_str) && !hide_inspect_button %] <a href="[% c.uri_for( '/around', { lat => latitude, lon => longitude } ) %]" class="problem-back js-back-to-report-list">[% loc('Back to all reports') %]</a> @@ -22,18 +23,15 @@ </form> [% END %] - [% IF moderating %] + [% IF can_moderate %] [% original = problem_original %] <form method="post" action="/moderate/report/[% problem.id %]"> <input type="hidden" name="token" value="[% csrf_token %]"> - <p class="moderate-display"> - <input type="button" class="btn moderate" value="Moderate this report"> - </p> [% END %] <h1 class="moderate-display">[% problem.title | html %]</h1> - [% IF moderating %] + [% IF can_moderate %] <div class="moderate-edit"> [% IF problem.title != original.title %] <label> @@ -62,7 +60,7 @@ [% INCLUDE 'report/_support.html' %] - [% IF moderating %] + [% IF can_moderate %] [% IF problem.photo or original.photo %] <p class="moderate-edit"> <label> @@ -78,7 +76,7 @@ [% problem.detail | add_links | html_para %] </div> - [% IF moderating %] + [% IF can_moderate %] <p class="moderate-edit"> [% IF problem.detail != original.detail %] <label> @@ -105,7 +103,20 @@ <input type="button" class="btn cancel" value="Discard changes"> </p> </div> + [% END %] + + [% IF can_moderate OR can_inspect %] + <p class="moderate-display"> + [% IF can_moderate %] + <input type="button" class="btn moderate" value="Moderate this report"> + [% END %] + [% IF can_inspect %] + <a href="/report/[% problem.id %]/inspect" class="btn inspect">Inspect</a> + [% END %] + </p> + [% END %] + [% IF can_moderate %] </form> [% END %] diff --git a/templates/web/base/report/display.html b/templates/web/base/report/display.html index 50c649f9a..fb8cd8191 100644 --- a/templates/web/base/report/display.html +++ b/templates/web/base/report/display.html @@ -1,5 +1,5 @@ [% - SET bodyclass = 'mappage'; + DEFAULT bodyclass = 'mappage'; PROCESS "report/photo-js.html"; PROCESS "maps/${map.type}.html"; @@ -45,6 +45,8 @@ [% END %] </div> + + [% second_column %] </div> [% INCLUDE 'footer.html' %] diff --git a/templates/web/base/report/inspect.html b/templates/web/base/report/inspect.html new file mode 100644 index 000000000..ad70b2ac5 --- /dev/null +++ b/templates/web/base/report/inspect.html @@ -0,0 +1,5 @@ +[% + SET bodyclass = 'mappage with-actions'; + PROCESS 'report/_inspect.html'; + INCLUDE 'report/display.html', hide_inspect_button = 1; +%] diff --git a/templates/web/fixmystreet-uk-councils/maps/fms.html b/templates/web/fixmystreet-uk-councils/maps/fms.html new file mode 100644 index 000000000..3cf503c96 --- /dev/null +++ b/templates/web/fixmystreet-uk-councils/maps/fms.html @@ -0,0 +1,10 @@ +[% map_js = BLOCK %] +<!-- <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&mkt=en-GB"></script> --> +<script type="text/javascript" src="[% version('/js/OpenLayers/OpenLayers.fixmystreet.js') %]"></script> +<script type="text/javascript" src="[% version('/js/OpenLayers.Projection.OrdnanceSurvey.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-bing-ol.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-fms.js') %]"></script> +[% END %] + +[% map_html = INCLUDE maps/openlayers.html include_key = 1 %] diff --git a/templates/web/fixmystreet.com/maps/fms.html b/templates/web/fixmystreet.com/maps/fms.html new file mode 100644 index 000000000..3cf503c96 --- /dev/null +++ b/templates/web/fixmystreet.com/maps/fms.html @@ -0,0 +1,10 @@ +[% map_js = BLOCK %] +<!-- <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&mkt=en-GB"></script> --> +<script type="text/javascript" src="[% version('/js/OpenLayers/OpenLayers.fixmystreet.js') %]"></script> +<script type="text/javascript" src="[% version('/js/OpenLayers.Projection.OrdnanceSurvey.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-bing-ol.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-fms.js') %]"></script> +[% END %] + +[% map_html = INCLUDE maps/openlayers.html include_key = 1 %] diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js index 914b8e7eb..5ab750679 100644 --- a/web/cobrands/fixmystreet/fixmystreet.js +++ b/web/cobrands/fixmystreet/fixmystreet.js @@ -324,15 +324,11 @@ $.extend(fixmystreet.set_up, { }); }, - geolocation: function() { - if (geo_position_js.init()) { - var link = '<a href="LINK" id="geolocate_link">… ' + translation_strings.geolocate + '</a>'; - $('form[action="/alert/list"]').append(link.replace('LINK','/alert/list')); - if ($('body.frontpage').length) { - $('#postcodeForm').after(link.replace('LINK','/around')); - } else{ - $('#postcodeForm').append(link.replace('LINK','/around')); - } + report_geolocation: function() { + if (!geo_position_js.init()) { + return; + } + function add_click_handler(success_callback) { $('#geolocate_link').click(function(e) { var $link = $(this); e.preventDefault(); @@ -345,10 +341,7 @@ $.extend(fixmystreet.set_up, { } geo_position_js.getCurrentPosition(function(pos) { $link.find('img').remove(); - var latitude = pos.coords.latitude; - var longitude = pos.coords.longitude; - var page = $link.attr('href'); - location.href = page + '?latitude=' + latitude + ';longitude=' + longitude; + success_callback(pos); }, function(err) { $link.find('img').remove(); if (err.code == 1) { // User said no @@ -366,6 +359,34 @@ $.extend(fixmystreet.set_up, { }); }); } + if ($('#postcodeForm').length) { + var link = '<a href="LINK" id="geolocate_link">… ' + translation_strings.geolocate + '</a>'; + $('form[action="/alert/list"]').append(link.replace('LINK','/alert/list')); + if ($('body.frontpage').length) { + $('#postcodeForm').after(link.replace('LINK','/around')); + } else{ + $('#postcodeForm').append(link.replace('LINK','/around')); + } + add_click_handler(function(pos) { + var latitude = pos.coords.latitude; + var longitude = pos.coords.longitude; + var page = $('#geolocate_link').attr('href'); + location.href = page + '?latitude=' + latitude + ';longitude=' + longitude; + }); + } + if ($('form#report_inspect_form').length) { + add_click_handler(function(pos) { + var latlon = new OpenLayers.LonLat(pos.coords.longitude, pos.coords.latitude); + var bng = latlon.clone().transform( + new OpenLayers.Projection("EPSG:4326"), + new OpenLayers.Projection("EPSG:27700") // TODO: Handle other projections + ); + $("#problem_northing").text(bng.lat.toFixed(1)); + $("#problem_easting").text(bng.lon.toFixed(1)); + $("form#report_inspect_form input[name=latitude]").val(latlon.lat); + $("form#report_inspect_form input[name=longitude]").val(latlon.lon); + }); + } }, category_change: function() { diff --git a/web/cobrands/oxfordshire/_oxon.scss b/web/cobrands/oxfordshire/_oxon.scss index 0859fad6a..c8c49a631 100644 --- a/web/cobrands/oxfordshire/_oxon.scss +++ b/web/cobrands/oxfordshire/_oxon.scss @@ -9,7 +9,7 @@ body { font-family:"Trebuchet MS",Arial, Helvetica, sans-serif; line-height:18px; - a, a:visited {text-decoration:none; color:$oxfordshire_link_colour} + a:not(.btn), a:visited:not(.btn) {text-decoration:none; color:$oxfordshire_link_colour} a { font-size: 1em; } // mySociety a:hover {text-decoration:underline} margin:0; diff --git a/web/cobrands/oxfordshire/layout.scss b/web/cobrands/oxfordshire/layout.scss index 5c3d5e8ac..c9783b14d 100644 --- a/web/cobrands/oxfordshire/layout.scss +++ b/web/cobrands/oxfordshire/layout.scss @@ -159,10 +159,6 @@ body.mappage { width: auto; } - #map_sidebar { - background-color: $oxfordshire_very_light_green; - } - .extra-text { padding: 1em; margin: 0 -1em; @@ -226,6 +222,15 @@ body.mappage { } } +#map_sidebar { + background-color: $oxfordshire_very_light_green; + + .with-actions & { + background-image: -webkit-linear-gradient(flip(90deg, 270deg), transparent 29em, #deead2 29em); + background-image: linear-gradient(flip(90deg, 270deg), transparent 29em, #deead2 29em); + } +} + .item-list--reports { li:after { background-color: $oxfordshire_mid_grey_green; diff --git a/web/cobrands/sass/_base.scss b/web/cobrands/sass/_base.scss index 67bc35164..576538daa 100644 --- a/web/cobrands/sass/_base.scss +++ b/web/cobrands/sass/_base.scss @@ -296,6 +296,11 @@ input[type=email] { line-height: 1em; } +input[readonly] { + border-color: #cccccc; + color: #888888; +} + label{ display: block; margin-top: 1.25em; @@ -391,6 +396,30 @@ label{ margin:1em 0; } +.problem-inspector-fields { + select { + height: 2.4em; // match text inputs + -webkit-appearance: menulist-button; // so it's the right height in Safari + } + + p.left, + p.right { + width: 46%; + + label { + margin-top: 0; + } + } + + p.left { + float: #{$left}; + } + + p.right { + float: #{$right}; + } +} + // form errors div.form-error, @@ -704,8 +733,9 @@ footer { /*BUTTONS*/ // Default style set for buttons, inputs and .btn class. Red and green class available. - -button, input[type=submit],.btn{ +// NB: a.btn is included in the selector otherwise a:visited is more specific and +// the wrong text colour is applied. +button, input[type=submit], .btn, a.btn { @include button-reset; } diff --git a/web/cobrands/sass/_layout.scss b/web/cobrands/sass/_layout.scss index 52c6c075d..73c614e91 100644 --- a/web/cobrands/sass/_layout.scss +++ b/web/cobrands/sass/_layout.scss @@ -333,6 +333,29 @@ body.mappage.admin { } } +// Some report pages have a second column of UI elements so make room +body.mappage.twocols { + #map_box { + #{$left}: 58em; + } + + #map_sidebar { + width: 58em; + padding: 0; + + #side-report, #side-report-secondary { + width: 50%; + float: #{$left}; + padding: 1em; + box-sizing: border-box; + } + + #side-report-secondary { + background-color: #eee; + } + } +} + #map_box { position: absolute; z-index: auto; diff --git a/web/cobrands/sass/_mixins.scss b/web/cobrands/sass/_mixins.scss index 5bbbc19eb..36a18b40a 100644 --- a/web/cobrands/sass/_mixins.scss +++ b/web/cobrands/sass/_mixins.scss @@ -2,6 +2,7 @@ $direction: 'left' !default; // Button reset @mixin button-reset($c1: #eee, $c2: #ccc, $c3: #999, $c4: #333, $c5: #777, $c6: #999, $c7: #666, $c8: #fff){ + display: inline-block; cursor:pointer; font:{ size: 0.875em; @@ -14,16 +15,17 @@ $direction: 'left' !default; margin:0; width: auto; height: auto; + vertical-align: top; @include border-radius(4px); background: $c1; @include linear-gradient($c1, $c2); - border:1px solid $c3; + border:1px solid $c3; color:$c4; &:hover:enabled { background:$c5; @include linear-gradient($c6, $c5); text-decoration: none; - border:1px solid $c7; + border:1px solid $c7; color:$c8; } } diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 0300c0acc..f6b2c879b 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -136,6 +136,37 @@ var fixmystreet = fixmystreet || {}; } else { return 'small'; } + }, + + // Handle a single report pin being moved by dragging it on the map. + // pin_moved_callback is called with a new EPSG:4326 OpenLayers.LonLat if + // the user drags the pin and confirms its new location. + admin_drag: function(pin_moved_callback, confirm_change) { + confirm_change = confirm_change || false; + var original_lonlat; + var drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, { + onStart: function(feature, e) { + // Keep track of where the feature started, so we can put it + // back if the user cancels the operation. + original_lonlat = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y); + }, + onComplete: function(feature, e) { + var lonlat = feature.geometry.clone(); + lonlat.transform( + fixmystreet.map.getProjectionObject(), + new OpenLayers.Projection("EPSG:4326") + ); + if ((confirm_change && window.confirm(translation_strings.correct_position)) || !confirm_change) { + // Let the callback know about the newly confirmed position + pin_moved_callback(lonlat); + } else { + // Put it back + fixmystreet.markers.features[0].move(original_lonlat); + } + } + } ); + fixmystreet.map.addControl( drag ); + drag.activate(); } }; @@ -239,6 +270,26 @@ var fixmystreet = fixmystreet || {}; fixmystreet.markers.refresh({force: true}); } + function setup_inspector_marker_drag() { + // On the 'inspect report' page the pin is draggable, so we need to + // update the easting/northing fields when it's dragged. + if (!$('form#report_inspect_form').length) { + // Not actually on the inspect report page + return; + } + fixmystreet.maps.admin_drag(function(lonlat) { + var bng = lonlat.clone().transform( + new OpenLayers.Projection("EPSG:4326"), + new OpenLayers.Projection("EPSG:27700") // TODO: Handle other projections + ); + $("#problem_northing").text(bng.y.toFixed(1)); + $("#problem_easting").text(bng.x.toFixed(1)); + $("form#report_inspect_form input[name=latitude]").val(lonlat.y); + $("form#report_inspect_form input[name=longitude]").val(lonlat.x); + }, + false); + } + function onload() { if ( fixmystreet.area.length ) { for (var i=0; i<fixmystreet.area.length; i++) { @@ -396,6 +447,10 @@ var fixmystreet = fixmystreet || {}; } fixmystreet.map.addLayer(fixmystreet.markers); + if (fixmystreet.page == "report") { + setup_inspector_marker_drag(); + } + if ( fixmystreet.zoomToBounds ) { zoomToBounds( fixmystreet.markers.getDataExtent() ); } diff --git a/web/js/map-wmts-zurich.js b/web/js/map-wmts-zurich.js index fc1dfa08f..18a858064 100644 --- a/web/js/map-wmts-zurich.js +++ b/web/js/map-wmts-zurich.js @@ -114,33 +114,9 @@ fixmystreet.maps.matrix_ids = [ ]; (function() { - - function admin_drag() { - var drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, { - onComplete: function(feature, e) { - var lonlat = feature.geometry.clone(); - lonlat.transform( - fixmystreet.map.getProjectionObject(), - new OpenLayers.Projection("EPSG:4326") - ); - if (window.confirm( 'Richtiger Ort?' ) ) { - // Store new co-ordinates - document.getElementById('fixmystreet.latitude').value = lonlat.y; - document.getElementById('fixmystreet.longitude').value = lonlat.x; - } else { - // Put it back - var lat = document.getElementById('fixmystreet.latitude').value; - var lon = document.getElementById('fixmystreet.longitude').value; - lonlat = new OpenLayers.LonLat(lon, lat).transform( - new OpenLayers.Projection("EPSG:4326"), - fixmystreet.map.getProjectionObject() - ); - fixmystreet.markers.features[0].move(lonlat); - } - } - } ); - fixmystreet.map.addControl( drag ); - drag.activate(); + function pin_dragged(lonlat) { + document.getElementById('fixmystreet.latitude').value = lonlat.y; + document.getElementById('fixmystreet.longitude').value = lonlat.x; } $(function(){ @@ -155,9 +131,9 @@ fixmystreet.maps.matrix_ids = [ /* Admin dragging of pin */ if (fixmystreet.page == 'admin') { if ($.browser.msie) { - $(window).load(admin_drag); + $(window).load(function() { fixmystreet.maps.admin_drag(pin_dragged, true); }); } else { - admin_drag(); + fixmystreet.maps.admin_drag(pin_dragged, true); } } }); |