diff --git a/.gitignore b/.gitignore
index af0faab..208f440 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
*~
.DS_Store
*.swp
+web-ext-artifacts
diff --git a/README.md b/README.md
index 8659703..5e58206 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
# SAC Route Portal GPX Downloader
-
The [Swiss Alpine Club](https://www.sac-cas.ch/en/) has a great
[route portal](https://www.sac-cas.ch/en/huts-and-tours/sac-route-portal/)
for finding interesting hiking routes.
@@ -19,3 +18,6 @@ Heed their warning and do not blindly follow the gps track! Use your brain and
plan your route beforehand to be aware of dangerous parts and alternatives.
Take a look at their [safety instructions](https://www.sac-cas.ch/en/training-and-safety/safety/).
+
+## Contributors
+- wizche
diff --git a/background.js b/background.js
index 75da0bd..e03772c 100644
--- a/background.js
+++ b/background.js
@@ -1,196 +1,255 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
+
let gpxTrack = null;
/**
* Convert the Swiss projection coordinates to WGS84 (lat/lon).
- *
- * Calculations from "Approximate formulas for the transformation between Swiss
- * projection coordinates and WGS84" by the Swiss Federal Office of Topography,
- * swisstopo
+ *
+ * Calculations from "Approximate formulas for the transformation between Swiss
+ * projection coordinates and WGS84" by the Swiss Federal Office of Topography,
+ * swisstopo
* (https://www.swisstopo.admin.ch/en/knowledge-facts/surveying-geodesy/reference-systems/map-projections.html).
- *
+ *
+ * @param {*} point Array of Swiss projection coordinates, position 0 is E and 1 is N.
+ * @returns Calculated lat and lon.
+ */
+function toWGS84(point) {
+ // convert LV95 into the civilian system
+ const y_aux = (point[0] - 2600000) / 1000000;
+ const x_aux = (point[1] - 1200000) / 1000000;
+
+ // calculate longitude and latitude in the unit 10000"
+ let lat = 16.9023892 +
+ 3.238272 * x_aux -
+ 0.270978 * Math.pow(y_aux, 2) -
+ 0.002528 * Math.pow(x_aux, 2) -
+ 0.0447 * Math.pow(y_aux, 2) * x_aux -
+ 0.014 * Math.pow(x_aux, 3);
+
+ let lon = 2.6779094 +
+ 4.728982 * y_aux +
+ 0.791484 * y_aux * x_aux +
+ 0.1306 * y_aux * Math.pow(x_aux, 2) -
+ 0.0436 * Math.pow(y_aux, 3);
+
+ // unit 10000" to 1" and seconds to degrees (dec)
+ lat = (lat * 100) / 36;
+ lon = (lon * 100) / 36;
+
+ return { lat: lat, lon: lon };
+}
+
+/**
+ * Get the gpx trackpoint representation of a Swiss projection coordinate point.
+ *
* @param {*} point Array of Swiss projection coordinates, position 0 is E and 1 is N.
* @returns Track point xml node for gpx.
*/
function toTrackPoint(point) {
- // convert LV95 into the civilian system
- let y_aux = (point[0] - 2600000)/1000000;
- let x_aux = (point[1] - 1200000)/1000000;
+ const wgs84Point = toWGS84(point);
+ return ``;
+}
- // calculate longitude and latitude in the unit 10000"
- let lat = 16.9023892 +
- 3.238272 * x_aux -
- 0.270978 * Math.pow(y_aux, 2) -
- 0.002528 * Math.pow(x_aux, 2) -
- 0.0447 * Math.pow(y_aux, 2) * x_aux -
- 0.0140 * Math.pow(x_aux, 3);
-
- let lng = 2.6779094 +
- 4.728982 * y_aux +
- 0.791484 * y_aux * x_aux +
- 0.1306 * y_aux * Math.pow(x_aux, 2) -
- 0.0436 * Math.pow(y_aux, 3);
-
- // unit 10000" to 1" and seconds to degrees (dec)
- lat = lat * 100 / 36;
- lng = lng * 100 / 36;
-
- return ``;
+/**
+ * Get the gpx waypoint representation of a route portal point.
+ *
+ * @returns Way point xml node for gpx.
+ */
+function toWayPoint(point) {
+ const wgs84Point = toWGS84(point.geom.coordinates);
+ return `
+
+ ${point.altitude}
+ ${point.display_name}
+ `;
}
/**
* Create track title.
- *
- * @param {*} geoJson
+ *
+ * @param {*} geoJson
* @returns Combined route number, id and route title.
*/
function trackTitle(geoJson) {
- const route = geoJson.segments[0];
- return `${geoJson.book_route_number}-${route.route_id} ${route.title}`;
+ const book = geoJson.book_route_number
+ ? `${geoJson.book_route_number} - `
+ : "";
+
+ return `${book}${geoJson.title}`;
}
/**
* Create a gpx representation from the sac GeoJSON data.
- *
- * @param {*} geoJson
+ *
+ * @param {*} geoJson
* @returns Simple gpx string.
*/
function toGpx(geoJson) {
- const route = geoJson.segments[0].geom;
- const routeTitle = trackTitle(geoJson);
+ const trackSegments = geoJson.segments
+ .map((segment) => {
+ if (segment.geom == null) return "";
+ return `
+ ${segment.geom.coordinates.map(toTrackPoint).join("")}
+ `;
+ })
+ .join("");
- const xmlString = `
+ const departurePoint = geoJson.departure_point
+ ? toWayPoint(geoJson.departure_point)
+ : "";
+ const endPoint = geoJson.end_point ? toWayPoint(geoJson.end_point) : "";
+ const waypoints = geoJson.waypoints
+ ? geoJson.waypoints
+ .map((wp) => {
+ return toWayPoint(wp.reference_poi);
+ })
+ .join("")
+ : "";
+
+ const routeTitle = trackTitle(geoJson);
+
+ const xmlString = `
+ ${departurePoint}
+ ${toWayPoint(geoJson.destination_poi)}
+ ${waypoints}
+ ${endPoint}
Track ${routeTitle}
-
- ${route.coordinates.map(toTrackPoint).join("")}
-
+ ${trackSegments}
`;
- const parser = new DOMParser();
- let xmlDoc = parser.parseFromString(xmlString, "text/xml");
+ const parser = new DOMParser();
+ const xmlDoc = parser.parseFromString(xmlString, "text/xml");
- return new XMLSerializer().serializeToString(xmlDoc.documentElement);
+ return new XMLSerializer().serializeToString(xmlDoc.documentElement);
}
/**
* Intercept the download of GeoJSON data and save it for the background script.
*/
function listener(details) {
- let filter = browser.webRequest.filterResponseData(details.requestId);
- let decoder = new TextDecoder("utf-8");
- let encoder = new TextEncoder();
+ const filter = browser.webRequest.filterResponseData(details.requestId);
+ const decoder = new TextDecoder("utf-8");
+ const encoder = new TextEncoder();
- let data = [];
- filter.ondata = event => {
- data.push(event.data);
- };
+ const data = [];
+ filter.ondata = (event) => {
+ data.push(event.data);
+ };
- filter.onstop = async event => {
- let blob = new Blob(data, {type: 'text/html'});
- let buffer = await blob.arrayBuffer();
- let str = decoder.decode(buffer);
+ filter.onstop = async (_event) => {
+ const blob = new Blob(data, { type: "text/html" });
+ const buffer = await blob.arrayBuffer();
+ const str = decoder.decode(buffer);
- gpxTrack = JSON.parse(str);
- updateActiveTab(browser.tabs);
+ updateActiveTab(browser.tabs);
- filter.write(encoder.encode(str));
- filter.close();
- };
+ filter.write(encoder.encode(str));
+ filter.close();
- return {};
+ const geoJson = JSON.parse(str);
+ const routeTitle = trackTitle(geoJson);
+ gpxTrack = { title: routeTitle, data: toGpx(geoJson) };
+ };
+
+ return {};
}
/**
* Check if a url should be intercepted.
- *
- * @param {*} tab
+ *
+ * @param {*} tab
* @returns True if the active tab is an sac website, false otherwise.
*/
function checkTrack(tab) {
- if (!tab.url) {
- return false;
- }
+ if (!tab.url) {
+ return false;
+ }
- return tab.url.match("https://www.sac-cas.ch/.*") && gpxTrack;
+ return tab.url.match("https://www.sac-cas.ch/.*") && gpxTrack;
}
/**
* If a valid tack was selected, download it as a gpx file.
*/
function handleClick(tab) {
- const hasTrack = checkTrack(tab);
- if (!hasTrack) {
- return;
- }
+ const hasTrack = checkTrack(tab);
+ if (!hasTrack) {
+ return;
+ }
- let blob = new Blob([toGpx(gpxTrack)], {type: "application/gpx+xml"});
- let objectURL = URL.createObjectURL(blob);
+ const blob = new Blob([gpxTrack.data], { type: "application/gpx+xml" });
+ const objectURL = URL.createObjectURL(blob);
- const routeTitle = trackTitle(gpxTrack);
+ const downloading = browser.downloads.download({
+ url: objectURL,
+ filename: `${gpxTrack.title}.gpx`,
+ saveAs: true,
+ conflictAction: "uniquify",
+ });
- let downloading = browser.downloads.download({
- url : objectURL,
- filename : `track-${routeTitle}.gpx`,
- saveAs: true,
- conflictAction : 'uniquify'
- });
-
- downloading.then(
- (id) => console.log(`Started downloading: ${id}`),
- (error) => console.log(`Download failed: ${error}`));
- gpxTrack = null;
+ downloading.then(
+ (id) => console.log(`Started downloading: ${id}`),
+ (error) => console.log(`Download failed: ${error}`),
+ );
+ gpxTrack = null;
}
/**
* Update the download icon and text.
*/
-function updateActiveTab(tabs) {
- function updateTab(tabs) {
- if (tabs[0]) {
- updateIcon(tabs[0]);
- }
+function updateActiveTab(_tabs) {
+ function updateTab(tabs) {
+ if (tabs[0]) {
+ updateIcon(tabs[0]);
}
-
- let gettingActiveTab = browser.tabs.query({active: true, currentWindow: true});
- gettingActiveTab.then(updateTab);
+ }
+
+ const gettingActiveTab = browser.tabs.query({
+ active: true,
+ currentWindow: true,
+ });
+ gettingActiveTab.then(updateTab);
}
/**
* Update the download icon.
*/
function updateIcon(tab) {
- const hasTrack = checkTrack(tab);
+ const hasTrack = checkTrack(tab);
- browser.browserAction.setIcon({
- path: hasTrack ? {
+ browser.browserAction.setIcon({
+ path: hasTrack
+ ? {
48: "icons/map.png",
- } : {
+ }
+ : {
48: "icons/map-disabled.png",
},
- tabId: tab.id
- });
- browser.browserAction.setTitle({
- title: hasTrack ? `Download track ${trackTitle(gpxTrack)}` : 'No track selected',
- tabId: tab.id
- });
+ tabId: tab.id,
+ });
+ browser.browserAction.setTitle({
+ title: hasTrack
+ ? `Download track "${gpxTrack.title}"`
+ : "No track selected",
+ tabId: tab.id,
+ });
}
browser.webRequest.onBeforeRequest.addListener(
- listener,
- {urls: ["https://www.sac-cas.ch/*[routeId]*"]},
- ["blocking"]
+ listener,
+ { urls: ["https://www.sac-cas.ch/*[routeId]*"] },
+ ["blocking"],
);
browser.browserAction.onClicked.addListener(handleClick);
@@ -198,5 +257,5 @@ browser.browserAction.onClicked.addListener(handleClick);
browser.tabs.onUpdated.addListener(updateActiveTab);
browser.tabs.onActivated.addListener(updateActiveTab);
browser.windows.onFocusChanged.addListener(updateActiveTab);
-
+
updateActiveTab();
diff --git a/manifest.json b/manifest.json
index 7448734..8c464a2 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,19 +1,15 @@
{
-
"manifest_version": 2,
- "name": "SAC Route Portal GPX",
- "version": "0.1",
+ "name": "SAC Route Portal GPX Downloader",
+ "version": "0.8",
"developer": {
"name": "Sebastian Hugentobler",
"url": "https://code.vanwa.ch/sebastian/sac-route-portal-gpx-fx"
},
-
"description": "Download gpx tracks from the sac route portal.",
-
"icons": {
"48": "icons/map.png"
},
-
"permissions": [
"activeTab",
"downloads",
@@ -21,13 +17,13 @@
"webRequestBlocking",
"https://www.sac-cas.ch/*"
],
-
"background": {
- "scripts": ["background.js"]
+ "scripts": [
+ "background.js"
+ ]
},
-
"browser_action": {
"default_icon": "icons/map.png",
"default_title": "To GPX"
- }
+ }
}