NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Geocache Circles
// @namespace inge.org.uk/userscripts
// @description Allows you to display a 0.1 mile radius circle around a cache on the Geocaching.com map page
// @match https://www.geocaching.com/map*
// @author JRI
// @oujs:author JRI
// @license MIT; http://www.opensource.org/licenses/mit-license.php
// @copyright 2016-2017, James Inge (http://geo.inge.org.uk/)
// @version 0.0.4
// @icon https://geo.inge.org.uk/userscripts/circleIcon48.png
// @icon64 https://geo.inge.org.uk/userscripts/circleIcon64.png
// @connect www.geocaching.com
// @updateURL https://geo.inge.org.uk/userscripts/Geocache_Circles.meta.js
// @downloadURL https://openuserjs.org/install/JRI/Geocache_Circles.user.js
// ==/UserScript==
/*jslint browser:true */
/*jshint esversion: 6, undef:true, unused:true */
/*global L, MapSettings, window, console */
(function () {
"use strict";
const version = "Geocache Circles v0.0.4";
const loggedIn = document.getElementById("uxLoginStatus_divSignedIn");
const template = document.getElementById("cacheDetailsTemplate");
const script = document.createElement("script");
const circleIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA6UlEQVQ4ja2TsY3DMAxFiUvvbOTaA0SVRhBEfooyBLjyON7FC3iVNNYVlwB3MQwH5/xW/A/8FEm0I+99E4K0IUjrvW/26jaKETeILZC0KqwqrELSCrElRtx2jaWUq0iaFFaBPKvawMwdM3eqNgB5VlgVSVMp5boBPMx3ibkfx/Hr9d05d5GYe4XdRdK0aVthVWLujyI+IPVPHIgtQJ6dc5cjgHPuAuQZYgsR/UwbklZVG47MT6naAEmr976hEKRVWGXm7l0AM3cKqyFIex5wOgLRySESfeAbiU4uEtEHVvl3nH8d06vePedvYUbM9ZMTrS4AAAAASUVORK5CYII=";
function handleCircleRequest(e) {
/* Fetch coordinates from cache page */
const req = new XMLHttpRequest();
const gc = e.detail;
req.addEventListener("load", function (ignore) {
const r = req.responseText;
const k = r.indexOf("mapLatLng = {");
if (req.status < 400) {
try {
const {lat, lng, name} = JSON.parse(r.substring(k + 12, r.indexOf("}", k) + 1));
if (typeof lat !== "number" || typeof lng !== "number") {
// Missing data in JSON string
console.error("Geocache Circles: no cache coordinates retrieved.");
return;
}
if (window.MapSettings && MapSettings.Map && window.L && window.L.Circle) {
const ll = new L.LatLng(lat, lng);
new L.Circle(ll, 161, {weight: 2})
.addTo(MapSettings.Map)
.bindPopup(`<p><strong>${name}</strong><br/>${ll.toUrl()}`);
} else {
console.error("Geocache Circles: couldn't find map interface.");
}
} catch (err) {
if (err instanceof SyntaxError) {
console.warn(`Geocache Circles: Received ${r.length} bytes, coords at ${k} but couldn't extract cache coordinates from data (are you still logged in?):
${err}`);
} else {
console.error(`Geocache Circles: couldn't add circle to ssmap: ${err}`);
}
}
} else {
console.warn(`Geocache Circles: error retrieving cache page to find coords for ${gc}: ${req.statusText}`);
}
});
req.open("GET", `https://www.geocaching.com/geocache/${gc}`);
req.send();
}
// Don't run on frames or iframes
if (window.top !== window.self) {
return false;
}
// Check feature support
if (!window.JSON || !window.XMLHttpRequest) {
console.warn(`${version} requires a browser with support for JSON and XMLHttpRequest`);
return false;
}
if (loggedIn === null) {
// Warn if not logged in, as coords unavailable. Don't quit, as user might log in later in a different window, or login detection might have failed.
console.warn("Geocache Circles may not be able to locate caches as you don't seem to be logged in.");
}
if (template) {
console.info(version);
// Attach to cache info popup template
template.textContent = template.textContent.replace(/<div\sclass="links\sClear">/, `<div class="links Clear"> <a class="jri-circle-link" style="cursor: pointer; text-decoration: underline;" onclick="document.dispatchEvent(new CustomEvent('gme_circle_request', {'detail':'{{=gc}}'}));"><img src="${circleIcon}" alt="O" style="vertical-align:middle; margin-right: 0.25em;" width="16" height="16" />Circle</a> `);
// Add event listener to content script context
script.type = "text/javascript";
script.text = `"use strict";
${handleCircleRequest.toString()}
document.addEventListener("gme_circle_request", handleCircleRequest, false)`;
document.documentElement.firstChild.appendChild(script);
document.documentElement.firstChild.removeChild(script);
} else {
// Couldn't find popup template
console.error(`${version} didn't understand page structure.`);
}
}());