WME Quick HN (DaveAcincy fork)

Quick House Numbers

当前为 2024-02-28 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         WME Quick HN (DaveAcincy fork)
// @description  Quick House Numbers
// @version      2024.02.28.01
// @author       Vinkoy (forked by DaveAcincy)
// @match        https://beta.waze.com/*editor*
// @match        https://www.waze.com/*editor*
// @exclude      https://www.waze.com/*user/*editor/*
// @namespace    https://greasyfork.org/users/166713
// @homepage     https://www.waze.com/forum/viewtopic.php?t=371460
// @require      https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @grant        none
// ==/UserScript==

/* global W */
/* global I18n */
/* global $ */
/* global WazeWrap */

(function() {
    var counter = 0;
    var interval = 1;
    var policySafeHTML = null;
    var hnlayerobserver = null;
    var hnWatch = null;
    var autoSetHN = false;
    var zoomKeys = false;
    var debug = false;
    var fillnext = false;
    var initCount = 0;

function setupPolicy() {
    if (typeof trustedTypes !== "undefined") {
        policySafeHTML = trustedTypes.createPolicy("policySafeHTML", {createHTML:innerText => innerText});
    }
}
function createSafeHtml(text) {
    if (policySafeHTML !== null) {
        return policySafeHTML.createHTML(text);
    } else {
        return text;
    }
}

function quickHN_bootstrap()
{
    if (typeof W === 'object' && W.userscripts?.state.isReady) {
        onWmeReady();
    } else {
        document.addEventListener("wme-ready", onWmeReady, {
            once: true,
        });
    }
}

function onWmeReady()
{
    initCount++;
    if (WazeWrap && WazeWrap.Ready)
        initialiseQuickHN();
    else {
        if (initCount == 1) {
            log('Waiting for WazeWrap...');
        } else if (initCount == 100) {
            console.error('WME Quick HN:', 'WazeWrap loading failed. Giving up.');
            return;
        }
        setTimeout(onWmeReady, 300);
    }
}

function createShortcut(id, desc, func, kcode)
{
    I18n.translations[I18n.locale].keyboard_shortcuts.groups.wmeqhn.members[id] = desc;
    var short = {};
    short[kcode] = id;
    W.accelerators.addAction(id, {group: 'wmeqhn'});
    W.accelerators.events.register(id, null, func);
    W.accelerators._registerShortcuts(short);
}

function log(message) {
    console.log('QuickHN: ' + message);
}

function dlog(message, data = '') {
    if (debug) { console.log('QuickHN# ' + message, data); }
}
function tlog(message, data = '') {
    const t = new Date;
    const h = t.getHours();
    const m = t.getMinutes();
    const s = t.getSeconds();
    const hms = h + ":" + m + ":" + s;
    const ms = ('00' + t.getMilliseconds()).slice(-3);
    if (debug) { console.log('QHN:' + hms +'.'+ ms + ': ' + message, data); }
}

function initialiseQuickHN()
{
    var ep = document.getElementById('edit-panel');
    if (!ep) {
        setTimeout(initialiseQuickHN, 200);
        return;
    }

    setupPolicy();
    W.editingMediator.on({ 'change:editingHouseNumbers': onChangeHNMode });

    hnlayerobserver = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            // Mutation is a NodeList and doesn't support forEach like an array
            for (var i = 0; i < mutation.addedNodes.length; i++) {
                var addedNode = mutation.addedNodes[i];

                // Only fire up if it's a node
                if (addedNode.nodeType === Node.ELEMENT_NODE && addedNode.classList.contains('is-active')) {
                    var x = addedNode.querySelector('input');
                    if (x !== undefined) {
                        x.onfocus = function() { sethn(); };
                    }
                }
            }

        });
    });

    let group = "wmeqhn";
    W.accelerators.Groups[group] = [];
    W.accelerators.Groups[group].members = [];
    I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[group] = [];
    I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[group].description = "Quick HN";
    I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[group].members = [];

    createShortcut("WME_QHN_newHN01", "New HN (+1)", addHN1t, "t");
    createShortcut("WME_QHN_newHN02", "New HN (+2)", addHN2r, "r");
    createShortcut("WME_QHN_newHNcust", "New HN (+CUSTOM_VALUE)", addHNcustom, "e");
    createShortcut("WME_QHN_newHN1", "New HN (+1)", addHN1, "1");
    createShortcut("WME_QHN_newHN2", "New HN (+2)", addHN2, "2");
    createShortcut("WME_QHN_newHN3", "New HN (+3)", addHN3, "3");
    createShortcut("WME_QHN_newHN4", "New HN (+4)", addHN4, "4");
    createShortcut("WME_QHN_newHN5", "New HN (+5)", addHN5, "5");
    createShortcut("WME_QHN_newHN6", "New HN (+6)", addHN6, "6");
    createShortcut("WME_QHN_newHN7", "New HN (+7)", addHN7, "7");
    createShortcut("WME_QHN_newHN8", "New HN (+8)", addHN8, "8");
    createShortcut("WME_QHN_newHN9", "New HN (+9)", addHN9, "9");
    createShortcut("WME_QHN_newHN10","New HN (+10)", addHN10, "0");
    localDataManager();
    log("initialize complete");
}

