Greasy Fork is available in English.

Waze Edit Count Monitor

Displays your daily edit count in the WME toolbar. Warns if you might be throttled.

Fra og med 18.08.2018. Se den nyeste version.

// ==UserScript==
// @name            Waze Edit Count Monitor
// @namespace       https://greasyfork.org/en/users/45389-mapomatic
// @version         2018.08.18.001
// @description     Displays your daily edit count in the WME toolbar.  Warns if you might be throttled.
// @author          MapOMatic
// @include         /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
// @require         https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @license         GNU GPLv3
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// @grant           GM_xmlhttpRequest
// @connect         www.waze.com

// ==/UserScript==

/* global W */
/* global GM_info */
/* global toastr */

// This function is injected into the page to allow it to run in the page's context.
function WECM_Injected() {
    'use strict';

    let _toastrSettings = {
        remindAtEditCount: 100,
        warnAtEditCount: 150,
        wasReminded: false,
        wasWarned: false
    };

    var debugLevel = 0;
    var $outputElem = null;
    var $outputElemContainer = null;
    var lastEditCount = null;
    var userName = null;
    var savesWithoutIncrease = 0;
    var lastURCount = null;
    var lastMPCount = null;
    var tooltipText = 'Your daily edit count from your profile.  Click to open your profile.';

    function log(message, level) {
        if (message && level <= debugLevel) {
            console.log('Edit Count Monitor: ' + message);
        }
    }

    function checkEditCount() {
        window.postMessage(JSON.stringify(['wecmGetCounts',userName]),'*');
        _toastrSettings.wasReminded = false;
        _toastrSettings.wasWarned = false;
        toastr.remove();
    }

    function getChangedObjectCount() {
        let count = 0;
        let changed = W.model._getModifiedObjects();
        Object.keys(changed).forEach(key => {
            let obj = changed[key];
            count += obj.Insert.length + obj.Update.length + obj.Delete.length;
        });
        return count;
    }

    function updateEditCount(editCount, urCount, mpCount, noIncrement) {
        var textColor;
        var bgColor;
        var tooltipTextColor;

        // Add the counter div if it doesn't exist.
        if ($('#wecm-count').length === 0) {
            $outputElemContainer = $('<div>', {style:'position:relative; border-radius:23px; text-color:#354148; height:24px; padding-top:1px; padding-left:10px; padding-right:10px; display:block; float:right; margin-top:11px; font-weight:bold; font-size:medium;'});  //margin:9px 5px 8px 5px;  display:inline;
            $outputElem = $('<a>', {id: 'wecm-count',
                                    href:'https://www.waze.com/user/editor/' + userName.toLowerCase(),
                                    target: '_blank',
                                    style:'text-decoration:none',
                                    'data-original-title': tooltipText});
            $outputElemContainer.append($outputElem);
            $('#edit-buttons').children().first().append($outputElemContainer);
            $outputElem.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; font-weight:600; !important"></div></div>'
            });
        }

        log('edit count = ' + editCount + ', UR count = ' + urCount.count, 1);
        if (lastEditCount !== editCount || lastURCount.count !== urCount.count || lastMPCount !== mpCount.count) {
            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';
        }
        $outputElemContainer.css('background-color', bgColor);
        $outputElem.css('color', textColor).html(editCount);
        var urCountText = '<div style="margin-top:8px;padding:3px;">UR\'s&nbsp;Closed:&nbsp;' + urCount.count + '&nbsp;&nbsp;(since&nbsp;' + (new Date(urCount.since)).toLocaleDateString() + ')</div>';
        var mpCountText = '<div style="margin-top:0px;padding:0px 3px;">MP\'s&nbsp;Closed:&nbsp;' + mpCount.count + '&nbsp;&nbsp;(since&nbsp;' + (new Date(mpCount.since)).toLocaleDateString() + ')</div>';
        var warningText = (savesWithoutIncrease > 0) ? '<div style="border-radius:8px;padding:3px;margin-top:8px;margin-bottom:5px;color:' + tooltipTextColor + ';background-color:' + bgColor + ';">' + savesWithoutIncrease + ' consecutive saves without an increase. (Are you throttled?)</div>' : '';
        $outputElem.attr('data-original-title', tooltipText + urCountText + mpCountText + warningText);
        lastEditCount = editCount;
        lastURCount = urCount;
    }

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

        if (msg && msg[0] === 'wecmUpdateUi') {
            var editCount = msg[1][0];
            var urCount = msg[1][1];
            var mpCount = msg[1][2];
            updateEditCount(editCount, urCount, mpCount);
        }
    }

    function checkChangedObjectCount() {
        let objectEditCount = getChangedObjectCount();
        if (objectEditCount >= _toastrSettings.warnAtEditCount && !_toastrSettings.wasWarned) {
            toastr.remove();
            toastr.warning('You have edited at least ' + _toastrSettings.warnAtEditCount + ' objects. You should consider saving soon. ' +
                           'If you get an error while saving, you may need to undo some actions and try again.', 'Reminder from Edit Count Monitor:');
            _toastrSettings.wasWarned = true;
            //_toastrSettings.wasReminded = true;
        } else if (objectEditCount >= _toastrSettings.remindAtEditCount && !_toastrSettings.wasReminded) {
            toastr.remove();
            toastr.info('You have edited at least ' + _toastrSettings.remindAtEditCount + ' objects. You should consider saving soon.', 'Reminder from Edit Count Monitor:');
            _toastrSettings.wasReminded = true;
        } else if (objectEditCount < _toastrSettings.remindAtEditCount) {
            _toastrSettings.wasWarned = false;
            _toastrSettings.wasReminded = false;
            toastr.remove();
        }
    }

    function errorHandler(callback) {
        try {
            callback();
        } catch (ex) {
            console.error('Waze Edit Count Monitor:', ex);
        }
    }

    function init() {
        userName = W.loginManager.user.userName;
        // Listen for events from sandboxed code.
        window.addEventListener('message', receiveMessage);
        // Listen for Save events.

        $('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;}</style>')
        );
        $.getScript('https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.js', function() {
            toastr.options = {
                target:'#map',
                timeOut: 9999999999,
                positionClass: 'toast-top-right',
                closeOnHover: false,
                closeDuration: 0,
                showDuration: 0,
                closeButton: true
                //preventDuplicates: true
            };
            W.model.actionManager.events.register('afterclearactions', null, () => errorHandler(checkEditCount));
            W.model.actionManager.events.register('afteraction', null, () => errorHandler(checkChangedObjectCount));
            W.model.actionManager.events.register('afterundoaction', null, () => errorHandler(checkChangedObjectCount));

            // Update the edit count first time.
            checkEditCount();
            log('Initialized.',0);
        });
    }

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

    bootstrap();
}


