WME WazeMY

WME script for WazeMY editing moderation

目前為 2022-08-08 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         WME WazeMY
// @namespace    https://greasyfork.org/en/scripts/404584-wazemy
// @version      2022.08.08.02
// @description  WME script for WazeMY editing moderation
// @author       junyianl
// @match        https://beta.waze.com/*
// @match        https://www.waze.com/forum/*
// @match        https://www.waze.com/editor*
// @match        https://www.waze.com/*/editor*
// @match        https://www.waze.com/user/editor*
// @require      https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @require      https://greasyfork.org/scripts/449165-wme-wazemy-trafcamlist/code/wme-wazemy-trafcamlist.js
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

// @connect      fgies.com
// @connect      jalanow.com
// @connect      odis.sgp1.digitaloceanspaces.com

/* global W */
/* global WazeWrap */
/* global $ */
/* global OL */
/* global OpenLayers */

/**
 * All mentions of script names and links in this script is my way of giving
 * credit to where it's due.
 * Without those scripts, I would have no place to start.
 * Big thanks to the original script authors.
 *
 * Huge thanks to the following contributors for cam locations around Malaysia.
 * :: epailxi | dckj | firman_bakti | rickylo103 ::
 */

const updateMessage = "► Moved traffic cams list to separate library file for more seamless updates of cams list.";
var staticUpdateID;

