Greasy Fork is available in English.

WME Edition Counter and Helper

It counts the edits and suggests a time for the next save.

// ==UserScript==
// @name             WME Edition Counter and Helper
// @name:es          WME Contador de Ediciones y Ayudante
// @description      It counts the edits and suggests a time for the next save.
// @description:es   Cuentas las ediciones y sugiere un tiempo para el próximo guardado.

// @author           Rodrigo_Reina
// @namespace        https://greasyfork.org/en/users/1192362-rodrigo-reina
// @version          2023.10.11.03
// @license          GNU GPLv3
// @icon             data:image/png;base64,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
// @contributionURL  https://ko-fi.com/wme_rodrigo_reina

// @include          /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
// @exclude          https://www.waze.com/user/*
// @exclude          https://www.waze.com/*/user/*
// @require          https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @require          https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @connect          www.waze.com
// @connect          greasyfork.org
// @grant            GM_xmlhttpRequest
// @grant            GM_addElement
// ==/UserScript==

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

/**
* ===============================================
*  This script is based on the following scripts:
*  - "Waze Edit Count Monitor" (by MapOMatic)
*  - "Waze WME Edition Helper" (by EdwardNavarro)
* ===============================================
*/

// TODO: 
// - Supporting languages

(function main() {
    'use strict';

    const SCRIPT_NAME = 'WME Edition Counter and Helper';
    const SCRIPT_VERSION = '2023.10.11.03';
    const DOWNLOAD_URL = 'https://greasyfork.org/scripts/40313-waze-edit-count-monitor/code/Waze%20Edit%20Count%20Monitor.user.js';

    function wmeECHInjected() {
        const TOOLTIP_TEXT = '<b>Ediciones Diarias</b><br><small>(Clic para ver el perfil)<small>';
        const TOASTR_URL = 'https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.js';
        const VERSION = '2023.10.11.03';
        const DEBUG_LEVEL = 0;
        let _toastrSettings  = {
            timeBeforeSaving: 70,
            remindAtEditCount: 30,
            warnAtEditCount: 30,
            wasReminded: false,
            wasWarned: false
        };

        let _userName = '';
        let _lastTodayEditCount = 0;
        let _lastYesterdayEditCount = 0;
        let _lastDayBeforeEditCount = 0;
        let _savesWithoutIncrease = 0;
        let _totalSeconds = 0;
        let _timerInterval;

        let _buttonContainer,
            _buttonContentWrap,
            _buttonItemContainer,
            _buttonItemLink,
            _buttonItemContent,
            _progressBarWrap,
            _progressBarFill,
            _savedTimer;
        
        if (!localStorage.WMEEditionHelperScript) {
            let options = [null,_toastrSettings .timeBeforeSaving,_toastrSettings .remindAtEditCount,_toastrSettings .warnAtEditCount,false,false];
            localStorage.WMEEditionHelperScript = JSON.stringify(options);
        }

        function log(message, level, prefix = 'LOG', bgColor = 'darkslategrey', textColor = 'white') {
            if (message && level <= DEBUG_LEVEL) {
                console.log('%c%s%s', `background:${bgColor};color:${textColor};padding:5px 10px;`, `[${prefix}] WME Edition Counter And Helper >>`, message);
            }
        }

        function checkCounters() {
            window.postMessage(JSON.stringify(['wme_echGetCounts', _userName]), '*');
            _toastrSettings.wasReminded = false;
            _toastrSettings.wasWarned = false;
            toastr.remove();
        }

        function getChangedObjectCount() {
            let _count = 0;
            try{
                _count = parseInt($('#save-button > div.counter').text());
            }
            catch(err){
                // Do Nothing
            }
            return _count;
        }

        function updateEditCount(todayEditCount = 0, noIncrement) {
            let _textColor;
            let _bgColor;
            let _tooltipTextColor;
            
            if ($('#wme_ech').length === 0) {
                _buttonContainer = $('<div>', { id: 'wme_ech', style: 'border-radius: 15px;'});
                _buttonContentWrap = $('<div>', { class: 'toolbar-button' });
                _buttonItemLink = $('<a>', { href: 'https://www.waze.com/user/editor/' + _userName, target: '_blank', style:'text-decoration: none;', 'data-original-title': TOOLTIP_TEXT });
                _buttonItemContainer = $('<div>', { class: 'item-container' });
                _buttonItemContent = $('<div>', { style: 'margin: 7px; line-height: 1;' });

                _progressBarWrap = $('<div>', { style: 'width: 100%; height: 5px; background-color: #d7dadc;border: 1px solid #fff; box-sizing: border-box;' });
                _progressBarFill = $('<div>', { class: 'progress', style: 'width: 0%; height: 5px; animation-fill-mode: both; animation-name: progressBar; animation-duration:' + _toastrSettings.timeBeforeSaving + 's; animation-timing-function: linear;' });

                _savedTimer = $('<div>', { id: 'saved-timer', style: 'font-size:8px; line-height:1; text-align:right; color:darkgray;' });

                _buttonContainer.append(_buttonContentWrap);
                _buttonContentWrap.append(_buttonItemLink);
                _buttonItemLink.append(_buttonItemContainer);
                _buttonItemContainer.append(_buttonItemContent);

                _buttonItemContent.append(_progressBarWrap);
                _buttonItemContent.append(_savedTimer);
                _progressBarWrap.append(_progressBarFill);

                $('#toolbar > div > div.secondary-toolbar > div:nth-child(1)').after(_buttonContainer);

                _buttonItemLink.tooltip({
                    placement: 'auto top',
                    delay: { show: 100, hide: 100 },
                    html: true,
                    template: '<div class="tooltip" role="tooltip" style="opacity:0.95"><div class="tooltip-arrow"></div><div class="my-tooltip-header" style="display:block;"><b></b></div><div class="my-tooltip-body tooltip-inner" style="display:block;"></div></div>'
                });
            }

            if (_lastTodayEditCount !== todayEditCount) {
                _savesWithoutIncrease = 0;
            } else {
                if (!noIncrement) _savesWithoutIncrease += 1;
            }
            
            switch (_savesWithoutIncrease) {
                case 0:
                case 1:
                    _textColor = '#354148';
                    _bgColor = '';
                    _tooltipTextColor = 'white';
                    break;
                case 2:
                    _textColor = '#354148';
                    _bgColor = 'yellow';
                    _tooltipTextColor = 'black';
                    break;
                default:
                    _textColor = 'white';
                    _bgColor = 'red';
                    _tooltipTextColor = 'white';
            }

            _buttonContainer.css('background-color', _bgColor);
            _buttonItemContent.css('color', _textColor).html(`Ediciones: ${todayEditCount}`);
            _buttonItemContent.append(_progressBarWrap);
            _buttonItemContent.append(_savedTimer);

            let _daysCounterText = `<hr style="border:0 none; border-bottom:1px #999 solid; margin:5px 0;"/><div class="days-group"><div class="day-1"><h3>Hoy</h3><span>${todayEditCount}</span></div><div class="day-2"><h3>Ayer</h3><span>${_lastYesterdayEditCount}</span></div><div class="day-3"><h3>Antier</h3><span>${_lastDayBeforeEditCount}</span></div></div>`;
            let _warningText = (_savesWithoutIncrease > 0) ? `<div style="font-size:13px;border-radius:5px;padding:5px;margin-top:5px;color:${_tooltipTextColor};background-color:${_bgColor};"><b>${_savesWithoutIncrease}</b> salvadas/guardadas consecutivas sin incremento en el contador.<br><span style="font-weight:bold;font-size:16px;">¿Estás estrangulado?<span></div>` : '';
            _buttonItemLink.attr('data-original-title', TOOLTIP_TEXT + _daysCounterText + _warningText);

            _lastTodayEditCount = todayEditCount;
            _totalSeconds = 0;

            clearTimeout(_timerInterval);
            runTimer();
        }

        function runTimer(){
            _timerInterval = setInterval(setTime, 1000);
        }

        function setTime(){
            ++_totalSeconds;
            const hours = parseInt(_totalSeconds / 3600) % 24;
            const minutes = parseInt(_totalSeconds / 60) % 60;
            const seconds = _totalSeconds % 60;
            const timeString = `${(hours > 0) ? `${pad(hours)}:` : ''}${pad(minutes)}:${pad(seconds)}`;
            $('#saved-timer').html(timeString);
        }

        function pad(val) {
            const valString = val + '';
            return (valString.length < 2) ? '0' + valString : valString;
        }

        function receiveMessage(event) {
            let _msg;
            try {
                _msg = JSON.parse(event.data);
            } catch (err) {
                // Do nothing
            }

            if (_msg && _msg[0] === 'wme_echUpdateCounts') {
                const todayEditCount = _msg[1][0];
                const yesterdayEditCount = _msg[1][1];
                const dayBeforeEditCount = _msg[1][2];
                _lastYesterdayEditCount = yesterdayEditCount;
                _lastDayBeforeEditCount = dayBeforeEditCount;
                updateEditCount(todayEditCount);
            }
        }

        function errorHandler(callback) {
            try {
                callback();
            } catch (e) {
                console.error('%c%s%s', 'background:darkred;color:white;padding:5px 10px;', '[ERROR] WME Edition Counter And Helper >>', e);
            }
        }

        function checkChangedObjectCount() {
            let objectEditCount = getChangedObjectCount();
            
            if (objectEditCount >= _toastrSettings.warnAtEditCount && !_toastrSettings.wasWarned) {
                toastr.remove();
                toastr.error('<span style="font-size:16px;">Has editado al menos <b>' + _toastrSettings.warnAtEditCount + '</b> objetos.</span><br><br> Deberías considerar guardar pronto. Si obtienes un error al guardar, necesitarás deshacer algunos cambios/acciones e intentar nuevamente.', 'WME Edition Counter And Helper:', {timeOut: 25000});
                _toastrSettings.wasWarned = true;
                //log('WARMED', 0, 'ALERT', 'tomato')
            } else if (objectEditCount >= _toastrSettings.remindAtEditCount && !_toastrSettings.wasReminded) {
                toastr.remove();
                toastr.warning('<span style="font-size:16px;">Has editado al menos <b>' + _toastrSettings.remindAtEditCount + '</b> objetos.</span><br><br> Deberías considerar guardar pronto.', 'WME Edition Counter And Helper:', {timeOut: 15000});
                _toastrSettings.wasReminded = true;
                //log('REMINDED', 0, 'ALERT', 'orange')
            } else if (objectEditCount < _toastrSettings.remindAtEditCount) {
                _toastrSettings.wasWarned = false;
                _toastrSettings.wasReminded = false;
                toastr.remove();
                //log('REMOVED', 0, 'ALERT', 'sienna')
            }
        }

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

        function getId(node) {
            return document.getElementById(node);
        }

        function updateAddonSettings(event) {
            _toastrSettings.timeBeforeSaving = getId('_ehSavingWaitTime').value;
            _toastrSettings.remindAtEditCount = getId('_ehRememberAfter').value;
            _toastrSettings.warnAtEditCount = getId('_ehAlertAfter').value;

            $('.progress').css('animation-duration', `${getId('_ehSavingWaitTime').value}s`);
        }

        async function init() {
            _userName = W.loginManager.user.getUsername();

            window.addEventListener('message', receiveMessage);

            // restore saved settings
            if (localStorage.WMEEditionHelperScript) {
                let options = JSON.parse(localStorage.WMEEditionHelperScript);

                _toastrSettings.timeBeforeSaving = options[1];
                _toastrSettings.remindAtEditCount = options[2];
                _toastrSettings.warnAtEditCount = options[3];
            }

            // check if sidebar is hidden
            let sidebar = getId('sidebar');
            if (sidebar.style.display == 'none') {
                log("Not logged in yet - will initialise at login", 0, 'WARN', 'orange');
                W.loginManager.events.register("login", null, init);
                return;
            }

            // check that user-info section is defined
            let userTabs = getId('user-info');
            if (userTabs === null) {
                log("Editor not initialised yet - trying again in a bit...", 0, 'WARN', 'orange');
                setTimeout(init, 789);
                return;
            }

            $('head').append(
                $('<link/>', {
                    rel: 'stylesheet',
                    type: 'text/css',
                    href: 'https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.css'
                }),
                $('<style type="text/css">'
                  + '#toast-container {position: absolute;} '
                  + '#toast-container > div {opacity: 0.95;} '
                  + '.toast-top-center {top: 30px;} '
                  + '#wme_ech { display:flex; } '
                  + '.toolbar .toolbar-icon-eh { color: #484848; font-size: 24px; margin: 8px 0; position: relative; text-align: center; width: 24px; } '
                  + '.progress { background-color: red; animation-fill-mode:both; } '
                  + '@keyframes progressBar { 0% { width: 0; } 99% { background-color: red; } 100% { width: 100%; background-color: green; } } '
                  + '.days-group { width:100%; display:flex; justify-content:space-between; align-item:center; } '
                  + '.days-group div { width:30%; padding:5px; background-color:darkgray; color:white; display:flex; flex-direction:column; align-item:center; border-radius:5px; } '
                  + '.days-group div h3 { font-size:12px; font-weight:bold; line-height:1; margin:5px 0; } '
                  + '.days-group div span { font-size:14px; font-weight:bold; } '
                  + '.days-group .day-1 { background-color:#22577a; } '
                  + '.days-group .day-2 { background-color:#38a3a5; } '
                  + '.days-group .day-3 { background-color:#57cc99; } '
                  + '</style>')
            );
            await $.getScript(TOASTR_URL);

            toastr.options = {
                target: '#map',
                timeOut: 9999999999,
                positionClass: 'toast-top-right',
                closeOnHover: false,
                closeDuration: 0,
                showDuration: 0,
                closeButton: true
            };

            W.model.actionManager.events.register('afterclearactions', null, () => errorHandler(checkCounters));
            W.model.actionManager.events.register('afteraction', null, () => errorHandler(checkChangedObjectCount));
            W.model.actionManager.events.register('afterundoaction', null, () => errorHandler(checkChangedObjectCount));
        
            checkCounters();
            toastr.success('Inicializado!', 'WME Edition Counter And Helper', {timeOut: 1500});
            log('Initialized!', 0, 'SUCCESS', 'green');
            //toastr.warning('<span style="font-size:16px;">Has editado al menos <b>' + _toastrSettings.remindAtEditCount + '</b> objetos.</span><br><br> Deberías considerar guardar pronto.', 'WME Edition Counter And Helper:', {timeOut: 1000});
            
            // add new box to left of the map
            let navTabs = getElementsByClassName('nav-tabs', userTabs)[0];
            let tabContent = getElementsByClassName('tab-content', userTabs)[0];
            let addon = document.createElement('section');
            addon.id = "edition-helper-addon";

            // advanced options
            let section = document.createElement('p');
            section.style.paddingTop = "0px";
            section.className = 'checkbox';
            section.id = 'advancedOptions';
            section.innerHTML = '<h4><span class="fa fa-pencil" title="WME Edition Counter And Helper"></span> WME Edition Counter And Helper</h4><div style="margin:5px 0 10px 0;"><b>Configuración</b></div>'
                + '<label for="_ehSavingWaitTime">Tiempo de espera para guardar</label><br>'
                + '<input type="number" min="1" max="3600" size="4" id="_ehSavingWaitTime" style="margin: 0 0 20px 0" /> segundos'
                + '<br>'
                + '<label for="_ehRememberAfter">Recomendar guardar despues de</label><br>'
                + '<input type="number" min="1" max="5000" size="4" id="_ehRememberAfter" style="margin: 0 0 20px 0" /> cambios'
                + '<br>'
                + '<label for="_ehAlertAfter">Alertar guardar despues de</label><br>'
                + '<input type="number" min="1" max="5000" size="4" id="_ehAlertAfter" style="margin: 0 0 20px 0" /> cambios'
            ;
            addon.appendChild(section);

            // Addon legal and credits
            addon.innerHTML += '<hr style="border:0 none; border-bottom:1px #ccc solid;">'
                + '<small><b><a href="https://greasyfork.org/en/scripts/434355-wme-edition-helper" target="_blank"><u>'
                + 'WME Edition Counter And Helper</u></a></b> &nbsp; v' + VERSION + '</small>';

            // Add tab button and panel content
            let newtab = document.createElement('li');
            newtab.innerHTML = '<a href="#sidepanel-edition-helper" data-toggle="tab"><span class="fa fa-pencil" title="WME Edition Counter And Helper"></span> WME ECH</a>';
            navTabs.appendChild(newtab);

            addon.id = "sidepanel-edition-helper";
            addon.className = "tab-pane";
            tabContent.appendChild(addon);

            getId('_ehSavingWaitTime').onchange = updateAddonSettings;
            getId('_ehRememberAfter').onchange = updateAddonSettings;
            getId('_ehAlertAfter').onchange = updateAddonSettings;

            // restore saved settings
            if (localStorage.WMEEditionHelperScript) {
                let options = JSON.parse(localStorage.WMEEditionHelperScript);

                getId('_ehSavingWaitTime').value = options[1];
                getId('_ehRememberAfter').value = options[2];
                getId('_ehAlertAfter').value = options[3];
            }

            // overload the WME exit function
            const saveEditionHelperOptions = function() {
                if (localStorage) {
                    let options = [];

                    // preserve previous options which may get lost after logout
                    if (localStorage.WMEEditionHelperScript) {
                        options = JSON.parse(localStorage.WMEEditionHelperScript);
                    }

                    options[1] = getId('_ehSavingWaitTime').value;
                    options[2] = getId('_ehRememberAfter').value;
                    options[3] = getId('_ehAlertAfter').value;

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

            window.addEventListener("beforeunload", saveEditionHelperOptions, false);
        }

        function bootstrap() {
            if (W && W.loginManager && W.loginManager.events && W.loginManager.events.register && W.map && W.loginManager.user) {
                log('Initializing...');
                init();
            } else {
                log('Bootstrap failed. Trying again...');
                setTimeout(bootstrap, 1000);
            }
        }

        bootstrap();
    }

    function getEditCountFromProfile(profile) {
        const { editingActivity } = profile;
        return editingActivity[editingActivity.length - 1];
    }

    function getEditCountByDayFromProfile(profile, day) {
        const { editingActivity } = profile;
        return editingActivity[editingActivity.length-day];
    }

    function receivePageMessage(event) {
        let _msg;
        try {
            _msg = JSON.parse(event.data);
        } catch (err) {
            // Do Nothing
        }

        if (_msg && _msg[0] === 'wme_echGetCounts') {
            const userName = _msg[1];
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://www.waze.com/Descartes/app/UserProfile/Profile?username=${userName}`,
                onload: res => {
                    const profile = JSON.parse(res.responseText);
                    window.postMessage(JSON.stringify(['wme_echUpdateCounts', [
                        getEditCountFromProfile(profile),
                        getEditCountByDayFromProfile(profile, 2),
                        getEditCountByDayFromProfile(profile, 3)
                    ]]), '*');
                }
            });
        }
    }

    function waitForWazeWrap() {
        return new Promise(resolve => {
            function loopCheck(tries = 0) {
                if (WazeWrap.Ready) {
                    resolve();
                } else if (tries < 1000) {
                    setTimeout(loopCheck, 200, ++tries);
                }
            }
            loopCheck();
        });
    }

    function injectScript() {
        GM_addElement('script', {
            textContent: `${wmeECHInjected.toString()} \nwmeECHInjected();`
        });

        window.addEventListener('message', receivePageMessage);
    }

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

    function startFunction() {
        injectScript();
        loadScriptUpdateMonitor();
    }

    startFunction();
})();