function wme_saveQuickHNOptions()
{
    if (localStorage)
    {
        var options = [];
        // preserve previous options which may get lost after logout
        if (localStorage.WMEquickHN)
            options = JSON.parse(localStorage.WMEquickHN);

        options[1] = document.getElementById('_custominterval').value;
        options[2] = autoSetHN;
        options[3] = zoomKeys;

        localStorage.WMEquickHN = JSON.stringify(options);
    }
}

function localDataManager()
{
    // restore saved settings
    var cust = 4;
    if (localStorage.WMEquickHN) {
        var options = JSON.parse(localStorage.WMEquickHN);
        if (options[1] !== undefined)
            cust = options[1];
        if (options[2] !== undefined)
            autoSetHN = options[2];
        if (options[3] !== undefined)
            zoomKeys = options[3];
    }
    const cele = document.getElementById('_custominterval');
    if (cele) {
        cele.value = cust;
        cele.onchange = wme_saveQuickHNOptions;
    }

    $('#quickHNAutoSetHNCheckBox').prop('checked', autoSetHN);
    $('#quickHNzoomKeysCheckBox').prop('checked', zoomKeys);
    window.addEventListener("beforeunload", wme_saveQuickHNOptions, false);
}

async function onChangeHNMode()
{
    tlog('onChangeHNMode: ' + W.editingMediator.attributes.editingHouseNumbers);
    var $x = $('.sidebar-layout > .overlay');
    if (!W.editingMediator.attributes.editingHouseNumbers) {
        if ($x.length > 0) {
            tlog('unhide overlay');
            $x.show();
        }
        if(document.getElementById("WME-Quick-HN")) {
            hnlayerobserver.disconnect();
            $('#WME-Quick-HN').remove();
            $('.wmequickhn-tab').remove();
            await new Promise(r => setTimeout(r,100));
            activateEditTab(0);
            WazeWrap.Events.unregister("afteraction",null, hnActionCheck);
        }
    }
    if(!document.getElementById("WME-Quick-HN") && W.editingMediator.attributes.editingHouseNumbers)
    {
        await new Promise(r => setTimeout(r,20));
        var userTabs = document.getElementById('edit-panel');
        if (!(userTabs && getElementsByClassName('nav-tabs', userTabs)))
            return;

        var navTabs = document.getElementById('edit-panel').getElementsByTagName('wz-tabs')[0];
        if (!navTabs) {
            setTimeout(onChangeHNMode, 200);
            return;
        }

        if ($x.length > 0) {
            tlog('hide overlay');
            $x.hide();
        }

        var btnSection = document.createElement('div');
        btnSection.id = 'WME-Quick-HN';
        if (typeof navTabs !== "undefined")
        {
            var tabContent = getElementsByClassName('segment-edit-section', userTabs)[0];

            if (typeof tabContent !== "undefined")
            {
                var quickTab = document.createElement('wz-tab');
                quickTab.className = 'wmequickhn-tab';
                quickTab.label = 'Quick HN';
                navTabs.appendChild(quickTab);

                btnSection.innerHTML = createSafeHtml('<div>'+
                    '<b>Quick House Numbers</b> v' + GM_info.script.version +
                    '</br>' +
                    '<div title="House number"><b>House number </b><input type="number" id="_housenumber" style="width: 60px;"/></div>' +
                    '<div><input type="checkbox" name="quickHNAutoSetHNCheckBox" title="When enabled, Auto set next HN updates the next HN field based on the last HN created or moved" id="quickHNAutoSetHNCheckBox"><label for="quickHNAutoSetHNCheckBox">Auto set next HN on typed/moved HN</label></div>' +
                    '<div><input type="checkbox" name="quickHNzoomKeysCheckBox" title="1-9 => Z11-19; 0 => Z20" id="quickHNzoomKeysCheckBox"><label for="quickHNzoomKeysCheckBox">Zoom Keys when not in HN mode</label></div>' +
                    '<div>Press <b>T</b> to add <u>HN +1</u> <i>(1,2,3...)</i></div>' +
                    '<div>Press <b>R</b> to add <u>HN +2</u> <i>(1,3,5... or 2,4,6...)</i></div>' +
                    '<div>Press <b>E</b> to add <u>HN +</u><input type="number" id="_custominterval" style="width: 42px;margin-left: 6px;height: 22px;"></div>' +
                    '<div>Press <b>1 - 9</b> to add <u>HN +x</u></div>' +
                    '<div>Press <b>0</b> to add <u>HN +10</u></div>');

                btnSection.className = "quickhn";
                quickTab.appendChild(btnSection);
                quickTab.setAttribute("is-active","false");
                localDataManager();

                $('#quickHNAutoSetHNCheckBox').change(function onAutosetCheckChanged() {
                    autoSetHN = this.checked;
                    if (autoSetHN)
                        WazeWrap.Events.register("afteraction",null, hnActionCheck);
                    else
                        WazeWrap.Events.unregister("afteraction",null, hnActionCheck);
                    wme_saveQuickHNOptions();
                });

                $('#quickHNzoomKeysCheckBox').change(function onZoomKeysCheckChanged() {
                    zoomKeys = this.checked;
                    wme_saveQuickHNOptions();
                });

                var tabChange = new MutationObserver(function(mutations) {
                    mutations.forEach(function(mutation) {
                        if (mutation.type === "attributes" && mutation.attributeName == "is-active") {
                            if (mutation.target.isActive) {
                                var tabs = document.getElementById('edit-panel').getElementsByTagName('wz-tabs')[0].getElementsByTagName('wz-tab');
                                for (var i=0; i < tabs.length; i++) {
                                    if (tabs[i] != quickTab) {
                                        tabs[i].setAttribute("is-active","false");
                                    }
                                }
                                mutation.target.style.display="block";
                            }
                            else {
                                mutation.target.style.display="none";
                            }
                        }
                    });
                });
                tabChange.observe(quickTab, { attributes: true });

                await new Promise(r => setTimeout(r,50));
                activateEditTab(-1);
            }
            else
            {
                btnSection.id='';
            }
        }
        else
        {
            btnSection.id='';
        }

        var hnlayer = getElementsByClassName("house-numbers-layer");
        hnlayerobserver.observe(hnlayer[0], { childList: true });

        var hn = document.getElementById('_housenumber');
        if (hn) {
            document.getElementById('_housenumber').value = counter + 1;
            document.getElementById('_housenumber').onchange = function(){
                counter = document.getElementById('_housenumber').value - 1;
            };

            //If user has Auto Set Next HN turned on, register an event to watch changes
            if (autoSetHN)
                WazeWrap.Events.register("afteraction",null, hnActionCheck);
       }
    }
}