(function() {
    'use strict';
    var settings = {};

    function bootstrap(tries = 1) {
        if (W && W.map && W.model && W.loginManager.user &&
            $ && WazeWrap.Ready) {
            init();
        } else if (tries < 1000) {
            setTimeout(function () {bootstrap(++tries);}, 200);
        } else {
            WazeWrap.Alerts.error(GM_info.script.name, "Bootstrap timeout.")
        }
    }

    async function init() {
        let $section = $('<div>');
        $section.html([
            '<div>',
            'Version: <span id="wazemyVersion"></span><br>',
            '<span id="wazemyUsername"></span> (<span id="wazemyRank"></span>)',
            '</div><br>',
            '<div id="wazemySettings">',
            '<b>Settings</b><br>',
            '<input type="checkbox" id="wazemySettings_tooltip">',
            '<label for="wazemySettings_tooltip">Map tooltip</label><br>',
            '<input type="checkbox" id="wazemySettings_trafcam">',
            '<label for="wazemySettings_trafcam">Traffic cameras</label><br>',
            '</div><br>',
            '<div>',
            '<b>Shortcuts</b><br>',
            'Ctrl+Alt+C: Copy lat/lon of mouse position to clipboard.<br>',
            '</div>'
        ].join(' '));
        
        // Initialize features of WME WazeMY
        wazemyTooltip_init();
        wazemyTrafcam_init();

        new WazeWrap.Interface.Tab('WazeMY', $section.html(), initializeSettings);
        WazeWrap.Interface.ShowScriptUpdate("WME WazeMY", GM_info.script.version, 
            updateMessage, "https://greasyfork.org/en/scripts/404584-wazemy", null);

        // Initialize keyboard shortcuts
        new WazeWrap.Interface.Shortcut('WazeMY_latloncopy', 
            'Copies lat/lon of mouse position', 'wazemy', 'WazeMY', 'CA+c', 
            wazemyCopyLatLon, null).add();
    }

    /* ******* */
    /* Tooltip */
    /* ******* */
    function wazemyTooltip_init() {
        let $tooltip = $('<div/>');
        $tooltip.attr('id', 'wazemyTooltip');
        $tooltip.css({
            'height':'auto',
            'width':'auto',
            'background':'rgba(0,0,0,0.5)',
            'color':'white',
            'borderRadius':'5px',
            'padding':'5px',
            'position':'absolute',
            'top':'0px',
            'left':'0px',
            'visibility':'hidden',
            'zIndex':'10000'
        })
        $tooltip.appendTo('body');
    }

    function wazemyTooltip_initSettings() {
        setChecked('wazemySettings_tooltip', settings.tooltip);
        if (settings.tooltip) {
            WazeWrap.Events.register('mousemove', null, wazemyTooltip_show);
        }
        $('#wazemySettings_tooltip').change(function () {
            var settingName = $(this)[0].id.substr(15); // strip off the "wazemySettings_" prefix
            settings[settingName] = this.checked;
            saveSettings();
            if (this.checked) {
                WazeWrap.Events.register('mousemove', null, wazemyTooltip_show);
            }
            else {
                WazeWrap.Events.unregister('mousemove', null, wazemyTooltip_show);
            }
        });
    }

    function wazemyTooltip_show(e) { // from URO+
        var result = '';
        var showTooltip = false;

        let landmark = W.map.venueLayer.getFeatureBy('renderIntent', 'highlight');
        let segment = W.map.segmentLayer.getFeatureBy('renderIntent', 'highlight');

        if (landmark != null) {
            result = '<b>' + landmark.model.attributes.name + '</b><br>';
            let address = landmark.model.getAddress();
            try {
                result += address.attributes.houseNumber ? (address.attributes.houseNumber + ', ') : ''
                result += (address.attributes.street.name ? address.attributes.street.name : 'No street') + '<br>';
                result += address.attributes.city.attributes.name + ', ';
                result += address.attributes.state.name + '<br>';
            }
            catch {
                result += 'No address<br>';
            }
            result += '<b>Lock:</b> ' + (landmark.model.getLockRank() + 1);
            showTooltip = true;
        } else if (segment != null) {
            let segmentId = segment.model.attributes.id;
            // let primaryStreetId = WazeWrap.Model.getPrimaryStreetId(segmentId);
            let address = segment.model.getAddress();
            result = '<b>';
            result += address.attributes.street.name ? address.attributes.street.name : 'No street';
            result += '</b><br>';
            result += address.attributes.city.attributes.name + ', ' + address.attributes.state.name;
            result += '<br>';
            result += '<b>ID:</b> ' + segmentId + '<br>';
            result += '<b>Lock:</b> ' + (segment.model.getLockRank() + 1);
            showTooltip = true;
        }

        if (showTooltip == true) {
            let tw = $('#wazemyTooltip').width();
            let th = $('#wazemyTooltip').height();
            var tooltipX = e.clientX + window.scrollX + 15;
            var tooltipY = e.clientY + window.scrollY + 15;
            if ((tooltipX + tw) > W.map.$map.innerWidth()) {
                tooltipX -= tw + 20; // 20 = scroll bar size
                if (tooltipX < 0) tooltipX = 0;
            }
            if ((tooltipY + th) > W.map.$map.innerHeight()) {
                tooltipY -= th + 20;
                if (tooltipY < 0) tooltipY = 0;
            }
            $('#wazemyTooltip').html(result);
            $('#wazemyTooltip').css({
                'top':tooltipY + 'px',
                'left':tooltipX + 'px',
                'visibility':'visible'
            });
        } else {
            $('#wazemyTooltip').css('visibility', 'hidden');
        }
    }

    /* *************** */
    /* Traffic cameras */
    /* *************** */
    // Adapted from WME DOT Cameras
    var wazemyTrafcamLayer;

    function wazemyTrafcam_init() {
        if (!OpenLayers.Icon) {
            wazemyTrafcam_installIconClass();
        }
        wazemyTrafcamLayer = new OpenLayers.Layer.Markers("wazemyTrafcamLayer");
        W.map.addLayer(wazemyTrafcamLayer);
        wazemyTrafcam_show();
        wazemyTrafcamLayer.setVisibility(false);
    }

    function wazemyTrafcam_initSettings() {
        setChecked('wazemySettings_trafcam', settings.trafcam);
        if (settings.trafcam) {
            wazemyTrafcamLayer.setVisibility(true);
            // WazeWrap.Events.register('moveend', null, wazemyTrafcam_show);
        }
        $('#wazemySettings_trafcam').change(function () {
            var settingName = $(this)[0].id.substr(15); // strip off the "wazemySettings_" prefix
            settings[settingName] = this.checked;
            saveSettings();
            if (this.checked) {
                wazemyTrafcamLayer.setVisibility(true);
                // WazeWrap.Events.register('moveend', null, wazemyTrafcam_show);
            } else {
                // WazeWrap.Events.unregister('moveend', null, wazemyTrafcam_show);
               wazemyTrafcamLayer.setVisibility(false);
            }
        });
    }

    function wazemyTrafcam_show(e) {
        trafficCamsData.forEach(e => {
            wazemyTrafcam_drawCam({
                desc:e.desc,
                src:e.url,
                width:20,
                height:20,
                lat:e.lat,
                lon:e.lon
            });
        });
    }

    function wazemyTrafcam_drawCam(spec) {
        const camIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAAGXcA1uAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpBRDNGNTkwRTYzQThFMzExQTc4MDhDNjAwODdEMzdEQSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2OUI0RUEyN0IwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2OUI0RUEyNkIwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjZGOEJBMzExNkZCMEUzMTFCOEY5QTU3QUQxM0M2MjI5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkFEM0Y1OTBFNjNBOEUzMTFBNzgwOEM2MDA4N0QzN0RBIi8+IDwvcmRmOkRlc2NyaXB0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';
        let size = new OpenLayers.Size(20,20);
        let icon = new OpenLayers.Icon(camIcon, size);
        let epsg4326 = new OpenLayers.Projection("EPSG:4326"); // WGS 1984 projection. Malaysia uses EPSG:900913
        let projectTo = W.map.getProjectionObject();
        let lonLat = new OpenLayers.LonLat(spec.lon, spec.lat).transform(epsg4326, projectTo);
        var newMarker = new OpenLayers.Marker(lonLat, icon);
        newMarker.title = spec.desc;
        newMarker.url = spec.src;
        newMarker.width = spec.width;
        newMarker.height = spec.height;
        newMarker.location = lonLat;
        newMarker.events.register('click', newMarker, wazemyTrafcam_popupCam);
        wazemyTrafcamLayer.addMarker(newMarker);
    }

    function wazemyTrafcam_popupCam(e) {
        console.log("wazemyTrafcam_popupCam");

        clearInterval(staticUpdateID);
        $("#gmPopupContainerCam").remove();
        $("#gmPopupContainerCam").hide();

        var popupHTML = ([`
            <div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100; position: absolute; color: white; background: rgba(0,0,0,0.5)">
            <table border=0>
                <tr>
                    <td><div id="mycamdivheader" style="min-height: 20px;white-space: pre-wrap;white-space: -moz-pre-wrap; white-space: -pre-wrap;white-space: -o-pre-wrap;word-wrap: break-word;width:380px">${this.title}</div></td>
                    <td align="right"><a href="#close" id="gmCloseCamDlgBtn" title="Close" style="color:red">X</a></td>
                </tr>
                <tr><td colspan=2><img style="width:400px" id="staticimage"></td></tr>
            </table></div>
        `]);
        $("body").append(popupHTML);
        GM_xmlhttpRequest({
            method: 'GET',
            responseType: 'blob',
            headers: {
                "authority":"p4.fgies.com",
                "referer":'https://www.jalanow.com/',
                'accept':'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'
            },
            url: this.url,
            onload: function (response) {
                document.getElementById('staticimage').src = URL.createObjectURL(response.response);
            }
        });
        $("#gmPopupContainerCam").css({ left: e.clientX + window.scrollX + 15 });
        $("#gmPopupContainerCam").css({ top: e.clientY + window.scrollY + 15 });

        //Add listener for popup's "Close" button
        $("#gmCloseCamDlgBtn").click(function () {
            clearInterval(staticUpdateID);
            $("#gmPopupContainerCam").remove();
            $("#gmPopupContainerCam").hide();
        });
        wazemyTrafcam_dragElement(document.getElementById("gmPopupContainerCam"));
    }

    function wazemyTrafcam_installIconClass() {
        OpenLayers.Icon = OpenLayers.Class({
            url: null,
            size: null,
            offset: null,
            calculateOffset: null,
            imageDiv: null,
            px: null,
            initialize: function (a, b, c, d) {
                this.url = a;
                this.size = b || {
                    w: 20,
                    h: 20
                };
                this.offset = c || {
                    x: -(this.size.w / 2),
                    y: -(this.size.h / 2)
                };
                this.calculateOffset = d;
                a = OpenLayers.Util.createUniqueID("OL_Icon_");
                let div = this.imageDiv = OpenLayers.Util.createAlphaImageDiv(a);
                $(div.firstChild).removeClass('olAlphaImg'); // LEAVE THIS LINE TO PREVENT WME-HARDHATS SCRIPT FROM TURNING ALL ICONS INTO HARDHAT WAZERS --MAPOMATIC
            },
            destroy: function () {
                this.erase();
                OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
                this.imageDiv.innerHTML = "";
                this.imageDiv = null;
            },
            clone: function () {
                return new OpenLayers.Icon(this.url, this.size, this.offset, this.calculateOffset);
            },
            setSize: function (a) {
                null !== a && (this.size = a);
                this.draw();
            },
            setUrl: function (a) {
                null !== a && (this.url = a);
                this.draw();
            },
            draw: function (a) {
                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, this.size, this.url, "absolute");
                this.moveTo(a);
                return this.imageDiv;
            },
            erase: function () {
                null !== this.imageDiv && null !== this.imageDiv.parentNode && OpenLayers.Element.remove(this.imageDiv);
            },
            setOpacity: function (a) {
                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, null, null, null, null, a);
            },
            moveTo: function (a) {
                null !== a && (this.px = a);
                null !== this.imageDiv && (null === this.px ? this.display(!1) : (
                    this.calculateOffset && (this.offset = this.calculateOffset(this.size)),
                    OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {
                        x: this.px.x + this.offset.x,
                        y: this.px.y + this.offset.y
                    })
                ));
            },
            display: function (a) {
                this.imageDiv.style.display = a ? "" : "none";
            },
            isDrawn: function () {
                return this.imageDiv && this.imageDiv.parentNode && 11 != this.imageDiv.parentNode.nodeType;
            },
            CLASS_NAME: "OpenLayers.Icon"
        });
    }

    // Make the DIV element draggable:
    function wazemyTrafcam_dragElement(elmnt) {
        var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        if (document.getElementById("mycamdivheader")) {
            // if present, the header is where you move the DIV from:
            document.getElementById("mycamdivheader").onmousedown = dragMouseDown;
        } else {
            // otherwise, move the DIV from anywhere inside the DIV:
            elmnt.onmousedown = dragMouseDown;
        }

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            // get the mouse cursor position at startup:
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            // call a function whenever the cursor moves:
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            // calculate the new cursor position:
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            // set the element's new position:
            elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
            elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
        }

        function closeDragElement() {
            // stop moving when mouse button is released:
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }

    /* ************ */
    /* Copy lat/lon */
    /* ************ */
    function wazemyCopyLatLon(){
        copyToClipboard($('.mouse-position').text());
    }

    function initializeSettings() {
        loadSettings();

        $('#wazemyVersion').text(GM_info.script.version);
        $('#wazemyUsername').text(WazeWrap.User.Username());
        $('#wazemyRank').text(WazeWrap.User.Rank());

        wazemyTooltip_initSettings();
        wazemyTrafcam_initSettings();
    }

    function saveSettings() {
        if (localStorage) {
            var localsettings = {
                tooltip: settings.tooltip,
                trafcam: settings.trafcam
            };

            localStorage.setItem('WME_wazemySettings', JSON.stringify(localsettings));
        }
    }

    function loadSettings() {
        var loadedSettings = $.parseJSON(localStorage.getItem("WME_wazemySettings"));
        var defaultSettings = {
            tooltip: false,
        };
        settings = loadedSettings ? loadedSettings : defaultSettings;
        for (var prop in defaultSettings) {
            if (!settings.hasOwnProperty(prop)) {
                settings[prop] = defaultSettings[prop];
            }
        }
    }

    function setChecked(checkboxId, checked) {
        $('#' + checkboxId).prop('checked', checked);
    }

    // utility functions
    var copyToClipboard = function(str) { // from PIE
        var $temp = $('<input>');
        $('body').append($temp);
        $temp.val(str).select();
        document.execCommand('copy');
        $temp.remove();
    };

    bootstrap();
})();