aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Arter <davea@mysociety.org>2016-07-19 15:56:26 +0100
committerDave Arter <davea@mysociety.org>2016-09-06 15:05:09 +0100
commit6f82bb9e094d679d24a6286259e7652fd1304639 (patch)
tree82e1375a50daacd03750328a1bdaef7568a48d38
parentd3ce66d0add6754dd54624f1d35efc922054ce9b (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.pm71
-rw-r--r--perllib/FixMyStreet/App/Controller/Location.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm98
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm9
-rw-r--r--templates/web/base/js/translation_strings.html2
-rw-r--r--templates/web/base/report/_inspect.html82
-rw-r--r--templates/web/base/report/_main.html27
-rw-r--r--templates/web/base/report/display.html4
-rw-r--r--templates/web/base/report/inspect.html5
-rw-r--r--templates/web/fixmystreet-uk-councils/maps/fms.html10
-rw-r--r--templates/web/fixmystreet.com/maps/fms.html10
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js47
-rw-r--r--web/cobrands/oxfordshire/_oxon.scss2
-rw-r--r--web/cobrands/oxfordshire/layout.scss13
-rw-r--r--web/cobrands/sass/_base.scss34
-rw-r--r--web/cobrands/sass/_layout.scss23
-rw-r--r--web/cobrands/sass/_mixins.scss6
-rw-r--r--web/js/map-OpenLayers.js55
-rw-r--r--web/js/map-wmts-zurich.js34
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') %] &raquo;
+ </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">&hellip; ' + 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">&hellip; ' + 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);
}
}
});