Work around iOS 3rd party browser download (#418)

- use FileReader.readAsDataURL (for iOS Chromium)
- add alternative Download from Server for now until proven in Prod and fixed in iOS Firefox (no i18n)
- replace cloud icons as client-side now
This commit is contained in:
Norbert Renner 2022-05-28 14:27:32 +02:00
parent 1d26949770
commit 0fc60c1821
5 changed files with 47 additions and 18 deletions

View file

@ -64,7 +64,7 @@
data-i18n-options='{ "action": "$t(navbar.export-tooltip)", "key": "X" }' data-i18n-options='{ "action": "$t(navbar.export-tooltip)", "key": "X" }'
title="Export route" title="Export route"
> >
<span class="fa fa-lg fa-cloud-download" aria-hidden="true"> </span> <span class="fa fa-lg fa-download" aria-hidden="true"> </span>
<span data-i18n="navbar.export">Export</span> <span data-i18n="navbar.export">Export</span>
</a> </a>
</div> </div>
@ -88,7 +88,7 @@
}' }'
title="Load route" title="Load route"
> >
<span class="fa fa-lg fa-cloud-upload" aria-hidden="true"> </span> <span class="fa fa-lg fa-upload" aria-hidden="true"> </span>
<span data-i18n="navbar.load.title">Load</span> <span data-i18n="navbar.load.title">Load</span>
</a> </a>
<div class="dropdown-menu" aria-labelledby="navbarLoadDropdown"> <div class="dropdown-menu" aria-labelledby="navbarLoadDropdown">
@ -515,14 +515,20 @@
<button type="button" class="btn btn-secondary" data-i18n="modal.close" data-dismiss="modal"> <button type="button" class="btn btn-secondary" data-i18n="modal.close" data-dismiss="modal">
Close Close
</button> </button>
<button <button type="button" class="btn btn-secondary" id="serverExport">
type="submit" <span>
class="btn btn-primary" <i class="fa fa-cloud-download"></i>
data-i18n="export.title" <i
form="exportForm" hidden
id="submitExport" id="export-beeline-warning"
> class="fa fa-exclamation-triangle"
Export route style="font-size: 10px; position: absolute; margin-top: -3px; margin-left: -1px"
></i>
</span>
</button>
<button type="submit" class="btn btn-primary" form="exportForm" id="submitExport">
<span class="fa fa-download"></span>
<span data-i18n="export.title">Export route</span>
</button> </button>
</div> </div>
</div> </div>
@ -919,7 +925,6 @@
</div> </div>
<div id="preview" hidden data-i18n="map.preview">Preview</div> <div id="preview" hidden data-i18n="map.preview">Preview</div>
</div> </div>
<div id="sidebar" class="leaflet-sidebar collapsed"> <div id="sidebar" class="leaflet-sidebar collapsed">
<div class="leaflet-sidebar-content"> <div class="leaflet-sidebar-content">
<div class="leaflet-sidebar-pane" id="tab_layers_control"> <div class="leaflet-sidebar-pane" id="tab_layers_control">

View file

@ -22,6 +22,10 @@
touchScreen: touchScreen, touchScreen: touchScreen,
touchScreenDetectable: touchScreenDetectable, touchScreenDetectable: touchScreenDetectable,
touch: touch, touch: touch,
download: 'Blob' in window && 'createObjectURL' in URL && 'download' in document.createElement('a'), download:
'Blob' in window &&
'FileReader' in window &&
'readAsDataURL' in FileReader.prototype &&
'download' in document.createElement('a'),
}; };
})(); })();

View file

@ -27,9 +27,12 @@ BR.Export = L.Class.extend({
this.exportButton.on('click', L.bind(this._generateTrackname, this)); this.exportButton.on('click', L.bind(this._generateTrackname, this));
L.DomUtil.get('submitExport').onclick = L.bind(this._export, this); L.DomUtil.get('submitExport').onclick = L.bind(this._export, this);
L.DomUtil.get('serverExport').onclick = L.bind(this._exportServer, this);
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this); L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
$('#export').on('show.bs.modal', this._warnStraightLine.bind(this));
this.update([]); this.update([]);
}, },
@ -44,6 +47,16 @@ BR.Export = L.Class.extend({
} }
}, },
_warnStraightLine: function () {
const hasBeeline = BR.Routing.hasBeeline(this.segments);
document.getElementById('export-beeline-warning').hidden = !hasBeeline;
let title = 'Download from server (deprecated)';
if (hasBeeline) {
title = '[Warning: straight lines not supported] ' + title;
}
document.getElementById('serverExport').title = title;
},
_getMimeType: function (format) { _getMimeType: function (format) {
const mimeTypeMap = { const mimeTypeMap = {
gpx: 'application/gpx+xml', gpx: 'application/gpx+xml',
@ -64,7 +77,11 @@ BR.Export = L.Class.extend({
link.click(); link.click();
}, },
_export: function (e) { _exportServer: function (e) {
this._export(e, true);
},
_export: function (e, server = false) {
var exportForm = document.forms['export']; var exportForm = document.forms['export'];
var format = exportForm['format'].value || $('#export-format input:radio:checked').val(); var format = exportForm['format'].value || $('#export-format input:radio:checked').val();
var name = exportForm['trackname'].value; var name = exportForm['trackname'].value;
@ -73,7 +90,7 @@ BR.Export = L.Class.extend({
e.preventDefault(); e.preventDefault();
if (BR.Browser.download) { if (!server && BR.Browser.download) {
const track = this._formatTrack(format, name, includeWaypoints); const track = this._formatTrack(format, name, includeWaypoints);
const fileName = (name || 'brouter') + '.' + format; const fileName = (name || 'brouter') + '.' + format;
@ -81,9 +98,10 @@ BR.Export = L.Class.extend({
const blob = new Blob([track], { const blob = new Blob([track], {
type: mimeType + ';charset=utf-8', type: mimeType + ';charset=utf-8',
}); });
const objectUrl = URL.createObjectURL(blob);
this._triggerDownload(objectUrl, fileName); const reader = new FileReader();
reader.onload = (e) => this._triggerDownload(reader.result, fileName);
reader.readAsDataURL(blob);
} else { } else {
var serverUrl = this.router.getUrl( var serverUrl = this.router.getUrl(
this.latLngs, this.latLngs,

View file

@ -9,8 +9,7 @@ BR.TrackStats = L.Class.extend({
$('#stats-container').show(); $('#stats-container').show();
$('#stats-info').hide(); $('#stats-info').hide();
const hasBeeline = segments.filter((line) => line?._routing?.beeline).length > 0; document.getElementById('beeline-warning').hidden = !BR.Routing.hasBeeline(segments);
document.getElementById('beeline-warning').hidden = !hasBeeline;
var stats = this.calcStats(polyline, segments), var stats = this.calcStats(polyline, segments),
length1 = L.Util.formatNum(stats.trackLength / 1000, 1).toLocaleString(), length1 = L.Util.formatNum(stats.trackLength / 1000, 1).toLocaleString(),

View file

@ -5,6 +5,9 @@ L.Routing.Draw.prototype._hideTrailer = function () {
}; };
BR.Routing = L.Routing.extend({ BR.Routing = L.Routing.extend({
statics: {
hasBeeline: (segments) => segments?.filter((line) => line?._routing?.beeline).length > 0,
},
options: { options: {
position: 'topright', position: 'topright',
icons: { icons: {