//Watches changes for new/moved HNs and updates the counter and house number text box
function hnActionCheck() {
    try {
        const lastAction = W.model.actionManager.getActions()[W.model.actionManager.getActionsNum()-1];
        const actionHN = +lastAction.houseNumber.getAttribute('number');
        if (counter != actionHN) {
            counter = actionHN;
            tlog('action: ' + actionHN, lastAction.houseNumber);
            if (document.getElementById('_housenumber') !== null )
                document.getElementById('_housenumber').value = counter + 1;
        }
    }
    catch {
        return;
    }
}

function activateEditTab(ind) {
    var ed = getElementsByClassName('segment-feature-editor');
    var tabs = ed[0].querySelector('wz-tabs');
    var tl = tabs.shadowRoot.querySelectorAll('.wz-tab-label');
    if ( tl && tl.length > 0) {
        if (ind < 0) ind = tl.length + ind;
        tl[ind].click();
    }
}

function getElementsByClassName(classname, node) {
    if(!node)
        node = document.getElementsByTagName("body")[0];
    var a = [];
    var re = new RegExp('\\b' + classname + '\\b');
    var els = node.getElementsByTagName("*");
    for (var i=0,j=els.length; i<j; i++)
        if (re.test(els[i].className)) a.push(els[i]);
    return a;
}

