Greasy Fork 支持简体中文。

Waze Editor Profile Enhancements

Pulls the correct forum post count - changed to red to signify the value as pulled from the forum by the script & more!

  1. // ==UserScript==
  2. // @name Waze Editor Profile Enhancements
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024.01.04.01
  5. // @description Pulls the correct forum post count - changed to red to signify the value as pulled from the forum by the script & more!
  6. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAUCAYAAACXtf2DAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAADQklEQVRIS92VS0wTQRjHq+IrvmKiB8VEbxK9aIweNMZEEi/Gkxq6u4UCKjEEiQajMRobE7DdbrvS8DCF3Z3ty8oqiGAw4KMKxKpBxUcEORTF+EZFRQjPz5llbVqo0nj0n/wzO535ft/szDdbXbwyAUylrWgNxUk5NCsdpTm0h7LLGw446mZqUyYXAEwxmUwJWleVgXPPoTnZTrHoG2WRvutZsRc/DzJWuZ/h0A+c7Attk7MURZmmhcTWbjzBYJE2ptnlRO0nnRGhWZRV7KdYqQ8b/mgr+omTfsxwKIu10IliWGElZS7fkckK80gyhpU249XhwBjAGNaz0ihpIxcYFtkaxipso1hxS5bFuYCyoSQ8+UckIG5bURfj8MzX0GOizaULDZy0dZ/DtUXPCksZKzqO93ooJmAS06w4jAshW0OPibGULUvLlxNzCtHNPLGqAVcLPsjYgHisZ9Frk6LM0PA6XUaBuJiy+RaRM8gu9ifjrVL389+NRkibyVbPUxNkFytzqQJnEklAm+V1EwPI4bkgnXerbaxxYjKWccYDeAfUBZISVxPg2p/KFJRtZk5L62nOuxzX+/D4YOKq4BPwNz4E4VoQztY1gaP2FhTV3obSq00gNATVsZr7zwCf4eAhRZmtwolIFenNwtosp3M6qeUosBWpbTUO7OzuCftMTQBaQm/C/aevPwBXeR2a20KQWejt1NAThV9vUyrnGiTQdN4FB8svwoMI0G9X3n0Cz998Cvc73n+GiuZWQDfuDRh5t0/DRWt/sT+VgK897hhpf9sdBYzHra/egpF39abx8moNGa1UTu464antf/EuGh6KeB7v0Kevatvc9lLdSgzfpeEmyhQIJODXK9nr8H0vrw8O+W4/gL0OL16VG843PYoCN7Z3QnbJeVwpMhxz1YwY7a6fBhtiNNTfZbBJG402TxFe0fApfx3w1QFcetKoyXulJ0+41JdfUf8Nl+PQYbEKyuvvqCtneLRdC49f+GPXkuu8AEekSwTSg/sp+H8gFyejKYvYmFV0Dk56r5CxAYb3LNHCJhe5IAwnrqLMwk69RbxOYCk2KYVcSFLSRjNawbAoGd+Xyxge1FtQLvncaOH/lXS6Xw40MXnm6lDsAAAAAElFTkSuQmCC
  7. // @author JustinS83
  8. // @include https://www.waze.com/*user/editor*
  9. // @include https://beta.waze.com/*user/editor*
  10. // @contributionURL https://github.com/WazeDev/Thank-The-Authors
  11. // @run-at document-start
  12. // ==/UserScript==
  13.  
  14. /* global W */
  15. /* global OL */
  16. /* global $ */
  17. /* global I18n */
  18. /* global _ */
  19. /* global WazeWrap */
  20. /* global require */
  21. /* eslint curly: ["warn", "multi-or-nest"] */
  22.  
  23. (function() {
  24. 'use strict';
  25. var gon = {"data":""};
  26. var settings = {};
  27. var nawkts, rowwkts, ilwkts = [];
  28. var combinedNAWKT, combinedROWWKT, combinedILWKT= "";
  29. var naMA, rowMA, ilMA;
  30. var lastEditEnv;
  31. const reducer = (accumulator, currentValue) => accumulator + currentValue;
  32. const delay = ms => new Promise(res => setTimeout(res, ms));
  33.  
  34. loadSettings();
  35.  
  36. function getApiUrlUserProfile(username, env) {
  37. let apiEnv = '';
  38. if (env != 'na')
  39. apiEnv = env + '-';
  40. return `https://${window.location.host}/${apiEnv}Descartes/app/UserProfile/Profile?username=${username}`;
  41. }
  42.  
  43. async function bootstrap(tries = 1) {
  44. console.log('WEPE: ' + tries);
  45. if (typeof W !== 'undefined' && typeof W.EditorProfile !== 'undefined' && typeof W.EditorProfile.data !== 'undefined' && $){
  46. await delay(2000);
  47. init();
  48. }
  49.  
  50. else if (tries < 1000)
  51. setTimeout(function () {bootstrap(++tries);}, 200);
  52. }
  53.  
  54. bootstrap();
  55.  
  56. async function init(){
  57. lastEditEnv = W.EditorProfile.data.lastEditEnv;
  58. if (typeof settings.Environment != 'undefined'
  59. && settings.Environment != 'default'
  60. && settings.Environment != gon.data.lastEditEnv) {
  61. let apiUrl = getApiUrlUserProfile(gon.data.username, settings.Environment);
  62.  
  63. // synchronous XMLHttpRequest required as we need to pause execution to replace window.gon object
  64. // The deprication warning in console is expected.
  65. var request = new XMLHttpRequest();
  66. request.open('GET', apiUrl, false); // 'false' makes the request synchronous
  67. request.send(null);
  68.  
  69. if (request.status === 200)
  70. gon.data = JSON.parse(request.responseText);
  71. gon.data.lastEditEnv = settings.Environment;
  72. }
  73.  
  74. $('body').append('<span id="ruler" style="visibility:hidden; white-space:nowrap;"></span>');
  75. //injectCSS();
  76. String.prototype.visualLength = function(){ //measures the visual length of a string so we can better center the area labels on the areas
  77. var ruler = $("#ruler");
  78. ruler[0].innerHTML = this;
  79. return ruler[0].offsetWidth;
  80. }
  81. $.get('https://www.waze.com/forum/memberlist.php?username=' + W.EditorProfile.data.username, function(forumResult){
  82. var re = 0;
  83. var matches = forumResult.match(/<a href=".*?"\s*?title="Search user’s posts">(\d+)<\/a>/);
  84. if(matches && matches.length > 0)
  85. re = matches[1];
  86. var WazeVal = $('.posts').parent().next()[0].innerHTML.trim();
  87. var userForumID = forumResult.match(/<a href="\.\/memberlist\.php\?mode=viewprofile&amp;u=(\d+)"/);
  88. if(userForumID != null){
  89. userForumID = userForumID[1];
  90. $('.posts').parent().css('position', 'relative');
  91.  
  92. if(WazeVal !== re.toString()){
  93. $('.posts').parent().next()[0].innerHTML = re;
  94. $('.posts').parent().next().css('color','red');
  95. $('.posts').parent().next().prop('title', 'Waze reported value: ' + WazeVal);
  96. }
  97.  
  98. $('.posts').parent().parent().wrap('<a href="https://www.waze.com/forum/search.php?author_id=' + userForumID + '&sr=posts" target="_blank"></a>');
  99.  
  100. $('#header > div > div.user-info > div > div.user-highlights').prepend('<a href="https://www.waze.com/forum/memberlist.php?mode=viewprofile&u=' + userForumID +'" target="_blank" style="margin-right:5px;" id="forumProfile" style="float: right;"><button class="s-modern-button s-modern" style="float: right;"><i class="fa fa-user"></i><span>Forum Profile</span></button></a>');
  101.  
  102. }
  103. });
  104.  
  105. var count = 0;
  106. W.EditorProfile.data.editingActivity.forEach(function(x) { if(x !== 0) count++; });
  107. $('#editing-activity > div > h3').append(" (" + count + " of last 91 days)");
  108.  
  109. await getManagedAreas();
  110. BuildManagedAreasWKTInterface();
  111. /************** Add Average & Total to Editing Activity ***********/
  112. AddEditingActivityAvgandTot();
  113. /************** Add Editor Stats Section **************/
  114. AddEditorStatsSection();
  115.  
  116. initEnvironmentChooser();
  117.  
  118. $('.user-stats-value').each(function(num){
  119. debugger;
  120. let num1 = Number($(this).text());
  121. if(!isNaN(num1))
  122. $(this).text(Number(num1).toLocaleString());
  123. })
  124.  
  125. $('.type-content__count > h3').each(function(num){
  126. $(this).text(Number($(this).text()).toLocaleString());
  127. })
  128. }
  129.  
  130. function initEnvironmentChooser(){
  131. let highlight = document.createElement('div');
  132. highlight.className="highlight";
  133. let highlightTitle = document.createElement('div');
  134. highlightTitle.className="highlight-title";
  135. let highlightTitleIcon = document.createElement('div');
  136. //highlightTitleIcon.className="highlight-title-icon posts";
  137. highlightTitleIcon.setAttribute('style',getIconStyle());
  138. let highlightTitleText = document.createElement('div');
  139. highlightTitleText.className="highlight-title-text";
  140. let userStatsValue = document.createElement('div');
  141. userStatsValue.className="user-stats-value";
  142.  
  143. highlightTitle.appendChild(highlightTitleIcon);
  144. highlightTitle.appendChild(highlightTitleText);
  145. highlight.appendChild(highlightTitle);
  146. highlight.appendChild(userStatsValue);
  147.  
  148. highlightTitleText.innerHTML = 'Environments';
  149. userStatsValue.setAttribute('style','margin-top: -10px;font-size: 17px;');
  150.  
  151. let frag = document.createDocumentFragment(),
  152. select = document.createElement("select");
  153. select.id = 'environmentSelect';
  154. select.name = 'environmentSelect';
  155. select.setAttribute('style','position:relative;box-shadow: 0 0 2px #57889C;background: white;font-family: sans-serif;display: inherit;top: -11px;border: 0px;outline: 0px;color: #59899e;');
  156.  
  157. select.options.add( new Option("Last Edit (" + lastEditEnv.toUpperCase() + ")","default", true, true) );
  158. select.options.add( new Option("NA","na") );
  159. select.options.add( new Option("ROW","row") );
  160. select.options.add( new Option("IL","il") );
  161.  
  162. for (var i = 0; i < select.options.length; i++) {
  163. if (select.options[i].value == settings.Environment)
  164. select.options[i].selected = true;
  165. }
  166.  
  167. frag.appendChild(select);
  168. document.getElementsByClassName('user-stats')[0].prepend(highlight);
  169. userStatsValue.appendChild(frag);
  170.  
  171. document.querySelector('select[name="environmentSelect"]').onchange = envChanged;
  172. }
  173.  
  174. function getIconStyle() {
  175. let tempQuerySelector = document.querySelector('#edits-by-type .venue-icon');
  176. let tempComputedStyle = window.getComputedStyle(tempQuerySelector);
  177. let iconStyle =
  178. `background-image:${tempComputedStyle.getPropertyValue('background-image')};`
  179. + `background-size:${tempComputedStyle.getPropertyValue('background-size')};`
  180. + `background-position:${tempComputedStyle.getPropertyValue('background-position')};`
  181. + `width:${tempComputedStyle.getPropertyValue('width')};`
  182. + `height:${tempComputedStyle.getPropertyValue('height')};`
  183. + `transform: scale(0.5);`
  184. + `display: inline-block;`
  185. + `float: left;`
  186. + `position: relative;`
  187. + `top: -10px;`
  188. + `left: -9px;`
  189. + `margin-right: -18px;`
  190. + `filter: invert(10%) sepia(39%) saturate(405%) hue-rotate(152deg) brightness(99%) contrast(86%);`;
  191. return iconStyle;
  192. }
  193.  
  194. function AddLabelsToAreas(){
  195. if($('svg.leaflet-zoom-animated').length > 0){
  196. $('svg.leaflet-zoom-animated g > text').remove();
  197. var svg = $('svg.leaflet-zoom-animated')[0];
  198. var pt = svg.createSVGPoint(), svgP;
  199.  
  200. let displayedAreas = $('svg.leaflet-zoom-animated g');
  201.  
  202. for(let i=0;i<displayedAreas.length;i++){
  203. let windowPosition = $(displayedAreas[i])[0].getBoundingClientRect();
  204. pt.x = (windowPosition.left + windowPosition.right) / 2;
  205. pt.y = (windowPosition.top + windowPosition.bottom) / 2;
  206. svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
  207.  
  208. if(svgP.x != 0 && svgP.y != 0){
  209. var newText = document.createElementNS("http://www.w3.org/2000/svg","text");
  210. newText.setAttributeNS(null,"x",svgP.x - (`Area ${i+1}`.visualLength() /2));
  211. newText.setAttributeNS(null,"y",svgP.y);
  212. newText.setAttributeNS(null, "fill", "red");
  213. newText.setAttributeNS(null,"font-size","12");
  214.  
  215. var textNode = document.createTextNode(`Area ${i+1}`);
  216. newText.appendChild(textNode);
  217. $(displayedAreas[i])[0].appendChild(newText);
  218. }
  219. }
  220. }
  221. }
  222.  
  223. function BuildManagedAreasWKTInterface(){
  224. if(naMA.managedAreas.length > 0 || rowMA.managedAreas.length > 0 || ilMA.managedAreas.length > 0){
  225. $('#header > div > div.user-info > div > div.user-highlights > div.user-stats').before('<a href="#" title="View editor\'s managed areas in WKT format"><button class="s-modern-button s-modern" id="userMA" style="float: right;"><i class="fa fa-map-o" aria-hidden="true"></i></button></a>');
  226.  
  227. /****** MO to update labels when panning/zooming the map ************/
  228. var observer = new MutationObserver(function(mutations) {
  229. mutations.forEach(function(mutation) {
  230. if ($(mutation.target).hasClass('leaflet-map-pane') && (mutation.attributeName === "class" || mutation.attributeName === "style")){
  231. if(mutation.attributeName === "class" && mutation.target.classList.length == 1) //zoom has ended, we can redraw our labels
  232. setTimeout(AddLabelsToAreas, 200);
  233. else if(mutation.attributeName === "style") //panning the map
  234. setTimeout(AddLabelsToAreas, 200);
  235. }
  236. });
  237. });
  238. observer.observe(document.getElementsByClassName('component-map-view')[0], { childList: true, subtree: true, attributes:true });
  239.  
  240. AddLabelsToAreas();
  241.  
  242. $('#userMA').click(function(){
  243. if($('#wpeWKT').css('visibility') === 'visible')
  244. $('#wpeWKT').css({'visibility': 'hidden'});
  245. else
  246. $('#wpeWKT').css({'visibility': 'visible'});
  247. });
  248.  
  249. var result = buildWKTArray(naMA);
  250. nawkts = result.wktArr;
  251. combinedNAWKT = result.combinedWKT;
  252.  
  253. result = buildWKTArray(rowMA);
  254. rowwkts = result.wktArr;
  255. combinedROWWKT = result.combinedWKT;
  256.  
  257. result = buildWKTArray(ilMA);
  258. ilwkts = result.wktArr;
  259. combinedILWKT = result.combinedWKT;
  260.  
  261. var $section = $("<div>", {style:"padding:8px 16px"});
  262. $section.html([
  263. '<div id="wpeWKT" style="padding:8px 16px; position:fixed; border-radius:10px; box-shadow:5px 5px 10px 4px Silver; top:25%; left:40%; background-color:white; visibility:hidden;">', //Main div
  264. '<div style="float:right; cursor:pointer;" id="wpeClose"><i class="fa fa-window-close" aria-hidden="true"></i></div>',
  265. '<ul class="nav nav-tabs">',
  266. `${naMA.managedAreas.length > 0 ? '<li class="active"><a data-toggle="pill" href="#naAreas">NA</a></li>' : ''}`,
  267. `${rowMA.managedAreas.length > 0 ? '<li><a data-toggle="pill" href="#rowAreas">ROW</a></li>' : ''}`,
  268. `${ilMA.managedAreas.length > 0 ? '<li><a data-toggle="pill" href="#ilAreas">IL</a></li>' : ''}`,
  269. '</ul>',
  270. '<div class="tab-content">',
  271. '<div id="naAreas" class="tab-pane fade in active">',
  272. '<div id="wpenaAreas" style="float:left; max-height:350px; overflow:auto;"><h3 style="float:left; left:50%;">Editor Areas</h3><br>' + buildAreaList(nawkts,"na") + '</div>',
  273. '<div id="wpenaPolygons" style="float:left; padding-left:15px;"><h3 style="position:relative; float:left; left:40%;">Area WKT</h3><br><textarea rows="7" cols="55" id="wpenaAreaWKT" style="height:auto;"></textarea></div>',
  274. '</div>',//naAreas
  275. '<div id="rowAreas" class="tab-pane fade">',
  276. '<div id="wperowAreas" style="float:left; max-height:350px; overflow:auto;"><h3 style="float:left; left:50%;">Editor Areas</h3><br>' + buildAreaList(rowwkts, "row") + '</div>',
  277. '<div id="wperowPolygons" style="float:left; padding-left:15px;"><h3 style="position:relative; float:left; left:40%;">Area WKT</h3><br><textarea rows="7" cols="55" id="wperowAreaWKT" style="height:auto;"></textarea></div>',
  278. '</div>',//rowAreas
  279. '<div id="ilAreas" class="tab-pane fade">',
  280. '<div id="wpeilAreas" style="float:left; max-height:350px; overflow:auto;"><h3 style="float:left; left:50%;">Editor Areas</h3><br>' + buildAreaList(ilwkts, "il") + '</div>',
  281. '<div id="wpeilPolygons" style="float:left; padding-left:15px;"><h3 style="position:relative; float:left; left:40%;">Area WKT</h3><br><textarea rows="7" cols="55" id="wpeilAreaWKT" style="height:auto;"></textarea></div>',
  282. '</div>',//ilAreas
  283. '<div id="wpeFooter" style="clear:both; margin-top:10px;">View the areas by entering the WKT at <a href="http://map.wazedev.com" target="_blank">http://map.wazedev.com</a></div>',
  284. '</div>', //tab-content
  285. '</div>' //end main div
  286. ].join(' '));
  287.  
  288. $('body').append($section.html());
  289.  
  290. $('[id^="wpenaAreaButton"]').click(function(){
  291. let index = parseInt($(this)[0].id.replace("wpenaAreaButton", ""));
  292. $('#wpenaAreaWKT').text(nawkts[index]);
  293. $('#wpenaPolygons > h3').text(`Area ${index+1} WKT`);
  294. });
  295.  
  296. $('[id^="wperowAreaButton"]').click(function(){
  297. let index = parseInt($(this)[0].id.replace("wperowAreaButton", ""));
  298. $('#wperowAreaWKT').text(rowwkts[index]);
  299. $('#wperowPolygons > h3').text(`Area ${index+1} WKT`);
  300. });
  301.  
  302. $('[id^="wpeilAreaButton"]').click(function(){
  303. let index = parseInt($(this)[0].id.replace("wpeilAreaButton", ""));
  304. $('#wpeilAreaWKT').text(ilwkts[index]);
  305. $('#wpeilPolygons > h3').text(`Area ${index+1} WKT`);
  306. });
  307.  
  308. $('#wpenaCombinedAreaButton').click(function(){
  309. $('#wpenaAreaWKT').text(combinedNAWKT);
  310. $('#wpenaPolygons > h3').text(`Combined Area WKT`);
  311. });
  312.  
  313. $('#wperowCombinedAreaButton').click(function(){
  314. $('#wperowAreaWKT').text(combinedROWWKT);
  315. $('#wperowPolygons > h3').text(`Combined Area WKT`);
  316. });
  317.  
  318. $('#wpeilCombinedAreaButton').click(function(){
  319. $('#wpeilAreaWKT').text(combinedILWKT);
  320. $('#wpeilPolygons > h3').text(`Combined Area WKT`);
  321. });
  322.  
  323. $('#wpeClose').click(function(){
  324. if($('#wpeWKT').css('visibility') === 'visible')
  325. $('#wpeWKT').css({'visibility': 'hidden'});
  326. else
  327. $('#wpeWKT').css({'visibility': 'visible'});
  328. });
  329. }
  330. }
  331.  
  332. function AddEditorStatsSection(){
  333. let edits = W.EditorProfile.data.edits
  334. let editActivity = [].concat(W.EditorProfile.data.editingActivity);
  335. let rank = W.EditorProfile.data.rank+1;
  336. let count = 0;
  337. editActivity.forEach(function(x) {if(x !== 0) count++; });
  338. let editAverageDailyActive = Math.round(editActivity.reduce(reducer)/count);
  339. let editAverageDaily = Math.round(editActivity.reduce(reducer)/91);
  340.  
  341. var $editorProgress = $("<div>");
  342. $editorProgress.html([
  343. `<div id="collapsible" style="display:${settings.EditingStatsExpanded ? "block" : "none"};">`,
  344. '<div style="display:inline-block;"><div><h4>Average Edits per Day</h4></div><div>' + editAverageDaily + '</div></div>',
  345. '<div style="display:inline-block; margin-left:25px;"><div><h4>Average Edits per Day (active days only)</h4></div><div>' + editAverageDailyActive + '</div></div>',
  346. '<div class="editor-progress-list" style="display:flex; flex-flow:row wrap; justify-content:space-around;">',
  347. buildProgressItemsHTML(),
  348. '</div>'
  349. ].join(' '));
  350.  
  351. $('#editing-activity').append('<div id="editor-progress"><h3 id="collapseHeader" style="cursor:pointer;">Editing Stats</h3></div>');
  352. $('#editor-progress').append($editorProgress.html()+'</div>');
  353.  
  354. $('#collapseHeader').click(function(){
  355. $('#collapsible').toggle();
  356. settings.EditingStatsExpanded = ($('#collapsible').css("display") === "block");
  357. saveSettings();
  358. });
  359. }
  360.  
  361. function buildProgressItemsHTML(){
  362. var itemsArr = [];
  363. var $items = $("<div>");
  364. let editActivity = W.EditorProfile.data.editingActivity;
  365.  
  366. //loop over the 13 tracked weeks on the profile
  367. for(let i=0; i<13; i++){
  368. let header = "";
  369. let weekEditCount = 0;
  370. //let weekEditPct = 0;
  371. if(i==0){
  372. header = "Past 7 days";
  373. weekEditCount = editActivity.slice(-7).reduce(reducer);
  374. }
  375. else{
  376. header = `Past ${i*7+1} - ${(i+1)*7} days`;
  377. weekEditCount = editActivity.slice(-((i+1)*7),-i*7).reduce(reducer);
  378. }
  379. let weekDailyAvg = Math.round(weekEditCount/7*100)/100;
  380. itemsArr.push('<div style="margin-right:20px;">');
  381. itemsArr.push(`<h4>${header}</h4>`);
  382. itemsArr.push('<div class="editor-progress-item">');
  383. itemsArr.push(`<div class="editor-progress__name">Week\'s Edits</div><div class="editor-progress__count">${weekEditCount}</div>`); //, ${weekEditPct}%</div>`);
  384. itemsArr.push(`<div class="editor-progress__name">Average Edits/Day</div><div class="editor-progress__count">${weekDailyAvg}</div>`);
  385. itemsArr.push('</div></div>');
  386. }
  387. $items.html(itemsArr.join(' '));
  388. return $items.html();
  389. }
  390.  
  391. function AddEditingActivityAvgandTot(){
  392. $('.legend').append('<div class="day-initial">Avg</div> <div class="day-initial">Tot</div>');
  393. $('.editing-activity').css({"width":"1010px"}); //With adding the Avg and Tot rows we have to widen the div a little so it doesn't wrap one of the columns
  394.  
  395. let currWeekday = new Date().getDay();
  396. if(currWeekday === 0)
  397. currWeekday = 7;
  398. let localEditActivity = [].concat(W.EditorProfile.data.editingActivity);
  399. let weekEditsArr = localEditActivity.splice(-currWeekday);
  400. let weekEditsCount = weekEditsArr.reduce(reducer);
  401. var iteratorStart = 13;
  402. if(currWeekday === 7)
  403. iteratorStart = 12;
  404. $(`.weeks div:nth-child(${iteratorStart+1}) .week`).append(`<div class="day" style="font-size:10px; height:10px; text-align:center; margin-top:-5px;" title="Average edits per day for this week">${Math.round(weekEditsCount/currWeekday * 100) / 100}</div><div style="font-size:10px; height:10px; text-align:center;" title="Total edits for this week">${weekEditsCount}</div>`);
  405. for(let i=iteratorStart; i>0; i--){
  406. weekEditsArr = localEditActivity.splice(-7);
  407. weekEditsCount = weekEditsArr.splice(-7).reduce(reducer);
  408. let avg = Math.round(weekEditsCount/7 * 100) / 100;
  409. $(`.weeks div:nth-child(${i}) .week`).append(`<div class="day" style="font-size:10px; height:10px; text-align:center; margin-top:-5px;" title="Average edits per day for this week">${avg}</div><div style="font-size:10px; height:10px; text-align:center;" title="Total edits for this week">${weekEditsCount}</div>`);
  410. }
  411. }
  412.  
  413. function buildAreaList(wkts, server){
  414. let html = "";
  415. for(let i=0; i<wkts.length; i++){
  416. html +=`<button id="wpe${server}AreaButton${i}" class="s-button s-button--mercury " style="margin-bottom:5px;">Area ${i+1}</button><br>`;
  417. }
  418. if(wkts.length > 1)
  419. html +=`<button id="wpe${server}CombinedAreaButton" class="s-button s-button--mercury " style="margin-bottom:5px;">Combined</button><br>`;
  420. return html;
  421. }
  422.  
  423. function buildWKTArray(wktObj){
  424. let wkt = "";
  425. let combined = "";
  426. let wktArr = [];
  427. for(let i=0; i<wktObj.managedAreas.length; i++){
  428. if(i>0)
  429. combined += ",";
  430. wkt = "";
  431. combined += "(";
  432. for(let j=0; j<wktObj.managedAreas[i].coordinates.length; j++){
  433. if(j>0){
  434. wkt += ",";
  435. combined += ",";
  436. }
  437. combined += "(";
  438. wkt +="(";
  439. for(let k=0; k<wktObj.managedAreas[i].coordinates[j].length; k++){
  440. if(k > 0){
  441. wkt+=", ";
  442. combined += ",";
  443. }
  444. wkt += round(parseFloat(wktObj.managedAreas[i].coordinates[j][k][0])).toString() + " " + round(parseFloat(wktObj.managedAreas[i].coordinates[j][k][1])).toString();
  445. combined += round(parseFloat(wktObj.managedAreas[i].coordinates[j][k][0])).toString() + " " + round(parseFloat(wktObj.managedAreas[i].coordinates[j][k][1])).toString();
  446. }
  447. combined += ")";
  448. wkt += ")";
  449. }
  450. combined += ")";
  451. wkt = `POLYGON${wkt}`;
  452. wktArr.push(wkt);
  453. }
  454. if(wktObj.managedAreas.length > 1)
  455. combined = `MULTIPOLYGON(${combined})` ;
  456. else
  457. combined = `POLYGON${combined}`;
  458.  
  459. return {wktArr: wktArr, combinedWKT: combined};
  460. }
  461.  
  462. function round(val){
  463. return Math.round(val*1000000)/1000000;
  464. }
  465.  
  466. async function getManagedAreas(){
  467. naMA = await $.get(`https://www.waze.com/Descartes/app/UserProfile/Areas?userID=${W.EditorProfile.data.userID}`);
  468. rowMA = await $.get(`https://www.waze.com/row-Descartes/app/UserProfile/Areas?userID=${W.EditorProfile.data.userID}`);
  469. ilMA = await $.get(`https://www.waze.com/il-Descartes/app/UserProfile/Areas?userID=${W.EditorProfile.data.userID}`);
  470.  
  471. /*return await new W.EditorProfile.Models.ManagedAreas([],{
  472. lastEditEnv: 'na',
  473. userId: W.EditorProfile.data.userID
  474. }).fetch();*/
  475. }
  476.  
  477. function envChanged(e) {
  478. settings.Environment = e.target.value;
  479. saveSettings();
  480. location.reload();
  481. }
  482.  
  483. function injectCSS() {
  484. /*var css = [
  485. ].join(' ');
  486. $('<style type="text/css">' + css + '</style>').appendTo('head');*/
  487. }
  488.  
  489. function loadSettings() {
  490. var loadedSettings = JSON.parse(localStorage.getItem("WEPE_Settings"));
  491. var defaultSettings = {
  492. EditingStatsExpanded: true,
  493. Environment: 'default'
  494. };
  495. settings = loadedSettings ? loadedSettings : defaultSettings;
  496. for (var prop in defaultSettings) {
  497. if (!settings.hasOwnProperty(prop))
  498. settings[prop] = defaultSettings[prop];
  499. }
  500. }
  501.  
  502. function saveSettings() {
  503. if (localStorage) {
  504. var localsettings = {
  505. EditingStatsExpanded: settings.EditingStatsExpanded,
  506. Environment: settings.Environment
  507. };
  508.  
  509. localStorage.setItem("WEPE_Settings", JSON.stringify(localsettings));
  510. }
  511. }
  512. })();