// ==UserScript==
// @name WME Edition Helper
// @name:es WME Ayudante de edición
// @description Monitor editions count and shows a timer for next suggested save action
// @description:es Monitorea el contador de ediciones y muestra un temporizador para la siguiente acción de guardado sugerida
// @author EdwardNavarro
// @namespace https://gf.qytechs.cn/en/users/670818-edward-navarro
// @version 2021.10.22.01
// @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
// @icon https://www.edwardnavarro.com/cdn/wme/wme_eh_icon_32x32.svg
// @connect www.waze.com
// @grant GM_xmlhttpRequest
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// ==/UserScript==
/* global W */
/* global toastr */
/* global $ */
/* global GM_xmlhttpRequest */
/**
* ===============================================
* This script is based on the following scripts:
* - "Waze Edit Count Monitor" (by MapOMatic)
* - "Waze Edit & UR Count Monitor" (by Crotalo)
* ===============================================
*/
// This function is injected into the page to allow it to run in the page's context.
function wmeEH_Injected() {
'use strict';
let _toastr_settings = {
remindAtEditCount: 30,
warnAtEditCount: 45,
wasReminded: false,
wasWarned: false
};
let debugLevel = 0;
let userName = '';
let lastTodayEditCount = 0;
let lastYesterdayEditCount = 0;
let lastDayBeforeEditCount = 0;
let savesWithoutIncrease = 0;
let button_container, button_content_wrap, button_item_container, button_item_icon, button_item_link, button_item_content, progress_bar_wrap, progress_bar_fill;
let tooltipText = '<b>Ediciones Diarias</b><br><small>(Clic para ver el perfil)<small>';
function log(message, level, prefix = 'LOG', bgColor = 'darkslategrey', textColor = 'white') {
if (message && level <= debugLevel) {
console.log('%c%s%s', `background:${bgColor};color:${textColor};padding:5px 10px;`, `[${prefix}] WME Edition Helper >>`, message);
}
}
function checkEditCount() {
window.postMessage(JSON.stringify(['wmeEHGetCounts',userName]),'*');
_toastr_settings.wasReminded = false;
_toastr_settings.wasWarned = false;
toastr.remove();
}
function getChangedObjectCount() {
let count = W.changesLogController._changesLogViewModel.attributes.actionsCount;
return count;
}
function updateEditCount(todayEditCount = 0, yesterdayEditCount = 0, dayBeforeEditCount = 0, noIncrement) {
let textColor;
let bgColor;
let tooltipTextColor;
// Add the counter div if it doesn't exist.
if ($('#eh-button').length === 0) {
button_container = $('<div>', { id: 'eh-button' });
button_content_wrap = $('<div>', { class: 'toolbar-button toolbar-button-with-icon' });
button_item_link = $('<a>', { href: 'https://www.waze.com/user/editor/' + userName.toLowerCase(), target: '_blank', style:'text-decoration: none;', 'data-original-title': tooltipText });
button_item_container = $('<div>', { class: 'item-container' });
button_item_icon = $('<div>', { class: 'toolbar-icon-eh w-icon w-icon-pencil' });
button_item_content = $('<div>', { style: 'margin:5px 0 0 5px; line-height: 1;' });
progress_bar_wrap = $('<div>', { style: 'width: 100%; height: 5px; background-color: #d7dadc; border:1px #fff solid; box-sizing: content-box;' });
progress_bar_fill = $('<div>', { class: 'progress', style: 'width: 0%; height: 5px;' });
button_container.append(button_content_wrap);
button_content_wrap.append(button_item_link);
button_item_link.append(button_item_container);
button_item_container.append(button_item_icon);
button_item_container.append(button_item_content);
button_item_content.append(progress_bar_wrap);
progress_bar_wrap.append(progress_bar_fill);
$('#edit-buttons').prepend(button_container);
button_item_link.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>'
});
}
log(`EDIT COUNTS -> Today: ${todayEditCount}, Yesterday: ${yesterdayEditCount}, Day before: ${dayBeforeEditCount}`, 1, 'INFO', 'purple');
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';
}
button_container.css('background-color', bgColor);
button_item_icon.css('color', textColor);
button_item_content.css('color', textColor).html(`Ediciones: ${todayEditCount}`);
button_item_content.append(progress_bar_wrap);
let dayBeforeEditCountText = `<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>${yesterdayEditCount}</span></div><div class="day-3"><h3>Antier</h3><span>${dayBeforeEditCount}</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 estragulado?<span></div>` : '';
button_item_link.attr('data-original-title', tooltipText + dayBeforeEditCountText + warningText);
lastTodayEditCount = todayEditCount;
lastYesterdayEditCount = yesterdayEditCount;
lastDayBeforeEditCount = dayBeforeEditCount;
}
function receiveMessage(event) {
let msg;
try {
msg = JSON.parse(event.data);
} catch (err) {
// Do nothing
}
if (msg && msg[0] === 'wmeEHUpdateUi') {
let todayEditCount = msg[1][0];
let yesterdayEditCount = msg[1][1];
let dayBeforeEditCount = msg[1][2];
updateEditCount(todayEditCount, yesterdayEditCount, dayBeforeEditCount);
}
}
function checkChangedObjectCount() {
let objectEditCount = getChangedObjectCount();
if (objectEditCount >= _toastr_settings.warnAtEditCount && !_toastr_settings.wasWarned) {
toastr.remove();
toastr.error('<span style="font-size:16px;">Has editado al menos <b>' + _toastr_settings.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.', 'Edition Helper:', {timeOut: 25000});
_toastr_settings.wasWarned = true;
//log('WARMED', 0, 'ALERT', 'tomato')
} else if (objectEditCount >= _toastr_settings.remindAtEditCount && !_toastr_settings.wasReminded) {
toastr.remove();
toastr.warning('<span style="font-size:16px;">Has editado al menos <b>' + _toastr_settings.remindAtEditCount + '</b> objetos.</span><br><br> Deberías considerar guardar pronto.', 'Edition Helper:', {timeOut: 15000});
_toastr_settings.wasReminded = true;
//log('REMINDED', 0, 'ALERT', 'orange')
} else if (objectEditCount < _toastr_settings.remindAtEditCount) {
_toastr_settings.wasWarned = false;
_toastr_settings.wasReminded = false;
toastr.remove();
//log('REMOVED', 0, 'ALERT', 'sienna')
}
}
function errorHandler(callback) {
try {
callback();
} catch (e) {
console.error('%c%s%s', 'background:darkred;color:white;padding:5px 10px;', '[ERROR] WME Edition Helper >>', e);
}
}
function init() {
userName = W.loginManager.user.userName;
window.addEventListener('message', receiveMessage);
$('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;} \
#edit-buttons #eh-button { 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: progressBar 70s ease-in-out; 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:darkcyan; } \
.days-group .day-2 { background-color:darkgreen; } \
.days-group .day-3 { background-color:darkolivegreen; } \
</style>')
);
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.js', function() {
toastr.options = {
target:'#map',
showDuration: 300,
hideDuration: 1000,
timeOut: 10000,
extendedTimeOut: 1000,
positionClass: 'toast-top-right',
closeOnHover: false,
closeButton: true,
newestOnTop: true,
progressBar: true,
showEasing: 'swing',
hideEasing: 'linear',
showMethod: 'fadeIn',
hideMethod: 'fadeOut',
};
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();
toastr.success("Edition Helper Inicializado!");
log('Initialized!', 0, 'SUCCESS', 'green');
});
}
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, 'ERROR', 'darkred');
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) {
let match = source.match(/gon.data=({.*?});gon.env=/i);
return JSON.parse(match[1]);
}
function getEditCountFromProfile(profile) {
let 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;
}
function getEditCountByDayFromProfile(profile, day) {
let editingActivity = profile.editingActivity;
return editingActivity[editingActivity.length-day];
}
// Handle messages from the page.
function receiveMessage(event) {
let msg;
try {
msg = JSON.parse(event.data);
}
catch (err) {
// Ignore errors
}
if (msg && msg[0] === 'wmeEHGetCounts') {
let userName = msg[1];
GM_xmlhttpRequest({
method: 'GET',
url: `https://www.waze.com/user/editor/${userName}`,
onload: function(res) {
let profile = getEditorProfileFromSource(res.responseText);
window.postMessage(JSON.stringify(['wmeEHUpdateUi',[getEditCountFromProfile(profile), getEditCountByDayFromProfile(profile,2), getEditCountByDayFromProfile(profile,3)]]),'*');
}
});
}
}
let wmeEH_Injected_script = document.createElement('script');
wmeEH_Injected_script.textContent = '' + wmeEH_Injected.toString() + ' \nwmeEH_Injected();';
wmeEH_Injected_script.setAttribute('type', 'application/javascript');
document.body.appendChild(wmeEH_Injected_script);
// Listen for events coming from the page script.
window.addEventListener('message', receiveMessage);
})();