function addHN1t() { interval = 1; setFocus(); }
function addHN2r() { interval = 2; setFocus(); }
function addHN1() { addOrZoom(1, 11); }
function addHN2() { addOrZoom(2, 12); }
function addHN3() { addOrZoom(3, 13); }
function addHN4() { addOrZoom(4, 14); }
function addHN5() { addOrZoom(5, 15); }
function addHN6() { addOrZoom(6, 16); }
function addHN7() { addOrZoom(7, 17); }
function addHN8() { addOrZoom(8, 18); }
function addHN9() { addOrZoom(9, 19); }
function addHN10() { addOrZoom(10, 20); }

function addOrZoom( ival, zoom )
{
    if (!W.editingMediator.attributes.editingHouseNumbers) {
        if (zoomKeys) {
            W.map.olMap.zoomTo(zoom);
        }
    }
    else {
        interval = ival;
        setFocus();
    }
}

function addHNcustom()
{
    var temp = document.getElementById('_custominterval');
    //dlog("add cust el: " + temp.parentElement.innerText);
    interval = document.getElementById('_custominterval').value;
    dlog("add cust " + interval);
    setFocus();
}

async function setFocus()
{
    tlog('setFocus');
    fillnext = true;
    $('#toolbar .add-house-number').click();
}

// this may be a hack but works for now.  https://stackoverflow.com/questions/30683628/react-js-setting-value-of-input
function setNativeValue(element, value) {
    let lastValue = element.value;
    element.value = value;
    let event = new Event("input", { target: element, bubbles: true });
    // React 15
    event.simulated = true;
    // React 16
    let tracker = element._valueTracker;
    if (tracker) {
        tracker.setValue(lastValue);
    }
    element.dispatchEvent(event);
}

async function sethn() {
    tlog('sethn');
    var hn = $('div.olLayerDiv.house-numbers-layer div.house-number div.content.active:not(".new") input.number');
    if (fillnext && hn[0].placeholder == I18n.translations[I18n.locale].edit.segment.house_numbers.no_number && hn.val() === "")
    {
        dlog("sethn ctr " + counter + " ival " + interval);
        counter = +counter + +interval;
        if (document.getElementById('_housenumber') !== null )
            document.getElementById('_housenumber').value = counter + 1;
        setNativeValue(hn[0], counter);
        await new Promise(r => setTimeout(r,80));
        $("div#WazeMap").focus();
        fillnext = false;
    }
}

quickHN_bootstrap();
})();