Waze Edit Count Monitor

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

  1. // ==UserScript==
  2. // @name Waze Edit Count Monitor
  3. // @namespace https://greatest.deepsurf.us/en/users/45389-mapomatic
  4. // @version 2024.10.28.000
  5. // @description Displays your daily edit count in the WME toolbar. Warns if you might be throttled.
  6. // @author MapOMatic
  7. // @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
  8. // @require https://greatest.deepsurf.us/scripts/24851-wazewrap/code/WazeWrap.js
  9. // @require https://update.greatest.deepsurf.us/scripts/509664/WME%20Utils%20-%20Bootstrap.js
  10. // @license GNU GPLv3
  11. // @contributionURL https://github.com/WazeDev/Thank-The-Authors
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_addElement
  14. // @grant GM_addStyle
  15. // @connect www.waze.com
  16. // @connect greatest.deepsurf.us
  17. // ==/UserScript==
  18.  
  19. /* global bootstrap */
  20.  
  21. (async function main() {
  22. 'use strict';
  23.  
  24. const downloadUrl = 'https://greatest.deepsurf.us/scripts/40313-waze-edit-count-monitor/code/Waze%20Edit%20Count%20Monitor.user.js';
  25. const sdk = await bootstrap({ scriptUpdateMonitor: { downloadUrl } });
  26.  
  27. const TOOLTIP_TEXT = 'Your daily edit count from your profile. Click to open your profile.';
  28.  
  29. let $outputElem = null;
  30. let $outputElemContainer = null;
  31. let userName;
  32. let savesWithoutIncrease = 0;
  33. let lastProfile;
  34.  
  35. function log(message) {
  36. console.log('Edit Count Monitor:', message);
  37. }
  38.  
  39. function updateEditCount() {
  40. sdk.DataModel.Users.getUserProfile({ userName }).then(profile => {
  41. // Add the counter div if it doesn't exist.
  42. if ($('#wecm-count').length === 0) {
  43. $outputElemContainer = $('<div>', { class: 'toolbar-button', style: 'font-weight: bold; font-size: 16px; border-radius: 10px; margin-left: 4px;' });
  44. const $innerDiv = $('<div>', { class: 'item-container', style: 'padding-left: 10px; padding-right: 10px; cursor: default;' });
  45. $outputElem = $('<a>', {
  46. id: 'wecm-count',
  47. href: sdk.DataModel.Users.getUserProfileLink({ userName }),
  48. target: '_blank',
  49. style: 'text-decoration:none',
  50. 'data-original-title': TOOLTIP_TEXT
  51. });
  52. $innerDiv.append($outputElem);
  53. $outputElemContainer.append($innerDiv);
  54. if ($('#toolbar > div > div.secondary-toolbar > div.secondary-toolbar-actions > div.secondary-toolbar-actions-edit').length) {
  55. // Production WME, as of 4/25/2023
  56. $('#toolbar > div > div.secondary-toolbar > div.secondary-toolbar-actions > div.secondary-toolbar-actions-edit').after($outputElemContainer);
  57. } else {
  58. // Beta WME, as of 4/25/2023
  59. $('#toolbar > div > div.secondary-toolbar > div:nth-child(1)').after($outputElemContainer);
  60. }
  61. $outputElem.tooltip({
  62. placement: 'auto top',
  63. delay: { show: 100, hide: 100 },
  64. html: true,
  65. template: '<div class="tooltip wecm-tooltip" role="tooltip"><div class="tooltip-arrow"></div>'
  66. + '<div class="wecm-tooltip-header"><b></b></div>'
  67. + '<div class="wecm-tooltip-body tooltip-inner""></div></div>'
  68. });
  69. }
  70.  
  71. // log('edit count = ' + editCount + ', UR count = ' + urCount.count);
  72. // TODO: check all editCountByType values here?
  73. if (!lastProfile) {
  74. lastProfile = profile;
  75. } else if (lastProfile.dailyEditCount[lastProfile.dailyEditCount.length - 1] !== profile.dailyEditCount[profile.dailyEditCount.length - 1]
  76. || lastProfile.editCountByType.updateRequests !== profile.editCountByType.updateRequests
  77. || lastProfile.editCountByType.mapProblems !== profile.editCountByType.mapProblems
  78. || lastProfile.editCountByType.placeUpdateRequests !== profile.editCountByType.placeUpdateRequests
  79. || lastProfile.editCountByType.segmentHouseNumbers !== profile.editCountByType.segmentHouseNumbers
  80. || lastProfile.totalEditCount !== profile.totalEditCount) {
  81. savesWithoutIncrease = 0;
  82. } else {
  83. savesWithoutIncrease++;
  84. }
  85.  
  86. let textColor;
  87. let bgColor;
  88. let warningStyleClass;
  89. if (savesWithoutIncrease < 5) {
  90. textColor = '#354148';
  91. bgColor = 'white';
  92. warningStyleClass = '';
  93. } else if (savesWithoutIncrease < 10) {
  94. textColor = '#354148';
  95. bgColor = 'yellow';
  96. warningStyleClass = 'yellow';
  97. } else {
  98. textColor = 'white';
  99. bgColor = 'red';
  100. warningStyleClass = 'red';
  101. }
  102. $outputElemContainer.css('background-color', bgColor);
  103.  
  104. $outputElem.css('color', textColor).html(profile.dailyEditCount[profile.dailyEditCount.length - 1].toLocaleString());
  105. const totalEditCountText = `<li>Total&nbsp;edits:&nbsp;${profile.totalEditCount.toLocaleString()}</li>`;
  106. const urCountText = `<li>URs&nbsp;closed:&nbsp;${profile.editCountByType.updateRequests.toLocaleString()}</li>`;
  107. const purCountText = `<li>PURs&nbsp;closed:&nbsp;${profile.editCountByType.placeUpdateRequests.toLocaleString()}</li>`;
  108. const mpCountText = `<li>MPs&nbsp;closed:&nbsp;${profile.editCountByType.mapProblems.toLocaleString()}</li>`;
  109. const segmentEditCountText = `<li>Segment&nbsp;edits:&nbsp;${profile.editCountByType.segments.toLocaleString()}</li>`;
  110. const placeEditCountText = `<li>Place&nbsp;edits:&nbsp;${profile.editCountByType.venues.toLocaleString()}</li>`;
  111. const hnEditCountText = `<li>Segment&nbsp;HN&nbsp;edits:&nbsp;${profile.editCountByType.segmentHouseNumbers.toLocaleString()}</li>`;
  112. let warningText = '';
  113. if (savesWithoutIncrease) {
  114. warningText = `<div class="wecm-warning ${warningStyleClass}">${savesWithoutIncrease} ${
  115. (savesWithoutIncrease > 1) ? 'consecutive saves' : 'save'} without an increase. ${
  116. (savesWithoutIncrease >= 5) ? '(Are you throttled?)' : ''}</div>`;
  117. }
  118. $outputElem.attr('data-original-title', `${
  119. TOOLTIP_TEXT}<ul>${
  120. totalEditCountText}${
  121. urCountText}${
  122. purCountText}${
  123. mpCountText}${
  124. segmentEditCountText}${
  125. hnEditCountText}${
  126. placeEditCountText}</ul>${
  127. warningText}`);
  128. lastProfile = profile;
  129. });
  130. }
  131.  
  132. async function init() {
  133. userName = sdk.State.getUserInfo().userName;
  134.  
  135. GM_addStyle(`
  136. .wecm-tooltip li {text-align: left;}
  137. .wecm-tooltip .wecm-warning {border-radius:8px; padding:3px; margin-top:8px; margin-bottom:5px;}
  138. .wecm-tooltip .wecm-warning.yellow {background-color:yellow; color:black;}
  139. .wecm-tooltip .wecm-warning.red {background-color:red; color:white;}
  140. `);
  141.  
  142. sdk.Events.on({ eventName: 'wme-save-finished', eventHandler: onSaveFinished });
  143. // Update the edit count first time.
  144. updateEditCount();
  145. log('Initialized.');
  146. }
  147.  
  148. function onSaveFinished(result) {
  149. if (result.success) updateEditCount();
  150. }
  151.  
  152. init();
  153. })();