aboutsummaryrefslogtreecommitdiffstats
path: root/web/js
diff options
context:
space:
mode:
Diffstat (limited to 'web/js')
-rw-r--r--web/js/dropzone.js.patch287
-rw-r--r--web/js/loading-attribute-polyfill.js213
-rw-r--r--web/js/map-OpenLayers.js57
-rw-r--r--web/js/map-OpenStreetMap.js45
-rw-r--r--web/js/map-bing-ol.js67
-rw-r--r--web/js/map-fms.js46
-rw-r--r--web/js/map-google.js2
-rw-r--r--web/js/map-mastermap.js5
8 files changed, 594 insertions, 128 deletions
diff --git a/web/js/dropzone.js.patch b/web/js/dropzone.js.patch
index b325b45d8..60a82709a 100644
--- a/web/js/dropzone.js.patch
+++ b/web/js/dropzone.js.patch
@@ -1,17 +1,92 @@
---- dropzone.5.1.1.js 2017-06-30 09:46:43.000000000 +0100
-+++ dropzone.exiffixes.js 2017-06-30 18:25:27.000000000 +0100
-@@ -1175,9 +1175,7 @@
- };
- if ((typeof EXIF !== "undefined" && EXIF !== null) && fixOrientation) {
- loadExif = function(callback) {
+--- dropzone.5.1.1.js 2020-06-30 15:56:05.557790000 +0100
++++ dropzone.exiffixes.js 2020-06-30 16:40:22.794951100 +0100
+@@ -26,7 +26,7 @@
+ */
+
+ (function() {
+- var Dropzone, Emitter, ExifRestore, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without,
++ var Dropzone, Emitter, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without,
+ slice = [].slice,
+ extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+@@ -1123,7 +1123,7 @@
+ };
+
+ Dropzone.prototype.resizeImage = function(file, width, height, resizeMethod, callback) {
+- return this.createThumbnail(file, width, height, resizeMethod, false, (function(_this) {
++ return this.createThumbnail(file, width, height, resizeMethod, true, (function(_this) {
+ return function(dataUrl, canvas) {
+ var resizeMimeType, resizedDataURL;
+ if (canvas === null) {
+@@ -1134,9 +1134,6 @@
+ resizeMimeType = file.type;
+ }
+ resizedDataURL = canvas.toDataURL(resizeMimeType, _this.options.resizeQuality);
+- if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') {
+- resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL);
+- }
+ return callback(Dropzone.dataURItoBlob(resizedDataURL));
+ }
+ };
+@@ -1164,23 +1161,17 @@
+ Dropzone.prototype.createThumbnailFromUrl = function(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) {
+ var img;
+ img = document.createElement("img");
++
++ // FixOrientation not needed anymore with browsers handling imageOrientation
++ fixOrientation = (getComputedStyle(document.body)['imageOrientation'] == 'from-image') ? false : fixOrientation;
++
+ if (crossOrigin) {
+ img.crossOrigin = crossOrigin;
+ }
+ img.onload = (function(_this) {
+ return function() {
+- var loadExif;
+- loadExif = function(callback) {
+- return callback(1);
+- };
+- if ((typeof EXIF !== "undefined" && EXIF !== null) && fixOrientation) {
+- loadExif = function(callback) {
- return EXIF.getData(img, function() {
- return callback(EXIF.getTag(this, 'Orientation'));
- });
-+ return callback(EXIF.getData(img));
- };
- }
- return loadExif(function(orientation) {
-@@ -1601,7 +1599,7 @@
+- };
+- }
+- return loadExif(function(orientation) {
++ var orientation = fixOrientation ? EXIF.getData(img) : 1;
++
+ var canvas, ctx, ref, ref1, ref2, ref3, resizeInfo, thumbnail;
+ file.width = img.width;
+ file.height = img.height;
+@@ -1212,23 +1203,23 @@
+ break;
+ case 6:
+ ctx.rotate(0.5 * Math.PI);
+- ctx.translate(0, -canvas.height);
++ ctx.translate(0, -canvas.width);
+ break;
+ case 7:
+ ctx.rotate(0.5 * Math.PI);
+- ctx.translate(canvas.width, -canvas.height);
++ ctx.translate(canvas.height, -canvas.width);
+ ctx.scale(-1, 1);
+ break;
+ case 8:
+ ctx.rotate(-0.5 * Math.PI);
+- ctx.translate(-canvas.width, 0);
++ ctx.translate(-canvas.height, 0);
+ }
+ drawImageIOSFix(ctx, img, (ref = resizeInfo.srcX) != null ? ref : 0, (ref1 = resizeInfo.srcY) != null ? ref1 : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, (ref2 = resizeInfo.trgX) != null ? ref2 : 0, (ref3 = resizeInfo.trgY) != null ? ref3 : 0, resizeInfo.trgWidth, resizeInfo.trgHeight);
+ thumbnail = canvas.toDataURL("image/png");
+ if (callback != null) {
+ return callback(thumbnail, canvas);
+ }
+- });
++
+ };
+ })(this);
+ if (callback != null) {
+@@ -1601,7 +1592,7 @@
return results;
};
@@ -20,31 +95,165 @@
Dropzone.isBrowserSupported = function() {
var capableBrowser, j, len, ref, regex;
-@@ -1904,6 +1902,27 @@
- var array, ato, buf, imageData, mae, separatePoint;
- imageData = resizedFileBase64.replace('data:image/jpeg;base64,', '');
- buf = this.decode64(imageData);
-+
-+ // Certain browsers (I'm looking at you, Safari) 'helpfully' provide their
-+ // own EXIF data in the JPEG returned from HTMLCanvasElement.toDataURL.
-+ // Dropzone doesn't take this into account when restoring the original
-+ // file's EXIF, meaning the final uploaded file has two sets of EXIF.
-+ // Certain JPEG tools (I'm looking at you, jhead) don't really handle this
-+ // very well, either ignoring the duplicate EXIF, picking the wrong one
-+ // or refusing to process the file entirely.
-+ // Seems like the best way out of this mess is to make sure the uploaded
-+ // JPEG only ever has one EXIF header. In this case, we want to keep the
-+ // EXIF from the original file.
-+ // This little loop inspects the new JPEG from the toDataURL call and
-+ // strips out any existing EXIF headers (technically any APP1 headers,
-+ // but same difference in this case).
-+ for (var i = 0; i < buf.length; i++) {
-+ if (buf[i] === 255 && buf[i+1] === 225) {
-+ var length = buf[i + 2] * 256 + buf[i + 3] + 2;
-+ buf.splice(i, length);
-+ }
-+ }
-+
- separatePoint = buf.indexOf(255, 3);
- mae = buf.slice(0, separatePoint);
- ato = buf.slice(separatePoint);
+@@ -1828,161 +1819,6 @@
+ return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
+ };
+
+- ExifRestore = (function() {
+- function ExifRestore() {}
+-
+- ExifRestore.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+-
+- ExifRestore.encode64 = function(input) {
+- var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output;
+- output = '';
+- chr1 = void 0;
+- chr2 = void 0;
+- chr3 = '';
+- enc1 = void 0;
+- enc2 = void 0;
+- enc3 = void 0;
+- enc4 = '';
+- i = 0;
+- while (true) {
+- chr1 = input[i++];
+- chr2 = input[i++];
+- chr3 = input[i++];
+- enc1 = chr1 >> 2;
+- enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+- enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+- enc4 = chr3 & 63;
+- if (isNaN(chr2)) {
+- enc3 = enc4 = 64;
+- } else if (isNaN(chr3)) {
+- enc4 = 64;
+- }
+- output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
+- chr1 = chr2 = chr3 = '';
+- enc1 = enc2 = enc3 = enc4 = '';
+- if (!(i < input.length)) {
+- break;
+- }
+- }
+- return output;
+- };
+-
+- ExifRestore.restore = function(origFileBase64, resizedFileBase64) {
+- var image, rawImage, segments;
+- if (!origFileBase64.match('data:image/jpeg;base64,')) {
+- return resizedFileBase64;
+- }
+- rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', ''));
+- segments = this.slice2Segments(rawImage);
+- image = this.exifManipulation(resizedFileBase64, segments);
+- return 'data:image/jpeg;base64,' + this.encode64(image);
+- };
+-
+- ExifRestore.exifManipulation = function(resizedFileBase64, segments) {
+- var aBuffer, exifArray, newImageArray;
+- exifArray = this.getExifArray(segments);
+- newImageArray = this.insertExif(resizedFileBase64, exifArray);
+- aBuffer = new Uint8Array(newImageArray);
+- return aBuffer;
+- };
+-
+- ExifRestore.getExifArray = function(segments) {
+- var seg, x;
+- seg = void 0;
+- x = 0;
+- while (x < segments.length) {
+- seg = segments[x];
+- if (seg[0] === 255 & seg[1] === 225) {
+- return seg;
+- }
+- x++;
+- }
+- return [];
+- };
+-
+- ExifRestore.insertExif = function(resizedFileBase64, exifArray) {
+- var array, ato, buf, imageData, mae, separatePoint;
+- imageData = resizedFileBase64.replace('data:image/jpeg;base64,', '');
+- buf = this.decode64(imageData);
+- separatePoint = buf.indexOf(255, 3);
+- mae = buf.slice(0, separatePoint);
+- ato = buf.slice(separatePoint);
+- array = mae;
+- array = array.concat(exifArray);
+- array = array.concat(ato);
+- return array;
+- };
+-
+- ExifRestore.slice2Segments = function(rawImageArray) {
+- var endPoint, head, length, seg, segments;
+- head = 0;
+- segments = [];
+- while (true) {
+- if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) {
+- break;
+- }
+- if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) {
+- head += 2;
+- } else {
+- length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3];
+- endPoint = head + length + 2;
+- seg = rawImageArray.slice(head, endPoint);
+- segments.push(seg);
+- head = endPoint;
+- }
+- if (head > rawImageArray.length) {
+- break;
+- }
+- }
+- return segments;
+- };
+-
+- ExifRestore.decode64 = function(input) {
+- var base64test, buf, chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output;
+- output = '';
+- chr1 = void 0;
+- chr2 = void 0;
+- chr3 = '';
+- enc1 = void 0;
+- enc2 = void 0;
+- enc3 = void 0;
+- enc4 = '';
+- i = 0;
+- buf = [];
+- base64test = /[^A-Za-z0-9\+\/\=]/g;
+- if (base64test.exec(input)) {
+- console.warning('There were invalid base64 characters in the input text.\n' + 'Valid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\n' + 'Expect errors in decoding.');
+- }
+- input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
+- while (true) {
+- enc1 = this.KEY_STR.indexOf(input.charAt(i++));
+- enc2 = this.KEY_STR.indexOf(input.charAt(i++));
+- enc3 = this.KEY_STR.indexOf(input.charAt(i++));
+- enc4 = this.KEY_STR.indexOf(input.charAt(i++));
+- chr1 = enc1 << 2 | enc2 >> 4;
+- chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+- chr3 = (enc3 & 3) << 6 | enc4;
+- buf.push(chr1);
+- if (enc3 !== 64) {
+- buf.push(chr2);
+- }
+- if (enc4 !== 64) {
+- buf.push(chr3);
+- }
+- chr1 = chr2 = chr3 = '';
+- enc1 = enc2 = enc3 = enc4 = '';
+- if (!(i < input.length)) {
+- break;
+- }
+- }
+- return buf;
+- };
+-
+- return ExifRestore;
+-
+- })();
+-
+-
+ /*
+ * contentloaded.js
+ *
diff --git a/web/js/loading-attribute-polyfill.js b/web/js/loading-attribute-polyfill.js
new file mode 100644
index 000000000..f11397985
--- /dev/null
+++ b/web/js/loading-attribute-polyfill.js
@@ -0,0 +1,213 @@
+/*
+ * Loading attribute polyfill - https://github.com/mfranzke/loading-attribute-polyfill
+ * @license Copyright(c) 2019 by Maximilian Franzke
+ * Credits for the initial kickstarter / script to @Sora2455, and supported by @cbirdsong, @eklingen, @DaPo, @nextgenthemes, @diogoterremoto, @dracos, @Flimm, @TomS- and @vinyfc93 - many thanks for that !
+ */
+/*
+ * A minimal and dependency-free vanilla JavaScript loading attribute polyfill.
+ * Supports standard's functionality and tests for native support upfront.
+ * Elsewhere the functionality gets emulated with the support of noscript wrapper tags.
+ * Use an IntersectionObserver polyfill in case of IE11 support necessary.
+ *
+ * MS - Removed iframe/picture/srcset parts, unneeded at present, and added external API
+ */
+
+(function () {
+ 'use strict';
+
+ var config = {
+ // Start download if the item gets within 256px in the Y axis
+ rootMargin: '256px 0px',
+ threshold: 0.01
+ };
+
+ // Device/browser capabilities object
+ var capabilities = {
+ loading: 'loading' in HTMLImageElement.prototype,
+ scrolling: 'onscroll' in window
+ };
+
+ // Nodelist foreach polyfill / source: https://stackoverflow.com/a/46929259
+ if (
+ typeof NodeList !== 'undefined' &&
+ NodeList.prototype &&
+ !NodeList.prototype.forEach
+ ) {
+ // Yes, there's really no need for `Object.defineProperty` here
+ NodeList.prototype.forEach = Array.prototype.forEach;
+ }
+
+ // Define according to browsers support of the IntersectionObserver feature (missing e.g. on IE11 or Safari 11)
+ var intersectionObserver;
+
+ if ('IntersectionObserver' in window) {
+ intersectionObserver = new IntersectionObserver(onIntersection, config);
+ }
+
+ // On using a browser w/o requestAnimationFrame support (IE9, Opera Mini), just run the passed function
+ var rAFWrapper;
+
+ if ('requestAnimationFrame' in window) {
+ rAFWrapper = window.requestAnimationFrame;
+ } else {
+ rAFWrapper = function (func) {
+ func();
+ };
+ }
+
+ /**
+ * Put the source back where it belongs - now that the elements content is attached to the document, it will load now
+ * @param {Object} lazyItem Current item to be restored after lazy loading.
+ */
+ function restoreSource(lazyItem) {
+ lazyItem.setAttribute('src', lazyItem.getAttribute('data-lazy-src'));
+ lazyItem.removeAttribute('data-lazy-src'); // Not using delete .dataset here for compatibility down to IE9
+ }
+
+ /**
+ * Handle IntersectionObservers callback
+ * @param {Object} entries Target elements Intersection observed changes
+ * @param {Object} observer IntersectionObserver instance reference
+ */
+ function onIntersection(entries, observer) {
+ entries.forEach(function (entry) {
+ // Mitigation for EDGE lacking support of .isIntersecting until v15, compare to e.g. https://github.com/w3c/IntersectionObserver/issues/211#issuecomment-309144669
+ if (entry.intersectionRatio === 0) {
+ return;
+ }
+
+ // If the item is visible now, load it and stop watching it
+ var lazyItem = entry.target;
+
+ observer.unobserve(lazyItem);
+
+ restoreSource(lazyItem);
+ });
+ }
+
+ /**
+ * Handle printing the page
+ */
+ function onPrinting() {
+ if (typeof window.matchMedia === 'undefined') {
+ return;
+ }
+
+ var mediaQueryList = window.matchMedia('print');
+
+ mediaQueryList.addListener(function (mql) {
+ if (mql.matches) {
+ document
+ .querySelectorAll('img[loading="lazy"][data-lazy-src]')
+ .forEach(function (lazyItem) {
+ restoreSource(lazyItem);
+ });
+ }
+ });
+ }
+
+ /**
+ * Get and prepare the HTML code depending on feature detection,
+ * and if not scrolling supported, because it's a Google or Bing Bot
+ * @param {String} lazyAreaHtml Noscript inner HTML code that src-urls need to get rewritten
+ */
+ function getAndPrepareHTMLCode(noScriptTag) {
+ // The contents of a <noscript> tag are treated as text to JavaScript
+ var lazyAreaHtml = noScriptTag.textContent || noScriptTag.innerHTML;
+
+ var getImageWidth = lazyAreaHtml.match(/width=['"](\d+)['"]/) || false;
+ var temporaryImageWidth = getImageWidth[1] || 1;
+ var getImageHeight = lazyAreaHtml.match(/height=['"](\d+)['"]/) || false;
+ var temporaryImageHeight = getImageHeight[1] || 1;
+
+ var temporaryImage =
+ 'data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 ' +
+ temporaryImageWidth +
+ ' ' +
+ temporaryImageHeight +
+ '%27%3E%3C/svg%3E';
+
+ if (!capabilities.loading && capabilities.scrolling) {
+ // Check for IntersectionObserver support
+ if (typeof intersectionObserver === 'undefined') {
+ // Attach abandonned attribute 'lazyload' to the HTML tags on browsers w/o IntersectionObserver being available
+ lazyAreaHtml = lazyAreaHtml.replace(
+ /(?:\r\n|\r|\n|\t| )src=/g,
+ ' lazyload="1" src='
+ );
+ } else {
+ // Temporarily replace a expensive resource load with a simple one by storing the actual source for later and point src to a temporary replacement (data URI)
+ lazyAreaHtml = lazyAreaHtml
+ .replace(
+ /(?:\r\n|\r|\n|\t| )src=/g,
+ ' src="' + temporaryImage + '" data-lazy-src='
+ );
+ }
+ }
+
+ return lazyAreaHtml;
+ }
+
+ /**
+ * Retrieve the elements from the 'lazy load' <noscript> tag and prepare them for display
+ * @param {Object} noScriptTag noscript HTML tag that should get initially transformed
+ */
+ function prepareElement(noScriptTag) {
+ // Sticking the noscript HTML code in the innerHTML of a new <div> tag to 'load' it after creating that <div>
+ var lazyArea = document.createElement('div');
+
+ lazyArea.innerHTML = getAndPrepareHTMLCode(noScriptTag);
+
+ // Move all children out of the element
+ while (lazyArea.firstChild) {
+ if (
+ !capabilities.loading &&
+ capabilities.scrolling &&
+ typeof intersectionObserver !== 'undefined' &&
+ lazyArea.firstChild.tagName &&
+ lazyArea.firstChild.tagName.toLowerCase() === 'img'
+ ) {
+ // Observe the item so that loading could start when it gets close to the viewport
+ intersectionObserver.observe(lazyArea.firstChild);
+ }
+
+ noScriptTag.parentNode.insertBefore(lazyArea.firstChild, noScriptTag);
+ }
+
+ // Remove the empty element - not using .remove() here for IE11 compatibility
+ noScriptTag.parentNode.removeChild(noScriptTag); // Preferred .removeChild over .remove here for IE
+ }
+
+ /* Add a function we can call externally */
+ fixmystreet.loading_recheck = function() {
+ var lazyLoadAreas = document.querySelectorAll('noscript.loading-lazy');
+ lazyLoadAreas.forEach(prepareElement);
+ };
+
+ /**
+ * Get all the <noscript> tags on the page and setup the printing
+ */
+ function prepareElements() {
+ fixmystreet.loading_recheck();
+
+ // Bind for someone printing the page
+ onPrinting();
+ }
+
+ // If the page has loaded already, run setup - if it hasn't, run as soon as it has.
+ // Use requestAnimationFrame as this will propably cause repaints
+ // document.readyState values: https://www.w3schools.com/jsref/prop_doc_readystate.asp
+ if (/comp|inter/.test(document.readyState)) {
+ rAFWrapper(prepareElements);
+ } else if ('addEventListener' in document) {
+ document.addEventListener('DOMContentLoaded', function () {
+ rAFWrapper(prepareElements);
+ });
+ } else {
+ document.attachEvent('onreadystatechange', function () {
+ if (document.readyState === 'complete') {
+ prepareElements();
+ }
+ });
+ }
+})();
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js
index 182cd79a1..ada51cbc0 100644
--- a/web/js/map-OpenLayers.js
+++ b/web/js/map-OpenLayers.js
@@ -132,20 +132,32 @@ $.extend(fixmystreet.utils, {
new OpenLayers.Projection("EPSG:4326")
);
- var lat = transformedLonlat.lat.toFixed(6);
- var lon = transformedLonlat.lon.toFixed(6);
-
- document.getElementById('fixmystreet.latitude').value = lat;
- document.getElementById('fixmystreet.longitude').value = lon;
-
+ fixmystreet.maps.update_pin_input_fields(transformedLonlat);
$(fixmystreet).trigger('maps:update_pin', [ lonlat ]);
+ var lat = transformedLonlat.lat.toFixed(6);
+ var lon = transformedLonlat.lon.toFixed(6);
return {
'url': { 'lon': lon, 'lat': lat },
'state': { 'lon': lonlat.lon, 'lat': lonlat.lat }
};
},
+ update_pin_input_fields: function(lonlat) {
+ var bng = lonlat.clone().transform(
+ new OpenLayers.Projection("EPSG:4326"),
+ new OpenLayers.Projection("EPSG:27700") // TODO: Handle other projections
+ );
+ var lat = lonlat.lat.toFixed(6);
+ var lon = lonlat.lon.toFixed(6);
+ $("#problem_northing").text(bng.lat.toFixed(1));
+ $("#problem_easting").text(bng.lon.toFixed(1));
+ $("#problem_latitude").text(lat);
+ $("#problem_longitude").text(lon);
+ $("input[name=latitude]").val(lat);
+ $("input[name=longitude]").val(lon);
+ },
+
display_around: function() {
// Required after changing the size of the map element
fixmystreet.map.updateSize();
@@ -278,9 +290,12 @@ $.extend(fixmystreet.utils, {
// 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) {
+ if (fixmystreet.maps.admin_drag_control) {
+ return;
+ }
confirm_change = confirm_change || false;
var original_lonlat;
- var drag = new OpenLayers.Control.DragFeatureFMS( fixmystreet.markers, {
+ var drag = fixmystreet.maps.admin_drag_control = new OpenLayers.Control.DragFeatureFMS( 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.
@@ -627,17 +642,9 @@ $.extend(fixmystreet.utils, {
// 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));
- $("#problem_latitude").text(lonlat.y.toFixed(6));
- $("#problem_longitude").text(lonlat.x.toFixed(6));
- $("input[name=latitude]").val(lonlat.y.toFixed(6));
- $("input[name=longitude]").val(lonlat.x.toFixed(6));
+ fixmystreet.maps.admin_drag(function(geom) {
+ var lonlat = new OpenLayers.LonLat(geom.x, geom.y);
+ fixmystreet.maps.update_pin_input_fields(lonlat);
},
false);
}
@@ -958,6 +965,8 @@ $.extend(fixmystreet.utils, {
);
} else if (layer_options.matrixIds) {
layer = new fixmystreet.map_type(layer_options);
+ } else if (fixmystreet.layer_options[i].map_type) {
+ layer = new fixmystreet.layer_options[i].map_type(fixmystreet.layer_name, layer_options);
} else {
layer = new fixmystreet.map_type(fixmystreet.layer_name, layer_options);
}
@@ -1278,6 +1287,9 @@ 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 (fixmystreet.loading_recheck) {
+ fixmystreet.loading_recheck();
+ }
if ( $('.item-list--reports').data('show-old-reports') ) {
$('#show_old_reports_wrapper').removeClass('hidden');
} else {
@@ -1318,8 +1330,13 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
// If we are looking at an individual report, and the report was
// ajaxed into the DOM from the all reports page, then clicking
// the map background should take us back to the all reports list.
- if ($('.js-back-to-report-list').length) {
- $('.js-back-to-report-list').trigger('click');
+ var asset_button_clicked = $('.btn--change-asset').hasClass('asset-spot');
+ if (asset_button_clicked) {
+ return true;
+ }
+ var back_link = $('.js-back-to-report-list');
+ if (back_link.length) {
+ back_link.trigger('click');
return true;
}
diff --git a/web/js/map-OpenStreetMap.js b/web/js/map-OpenStreetMap.js
index 9ed3a2ee3..46aba1c91 100644
--- a/web/js/map-OpenStreetMap.js
+++ b/web/js/map-OpenStreetMap.js
@@ -7,6 +7,13 @@ fixmystreet.maps.config = function() {
new OpenLayers.Control.PermalinkFMS('map'),
new OpenLayers.Control.PanZoomFMS({id: 'fms_pan_zoom' })
];
+
+ if (OpenLayers.Layer.BingAerial) {
+ fixmystreet.layer_options = [
+ { map_type: fixmystreet.map_type },
+ { map_type: OpenLayers.Layer.BingAerial }
+ ];
+ }
};
// http://www.openstreetmap.org/openlayers/OpenStreetMap.js (added maxResolution)
@@ -34,7 +41,7 @@ OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, {
options = OpenLayers.Util.extend({
/* Below line added to OSM's file in order to allow minimum zoom level */
maxResolution: 156543.03390625/Math.pow(2, options.zoomOffset || 0),
- numZoomLevels: 19,
+ numZoomLevels: 20,
buffer: 0
}, options);
var newArguments = [name, url, options];
@@ -45,40 +52,6 @@ OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, {
});
/**
- * Class: OpenLayers.Layer.OSM.MapQuestOpen
- *
- * Inherits from:
- * - <OpenLayers.Layer.OSM>
- */
-OpenLayers.Layer.OSM.MapQuestOpen = OpenLayers.Class(OpenLayers.Layer.OSM, {
- /**
- * Constructor: OpenLayers.Layer.OSM.MapQuestOpen
- *
- * Parameters:
- * name - {String}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, options) {
- var url = [
- "https://otile1-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png",
- "https://otile2-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png",
- "https://otile3-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png",
- "https://otile4-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png"
- ];
- options = OpenLayers.Util.extend({
- /* Below line added to OSM's file in order to allow minimum zoom level */
- maxResolution: 156543.03390625/Math.pow(2, options.zoomOffset || 0),
- numZoomLevels: 19,
- buffer: 0
- }, options);
- var newArguments = [name, url, options];
- OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
- },
-
- CLASS_NAME: "OpenLayers.Layer.OSM.MapQuestOpen"
-});
-
-/**
* Class: OpenLayers.Layer.OSM.CycleMap
*
* Inherits from:
@@ -101,7 +74,7 @@ OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
options = OpenLayers.Util.extend({
/* Below line added to OSM's file in order to allow minimum zoom level */
maxResolution: 156543.03390625/Math.pow(2, options.zoomOffset || 0),
- numZoomLevels: 19,
+ numZoomLevels: 20,
buffer: 0
}, options);
var newArguments = [name, url, options];
diff --git a/web/js/map-bing-ol.js b/web/js/map-bing-ol.js
index 4e01ff58b..c44cf96f8 100644
--- a/web/js/map-bing-ol.js
+++ b/web/js/map-bing-ol.js
@@ -10,10 +10,30 @@ fixmystreet.maps.config = function() {
if ( fixmystreet.page == 'report' ) {
fixmystreet.controls.push( new OpenLayers.Control.PermalinkFMS('key-tool-problems-nearby', '/around') );
}
- fixmystreet.map_type = OpenLayers.Layer.Bing;
};
+(function() {
+ $(function(){
+ $('#map_layer_toggle').click(function(e) {
+ e.preventDefault();
+ var $this = $(this);
+ if ($this.text() == translation_strings.map_aerial) {
+ $this.text(translation_strings.map_roads);
+ fixmystreet.map.setBaseLayer(fixmystreet.map.layers[1]);
+ } else {
+ $this.text(translation_strings.map_aerial);
+ fixmystreet.map.setBaseLayer(fixmystreet.map.layers[0]);
+ }
+ });
+ // If page loaded with Aerial as starting, rather than default road
+ if ($('#map_layer_toggle').text() == translation_strings.map_roads) {
+ fixmystreet.map.setBaseLayer(fixmystreet.map.layers[1]);
+ }
+ });
+})();
+
OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
+ tile_base: '//t{S}.ssl.ak.dynamic.tiles.virtualearth.net/comp/ch/${id}?mkt=en-US&it=G,L&src=t&shading=hill&og=969&n=z',
attributionTemplate: '${logo}${copyrights}',
setMap: function() {
@@ -35,7 +55,8 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
},
updateAttribution: function() {
- var copyrights = '&copy; 2011 <a href="https://www.bing.com/maps/">Microsoft</a>. &copy; AND, Navteq';
+ var year = (new Date()).getFullYear();
+ var copyrights = '&copy; ' + year + ' <a href="https://www.bing.com/maps/">Microsoft</a>, HERE';
var logo = '<a href="https://www.bing.com/maps/"><img border=0 src="//dev.virtualearth.net/Branding/logo_powered_by.png"></a>';
this._updateAttribution(copyrights, logo);
},
@@ -45,7 +66,7 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
options = OpenLayers.Util.extend({
/* Below line added to OSM's file in order to allow minimum zoom level */
maxResolution: 156543.03390625/Math.pow(2, options.zoomOffset || 0),
- numZoomLevels: 19,
+ numZoomLevels: 20,
sphericalMercator: true,
buffer: 0
}, options);
@@ -89,13 +110,41 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
},
get_urls: function(bounds, z) {
- return [
- "//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"
- ];
+ var urls = [];
+ for (var i=0; i<4; i++) {
+ urls.push(this.tile_base.replace('{S}', i));
+ }
+ return urls;
},
CLASS_NAME: "OpenLayers.Layer.Bing"
});
+
+OpenLayers.Layer.BingAerial = OpenLayers.Class(OpenLayers.Layer.Bing, {
+ tile_base: '//t{S}.ssl.ak.dynamic.tiles.virtualearth.net/comp/ch/${id}?mkt=en-US&it=A,G,L&src=t&og=969&n=z',
+
+ setMap: function() {
+ OpenLayers.Layer.Bing.prototype.setMap.apply(this, arguments);
+ this.map.events.register("moveend", this, this.updateAttribution);
+ },
+
+ updateAttribution: function() {
+ var z = this.map.getZoom() + this.zoomOffset;
+ var year = (new Date()).getFullYear();
+ var copyrights = '&copy; ' + year + ' <a href="https://www.bing.com/maps/">Microsoft</a>, HERE, ';
+ if (z >= 13) {
+ copyrights += 'Maxar, CNES Distribution Airbus DS';
+ } else {
+ copyrights += 'Earthstar Geographics SIO';
+ }
+ var logo = '<a href="https://www.bing.com/maps/"><img border=0 src="//dev.virtualearth.net/Branding/logo_powered_by.png"></a>';
+ this._updateAttribution(copyrights, logo);
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.BingAerial"
+});
+
+fixmystreet.layer_options = [
+ { map_type: OpenLayers.Layer.Bing },
+ { map_type: OpenLayers.Layer.BingAerial }
+];
diff --git a/web/js/map-fms.js b/web/js/map-fms.js
index ac27cfbce..bb51467a7 100644
--- a/web/js/map-fms.js
+++ b/web/js/map-fms.js
@@ -1,11 +1,4 @@
-fixmystreet.maps.tile_base = [ [ '', 'a-', 'b-', 'c-' ], '//{S}tilma.mysociety.org/oml' ];
-
-fixmystreet.maps.config = (function(original) {
- return function(){
- original();
- fixmystreet.map_type = OpenLayers.Layer.BingUK;
- };
-})(fixmystreet.maps.config);
+fixmystreet.maps.tile_base = '//{S}tilma.mysociety.org/oml';
OpenLayers.Layer.BingUK = OpenLayers.Class(OpenLayers.Layer.Bing, {
uk_bounds: [
@@ -38,41 +31,48 @@ OpenLayers.Layer.BingUK = OpenLayers.Class(OpenLayers.Layer.Bing, {
var logo = '';
var c = this.map.getCenter();
var in_uk = c ? this.in_uk(c) : true;
+ var year = (new Date()).getFullYear();
if (z >= 16 && in_uk) {
- copyrights = 'Contains Highways England and Ordnance Survey data &copy; Crown copyright and database right 2016';
+ copyrights = 'Contains Highways England and Ordnance Survey data &copy; Crown copyright and database right ' + year;
} else {
logo = '<a href="https://www.bing.com/maps/"><img border=0 src="//dev.virtualearth.net/Branding/logo_powered_by.png"></a>';
if (in_uk) {
- copyrights = '&copy; 2016 <a href="https://www.bing.com/maps/">Microsoft</a>. &copy; AND, Navteq, Highways England, Ordnance Survey';
+ copyrights = '&copy; ' + year + ' <a href="https://www.bing.com/maps/">Microsoft</a>, HERE, Highways England, Ordnance Survey';
} else {
- copyrights = '&copy; 2016 <a href="https://www.bing.com/maps/">Microsoft</a>. &copy; AND, Navteq, Ordnance Survey';
+ copyrights = '&copy; ' + year + ' <a href="https://www.bing.com/maps/">Microsoft</a>, HERE, Ordnance Survey';
}
}
this._updateAttribution(copyrights, logo);
},
+ tile_prefix: [ '', 'a-', 'b-', 'c-' ],
+
get_urls: function(bounds, z) {
- var urls;
+ var urls = [], i;
var in_uk = this.in_uk(bounds.getCenterLonLat());
if (z >= 16 && in_uk) {
urls = [];
- for (var i=0; i< fixmystreet.maps.tile_base[0].length; i++) {
- urls.push( fixmystreet.maps.tile_base[1].replace('{S}', fixmystreet.maps.tile_base[0][i]) + "/${z}/${x}/${y}.png" );
+ for (i=0; i< this.tile_prefix.length; i++) {
+ urls.push( fixmystreet.maps.tile_base.replace('{S}', this.tile_prefix[i]) + "/${z}/${x}/${y}.png" );
+ }
+ } else if (z > 11 && in_uk) {
+ var type = 'g=8702&lbl=l1&productSet=mmOS&key=' + fixmystreet.key;
+ var tile_base = "//ecn.t{S}.tiles.virtualearth.net/tiles/r${id}?" + type;
+ for (i=0; i<4; i++) {
+ urls.push(tile_base.replace('{S}', i));
}
} else {
- var type = '';
- if (z > 11 && in_uk) {
- type = '&productSet=mmOS&key=' + fixmystreet.key;
+ for (i=0; i<4; i++) {
+ urls.push(this.tile_base.replace('{S}', i));
}
- urls = [
- "//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;
},
CLASS_NAME: "OpenLayers.Layer.BingUK"
});
+
+fixmystreet.layer_options = [
+ { map_type: OpenLayers.Layer.BingUK },
+ { map_type: OpenLayers.Layer.BingAerial }
+];
diff --git a/web/js/map-google.js b/web/js/map-google.js
index fc515b9dd..801fed210 100644
--- a/web/js/map-google.js
+++ b/web/js/map-google.js
@@ -156,7 +156,7 @@ fixmystreet.maps = {};
};
if (!fixmystreet.zoomToBounds) {
map_args.minZoom = 13;
- map_args.maxZoom = 18;
+ map_args.maxZoom = 19;
}
fixmystreet.map = new google.maps.Map(document.getElementById("map"), map_args);
diff --git a/web/js/map-mastermap.js b/web/js/map-mastermap.js
index bb9adf532..663ccbdfb 100644
--- a/web/js/map-mastermap.js
+++ b/web/js/map-mastermap.js
@@ -23,3 +23,8 @@ OpenLayers.Layer.MasterMap = OpenLayers.Class(OpenLayers.Layer.BingUK, {
CLASS_NAME: "OpenLayers.Layer.MasterMap"
});
+
+fixmystreet.layer_options = [
+ { map_type: OpenLayers.Layer.MasterMap },
+ { map_type: OpenLayers.Layer.BingAerial }
+];