diff --git a/js/Browser.js b/js/Browser.js
index 646cc48..f70a5de 100644
--- a/js/Browser.js
+++ b/js/Browser.js
@@ -22,5 +22,6 @@
touchScreen: touchScreen,
touchScreenDetectable: touchScreenDetectable,
touch: touch,
+ download: 'Blob' in window && 'createObjectURL' in URL && 'download' in document.createElement('a'),
};
})();
diff --git a/js/control/Export.js b/js/control/Export.js
index b19dd4c..8f94f10 100644
--- a/js/control/Export.js
+++ b/js/control/Export.js
@@ -15,7 +15,8 @@ BR.Export = L.Class.extend({
var trackname = (this.trackname = document.getElementById('trackname'));
this.tracknameAllowedChars = BR.conf.tracknameAllowedChars;
- if (this.tracknameAllowedChars) {
+ // a.download attribute automatically replaces invalid characters
+ if (!BR.Browser.download && this.tracknameAllowedChars) {
this.tracknameMessage = document.getElementById('trackname-message');
var patternRegex = new RegExp('[' + this.tracknameAllowedChars + ']+');
@@ -52,19 +53,33 @@ BR.Export = L.Class.extend({
e.preventDefault();
- if (true) {
- var uri = this.router.getUrl(this.latLngs, this.pois.getMarkers(), null, format, nameUri, includeWaypoints);
-
- // var evt = document.createEvent('MouseEvents');
- // evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
- // var link = document.createElement('a');
- // link.href = uri;
- // link.dispatchEvent(evt);
- //} else {
-
+ if (BR.Browser.download) {
const track = this._formatTrack(format, name, includeWaypoints);
- console.log('track: ', track);
- BR.Diff.diff(uri, track, format);
+
+ const mimeTypeMap = {
+ gpx: 'application/gpx+xml',
+ kml: 'application/vnd.google-earth.kml+xml',
+ geojson: 'application/vnd.geo+json',
+ csv: 'text/tab-separated-values',
+ };
+
+ const mimeType = mimeTypeMap[format];
+
+ const blob = new Blob([track], {
+ type: mimeType + ';charset=utf-8',
+ });
+ const objectUrl = URL.createObjectURL(blob);
+ const link = document.createElement('a');
+ link.href = objectUrl;
+ link.download = (name || 'brouter') + '.' + format;
+ link.click();
+ } else {
+ var uri = this.router.getUrl(this.latLngs, this.pois.getMarkers(), null, format, nameUri, includeWaypoints);
+ var evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ var link = document.createElement('a');
+ link.href = uri;
+ link.dispatchEvent(evt);
}
},
@@ -134,7 +149,6 @@ BR.Export = L.Class.extend({
},
_generateTrackname: function () {
- return; // TODO remove
var trackname = this.trackname;
this._getCityAtPosition(
this.latLngs[0],
@@ -143,7 +157,7 @@ BR.Export = L.Class.extend({
this.latLngs[this.latLngs.length - 1],
L.bind(function (to) {
var distance = document.getElementById('distance').innerHTML;
- if (this.tracknameAllowedChars) {
+ if (!BR.Browser.download && this.tracknameAllowedChars) {
distance = distance.replace(',', '.'); // temp. fix (#202)
}
if (!from || !to) {
@@ -161,7 +175,7 @@ BR.Export = L.Class.extend({
});
}
- if (this.tracknameAllowedChars) {
+ if (!BR.Browser.download && this.tracknameAllowedChars) {
// temp. fix: replace and remove characters that will get removed by server quick fix (#194)
trackname.value = trackname.value.replace(/[>)]/g, '').replace(/ \(/g, ' - ');
this._validationMessage();
diff --git a/js/util/Diff.js b/js/util/Diff.js
deleted file mode 100644
index 5cf16b6..0000000
--- a/js/util/Diff.js
+++ /dev/null
@@ -1,124 +0,0 @@
-BR.Diff = {};
-
-//
-BR.Diff.diff = function (uri, track, format) {
- BR.Util.get(
- uri,
- ((err, text) => {
- if (err) {
- console.error('Error exporting "' + profileUrl + '": ' + err);
- return;
- }
-
- if (format === 'gpx') {
- text = BR.Gpx.pretty(BR.Diff.adoptGpx(text));
- } else if (format === 'geojson') {
- text = JSON.stringify(JSON.parse(text), null, 2);
- }
- var dmp = new diff_match_patch();
- var diff = dmp.diff_main(text, track);
- dmp.diff_cleanupSemantic(diff);
-
- if (dmp.diff_levenshtein(diff) > 0) {
- let i = 0;
- while (i < diff.length - 2) {
- if (
- diff[i][0] === 0 &&
- diff[i + 1][0] === -1 &&
- diff[i + 2][0] === 1 &&
- (/(rteTime|rteSpeed)>\d+\.\d{0,2}$/.test(diff[i][1]) || /time=[0-9h ]*m \d$/.test(diff[i][1]))
- ) {
- const del = +diff[i + 1][1];
- const ins = +diff[i + 2][1];
- if (Number.isInteger(del) && Number.isInteger(ins) && Math.abs(del - ins) <= 1) {
- diff.splice(i + 1, 2);
- if (i + 1 < diff.length && diff[i + 1][0] === 0) {
- diff[i + 1][1] = diff[i][1] + diff[i + 1][1];
- diff.splice(i, 1);
- continue;
- }
- }
- }
- i++;
- }
- }
-
- if (dmp.diff_levenshtein(diff) > 0) {
- //console.log('server: ', text);
- //console.log('client: ', track);
- console.log(diff);
- bootbox.alert(BR.Diff.diffPrettyHtml(diff));
- } else {
- console.log('diff equal');
- }
- }).bind(this)
- );
-};
-
-// diff_match_patch.prototype.diff_prettyHtml modified to only show specified number of context lines
-BR.Diff.diffPrettyHtml = function (diffs, contextLen = 2) {
- var html = [];
- var pattern_amp = /&/g;
- var pattern_lt = //g;
- var pattern_para = /\n/g;
- for (var x = 0; x < diffs.length; x++) {
- var op = diffs[x][0]; // Operation (insert, delete, equal)
- var data = diffs[x][1]; // Text of change.
- var text = data
- .replace(pattern_amp, '&')
- .replace(pattern_lt, '<')
- .replace(pattern_gt, '>')
- //.replace(pattern_para, '¶
');
- .replace(pattern_para, '
');
- switch (op) {
- case DIFF_INSERT:
- html[x] = '' + text + '';
- break;
- case DIFF_DELETE:
- html[x] = '' + text + '';
- break;
- case DIFF_EQUAL:
- const lines = text.split('
');
- const len = lines.length;
- if (len > contextLen * 2) {
- text = [...lines.slice(0, contextLen), '...', ...lines.slice(-contextLen)].join('
');
- }
-
- html[x] = '' + text + '';
- break;
- }
- }
- return html.join('');
-};
-
-// TODO remove
-// copied from Gpx.test.js
-BR.Diff.adoptGpx = function (gpx, replaceCreator = true) {
- const creator = 'BRouter-Web 0.15.1';
- const name = 'Track';
- const newline = '\n';
-
- gpx = gpx.replace(/=\.(?=\d)/, '=0.');
- if (replaceCreator) {
- gpx = gpx.replace(/creator="(?!OsmAndRouter)[^"]*"/, `creator="${creator}"`);
- }
- gpx = gpx.replace(/creator="([^"]*)" version="1.1"/, 'version="1.1" \n creator="$1"');
- //gpx = gpx.replace(/\n [^<]*<\/name>/, `\n ${name}`);
- gpx = gpx
- .split(newline)
- .map((line) => line.replace(/lon="([^"]*)" lat="([^"]*)"/, 'lat="$2" lon="$1"'))
- .join(newline);
- gpx = gpx.replace(/(lon|lat)="([-0-9]+.[0-9]+?)0+"/g, '$1="$2"'); // remove trailing zeros
- // remove trailing zeros comment-style voicehints
- gpx = gpx.replace(/;\s*([-0-9]+.[0-9]+?)0+;/g, (match, p1) => `;${p1.padStart(10)};`);
- gpx = gpx.replace(/>([-0-9]+?\.\d*0+)<\//g, (match, p1) => `>${+p1}`); // remove trailing zeros
- gpx = gpx.replace('\n', '');
-
- // added
- // trunc bc. float precision diffs
- gpx = gpx.replace(/(rteTime|rteSpeed)>([^<]*)<\//g, (match, p1, p2) => `${p1}>${(+p2).toFixed(3)}`);
- gpx = gpx.replace(/\n?\s*<\/extensions>\n?\s*/, ''); // ignore (invalid) double tag
-
- return gpx;
-};
diff --git a/tests/control/Export.test.js b/tests/control/Export.test.js
index 72b003d..76bfd67 100644
--- a/tests/control/Export.test.js
+++ b/tests/control/Export.test.js
@@ -3,6 +3,7 @@ BR.conf = {};
$ = require('jquery');
require('leaflet');
turf = require('@turf/turf');
+require('../../js/Browser.js');
require('../../js/control/Export.js');
const fs = require('fs');
diff --git a/tests/format/Gpx.test.js b/tests/format/Gpx.test.js
index 2f73b3a..df9d972 100644
--- a/tests/format/Gpx.test.js
+++ b/tests/format/Gpx.test.js
@@ -3,6 +3,7 @@ BR.version = '1.5.1';
turf = require('@turf/turf');
togpx = require('togpx');
require('leaflet');
+require('../../js/Browser.js');
require('../../js/format/VoiceHints.js');
require('../../js/format/Xml.js');
require('../../js/format/Gpx.js');