Greasy Fork

Greasy Fork is available in English.

Geocaching Map Auto-Refresh

Auto-refreshes the map in search mode. Adds an on/off button for this script. Disables "no geocaches" popup.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Geocaching Map Auto-Refresh
// @namespace    http://greasyfork.icu/users/754130
// @version      1.01
// @description  Auto-refreshes the map in search mode. Adds an on/off button for this script. Disables "no geocaches" popup.
// @author       Bl4ke
// @match        *.geocaching.com/play/map*
// @grant        none
// ==/UserScript==

(function() {
    "use strict";
    // number increases every time the map shows a new area, meaning the map has been dragged or zoomed
    var area_current = 0;
    var observersActive = false;
    var rf_bttn;
    var onOffBttn;
    // variables for measuring time between refreshes
    var startTime_refresh = new Date();
    var endTime_refresh;
    // when mouse down, map is dragged
    var mouseIsDown = false;
    window.addEventListener('mousedown', function() {
        mouseIsDown = true;
    });
    window.addEventListener('mouseup', function() {
        mouseIsDown = false;
    });


    // hide and press refresh button if available
    function handle_refresh_bttn() {
        rf_bttn = document.getElementById("clear-map-control");
        if(rf_bttn != null) {
            rf_bttn.style.zIndex = "-2";
            // for each area the refresh method is called
            refresh(area_current);
        }
    }

    // recursive function; presses refresh_bttn if map hasn't moved for a while and map isn't beeing dragged
    function refresh(area_temporary, startTime_area){
        // at first call set startTime_area
        if(startTime_area == undefined){
            startTime_area = new Date();
        }
        let endTime_refresh = new Date();

        //if map area hasn't moved
        if(area_temporary == area_current) {

            // if map isn't moved for a short time and isn't dragged, else try again later
            if(endTime_refresh - startTime_area > 850 && !mouseIsDown) {

                // if enough time has passed since last refresh, else try again later
                endTime_refresh = new Date();
                let cooldown = 4000;
                if(endTime_refresh - startTime_refresh > cooldown){
                    rf_bttn.click();
                    //console.log("[AR-Debug] Map refreshed!");
                    startTime_refresh = new Date();
                    return;
                }
                //console.log("[AR-Debug] waiting for cooldown");
            }
            window.setTimeout(refresh, 200, area_temporary, startTime_area);
        }
    }

    //closes "no geocaches found" pop-up and restarts obervers
    function close_popup() {
        let close_bttn = document.querySelector("button.modal-close-control");
        if(close_bttn != null){
            close_bttn.click();
            console.log("[AR] Popup closed!");
            stopObservers();

            // wait before restarting observers
            let offTime = 8;
            onOffBttn.disabled = true;
            let timer = setInterval(function(){
                if(offTime <= 0){
                    onOffBttn.innerHTML = "Auto-Refresh";
                    onOffBttn.disabled = false;
                    startObservers();
                    clearInterval(timer);
                }
                else{
                    onOffBttn.innerHTML = offTime;
                    offTime -= 1;
                }
            }, 1000);
        }
    }

    // disables the observers temporarily when settings are opened so that the popup trigger isn't activated
    function settings_popup_exemption() {
        document.querySelector("button[aria-label='Map settings']").addEventListener('click', function(){
            console.log("[AR] Settings opened. Disabling observers temporarily.");
            stopObservers();
            setTimeout(startObservers, 1000);
        });
    }

    // callback function for observer, executed when mutations are observed
    function callback(mutationsList, observer) {
        area_current += 1;
        //console.log("[AR-Debug] Map moved.");
        handle_refresh_bttn();
    }

    // callback function for popup observer, executed when mutations are observed
    function callback_popup(mutationsList, observer_popup) {
        //console.log("[AR-Debug] Observer_popup firing.");
        close_popup();
    }

    // create observer instances linked to their callback functions
    const observer = new MutationObserver(callback);
    const observer_popup = new MutationObserver(callback_popup);

    function startObservers() {
        // selecting the node that will be observed for mutations
        const targetNode = document.querySelector("a.map-cta");
        const targetNode_popup = document.body;

        // options for the observer (which mutations to observe)
        const config = { attributes: true, childList: false, subtree: false };
        const config_popup = {attributes: false, childList: true, subtree: false };

        // start observing the target nodes for configured mutations
        observer.observe(targetNode, config);
        observer_popup.observe(targetNode_popup, config_popup);

		observersActive = true;
        onOffBttn.style.cssText += "background-color: white";
		console.log("[AR] Observers started!");
        // check for refresh possibility on start
        handle_refresh_bttn();
    }

    function stopObservers() {
        observer_popup.disconnect();
        observer.disconnect();
		observersActive = false;
        onOffBttn.style.cssText += "background-color: rgb(228, 228, 228)";
        console.log("[AR] Observers stopped!");
    }

    function insertOnOffBttn() {
        var menuItem = document.createElement("li");
        menuItem.setAttribute("role", "menuitem");
        document.querySelector("button[aria-label='Map settings']").parentElement.parentElement.prepend(menuItem);
        onOffBttn = document.createElement("button");
        onOffBttn.setAttribute("aria-label", "Auto-refresh Switch");
        onOffBttn.setAttribute("class", "map-control");
        onOffBttn.innerHTML = "Auto-Refresh";
        onOffBttn.style.cssText += "background-color: white";
        onOffBttn.style.cssText += "font-size: 60%";
        // on-off function
        onOffBttn.addEventListener('click', function(){
            if(observersActive) {
                stopObservers();
            }
            else {
                startObservers();
            }
        });
        menuItem.append(onOffBttn);
    }

    // wait until map is loaded
    function waitUntilMapAvailable() {
        let mapNode = document.querySelector("div.map-container");
        if(mapNode == null) {
            // the node doesn't exist yet, wait and try again
            window.setTimeout(waitUntilMapAvailable, 300);
            return;
        }
        // setup
        insertOnOffBttn();
        startObservers();
        settings_popup_exemption(); //sets up exemption

    }
    waitUntilMapAvailable();
})();