Greasy Fork

Greasy Fork is available in English.

WME EZRoad

Easily update roads

当前为 2025-01-20 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         WME EZRoad
// @namespace    http://greasyfork.icu/en/scripts/518381-wme-ezroad
// @version      0.0.8
// @description  Easily update roads
// @author       https://github.com/michaelrosstarr
// @include 	 /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor.*$/
// @exclude      https://www.waze.com/user/*editor/*
// @exclude      https://www.waze.com/*/user/*editor/*
// @grant        GM_getValue
// @grant        GM_setValue
// @icon         https://www.google.com/s2/favicons?sz=64&domain=waze.com
// @grant        none
// @license MIT
// ==/UserScript==

const ScriptName = GM_info.script.name;
const ScriptVersion = GM_info.script.version;
let wmeSDK;

const log = (message) => {
    if (typeof message === 'string') {
        console.log('WME_EZRoads: ' + message);
    } else {
        console.log('WME_EZRoads: ', message);
    }
}

window.SDK_INITIALIZED.then(initScript);

function initScript() {
    wmeSDK = getWmeSdk({ scriptId: "wme-ez-roads", scriptName: "EZ Roads" });
    WME_EZRoads_bootstrap();
}

const getCurrentCountry = () => {
    return wmeSDK.DataModel.Countries.getTopCountry();
}

const getTopCity = () => {
    return wmeSDK.DataModel.Cities.getTopCity();
}

const getAllCities = () => {
    return wmeSDK.DataModel.Cities.getAll();
}

const saveOptions = (options) => {
    window.localStorage.setItem('WME_EZRoads_Options', JSON.stringify(options));
}

const getOptions = () => {
    return JSON.parse(window.localStorage.getItem('WME_EZRoads_Options')) || {roadType: 1, unpaved: false, setStreet: false, autosave: false, setSpeed: 60 };
}

const WME_EZRoads_bootstrap = () => {
    if (
        !document.getElementById('edit-panel')
        || !wmeSDK.DataModel.Countries.getTopCountry()
    ) {
        setTimeout(WME_EZRoads_bootstrap, 250);
        return;
    }

    if (wmeSDK.State.isReady) {
        WME_EZRoads_init();
    } else {
        wmeSDK.Events.once({ eventName: 'wme-ready' }).then(WME_EZRoads_init());
    }
}

let openPanel;

const WME_EZRoads_init = () => {
    log("Initing");

    const roadObserver = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            for (let i = 0; i < mutation.addedNodes.length; i++) {
                const addedNode = mutation.addedNodes[i];

                if (addedNode.nodeType === Node.ELEMENT_NODE) {
                    let editSegment = addedNode.querySelector('#segment-edit-general');
                    if (editSegment) {
                        openPanel = editSegment;
                        const quickButton = document.createElement('wz-button');
                        quickButton.setAttribute('type', 'button');
                        quickButton.setAttribute('style', 'margin-bottom: 5px, width: 100%');
                        quickButton.setAttribute('disabled', 'false');
                        quickButton.classList.add('send-button', 'ez-comment-button');
                        quickButton.textContent = 'Quick Set Road';
                        editSegment.parentNode.insertBefore(quickButton, editSegment);
                        quickButton.addEventListener('mousedown', () => handleUpdate());
                    }
                }
            }
        });
    });

    roadObserver.observe(document.getElementById('edit-panel'), { childList: true, subtree: true });

    constructSettings();

    document.addEventListener("keydown", (event) => {
        // Check if the active element is an input or textarea
        const isInputActive = document.activeElement && (
            document.activeElement.tagName === 'INPUT' ||
            document.activeElement.tagName === 'TEXTAREA' ||
            document.activeElement.contentEditable === 'true' ||
            document.activeElement.tagName === 'WZ-AUTOCOMPLETE' ||
            document.activeElement.tagName === 'WZ-TEXTAREA'
        );

        log(document.activeElement.tagName);
        log(isInputActive);

        // Only trigger the update if the active element is not an input or textarea
        if (!isInputActive && event.key.toLowerCase() === "u") {
            handleUpdate();
        }
    });

    log("Completed Init")
}

const getEmptyStreet = () => {
}

const getEmptyCity = () => {

    return wmeSDK.DataModel.Cities.getCity({
        cityName: '',
        countryId: getCurrentCountry().id
    }) || wmeSDK.DataModel.Cities.addCity({
        cityName: '',
        countryId: getCurrentCountry().id
    });

}

