Greasy Fork 支持简体中文。

WME Shortcuts+

Shortcuts for multiple WME functions

// ==UserScript==
// @name         WME Shortcuts+
// @description  Shortcuts for multiple WME functions
// @icon         data:image/png;base64,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
// @author       N190392
// @match        https://*.waze.com/*editor*
// @version      0.3
// @require      https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @namespace    https://greasyfork.org/en/scripts/517140-wme-shortcuts
// @grant        GM_xmlhttpRequest
// @license      GPLv3
// ==/UserScript==

/* global W */
/* global WazeWrap */

(function() {
    'use strict';

    const SCRIPT_NAME = 'WME Shortcuts+';
    const SCRIPT_VERSION = '0.3';
    const UPDATE_MESSAGE = '';
    const FORUM_URL = '';
    const DOWNLOAD_URL = '';
    const EXTERNAL_SETTINGS_NAME = 'WME_SHORTCUTS_PLUS_SETTINGS';

// *** 1 ADD SHORTCUTS HERE *** //
    const EXTERNAL_SETTINGS = {
        pressPieEditGeomShortcut: '',
        clickOtherPointShortcut: '',
        toggleRankShortcut: '',
        clickOtherPolygonShortcut: '',
        highlightSmallVenuesShortcut: ''
    };

// *** 2 FUNCTIONS *** //
    // Function to create Other point
    function clickOtherPoint() {
        const menuItems = document.querySelectorAll('wz-menu-item');
        let pointButtonFound = false;

        menuItems.forEach(item => {
            const label = item.querySelector('.itemLabel--kXZjU');
            if (label && ["Cits", "Other"].includes(label.textContent.trim())) {
                const pointButton = item.querySelector('wz-button.point');
                if (pointButton) {
                    pointButton.click();
                    console.log("WME Shortcuts+: Other (point) activated successfully.");
                    pointButtonFound = true;
                }
            }
        });

        if (!pointButtonFound) {
            console.log("WME Shortcuts+: 'Other' button not found.");
        }
    }

    // Function to create Other polygon
    function clickOtherPolygon() {
        const menuItems = document.querySelectorAll('wz-menu-item');
        let PolygonButtonFound = false;

        menuItems.forEach(item => {
            const label = item.querySelector('.itemLabel--kXZjU');
            if (label && ["Cits", "Other"].includes(label.textContent.trim())) {
                const PolygonButton = item.querySelector('wz-button.polygon');
                if (PolygonButton) {
                    PolygonButton.click();
                    console.log("WME Shortcuts+: Other (polygon) activated successfully.");
                    PolygonButtonFound = true;
                }
            }
        });

        if (!PolygonButtonFound) {
            console.log("WME Shortcuts+: 'Other' button not found.");
        }
    }

    // Function to toggle rank to 2 and transoform point to area
    function toggleRank() {
        const checkableChip = document.querySelector('#lockRank-1');
        if (checkableChip) {
            checkableChip.click();
            console.log("WME Shortcuts+: Local rank changed to 2.");
        }

        const poligonsChip = Array.from(document.querySelectorAll('wz-checkable-chip'))
        .find(chip => ['Poligons', 'Area'].some(text => chip.textContent.includes(text)));
        if (poligonsChip) {
            poligonsChip.click();
            console.log("WME Shortcuts+: Point transformed to polygon");
        }
    }

    // Function to open PIE Geometry settings
    function pressPieEditGeomButton() {
        const button = document.querySelector('#pieEditGeom');
        if (button) {
            button.click();
            console.log("WME Shortcuts+: Opened Geometry menu.");
        }
    }

    // Function to highlight a place with specified colors
    function highlightSmallVenues() {
    //console.log("Starting small venues scan...");
        function highlightAPlace(venue, fg, bg) {
            var poly = W.userscripts.getFeatureElementByDataModel(venue);
            if (poly) {
                if (venue.isPoint()) {
                    poly.setAttribute("fill", fg);
                } else { // area (polygon)
                    poly.setAttribute("stroke", fg);
                    poly.setAttribute("fill", bg);
                    poly.setAttribute("stroke-width", 2);
                }
            }
        }
        // Iterate over all venues
        for (var mark in W.model.venues.objects) {
            var venue = W.model.venues.getObjectById(mark);
            if (!venue) continue;
            if (venue.attributes) {
                try {
                    // Try to get geometry directly from the venue
                    var metersArea = venue.getOLGeometry().getGeodesicArea(W.map.getProjectionObject());
                    // If area is less than 500m², highlight in red
                    if (metersArea < 500) {
                        highlightAPlace(venue, "#f00", "#f99");  // Red stroke, light red fill
                        console.log(
                            "Small venue found: " + venue.attributes.name +
                            "\nArea: " + metersArea.toFixed(2) + " m²"
                        );
                    }
                } catch(e) {
                    // Skip venues that cause errors (like points)
                    continue;
                }
            }
        }
    }

// *** 3 SHORTCUT MENU *** //
    // WazeWrap Shortcut setup functions
    function addShortcuts() {
        new WazeWrap.Interface.Shortcut(
            'clickOtherPoint',
            'Cits: Izveidot punktu',
            'shortcuts_plus',
            'WME Shortcuts+',
            EXTERNAL_SETTINGS.clickOtherPointShortcut,
            clickOtherPoint,
            null
        ).add();

        new WazeWrap.Interface.Shortcut(
            'clickOtherPolygon',
            'Cits: Izveidot poligonu',
            'shortcuts_plus',
            'WME Shortcuts+',
            EXTERNAL_SETTINGS.clickOtherPolygonShortcut,
            clickOtherPolygon,
            null
        ).add();

        new WazeWrap.Interface.Shortcut(
            'toggleRank',
            'Slēgt ar līmeni (2) & pārveidot punktu par poligonu',
            'shortcuts_plus',
            'WME Shortcuts+',
            EXTERNAL_SETTINGS.toggleRankShortcut,
            toggleRank,
            null
        ).add();

        new WazeWrap.Interface.Shortcut(
            'PressEditGeom',
            'Atvērt ģeometrijas izvēlni',
            'shortcuts_plus',
            'WME Shortcuts+',
            EXTERNAL_SETTINGS.pressPieEditGeomShortcut,
            pressPieEditGeomButton,
            null
        ).add();

        new WazeWrap.Interface.Shortcut(
        'highlightSmallVenues',
        'Iezīmēt vietas, kas ir mazākas par 500m²',
        'shortcuts_plus',
        'WME Shortcuts+',
        EXTERNAL_SETTINGS.highlightSmallVenuesShortcut,
        highlightSmallVenues,
        null
    ).add();
    }

// *** 4 MAKE SHORTCUTS CHANGABLE *** //
    function sandboxLoadSettings() {
        const loadedSettings = JSON.parse(localStorage.getItem(EXTERNAL_SETTINGS_NAME)) || {};
        EXTERNAL_SETTINGS.clickOtherPointShortcut = loadedSettings.clickOtherPointShortcut || 'C+1';
        EXTERNAL_SETTINGS.clickOtherPolygonShortcut = loadedSettings.clickOtherPolygonShortcut || 'C+2';
        EXTERNAL_SETTINGS.toggleRankShortcut = loadedSettings.toggleRankShortcut || 'A+2';
        EXTERNAL_SETTINGS.pressPieEditGeomShortcut = loadedSettings.pressPieEditGeomShortcut || 'A+3';
        EXTERNAL_SETTINGS.highlightSmallVenuesShortcut = loadedSettings.highlightSmallVenuesShortcut || 'A+1';
        addShortcuts();
        $(window).on('beforeunload', () => sandboxSaveSettings());
    }

    function getShortcutKeys(shortcutAction) {
        let keys = '';
        const { shortcut } = shortcutAction;
        if (shortcut) {
            if (shortcut.altKey) keys += 'A';
            if (shortcut.shiftKey) keys += 'S';
            if (shortcut.ctrlKey) keys += 'C';
            if (keys.length) keys += '+';
            if (shortcut.keyCode) keys += shortcut.keyCode;
        }
        return keys;
    }

    function sandboxSaveSettings() {
        EXTERNAL_SETTINGS.clickOtherPointShortcut = getShortcutKeys(W.accelerators.Actions.clickOtherPoint);
        EXTERNAL_SETTINGS.toggleRankShortcut = getShortcutKeys(W.accelerators.Actions.toggleRank);
        EXTERNAL_SETTINGS.pressPieEditGeomShortcut = getShortcutKeys(W.accelerators.Actions.PressEditGeom);
        EXTERNAL_SETTINGS.clickOtherPolygonShortcut = getShortcutKeys(W.accelerators.Actions.clickOtherPolygon);
        EXTERNAL_SETTINGS.highlightSmallVenuesShortcut = getShortcutKeys(W.accelerators.Actions.highlightSmallVenues);  // Add this line
        localStorage.setItem(EXTERNAL_SETTINGS_NAME, JSON.stringify(EXTERNAL_SETTINGS));
    }

    function loadScriptUpdateMonitor() {
        let updateMonitor;
        try {
            updateMonitor = new WazeWrap.Alerts.ScriptUpdateMonitor(
                SCRIPT_NAME,
                SCRIPT_VERSION,
                DOWNLOAD_URL,
                GM_xmlhttpRequest
            );
            updateMonitor.start();
        } catch (ex) {
            console.error(`${SCRIPT_NAME}:`, ex);
        }
    }

    function bootstrap() {
        if (WazeWrap?.Ready) {
            WazeWrap.Interface.ShowScriptUpdate(
                SCRIPT_NAME,
                SCRIPT_VERSION,
                UPDATE_MESSAGE,
                FORUM_URL
            );
            loadScriptUpdateMonitor();
            sandboxLoadSettings();
        } else {
            setTimeout(bootstrap, 250);
        }
    }

    bootstrap();
})();