aboutsummaryrefslogtreecommitdiffstats
path: root/web/js
diff options
context:
space:
mode:
Diffstat (limited to 'web/js')
-rw-r--r--web/js/contact.js14
-rw-r--r--web/js/dashboard.js36
-rw-r--r--web/js/duplicates.js188
-rw-r--r--web/js/front.js16
-rw-r--r--web/js/map-OpenLayers.js309
-rw-r--r--web/js/map-OpenStreetMap.js2
-rw-r--r--web/js/map-bing-ol.js10
-rw-r--r--web/js/map-fms.js20
-rw-r--r--web/js/map-google-ol.js2
-rw-r--r--web/js/map-streetview.js2
-rw-r--r--web/js/map-toner-lite.js2
-rw-r--r--web/js/map-wmts-bristol.js2
-rw-r--r--web/js/map-wmts-zurich.js2
-rw-r--r--web/js/validation_rules.js4
14 files changed, 510 insertions, 99 deletions
diff --git a/web/js/contact.js b/web/js/contact.js
new file mode 100644
index 000000000..9529ede16
--- /dev/null
+++ b/web/js/contact.js
@@ -0,0 +1,14 @@
+$('[name=dest]').change(function() {
+ var err = $('.form-error--' + this.value),
+ inputs = $(this).closest('form').find('input[type=text], input[type=submit]');
+ $('.form-error__box').addClass('hidden');
+ if (err.length) {
+ $('#dest-error').removeClass('hidden');
+ $('#dest-error .form-error').show(); // might have been hidden by normal validate
+ inputs.prop('disabled', true);
+ $('.form-error--' + this.value).removeClass('hidden');
+ } else {
+ $('#dest-error').addClass('hidden');
+ inputs.prop('disabled', false);
+ }
+});
diff --git a/web/js/dashboard.js b/web/js/dashboard.js
index 82b5e6188..48a273ed6 100644
--- a/web/js/dashboard.js
+++ b/web/js/dashboard.js
@@ -30,6 +30,9 @@ $(function(){
var lasty = 0;
$.each(chart.config.data.datasets, function(datasetIndex, dataset){
+ if (dataset.data.length == 0) {
+ return;
+ }
var $label = $('.label[data-datasetIndex="' + datasetIndex + '"]', $parent);
var latestPoint = chart.getDatasetMeta(datasetIndex).data[ dataset.data.length - 1 ];
var y = latestPoint._model.y;
@@ -136,21 +139,26 @@ $(function(){
data0 = $allReports.data('values-reports'),
data1 = $allReports.data('values-fixed');
- window.chartAllReports = new Chart($allReports, {
- type: 'line',
- data: {
- labels: labels,
- datasets: [{
- data: data0,
- pointRadius: pointRadiusFinalDot(data0.length, 4),
- pointBackgroundColor: colours[1],
- borderColor: colours[1]
- }, {
+ var data = [{
+ data: data0,
+ pointRadius: pointRadiusFinalDot(data0.length, 4),
+ pointBackgroundColor: colours[1],
+ borderColor: colours[1]
+ }];
+ if ( data1 ) {
+ data.push({
data: data1,
pointRadius: pointRadiusFinalDot(data1.length, 4),
pointBackgroundColor: colours[3],
borderColor: colours[3]
- }]
+ });
+ }
+
+ window.chartAllReports = new Chart($allReports, {
+ type: 'line',
+ data: {
+ labels: labels,
+ datasets: data
},
options: {
animation: {
@@ -193,9 +201,11 @@ $(function(){
var $table = $(this);
var $trs = $table.find('tr');
var $wrapper = $('<div>').addClass('responsive-bar-chart').insertBefore($table);
+ var canvasWidth = $table.attr('data-canvas-width') || 600;
+ var rowHeight = $table.attr('data-row-height') || 30;
var $canvas = $('<canvas>').attr({
- 'width': 600,
- 'height': 30 * $trs.length
+ 'width': canvasWidth,
+ 'height': rowHeight * $trs.length
}).appendTo($wrapper);
var rowLabels = [];
var rowValues = [];
diff --git a/web/js/duplicates.js b/web/js/duplicates.js
new file mode 100644
index 000000000..723c357e9
--- /dev/null
+++ b/web/js/duplicates.js
@@ -0,0 +1,188 @@
+(function() {
+
+ // Store a reference to the "duplicate" report pins so we can
+ // quickly remove them when we’re finished showing duplicates.
+ var current_duplicate_markers;
+
+ // Report ID will be available on report inspect page,
+ // but undefined on new report page.
+ var report_id = $("#report_inspect_form .js-report-id").text() || undefined;
+
+ function refresh_duplicate_list() {
+ var category = $('select[name="category"]').val();
+ if (category === '-- Pick a category --') {
+ return;
+ }
+
+ var nearby_url;
+ var url_params = {
+ filter_category: category,
+ latitude: $('input[name="latitude"]').val(),
+ longitude: $('input[name="longitude"]').val()
+ };
+
+ if ( report_id ) {
+ nearby_url = '/report/' + report_id + '/nearby.json';
+ url_params.distance = 1000; // Inspectors might want to see reports fairly far away (1000 metres)
+ url_params.pin_size = 'small'; // How it's always been
+ } else {
+ nearby_url = '/around/nearby';
+ url_params.distance = 250; // Only want to bother public with very nearby reports (250 metres)
+ url_params.pin_size = 'normal';
+ }
+
+ $.ajax({
+ url: nearby_url,
+ data: url_params,
+ dataType: 'json'
+ }).done(function(response) {
+ if ( response.pins.length ){
+ render_duplicate_list(response);
+ render_duplicate_pins(response);
+ } else {
+ remove_duplicate_pins();
+ remove_duplicate_list();
+ }
+ }).fail(function(){
+ remove_duplicate_pins();
+ remove_duplicate_list();
+ });
+ }
+
+ function render_duplicate_list(api_response) {
+ var $reports = $( api_response.reports_list );
+
+ var duplicate_of = $('#report_inspect_form [name="duplicate_of"]').val();
+ if ( duplicate_of ) {
+ $reports.filter('[data-report-id="' + duplicate_of + '"]')
+ .addClass("item-list__item--selected");
+ }
+
+ $("#js-duplicate-reports ul").empty().prepend( $reports );
+ fixmystreet.set_up.fancybox_images();
+
+ $('#js-duplicate-reports').hide().removeClass('hidden').slideDown();
+ if ( $('#problem_form').length ) {
+ $('.js-hide-if-invalid-category').slideUp();
+ }
+
+ // Highlight map pin when hovering associated list item.
+ var timeout;
+ $reports.on('mouseenter', function(){
+ var id = parseInt( $(this).data('reportId'), 10 );
+ clearTimeout( timeout );
+ fixmystreet.maps.markers_highlight( id );
+ }).on('mouseleave', function(){
+ timeout = setTimeout( fixmystreet.maps.markers_highlight, 50 );
+ });
+
+ // Add a "select this report" button, when on the report inspect form.
+ if ( $('#report_inspect_form').length ) {
+ $reports.each(function(){
+ var $button = $('<button>').addClass('btn btn--small btn--primary');
+ $button.text(translation_strings.this_report);
+ $button.on('click', function(e) {
+ e.preventDefault(); // Prevent button from submitting parent form
+ var report_id = $(this).closest('li').data('reportId');
+ $('#report_inspect_form [name="duplicate_of"]').val(report_id);
+ $(this).closest('li')
+ .addClass('item-list__item--selected')
+ .siblings('.item-list__item--selected')
+ .removeClass('item-list__item--selected');
+ });
+ $(this).find('.item-list__item--expandable__actions').append($button);
+ });
+ }
+
+ // Add a "track this report" button when on the regular reporting form.
+ if ( $('#problem_form').length ) {
+ $reports.each(function() {
+ var $li = $(this);
+ var id = parseInt( $li.data('reportId'), 10 );
+ var alert_url = '/alert/subscribe?id=' + encodeURIComponent(id);
+ var $button = $('<a>').addClass('btn btn--small btn--primary');
+ $button.text(translation_strings.this_is_the_problem);
+ $button.attr('href', alert_url);
+ $button.on('click', function(e){
+ e.preventDefault();
+ var $div = $('.js-template-get-updates > div').clone();
+ $div.find('input[name="id"]').val(id);
+ $div.find('input[disabled]').prop('disabled', false);
+ $div.hide().appendTo($li).slideDown(250, function(){
+ $div.find('input[type="email"]').focus();
+ });
+ $li.find('.item-list__item--expandable__actions').slideUp(250);
+ $li.removeClass('js-expandable');
+ $li.addClass('item-list__item--selected');
+ });
+ $li.find('.item-list__item--expandable__actions').append($button);
+ });
+ }
+ }
+
+ function render_duplicate_pins(api_response) {
+ var markers = fixmystreet.maps.markers_list( api_response.pins, true );
+ fixmystreet.markers.removeFeatures( current_duplicate_markers );
+ fixmystreet.markers.addFeatures( markers );
+ current_duplicate_markers = markers;
+ }
+
+ function remove_duplicate_list(cb) {
+ var animations = [];
+
+ animations.push( $.Deferred() );
+ $('#js-duplicate-reports').slideUp(function(){
+ $(this).addClass('hidden');
+ $(this).find('ul').empty();
+ animations[0].resolve();
+ });
+ if ( $('#problem_form').length ) {
+ animations.push( $.Deferred() );
+ $('.js-hide-if-invalid-category').slideDown(function(){
+ animations[1].resolve();
+ });
+ }
+
+ $.when.apply(this, animations).then(cb);
+ }
+
+ function remove_duplicate_pins() {
+ fixmystreet.markers.removeFeatures( current_duplicate_markers );
+ }
+
+ function inspect_form_state_change() {
+ // The duplicate report list only makes sense when state is 'duplicate'
+ if ($(this).val() !== "duplicate") {
+ $("#js-duplicate-reports").addClass("hidden");
+ return;
+ } else {
+ $("#js-duplicate-reports").removeClass("hidden");
+ }
+ // If this report is already marked as a duplicate of another, then
+ // there's no need to refresh the list of duplicate reports
+ var duplicate_of = $("#report_inspect_form [name=duplicate_of]").val();
+ if (!!duplicate_of) {
+ return;
+ }
+ refresh_duplicate_list();
+ }
+
+ // Want to show potential duplicates when a regular user starts a new
+ // report, or changes the category/location of a partial report.
+ $(fixmystreet).on('report_new:category_change', refresh_duplicate_list);
+
+ // Want to show duplicates when an inspector sets a report’s state to "duplicate".
+ $(document).on('change.state', "#report_inspect_form select#state", inspect_form_state_change);
+
+ // Also want to give inspectors a way to select a *new* duplicate report.
+ $(document).on('click', "#js-change-duplicate-report", refresh_duplicate_list);
+
+ $('.js-hide-duplicate-suggestions').on('click', function(e){
+ e.preventDefault();
+ remove_duplicate_pins();
+ remove_duplicate_list(function(){
+ $('#form_title').focus();
+ });
+ });
+
+})();
diff --git a/web/js/front.js b/web/js/front.js
index 67486888b..1efa516fd 100644
--- a/web/js/front.js
+++ b/web/js/front.js
@@ -10,6 +10,7 @@ document.getElementById('pc').focus();
el.value = 1;
form.insertBefore(el, form.firstChild);
}
+
var around_links = document.querySelectorAll('a[href*="around"]');
for (i=0; i<around_links.length; i++) {
var link = around_links[i];
@@ -17,9 +18,20 @@ document.getElementById('pc').focus();
}
var lk = document.querySelector('span.report-a-problem-btn');
- if (lk.addEventListener) {
- lk.addEventListener('click', function(){
+ if (lk && lk.addEventListener) {
+ lk.addEventListener('click', function(e){
+ e.preventDefault();
+ scrollTo(0,0);
+ document.getElementById('pc').focus();
+ });
+ }
+
+ var cta = document.getElementById('report-cta');
+ if (cta && cta.addEventListener) {
+ cta.addEventListener('click', function(e) {
+ e.preventDefault();
scrollTo(0,0);
+ document.getElementById('pc').focus();
});
}
})();
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js
index 8f84e5c94..ae86269c9 100644
--- a/web/js/map-OpenLayers.js
+++ b/web/js/map-OpenLayers.js
@@ -15,6 +15,60 @@ var fixmystreet = fixmystreet || {};
fixmystreet.utils = fixmystreet.utils || {};
$.extend(fixmystreet.utils, {
+ array_to_csv_line: function(arr) {
+ var out = [], s;
+ for (var i=0; i<arr.length; i++) {
+ s = arr[i];
+ if (/[",]/.test(s)) {
+ s = '"' + s.replace('"', '""') + '"';
+ }
+ out.push(s);
+ }
+ return out.join(',');
+ },
+
+ // https://stackoverflow.com/questions/1293147/javascript-code-to-parse-csv-data/1293163#1293163
+ csv_to_array: function( strData, strDelimiter ) {
+ strDelimiter = (strDelimiter || ",");
+
+ var objPattern = new RegExp(
+ (
+ "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
+ "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
+ "([^\"\\" + strDelimiter + "\\r\\n]*))"
+ ),
+ "gi"
+ );
+
+ var arrData = [[]];
+
+ var arrMatches = objPattern.exec( strData );
+ while (arrMatches) {
+
+ var strMatchedDelimiter = arrMatches[ 1 ];
+
+ if ( strMatchedDelimiter.length &&
+ strMatchedDelimiter !== strDelimiter) {
+ arrData.push( [] );
+ }
+
+ var strMatchedValue;
+ if (arrMatches[ 2 ]) {
+ strMatchedValue = arrMatches[ 2 ].replace(
+ new RegExp( "\"\"", "g" ),
+ "\""
+ );
+ } else {
+ strMatchedValue = arrMatches[ 3 ];
+ }
+
+ arrData[ arrData.length - 1 ].push( strMatchedValue );
+ arrMatches = objPattern.exec( strData );
+ }
+
+ return( arrData );
+ },
+
parse_query_string: function() {
var qs = {};
if (!location.search) {
@@ -124,12 +178,19 @@ $.extend(fixmystreet.utils, {
return lonlat;
},
+ setup_inspector: function() {
+ setup_inspector_marker_drag();
+ },
+
markers_list: function(pins, transform) {
var markers = [];
var size = fixmystreet.maps.marker_size();
var selected_size = fixmystreet.maps.selected_marker_size();
for (var i=0; i<pins.length; i++) {
var pin = pins[i];
+ if (pin[1] == 0 && pin[0] == 0) {
+ continue;
+ }
var loc = new OpenLayers.Geometry.Point(pin[1], pin[0]);
if (transform) {
// The Strategy does this for us, so don't do it in that case.
@@ -140,13 +201,14 @@ $.extend(fixmystreet.utils, {
}
var id = pin[3] === undefined ? pin[3] : +pin[3];
var marker_size = (id === window.selected_problem_id) ? selected_size : size;
+ var draggable = (id === window.selected_problem_id) ? true : (pin[6] === false ? false : true);
var marker = new OpenLayers.Feature.Vector(loc, {
colour: pin[2],
size: pin[5] || marker_size,
faded: 0,
id: id,
title: pin[4] || '',
- draggable: pin[6] === false ? false : true
+ draggable: draggable
});
markers.push( marker );
}
@@ -157,10 +219,13 @@ $.extend(fixmystreet.utils, {
var size = fixmystreet.maps.marker_size();
var selected_size = fixmystreet.maps.selected_marker_size();
for (var i = 0; i < fixmystreet.markers.features.length; i++) {
- if (fixmystreet.markers.features[i].attributes.id == window.selected_problem_id) {
- fixmystreet.markers.features[i].attributes.size = selected_size;
+ var attr = fixmystreet.markers.features[i].attributes;
+ if (attr.id == window.selected_problem_id) {
+ attr.size = selected_size;
+ attr.draggable = true;
} else {
- fixmystreet.markers.features[i].attributes.size = size;
+ attr.size = size;
+ attr.draggable = false;
}
}
fixmystreet.markers.redraw();
@@ -219,6 +284,8 @@ $.extend(fixmystreet.utils, {
}
}
} );
+ // Allow handled feature click propagation to other click handlers
+ drag.handlers.feature.stopClick = false;
fixmystreet.map.addControl( drag );
drag.activate();
},
@@ -276,13 +343,29 @@ $.extend(fixmystreet.utils, {
$('#loading-indicator').attr('aria-hidden', true);
}
}
+ },
+
+ get_map_state: function() {
+ var centre = fixmystreet.map.getCenter();
+ return {
+ zoom: fixmystreet.map.getZoom(),
+ lat: centre.lat,
+ lon: centre.lon,
+ };
+ },
+
+ set_map_state: function(state) {
+ fixmystreet.map.setCenter(
+ new OpenLayers.LonLat( state.lon, state.lat ),
+ state.zoom
+ );
}
});
/* Make sure pins aren't going to reload just because we're zooming out,
* we already have the pins when the page loaded */
function zoomToBounds(bounds) {
- if (!bounds) { return; }
+ if (!bounds || !fixmystreet.markers.strategies) { return; }
var strategy = fixmystreet.markers.strategies[0];
strategy.deactivate();
var center = bounds.getCenterLonLat();
@@ -298,15 +381,15 @@ $.extend(fixmystreet.utils, {
function sidebar_highlight(problem_id) {
if (typeof problem_id !== 'undefined') {
- var $a = $('.item-list--reports a[href$="/' + problem_id + '"]');
- $a.parent().addClass('hovered');
+ var $li = $('[data-report-id="' + problem_id + '"]');
+ $li.addClass('hovered');
} else {
- $('.item-list--reports .hovered').removeClass('hovered');
+ $('.item-list .hovered').removeClass('hovered');
}
}
function marker_click(problem_id, evt) {
- var $a = $('.item-list--reports a[href$="/' + problem_id + '"]');
+ var $a = $('.item-list a[href$="/' + problem_id + '"]');
if (!$a[0]) {
return;
}
@@ -348,11 +431,25 @@ $.extend(fixmystreet.utils, {
}
function replace_query_parameter(qs, id, key) {
- var value = $('#' + id).val();
- if (value) {
- qs[key] = (typeof value === 'string') ? value : value.join(',');
+ var value,
+ $el = $('#' + id);
+ if (!$el[0]) {
+ return;
+ }
+ if ( $el[0].type === 'checkbox' ) {
+ value = $el[0].checked ? '1' : '';
+ if (value) {
+ qs[key] = value;
+ } else {
+ delete qs[key];
+ }
} else {
- delete qs[key];
+ value = $el.val();
+ if (value) {
+ qs[key] = (typeof value === 'string') ? value : fixmystreet.utils.array_to_csv_line(value);
+ } else {
+ delete qs[key];
+ }
}
return value;
}
@@ -369,22 +466,33 @@ $.extend(fixmystreet.utils, {
return new_url;
}
+ function update_history(qs, data) {
+ var new_url = update_url(qs);
+ history.pushState(data, null, new_url);
+
+ // Ensure the permalink control is updated when the filters change
+ var permalink_controls = fixmystreet.map.getControlsByClass(/Permalink/);
+ if (permalink_controls.length) {
+ permalink_controls[0].updateLink();
+ }
+ }
+
function page_changed_history() {
if (!('pushState' in history)) {
return;
}
var qs = fixmystreet.utils.parse_query_string();
- var page = $('.pagination').data('page');
+ var show_old_reports = replace_query_parameter(qs, 'show_old_reports', 'show_old_reports');
+ var page = $('.pagination:first').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);
+ update_history(qs, {
+ page_change: { 'page': page, 'show_old_reports': show_old_reports }
+ });
}
function categories_or_status_changed_history() {
@@ -395,11 +503,11 @@ $.extend(fixmystreet.utils, {
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');
+ var show_old_reports = replace_query_parameter(qs, 'show_old_reports', 'show_old_reports');
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);
+ update_history(qs, {
+ filter_change: { 'filter_categories': filter_categories, 'statuses': filter_statuses, 'sort': sort_key, 'show_old_reports': show_old_reports }
+ });
}
function setup_inspector_marker_drag() {
@@ -418,8 +526,8 @@ $.extend(fixmystreet.utils, {
$("#problem_easting").text(bng.x.toFixed(1));
$("#problem_latitude").text(lonlat.y.toFixed(6));
$("#problem_longitude").text(lonlat.x.toFixed(6));
- $("form#report_inspect_form input[name=latitude]").val(lonlat.y);
- $("form#report_inspect_form input[name=longitude]").val(lonlat.x);
+ $("input[name=latitude]").val(lonlat.y.toFixed(6));
+ $("input[name=longitude]").val(lonlat.x.toFixed(6));
},
false);
}
@@ -452,7 +560,8 @@ $.extend(fixmystreet.utils, {
$.extend(style.defaultStyle, { fillColor: 'black', strokeColor: 'black' });
}
var geometry = this.features[0].geometry;
- if (geometry.CLASS_NAME == 'OpenLayers.Geometry.Collection') {
+ if (geometry.CLASS_NAME == 'OpenLayers.Geometry.Collection' ||
+ geometry.CLASS_NAME == 'OpenLayers.Geometry.MultiPolygon') {
$.each(geometry.components, function(i, polygon) {
new_geometry.addComponents(polygon.components);
extent.extend(polygon.getBounds());
@@ -466,8 +575,10 @@ $.extend(fixmystreet.utils, {
f.geometry = new_geometry;
this.removeAllFeatures();
this.addFeatures([f]);
- var qs = fixmystreet.utils.parse_query_string();
- if (!qs.bbox) {
+ // Look at original href here to know if location was present at load.
+ // If it was, we don't want to zoom out to the bounds of the area.
+ var qs = OpenLayers.Util.getParameters(fixmystreet.original.href);
+ if (!qs.bbox && !qs.lat && !qs.lon) {
zoomToBounds(extent);
}
} else {
@@ -479,8 +590,8 @@ $.extend(fixmystreet.utils, {
renderers: ['SVGBig', 'VML', 'Canvas'],
strategies: [ new OpenLayers.Strategy.Fixed() ],
protocol: new OpenLayers.Protocol.HTTP({
- url: "/mapit/area/" + fixmystreet.area[i] + ".kml?simplify_tolerance=0.0001",
- format: new OpenLayers.Format.KML()
+ url: "/mapit/area/" + fixmystreet.area[i] + ".geojson?simplify_tolerance=0.0001",
+ format: new OpenLayers.Format.GeoJSON()
})
});
fixmystreet.map.addLayer(area);
@@ -619,23 +730,26 @@ $.extend(fixmystreet.utils, {
);
fixmystreet.map.addControl( fixmystreet.select_feature );
fixmystreet.select_feature.activate();
- fixmystreet.map.events.register( 'zoomend', null, fixmystreet.maps.markers_resize );
fixmystreet.map.events.register( 'zoomend', null, function() {
- fixmystreet.run(fixmystreet.maps.show_shortlist_control);
+ fixmystreet.maps.markers_resize();
+ $(fixmystreet).trigger('map:zoomend');
});
// Set up the event handlers to populate the filters and react to them changing
$("#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);
+ $("#show_old_reports").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);
+ var page = $('.pagination:first').data('page');
+ if ($(this).hasClass('show_old')) {
+ $("#show_old_reports").prop('checked', true);
+ } else if ($(this).hasClass('next')) {
+ $('.pagination:first').data('page', page + 1);
} else {
- $('.pagination').data('page', page - 1);
+ $('.pagination:first').data('page', page - 1);
}
fixmystreet.markers.protocol.use_page = true;
$(this).trigger('change');
@@ -643,6 +757,7 @@ $.extend(fixmystreet.utils, {
$("#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);
+ $("#show_old_reports").on("change.user", categories_or_status_changed_history);
$('.js-pagination').on('click', 'a', page_changed_history);
} else if (fixmystreet.page == 'new') {
drag.activate();
@@ -715,14 +830,15 @@ $.extend(fixmystreet.utils, {
fixmystreet.map.addLayer(layer);
}
- if (!fixmystreet.map.getCenter()) {
- var centre = new OpenLayers.LonLat( fixmystreet.longitude, fixmystreet.latitude );
- centre.transform(
- new OpenLayers.Projection("EPSG:4326"),
- fixmystreet.map.getProjectionObject()
+ // map.getCenter() returns a position in "map units", but sometimes you
+ // want the center in GPS-style latitude/longitude coordinates (WGS84)
+ // for example, to pass as GET params to fixmystreet.com/report/new.
+ fixmystreet.map.getCenterWGS84 = function() {
+ return fixmystreet.map.getCenter().transform(
+ fixmystreet.map.getProjectionObject(),
+ new OpenLayers.Projection("EPSG:4326")
);
- fixmystreet.map.setCenter(centre, fixmystreet.zoom || 3);
- }
+ };
if (document.getElementById('mapForm')) {
var click = fixmystreet.maps.click_control = new OpenLayers.Control.Click();
@@ -737,17 +853,26 @@ $.extend(fixmystreet.utils, {
onload();
}
- (function() {
- var timeout;
- $('#js-reports-list').on('mouseenter', '.item-list--reports__item', function(){
- var href = $('a', this).attr('href');
- var id = parseInt(href.replace(/^.*[\/]([0-9]+)$/, '$1'),10);
- clearTimeout(timeout);
- fixmystreet.maps.markers_highlight(id);
- }).on('mouseleave', '.item-list--reports__item', function(){
- timeout = setTimeout(fixmystreet.maps.markers_highlight, 50);
- });
- })();
+ // Allow external scripts to react to pans/zooms on the map,
+ // by subscribing to $(fixmystreet).on('maps:update_view')
+ fixmystreet.map.events.register('moveend', null, function(){
+ $(fixmystreet).trigger('maps:update_view');
+ });
+
+ if (!fixmystreet.map.events.extensions.buttonclick.isDeviceTouchCapable) {
+ // On touchscreens go straight to the report (see #2294).
+ (function() {
+ var timeout;
+ $('#js-reports-list').on('mouseenter', '.item-list--reports__item', function(){
+ var href = $('a', this).attr('href');
+ var id = parseInt(href.replace(/^.*[\/]([0-9]+)$/, '$1'),10);
+ clearTimeout(timeout);
+ fixmystreet.maps.markers_highlight(id);
+ }).on('mouseleave', '.item-list--reports__item', function(){
+ timeout = setTimeout(fixmystreet.maps.markers_highlight, 50);
+ });
+ })();
+ }
});
// End maps closure
@@ -786,9 +911,34 @@ OpenLayers.Control.PanZoomFMS = OpenLayers.Class(OpenLayers.Control.PanZoom, {
}
});
+OpenLayers.Control.ArgParserFMS = OpenLayers.Class(OpenLayers.Control.ArgParser, {
+ getParameters: function(url) {
+ var args = OpenLayers.Control.ArgParser.prototype.getParameters.apply(this, arguments);
+ // Get defaults from provided data if not in URL
+ if (!args.lat && !args.lon) {
+ args.lon = fixmystreet.longitude;
+ args.lat = fixmystreet.latitude;
+ }
+ if (args.lat && !args.zoom) {
+ args.zoom = fixmystreet.zoom || 3;
+ }
+ return args;
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ArgParserFMS"
+});
+
/* Overriding Permalink so that it can pass the correct zoom to OSM */
OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control.Permalink, {
_updateLink: function(alter_zoom) {
+ // this.base was originally set in initialize(), but the window's href
+ // may have changed since then if e.g. the map filters have been updated.
+ // NB this won't change the base of the 'problems nearby' permalink on
+ // /report, as this would result in it pointing at the wrong page.
+ if (this.base !== '/around' && fixmystreet.page !== 'report') {
+ this.base = window.location.href;
+ }
+
var separator = this.anchor ? '#' : '?';
var href = this.base;
if (href.indexOf(separator) != -1) {
@@ -801,7 +951,17 @@ OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control.Permalink,
if ( alter_zoom ) {
zoom += fixmystreet.zoomOffset;
}
- href += separator + OpenLayers.Util.getParameterString(this.createParams(center, zoom));
+
+ var params = this.createParams(center, zoom);
+
+ // Strip out the ugly OpenLayers layers state string
+ delete params.layers;
+ if (params.lat && params.lon) {
+ // No need for the postcode string either, if we have a latlon
+ delete params.pc;
+ }
+
+ href += separator + OpenLayers.Util.getParameterString(params);
// Could use mlat/mlon here as well if we are on a page with a marker
if (this.base == '/around') {
href += '&js=1';
@@ -813,15 +973,21 @@ OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control.Permalink,
else {
this.element.href = href;
}
+
+ if ('replaceState' in history) {
+ if (fixmystreet.page.match(/around|reports/)) {
+ history.replaceState(
+ history.state,
+ null,
+ href
+ );
+ }
+ }
},
updateLink: function() {
this._updateLink(0);
- }
-});
-OpenLayers.Control.PermalinkFMSz = OpenLayers.Class(OpenLayers.Control.PermalinkFMS, {
- updateLink: function() {
- this._updateLink(1);
- }
+ },
+ CLASS_NAME: "OpenLayers.Control.PermalinkFMS"
});
OpenLayers.Strategy.FixMyStreet = OpenLayers.Class(OpenLayers.Strategy.BBOX, {
@@ -889,6 +1055,13 @@ OpenLayers.Strategy.FixMyStreetFixed = OpenLayers.Class(OpenLayers.Strategy.Fixe
// is dragged (modulo a buffer extending outside the viewport).
// 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.
+
+fixmystreet.protocol_params = {
+ filter_category: 'filter_categories',
+ status: 'statuses',
+ sort: 'sort'
+};
+
OpenLayers.Protocol.FixMyStreet = OpenLayers.Class(OpenLayers.Protocol.HTTP, {
initial_page: null,
use_page: false,
@@ -896,15 +1069,18 @@ OpenLayers.Protocol.FixMyStreet = OpenLayers.Class(OpenLayers.Protocol.HTTP, {
read: function(options) {
// Pass the values of the category, status, and sort fields as query params
options.params = options.params || {};
- $.each({ filter_category: 'filter_categories', status: 'statuses', sort: 'sort' }, function(key, id) {
+ $.each(fixmystreet.protocol_params, function(key, id) {
var val = $('#' + id).val();
- if (val !== undefined) {
- options.params[key] = val;
+ if (val && val.length) {
+ options.params[key] = val.join ? fixmystreet.utils.array_to_csv_line(val) : val;
}
});
+ if ( $('#show_old_reports').is(':checked') ) {
+ options.params.show_old_reports = 1;
+ }
var page;
if (this.use_page) {
- page = $('.pagination').data('page');
+ page = $('.pagination:first').data('page');
this.use_page = false;
} else if (this.initial_page) {
page = 1;
@@ -930,6 +1106,11 @@ OpenLayers.Format.FixMyStreet = OpenLayers.Class(OpenLayers.Format.JSON, {
var reports_list;
if (typeof(obj.reports_list) != 'undefined' && (reports_list = document.getElementById('js-reports-list'))) {
reports_list.innerHTML = obj.reports_list;
+ if ( $('.item-list--reports').data('show-old-reports') ) {
+ $('#show_old_reports_wrapper').removeClass('hidden');
+ } else {
+ $('#show_old_reports_wrapper').addClass('hidden');
+ }
}
if (typeof(obj.pagination) != 'undefined') {
$('.js-pagination').html(obj.pagination);
diff --git a/web/js/map-OpenStreetMap.js b/web/js/map-OpenStreetMap.js
index 4165f8ee4..52eb95493 100644
--- a/web/js/map-OpenStreetMap.js
+++ b/web/js/map-OpenStreetMap.js
@@ -4,7 +4,7 @@ fixmystreet.maps.config = function() {
permalink_id = 'map_permalink';
}
fixmystreet.controls = [
- new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.ArgParserFMS(),
new OpenLayers.Control.Attribution(),
//new OpenLayers.Control.LayerSwitcher(),
new OpenLayers.Control.Navigation(),
diff --git a/web/js/map-bing-ol.js b/web/js/map-bing-ol.js
index 6662bf91a..6c9ab8a62 100644
--- a/web/js/map-bing-ol.js
+++ b/web/js/map-bing-ol.js
@@ -6,7 +6,7 @@ fixmystreet.maps.config = function() {
fixmystreet.controls = [
new OpenLayers.Control.Attribution(),
- new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.ArgParserFMS(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PermalinkFMS(permalink_id),
new OpenLayers.Control.PanZoomFMS({id: 'fms_pan_zoom' })
@@ -95,10 +95,10 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
get_urls: function(bounds, z) {
return [
- "//ecn.t0.tiles.virtualearth.net/tiles/r${id}.png?g=5941",
- "//ecn.t1.tiles.virtualearth.net/tiles/r${id}.png?g=5941",
- "//ecn.t2.tiles.virtualearth.net/tiles/r${id}.png?g=5941",
- "//ecn.t3.tiles.virtualearth.net/tiles/r${id}.png?g=5941"
+ "//ecn.t0.tiles.virtualearth.net/tiles/r${id}.png?g=6570",
+ "//ecn.t1.tiles.virtualearth.net/tiles/r${id}.png?g=6570",
+ "//ecn.t2.tiles.virtualearth.net/tiles/r${id}.png?g=6570",
+ "//ecn.t3.tiles.virtualearth.net/tiles/r${id}.png?g=6570"
];
},
diff --git a/web/js/map-fms.js b/web/js/map-fms.js
index 014bd58bb..ac27cfbce 100644
--- a/web/js/map-fms.js
+++ b/web/js/map-fms.js
@@ -1,4 +1,4 @@
-fixmystreet.maps.tile_base = [ [ '', 'a-', 'b-', 'c-' ], '//{S}tilma.mysociety.org/sv' ];
+fixmystreet.maps.tile_base = [ [ '', 'a-', 'b-', 'c-' ], '//{S}tilma.mysociety.org/oml' ];
fixmystreet.maps.config = (function(original) {
return function(){
@@ -39,10 +39,14 @@ OpenLayers.Layer.BingUK = OpenLayers.Class(OpenLayers.Layer.Bing, {
var c = this.map.getCenter();
var in_uk = c ? this.in_uk(c) : true;
if (z >= 16 && in_uk) {
- copyrights = 'Contains Ordnance Survey data &copy; Crown copyright and database right 2016';
+ copyrights = 'Contains Highways England and Ordnance Survey data &copy; Crown copyright and database right 2016';
} else {
logo = '<a href="https://www.bing.com/maps/"><img border=0 src="//dev.virtualearth.net/Branding/logo_powered_by.png"></a>';
- copyrights = '&copy; 2016 <a href="https://www.bing.com/maps/">Microsoft</a>. &copy; AND, Navteq, Ordnance Survey';
+ if (in_uk) {
+ copyrights = '&copy; 2016 <a href="https://www.bing.com/maps/">Microsoft</a>. &copy; AND, Navteq, Highways England, Ordnance Survey';
+ } else {
+ copyrights = '&copy; 2016 <a href="https://www.bing.com/maps/">Microsoft</a>. &copy; AND, Navteq, Ordnance Survey';
+ }
}
this._updateAttribution(copyrights, logo);
},
@@ -57,14 +61,14 @@ OpenLayers.Layer.BingUK = OpenLayers.Class(OpenLayers.Layer.Bing, {
}
} else {
var type = '';
- if (z > 10 && in_uk) {
+ if (z > 11 && in_uk) {
type = '&productSet=mmOS&key=' + fixmystreet.key;
}
urls = [
- "//ecn.t0.tiles.virtualearth.net/tiles/r${id}.png?g=5941" + type,
- "//ecn.t1.tiles.virtualearth.net/tiles/r${id}.png?g=5941" + type,
- "//ecn.t2.tiles.virtualearth.net/tiles/r${id}.png?g=5941" + type,
- "//ecn.t3.tiles.virtualearth.net/tiles/r${id}.png?g=5941" + type
+ "//ecn.t0.tiles.virtualearth.net/tiles/r${id}.png?g=6570" + type,
+ "//ecn.t1.tiles.virtualearth.net/tiles/r${id}.png?g=6570" + type,
+ "//ecn.t2.tiles.virtualearth.net/tiles/r${id}.png?g=6570" + type,
+ "//ecn.t3.tiles.virtualearth.net/tiles/r${id}.png?g=6570" + type
];
}
return urls;
diff --git a/web/js/map-google-ol.js b/web/js/map-google-ol.js
index 99670d4f2..4b2d818c9 100644
--- a/web/js/map-google-ol.js
+++ b/web/js/map-google-ol.js
@@ -23,7 +23,7 @@ fixmystreet.maps.config = function() {
}
fixmystreet.controls = [
- new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.ArgParserFMS(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PermalinkFMS(permalink_id),
new OpenLayers.Control.PanZoomFMS({id: 'fms_pan_zoom' })
diff --git a/web/js/map-streetview.js b/web/js/map-streetview.js
index 6d9195246..4701a7f20 100644
--- a/web/js/map-streetview.js
+++ b/web/js/map-streetview.js
@@ -1,6 +1,6 @@
fixmystreet.maps.config = function() {
fixmystreet.controls = [
- new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.ArgParserFMS(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.Permalink(),
new OpenLayers.Control.PanZoomFMS()
diff --git a/web/js/map-toner-lite.js b/web/js/map-toner-lite.js
index eda12ff28..0700dbb55 100644
--- a/web/js/map-toner-lite.js
+++ b/web/js/map-toner-lite.js
@@ -4,7 +4,7 @@ fixmystreet.maps.config = function() {
permalink_id = 'map_permalink';
}
fixmystreet.controls = [
- new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.ArgParserFMS(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PermalinkFMS(permalink_id),
new OpenLayers.Control.PanZoomFMS({id: 'fms_pan_zoom' })
diff --git a/web/js/map-wmts-bristol.js b/web/js/map-wmts-bristol.js
index 35f5ed0d6..88db20c52 100644
--- a/web/js/map-wmts-bristol.js
+++ b/web/js/map-wmts-bristol.js
@@ -104,7 +104,7 @@ fixmystreet.maps.config = function() {
}
fixmystreet.controls = [
- new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.ArgParserFMS(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PermalinkFMS(permalink_id)
];
diff --git a/web/js/map-wmts-zurich.js b/web/js/map-wmts-zurich.js
index eda0fbf44..346e9b89a 100644
--- a/web/js/map-wmts-zurich.js
+++ b/web/js/map-wmts-zurich.js
@@ -135,7 +135,7 @@ fixmystreet.maps.config = function() {
// This stuff is copied from js/map-bing-ol.js
fixmystreet.controls = [
- new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.ArgParserFMS(),
new OpenLayers.Control.Navigation()
];
if ( fixmystreet.page != 'report' || !$('html').hasClass('mobile') ) {
diff --git a/web/js/validation_rules.js b/web/js/validation_rules.js
index e6d745336..3e7b010f2 100644
--- a/web/js/validation_rules.js
+++ b/web/js/validation_rules.js
@@ -1,4 +1,4 @@
- validation_rules = {
+ core_validation_rules = {
title: { required: true },
detail: { required: true },
update: { required: true },
@@ -9,3 +9,5 @@
}
}
};
+
+ validation_rules = core_validation_rules;