const handleUpdate = () => {
    const selection = wmeSDK.Editing.getSelection();

    if (!selection || selection.objectType !== 'segment') return;

    log('Updating RoadType');

    const options = getOptions();

    selection.ids.forEach(id => {

        // Road Type
        if (options.roadType) {

            const seg = wmeSDK.DataModel.Segments.getById({segmentId: id});

            if(seg.roadType !== options.roadType) {
                wmeSDK.DataModel.Segments.updateSegment({segmentId: id, roadType: options.roadType});
            }
        }

        // Speed Limit
        if(options.setSpeed != -1) {
            wmeSDK.DataModel.Segments.updateSegment({
                segmentId: id,
                fwdSpeedLimit: parseInt(options.setSpeed),
                revSpeedLimit: parseInt(options.setSpeed)
            });
        }

        // Handling the street
        if (options.setStreet) {

            let city;
            let street;

            city = getTopCity() || getEmptyCity();

            street = wmeSDK.DataModel.Streets.getStreet({
                cityId: city.id,
                streetName: '',
            });

            log(`City ${city.id}`);

            if(!street) {
                street = wmeSDK.DataModel.Streets.addStreet({
                    streetName: '',
                    cityId: city.id
                });
            }

            wmeSDK.DataModel.Segments.updateAddress({
                segmentId: id,
                primaryStreetId: street.id
            })
        }

        log(options);

        if(options.unpaved) {
            const wzCheckbox = openPanel.querySelector('wz-checkbox[name="unpaved"]');
            const hiddenInput = wzCheckbox.querySelector('input[type="checkbox"][name="unpaved"]');
            hiddenInput.click();
        }

    })

    // Autosave
    if (options.autosave) {
        wmeSDK.Editing.save().then(() => {});
    }

}

const constructSettings = () => {

    let localOptions = getOptions();

    const update = (key, value) => {
        const options = getOptions();
        options[key] = value;
        localOptions[key] = value;
        saveOptions(options);
    }

    // -- Set up the tab for the script
    wmeSDK.Sidebar.registerScriptTab().then(({ tabLabel, tabPane }) => {
        tabLabel.innerText = 'EZRoads';
        tabLabel.title = 'Easily Update Roads';

        tabPane.innerHTML = '<div id="ezroads-settings"></div>';

        const scriptContentPane = $('#ezroads-settings');

        scriptContentPane.append(`<h2 style="margin-top: 0;">EZRoads</h2>`);
        scriptContentPane.append(`<span>Current Version: <b>${ScriptVersion}</b></span><br>`);
        scriptContentPane.append(`<span>Update Keybind: <kbd>u</kbd></span><br>`);

        scriptContentPane.append(`<h5 style="margin-top: 0;">Set Road Type</h5>`);

        const primary = $(`<div>
            <input type="radio" id="road-ps" name="defaultRoad" ${localOptions.roadType === 2 && 'checked'}>
            <label for="road-ps">Primary Street</label><br>
        </div>`);
        primary.on('click', () => update('roadType', 2));

        const private = $(`<div>
            <input type="radio" id="road-private" name="defaultRoad" ${localOptions.roadType === 17 && 'checked'}>
            <label for="road-private">Private Road</label><br>
        </div>`);
        private.on('click', () => update('roadType', 17));

        const parking = $(`<div>
            <input type="radio" id="road-parking" name="defaultRoad" ${localOptions.roadType === 20 && 'checked'}>
            <label for="road-parking">Parking Lot Road</label><br>
        </div>`)
        parking.on('click', () => update('roadType', 20));

        const street = $(`<div>
            <input type="radio" id="road-street" name="defaultRoad" ${localOptions.roadType === 1 && 'checked'}>
            <label for="road-street">Street</label><br>
        </div>`)
        street.on('click', () => update('roadType', 1));

        const offroad = $(`<div>
            <input type="radio" id="offroad" name="defaultRoad" ${localOptions.roadType === 8 && 'checked'}>
            <label for="offroad">Set Offroad</label><br>
        </div>`)
        offroad.on('click', () => update('roadType', 8))

         const railroad = $(`<div>
            <input type="radio" id="railroad" name="defaultRoad" ${localOptions.roadType === 18 && 'checked'}>
            <label for="railroad">Set Railroad</label><br>
        </div>`)
        offroad.on('click', () => update('roadType', 18))

        scriptContentPane.append(primary).append(private).append(parking).append(street).append(offroad).append(railroad);

        scriptContentPane.append(`<h5 style="margin-top: 0;">Additional Options</h5>`);

        const setStreet = $(`<div>
            <input type="checkbox" id="setStreet" name="setStreet"  ${localOptions.setStreet && 'checked'}>
            <label for="setStreet">Set Street To None</label><br/>
        </div>`)
        .on('click', () => update('setStreet', !localOptions.setStreet))


        const autosave = $(`<div>
            <input type="checkbox" id="autosave" name="autosave"  ${localOptions.autosave && 'checked'}>
            <label for="autosave">Autosave on Action</label><br/>
        </div>`)
        .on('click', () => update('autosave', !localOptions.autosave))

        const unpaved = $(`<div>
            <input type="checkbox" id="unpaved" name="unpaved"  ${localOptions.unpaved && 'checked'}>
            <label for="unpaved">Set Road as Unpaved</label>
        </div>`)
        .on('click', () => update('unpaved', !localOptions.unpaved))

        scriptContentPane.append(setStreet).append(autosave).append(unpaved);

        const speedInput = $(`
        <div>
            <label for="setSpeed">Value to set speed to (set to -1 to disable)</label>
            <input type="number" id="setSpeed" name="setSpeed" value=${localOptions.setSpeed}>
        </div>
        `);

        speedInput.find('input').on('blur', function () {
            update('setSpeed', this.value);
        });

        scriptContentPane.append(speedInput);

    });

}