diff --git a/src/maps/export.js b/src/maps/export.js index 5ac535183..aa7746712 100644 --- a/src/maps/export.js +++ b/src/maps/export.js @@ -3,29 +3,53 @@ import { saveAs } from 'file-saver' export function exportAsGPX (markers, filename) { saveAs(new Blob( - [toXML({ - _name: 'gpx', - _attrs: { - version: '1.1', - 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation': 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd', - }, - _content: markers.map(marker => { - const { lat, lng: lon } = marker.latLng - return { - _name: 'wpt', - _attrs: { - lat, - lon, - }, - _content: marker.gpx, - } - }), - }, { - header: true, - })], + [markersAsGPX(markers)], { type: 'application/gpx+xml', }, ), filename) } + +export function markersAsGPX (markers) { + return toXML({ + _name: 'gpx', + _attrs: { + version: '1.1', + 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation': 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd', + }, + _content: markers.map(marker => { + const { lat, lng: lon } = marker.latLng + return { + _name: 'wpt', + _attrs: { + lat, + lon, + }, + // Remove this handling if https://github.com/davidcalhoun/jstoxml/issues/41 gets fixed! + _content: escapeObject(marker.gpx), + } + }), + }, { + header: true, + }) +} + +// Only escapes top level values and assumes they are strings +function escapeObject (obj) { + const newObj = {} + for (const key of Object.keys(obj)) { + newObj[key] = escapeValue(obj[key]) + } + return newObj +} + +function escapeValue (content) { + return content.replace(/[<>&"']/g, c => ({ + '<': '<', + '>': '>', + '&': '&', + '"': '"', + "'": ''', + }[c])) +} diff --git a/src/maps/export.spec.js b/src/maps/export.spec.js new file mode 100644 index 000000000..419442271 --- /dev/null +++ b/src/maps/export.spec.js @@ -0,0 +1,34 @@ +import { groupMarker } from './components/markers' +import { makeGroup } from '>/enrichedFactories' + +import { markersAsGPX } from './export' + +describe('map export', () => { + it('creates GPX', async () => { + const marker = groupMarker(makeGroup({ name: 'foobar' })) + expect(markersAsGPX([marker])).toBe(` + + + + foobar + groups + + + `.trim().replace(/\s*\n\s*/g, ''), + ) + }) + + it('escapes content correctly', () => { + const marker = groupMarker(makeGroup({ name: 'foo & bar' })) + expect(markersAsGPX([marker])).toBe(` + + + + foo & bar + groups + + + `.trim().replace(/\s*\n\s*/g, ''), + ) + }) +})