// Code that is NOT injected into the page.
// Note that jQuery may or may not be available, so don't rely on it in this part of the script.
(function(){
    'use strict';

    function getEditorProfileFromSource(source) {
        var match = source.match(/gon.data=({.*?});gon.env=/i);
        return JSON.parse(match[1]);
    }

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

    function getEditCountByTypeFromProfile(profile, type) {
        let edits = profile.editsByType.find(edits => edits.key === type);
        return edits ? edits.value : -1;
    }

    // Handle messages from the page.
    function receiveMessage(event) {
        var msg;
        try {
            msg = JSON.parse(event.data);
        }
        catch (err) {
            // Ignore errors
        }

        if (msg && msg[0] === 'wecmGetCounts') {
            var userName = msg[1];
            GM_xmlhttpRequest({
                method: 'GET',
                url: 'https://www.waze.com/user/editor/' + userName,
                onload: function(res) {
                    var profile = getEditorProfileFromSource(res.responseText);
                    window.postMessage(JSON.stringify(['wecmUpdateUi',[getEditCountFromProfile(profile), getEditCountByTypeFromProfile(profile,'mapUpdateRequest'), getEditCountByTypeFromProfile(profile,'machineMapProblem')]]),'*');
                }
            });
        }
    }


    var WECM_Injected_script = document.createElement('script');
    WECM_Injected_script.textContent = '' + WECM_Injected.toString() + ' \nWECM_Injected();';
    WECM_Injected_script.setAttribute('type', 'application/javascript');
    document.body.appendChild(WECM_Injected_script);

    // Listen for events coming from the page script.
    window.addEventListener('message', receiveMessage);
})();