LiveMap UR Overlay

Overlays UR, MP and PU markers onto Livemap

  1. // ==UserScript==
  2. // @name LiveMap UR Overlay
  3. // @namespace http://greasemonkey.chizzum.com
  4. // @description Overlays UR, MP and PU markers onto Livemap
  5. // @include https://*.waze.com/*live-map*
  6. // @include http://*.waze.com/*live-map*
  7. // @grant none
  8. // @version 3.3
  9. // ==/UserScript==
  10.  
  11. /*
  12. To-do list:
  13.  
  14. - Adaptive block sizes to deal with 500 UR limit
  15. - WME links in popup - in progress as click on marker (check PUR positioning vs WME?)
  16. - display UR comments
  17. - store marker data in separate arrays for each request area.
  18.  
  19. */
  20.  
  21. /* JSHint Directives */
  22. /* globals L: true */
  23. /* jshint bitwise: false */
  24. /* jshint eqnull: true */
  25. /* jshint esversion: 8 */
  26.  
  27. var lmurVersion = '3.3';
  28.  
  29. var lmurShowDebugOutput = false;
  30. var lmurShowTraceOutput = false;
  31.  
  32. var lmurClearStartupCrud = true;
  33.  
  34. const T_MARKER =
  35. {
  36. UR: 0,
  37. MP: 1,
  38. MP200: 2,
  39. PUR: 3,
  40. };
  41. var MARKER_FCOL =
  42. [
  43. 'red',
  44. 'green',
  45. 'blue',
  46. 'yellow'
  47. ];
  48. var MARKER_SCOL =
  49. [
  50. 'blue',
  51. 'red',
  52. 'red',
  53. 'black'
  54. ];
  55. const T_RESOLVED =
  56. {
  57. FCOL: 'white',
  58. SCOL: 'black'
  59. };
  60.  
  61. var lmurVPLeft = null;
  62. var lmurVPRight = null;
  63. var lmurVPTop = null;
  64. var lmurVPBottom = null;
  65.  
  66. var lmurMarkers = [];
  67. var lmurCachedURs = [];
  68. var lmurCachedMPs = [];
  69. var lmurCachedPURs = [];
  70. var lmurCachesToRender = [];
  71. var lmurDownloadRequests = [];
  72. var lmurAreaHighlights = [];
  73. var lmurClusterMarkers = [];
  74. var lmurRouteDetails = [];
  75.  
  76. var lmurRateLimiter = 1;
  77. var lmurUpdateURL = '';
  78. var lmurDoOnload = true;
  79. var lmurDragBar = null;
  80. var lmurWindow = null;
  81. var lmurDiv = null;
  82. var lmurPopup = null;
  83. var lmurUI = null;
  84. var lmurUserName = '';
  85. var lmurUserID = null;
  86. var lmurIsLoggedIn;
  87.  
  88. var lmurInhibitNudgeDetection = true;
  89. var lmurControlsHidden = true;
  90. var lmurPlayModeEnabled = false;
  91. var lmurInhibitSave = true;
  92. var lmurInnerHeight = -1;
  93. var lmurUIHeight = 0;
  94. var lmurCacheExpiryPeriod = 300;
  95. var lmurInhibitCacheRefresh = false;
  96. var lmurNoForcedRefreshThisCycle = true;
  97. var lmurEnabled = false;
  98. var lmurXHRIsBusy = false;
  99. var lmurControlsMinimised =
  100. [
  101. false, false, false, false
  102. ];
  103. var lmurControlsID =
  104. [
  105. 'lmurURCtrls', 'lmurMPCtrls', 'lmurPURCtrls', 'lmurOptions'
  106. ];
  107. var lmurControlsImg =
  108. [
  109. '_minimaxURCtrls', '_minimaxMPCtrls', '_minimaxPURCtrls', '_minimaxLMURCtrls'
  110. ];
  111.  
  112. var lmurSquareSize = 0.05;
  113. var lmurMaxGrabWidth = 0.25;
  114. var lmurMaxGrabHeight = 0.25;
  115.  
  116. var lmurGetCommentsList = [];
  117. var lmurURLPrefix = '';
  118.  
  119. var lmurIcons =
  120. [
  121. 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wMBAsgGGkHX7cAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAUUlEQVQoz63SQQqAQAxD0R/xXoIXH/RicaUgtIOdscuE8DaVbaq3ZIWaXB6VJTWZE7TH2j/SrQCwxdq89FLItTkpVBJtXOoqgbY+4fFd0sjDXtyHHG22yaK0AAAAAElFTkSuQmCC',
  122. 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wMBAshHpl/y8MAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAXUlEQVQoz63SQQqAMAxE0T/Fe0k9uNKTjQtBpLZSowOBQBjeJrLN20wA2jTcdLZkGy0y80CjgFcrwbFQxgoAiUDO0qN2Ub5LXa1S/pFuWkMJS9huDhn3biFJkYfdAYUjUx2jRgIlAAAAAElFTkSuQmCC'
  123. ];
  124.  
  125. function lmurModifyHTML(htmlIn)
  126. {
  127. if(typeof trustedTypes === "undefined")
  128. {
  129. return htmlIn;
  130. }
  131. else
  132. {
  133. const escapeHTMLPolicy = trustedTypes.createPolicy("forceInner", {createHTML: (to_escape) => to_escape});
  134. return escapeHTMLPolicy.createHTML(htmlIn);
  135. }
  136. }
  137. function lmurShowTrace(traceText)
  138. {
  139. if(lmurShowTraceOutput)
  140. {
  141. console.log('LMURtrace: ('+Math.round(performance.now()*100)/100+') '+traceText);
  142. }
  143. }
  144.  
  145. function lmurGetCBChecked(cbID)
  146. {
  147. lmurShowTrace('lmurGetCBChecked('+cbID+')');
  148. if(document.getElementById(cbID) === null) return undefined;
  149. return(document.getElementById(cbID).checked);
  150. }
  151.  
  152. function lmurSaveSettings()
  153. {
  154. lmurShowTrace('lmurSaveSettings()');
  155. if(lmurInhibitSave) return;
  156. if(!lmurIsLoggedIn) return;
  157.  
  158. if (localStorage)
  159. {
  160. var options = '';
  161. var id;
  162. var lmurOptions = lmurUI.getElementsByTagName('input');
  163. for (var optIdx=0;optIdx<lmurOptions.length;optIdx++)
  164. {
  165. id = lmurOptions[optIdx].id;
  166. if((id.indexOf('_cb') === 0)||(id.indexOf('_text') === 0)||(id.indexOf('_input') === 0)||(id.indexOf('_radio') === 0))
  167. {
  168. options += ':' + id;
  169. if((lmurOptions[optIdx].type == 'checkbox')||(lmurOptions[optIdx].type == 'radio')) options += ',' + lmurOptions[optIdx].checked.toString();
  170. else if((lmurOptions[optIdx].type == 'text')||(lmurOptions[optIdx].type == 'number')) options += ',' + lmurOptions[optIdx].value.toString();
  171. }
  172. }
  173.  
  174. lmurOptions = lmurUI.getElementsByTagName('select');
  175. for (optIdx=0;optIdx<lmurOptions.length;optIdx++)
  176. {
  177. id = lmurOptions[optIdx].id;
  178. if(id.indexOf('_select') === 0)
  179. {
  180. options += ':' + id;
  181. options += ',' + lmurOptions[optIdx].selectedIndex.toString();
  182. }
  183. }
  184.  
  185. localStorage.LMUROverviewOptions = options;
  186. }
  187. }
  188.  
  189. function lmurLoadSettings()
  190. {
  191. lmurShowTrace('lmurLoadSettings()');
  192. lmurAddLog('loadSettings()');
  193. if (localStorage.LMUROverviewOptions)
  194. {
  195. var options = localStorage.LMUROverviewOptions.split(':');
  196. for(var optIdx=0;optIdx<options.length;optIdx++)
  197. {
  198. let fields = options[optIdx].split(',');
  199. if((document.getElementById(fields[0]) !== undefined) && (document.getElementById(fields[0]) !== null))
  200. {
  201. if((fields[0].indexOf('_cb') === 0)||(fields[0].indexOf('_radio') === 0))
  202. {
  203. document.getElementById(fields[0]).checked = (fields[1] == 'true');
  204. }
  205. else if(fields[0].indexOf('_select') === 0)
  206. {
  207. document.getElementById(fields[0]).selectedIndex = fields[1];
  208. }
  209. else if((fields[0].indexOf('_input') === 0)||(fields[0].indexOf('_text') === 0))
  210. {
  211. document.getElementById(fields[0]).value = fields[1];
  212. }
  213. }
  214. }
  215.  
  216. var userDecayValue = document.getElementById('_inputCacheDecayPeriod').value;
  217. if(userDecayValue === "")
  218. {
  219. document.getElementById('_inputCacheDecayPeriod').value = (lmurCacheExpiryPeriod / 60);
  220. }
  221. else
  222. {
  223. lmurCacheExpiryPeriod = (parseInt(userDecayValue) * 60);
  224. }
  225. }
  226. lmurInhibitSave = false;
  227. }
  228.  
  229. function lmurAddLog(logtext)
  230. {
  231. if(lmurShowDebugOutput)
  232. {
  233. console.log('LMUR: ('+Math.round(performance.now()*100)/100+') '+logtext);
  234. }
  235. }
  236.  
  237. function lmurMarker(pos, obj, type, lon, lat, nComments, userLastComment, ageLastComment, loggedInUserComments, isFollowing, customTagType)
  238. {
  239. this.pos = pos;
  240. this.obj = obj;
  241. this.type = type;
  242. if(obj.subType == 200)
  243. {
  244. this.type = T_MARKER.MP200;
  245. }
  246. this.lon = lon;
  247. this.lat = lat;
  248. this.markerHidden = false;
  249. this.px = -1;
  250. this.py = -1;
  251. this.nComments = nComments;
  252. this.userLastComment = userLastComment;
  253. this.ageLastComment = ageLastComment;
  254. this.loggedInUserComments = loggedInUserComments;
  255. this.isFollowing = isFollowing;
  256. this.customTagType = customTagType;
  257.  
  258. this.fCol = MARKER_FCOL[type];
  259. this.sCol = MARKER_SCOL[type];
  260. this.fOpa = 1.0;
  261. this.sOpa = 1.0;
  262. this.MID = null;
  263. this.RID = null;
  264. }
  265.  
  266. function lmurCacheObj(lon, lat, getTime)
  267. {
  268. lon = +lon.toFixed(2);
  269. lat = +lat.toFixed(2);
  270.  
  271. this.lon = lon;
  272. this.lat = lat;
  273. this.getTime = getTime;
  274. }
  275.  
  276. function lmurDlReqObj(lon, lat, getURs, getMPs, getPURs)
  277. {
  278. lon = +lon.toFixed(2);
  279. lat = +lat.toFixed(2);
  280.  
  281. this.lon = lon;
  282. this.lat = lat;
  283. this.getURs = getURs;
  284. this.getMPs = getMPs;
  285. this.getPURs = getPURs;
  286. this.retries = 0;
  287. this.requested = false;
  288. }
  289.  
  290. function lmurAreaDisplay(SID, age, fCol, fOpa)
  291. {
  292. this.SID = SID;
  293. this.age = age;
  294. this.fCol = fCol;
  295. this.fOpa = fOpa;
  296. }
  297.  
  298. function lmurClusteredMarker(CID, TID, opa)
  299. {
  300. this.CID = CID;
  301. this.TID = TID;
  302. this.opa = opa;
  303. }
  304.  
  305. function lmurPix(x, y)
  306. {
  307. this.x = Math.round(x);
  308. this.y = Math.round(y);
  309. }
  310.  
  311. function lmurGetVPSize()
  312. {
  313. return new lmurPix(document.getElementById('map').clientWidth, document.getElementById('map').clientHeight);
  314. }
  315.  
  316. function lmurLatLonToPix(llObj)
  317. {
  318. var vpSize = lmurGetVPSize();
  319. var relX = (llObj.lng - lmurVPLeft) / (lmurVPRight - lmurVPLeft);
  320. var relY = (lmurVPTop - llObj.lat) / (lmurVPTop - lmurVPBottom);
  321. var retval = new lmurPix(vpSize.x * relX, vpSize.y * relY);
  322. return retval;
  323. }
  324.  
  325. function lmurUpdateMarkerObj(markerID, nComments, userLastComment, ageLastComment, loggedInUserComments, isFollowing, customTagType)
  326. {
  327. lmurShowTrace('lmurUpdateMarkerObj('+markerID+','+nComments+','+userLastComment+','+ageLastComment+','+loggedInUserComments+','+isFollowing+','+customTagType+')');
  328. for(var objID=0; objID < lmurMarkers.length; objID++)
  329. {
  330. if(lmurMarkers[objID].obj.id == markerID)
  331. {
  332. lmurMarkers[objID].nComments = nComments;
  333. lmurMarkers[objID].userLastComment = userLastComment;
  334. lmurMarkers[objID].ageLastComment = ageLastComment;
  335. lmurMarkers[objID].loggedInUserComments = loggedInUserComments;
  336. lmurMarkers[objID].isFollowing = isFollowing;
  337. if(customTagType !== null) lmurMarkers[objID].customTagType = customTagType;
  338. break;
  339. }
  340. }
  341. }
  342.  
  343. function lmurGetCacheIdx(lon, lat, type)
  344. {
  345. lmurShowTrace('lmurGetCacheIdx('+lon+','+lat+','+type+')');
  346. lon = +lon.toFixed(2);
  347. lat = +lat.toFixed(2);
  348.  
  349. var lmurCached;
  350. if(type == T_MARKER.UR) lmurCached = lmurCachedURs;
  351. else if((type == T_MARKER.MP)||(type == T_MARKER.MP200)) lmurCached = lmurCachedMPs;
  352. else if(type == T_MARKER.PUR) lmurCached = lmurCachedPURs;
  353. else if(type == -1) lmurCached = lmurDownloadRequests;
  354. else if(type == -2) lmurCached = lmurCachesToRender;
  355. else return null;
  356.  
  357. for(var idx=0; idx<lmurCached.length; idx++)
  358. {
  359. if((lmurCached[idx].lon == lon) && (lmurCached[idx].lat == lat))
  360. {
  361. return idx;
  362. }
  363. }
  364. return null;
  365. }
  366.  
  367. function lmurSquareIsCached(lon, lat, cachedURs, cachedMPs, cachedPURs)
  368. {
  369. lmurShowTrace('lmurSquareIsCached('+lon+','+lat+','+cachedURs+','+cachedMPs+','+cachedPURs+')');
  370. lon = +lon.toFixed(2);
  371. lat = +lat.toFixed(2);
  372.  
  373. var idx;
  374.  
  375. if((!cachedURs) && (!cachedMPs) && (!cachedPURs)) return false;
  376. if(cachedURs)
  377. {
  378. idx = lmurGetCacheIdx(lon, lat, T_MARKER.UR);
  379. if(idx === null) return false;
  380. if(lmurCachedURs[idx].getTime === null) return false;
  381. }
  382. if(cachedMPs)
  383. {
  384. idx = lmurGetCacheIdx(lon, lat, T_MARKER.MP);
  385. if(idx === null) return false;
  386. if(lmurCachedMPs[idx].getTime === null) return false;
  387. }
  388. if(cachedPURs)
  389. {
  390. idx = lmurGetCacheIdx(lon, lat, T_MARKER.PUR);
  391. if(idx === null) return false;
  392. if(lmurCachedPURs[idx].getTime === null) return false;
  393. }
  394. return true;
  395. }
  396.  
  397. function lmurSquareIsQueued(lon, lat)
  398. {
  399. lmurShowTrace('lmurSquareIsQueued('+lon+','+lat+')');
  400. lon = +lon.toFixed(2);
  401. lat = +lat.toFixed(2);
  402.  
  403. var idx;
  404.  
  405. idx = lmurGetCacheIdx(lon, lat, -1);
  406. if(idx === null) return false;
  407. return true;
  408. }
  409.  
  410. function lmurGetSquareAge(lon, lat, type)
  411. {
  412. lmurShowTrace('lmurGetSquareAge('+lon+','+lat+','+type+')');
  413. lon = +lon.toFixed(2);
  414. lat = +lat.toFixed(2);
  415.  
  416. var idx = lmurGetCacheIdx(lon, lat, type);
  417. if(idx !== null)
  418. {
  419. var timeNow = Math.floor(new Date().getTime() / 1000);
  420. var cacheTime = null;
  421. if((type == T_MARKER.UR)&&(lmurCachedURs.length >= idx+1)) cacheTime = lmurCachedURs[idx].getTime;
  422. else if(((type == T_MARKER.MP)||(type == T_MARKER.MP200))&&(lmurCachedMPs.length >= idx+1)) cacheTime = lmurCachedMPs[idx].getTime;
  423. else if((type == T_MARKER.PUR)&&(lmurCachedPURs.length >= idx+1)) cacheTime = lmurCachedPURs[idx].getTime;
  424. else if((type == -2)&&(lmurCachesToRender.length >= idx+1)) cacheTime = lmurCachesToRender[idx].getTime;
  425. if(cacheTime !== null)
  426. {
  427. return (timeNow - cacheTime);
  428. }
  429. }
  430. return null;
  431. }
  432.  
  433. function lmurRemoveMarkersFromCache()
  434. {
  435. lmurShowTrace('lmurRemoveMarkersFromCache()');
  436. lmurAddLog('removing expired markers from cache');
  437. var idx=0;
  438. while(idx < lmurMarkers.length)
  439. {
  440. var markerAge = lmurGetMarkerAge(lmurMarkers[idx]);
  441. if((markerAge > lmurCacheExpiryPeriod) || (markerAge === null))
  442. {
  443. lmurMarkers.splice(idx,1);
  444. }
  445. else
  446. {
  447. idx++;
  448. }
  449. }
  450. }
  451.  
  452. function lmurRemoveSquareFromCacheList(lon, lat, type)
  453. {
  454. lmurShowTrace('lmurRemoveSquareFromCacheList('+lon+','+lat+','+type+')');
  455. lon = +lon.toFixed(2);
  456. lat = +lat.toFixed(2);
  457.  
  458. if(type !== null)
  459. {
  460. lmurAddLog('removing square '+lon+','+lat+':'+type+' from cache');
  461. var idx = lmurGetCacheIdx(lon, lat, type);
  462.  
  463. if(idx !== null)
  464. {
  465. if(type == T_MARKER.UR) lmurCachedURs.splice(idx,1);
  466. else if((type == T_MARKER.MP)||(type == T_MARKER.MP200)) lmurCachedMPs.splice(idx,1);
  467. else if(type == T_MARKER.PUR) lmurCachedPURs.splice(idx,1);
  468. else if(type == -1) lmurCachesToRender.splice(idx,1);
  469. }
  470. }
  471. }
  472.  
  473. function lmurResetCaches()
  474. {
  475. lmurShowTrace('lmurResetCaches()');
  476. lmurMarkers = [];
  477. lmurCachedURs = [];
  478. lmurCachedMPs = [];
  479. lmurCachedPURs = [];
  480. lmurCachesToRender = [];
  481. lmurDownloadRequests = [];
  482. }
  483.  
  484. function lmurChangeServer()
  485. {
  486. lmurShowTrace('lmurChangeServer()');
  487. lmurResetCaches();
  488. lmurUpdateRequestQueue();
  489. }
  490.  
  491. function lmurGetMarkerAge(ureq)
  492. {
  493. lmurShowTrace('lmurGetMarkerAge('+ureq+')');
  494. return lmurGetSquareAge(ureq.lon, ureq.lat, ureq.type);
  495. }
  496.  
  497. function lmurGetCommentsData()
  498. {
  499. lmurShowTrace('lmurGetCommentsData()');
  500. if(lmurGetCommentsList.length === 0)
  501. {
  502. lmurVisualiseMarkers();
  503. return;
  504. }
  505. if(lmurXHRIsBusy)
  506. {
  507. window.setTimeout(lmurGetCommentsData,lmurRateLimiter);
  508. return;
  509. }
  510.  
  511. var idList = '';
  512. var idCount;
  513.  
  514. if(lmurGetCommentsList.length > 50) idCount = 50;
  515. else idCount = lmurGetCommentsList.length;
  516. while(idCount)
  517. {
  518. idList += lmurGetCommentsList.pop();
  519. if(idCount != 1) idList += ',';
  520. idCount--;
  521. }
  522. var lmurRequest = new XMLHttpRequest();
  523. lmurRequest.onreadystatechange = function ()
  524. {
  525. if (lmurRequest.readyState == 4)
  526. {
  527. lmurXHRIsBusy = false;
  528. lmurAddLog('lmurGetCommentsData() response '+lmurRequest.status+' received');
  529. if (lmurRequest.status == 200)
  530. {
  531. var lmurData = JSON.parse(lmurRequest.responseText);
  532. lmurAddLog('data received for '+lmurData.updateRequestSessions.objects.length+' URs');
  533. var timeNow = new Date().getTime();
  534. for(var ursObj in lmurData.updateRequestSessions.objects)
  535. {
  536. if(lmurData.updateRequestSessions.objects.hasOwnProperty(ursObj))
  537. {
  538. var urSesh = lmurData.updateRequestSessions.objects[ursObj];
  539. var nComments = urSesh.comments.length;
  540. var loggedInUserComments = false;
  541. var userLastComment = null;
  542. var ageLastComment = null;
  543. var customTagType = null;
  544. if(nComments > 0)
  545. {
  546. userLastComment = urSesh.comments[nComments-1].userID;
  547. ageLastComment = Math.floor((timeNow - urSesh.comments[nComments-1].createdOn) / 86400000);
  548.  
  549. for(var loop=0;loop<nComments;loop++)
  550. {
  551. if(urSesh.comments[loop].userID == lmurUserID)
  552. {
  553. loggedInUserComments = true;
  554. }
  555. if(urSesh.comments[loop].text.indexOf('[ROADWORKS]') != -1) customTagType = 1;
  556. else if(urSesh.comments[loop].text.indexOf('[CONSTRUCTION]') != -1) customTagType = 2;
  557. else if(urSesh.comments[loop].text.indexOf('[CLOSURE]') != -1) customTagType = 3;
  558. else if(urSesh.comments[loop].text.indexOf('[EVENT]') != -1) customTagType = 4;
  559. else if(urSesh.comments[loop].text.indexOf('[NOTE]') != -1) customTagType = 5;
  560. }
  561. }
  562. var isFollowing = urSesh.isFollowing;
  563. lmurUpdateMarkerObj(urSesh.id,nComments,userLastComment,ageLastComment,loggedInUserComments,isFollowing,customTagType);
  564. }
  565. }
  566. }
  567. window.setTimeout(lmurGetCommentsData,lmurRateLimiter);
  568. }
  569. };
  570. var lmurFetchURL = 'https://www.waze.com/' + lmurURLPrefix + 'Descartes-live/app/MapProblems/UpdateRequests?ids='+idList;
  571. lmurAddLog('requesting '+lmurFetchURL);
  572.  
  573. lmurRequest.open("GET", lmurFetchURL, true);
  574. lmurRequest.send();
  575. lmurXHRIsBusy = true;
  576. }
  577.  
  578. function lmurUpdateRequestQueue()
  579. {
  580. lmurShowTrace('lmurUpdateRequestQueue()');
  581. // don't visualise anything if the user isn't logged-in or hasn't asked for anything to be visualised...
  582. if
  583. (
  584. (!lmurIsLoggedIn) ||
  585. (
  586. (!lmurGetCBChecked('_cbShowURs')) &&
  587. (!lmurGetCBChecked('_cbShowProblems')) &&
  588. (!lmurGetCBChecked('_cbShowPlaceUpdates'))
  589. ) ||
  590. (!lmurEnabled)
  591. )
  592. {
  593. lmurAddLog('inhibit visualisation');
  594. lmurDiv.innerHTML = lmurModifyHTML('');
  595. return;
  596. }
  597.  
  598. var midpoint;
  599. var vpLeft = lmurVPLeft;
  600. var vpRight = lmurVPRight;
  601. var vpTop = lmurVPTop;
  602. var vpBottom = lmurVPBottom;
  603. if((vpRight - vpLeft) > lmurMaxGrabWidth)
  604. {
  605. midpoint = (vpRight + vpLeft) / 2;
  606. vpRight = midpoint + (lmurMaxGrabWidth / 2);
  607. vpLeft = midpoint - (lmurMaxGrabWidth / 2);
  608. }
  609. if((vpTop - vpBottom) > lmurMaxGrabHeight)
  610. {
  611. midpoint = (vpTop + vpBottom) / 2;
  612. vpTop = midpoint + (lmurMaxGrabHeight / 2);
  613. vpBottom = midpoint - (lmurMaxGrabHeight / 2);
  614. }
  615.  
  616. var startLon = (vpLeft / lmurSquareSize);
  617. if(startLon < 0) startLon = Math.floor(startLon) * lmurSquareSize;
  618. else startLon = Math.ceil(startLon) * lmurSquareSize;
  619.  
  620. var endLon = (vpRight / lmurSquareSize);
  621. if(endLon < 0) endLon = Math.ceil(endLon) * lmurSquareSize;
  622. else endLon = Math.floor(endLon) * lmurSquareSize;
  623.  
  624. var startLat = (vpBottom / lmurSquareSize);
  625. if(startLat < 0) startLat = Math.ceil(startLat) * lmurSquareSize;
  626. else startLat = Math.floor(startLat) * lmurSquareSize;
  627.  
  628. var endLat = (vpTop / lmurSquareSize);
  629. if(endLat < 0) endLat = Math.floor(endLat) * lmurSquareSize;
  630. else endLat = Math.ceil(endLat) * lmurSquareSize;
  631.  
  632. var getURs = lmurGetCBChecked('_cbShowURs');
  633. var getMPs = lmurGetCBChecked('_cbShowProblems');
  634. var getPURs = lmurGetCBChecked('_cbShowPlaceUpdates');
  635.  
  636. for(var sqLon = startLon; sqLon <= endLon; sqLon += lmurSquareSize)
  637. {
  638. for(var sqLat = startLat; sqLat <= endLat; sqLat += lmurSquareSize)
  639. {
  640. sqLon = +sqLon.toFixed(2);
  641. sqLat = +sqLat.toFixed(2);
  642.  
  643. if(!lmurSquareIsCached(sqLon, sqLat, getURs, getMPs, getPURs))
  644. {
  645. if(!lmurSquareIsQueued(sqLon, sqLat))
  646. {
  647. lmurDownloadRequests.push(new lmurDlReqObj(sqLon, sqLat, getURs, getMPs, getPURs));
  648. }
  649. }
  650. }
  651. }
  652.  
  653. if(lmurDownloadRequests.length)
  654. {
  655. window.setTimeout(lmurGetMarkers,lmurRateLimiter);
  656. }
  657. }
  658.  
  659. function lmurGetMarkers()
  660. {
  661. lmurShowTrace('lmurGetMarkers()');
  662. if(lmurDownloadRequests.length === 0)
  663. {
  664. return;
  665. }
  666. if(lmurXHRIsBusy)
  667. {
  668. window.setTimeout(lmurGetMarkers,lmurRateLimiter);
  669. return;
  670. }
  671.  
  672. var timeNow = Math.floor(new Date().getTime() / 1000);
  673.  
  674. var dlReq = lmurDownloadRequests[0];
  675. var idx = lmurGetCacheIdx(dlReq.lon, dlReq.lat, -1);
  676. if((idx === null) || (!dlReq.requested))
  677. {
  678. lmurAddLog('cache miss at '+dlReq.lon+' '+dlReq.lat);
  679. if(dlReq.retries++ < 3)
  680. {
  681. lmurAddLog('block has retries remaining, requesting from server...');
  682. dlReq.requested = true;
  683. var getURs = ((dlReq.getURs) && (!lmurSquareIsCached(dlReq.lon, dlReq.lat, true, false, false)));
  684. var getMPs = ((dlReq.getMPs) && (!lmurSquareIsCached(dlReq.lon, dlReq.lat, false, true, false)));
  685. var getPURs = ((dlReq.getPURs) && (!lmurSquareIsCached(dlReq.lon, dlReq.lat, false, false, true)));
  686.  
  687. if(lmurGetCBChecked('_radioROWServer')) lmurURLPrefix = 'row-';
  688. else if(lmurGetCBChecked('_radioUSAServer')) lmurURLPrefix = '';
  689. else lmurURLPrefix = 'il-';
  690.  
  691. var lmurRequest = new XMLHttpRequest();
  692. lmurRequest.onreadystatechange = function ()
  693. {
  694. if (lmurRequest.readyState == 4)
  695. {
  696. lmurXHRIsBusy = false;
  697. lmurAddLog('lmurGetMarkers() response '+lmurRequest.status+' received');
  698. if (lmurRequest.status == 200)
  699. {
  700. var lmurData = JSON.parse(lmurRequest.responseText);
  701. var loop;
  702. var isDupe;
  703. var cacheObj = new lmurCacheObj(dlReq.lon, dlReq.lat, timeNow);
  704.  
  705. if((lmurData.users !== undefined) && (lmurUserName.length !== 0) && (lmurUserID === null))
  706. {
  707. for(var userObj in lmurData.users.objects)
  708. {
  709. if(lmurData.users.objects.hasOwnProperty(userObj))
  710. {
  711. var user = lmurData.users.objects[userObj];
  712. if(user.userName === lmurUserName)
  713. {
  714. lmurUserID = user.id;
  715. lmurAddLog('Found ID '+lmurUserID+' for logged-in user...');
  716. break;
  717. }
  718. }
  719. }
  720. }
  721.  
  722. lmurAddLog('This area contains:');
  723. if(lmurData.mapUpdateRequests !== undefined)
  724. {
  725. lmurAddLog(' '+lmurData.mapUpdateRequests.objects.length+' URs');
  726. // store URs
  727. for(var urobj in lmurData.mapUpdateRequests.objects)
  728. {
  729. if(lmurData.mapUpdateRequests.objects.hasOwnProperty(urobj))
  730. {
  731. var ureq = lmurData.mapUpdateRequests.objects[urobj];
  732. isDupe = false;
  733. for(loop=0; loop<lmurMarkers.length; loop++)
  734. {
  735. if((lmurMarkers[loop].type == T_MARKER.UR) && (lmurMarkers[loop].obj.id == ureq.id))
  736. {
  737. isDupe = true;
  738. break;
  739. }
  740. }
  741. if(!isDupe)
  742. {
  743. var urpos = new L.LatLng(ureq.geometry.coordinates[1],ureq.geometry.coordinates[0]);
  744. var customTagType = 0;
  745. if(ureq.description !== null)
  746. {
  747. var desc = ureq.description;
  748. if(desc.indexOf('[ROADWORKS]') != -1) customTagType = 1;
  749. else if(desc.indexOf('[CONSTRUCTION]') != -1) customTagType = 2;
  750. else if(desc.indexOf('[CLOSURE]') != -1) customTagType = 3;
  751. else if(desc.indexOf('[EVENT]') != -1) customTagType = 4;
  752. else if(desc.indexOf('[NOTE]') != -1) customTagType = 5;
  753. }
  754.  
  755. lmurMarkers.push(new lmurMarker(urpos, ureq, T_MARKER.UR, dlReq.lon, dlReq.lat, -1, -1, -1, false, false, customTagType));
  756. if(lmurUserName.length !== 0)
  757. {
  758. lmurGetCommentsList.push(ureq.id);
  759. }
  760. }
  761. }
  762. }
  763. lmurAddLog(' URs processed, '+lmurMarkers.length+' objects in lmurMarkers');
  764. }
  765.  
  766. if(lmurData.problems !== undefined)
  767. {
  768. lmurAddLog(' '+lmurData.problems.objects.length+' MPs');
  769. // store map problems
  770. for(var mpobj in lmurData.problems.objects)
  771. {
  772. if(lmurData.problems.objects.hasOwnProperty(mpobj))
  773. {
  774. var mprob = lmurData.problems.objects[mpobj];
  775. isDupe = false;
  776. for(loop=0; loop<lmurMarkers.length; loop++)
  777. {
  778. if
  779. (
  780. (
  781. (lmurMarkers[loop].type == T_MARKER.MP) ||
  782. (lmurMarkers[loop].type == T_MARKER.MP200)
  783. ) &&
  784. (lmurMarkers[loop].obj.id == mprob.id)
  785. )
  786. {
  787. isDupe = true;
  788. break;
  789. }
  790. }
  791. if(!isDupe)
  792. {
  793. var mppos = new L.LatLng(mprob.geometry.coordinates[1],mprob.geometry.coordinates[0]);
  794. lmurMarkers.push(new lmurMarker(mppos, mprob, T_MARKER.MP, dlReq.lon, dlReq.lat, 0, -1, -1, false, false, -1));
  795. }
  796. }
  797. }
  798. lmurAddLog(' MPs processed, '+lmurMarkers.length+' objects in lmurMarkers');
  799. }
  800.  
  801. if(lmurData.venues !== undefined)
  802. {
  803. lmurAddLog(' '+lmurData.venues.objects.length+' PURs');
  804. // store PURs
  805. for(var puobj in lmurData.venues.objects)
  806. {
  807. if(lmurData.venues.objects.hasOwnProperty(puobj))
  808. {
  809. var pupd = lmurData.venues.objects[puobj];
  810. isDupe = false;
  811. for(loop=0; loop<lmurMarkers.length; loop++)
  812. {
  813. if((lmurMarkers[loop].type == T_MARKER.PUR) && (lmurMarkers[loop].obj.id == pupd.id))
  814. {
  815. isDupe = true;
  816. break;
  817. }
  818. }
  819. if(!isDupe)
  820. {
  821. if(pupd.venueUpdateRequests === undefined) continue;
  822. if(pupd.geometry.type == 'Point')
  823. {
  824. var pupos_point = new L.LatLng(pupd.geometry.coordinates[1],pupd.geometry.coordinates[0]);
  825. lmurMarkers.push(new lmurMarker(pupos_point, pupd, T_MARKER.PUR, dlReq.lon, dlReq.lat, 0, -1, -1, false, false, -1));
  826. }
  827. else if(pupd.geometry.type == 'Polygon')
  828. {
  829. var pupos_poly = new L.LatLng(pupd.geometry.coordinates[0][0][1],pupd.geometry.coordinates[0][0][0]);
  830. lmurMarkers.push(new lmurMarker(pupos_poly, pupd, T_MARKER.PUR, dlReq.lon, dlReq.lat, 0, -1, -1, false, false, -1));
  831. }
  832. }
  833. }
  834. }
  835. lmurAddLog(' PURs processed, '+lmurMarkers.length+' objects in lmurMarkers');
  836. }
  837.  
  838. if(getURs) lmurCachedURs.push(cacheObj);
  839. if(getMPs) lmurCachedMPs.push(cacheObj);
  840. if(getPURs) lmurCachedPURs.push(cacheObj);
  841. if(lmurGetCommentsList.length > 0)
  842. {
  843. window.setTimeout(lmurGetCommentsData,lmurRateLimiter);
  844. }
  845. lmurVisualiseMarkers();
  846. lmurDownloadRequests.shift();
  847. }
  848. window.setTimeout(lmurGetMarkers,lmurRateLimiter);
  849. }
  850. };
  851. var lmurFetchURL = 'https://www.waze.com/' + lmurURLPrefix + 'Descartes-live/app/Features?language=en';
  852. if(getURs) lmurFetchURL += '&mapUpdateRequestFilter=1';
  853. if(getMPs) lmurFetchURL += '&problemFilter=1&turnProblemFilter=1';
  854. if(getPURs) lmurFetchURL += '&venueFilter=1&venueLevel=1&venueUpdateRequests=true';
  855. if(lmurGetCBChecked('_cbEnablePlayMode')) lmurFetchURL += '&sandbox=true';
  856. lmurFetchURL += '&bbox=';
  857. lmurFetchURL += dlReq.lon + ',' + dlReq.lat + ',' + (dlReq.lon + lmurSquareSize) + ',' + (dlReq.lat + lmurSquareSize);
  858. lmurRequest.open('GET', lmurFetchURL, true);
  859. lmurRequest.send();
  860. lmurXHRIsBusy = true;
  861. lmurAddLog('requesting '+lmurFetchURL);
  862. }
  863. else
  864. {
  865. lmurAddLog('out of retries, sorry...');
  866. lmurDownloadRequests.shift();
  867. }
  868. }
  869. else
  870. {
  871. lmurAddLog('cache hit at '+dlReq.lon+' '+dlReq.lat);
  872. lmurDownloadRequests.shift();
  873. window.setTimeout(lmurGetMarkers,lmurRateLimiter);
  874. }
  875. }
  876.  
  877. function lmurKeywordPresent(desc, keyword)
  878. {
  879. lmurShowTrace('lmurKeywordPresent('+desc+','+keyword+')');
  880. var re;
  881. if(lmurGetCBChecked('_cbURCaseInsensitive')) re = RegExp(keyword,'i');
  882. else re = RegExp(keyword);
  883. if(desc.search(re) == -1) return false;
  884. else return true;
  885. }
  886.  
  887. function lmurFilterMarkers(ureq)
  888. {
  889. lmurShowTrace('lmurFilterMarkers('+ureq+')');
  890. var daysOld;
  891.  
  892. // URs
  893. if(ureq.type == T_MARKER.UR)
  894. {
  895. if (!lmurGetCBChecked('_cbShowURs')) return true;
  896.  
  897. // resolved filtering
  898. if(lmurGetCBChecked('_cbUREnableResolvedFilter'))
  899. {
  900. if(ureq.obj.resolvedOn !== null) return true;
  901. }
  902.  
  903. // age-based filtering
  904. daysOld = lmurGetURAge(ureq.obj,0);
  905. if(daysOld != 999999)
  906. {
  907. if(lmurGetCBChecked('_cbUREnableMinAgeFilter'))
  908. {
  909. if(daysOld < document.getElementById('_inputURFilterMinDays').value) return true;
  910. }
  911. if(lmurGetCBChecked('_cbUREnableMaxAgeFilter'))
  912. {
  913. if(daysOld > document.getElementById('_inputURFilterMaxDays').value) return true;
  914. }
  915. }
  916.  
  917. // comment based filtering
  918. if(lmurIsLoggedIn)
  919. {
  920. if
  921. (
  922. ((lmurGetCBChecked('_cbURShowUnloadedComments')) && (ureq.nComments != -1)) ||
  923. ((lmurGetCBChecked('_cbURHideUnloadedComments')) && (ureq.nComments == -1))
  924. )
  925. {
  926. return true;
  927. }
  928.  
  929. if (ureq.nComments != -1)
  930. {
  931. if(lmurGetCBChecked('_cbURHideWithMyComments'))
  932. {
  933. if(ureq.loggedInUserComments) return true;
  934. }
  935. if(lmurGetCBChecked('_cbURShowWithMyComments'))
  936. {
  937. if(!ureq.loggedInUserComments) return true;
  938. }
  939. if(lmurGetCBChecked('_cbURHideLastCommentByMe'))
  940. {
  941. if(ureq.userLastComment == lmurUserID) return true;
  942. }
  943. if(lmurGetCBChecked('_cbURShowLastCommentByMe'))
  944. {
  945. if(ureq.userLastComment != lmurUserID) return true;
  946. }
  947. if(lmurGetCBChecked('_cbURHideLastCommentByReporter'))
  948. {
  949. if(ureq.userLastComment == -1) return true;
  950. }
  951. if(lmurGetCBChecked('_cbURShowLastCommentByReporter'))
  952. {
  953. if(ureq.userLastComment != -1) return true;
  954. }
  955. if(lmurGetCBChecked('_cbURHideWithLessThanComments'))
  956. {
  957. if(ureq.nComments < document.getElementById('_inputFilterMinComments').value) return true;
  958. }
  959. if(lmurGetCBChecked('_cbURShowWithLessThanComments'))
  960. {
  961. if(ureq.nComments >= document.getElementById('_inputFilterMinComments').value) return true;
  962. }
  963.  
  964. if(lmurGetCBChecked('_cbURHideFollowedURs'))
  965. {
  966. if(ureq.isFollowing) return true;
  967. }
  968. if(lmurGetCBChecked('_cbURShowFollowedURs'))
  969. {
  970. if(!ureq.isFollowing) return true;
  971. }
  972.  
  973. if(lmurGetCBChecked('_cbURHideLastCommentAge'))
  974. {
  975. if(ureq.nComments > 0)
  976. {
  977. if(ureq.ageLastComment < document.getElementById('_inputFilterCommentAge').value) return true;
  978. }
  979. }
  980. if(lmurGetCBChecked('_cbURShowLastCommentAge'))
  981. {
  982. if(ureq.ageLastComment >= document.getElementById('_inputFilterCommentAge').value) return true;
  983. }
  984. }
  985. }
  986.  
  987.  
  988. // keyword and type-specific filtering
  989. var desc = '';
  990. var urFilter = false;
  991.  
  992. if(ureq.obj.description !== null) desc = ureq.obj.description;
  993. if(lmurGetCBChecked('_cbUREnableKeywordMustBePresent'))
  994. {
  995. if(!lmurKeywordPresent(desc,document.getElementById('_textURKeywordPresent').value)) return true;
  996. }
  997. if(lmurGetCBChecked('_cbUREnableKeywordMustBeAbsent'))
  998. {
  999. if(lmurKeywordPresent(desc,document.getElementById('_textURKeywordAbsent').value)) return true;
  1000. }
  1001. if(lmurGetCBChecked('_cbURHideWithNoDescription'))
  1002. {
  1003. if(desc === "") return true;
  1004. }
  1005. if(lmurGetCBChecked('_cbURShowWithNoDescription'))
  1006. {
  1007. if(desc !== "") return true;
  1008. }
  1009.  
  1010.  
  1011. // type-based filtering...
  1012. // Need to check for Waze automatic URs first - these always (?) get inserted as General Error URs,
  1013. // so although they're treated as a "type" UR for filtering purposes, we have to filter them out
  1014. // via description keyword matching before we can do any real type filtering
  1015. if(desc.indexOf('Waze Automatic:') != -1) urFilter |= lmurGetCBChecked('_cbURFilterWazeAuto');
  1016. // Now custom tagged URs
  1017. else if(ureq.customTagType == 1) urFilter |= lmurGetCBChecked('_cbURFilterRoadworks');
  1018. else if(ureq.customTagType == 2) urFilter |= lmurGetCBChecked('_cbURFilterConstruction');
  1019. else if(ureq.customTagType == 3) urFilter |= lmurGetCBChecked('_cbURFilterClosure');
  1020. else if(ureq.customTagType == 4) urFilter |= lmurGetCBChecked('_cbURFilterEvent');
  1021. else if(ureq.customTagType == 5) urFilter |= lmurGetCBChecked('_cbURFilterNote');
  1022.  
  1023. if(ureq.obj.type == 6) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectTurn');
  1024. else if(ureq.obj.type == 7) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectAddress');
  1025. else if(ureq.obj.type == 8) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectRoute');
  1026. else if(ureq.obj.type == 9) urFilter |= lmurGetCBChecked('_cbURFilterMissingRoundabout');
  1027. else if(ureq.obj.type == 10) urFilter |= lmurGetCBChecked('_cbURFilterGeneralError');
  1028. else if(ureq.obj.type == 11) urFilter |= lmurGetCBChecked('_cbURFilterTurnNotAllowed');
  1029. else if(ureq.obj.type == 12) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectJunction');
  1030. else if(ureq.obj.type == 13) urFilter |= lmurGetCBChecked('_cbURFilterMissingBridgeOverpass');
  1031. else if(ureq.obj.type == 14) urFilter |= lmurGetCBChecked('_cbURFilterWrongDrivingDirection');
  1032. else if(ureq.obj.type == 15) urFilter |= lmurGetCBChecked('_cbURFilterMissingExit');
  1033. else if(ureq.obj.type == 16) urFilter |= lmurGetCBChecked('_cbURFilterMissingRoad');
  1034. else if(ureq.obj.type == 18) urFilter |= lmurGetCBChecked('_cbURFilterMissingLandmark');
  1035. else if(ureq.obj.type == 19) urFilter |= lmurGetCBChecked('_cbURFilterBlockedRoad');
  1036. else if(lmurGetCBChecked('_cbURFilterUndefined')) urFilter |= true;
  1037.  
  1038.  
  1039. if(document.getElementsByName('lmurShowURs')[0].checked)
  1040. {
  1041. urFilter = !urFilter;
  1042. }
  1043. return urFilter;
  1044. }
  1045.  
  1046. // MPs
  1047. else if(ureq.type == T_MARKER.MP)
  1048. {
  1049. if (!lmurGetCBChecked('_cbShowProblems')) return true;
  1050.  
  1051. // resolved filtering
  1052. if(lmurGetCBChecked('_cbMPEnableResolvedFilter'))
  1053. {
  1054. if(ureq.obj.resolvedOn !== null) return true;
  1055. }
  1056.  
  1057. // filter by severity
  1058. if(ureq.obj.priority <= 3)
  1059. {
  1060. if (lmurGetCBChecked('_cbMPFilterLowSeverity')) return true;
  1061. }
  1062. else if(ureq.obj.priority <= 7)
  1063. {
  1064. if (lmurGetCBChecked('_cbMPFilterMediumSeverity')) return true;
  1065. }
  1066. else if(ureq.obj.priority > 7)
  1067. {
  1068. if (lmurGetCBChecked('_cbMPFilterHighSeverity')) return true;
  1069. }
  1070.  
  1071. var problemFilter = false;
  1072.  
  1073. if(ureq.obj.subType == 101) problemFilter |= lmurGetCBChecked('_cbMPFilterDrivingDirectionMismatch');
  1074. else if(ureq.obj.subType == 102) problemFilter |= lmurGetCBChecked('_cbMPFilterMissingJunction');
  1075. else if(ureq.obj.subType == 103) problemFilter |= lmurGetCBChecked('_cbMPFilterMissingRoad');
  1076. else if(ureq.obj.subType == 104) problemFilter |= lmurGetCBChecked('_cbMPFilterCrossroadsJunctionMissing');
  1077. else if(ureq.obj.subType == 105) problemFilter |= lmurGetCBChecked('_cbMPFilterRoadTypeMismatch');
  1078. else if(ureq.obj.subType == 106) problemFilter |= lmurGetCBChecked('_cbMPFilterRestrictedTurn');
  1079. else if(ureq.obj.subType == 300) problemFilter |= lmurGetCBChecked('_cbMPFilterRoadClosure');
  1080. else if(lmurGetCBChecked('_cbMPFilterUnknownProblem')) problemFilter = true;
  1081.  
  1082. if(document.getElementsByName('lmurShowProblems')[0].checked)
  1083. {
  1084. problemFilter = !problemFilter;
  1085. }
  1086. return problemFilter;
  1087. }
  1088. else if(ureq.type == T_MARKER.MP200)
  1089. {
  1090. // resolved filtering
  1091. if(lmurGetCBChecked('_cbTPEnableResolvedFilter'))
  1092. {
  1093. if(ureq.obj.resolvedOn !== null) return true;
  1094. }
  1095. if (!lmurGetCBChecked('_cbShowTurnProbs')) return true;
  1096. return false;
  1097. }
  1098.  
  1099. // PURs
  1100. else if(ureq.type == T_MARKER.PUR)
  1101. {
  1102. if (!lmurGetCBChecked('_cbShowPlaceUpdates')) return true;
  1103.  
  1104. // residential/non-residential filtering
  1105. if(ureq.obj.residential)
  1106. {
  1107. if (lmurGetCBChecked('_cbPURFilterResidential')) return true;
  1108. }
  1109. else
  1110. {
  1111. if (lmurGetCBChecked('_cbPURFilterNonResidential')) return true;
  1112. }
  1113.  
  1114. // age-based filtering
  1115. daysOld = lmurGetURAge(ureq.obj,3);
  1116. if(daysOld != 999999)
  1117. {
  1118. if(lmurGetCBChecked('_cbPUREnableMinAgeFilter'))
  1119. {
  1120. if(daysOld < document.getElementById('_inputPURFilterMinDays').value) return true;
  1121. }
  1122. if(lmurGetCBChecked('_cbPUREnableMaxAgeFilter'))
  1123. {
  1124. if(daysOld > document.getElementById('_inputPURFilterMaxDays').value) return true;
  1125. }
  1126. }
  1127.  
  1128. var purFilter = false;
  1129. var purUpdateDetails = false;
  1130. var purNewPhoto = false;
  1131. var purNewPlace = false;
  1132. var purFlagged = false;
  1133. var purNonZeroLR = false;
  1134.  
  1135. if(ureq.obj.lockRank !== undefined)
  1136. {
  1137. purNonZeroLR = (ureq.obj.lockRank > 0);
  1138. }
  1139.  
  1140. for(var vurIdx=0; vurIdx < ureq.obj.venueUpdateRequests.length; vurIdx++)
  1141. {
  1142. var vurObj = ureq.obj.venueUpdateRequests[vurIdx];
  1143. if(vurObj.type !== undefined)
  1144. {
  1145. purNewPhoto |= (vurObj.type == 'IMAGE');
  1146. purNewPlace |= (vurObj.type == 'VENUE');
  1147. }
  1148.  
  1149. if(vurObj.subType !== undefined)
  1150. {
  1151. purUpdateDetails |= (vurObj.subType == 'UPDATE');
  1152. purFlagged |= (vurObj.subType == 'FLAG');
  1153. }
  1154. }
  1155.  
  1156. purFilter |= ((lmurGetCBChecked('_cbPURFilterNewPlace')) && (purNewPlace));
  1157. purFilter |= ((lmurGetCBChecked('_cbPURFilterUpdateDetails')) && (purUpdateDetails));
  1158. purFilter |= ((lmurGetCBChecked('_cbPURFilterNewPhoto')) && (purNewPhoto));
  1159. purFilter |= ((lmurGetCBChecked('_cbPURFilterFlagged')) && (purFlagged));
  1160. purFilter |= ((lmurGetCBChecked('_cbPURNonZeroLockRank')) && (purNonZeroLR));
  1161.  
  1162. if(document.getElementsByName('lmurShowPURs')[0].checked)
  1163. {
  1164. purFilter = !purFilter;
  1165. }
  1166. return purFilter;
  1167. }
  1168. }
  1169.  
  1170. function lmurGetZoom()
  1171. {
  1172. var zoom = null;
  1173. var pos;
  1174. var tStr;
  1175. var cList = document.getElementsByClassName('wm-map__leaflet')[0].classList;
  1176. for(var i = 0; i < cList.length; ++i)
  1177. {
  1178. pos = cList[i].indexOf('--zoom-');
  1179. if(pos > 0)
  1180. {
  1181. tStr = cList[i].slice(pos + 7);
  1182. zoom = parseInt(tStr);
  1183. if(isNaN(zoom) == false)
  1184. {
  1185. break;
  1186. }
  1187. }
  1188. }
  1189. return zoom;
  1190. }
  1191.  
  1192. function lmurVisualiseMarkers()
  1193. {
  1194. lmurShowTrace('lmurVisualiseMarkers()');
  1195. // don't visualise anything if the user isn't logged-in or hasn't asked for anything to be visualised...
  1196. if
  1197. (
  1198. (!lmurIsLoggedIn) ||
  1199. (
  1200. (!lmurGetCBChecked('_cbShowURs')) &&
  1201. (!lmurGetCBChecked('_cbShowProblems')) &&
  1202. (!lmurGetCBChecked('_cbShowPlaceUpdates'))
  1203. ) ||
  1204. (!lmurEnabled)
  1205. )
  1206. {
  1207. lmurAddLog('inhibit visualisation');
  1208. lmurDiv.innerHTML = lmurModifyHTML('');
  1209. return;
  1210. }
  1211.  
  1212. lmurAddLog('enabling nudge detection');
  1213. lmurInhibitNudgeDetection = false;
  1214.  
  1215. lmurAddLog('visualise markers');
  1216. var mapObj = document.getElementById("map");
  1217. var currentwidth = mapObj.offsetWidth;
  1218. var currentheight = mapObj.offsetHeight;
  1219.  
  1220.  
  1221. lmurDiv.style.width = currentwidth;
  1222. lmurDiv.style.height = currentheight;
  1223. var svgSrc = '<svg xmlns="http://www.w3.org/2000/svg" width="'+currentwidth+'px" height="'+currentheight+'px" version="1.1">';
  1224.  
  1225. // visualise cached data areas
  1226. var corner1 = new L.LatLng(0,0);
  1227. var corner2 = new L.LatLng(0,0);
  1228.  
  1229. lmurCachesToRender = [];
  1230.  
  1231. var sq;
  1232. var sqAge;
  1233. var idx;
  1234. var fillOpacity;
  1235. var pix1;
  1236. var pix2;
  1237.  
  1238. for(sq=0;sq<lmurCachedURs.length;sq++)
  1239. {
  1240. corner1.lat = lmurCachedURs[sq].lat;
  1241. corner1.lng = lmurCachedURs[sq].lon;
  1242. sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, T_MARKER.UR);
  1243. if(sqAge !== null)
  1244. {
  1245. if((sqAge > lmurCacheExpiryPeriod)&&(lmurCacheExpiryPeriod !== 0)) lmurRemoveSquareFromCacheList(corner1.lng, corner1.lat, T_MARKER.UR);
  1246. else if(sqAge != -1)
  1247. {
  1248. sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2);
  1249. if(sqAge === null) lmurCachesToRender.push(new lmurCacheObj(lmurCachedURs[sq].lon, lmurCachedURs[sq].lat, lmurCachedURs[sq].getTime));
  1250. }
  1251. }
  1252. }
  1253.  
  1254. for(sq=0;sq<lmurCachedMPs.length;sq++)
  1255. {
  1256. corner1.lat = lmurCachedMPs[sq].lat;
  1257. corner1.lng = lmurCachedMPs[sq].lon;
  1258. sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, T_MARKER.MP);
  1259. if(sqAge !== null)
  1260. {
  1261. if((sqAge > lmurCacheExpiryPeriod)&&(lmurCacheExpiryPeriod !== 0)) lmurRemoveSquareFromCacheList(corner1.lng, corner1.lat, T_MARKER.MP);
  1262. else if(sqAge != -1)
  1263. {
  1264. sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2);
  1265. if(sqAge === null) lmurCachesToRender.push(new lmurCacheObj(lmurCachedMPs[sq].lon, lmurCachedMPs[sq].lat, lmurCachedMPs[sq].getTime));
  1266. else if(sqAge < lmurGetSquareAge(corner1.lng, corner1.lat, -1)) lmurCachesToRender[idx].getTime = lmurCachedMPs[sq].getTime;
  1267. }
  1268. }
  1269. }
  1270.  
  1271. for(sq=0;sq<lmurCachedPURs.length;sq++)
  1272. {
  1273. corner1.lat = lmurCachedPURs[sq].lat;
  1274. corner1.lng = lmurCachedPURs[sq].lon;
  1275. sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, T_MARKER.PUR);
  1276. if(sqAge !== null)
  1277. {
  1278. if((sqAge > lmurCacheExpiryPeriod)&&(lmurCacheExpiryPeriod !== 0)) lmurRemoveSquareFromCacheList(corner1.lng, corner1.lat, T_MARKER.PUR);
  1279. else if(sqAge != -1)
  1280. {
  1281. sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2);
  1282. if(sqAge === null) lmurCachesToRender.push(new lmurCacheObj(lmurCachedPURs[sq].lon, lmurCachedPURs[sq].lat, lmurCachedPURs[sq].getTime));
  1283. else if(sqAge < lmurGetSquareAge(corner1.lng, corner1.lat, -1)) lmurCachesToRender[idx].getTime = lmurCachedPURs[sq].getTime;
  1284. }
  1285. }
  1286. }
  1287.  
  1288. for(sq=0;sq<lmurDownloadRequests.length;sq++)
  1289. {
  1290. corner1.lat = lmurDownloadRequests[sq].lat;
  1291. corner1.lng = lmurDownloadRequests[sq].lon;
  1292. if
  1293. (
  1294. (corner1.lng <= lmurVPRight) &&
  1295. ((corner1.lng + lmurSquareSize) >= lmurVPLeft) &&
  1296. (corner1.lat <= lmurVPTop) &&
  1297. ((corner1.lat + lmurSquareSize) >= lmurVPBottom)
  1298. )
  1299. {
  1300. corner2.lat = parseFloat(corner1.lat)+lmurSquareSize;
  1301. corner2.lng = parseFloat(corner1.lng)+lmurSquareSize;
  1302. pix1 = lmurLatLonToPix(corner1);
  1303. pix2 = lmurLatLonToPix(corner2);
  1304. var sID = 'ASQ-'+lmurAreaHighlights.length;
  1305. svgSrc += '<rect id="'+sID+'" x="'+pix1.x+'" y="'+pix2.y+'" width="'+(pix2.x-pix1.x)+'" height="'+(pix1.y-pix2.y)+'" />';
  1306. lmurAreaHighlights.push(new lmurAreaDisplay(sID, -1, 'grey', 0.2));
  1307. }
  1308. }
  1309.  
  1310. if(!lmurGetCBChecked('_cbHighlightDisabled'))
  1311. {
  1312. for(sq=0;sq<lmurCachesToRender.length;sq++)
  1313. {
  1314. corner1.lat = lmurCachesToRender[sq].lat;
  1315. corner1.lng = lmurCachesToRender[sq].lon;
  1316. if
  1317. (
  1318. (corner1.lng <= lmurVPRight) &&
  1319. ((corner1.lng + lmurSquareSize) >= lmurVPLeft) &&
  1320. (corner1.lat <= lmurVPTop) &&
  1321. ((corner1.lat + lmurSquareSize) >= lmurVPBottom)
  1322. )
  1323. {
  1324. sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2);
  1325. if(sqAge > lmurCacheExpiryPeriod)
  1326. {
  1327. sqAge = lmurCacheExpiryPeriod;
  1328. }
  1329. if((sqAge != -1) && (sqAge <= lmurCacheExpiryPeriod))
  1330. {
  1331. if(lmurCacheExpiryPeriod === 0)
  1332. {
  1333. fillOpacity = 0.2;
  1334. }
  1335. else
  1336. {
  1337. fillOpacity = 0.2 - ((sqAge * 0.15) / lmurCacheExpiryPeriod);
  1338. }
  1339. corner2.lat = parseFloat(corner1.lat)+lmurSquareSize;
  1340. corner2.lng = parseFloat(corner1.lng)+lmurSquareSize;
  1341.  
  1342. pix1 = lmurLatLonToPix(corner1);
  1343. pix2 = lmurLatLonToPix(corner2);
  1344.  
  1345. let sID = 'ASQ-'+lmurAreaHighlights.length;
  1346. svgSrc += '<rect id="'+sID+'" x="'+pix1.x+'" y="'+pix2.y+'" width="'+(pix2.x-pix1.x)+'" height="'+(pix1.y-pix2.y)+'" />';
  1347. lmurAreaHighlights.push(new lmurAreaDisplay(sID, sqAge, 'yellow', fillOpacity));
  1348. }
  1349. }
  1350. }
  1351. }
  1352.  
  1353. if(lmurCacheExpiryPeriod > 0)
  1354. {
  1355. lmurRemoveMarkersFromCache();
  1356. }
  1357.  
  1358. var urpos = new L.LatLng(0,0);
  1359. var hideMarker;
  1360. var i;
  1361. var ureq;
  1362. var filteredMarkers = 0;
  1363. var vpSize = lmurGetVPSize();
  1364.  
  1365. for(i=0;i<lmurMarkers.length;i++)
  1366. {
  1367. ureq = lmurMarkers[i];
  1368.  
  1369. hideMarker = lmurFilterMarkers(ureq);
  1370. if(!hideMarker)
  1371. {
  1372. urpos.lng = ureq.pos.lng;
  1373. urpos.lat = ureq.pos.lat;
  1374. var urpix = lmurLatLonToPix(urpos);
  1375. lmurMarkers[i].px = urpix.x;
  1376. lmurMarkers[i].py = urpix.y;
  1377. if((urpix.x < 0)||(urpix.x >= vpSize.x)||(urpix.y < 0)||(urpix.y >= vpSize.y)) hideMarker = true;
  1378. }
  1379. else
  1380. {
  1381. lmurMarkers[i].px = -1;
  1382. lmurMarkers[i].py = -1;
  1383. filteredMarkers++;
  1384. }
  1385. lmurMarkers[i].markerHidden = hideMarker;
  1386. }
  1387.  
  1388. var zoom = lmurGetZoom();
  1389. if((zoom < 11) && (!lmurGetCBChecked('_cbClusteringDisabled')))
  1390. {
  1391. var clusterDist = Math.min(Math.floor(vpSize.y / 20),Math.floor(vpSize.x / 20));
  1392. var marker_rad = clusterDist / 3;
  1393. if(marker_rad < 10) marker_rad = 10;
  1394. var threshold = 1;
  1395. lmurClusterMarkers = [];
  1396.  
  1397. if(lmurMarkers.length > 1)
  1398. {
  1399. for(i=0;i<lmurMarkers.length-1;i++)
  1400. {
  1401. if(!lmurMarkers[i].markerHidden)
  1402. {
  1403. if(lmurCacheExpiryPeriod === 0)
  1404. {
  1405. fillOpacity = 1;
  1406. }
  1407. else
  1408. {
  1409. fillOpacity = 1 - ((lmurGetMarkerAge(lmurMarkers[i]) * 0.9) / lmurCacheExpiryPeriod);
  1410. }
  1411. if(fillOpacity < 0.1) fillOpacity = 0.1;
  1412. var clusterSize = 1;
  1413. var clusterX = lmurMarkers[i].px;
  1414. var clusterY = lmurMarkers[i].py;
  1415. var xmin = lmurMarkers[i].px-clusterDist;
  1416. var xmax = lmurMarkers[i].px+clusterDist;
  1417. var ymin = lmurMarkers[i].py-clusterDist;
  1418. var ymax = lmurMarkers[i].py+clusterDist;
  1419. for(var j=i+1;j<lmurMarkers.length;j++)
  1420. {
  1421. if(!lmurMarkers[j].markerHidden)
  1422. {
  1423. if((lmurMarkers[j].px > xmin)&&(lmurMarkers[j].px < xmax)&&(lmurMarkers[j].py > ymin)&&(lmurMarkers[j].py < ymax))
  1424. {
  1425. clusterSize++;
  1426. clusterX += lmurMarkers[j].px;
  1427. clusterY += lmurMarkers[j].py;
  1428. lmurMarkers[j].markerHidden = true;
  1429. }
  1430. }
  1431. }
  1432. if(clusterSize > threshold)
  1433. {
  1434. lmurMarkers[i].markerHidden = true;
  1435. var cx = clusterX / clusterSize;
  1436. var cy = clusterY / clusterSize;
  1437. var CID = "CCID_"+i;
  1438. var TID = "CTID_"+i;
  1439. svgSrc += '<circle id="'+CID+'" cx="'+cx+'" cy="'+cy+'" r="'+marker_rad+'" />';
  1440. svgSrc += '<text id="'+TID+'" x="'+cx+'" y="'+cy+'" font-size="12" fill="white" dy="5">'+clusterSize+'</text>';
  1441. lmurClusterMarkers.push(new lmurClusteredMarker(CID, TID, fillOpacity));
  1442. }
  1443. }
  1444. }
  1445. }
  1446. }
  1447.  
  1448. for(i=0;i<lmurMarkers.length;i++)
  1449. {
  1450. if(!lmurMarkers[i].markerHidden)
  1451. {
  1452. ureq = lmurMarkers[i];
  1453. if(lmurCacheExpiryPeriod === 0)
  1454. {
  1455. fillOpacity = 1;
  1456. }
  1457. else
  1458. {
  1459. fillOpacity = 1 - ((lmurGetMarkerAge(ureq) * 0.9) / lmurCacheExpiryPeriod);
  1460. }
  1461. if(fillOpacity < 0.1) fillOpacity = 0.1;
  1462. if(ureq.type == T_MARKER.UR)
  1463. {
  1464. if(ureq.obj.resolvedOn !== null)
  1465. {
  1466. lmurMarkers[i].RID = "RID_"+i;
  1467. svgSrc += '<circle id="RID_'+i+'" cx="'+ureq.px+'" cy="'+(ureq.py+7)+'" r="9" />';
  1468. }
  1469. lmurMarkers[i].MID = "MID_"+i;
  1470. svgSrc += '<rect id="MID_'+i+'" x="'+ureq.px+'" y="'+ureq.py+'" transform="rotate(45,'+ureq.px+','+ureq.py+')" width="10" height="10" />';
  1471. }
  1472. else if(ureq.type == T_MARKER.MP)
  1473. {
  1474. if(ureq.obj.resolvedOn !== null)
  1475. {
  1476. lmurMarkers[i].RID = "RID_"+i;
  1477. svgSrc += '<circle id="RID_'+i+'" cx="'+ureq.px+'" cy="'+(ureq.py)+'" r="9" />';
  1478. }
  1479. lmurMarkers[i].MID = "MID_"+i;
  1480. svgSrc += '<rect id="MID_'+i+'" x="'+(ureq.px-5)+'" y="'+(ureq.py-5)+'" width="10" height="10" />';
  1481. }
  1482. else if(ureq.type == T_MARKER.MP200)
  1483. {
  1484. if(ureq.obj.resolvedOn !== null)
  1485. {
  1486. lmurMarkers[i].RID = "RID_"+i;
  1487. svgSrc += '<circle id="RID_'+i+'" cx="'+ureq.px+'" cy="'+(ureq.py)+'" r="9" />';
  1488. }
  1489. lmurMarkers[i].MID = "MID_"+i;
  1490. svgSrc += '<circle id="MID_'+i+'" cx="'+ureq.px+'" cy="'+ureq.py+'" r="5" />';
  1491. }
  1492. else if(ureq.type == T_MARKER.PUR)
  1493. {
  1494. lmurMarkers[i].MID = "MID_"+i;
  1495. svgSrc += '<polygon id="MID_'+i+'" points="'+(ureq.px+0)+','+(ureq.py+5)+' '+(ureq.px+5)+','+(ureq.py+1)+' '+(ureq.px+3)+','+(ureq.py-5)+' '+(ureq.px-3)+','+(ureq.py-5)+' '+(ureq.px-5)+','+(ureq.py+1)+'" />';
  1496. }
  1497. }
  1498. }
  1499. svgSrc += '</svg>';
  1500.  
  1501. lmurDiv.innerHTML = lmurModifyHTML(svgSrc);
  1502. lmurDiv.style.visibility = '';
  1503.  
  1504. lmurUpdateSVGStyles();
  1505. }
  1506.  
  1507. function lmurUpdateSVGStyles()
  1508. {
  1509. var sObj = null;
  1510. for(let i = 0; i < lmurMarkers.length; ++i)
  1511. {
  1512. if(lmurMarkers[i].RID != null)
  1513. {
  1514. sObj = document.getElementById(lmurMarkers[i].RID);
  1515. if(sObj != null)
  1516. {
  1517. sObj.style.fill = T_RESOLVED.FCOL;
  1518. sObj.style.fillOpacity = lmurMarkers[i].fOpa;
  1519. sObj.style.stroke = T_RESOLVED.SCOL;
  1520. sObj.style.strokeOpacity = lmurMarkers[i].sOpa;
  1521. }
  1522. }
  1523. if(lmurMarkers[i].MID != null)
  1524. {
  1525. sObj = document.getElementById(lmurMarkers[i].MID);
  1526. if(sObj != null)
  1527. {
  1528. sObj.style.fill = lmurMarkers[i].fCol;
  1529. sObj.style.fillOpacity = lmurMarkers[i].fOpa;
  1530. sObj.style.stroke = lmurMarkers[i].sCol;
  1531. sObj.style.strokeOpacity = lmurMarkers[i].sOpa;
  1532. }
  1533. }
  1534. }
  1535. for(let i = 0; i < lmurAreaHighlights.length; ++i)
  1536. {
  1537. sObj = document.getElementById(lmurAreaHighlights[i].SID);
  1538. if(sObj != null)
  1539. {
  1540. sObj.style.fill = lmurAreaHighlights[i].fCol;
  1541. sObj.style.fillOpacity = lmurAreaHighlights[i].fOpa;
  1542. }
  1543. }
  1544. for(var i = 0; i < lmurClusterMarkers.length; ++i)
  1545. {
  1546. sObj = document.getElementById(lmurClusterMarkers[i].CID);
  1547. if(sObj != null)
  1548. {
  1549. sObj.style.fill = "black";
  1550. sObj.style.stroke = "white";
  1551. sObj.style.fillOpacity = lmurClusterMarkers[i].opa;
  1552. sObj.style.strokeOpacity = 1;
  1553. sObj = document.getElementById(lmurClusterMarkers[i].TID);
  1554. if(sObj != null)
  1555. {
  1556. sObj.style.textAnchor = "middle";
  1557. }
  1558. }
  1559. }
  1560. }
  1561.  
  1562. function lmurInitDrag()
  1563. {
  1564. lmurShowTrace('lmurInitDrag()');
  1565. lmurAddLog('inhibiting nudge detection');
  1566. lmurInhibitNudgeDetection = true;
  1567. lmurDiv.style.visibility = 'hidden';
  1568. }
  1569.  
  1570. function lmurEndDrag()
  1571. {
  1572. lmurShowTrace('lmurEndDrag()');
  1573. lmurAddLog('re-enabling nudge detection');
  1574. lmurInhibitNudgeDetection = false;
  1575. lmurDiv.style.visibility = '';
  1576. }
  1577.  
  1578. function lmurMouseInUI()
  1579. {
  1580. lmurShowTrace('lmurMouseInUI()');
  1581. lmurInhibitCacheRefresh = true;
  1582. }
  1583. function lmurMouseOutUI()
  1584. {
  1585. lmurShowTrace('lmurMouseOutUI()');
  1586. lmurInhibitCacheRefresh = false;
  1587. }
  1588.  
  1589. function lmurChangeDecayPeriod()
  1590. {
  1591. lmurShowTrace('lmurChangeDecayPeriod()');
  1592. var userDecayValue = document.getElementById('_inputCacheDecayPeriod').value;
  1593. lmurCacheExpiryPeriod = (parseInt(userDecayValue) * 60);
  1594. }
  1595.  
  1596. function lmurCheckActivation()
  1597. {
  1598. lmurShowTrace('lmurCheckActivation()');
  1599. lmurEnabled = lmurGetCBChecked('_cbEnableLMUR');
  1600.  
  1601. var mapObj = document.getElementById("map");
  1602. mapObj.onmouseup = null;
  1603. mapObj.onmousedown = null;
  1604.  
  1605. if
  1606. (
  1607. ((lmurGetCBChecked('_cbEnablePlayMode')) && (!lmurPlayModeEnabled)) ||
  1608. ((!lmurGetCBChecked('_cbEnablePlayMode')) && (lmurPlayModeEnabled))
  1609. )
  1610. {
  1611. lmurInhibitCacheRefresh = false;
  1612. lmurResetCaches();
  1613. }
  1614. lmurPlayModeEnabled = lmurGetCBChecked('_cbEnablePlayMode');
  1615.  
  1616. lmurLSPUpdate();
  1617. lmurLOPUpdate();
  1618. lmurLMPUpdate();
  1619.  
  1620. if
  1621. (
  1622. (!lmurGetCBChecked('_cbShowURs')) &&
  1623. (!lmurGetCBChecked('_cbShowProblems')) &&
  1624. (!lmurGetCBChecked('_cbShowTurnProbs')) &&
  1625. (!lmurGetCBChecked('_cbShowPlaceUpdates'))
  1626. )
  1627. {
  1628. lmurDiv.innerHTML = lmurModifyHTML('');
  1629. return;
  1630. }
  1631.  
  1632. lmurNoForcedRefreshThisCycle = false;
  1633. lmurAddLog('re-visualising after CheckActivation call');
  1634.  
  1635. lmurUpdateRequestQueue();
  1636. if(lmurDownloadRequests.length === 0) lmurVisualiseMarkers();
  1637.  
  1638. mapObj.onmouseup = lmurEndDrag;
  1639. mapObj.onmousedown = lmurInitDrag;
  1640. }
  1641. var lmurLSPObserver = new MutationObserver(function(mutations)
  1642. {
  1643. lmurLSPUpdate();
  1644. });
  1645. function lmurLSPUpdate()
  1646. {
  1647. var lsp = document.getElementsByClassName('leaflet-shadow-pane');
  1648. if(lsp.length > 0)
  1649. {
  1650. lmurLSPObserver.disconnect();
  1651. if(lmurGetCBChecked('_cbHideNativeMarkers'))
  1652. {
  1653. lsp[0].style.visibility = 'hidden';
  1654. }
  1655. else
  1656. {
  1657. lsp[0].style.visibility = '';
  1658. }
  1659. lmurLSPObserver.observe(lsp[0], { childList: true, subtree: true });
  1660. }
  1661. }
  1662. var lmurLOPObserver = new MutationObserver(function(mutations)
  1663. {
  1664. lmurLOPUpdate();
  1665. });
  1666. function lmurLOPUpdate()
  1667. {
  1668. var lop = document.getElementsByClassName('leaflet-overlay-pane');
  1669. if(lop.length > 0)
  1670. {
  1671. lmurLOPObserver.disconnect();
  1672. if(lmurGetCBChecked('_cbHideNativeMarkers'))
  1673. {
  1674. for(let p of lop[0].getElementsByTagName("path"))
  1675. {
  1676. if
  1677. (
  1678. (p.classList.contains("wm-route") === false) &&
  1679. (p.classList.contains("wm-jam-layer__outline--closure") === false) &&
  1680. (p.classList.contains("wm-jam-layer__bg--closure") === false) &&
  1681. (p.classList.contains("wm-jam-layer__dotted--closure") === false)
  1682. )
  1683. {
  1684. p.setAttribute("visibility", "hidden");
  1685. }
  1686. }
  1687. }
  1688. else
  1689. {
  1690. for(let p of lop[0].getElementsByTagName("path"))
  1691. {
  1692. p.setAttribute("visibility", "");
  1693. }
  1694. }
  1695. lmurLOPObserver.observe(lop[0], { childList: true, subtree: true });
  1696. }
  1697. }
  1698. var lmurLMPObserver = new MutationObserver(function(mutations)
  1699. {
  1700. lmurLMPUpdate();
  1701. });
  1702. function lmurLMPUpdate()
  1703. {
  1704. var lmp = document.getElementsByClassName('leaflet-marker-pane');
  1705. if(lmp.length > 0)
  1706. {
  1707. lmurLMPObserver.disconnect();
  1708. if(lmurGetCBChecked('_cbHideNativeMarkers'))
  1709. {
  1710. for(let m of lmp[0].getElementsByTagName("div"))
  1711. {
  1712. if
  1713. (
  1714. (m.classList.contains("wm-user-icon") === true) ||
  1715. (m.classList.contains("wm-alert-icon") === true) ||
  1716. (m.classList.contains("wm-alert-cluster-icon") === true)
  1717. )
  1718. {
  1719. m.style.visibility = "hidden";
  1720. }
  1721. }
  1722. }
  1723. else
  1724. {
  1725. for(let m of lmp[0].getElementsByTagName("div"))
  1726. {
  1727. m.style.visibility = "";
  1728. }
  1729. }
  1730. lmurLMPObserver.observe(lmp[0], { childList: true, subtree: true });
  1731. }
  1732. }
  1733. function lmurDateToDays(dateToConvert)
  1734. {
  1735. lmurShowTrace('lmurDateToDays('+dateToConvert+')');
  1736. if(dateToConvert === 0)
  1737. {
  1738. return 999999;
  1739. }
  1740.  
  1741. var dateNow = new Date();
  1742.  
  1743. var elapsedSinceEpoch = dateNow.getTime();
  1744. var elapsedSinceEvent = elapsedSinceEpoch - dateToConvert;
  1745.  
  1746. dateNow.setHours(0);
  1747. dateNow.setMinutes(0);
  1748. dateNow.setSeconds(0);
  1749. dateNow.setMilliseconds(0);
  1750.  
  1751. var elapsedSinceMidnight = elapsedSinceEpoch - dateNow.getTime();
  1752.  
  1753. if(elapsedSinceEvent < elapsedSinceMidnight)
  1754. {
  1755. // event occurred today...
  1756. return 0;
  1757. }
  1758. else
  1759. {
  1760. // event occurred at some point prior to midnight this morning, so return a minimum value of 1...
  1761. return 1 + Math.floor((elapsedSinceEvent - elapsedSinceMidnight) / 86400000);
  1762. }
  1763. }
  1764.  
  1765. function lmurGetURAge(urObj,whichAgeToGet)
  1766. {
  1767. lmurShowTrace('lmurGetURAge([urObj],'+whichAgeToGet+')');
  1768. var uroDate = -1;
  1769. if(whichAgeToGet === 0)
  1770. {
  1771. if(urObj.driveDate !== null)
  1772. {
  1773. uroDate = urObj.driveDate;
  1774. return lmurDateToDays(uroDate);
  1775. }
  1776. else return 999999;
  1777. }
  1778. else if(whichAgeToGet == 1)
  1779. {
  1780. if(urObj.updatedOn !== null)
  1781. {
  1782. uroDate = urObj.updatedOn;
  1783. return lmurDateToDays(uroDate);
  1784. }
  1785. else return 999999;
  1786. }
  1787. else if(whichAgeToGet == 2)
  1788. {
  1789. if((urObj.resolvedOn !== undefined) && (urObj.resolvedOn !== null))
  1790. {
  1791. uroDate = urObj.resolvedOn;
  1792. return lmurDateToDays(uroDate);
  1793. }
  1794. else return 999999;
  1795. }
  1796. else if(whichAgeToGet == 3)
  1797. {
  1798. if((urObj.venueUpdateRequests.length > 0) && (urObj.venueUpdateRequests[0].dateAdded !== undefined))
  1799. {
  1800. uroDate = urObj.venueUpdateRequests[0].dateAdded;
  1801. return lmurDateToDays(uroDate);
  1802. }
  1803. else return 999999;
  1804. }
  1805. else return 999999;
  1806. }
  1807.  
  1808. function lmurParseDaysAgo(days)
  1809. {
  1810. lmurShowTrace('lmurParseDaysAgo('+days+')');
  1811. if(days === 0) return 'today';
  1812. else if(days == 1) return '1 day ago';
  1813. else return days+' days ago';
  1814. }
  1815.  
  1816. function lmurGetMarkerUnderPointer(mouseX, mouseY)
  1817. {
  1818. var urpos = new L.LatLng(0,0);
  1819. var urpix;
  1820. var retval = null;
  1821. var ureq;
  1822.  
  1823. for(var i=0;i<lmurMarkers.length;i++)
  1824. {
  1825. if(!lmurMarkers[i].markerHidden)
  1826. {
  1827. ureq = lmurMarkers[i];
  1828. urpos.lng = ureq.pos.lng;
  1829. urpos.lat = ureq.pos.lat;
  1830. urpix = lmurLatLonToPix(urpos);
  1831. if(lmurMarkers[i].type == T_MARKER.UR)
  1832. {
  1833. if((mouseX >= urpix.x - 5) && (mouseX < urpix.x + 10) && (mouseY >= urpix.y - 5) && (mouseY < urpix.y + 10))
  1834. {
  1835. retval = i;
  1836. break;
  1837. }
  1838. }
  1839. else
  1840. {
  1841. if((mouseX >= urpix.x - 5) && (mouseX < urpix.x + 5) && (mouseY >= urpix.y - 10) && (mouseY < urpix.y + 5))
  1842. {
  1843. retval = i;
  1844. break;
  1845. }
  1846. }
  1847. }
  1848. }
  1849.  
  1850. return retval;
  1851. }
  1852.  
  1853. function lmurCheckClickOnMarker(e)
  1854. {
  1855. lmurShowTrace('lmurCheckClickOnMarker([e])');
  1856. if(!lmurEnabled)
  1857. {
  1858. return;
  1859. }
  1860.  
  1861. var mouseX = e.pageX;
  1862. var mouseY = e.pageY;
  1863. var markerIdx = lmurGetMarkerUnderPointer(mouseX, mouseY);
  1864. if(markerIdx != null)
  1865. {
  1866. var url = 'https://www.waze.com/editor?zoom=5';
  1867. url += '&lat=' + lmurMarkers[markerIdx].pos.lat;
  1868. url += '&lon=' + lmurMarkers[markerIdx].pos.lng;
  1869.  
  1870. if(lmurMarkers[markerIdx].type == T_MARKER.UR)
  1871. {
  1872. url += '&s=85980435&mapUpdateRequest=' + lmurMarkers[markerIdx].obj.id;
  1873. }
  1874. else if((lmurMarkers[markerIdx].type == T_MARKER.MP) || (lmurMarkers[markerIdx].type == T_MARKER.MP200))
  1875. {
  1876. url += '&s=85980423&mapProblem=' + encodeURIComponent(lmurMarkers[markerIdx].obj.id);
  1877. }
  1878. else if(lmurMarkers[markerIdx].type == T_MARKER.PUR)
  1879. {
  1880. url += '&s=1159724501&showpur=' + lmurMarkers[markerIdx].obj.id + '&endshow';
  1881. }
  1882. else
  1883. {
  1884. url = null;
  1885. }
  1886. if(url != null)
  1887. {
  1888. window.open(url);
  1889. }
  1890. }
  1891. return lmurCancelEvent(e);
  1892. }
  1893.  
  1894. function lmurCheckOverMarker(e)
  1895. {
  1896. lmurShowTrace('lmurCheckOverMarker([e])');
  1897. if(!lmurEnabled)
  1898. {
  1899. return;
  1900. }
  1901.  
  1902. var mouseX = e.pageX;
  1903. var mouseY = e.pageY;
  1904.  
  1905. var markerIdx = lmurGetMarkerUnderPointer(mouseX, mouseY);
  1906. var result = '';
  1907. if(markerIdx != null)
  1908. {
  1909. var ureq = lmurMarkers[markerIdx].obj;
  1910. var urAge = lmurGetMarkerAge(lmurMarkers[markerIdx]);
  1911. if(urAge === null) urAge = '>'+lmurCacheExpiryPeriod;
  1912. var daysOld;
  1913.  
  1914. if(lmurMarkers[markerIdx].type == T_MARKER.UR)
  1915. {
  1916. var ureqTypeText;
  1917. if(ureq.type == 6) ureqTypeText = "Incorrect turn";
  1918. else if(ureq.type == 7) ureqTypeText = "Incorrect address";
  1919. else if(ureq.type == 8) ureqTypeText = "Incorrect route";
  1920. else if(ureq.type == 9) ureqTypeText = "Missing roundabout";
  1921. else if(ureq.type == 10) ureqTypeText = "General error";
  1922. else if(ureq.type == 11) ureqTypeText = "Turn not allowed";
  1923. else if(ureq.type == 12) ureqTypeText = "Incorrect junction";
  1924. else if(ureq.type == 13) ureqTypeText = "Missing bridge overpass";
  1925. else if(ureq.type == 14) ureqTypeText = "Wrong driving direction";
  1926. else if(ureq.type == 15) ureqTypeText = "Missing exit";
  1927. else if(ureq.type == 16) ureqTypeText = "Missing road";
  1928. else if(ureq.type == 19) ureqTypeText = "Blocked road";
  1929. else ureqTypeText = "Unknown";
  1930.  
  1931. result = '<b>Update Request: ' + ureqTypeText + '</b>';
  1932. result += '<br>ID: ' + ureq.id;
  1933. if(ureq.description !== null)
  1934. {
  1935. result += '<br>' + ureq.description.replace(/<\/?[^>]+(>|$)/g, "");
  1936. }
  1937. daysOld = lmurGetURAge(ureq,0);
  1938. if(daysOld != 999999)
  1939. {
  1940. result += '<br><i>Submitted ' + lmurParseDaysAgo(daysOld) + '</i>';
  1941. }
  1942. daysOld = lmurGetURAge(ureq,2);
  1943. if(daysOld != 999999)
  1944. {
  1945. result += '<br><i>Resolved ' + lmurParseDaysAgo(daysOld) + '</i>';
  1946. }
  1947.  
  1948. var nComments = lmurMarkers[markerIdx].nComments;
  1949. if(nComments == -1)
  1950. {
  1951. result += '<br><i>Waiting for comment data...</i>';
  1952. }
  1953. else
  1954. {
  1955. result += '<br><i>UR has ' + nComments + ' comment';
  1956. if(nComments != 1) result += 's';
  1957. result += '</i>';
  1958. }
  1959. result += '<br><small>(Data refreshed '+urAge+'s ago)</small>';
  1960. }
  1961. else
  1962. {
  1963. if((lmurMarkers[markerIdx].type == T_MARKER.MP)||(lmurMarkers[markerIdx].type == T_MARKER.MP200))
  1964. {
  1965. if(ureq.subType == 200)
  1966. {
  1967. result = '<b>Turn Problem: ';
  1968. }
  1969. else
  1970. {
  1971. result = '<b>Map Problem: ';
  1972. }
  1973. if(ureq.subType == 101) result += 'Driving direction mismatch';
  1974. else if(ureq.subType == 102) result += 'Missing junction';
  1975. else if(ureq.subType == 103) result += 'Missing road';
  1976. else if(ureq.subType == 104) result += 'Cross roads junction missing';
  1977. else if(ureq.subType == 105) result += 'Road type mismatch';
  1978. else if(ureq.subType == 106) result += 'Restricted turn might be allowed';
  1979. else if(ureq.subType == 200) result += 'The displayed route is frequently not taken by users';
  1980. else if(ureq.subType == 300) result += 'Road closure request';
  1981. else result += 'Unknown problem type ('+ureq.subType+')';
  1982. result += '</b><br>';
  1983. if(ureq.priority <= 3) result += 'Severity: Low';
  1984. else if(ureq.priority <= 7) result += 'Severity: Medium';
  1985. else result += 'Severity: High';
  1986. }
  1987. else if(lmurMarkers[markerIdx].type == T_MARKER.PUR)
  1988. {
  1989. result = '<b>Place Update</b><br>';
  1990. var putype;
  1991. for(var loop=0; loop<ureq.venueUpdateRequests.length; loop++)
  1992. {
  1993. putype = ureq.venueUpdateRequests[loop].type;
  1994. result += 'Type: ';
  1995. if(putype == 'VENUE') result += 'New place';
  1996. else if(putype == 'IMAGE') result += 'New Photo';
  1997. else if(putype == 'REQUEST') result += 'Change Details';
  1998. else result += putype;
  1999. result += '<br>';
  2000. }
  2001. daysOld = lmurGetURAge(ureq,3);
  2002. if(daysOld != 999999)
  2003. {
  2004. result += '<br><i>Received ' + lmurParseDaysAgo(daysOld) + '</i>';
  2005. }
  2006. }
  2007. daysOld = lmurGetURAge(ureq,2);
  2008. if(daysOld != 999999)
  2009. {
  2010. result += '<br><i>Resolved ' + lmurParseDaysAgo(daysOld) + '</i>';
  2011. }
  2012. result += '<br><small>(Data refreshed '+urAge+'s ago)</small>';
  2013. }
  2014. }
  2015. if(result === '')
  2016. {
  2017. lmurPopup.style.visibility = 'hidden';
  2018. }
  2019. else if(lmurPopup.style.visibility == 'hidden')
  2020. {
  2021. lmurPopup.innerHTML = lmurModifyHTML(result);
  2022. var posX = mouseX;
  2023. var posY = mouseY;
  2024. var vpSize = lmurGetVPSize();
  2025. if((posX + lmurPopup.clientWidth) > vpSize.x) posX = vpSize.x - lmurPopup.clientWidth;
  2026. if((posY + lmurPopup.clientHeight + 10) > vpSize.y) posY = vpSize.y - lmurPopup.clientHeight - 10;
  2027. else posY += 10;
  2028. lmurPopup.style.left = posX + 'px';
  2029. lmurPopup.style.top = posY + 'px';
  2030. lmurPopup.style.visibility = 'visible';
  2031. }
  2032. }
  2033.  
  2034. function lmurToggleDebug()
  2035. {
  2036. lmurShowTrace('lmurToggleDebug()');
  2037. lmurShowDebugOutput = !lmurShowDebugOutput;
  2038. var dbgMode = "none";
  2039. if(lmurShowDebugOutput)
  2040. {
  2041. dbgMode = "inline";
  2042. }
  2043. document.getElementById('_lmurDebugMode').style.display = dbgMode;
  2044. }
  2045.  
  2046. function lmurDumpDebug()
  2047. {
  2048. lmurShowTrace('lmurDumpDebug()');
  2049. var debug = '';
  2050. for(var i=0;i<lmurMarkers.length;i++)
  2051. {
  2052. var ureq = lmurMarkers[i];
  2053. debug += ureq.pos.lng+',';
  2054. debug += ureq.pos.lat+',';
  2055. debug += ureq.type+',';
  2056. debug += ureq.nComments+',';
  2057. if(ureq.obj.resolvedOn === null) debug += '1<br>';
  2058. else debug += '0<br>';
  2059. }
  2060. document.body.innerHTML = lmurModifyHTML(debug);
  2061. }
  2062.  
  2063. function lmurUpdateHeader()
  2064. {
  2065. lmurShowTrace('lmurUpdateHeader()');
  2066. if(document.getElementById('lmurHeader') === null)
  2067. {
  2068. window.setTimeout(lmurUpdateHeader,100);
  2069. return;
  2070. }
  2071.  
  2072. lmurUpdateURL = 'https://greasyfork.org/en/scripts/1948-livemap-ur-overlay';
  2073.  
  2074. var tHTML = '<img id="_minimax" align=left valign=middle src="';
  2075. if(!lmurControlsHidden)
  2076. {
  2077. tHTML += lmurIcons[0];
  2078. }
  2079. else
  2080. {
  2081. tHTML += lmurIcons[1];
  2082. }
  2083. tHTML += '"/>';
  2084. tHTML += '<b><a href="'+lmurUpdateURL+'" target="_blank">LMUR</a></b> <label id="_lmurVersion">v'+lmurVersion+'</label>';
  2085. tHTML += '<label id="_lmurDebugMode">(dbg)</label>';
  2086.  
  2087. tHTML += '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" id="_cbEnableLMUR"';
  2088. if(lmurEnabled) tHTML += ' checked';
  2089. tHTML += '>Enabled</a>';
  2090. lmurDragBar.innerHTML = lmurModifyHTML(tHTML);
  2091. var dbgMode = "none";
  2092. if(lmurShowDebugOutput)
  2093. {
  2094. dbgMode = "inline";
  2095. }
  2096. document.getElementById('_lmurDebugMode').style.display = dbgMode;
  2097. document.getElementById('_cbEnableLMUR').addEventListener("click", lmurCheckActivation, true);
  2098. document.getElementById('_lmurVersion').addEventListener("click", lmurToggleDebug, true);
  2099. document.getElementById('_lmurDebugMode').addEventListener("dblclick", lmurDumpDebug, true);
  2100. }
  2101.  
  2102. function lmurShowHideCtrls(tab)
  2103. {
  2104. lmurShowTrace('lmurShowHideCtrls('+tab+')');
  2105. if(lmurControlsMinimised[tab])
  2106. {
  2107. lmurControlsMinimised[tab] = false;
  2108. document.getElementById(lmurControlsID[tab]).style.height = 'auto';
  2109. document.getElementById(lmurControlsID[tab]).style.overflow = 'visible';
  2110. document.getElementById(lmurControlsImg[tab]).src = lmurIcons[0];
  2111. }
  2112. else
  2113. {
  2114. lmurControlsMinimised[tab] = true;
  2115. document.getElementById(lmurControlsID[tab]).style.height = '0px';
  2116. document.getElementById(lmurControlsID[tab]).style.overflow = 'hidden';
  2117. document.getElementById(lmurControlsImg[tab]).src = lmurIcons[1];
  2118. }
  2119. lmurInnerHeight = -1;
  2120. lmurShowControls();
  2121. }
  2122.  
  2123. function lmurShowHideURCtrls()
  2124. {
  2125. lmurShowTrace('lmurShowHideURCtrls()');
  2126. lmurShowHideCtrls(0);
  2127. }
  2128.  
  2129. function lmurShowHideMPCtrls()
  2130. {
  2131. lmurShowTrace('lmurShowHideMPCtrls()');
  2132. lmurShowHideCtrls(1);
  2133. }
  2134.  
  2135. function lmurShowHidePURCtrls()
  2136. {
  2137. lmurShowTrace('lmurShowHidePURCtrls()');
  2138. lmurShowHideCtrls(2);
  2139. }
  2140.  
  2141. function lmurShowHideOptions()
  2142. {
  2143. lmurShowTrace('lmurShowHideOptions()');
  2144. lmurShowHideCtrls(3);
  2145. }
  2146.  
  2147. function lmurShowControls()
  2148. {
  2149. lmurShowTrace('lmurShowControls()');
  2150. lmurControlsHidden = false;
  2151. lmurUpdateHeader();
  2152. document.getElementById('_minimax').addEventListener('click', lmurHideControls, false);
  2153.  
  2154. if(window.innerHeight != lmurInnerHeight)
  2155. {
  2156. lmurInnerHeight = window.innerHeight;
  2157. var htop = document.getElementsByClassName('leaflet-top')[0].offsetTop + document.getElementById('lmurHeader').offsetTop + 10;
  2158. var hmax = window.innerHeight - htop - 100;
  2159. document.getElementById('lmurCtrls').style.height = 'auto';
  2160. document.getElementById('lmurCtrls').style.height = document.getElementById('lmurCtrls').clientHeight + 1 + 'px';
  2161.  
  2162. if(document.getElementById('lmurCtrls').clientHeight > hmax)
  2163. {
  2164. document.getElementById('lmurCtrls').style.height = hmax+'px';
  2165. }
  2166. lmurUIHeight = document.getElementById('lmurCtrls').style.height;
  2167. document.getElementById('lmurCtrls').scrollTop = 0;
  2168. }
  2169. else
  2170. {
  2171. document.getElementById('lmurCtrls').style.height = lmurUIHeight;
  2172. }
  2173. document.getElementById('lmurCtrls').style.overflow = 'auto';
  2174. }
  2175.  
  2176. function lmurHideControls()
  2177. {
  2178. lmurShowTrace('lmurHideControls()');
  2179. lmurControlsHidden = true;
  2180. lmurUpdateHeader();
  2181. document.getElementById('_minimax').addEventListener('click', lmurShowControls, false);
  2182.  
  2183. document.getElementById('lmurCtrls').style.height = '0px';
  2184. document.getElementById('lmurCtrls').style.overflow = 'hidden';
  2185. }
  2186.  
  2187. function lmurAddCheckbox(id, text, addbr)
  2188. {
  2189. var retval = '<input type="checkbox" id="' + id + '">' + text + '</input>';
  2190. if(addbr) retval += '<br>';
  2191. return retval;
  2192. }
  2193. function lmurAddNumInput(id, text, min, size, addbr)
  2194. {
  2195. var retval = '<input type="number" min="' + min +'" size="' + size + '" id="' + id + '"> ' + text;
  2196. if(addbr) retval += '<br>';
  2197. return retval;
  2198. }
  2199. function lmurAddTextInput(id, text, addbr)
  2200. {
  2201. var retval = '<input type="text" id="' + id + '"> ' + text;
  2202. if(addbr) retval += '<br>';
  2203. return retval;
  2204. }
  2205. function lmurAddRadioBtn(id, group, text, ischecked, addbr)
  2206. {
  2207. var retval = '<input type="radio" name="' + group + '" id="' + id + '"';
  2208. if(ischecked) retval += ' checked';
  2209. retval += '/>' + text;
  2210. if (addbr) retval += '<br>';
  2211. return retval;
  2212. }
  2213.  
  2214. function lmurRemoveWazeStyling()
  2215. {
  2216. var elm = null;
  2217. var myStyle = '';
  2218.  
  2219. for(var i = 0; i < document.getElementById('lmurUI').getElementsByTagName('input').length; i++)
  2220. {
  2221. elm = document.getElementById('lmurUI').getElementsByTagName('input')[i];
  2222. myStyle = "opacity:1;position:relative;padding:0 0;color:#000000;";
  2223. if(elm.type == "number") myStyle += "width:50px;height:auto;";
  2224. else if(elm.type == "text") myStyle += "line-height:14px;height:auto;margin-bottom:4px;";
  2225. elm.style = myStyle;
  2226. }
  2227. }
  2228.  
  2229. var lmurDragging = false;
  2230. var lmurPrevMouseX;
  2231. var lmurPrevMouseY;
  2232. var lmurWindowLeft = 0;
  2233. var lmurWindowTop = 0;
  2234.  
  2235. function lmurCancelEvent(e)
  2236. {
  2237. e = e ? e : window.event;
  2238. if(e.stopPropagation)
  2239. {
  2240. e.stopPropagation();
  2241. }
  2242. if(e.preventDefault)
  2243. {
  2244. e.preventDefault();
  2245. }
  2246. e.cancelBubble = true;
  2247. e.cancel = true;
  2248. e.returnValue = false;
  2249. return false;
  2250. }
  2251. function lmurDragbarMouseDown(e)
  2252. {
  2253. lmurPrevMouseX = e.pageX;
  2254. lmurPrevMouseY = e.pageY;
  2255. lmurDragging = true;
  2256. //lmurDragBar.style.cursor = 'move';
  2257. document.body.addEventListener('mousemove', lmurDragbarMouseMove, false);
  2258. document.body.addEventListener('mouseup', lmurDragbarMouseUp, false);
  2259. return true;
  2260. }
  2261. function lmurDragbarMouseUp()
  2262. {
  2263. if(lmurDragging)
  2264. {
  2265. lmurDragging = false;
  2266. localStorage.LMURWindowLeft = lmurWindowLeft;
  2267. localStorage.LMURWindowTop = lmurWindowTop;
  2268. }
  2269. //lmurDragBar.style.cursor = 'auto';
  2270. document.body.removeEventListener('mousemove', lmurDragbarMouseMove, false);
  2271. document.body.removeEventListener('mouseup', lmurDragbarMouseUp, false);
  2272. return true;
  2273. }
  2274. function lmurDragbarMouseMove(e)
  2275. {
  2276. var vpHeight = window.innerHeight;
  2277. var vpWidth = window.innerWidth;
  2278.  
  2279. lmurWindowTop = parseInt(lmurWindowTop) + parseInt((e.pageY - lmurPrevMouseY));
  2280. lmurWindowLeft = parseInt(lmurWindowLeft) + parseInt((e.pageX - lmurPrevMouseX));
  2281. lmurPrevMouseX = e.pageX;
  2282. lmurPrevMouseY = e.pageY;
  2283.  
  2284. if(lmurWindowTop < 0) lmurWindowTop = 0;
  2285. if(lmurWindowTop + 16 >= vpHeight) lmurWindowTop = vpHeight-16;
  2286. if(lmurWindowLeft < 0) lmurWindowLeft = 0;
  2287. if(lmurWindowLeft + 32 >= vpWidth) lmurWindowLeft = vpWidth-32;
  2288.  
  2289. lmurWindow.style.top = lmurWindowTop+'px';
  2290. lmurWindow.style.left = lmurWindowLeft+'px';
  2291. return lmurCancelEvent(e);
  2292. }
  2293.  
  2294. function lmurAddUIHeaderStyle(uID, bgCol)
  2295. {
  2296. var uObj = document.getElementById(uID);
  2297. uObj.style.backgroundColor = bgCol;
  2298. uObj.style.padding = "10px";
  2299. uObj.style.height = "auto";
  2300. }
  2301. function lmurAddUIColStyle(uID, bgCol)
  2302. {
  2303. var uObj = document.getElementById(uID);
  2304. uObj.style.float = "left";
  2305. uObj.style.paddingLeft = "10px";
  2306. uObj.style.paddingRight = "10px";
  2307. uObj.style.height = "auto";
  2308. if(bgCol != null)
  2309. {
  2310. uObj.style.backgroundColor = bgCol;
  2311. }
  2312. }
  2313. function lmurAddUIDivSepStyle(uID)
  2314. {
  2315. var uObj = document.getElementById(uID);
  2316. uObj.style.clear = "both";
  2317. }
  2318. function lmurAddUIStyles()
  2319. {
  2320. if(document.getElementById("lmurCtrls") == null)
  2321. {
  2322. window.setTimeout(lmurAddUIStyles, 100);
  2323. return;
  2324. }
  2325. lmurAddUIHeaderStyle("lmurURCtrlOuter", "#DDFFDD");
  2326. lmurAddUIHeaderStyle("lmurMPCtrlOuter", "#DDDDFF");
  2327. lmurAddUIHeaderStyle("lmurPURCtrlOuter", "#FFDDDD");
  2328. lmurAddUIHeaderStyle("lmurOptionsOuter", "#EEEEEE");
  2329. lmurAddUIColStyle("lmurURCtrls_lCol", null);
  2330. lmurAddUIColStyle("lmurURCtrls_rCol", null);
  2331. lmurAddUIColStyle("lmurMPCtrls_lCol", null);
  2332. lmurAddUIColStyle("lmurMPCtrls_mCol", null);
  2333. lmurAddUIColStyle("lmurMPCtrls_rCol", null);
  2334. lmurAddUIColStyle("lmurPURCtrls_lCol", null);
  2335. lmurAddUIColStyle("lmurURCtrls_Tags_lCol", "#CCEECC");
  2336. lmurAddUIColStyle("lmurURCtrls_Tags_lCol", "#CCEECC");
  2337. lmurAddUIDivSepStyle("lmurURCtrls_DivSep1");
  2338. lmurAddUIDivSepStyle("lmurURCtrls_DivSep2");
  2339. lmurAddUIDivSepStyle("lmurURCtrls_DivSep3");
  2340. lmurAddUIDivSepStyle("lmurURCtrls_DivSep4");
  2341. }
  2342.  
  2343. function lmurEnhanceRouteDetails()
  2344. {
  2345. var ri = document.getElementsByClassName('wm-routes-item-desktop');
  2346. if(ri.length > 0)
  2347. {
  2348. RouteObserver.disconnect();
  2349.  
  2350. var lra = document.getElementsByClassName('lmurAreas');
  2351. var nLRA = lra.length;
  2352. while(nLRA > 0)
  2353. {
  2354. --nLRA;
  2355. document.getElementsByClassName('lmurAreas')[nLRA].remove();
  2356. }
  2357.  
  2358. var rIdx = 0;
  2359. for(let r of ri)
  2360. {
  2361. var rString;
  2362.  
  2363. var routeTime = lmurRouteDetails[rIdx].rTime;
  2364. var rtS = routeTime % 60;
  2365. routeTime -= rtS;
  2366. routeTime /= 60;
  2367. var rtM = routeTime % 60;
  2368. routeTime -= rtM;
  2369. routeTime /= 60;
  2370. var rtH = routeTime % 24;
  2371. routeTime -= rtH;
  2372. routeTime /= 24;
  2373. rString = rtH + "h " + rtM + "m " + rtS + "s";
  2374. r.childNodes[0].childNodes[1].childNodes[0].innerText = rString;
  2375.  
  2376. var rDist = lmurRouteDetails[rIdx].rDist;
  2377. rString = (Math.round(rDist / 10) / 100) + 'km / ';
  2378. rDist /= 1.609;
  2379. rString += (Math.round(rDist / 10) / 100) + 'miles';
  2380. r.childNodes[1].childNodes[0].childNodes[1].innerText = rString;
  2381.  
  2382. var nAreas = lmurRouteDetails[rIdx].rAreas.length;
  2383. if(nAreas > 0)
  2384. {
  2385. var tSpan = document.createElement('span');
  2386. tSpan.className = "lmurAreas";
  2387. var iHTML = '<br>';
  2388. for(var i = 0; i < nAreas; ++i)
  2389. {
  2390. iHTML += lmurRouteDetails[rIdx].rAreas[i] + '<br>';
  2391. }
  2392. tSpan.innerHTML = lmurModifyHTML(iHTML);
  2393. r.childNodes[1].appendChild(tSpan);
  2394. }
  2395. ++rIdx;
  2396. }
  2397. RouteObserver.observe(document.getElementsByClassName('wm-card is-routing')[0], { childList: true, subtree: true });
  2398. }
  2399. }
  2400. var RouteObserver = new MutationObserver(function(mutations)
  2401. {
  2402. if(lmurRouteDetails.length > 0)
  2403. {
  2404. // Call this here in case our request promise handler fired before the native one, such
  2405. // that we already have the info required to enhance the default route details which we
  2406. // now know will be present in the DOM...
  2407. lmurEnhanceRouteDetails();
  2408. }
  2409.  
  2410. });
  2411. function lmurFakeOnload()
  2412. {
  2413. lmurShowTrace('lmurFakeOnload()');
  2414.  
  2415. lmurAddLog('onload');
  2416.  
  2417. if(document.getElementById('lmurUI') === null)
  2418. {
  2419. lmurAddLog(' adding lmurUI container...');
  2420.  
  2421. // add a new div to hold the OS Locator results, in the form of a draggable window
  2422. lmurWindow = document.createElement('div');
  2423. lmurWindow.id = "lmurWindow";
  2424. lmurWindow.style.position = 'absolute';
  2425. lmurWindow.style.border = '1px solid #BBDDBB';
  2426. lmurWindow.style.borderRadius = '4px';
  2427. lmurWindow.style.overflow = 'hidden';
  2428. lmurWindow.style.zIndex = 2000;
  2429. lmurWindow.style.opacity = 0;
  2430. lmurWindow.style.transitionProperty = "opacity";
  2431. lmurWindow.style.transitionDuration = "1000ms";
  2432. lmurWindow.style.webkitTransitionProperty = "opacity";
  2433. lmurWindow.style.webkitTransitionDuration = "1000ms";
  2434. lmurWindow.style.boxShadow = '5px 5px 10px Silver';
  2435. document.body.appendChild(lmurWindow);
  2436.  
  2437. // dragbar div
  2438. lmurDragBar = document.createElement('div');
  2439. lmurDragBar.id = "lmurDragBar";
  2440. lmurDragBar.style.backgroundColor = '#D0D0D0';
  2441. lmurDragBar.style.padding = '4px';
  2442. lmurDragBar.style.fontSize = '16px';
  2443. lmurDragBar.style.lineHeight = '18px';
  2444. lmurWindow.appendChild(lmurDragBar);
  2445.  
  2446. lmurWindow.appendChild(lmurUI);
  2447. lmurUI.id = "lmurUI";
  2448. lmurUI.style.lineHeight = '16px';
  2449. lmurUI.style.overflow = 'hidden';
  2450. lmurUI.addEventListener('mouseover', lmurMouseInUI, false);
  2451. lmurUI.addEventListener('mouseout', lmurMouseOutUI, false);
  2452. lmurDragBar.addEventListener('mousedown', lmurDragbarMouseDown, false);
  2453. lmurDragBar.addEventListener('mouseup', lmurDragbarMouseUp, false);
  2454.  
  2455. lmurDragBar.innerHTML = lmurModifyHTML('<b>LMUR v'+lmurVersion+'</b>');
  2456. lmurWindow.style.opacity = 1;
  2457.  
  2458. lmurAddLog('...done');
  2459. }
  2460. else
  2461. {
  2462. lmurAddLog(' lmurUI container already present');
  2463. }
  2464.  
  2465. var tHTML;
  2466. if(!lmurIsLoggedIn)
  2467. {
  2468. tHTML = '<b><a href="'+lmurUpdateURL+'" target="_blank">LMUR</a></b> v'+lmurVersion;
  2469. tHTML += ' - Please log-in to the Livemap server to enable LMUR operation.';
  2470. lmurDragBar.innerHTML = lmurModifyHTML(tHTML);
  2471. }
  2472. else if(document.location.protocol == 'https:')
  2473. {
  2474. lmurAddLog(' adding lmurUI contents...');
  2475. var gmapObj = document.getElementById('map');
  2476.  
  2477. gmapObj.addEventListener("mousemove", lmurCheckOverMarker, false);
  2478. gmapObj.addEventListener("click", lmurCheckClickOnMarker, false);
  2479.  
  2480. gmapObj.appendChild(lmurDiv);
  2481. gmapObj.appendChild(lmurPopup);
  2482.  
  2483. tHTML = '<div id="lmurHeader">';
  2484. tHTML += '</div>';
  2485.  
  2486. tHTML += '<div id="lmurCtrls">';
  2487.  
  2488. tHTML += '<div id="lmurURCtrlOuter">';
  2489. tHTML += '<img id="_minimaxURCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>UR Filtering</b>&nbsp;&nbsp;';
  2490. tHTML += lmurAddCheckbox("_cbShowURs", '', true);
  2491. tHTML += '<div id="lmurURCtrls">';
  2492. tHTML += lmurAddRadioBtn("_radioShowURs", "lmurShowURs", 'Show or ', false, false);
  2493. tHTML += lmurAddRadioBtn("_radioHideURs", "lmurShowURs", 'hide URs by type:', true, true);
  2494. tHTML += '<div id="lmurURCtrls_lCol">';
  2495. tHTML += lmurAddCheckbox("_cbURFilterIncorrectTurn", 'Incorrect turn', true);
  2496. tHTML += lmurAddCheckbox("_cbURFilterIncorrectAddress", 'Incorrect address', true);
  2497. tHTML += lmurAddCheckbox("_cbURFilterIncorrectRoute", 'Incorrect route', true);
  2498. tHTML += lmurAddCheckbox("_cbURFilterIncorrectJunction", 'Incorrect junction', true);
  2499. tHTML += lmurAddCheckbox("_cbURFilterWazeAuto", 'Waze Automatic', true);
  2500. tHTML += lmurAddCheckbox("_cbURFilterGeneralError", 'General error', true);
  2501. tHTML += lmurAddCheckbox("_cbURFilterTurnNotAllowed", 'Turn not allowed', true);
  2502. tHTML += lmurAddCheckbox("_cbURFilterUndefined", 'Undefined', true);
  2503. tHTML += '</div>';
  2504. tHTML += '<div id="lmurURCtrls_rCol">';
  2505. tHTML += lmurAddCheckbox("_cbURFilterMissingRoundabout",'Missing roundabout', true);
  2506. tHTML += lmurAddCheckbox("_cbURFilterMissingBridgeOverpass", 'Missing bridge overpass' ,true);
  2507. tHTML += lmurAddCheckbox("_cbURFilterMissingExit", 'Missing exit', true);
  2508. tHTML += lmurAddCheckbox("_cbURFilterMissingRoad", 'Missing road', true);
  2509. tHTML += lmurAddCheckbox("_cbURFilterMissingLandmark", 'Missing landmark', true);
  2510. tHTML += lmurAddCheckbox("_cbURFilterWrongDrivingDirection", 'Wrong driving direction', true);
  2511. tHTML += lmurAddCheckbox("_cbURFilterBlockedRoad", 'Blocked Road', true);
  2512. tHTML += '<br>';
  2513. tHTML += '</div>';
  2514. tHTML += '<div id="lmurURCtrls_DivSep1">';
  2515. tHTML += '</div>';
  2516. tHTML += '<div id="lmurURCtrls_Tags_lCol">';
  2517. tHTML += '<i>Tagged URs</i><br>';
  2518. tHTML += lmurAddCheckbox("_cbURFilterRoadworks", '[ROADWORKS]', true);
  2519. tHTML += lmurAddCheckbox("_cbURFilterConstruction", '[CONSTRUCTION]', true);
  2520. tHTML += lmurAddCheckbox("_cbURFilterNote", '[NOTE]', true);
  2521. tHTML += '</div>';
  2522. tHTML += '<div id="lmurURCtrls_Tags_lCol">';
  2523. tHTML += '<br>';
  2524. tHTML += lmurAddCheckbox("_cbURFilterClosure", '[CLOSURE]', true);
  2525. tHTML += lmurAddCheckbox("_cbURFilterEvent", '[EVENT]', true);
  2526. tHTML += '&nbsp;';
  2527. tHTML += '</div>';
  2528. tHTML += '<div id="lmurURCtrls_DivSep2">';
  2529. tHTML += '</div>';
  2530. tHTML += '<br>';
  2531. tHTML += lmurAddCheckbox("_cbUREnableResolvedFilter", 'Hide resolved URs', true);
  2532. tHTML += lmurAddCheckbox("_cbUREnableMinAgeFilter", 'Hide URs less than ', false);
  2533. tHTML += lmurAddNumInput("_inputURFilterMinDays", 'days old', 1, 3, true);
  2534. tHTML += lmurAddCheckbox("_cbUREnableMaxAgeFilter", 'Hide URs more than ', false);
  2535. tHTML += lmurAddNumInput("_inputURFilterMaxDays", 'days old', 1, 3, true);
  2536. tHTML += '<br>';
  2537. tHTML += lmurAddCheckbox("_cbURHideWithNoDescription", 'Hide or ', false);
  2538. tHTML += lmurAddCheckbox("_cbURShowWithNoDescription", 'show URs with no description', true);
  2539. tHTML += lmurAddCheckbox("_cbUREnableKeywordMustBePresent", 'Hide URs not including ', false);
  2540. tHTML += lmurAddTextInput("_textURKeywordPresent", 'in their description', true);
  2541. tHTML += lmurAddCheckbox("_cbUREnableKeywordMustBeAbsent", 'Hide URs including ', false);
  2542. tHTML += lmurAddTextInput("_textURKeywordAbsent", 'in their description', true);
  2543. tHTML += lmurAddCheckbox("_cbURCaseInsensitive", 'Case-insensitive matching', true);
  2544. tHTML += '<br><br>Filter URs by comments:<br>';
  2545. tHTML += lmurAddCheckbox("_cbURHideUnloadedComments", 'Hide or ', false);
  2546. tHTML += lmurAddCheckbox("_cbURShowUnloadedComments", 'show URs where comment data has not been received from server', true);
  2547. tHTML += '<br>';
  2548. tHTML += lmurAddCheckbox("_cbURHideWithMyComments", 'Hide or ', false);
  2549. tHTML += lmurAddCheckbox("_cbURShowWithMyComments", 'show URs with comments from me', true);
  2550. tHTML += lmurAddCheckbox("_cbURHideLastCommentByMe", 'Hide or ', false);
  2551. tHTML += lmurAddCheckbox("_cbURShowLastCommentByMe", 'show URs last commented on by me', true);
  2552. tHTML += lmurAddCheckbox("_cbURHideLastCommentByReporter", 'Hide or ', false);
  2553. tHTML += lmurAddCheckbox("_cbURShowLastCommentByReporter", 'show URs last commented on by reporter', true);
  2554. tHTML += lmurAddCheckbox("_cbURHideWithLessThanComments", 'Hide or ', false);
  2555. tHTML += lmurAddCheckbox("_cbURShowWithLessThanComments", 'show with less than ', false);
  2556. tHTML += lmurAddNumInput("_inputFilterMinComments", 'comments', 0, 3, true);
  2557. tHTML += lmurAddCheckbox("_cbURHideFollowedURs", 'Hide or ', false);
  2558. tHTML += lmurAddCheckbox("_cbURShowFollowedURs", 'show URs I\'m following', true);
  2559. tHTML += lmurAddCheckbox("_cbURHideLastCommentAge", 'Hide or ', false);
  2560. tHTML += lmurAddCheckbox("_cbURShowLastCommentAge", 'show if last comment made less than ', false);
  2561. tHTML += lmurAddNumInput("_inputFilterCommentAge", 'days ago', 0, 3, true);
  2562. tHTML += '<br>';
  2563. tHTML += lmurAddCheckbox("_cbEnablePlayMode", 'Show UR markers outside my editable area', true);
  2564. tHTML += '</div>';
  2565. tHTML += '</div>';
  2566.  
  2567. tHTML += '<div id="lmurMPCtrlOuter">';
  2568. tHTML += '<img id="_minimaxMPCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>MP Filtering</b>&nbsp;&nbsp;';
  2569. tHTML += lmurAddCheckbox("_cbShowProblems", '', true);
  2570. tHTML += '<div id="lmurMPCtrls">';
  2571. tHTML += lmurAddRadioBtn("_radioShowProblems", "lmurShowProblems", 'Show or ', false, false);
  2572. tHTML += lmurAddRadioBtn("_radioHideProblems", "lmurShowProblems", 'hide map problems by type:', true, true);
  2573. tHTML += '<div id="lmurMPCtrls_lCol">';
  2574. tHTML += lmurAddCheckbox("_cbMPFilterMissingJunction", 'Missing junction', true);
  2575. tHTML += lmurAddCheckbox("_cbMPFilterMissingRoad", 'Missing road', true);
  2576. tHTML += lmurAddCheckbox("_cbMPFilterCrossroadsJunctionMissing", 'Missing crossroads', true);
  2577. tHTML += '</div>';
  2578. tHTML += '<div id="lmurMPCtrls_mCol">';
  2579. tHTML += lmurAddCheckbox("_cbMPFilterDrivingDirectionMismatch", 'Driving direction mismatch', true);
  2580. tHTML += lmurAddCheckbox("_cbMPFilterRoadTypeMismatch", 'Road type mismatch', true);
  2581. tHTML += lmurAddCheckbox("_cbMPFilterRoadClosure", 'Road closure', true);
  2582. tHTML += '</div>';
  2583. tHTML += '<div id="lmurMPCtrls_rCol">';
  2584. tHTML += lmurAddCheckbox("_cbMPFilterRestrictedTurn", 'Restricted turn might be allowed', true);
  2585. tHTML += lmurAddCheckbox("_cbMPFilterUnknownProblem", 'Unknown problem type', true);
  2586. tHTML += '</div>';
  2587. tHTML += '<div id="lmurURCtrls_DivSep3">';
  2588. tHTML += '</div>';
  2589. tHTML += '<br>';
  2590. tHTML += lmurAddCheckbox("_cbMPEnableResolvedFilter", 'Hide resolved Problems', true);
  2591. tHTML += '<br>';
  2592. tHTML += 'Hide problems by severity:<br>';
  2593. tHTML += lmurAddCheckbox("_cbMPFilterLowSeverity", 'Low', false);
  2594. tHTML += lmurAddCheckbox("_cbMPFilterMediumSeverity", 'Medium', false);
  2595. tHTML += lmurAddCheckbox("_cbMPFilterHighSeverity", 'High', true);
  2596. tHTML += '<br>';
  2597. tHTML += lmurAddCheckbox("_cbShowTurnProbs", 'Show Turn Problems', true);
  2598. tHTML += lmurAddCheckbox("_cbTPEnableResolvedFilter", 'Hide resolved Turn Problems', false);
  2599. tHTML += '</div>';
  2600. tHTML += '</div>';
  2601.  
  2602. tHTML += '<div id="lmurPURCtrlOuter">';
  2603. tHTML += '<img id="_minimaxPURCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>PUR Filtering</b>&nbsp;&nbsp;';
  2604. tHTML += lmurAddCheckbox("_cbShowPlaceUpdates", '', true);
  2605. tHTML += '<div id="lmurPURCtrls">';
  2606. tHTML += lmurAddRadioBtn("_radioShowPURs", "lmurShowPURs", 'Show or ', false, false);
  2607. tHTML += lmurAddRadioBtn("_radioHidePURs", "lmurShowPURs", 'hide PURs by type:', true, true);
  2608. tHTML += '<div id="lmurPURCtrls_lCol">';
  2609. tHTML += lmurAddCheckbox("_cbPURFilterNewPlace", 'New place', true);
  2610. tHTML += lmurAddCheckbox("_cbPURFilterUpdateDetails", 'Updated details', true);
  2611. tHTML += lmurAddCheckbox("_cbPURFilterNewPhoto", 'New photo', true);
  2612. tHTML += lmurAddCheckbox("_cbPURFilterFlagged", 'Flagged for attention', true);
  2613. tHTML += lmurAddCheckbox("_cbPURNonZeroLockRank", 'Non-zero lockRank', true);
  2614. tHTML += '</div>';
  2615. tHTML += '<div id="lmurURCtrls_DivSep4">';
  2616. tHTML += '</div>';
  2617. tHTML += lmurAddCheckbox("_cbPUREnableMinAgeFilter", 'Hide PURs less than ', false);
  2618. tHTML += lmurAddNumInput("_inputPURFilterMinDays", 'days old', 1, 3, true);
  2619. tHTML += lmurAddCheckbox("_cbPUREnableMaxAgeFilter", 'Hide PURs more than ', false);
  2620. tHTML += lmurAddNumInput("_inputPURFilterMaxDays", 'days old', 1, 3, true);
  2621. tHTML += lmurAddCheckbox("_cbPURFilterResidential", 'Hide Residential PURs', true);
  2622. tHTML += lmurAddCheckbox("_cbPURFilterNonResidential", 'Hide Non-residential PURs', true);
  2623. tHTML += '<br>';
  2624. tHTML += '</div>';
  2625. tHTML += '</div>';
  2626.  
  2627. tHTML += '<div id="lmurOptionsOuter">';
  2628. tHTML += '<img id="_minimaxLMURCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>Options</b><br>';
  2629. tHTML += '<div id="lmurOptions">';
  2630. tHTML += 'Select Server: ';
  2631. tHTML += lmurAddRadioBtn("_radioROWServer", "lmurSelectServer", 'RoW ', false, false);
  2632. tHTML += lmurAddRadioBtn("_radioUSAServer", "lmurSelectServer", 'USA ', false, false);
  2633. tHTML += lmurAddRadioBtn("_radioIsraelServer", "lmurSelectServer", 'Israel', false, true);
  2634. tHTML += lmurAddCheckbox("_cbHideNativeMarkers", 'Hide Livemap markers', true);
  2635. tHTML += lmurAddCheckbox("_cbClusteringDisabled", 'Disable marker clustering', true);
  2636. tHTML += lmurAddCheckbox("_cbHighlightDisabled", 'Disable cached area highlight', true);
  2637. tHTML += 'Removed cached blocks after ';
  2638. tHTML += lmurAddNumInput("_inputCacheDecayPeriod", 'minutes', 0, 1440, true);
  2639. tHTML += '<i>(Range is 0-1440 minutes, 0 = never remove)</i>';
  2640. tHTML += '</div>';
  2641. tHTML += '</div>';
  2642.  
  2643. tHTML += '</div>';
  2644.  
  2645. lmurUI.innerHTML = lmurModifyHTML(tHTML);
  2646. lmurAddLog(' ...done');
  2647. lmurUI.style.backgroundColor = '#FFFFFF';
  2648. lmurAddUIStyles();
  2649. lmurShowHideURCtrls();
  2650. lmurShowHideMPCtrls();
  2651. lmurShowHidePURCtrls();
  2652. lmurShowHideOptions();
  2653. lmurHideControls();
  2654. lmurUI.addEventListener("click", lmurCheckActivation, true);
  2655. document.getElementById('_inputCacheDecayPeriod').addEventListener("change", lmurChangeDecayPeriod, true);
  2656. document.getElementById('_radioROWServer').addEventListener("click", lmurChangeServer, true);
  2657. document.getElementById('_radioUSAServer').addEventListener("click", lmurChangeServer, true);
  2658. document.getElementById('_radioIsraelServer').addEventListener("click", lmurChangeServer, true);
  2659.  
  2660. document.getElementById('_minimaxURCtrls').addEventListener("click", lmurShowHideURCtrls, true);
  2661. document.getElementById('_minimaxMPCtrls').addEventListener("click", lmurShowHideMPCtrls, true);
  2662. document.getElementById('_minimaxPURCtrls').addEventListener("click", lmurShowHidePURCtrls, true);
  2663. document.getElementById('_minimaxLMURCtrls').addEventListener("click", lmurShowHideOptions, true);
  2664. lmurPopup.style.visibility = 'hidden';
  2665.  
  2666. lmurLoadSettings();
  2667. lmurCheckActivation();
  2668. lmurRemoveWazeStyling();
  2669. }
  2670. else
  2671. {
  2672. tHTML = '<b><a href="'+lmurUpdateURL+'" target="_blank">LMUR</a></b> v'+lmurVersion;
  2673. tHTML += ' - requires a HTTPS connection, please click ';
  2674. tHTML += '<a href="https://' + document.location.host + document.location.pathname + '">here</a> to switch';
  2675. lmurDragBar.innerHTML = lmurModifyHTML(tHTML);
  2676. }
  2677.  
  2678. if
  2679. (
  2680. (localStorage.LMURWindowTop === undefined)||
  2681. (localStorage.LMURWindowLeft === undefined)||
  2682. (localStorage.LMURWindowTop === "NaN")||
  2683. (localStorage.LMURWindowLeft === "NaN")||
  2684. (localStorage.LMURWindowTop > window.innerHeight)||
  2685. (localStorage.LMURWindowLeft > window.innerWidth)||
  2686. (localStorage.LMURWindowTop < 0)||
  2687. (localStorage.LMURWindowLeft < 0)
  2688. )
  2689. {
  2690. lmurWindow.style.top = '0px';
  2691. lmurWindow.style.left = '0px';
  2692. lmurWindowTop = 0;
  2693. lmurWindowLeft = 0;
  2694. }
  2695. else
  2696. {
  2697. lmurWindowTop = localStorage.LMURWindowTop;
  2698. lmurWindowLeft = localStorage.LMURWindowLeft;
  2699. lmurWindow.style.top = lmurWindowTop +'px';
  2700. lmurWindow.style.left = lmurWindowLeft + 'px';
  2701. }
  2702.  
  2703. RouteObserver.observe(document.getElementsByClassName('wm-card is-routing')[0], { childList: true, subtree: true });
  2704.  
  2705. var lsp = document.getElementsByClassName('leaflet-shadow-pane');
  2706. if(lsp.length > 0)
  2707. {
  2708. lmurLSPObserver.observe(lsp[0], { childList: true, subtree: true });
  2709. }
  2710. var lop = document.getElementsByClassName('leaflet-overlay-pane');
  2711. if(lop.length > 0)
  2712. {
  2713. lmurLOPObserver.observe(lop[0], { childList: true, subtree: true });
  2714. }
  2715. var lmp = document.getElementsByClassName('leaflet-marker-pane');
  2716. if(lmp.length > 0)
  2717. {
  2718. lmurLMPObserver.observe(lmp[0], { childList: true, subtree: true });
  2719. }
  2720.  
  2721. lmurDoOnload = false;
  2722. lmurAddLog('onload complete');
  2723. }
  2724.  
  2725. function lmurHeartbeat()
  2726. {
  2727. //lmurShowTrace('lmurHeartbeat()');
  2728. var oldLoginState = lmurIsLoggedIn;
  2729. var revisualise = false;
  2730. lmurIsLoggedIn = (document.getElementsByClassName('wz-header__login-button').length === 0);
  2731. if(oldLoginState != lmurIsLoggedIn)
  2732. {
  2733. if(!lmurIsLoggedIn)
  2734. {
  2735. // temporarily reinstate lmurIsLoggedIn so that lmurSaveSettings() won't just return as soon as it's called...
  2736. lmurIsLoggedIn = true;
  2737. lmurSaveSettings();
  2738. lmurIsLoggedIn = false;
  2739. }
  2740. lmurDoOnload = true;
  2741. revisualise = true;
  2742. }
  2743.  
  2744. if(lmurIsLoggedIn)
  2745. {
  2746. if(lmurUserName.length === 0)
  2747. {
  2748. var lmurRequest = new XMLHttpRequest();
  2749. lmurRequest.onreadystatechange = function ()
  2750. {
  2751. if (lmurRequest.readyState == 4)
  2752. {
  2753. lmurAddLog('Get user data response '+lmurRequest.status+' received');
  2754. if (lmurRequest.status == 200)
  2755. {
  2756. var lmurData = JSON.parse(lmurRequest.responseText);
  2757. lmurUserName = lmurData.username;
  2758. lmurUserID = lmurData.id;
  2759. lmurAddLog('user '+lmurUserName+' (ID: '+lmurUserID+') has logged-in');
  2760. }
  2761. }
  2762. };
  2763. var lmurFetchURL = 'https://www.waze.com/UsersProfile/app/userInfo';
  2764. lmurAddLog('requesting '+lmurFetchURL);
  2765. lmurRequest.open("GET", lmurFetchURL, true);
  2766. lmurRequest.send();
  2767. }
  2768. }
  2769. else
  2770. {
  2771. if(lmurUserID !== null)
  2772. {
  2773. lmurAddLog('user has logged-out');
  2774. lmurUserID = null;
  2775. }
  2776. }
  2777.  
  2778. // reload UI if it gets nuked by Livemap when the user closes the route options window
  2779. if(document.getElementById('lmurUI') === null)
  2780. {
  2781. lmurDoOnload = true;
  2782. }
  2783.  
  2784. if(lmurDoOnload)
  2785. {
  2786. lmurFakeOnload();
  2787. if(revisualise)
  2788. {
  2789. lmurAddLog('re-visualising after login state change');
  2790. lmurNoForcedRefreshThisCycle = false;
  2791. lmurVisualiseMarkers();
  2792. }
  2793. }
  2794. else
  2795. {
  2796. }
  2797.  
  2798. if(lmurClearStartupCrud === true)
  2799. {
  2800. if(document.getElementsByClassName('wz-downloadbar__close-button').length > 0)
  2801. {
  2802. document.getElementsByClassName('wz-downloadbar__close-button')[0].click();
  2803. lmurClearStartupCrud = false;
  2804. }
  2805. }
  2806.  
  2807. window.setTimeout(lmurHeartbeat,100);
  2808. }
  2809.  
  2810. function lmurDecayCache()
  2811. {
  2812. lmurShowTrace('lmurDecayCache()');
  2813. if(lmurInhibitNudgeDetection) return;
  2814. if(lmurNoForcedRefreshThisCycle)
  2815. {
  2816. lmurVisualiseMarkers();
  2817. }
  2818. else
  2819. {
  2820. lmurAddLog('auto cache decay blocked by manual cache reload');
  2821. }
  2822. lmurNoForcedRefreshThisCycle = true;
  2823. }
  2824.  
  2825. function lmurRouteDetailObj(rTime, rDist, rAreas)
  2826. {
  2827. this.rTime = rTime;
  2828. this.rDist = rDist;
  2829. this.rAreas = rAreas;
  2830. }
  2831. function lmurParseRouteResponse(respBody)
  2832. {
  2833. // For each route returned in this response, store the bits of information we use to enhance the
  2834. // route details...
  2835. lmurRouteDetails = [];
  2836. for(var rIdx = 0; rIdx < respBody.alternatives.length; ++rIdx)
  2837. {
  2838. let r = respBody.alternatives[rIdx].response;
  2839. lmurRouteDetails.push(new lmurRouteDetailObj(r.totalSeconds, r.totalLength, r.areas));
  2840. }
  2841. // ...and then attempt to apply the enhancements - this may or may not work at this point depending
  2842. // on how the asynchronous nature of the response promises are handled... if ours is handled before
  2843. // the native one then the basic details won't yet be present in the sidebar and so the enhancement
  2844. // call will fail, whereas if the native one is handled first then the sidebar will now be ready for
  2845. // us to tweak.
  2846. lmurEnhanceRouteDetails();
  2847. }
  2848. function lmurAddInterceptor()
  2849. {
  2850. // intercept XHR open so we can grab the current viewport lat/lon bounds from the request LM sends to
  2851. // the servers to get its map data, now that access to this sort of stuff has been hidden from us
  2852. // with the removal of W.app.map...
  2853.  
  2854. // From https://lowrey.me/intercept-2/
  2855. const origXHRopen = window.XMLHttpRequest.prototype.open;
  2856. window.XMLHttpRequest.prototype.open = function()
  2857. {
  2858. if(arguments[1].indexOf("georss") != -1)
  2859. {
  2860. // the lat/lon bounds are passed up to the server as arguments in the XHR URL, so split these off into
  2861. // an array for easier processing
  2862. var argBits = arguments[1].split('&');
  2863. for(var i = 0; i < argBits.length; ++i)
  2864. {
  2865. // now iterate through the array looking for those entries containing the four bounding values
  2866. // we're after...
  2867. if(argBits[i].indexOf('left=') != -1) lmurVPLeft = parseFloat(argBits[i].split('=')[1]);
  2868. if(argBits[i].indexOf('right=') != -1) lmurVPRight = parseFloat(argBits[i].split('=')[1]);
  2869. if(argBits[i].indexOf('top=') != -1) lmurVPTop = parseFloat(argBits[i].split('=')[1]);
  2870. if(argBits[i].indexOf('bottom=') != -1) lmurVPBottom = parseFloat(argBits[i].split('=')[1]);
  2871. }
  2872.  
  2873. // adjust the bounds to compensate for overscan
  2874. var bWidth = lmurVPRight - lmurVPLeft;
  2875. var bHeight = lmurVPTop - lmurVPBottom;
  2876. var xCentre = (lmurVPRight + lmurVPLeft) / 2;
  2877. var yCentre = (lmurVPTop + lmurVPBottom) / 2;
  2878. // these scaling factors seem to work nicely at all zoom levels for the UK map in Chrome, need to
  2879. // see if they're universal...
  2880. bWidth *= 0.83;
  2881. bHeight *= 0.83;
  2882. lmurVPLeft = xCentre - (bWidth / 2);
  2883. lmurVPRight = xCentre + (bWidth / 2);
  2884. lmurVPTop = yCentre + (bHeight / 2);
  2885. lmurVPBottom = yCentre - (bHeight / 2);
  2886.  
  2887. if(!lmurInhibitNudgeDetection)
  2888. {
  2889. lmurAddLog('re-visualising after map nudge');
  2890. lmurNoForcedRefreshThisCycle = false;
  2891. lmurUpdateRequestQueue();
  2892. lmurVisualiseMarkers();
  2893. }
  2894. }
  2895. origXHRopen.apply(this, arguments);
  2896. }
  2897.  
  2898.  
  2899. // also intercept fetch() so we can grab the responses to routing requests...
  2900.  
  2901. // From https://blog.logrocket.com/intercepting-javascript-fetch-api-requests-responses/
  2902. // and https://stackoverflow.com/questions/45425169/intercept-fetch-api-requests-and-responses-in-javascript
  2903. const origFetch = window.fetch;
  2904. window.fetch = async (...args) =>
  2905. {
  2906. let [resource, config ] = args;
  2907. const response = await origFetch(resource, config);
  2908.  
  2909. // let all responses through as-is, except for the ones related to routing requests,
  2910. // which include the details we need to enhance the route results - these responses are
  2911. // always originated from a request which includes "user-drive" in its URL...
  2912. if(response.url.indexOf('user-drive') != -1)
  2913. {
  2914. response
  2915. .clone()
  2916. .json()
  2917. .then(body => lmurParseRouteResponse(body));
  2918. }
  2919.  
  2920. return response;
  2921. };
  2922. }
  2923.  
  2924. function lmurInitialise()
  2925. {
  2926. lmurShowTrace('lmurInitialise()');
  2927. lmurAddInterceptor();
  2928. lmurDiv = document.createElement('div');
  2929. lmurPopup = document.createElement('div');
  2930. lmurUI = document.createElement('div');
  2931. lmurResetCaches();
  2932. lmurAddLog('initialisation');
  2933. lmurDiv.id = 'lmurDiv';
  2934. lmurDiv.style.position = 'absolute';
  2935. lmurDiv.style.top = '0';
  2936. lmurDiv.style.left = '0';
  2937. lmurDiv.style.zIndex = 6;
  2938. lmurDiv.style.pointerEvents = 'none';
  2939. lmurPopup.id = 'lmurPopup';
  2940. lmurPopup.style.position = 'absolute';
  2941. lmurPopup.style.top = '0';
  2942. lmurPopup.style.left = '0';
  2943. lmurPopup.style.zIndex = 6;
  2944. lmurPopup.style.pointerEvents = 'none';
  2945. lmurPopup.style.backgroundColor = 'aliceblue';
  2946. lmurPopup.style.border = '1px solid blue';
  2947. lmurPopup.style.boxShadow = '5px 5px 10px Silver';
  2948. lmurPopup.style.padding = '4px';
  2949. window.addEventListener("beforeunload", lmurSaveSettings, false);
  2950. window.setTimeout(lmurHeartbeat,2000);
  2951. window.setTimeout(lmurGetMarkers,2500);
  2952.  
  2953. window.setInterval(lmurDecayCache,30000);
  2954. }
  2955.  
  2956. lmurInitialise();