您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Overlays UR, MP and PU markers onto Livemap
// ==UserScript== // @name LiveMap UR Overlay // @namespace http://greasemonkey.chizzum.com // @description Overlays UR, MP and PU markers onto Livemap // @include https://*.waze.com/*live-map* // @include http://*.waze.com/*live-map* // @grant none // @version 3.3 // ==/UserScript== /* To-do list: - Adaptive block sizes to deal with 500 UR limit - WME links in popup - in progress as click on marker (check PUR positioning vs WME?) - display UR comments - store marker data in separate arrays for each request area. */ /* JSHint Directives */ /* globals L: true */ /* jshint bitwise: false */ /* jshint eqnull: true */ /* jshint esversion: 8 */ var lmurVersion = '3.3'; var lmurShowDebugOutput = false; var lmurShowTraceOutput = false; var lmurClearStartupCrud = true; const T_MARKER = { UR: 0, MP: 1, MP200: 2, PUR: 3, }; var MARKER_FCOL = [ 'red', 'green', 'blue', 'yellow' ]; var MARKER_SCOL = [ 'blue', 'red', 'red', 'black' ]; const T_RESOLVED = { FCOL: 'white', SCOL: 'black' }; var lmurVPLeft = null; var lmurVPRight = null; var lmurVPTop = null; var lmurVPBottom = null; var lmurMarkers = []; var lmurCachedURs = []; var lmurCachedMPs = []; var lmurCachedPURs = []; var lmurCachesToRender = []; var lmurDownloadRequests = []; var lmurAreaHighlights = []; var lmurClusterMarkers = []; var lmurRouteDetails = []; var lmurRateLimiter = 1; var lmurUpdateURL = ''; var lmurDoOnload = true; var lmurDragBar = null; var lmurWindow = null; var lmurDiv = null; var lmurPopup = null; var lmurUI = null; var lmurUserName = ''; var lmurUserID = null; var lmurIsLoggedIn; var lmurInhibitNudgeDetection = true; var lmurControlsHidden = true; var lmurPlayModeEnabled = false; var lmurInhibitSave = true; var lmurInnerHeight = -1; var lmurUIHeight = 0; var lmurCacheExpiryPeriod = 300; var lmurInhibitCacheRefresh = false; var lmurNoForcedRefreshThisCycle = true; var lmurEnabled = false; var lmurXHRIsBusy = false; var lmurControlsMinimised = [ false, false, false, false ]; var lmurControlsID = [ 'lmurURCtrls', 'lmurMPCtrls', 'lmurPURCtrls', 'lmurOptions' ]; var lmurControlsImg = [ '_minimaxURCtrls', '_minimaxMPCtrls', '_minimaxPURCtrls', '_minimaxLMURCtrls' ]; var lmurSquareSize = 0.05; var lmurMaxGrabWidth = 0.25; var lmurMaxGrabHeight = 0.25; var lmurGetCommentsList = []; var lmurURLPrefix = ''; var lmurIcons = [ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wMBAsgGGkHX7cAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAUUlEQVQoz63SQQqAQAxD0R/xXoIXH/RicaUgtIOdscuE8DaVbaq3ZIWaXB6VJTWZE7TH2j/SrQCwxdq89FLItTkpVBJtXOoqgbY+4fFd0sjDXtyHHG22yaK0AAAAAElFTkSuQmCC', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wMBAshHpl/y8MAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAXUlEQVQoz63SQQqAMAxE0T/Fe0k9uNKTjQtBpLZSowOBQBjeJrLN20wA2jTcdLZkGy0y80CjgFcrwbFQxgoAiUDO0qN2Ub5LXa1S/pFuWkMJS9huDhn3biFJkYfdAYUjUx2jRgIlAAAAAElFTkSuQmCC' ]; function lmurModifyHTML(htmlIn) { if(typeof trustedTypes === "undefined") { return htmlIn; } else { const escapeHTMLPolicy = trustedTypes.createPolicy("forceInner", {createHTML: (to_escape) => to_escape}); return escapeHTMLPolicy.createHTML(htmlIn); } } function lmurShowTrace(traceText) { if(lmurShowTraceOutput) { console.log('LMURtrace: ('+Math.round(performance.now()*100)/100+') '+traceText); } } function lmurGetCBChecked(cbID) { lmurShowTrace('lmurGetCBChecked('+cbID+')'); if(document.getElementById(cbID) === null) return undefined; return(document.getElementById(cbID).checked); } function lmurSaveSettings() { lmurShowTrace('lmurSaveSettings()'); if(lmurInhibitSave) return; if(!lmurIsLoggedIn) return; if (localStorage) { var options = ''; var id; var lmurOptions = lmurUI.getElementsByTagName('input'); for (var optIdx=0;optIdx<lmurOptions.length;optIdx++) { id = lmurOptions[optIdx].id; if((id.indexOf('_cb') === 0)||(id.indexOf('_text') === 0)||(id.indexOf('_input') === 0)||(id.indexOf('_radio') === 0)) { options += ':' + id; if((lmurOptions[optIdx].type == 'checkbox')||(lmurOptions[optIdx].type == 'radio')) options += ',' + lmurOptions[optIdx].checked.toString(); else if((lmurOptions[optIdx].type == 'text')||(lmurOptions[optIdx].type == 'number')) options += ',' + lmurOptions[optIdx].value.toString(); } } lmurOptions = lmurUI.getElementsByTagName('select'); for (optIdx=0;optIdx<lmurOptions.length;optIdx++) { id = lmurOptions[optIdx].id; if(id.indexOf('_select') === 0) { options += ':' + id; options += ',' + lmurOptions[optIdx].selectedIndex.toString(); } } localStorage.LMUROverviewOptions = options; } } function lmurLoadSettings() { lmurShowTrace('lmurLoadSettings()'); lmurAddLog('loadSettings()'); if (localStorage.LMUROverviewOptions) { var options = localStorage.LMUROverviewOptions.split(':'); for(var optIdx=0;optIdx<options.length;optIdx++) { let fields = options[optIdx].split(','); if((document.getElementById(fields[0]) !== undefined) && (document.getElementById(fields[0]) !== null)) { if((fields[0].indexOf('_cb') === 0)||(fields[0].indexOf('_radio') === 0)) { document.getElementById(fields[0]).checked = (fields[1] == 'true'); } else if(fields[0].indexOf('_select') === 0) { document.getElementById(fields[0]).selectedIndex = fields[1]; } else if((fields[0].indexOf('_input') === 0)||(fields[0].indexOf('_text') === 0)) { document.getElementById(fields[0]).value = fields[1]; } } } var userDecayValue = document.getElementById('_inputCacheDecayPeriod').value; if(userDecayValue === "") { document.getElementById('_inputCacheDecayPeriod').value = (lmurCacheExpiryPeriod / 60); } else { lmurCacheExpiryPeriod = (parseInt(userDecayValue) * 60); } } lmurInhibitSave = false; } function lmurAddLog(logtext) { if(lmurShowDebugOutput) { console.log('LMUR: ('+Math.round(performance.now()*100)/100+') '+logtext); } } function lmurMarker(pos, obj, type, lon, lat, nComments, userLastComment, ageLastComment, loggedInUserComments, isFollowing, customTagType) { this.pos = pos; this.obj = obj; this.type = type; if(obj.subType == 200) { this.type = T_MARKER.MP200; } this.lon = lon; this.lat = lat; this.markerHidden = false; this.px = -1; this.py = -1; this.nComments = nComments; this.userLastComment = userLastComment; this.ageLastComment = ageLastComment; this.loggedInUserComments = loggedInUserComments; this.isFollowing = isFollowing; this.customTagType = customTagType; this.fCol = MARKER_FCOL[type]; this.sCol = MARKER_SCOL[type]; this.fOpa = 1.0; this.sOpa = 1.0; this.MID = null; this.RID = null; } function lmurCacheObj(lon, lat, getTime) { lon = +lon.toFixed(2); lat = +lat.toFixed(2); this.lon = lon; this.lat = lat; this.getTime = getTime; } function lmurDlReqObj(lon, lat, getURs, getMPs, getPURs) { lon = +lon.toFixed(2); lat = +lat.toFixed(2); this.lon = lon; this.lat = lat; this.getURs = getURs; this.getMPs = getMPs; this.getPURs = getPURs; this.retries = 0; this.requested = false; } function lmurAreaDisplay(SID, age, fCol, fOpa) { this.SID = SID; this.age = age; this.fCol = fCol; this.fOpa = fOpa; } function lmurClusteredMarker(CID, TID, opa) { this.CID = CID; this.TID = TID; this.opa = opa; } function lmurPix(x, y) { this.x = Math.round(x); this.y = Math.round(y); } function lmurGetVPSize() { return new lmurPix(document.getElementById('map').clientWidth, document.getElementById('map').clientHeight); } function lmurLatLonToPix(llObj) { var vpSize = lmurGetVPSize(); var relX = (llObj.lng - lmurVPLeft) / (lmurVPRight - lmurVPLeft); var relY = (lmurVPTop - llObj.lat) / (lmurVPTop - lmurVPBottom); var retval = new lmurPix(vpSize.x * relX, vpSize.y * relY); return retval; } function lmurUpdateMarkerObj(markerID, nComments, userLastComment, ageLastComment, loggedInUserComments, isFollowing, customTagType) { lmurShowTrace('lmurUpdateMarkerObj('+markerID+','+nComments+','+userLastComment+','+ageLastComment+','+loggedInUserComments+','+isFollowing+','+customTagType+')'); for(var objID=0; objID < lmurMarkers.length; objID++) { if(lmurMarkers[objID].obj.id == markerID) { lmurMarkers[objID].nComments = nComments; lmurMarkers[objID].userLastComment = userLastComment; lmurMarkers[objID].ageLastComment = ageLastComment; lmurMarkers[objID].loggedInUserComments = loggedInUserComments; lmurMarkers[objID].isFollowing = isFollowing; if(customTagType !== null) lmurMarkers[objID].customTagType = customTagType; break; } } } function lmurGetCacheIdx(lon, lat, type) { lmurShowTrace('lmurGetCacheIdx('+lon+','+lat+','+type+')'); lon = +lon.toFixed(2); lat = +lat.toFixed(2); var lmurCached; if(type == T_MARKER.UR) lmurCached = lmurCachedURs; else if((type == T_MARKER.MP)||(type == T_MARKER.MP200)) lmurCached = lmurCachedMPs; else if(type == T_MARKER.PUR) lmurCached = lmurCachedPURs; else if(type == -1) lmurCached = lmurDownloadRequests; else if(type == -2) lmurCached = lmurCachesToRender; else return null; for(var idx=0; idx<lmurCached.length; idx++) { if((lmurCached[idx].lon == lon) && (lmurCached[idx].lat == lat)) { return idx; } } return null; } function lmurSquareIsCached(lon, lat, cachedURs, cachedMPs, cachedPURs) { lmurShowTrace('lmurSquareIsCached('+lon+','+lat+','+cachedURs+','+cachedMPs+','+cachedPURs+')'); lon = +lon.toFixed(2); lat = +lat.toFixed(2); var idx; if((!cachedURs) && (!cachedMPs) && (!cachedPURs)) return false; if(cachedURs) { idx = lmurGetCacheIdx(lon, lat, T_MARKER.UR); if(idx === null) return false; if(lmurCachedURs[idx].getTime === null) return false; } if(cachedMPs) { idx = lmurGetCacheIdx(lon, lat, T_MARKER.MP); if(idx === null) return false; if(lmurCachedMPs[idx].getTime === null) return false; } if(cachedPURs) { idx = lmurGetCacheIdx(lon, lat, T_MARKER.PUR); if(idx === null) return false; if(lmurCachedPURs[idx].getTime === null) return false; } return true; } function lmurSquareIsQueued(lon, lat) { lmurShowTrace('lmurSquareIsQueued('+lon+','+lat+')'); lon = +lon.toFixed(2); lat = +lat.toFixed(2); var idx; idx = lmurGetCacheIdx(lon, lat, -1); if(idx === null) return false; return true; } function lmurGetSquareAge(lon, lat, type) { lmurShowTrace('lmurGetSquareAge('+lon+','+lat+','+type+')'); lon = +lon.toFixed(2); lat = +lat.toFixed(2); var idx = lmurGetCacheIdx(lon, lat, type); if(idx !== null) { var timeNow = Math.floor(new Date().getTime() / 1000); var cacheTime = null; if((type == T_MARKER.UR)&&(lmurCachedURs.length >= idx+1)) cacheTime = lmurCachedURs[idx].getTime; else if(((type == T_MARKER.MP)||(type == T_MARKER.MP200))&&(lmurCachedMPs.length >= idx+1)) cacheTime = lmurCachedMPs[idx].getTime; else if((type == T_MARKER.PUR)&&(lmurCachedPURs.length >= idx+1)) cacheTime = lmurCachedPURs[idx].getTime; else if((type == -2)&&(lmurCachesToRender.length >= idx+1)) cacheTime = lmurCachesToRender[idx].getTime; if(cacheTime !== null) { return (timeNow - cacheTime); } } return null; } function lmurRemoveMarkersFromCache() { lmurShowTrace('lmurRemoveMarkersFromCache()'); lmurAddLog('removing expired markers from cache'); var idx=0; while(idx < lmurMarkers.length) { var markerAge = lmurGetMarkerAge(lmurMarkers[idx]); if((markerAge > lmurCacheExpiryPeriod) || (markerAge === null)) { lmurMarkers.splice(idx,1); } else { idx++; } } } function lmurRemoveSquareFromCacheList(lon, lat, type) { lmurShowTrace('lmurRemoveSquareFromCacheList('+lon+','+lat+','+type+')'); lon = +lon.toFixed(2); lat = +lat.toFixed(2); if(type !== null) { lmurAddLog('removing square '+lon+','+lat+':'+type+' from cache'); var idx = lmurGetCacheIdx(lon, lat, type); if(idx !== null) { if(type == T_MARKER.UR) lmurCachedURs.splice(idx,1); else if((type == T_MARKER.MP)||(type == T_MARKER.MP200)) lmurCachedMPs.splice(idx,1); else if(type == T_MARKER.PUR) lmurCachedPURs.splice(idx,1); else if(type == -1) lmurCachesToRender.splice(idx,1); } } } function lmurResetCaches() { lmurShowTrace('lmurResetCaches()'); lmurMarkers = []; lmurCachedURs = []; lmurCachedMPs = []; lmurCachedPURs = []; lmurCachesToRender = []; lmurDownloadRequests = []; } function lmurChangeServer() { lmurShowTrace('lmurChangeServer()'); lmurResetCaches(); lmurUpdateRequestQueue(); } function lmurGetMarkerAge(ureq) { lmurShowTrace('lmurGetMarkerAge('+ureq+')'); return lmurGetSquareAge(ureq.lon, ureq.lat, ureq.type); } function lmurGetCommentsData() { lmurShowTrace('lmurGetCommentsData()'); if(lmurGetCommentsList.length === 0) { lmurVisualiseMarkers(); return; } if(lmurXHRIsBusy) { window.setTimeout(lmurGetCommentsData,lmurRateLimiter); return; } var idList = ''; var idCount; if(lmurGetCommentsList.length > 50) idCount = 50; else idCount = lmurGetCommentsList.length; while(idCount) { idList += lmurGetCommentsList.pop(); if(idCount != 1) idList += ','; idCount--; } var lmurRequest = new XMLHttpRequest(); lmurRequest.onreadystatechange = function () { if (lmurRequest.readyState == 4) { lmurXHRIsBusy = false; lmurAddLog('lmurGetCommentsData() response '+lmurRequest.status+' received'); if (lmurRequest.status == 200) { var lmurData = JSON.parse(lmurRequest.responseText); lmurAddLog('data received for '+lmurData.updateRequestSessions.objects.length+' URs'); var timeNow = new Date().getTime(); for(var ursObj in lmurData.updateRequestSessions.objects) { if(lmurData.updateRequestSessions.objects.hasOwnProperty(ursObj)) { var urSesh = lmurData.updateRequestSessions.objects[ursObj]; var nComments = urSesh.comments.length; var loggedInUserComments = false; var userLastComment = null; var ageLastComment = null; var customTagType = null; if(nComments > 0) { userLastComment = urSesh.comments[nComments-1].userID; ageLastComment = Math.floor((timeNow - urSesh.comments[nComments-1].createdOn) / 86400000); for(var loop=0;loop<nComments;loop++) { if(urSesh.comments[loop].userID == lmurUserID) { loggedInUserComments = true; } if(urSesh.comments[loop].text.indexOf('[ROADWORKS]') != -1) customTagType = 1; else if(urSesh.comments[loop].text.indexOf('[CONSTRUCTION]') != -1) customTagType = 2; else if(urSesh.comments[loop].text.indexOf('[CLOSURE]') != -1) customTagType = 3; else if(urSesh.comments[loop].text.indexOf('[EVENT]') != -1) customTagType = 4; else if(urSesh.comments[loop].text.indexOf('[NOTE]') != -1) customTagType = 5; } } var isFollowing = urSesh.isFollowing; lmurUpdateMarkerObj(urSesh.id,nComments,userLastComment,ageLastComment,loggedInUserComments,isFollowing,customTagType); } } } window.setTimeout(lmurGetCommentsData,lmurRateLimiter); } }; var lmurFetchURL = 'https://www.waze.com/' + lmurURLPrefix + 'Descartes-live/app/MapProblems/UpdateRequests?ids='+idList; lmurAddLog('requesting '+lmurFetchURL); lmurRequest.open("GET", lmurFetchURL, true); lmurRequest.send(); lmurXHRIsBusy = true; } function lmurUpdateRequestQueue() { lmurShowTrace('lmurUpdateRequestQueue()'); // don't visualise anything if the user isn't logged-in or hasn't asked for anything to be visualised... if ( (!lmurIsLoggedIn) || ( (!lmurGetCBChecked('_cbShowURs')) && (!lmurGetCBChecked('_cbShowProblems')) && (!lmurGetCBChecked('_cbShowPlaceUpdates')) ) || (!lmurEnabled) ) { lmurAddLog('inhibit visualisation'); lmurDiv.innerHTML = lmurModifyHTML(''); return; } var midpoint; var vpLeft = lmurVPLeft; var vpRight = lmurVPRight; var vpTop = lmurVPTop; var vpBottom = lmurVPBottom; if((vpRight - vpLeft) > lmurMaxGrabWidth) { midpoint = (vpRight + vpLeft) / 2; vpRight = midpoint + (lmurMaxGrabWidth / 2); vpLeft = midpoint - (lmurMaxGrabWidth / 2); } if((vpTop - vpBottom) > lmurMaxGrabHeight) { midpoint = (vpTop + vpBottom) / 2; vpTop = midpoint + (lmurMaxGrabHeight / 2); vpBottom = midpoint - (lmurMaxGrabHeight / 2); } var startLon = (vpLeft / lmurSquareSize); if(startLon < 0) startLon = Math.floor(startLon) * lmurSquareSize; else startLon = Math.ceil(startLon) * lmurSquareSize; var endLon = (vpRight / lmurSquareSize); if(endLon < 0) endLon = Math.ceil(endLon) * lmurSquareSize; else endLon = Math.floor(endLon) * lmurSquareSize; var startLat = (vpBottom / lmurSquareSize); if(startLat < 0) startLat = Math.ceil(startLat) * lmurSquareSize; else startLat = Math.floor(startLat) * lmurSquareSize; var endLat = (vpTop / lmurSquareSize); if(endLat < 0) endLat = Math.floor(endLat) * lmurSquareSize; else endLat = Math.ceil(endLat) * lmurSquareSize; var getURs = lmurGetCBChecked('_cbShowURs'); var getMPs = lmurGetCBChecked('_cbShowProblems'); var getPURs = lmurGetCBChecked('_cbShowPlaceUpdates'); for(var sqLon = startLon; sqLon <= endLon; sqLon += lmurSquareSize) { for(var sqLat = startLat; sqLat <= endLat; sqLat += lmurSquareSize) { sqLon = +sqLon.toFixed(2); sqLat = +sqLat.toFixed(2); if(!lmurSquareIsCached(sqLon, sqLat, getURs, getMPs, getPURs)) { if(!lmurSquareIsQueued(sqLon, sqLat)) { lmurDownloadRequests.push(new lmurDlReqObj(sqLon, sqLat, getURs, getMPs, getPURs)); } } } } if(lmurDownloadRequests.length) { window.setTimeout(lmurGetMarkers,lmurRateLimiter); } } function lmurGetMarkers() { lmurShowTrace('lmurGetMarkers()'); if(lmurDownloadRequests.length === 0) { return; } if(lmurXHRIsBusy) { window.setTimeout(lmurGetMarkers,lmurRateLimiter); return; } var timeNow = Math.floor(new Date().getTime() / 1000); var dlReq = lmurDownloadRequests[0]; var idx = lmurGetCacheIdx(dlReq.lon, dlReq.lat, -1); if((idx === null) || (!dlReq.requested)) { lmurAddLog('cache miss at '+dlReq.lon+' '+dlReq.lat); if(dlReq.retries++ < 3) { lmurAddLog('block has retries remaining, requesting from server...'); dlReq.requested = true; var getURs = ((dlReq.getURs) && (!lmurSquareIsCached(dlReq.lon, dlReq.lat, true, false, false))); var getMPs = ((dlReq.getMPs) && (!lmurSquareIsCached(dlReq.lon, dlReq.lat, false, true, false))); var getPURs = ((dlReq.getPURs) && (!lmurSquareIsCached(dlReq.lon, dlReq.lat, false, false, true))); if(lmurGetCBChecked('_radioROWServer')) lmurURLPrefix = 'row-'; else if(lmurGetCBChecked('_radioUSAServer')) lmurURLPrefix = ''; else lmurURLPrefix = 'il-'; var lmurRequest = new XMLHttpRequest(); lmurRequest.onreadystatechange = function () { if (lmurRequest.readyState == 4) { lmurXHRIsBusy = false; lmurAddLog('lmurGetMarkers() response '+lmurRequest.status+' received'); if (lmurRequest.status == 200) { var lmurData = JSON.parse(lmurRequest.responseText); var loop; var isDupe; var cacheObj = new lmurCacheObj(dlReq.lon, dlReq.lat, timeNow); if((lmurData.users !== undefined) && (lmurUserName.length !== 0) && (lmurUserID === null)) { for(var userObj in lmurData.users.objects) { if(lmurData.users.objects.hasOwnProperty(userObj)) { var user = lmurData.users.objects[userObj]; if(user.userName === lmurUserName) { lmurUserID = user.id; lmurAddLog('Found ID '+lmurUserID+' for logged-in user...'); break; } } } } lmurAddLog('This area contains:'); if(lmurData.mapUpdateRequests !== undefined) { lmurAddLog(' '+lmurData.mapUpdateRequests.objects.length+' URs'); // store URs for(var urobj in lmurData.mapUpdateRequests.objects) { if(lmurData.mapUpdateRequests.objects.hasOwnProperty(urobj)) { var ureq = lmurData.mapUpdateRequests.objects[urobj]; isDupe = false; for(loop=0; loop<lmurMarkers.length; loop++) { if((lmurMarkers[loop].type == T_MARKER.UR) && (lmurMarkers[loop].obj.id == ureq.id)) { isDupe = true; break; } } if(!isDupe) { var urpos = new L.LatLng(ureq.geometry.coordinates[1],ureq.geometry.coordinates[0]); var customTagType = 0; if(ureq.description !== null) { var desc = ureq.description; if(desc.indexOf('[ROADWORKS]') != -1) customTagType = 1; else if(desc.indexOf('[CONSTRUCTION]') != -1) customTagType = 2; else if(desc.indexOf('[CLOSURE]') != -1) customTagType = 3; else if(desc.indexOf('[EVENT]') != -1) customTagType = 4; else if(desc.indexOf('[NOTE]') != -1) customTagType = 5; } lmurMarkers.push(new lmurMarker(urpos, ureq, T_MARKER.UR, dlReq.lon, dlReq.lat, -1, -1, -1, false, false, customTagType)); if(lmurUserName.length !== 0) { lmurGetCommentsList.push(ureq.id); } } } } lmurAddLog(' URs processed, '+lmurMarkers.length+' objects in lmurMarkers'); } if(lmurData.problems !== undefined) { lmurAddLog(' '+lmurData.problems.objects.length+' MPs'); // store map problems for(var mpobj in lmurData.problems.objects) { if(lmurData.problems.objects.hasOwnProperty(mpobj)) { var mprob = lmurData.problems.objects[mpobj]; isDupe = false; for(loop=0; loop<lmurMarkers.length; loop++) { if ( ( (lmurMarkers[loop].type == T_MARKER.MP) || (lmurMarkers[loop].type == T_MARKER.MP200) ) && (lmurMarkers[loop].obj.id == mprob.id) ) { isDupe = true; break; } } if(!isDupe) { var mppos = new L.LatLng(mprob.geometry.coordinates[1],mprob.geometry.coordinates[0]); lmurMarkers.push(new lmurMarker(mppos, mprob, T_MARKER.MP, dlReq.lon, dlReq.lat, 0, -1, -1, false, false, -1)); } } } lmurAddLog(' MPs processed, '+lmurMarkers.length+' objects in lmurMarkers'); } if(lmurData.venues !== undefined) { lmurAddLog(' '+lmurData.venues.objects.length+' PURs'); // store PURs for(var puobj in lmurData.venues.objects) { if(lmurData.venues.objects.hasOwnProperty(puobj)) { var pupd = lmurData.venues.objects[puobj]; isDupe = false; for(loop=0; loop<lmurMarkers.length; loop++) { if((lmurMarkers[loop].type == T_MARKER.PUR) && (lmurMarkers[loop].obj.id == pupd.id)) { isDupe = true; break; } } if(!isDupe) { if(pupd.venueUpdateRequests === undefined) continue; if(pupd.geometry.type == 'Point') { var pupos_point = new L.LatLng(pupd.geometry.coordinates[1],pupd.geometry.coordinates[0]); lmurMarkers.push(new lmurMarker(pupos_point, pupd, T_MARKER.PUR, dlReq.lon, dlReq.lat, 0, -1, -1, false, false, -1)); } else if(pupd.geometry.type == 'Polygon') { var pupos_poly = new L.LatLng(pupd.geometry.coordinates[0][0][1],pupd.geometry.coordinates[0][0][0]); lmurMarkers.push(new lmurMarker(pupos_poly, pupd, T_MARKER.PUR, dlReq.lon, dlReq.lat, 0, -1, -1, false, false, -1)); } } } } lmurAddLog(' PURs processed, '+lmurMarkers.length+' objects in lmurMarkers'); } if(getURs) lmurCachedURs.push(cacheObj); if(getMPs) lmurCachedMPs.push(cacheObj); if(getPURs) lmurCachedPURs.push(cacheObj); if(lmurGetCommentsList.length > 0) { window.setTimeout(lmurGetCommentsData,lmurRateLimiter); } lmurVisualiseMarkers(); lmurDownloadRequests.shift(); } window.setTimeout(lmurGetMarkers,lmurRateLimiter); } }; var lmurFetchURL = 'https://www.waze.com/' + lmurURLPrefix + 'Descartes-live/app/Features?language=en'; if(getURs) lmurFetchURL += '&mapUpdateRequestFilter=1'; if(getMPs) lmurFetchURL += '&problemFilter=1&turnProblemFilter=1'; if(getPURs) lmurFetchURL += '&venueFilter=1&venueLevel=1&venueUpdateRequests=true'; if(lmurGetCBChecked('_cbEnablePlayMode')) lmurFetchURL += '&sandbox=true'; lmurFetchURL += '&bbox='; lmurFetchURL += dlReq.lon + ',' + dlReq.lat + ',' + (dlReq.lon + lmurSquareSize) + ',' + (dlReq.lat + lmurSquareSize); lmurRequest.open('GET', lmurFetchURL, true); lmurRequest.send(); lmurXHRIsBusy = true; lmurAddLog('requesting '+lmurFetchURL); } else { lmurAddLog('out of retries, sorry...'); lmurDownloadRequests.shift(); } } else { lmurAddLog('cache hit at '+dlReq.lon+' '+dlReq.lat); lmurDownloadRequests.shift(); window.setTimeout(lmurGetMarkers,lmurRateLimiter); } } function lmurKeywordPresent(desc, keyword) { lmurShowTrace('lmurKeywordPresent('+desc+','+keyword+')'); var re; if(lmurGetCBChecked('_cbURCaseInsensitive')) re = RegExp(keyword,'i'); else re = RegExp(keyword); if(desc.search(re) == -1) return false; else return true; } function lmurFilterMarkers(ureq) { lmurShowTrace('lmurFilterMarkers('+ureq+')'); var daysOld; // URs if(ureq.type == T_MARKER.UR) { if (!lmurGetCBChecked('_cbShowURs')) return true; // resolved filtering if(lmurGetCBChecked('_cbUREnableResolvedFilter')) { if(ureq.obj.resolvedOn !== null) return true; } // age-based filtering daysOld = lmurGetURAge(ureq.obj,0); if(daysOld != 999999) { if(lmurGetCBChecked('_cbUREnableMinAgeFilter')) { if(daysOld < document.getElementById('_inputURFilterMinDays').value) return true; } if(lmurGetCBChecked('_cbUREnableMaxAgeFilter')) { if(daysOld > document.getElementById('_inputURFilterMaxDays').value) return true; } } // comment based filtering if(lmurIsLoggedIn) { if ( ((lmurGetCBChecked('_cbURShowUnloadedComments')) && (ureq.nComments != -1)) || ((lmurGetCBChecked('_cbURHideUnloadedComments')) && (ureq.nComments == -1)) ) { return true; } if (ureq.nComments != -1) { if(lmurGetCBChecked('_cbURHideWithMyComments')) { if(ureq.loggedInUserComments) return true; } if(lmurGetCBChecked('_cbURShowWithMyComments')) { if(!ureq.loggedInUserComments) return true; } if(lmurGetCBChecked('_cbURHideLastCommentByMe')) { if(ureq.userLastComment == lmurUserID) return true; } if(lmurGetCBChecked('_cbURShowLastCommentByMe')) { if(ureq.userLastComment != lmurUserID) return true; } if(lmurGetCBChecked('_cbURHideLastCommentByReporter')) { if(ureq.userLastComment == -1) return true; } if(lmurGetCBChecked('_cbURShowLastCommentByReporter')) { if(ureq.userLastComment != -1) return true; } if(lmurGetCBChecked('_cbURHideWithLessThanComments')) { if(ureq.nComments < document.getElementById('_inputFilterMinComments').value) return true; } if(lmurGetCBChecked('_cbURShowWithLessThanComments')) { if(ureq.nComments >= document.getElementById('_inputFilterMinComments').value) return true; } if(lmurGetCBChecked('_cbURHideFollowedURs')) { if(ureq.isFollowing) return true; } if(lmurGetCBChecked('_cbURShowFollowedURs')) { if(!ureq.isFollowing) return true; } if(lmurGetCBChecked('_cbURHideLastCommentAge')) { if(ureq.nComments > 0) { if(ureq.ageLastComment < document.getElementById('_inputFilterCommentAge').value) return true; } } if(lmurGetCBChecked('_cbURShowLastCommentAge')) { if(ureq.ageLastComment >= document.getElementById('_inputFilterCommentAge').value) return true; } } } // keyword and type-specific filtering var desc = ''; var urFilter = false; if(ureq.obj.description !== null) desc = ureq.obj.description; if(lmurGetCBChecked('_cbUREnableKeywordMustBePresent')) { if(!lmurKeywordPresent(desc,document.getElementById('_textURKeywordPresent').value)) return true; } if(lmurGetCBChecked('_cbUREnableKeywordMustBeAbsent')) { if(lmurKeywordPresent(desc,document.getElementById('_textURKeywordAbsent').value)) return true; } if(lmurGetCBChecked('_cbURHideWithNoDescription')) { if(desc === "") return true; } if(lmurGetCBChecked('_cbURShowWithNoDescription')) { if(desc !== "") return true; } // type-based filtering... // Need to check for Waze automatic URs first - these always (?) get inserted as General Error URs, // so although they're treated as a "type" UR for filtering purposes, we have to filter them out // via description keyword matching before we can do any real type filtering if(desc.indexOf('Waze Automatic:') != -1) urFilter |= lmurGetCBChecked('_cbURFilterWazeAuto'); // Now custom tagged URs else if(ureq.customTagType == 1) urFilter |= lmurGetCBChecked('_cbURFilterRoadworks'); else if(ureq.customTagType == 2) urFilter |= lmurGetCBChecked('_cbURFilterConstruction'); else if(ureq.customTagType == 3) urFilter |= lmurGetCBChecked('_cbURFilterClosure'); else if(ureq.customTagType == 4) urFilter |= lmurGetCBChecked('_cbURFilterEvent'); else if(ureq.customTagType == 5) urFilter |= lmurGetCBChecked('_cbURFilterNote'); if(ureq.obj.type == 6) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectTurn'); else if(ureq.obj.type == 7) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectAddress'); else if(ureq.obj.type == 8) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectRoute'); else if(ureq.obj.type == 9) urFilter |= lmurGetCBChecked('_cbURFilterMissingRoundabout'); else if(ureq.obj.type == 10) urFilter |= lmurGetCBChecked('_cbURFilterGeneralError'); else if(ureq.obj.type == 11) urFilter |= lmurGetCBChecked('_cbURFilterTurnNotAllowed'); else if(ureq.obj.type == 12) urFilter |= lmurGetCBChecked('_cbURFilterIncorrectJunction'); else if(ureq.obj.type == 13) urFilter |= lmurGetCBChecked('_cbURFilterMissingBridgeOverpass'); else if(ureq.obj.type == 14) urFilter |= lmurGetCBChecked('_cbURFilterWrongDrivingDirection'); else if(ureq.obj.type == 15) urFilter |= lmurGetCBChecked('_cbURFilterMissingExit'); else if(ureq.obj.type == 16) urFilter |= lmurGetCBChecked('_cbURFilterMissingRoad'); else if(ureq.obj.type == 18) urFilter |= lmurGetCBChecked('_cbURFilterMissingLandmark'); else if(ureq.obj.type == 19) urFilter |= lmurGetCBChecked('_cbURFilterBlockedRoad'); else if(lmurGetCBChecked('_cbURFilterUndefined')) urFilter |= true; if(document.getElementsByName('lmurShowURs')[0].checked) { urFilter = !urFilter; } return urFilter; } // MPs else if(ureq.type == T_MARKER.MP) { if (!lmurGetCBChecked('_cbShowProblems')) return true; // resolved filtering if(lmurGetCBChecked('_cbMPEnableResolvedFilter')) { if(ureq.obj.resolvedOn !== null) return true; } // filter by severity if(ureq.obj.priority <= 3) { if (lmurGetCBChecked('_cbMPFilterLowSeverity')) return true; } else if(ureq.obj.priority <= 7) { if (lmurGetCBChecked('_cbMPFilterMediumSeverity')) return true; } else if(ureq.obj.priority > 7) { if (lmurGetCBChecked('_cbMPFilterHighSeverity')) return true; } var problemFilter = false; if(ureq.obj.subType == 101) problemFilter |= lmurGetCBChecked('_cbMPFilterDrivingDirectionMismatch'); else if(ureq.obj.subType == 102) problemFilter |= lmurGetCBChecked('_cbMPFilterMissingJunction'); else if(ureq.obj.subType == 103) problemFilter |= lmurGetCBChecked('_cbMPFilterMissingRoad'); else if(ureq.obj.subType == 104) problemFilter |= lmurGetCBChecked('_cbMPFilterCrossroadsJunctionMissing'); else if(ureq.obj.subType == 105) problemFilter |= lmurGetCBChecked('_cbMPFilterRoadTypeMismatch'); else if(ureq.obj.subType == 106) problemFilter |= lmurGetCBChecked('_cbMPFilterRestrictedTurn'); else if(ureq.obj.subType == 300) problemFilter |= lmurGetCBChecked('_cbMPFilterRoadClosure'); else if(lmurGetCBChecked('_cbMPFilterUnknownProblem')) problemFilter = true; if(document.getElementsByName('lmurShowProblems')[0].checked) { problemFilter = !problemFilter; } return problemFilter; } else if(ureq.type == T_MARKER.MP200) { // resolved filtering if(lmurGetCBChecked('_cbTPEnableResolvedFilter')) { if(ureq.obj.resolvedOn !== null) return true; } if (!lmurGetCBChecked('_cbShowTurnProbs')) return true; return false; } // PURs else if(ureq.type == T_MARKER.PUR) { if (!lmurGetCBChecked('_cbShowPlaceUpdates')) return true; // residential/non-residential filtering if(ureq.obj.residential) { if (lmurGetCBChecked('_cbPURFilterResidential')) return true; } else { if (lmurGetCBChecked('_cbPURFilterNonResidential')) return true; } // age-based filtering daysOld = lmurGetURAge(ureq.obj,3); if(daysOld != 999999) { if(lmurGetCBChecked('_cbPUREnableMinAgeFilter')) { if(daysOld < document.getElementById('_inputPURFilterMinDays').value) return true; } if(lmurGetCBChecked('_cbPUREnableMaxAgeFilter')) { if(daysOld > document.getElementById('_inputPURFilterMaxDays').value) return true; } } var purFilter = false; var purUpdateDetails = false; var purNewPhoto = false; var purNewPlace = false; var purFlagged = false; var purNonZeroLR = false; if(ureq.obj.lockRank !== undefined) { purNonZeroLR = (ureq.obj.lockRank > 0); } for(var vurIdx=0; vurIdx < ureq.obj.venueUpdateRequests.length; vurIdx++) { var vurObj = ureq.obj.venueUpdateRequests[vurIdx]; if(vurObj.type !== undefined) { purNewPhoto |= (vurObj.type == 'IMAGE'); purNewPlace |= (vurObj.type == 'VENUE'); } if(vurObj.subType !== undefined) { purUpdateDetails |= (vurObj.subType == 'UPDATE'); purFlagged |= (vurObj.subType == 'FLAG'); } } purFilter |= ((lmurGetCBChecked('_cbPURFilterNewPlace')) && (purNewPlace)); purFilter |= ((lmurGetCBChecked('_cbPURFilterUpdateDetails')) && (purUpdateDetails)); purFilter |= ((lmurGetCBChecked('_cbPURFilterNewPhoto')) && (purNewPhoto)); purFilter |= ((lmurGetCBChecked('_cbPURFilterFlagged')) && (purFlagged)); purFilter |= ((lmurGetCBChecked('_cbPURNonZeroLockRank')) && (purNonZeroLR)); if(document.getElementsByName('lmurShowPURs')[0].checked) { purFilter = !purFilter; } return purFilter; } } function lmurGetZoom() { var zoom = null; var pos; var tStr; var cList = document.getElementsByClassName('wm-map__leaflet')[0].classList; for(var i = 0; i < cList.length; ++i) { pos = cList[i].indexOf('--zoom-'); if(pos > 0) { tStr = cList[i].slice(pos + 7); zoom = parseInt(tStr); if(isNaN(zoom) == false) { break; } } } return zoom; } function lmurVisualiseMarkers() { lmurShowTrace('lmurVisualiseMarkers()'); // don't visualise anything if the user isn't logged-in or hasn't asked for anything to be visualised... if ( (!lmurIsLoggedIn) || ( (!lmurGetCBChecked('_cbShowURs')) && (!lmurGetCBChecked('_cbShowProblems')) && (!lmurGetCBChecked('_cbShowPlaceUpdates')) ) || (!lmurEnabled) ) { lmurAddLog('inhibit visualisation'); lmurDiv.innerHTML = lmurModifyHTML(''); return; } lmurAddLog('enabling nudge detection'); lmurInhibitNudgeDetection = false; lmurAddLog('visualise markers'); var mapObj = document.getElementById("map"); var currentwidth = mapObj.offsetWidth; var currentheight = mapObj.offsetHeight; lmurDiv.style.width = currentwidth; lmurDiv.style.height = currentheight; var svgSrc = '<svg xmlns="http://www.w3.org/2000/svg" width="'+currentwidth+'px" height="'+currentheight+'px" version="1.1">'; // visualise cached data areas var corner1 = new L.LatLng(0,0); var corner2 = new L.LatLng(0,0); lmurCachesToRender = []; var sq; var sqAge; var idx; var fillOpacity; var pix1; var pix2; for(sq=0;sq<lmurCachedURs.length;sq++) { corner1.lat = lmurCachedURs[sq].lat; corner1.lng = lmurCachedURs[sq].lon; sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, T_MARKER.UR); if(sqAge !== null) { if((sqAge > lmurCacheExpiryPeriod)&&(lmurCacheExpiryPeriod !== 0)) lmurRemoveSquareFromCacheList(corner1.lng, corner1.lat, T_MARKER.UR); else if(sqAge != -1) { sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2); if(sqAge === null) lmurCachesToRender.push(new lmurCacheObj(lmurCachedURs[sq].lon, lmurCachedURs[sq].lat, lmurCachedURs[sq].getTime)); } } } for(sq=0;sq<lmurCachedMPs.length;sq++) { corner1.lat = lmurCachedMPs[sq].lat; corner1.lng = lmurCachedMPs[sq].lon; sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, T_MARKER.MP); if(sqAge !== null) { if((sqAge > lmurCacheExpiryPeriod)&&(lmurCacheExpiryPeriod !== 0)) lmurRemoveSquareFromCacheList(corner1.lng, corner1.lat, T_MARKER.MP); else if(sqAge != -1) { sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2); if(sqAge === null) lmurCachesToRender.push(new lmurCacheObj(lmurCachedMPs[sq].lon, lmurCachedMPs[sq].lat, lmurCachedMPs[sq].getTime)); else if(sqAge < lmurGetSquareAge(corner1.lng, corner1.lat, -1)) lmurCachesToRender[idx].getTime = lmurCachedMPs[sq].getTime; } } } for(sq=0;sq<lmurCachedPURs.length;sq++) { corner1.lat = lmurCachedPURs[sq].lat; corner1.lng = lmurCachedPURs[sq].lon; sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, T_MARKER.PUR); if(sqAge !== null) { if((sqAge > lmurCacheExpiryPeriod)&&(lmurCacheExpiryPeriod !== 0)) lmurRemoveSquareFromCacheList(corner1.lng, corner1.lat, T_MARKER.PUR); else if(sqAge != -1) { sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2); if(sqAge === null) lmurCachesToRender.push(new lmurCacheObj(lmurCachedPURs[sq].lon, lmurCachedPURs[sq].lat, lmurCachedPURs[sq].getTime)); else if(sqAge < lmurGetSquareAge(corner1.lng, corner1.lat, -1)) lmurCachesToRender[idx].getTime = lmurCachedPURs[sq].getTime; } } } for(sq=0;sq<lmurDownloadRequests.length;sq++) { corner1.lat = lmurDownloadRequests[sq].lat; corner1.lng = lmurDownloadRequests[sq].lon; if ( (corner1.lng <= lmurVPRight) && ((corner1.lng + lmurSquareSize) >= lmurVPLeft) && (corner1.lat <= lmurVPTop) && ((corner1.lat + lmurSquareSize) >= lmurVPBottom) ) { corner2.lat = parseFloat(corner1.lat)+lmurSquareSize; corner2.lng = parseFloat(corner1.lng)+lmurSquareSize; pix1 = lmurLatLonToPix(corner1); pix2 = lmurLatLonToPix(corner2); var sID = 'ASQ-'+lmurAreaHighlights.length; svgSrc += '<rect id="'+sID+'" x="'+pix1.x+'" y="'+pix2.y+'" width="'+(pix2.x-pix1.x)+'" height="'+(pix1.y-pix2.y)+'" />'; lmurAreaHighlights.push(new lmurAreaDisplay(sID, -1, 'grey', 0.2)); } } if(!lmurGetCBChecked('_cbHighlightDisabled')) { for(sq=0;sq<lmurCachesToRender.length;sq++) { corner1.lat = lmurCachesToRender[sq].lat; corner1.lng = lmurCachesToRender[sq].lon; if ( (corner1.lng <= lmurVPRight) && ((corner1.lng + lmurSquareSize) >= lmurVPLeft) && (corner1.lat <= lmurVPTop) && ((corner1.lat + lmurSquareSize) >= lmurVPBottom) ) { sqAge = lmurGetSquareAge(corner1.lng, corner1.lat, -2); if(sqAge > lmurCacheExpiryPeriod) { sqAge = lmurCacheExpiryPeriod; } if((sqAge != -1) && (sqAge <= lmurCacheExpiryPeriod)) { if(lmurCacheExpiryPeriod === 0) { fillOpacity = 0.2; } else { fillOpacity = 0.2 - ((sqAge * 0.15) / lmurCacheExpiryPeriod); } corner2.lat = parseFloat(corner1.lat)+lmurSquareSize; corner2.lng = parseFloat(corner1.lng)+lmurSquareSize; pix1 = lmurLatLonToPix(corner1); pix2 = lmurLatLonToPix(corner2); let sID = 'ASQ-'+lmurAreaHighlights.length; svgSrc += '<rect id="'+sID+'" x="'+pix1.x+'" y="'+pix2.y+'" width="'+(pix2.x-pix1.x)+'" height="'+(pix1.y-pix2.y)+'" />'; lmurAreaHighlights.push(new lmurAreaDisplay(sID, sqAge, 'yellow', fillOpacity)); } } } } if(lmurCacheExpiryPeriod > 0) { lmurRemoveMarkersFromCache(); } var urpos = new L.LatLng(0,0); var hideMarker; var i; var ureq; var filteredMarkers = 0; var vpSize = lmurGetVPSize(); for(i=0;i<lmurMarkers.length;i++) { ureq = lmurMarkers[i]; hideMarker = lmurFilterMarkers(ureq); if(!hideMarker) { urpos.lng = ureq.pos.lng; urpos.lat = ureq.pos.lat; var urpix = lmurLatLonToPix(urpos); lmurMarkers[i].px = urpix.x; lmurMarkers[i].py = urpix.y; if((urpix.x < 0)||(urpix.x >= vpSize.x)||(urpix.y < 0)||(urpix.y >= vpSize.y)) hideMarker = true; } else { lmurMarkers[i].px = -1; lmurMarkers[i].py = -1; filteredMarkers++; } lmurMarkers[i].markerHidden = hideMarker; } var zoom = lmurGetZoom(); if((zoom < 11) && (!lmurGetCBChecked('_cbClusteringDisabled'))) { var clusterDist = Math.min(Math.floor(vpSize.y / 20),Math.floor(vpSize.x / 20)); var marker_rad = clusterDist / 3; if(marker_rad < 10) marker_rad = 10; var threshold = 1; lmurClusterMarkers = []; if(lmurMarkers.length > 1) { for(i=0;i<lmurMarkers.length-1;i++) { if(!lmurMarkers[i].markerHidden) { if(lmurCacheExpiryPeriod === 0) { fillOpacity = 1; } else { fillOpacity = 1 - ((lmurGetMarkerAge(lmurMarkers[i]) * 0.9) / lmurCacheExpiryPeriod); } if(fillOpacity < 0.1) fillOpacity = 0.1; var clusterSize = 1; var clusterX = lmurMarkers[i].px; var clusterY = lmurMarkers[i].py; var xmin = lmurMarkers[i].px-clusterDist; var xmax = lmurMarkers[i].px+clusterDist; var ymin = lmurMarkers[i].py-clusterDist; var ymax = lmurMarkers[i].py+clusterDist; for(var j=i+1;j<lmurMarkers.length;j++) { if(!lmurMarkers[j].markerHidden) { if((lmurMarkers[j].px > xmin)&&(lmurMarkers[j].px < xmax)&&(lmurMarkers[j].py > ymin)&&(lmurMarkers[j].py < ymax)) { clusterSize++; clusterX += lmurMarkers[j].px; clusterY += lmurMarkers[j].py; lmurMarkers[j].markerHidden = true; } } } if(clusterSize > threshold) { lmurMarkers[i].markerHidden = true; var cx = clusterX / clusterSize; var cy = clusterY / clusterSize; var CID = "CCID_"+i; var TID = "CTID_"+i; svgSrc += '<circle id="'+CID+'" cx="'+cx+'" cy="'+cy+'" r="'+marker_rad+'" />'; svgSrc += '<text id="'+TID+'" x="'+cx+'" y="'+cy+'" font-size="12" fill="white" dy="5">'+clusterSize+'</text>'; lmurClusterMarkers.push(new lmurClusteredMarker(CID, TID, fillOpacity)); } } } } } for(i=0;i<lmurMarkers.length;i++) { if(!lmurMarkers[i].markerHidden) { ureq = lmurMarkers[i]; if(lmurCacheExpiryPeriod === 0) { fillOpacity = 1; } else { fillOpacity = 1 - ((lmurGetMarkerAge(ureq) * 0.9) / lmurCacheExpiryPeriod); } if(fillOpacity < 0.1) fillOpacity = 0.1; if(ureq.type == T_MARKER.UR) { if(ureq.obj.resolvedOn !== null) { lmurMarkers[i].RID = "RID_"+i; svgSrc += '<circle id="RID_'+i+'" cx="'+ureq.px+'" cy="'+(ureq.py+7)+'" r="9" />'; } lmurMarkers[i].MID = "MID_"+i; svgSrc += '<rect id="MID_'+i+'" x="'+ureq.px+'" y="'+ureq.py+'" transform="rotate(45,'+ureq.px+','+ureq.py+')" width="10" height="10" />'; } else if(ureq.type == T_MARKER.MP) { if(ureq.obj.resolvedOn !== null) { lmurMarkers[i].RID = "RID_"+i; svgSrc += '<circle id="RID_'+i+'" cx="'+ureq.px+'" cy="'+(ureq.py)+'" r="9" />'; } lmurMarkers[i].MID = "MID_"+i; svgSrc += '<rect id="MID_'+i+'" x="'+(ureq.px-5)+'" y="'+(ureq.py-5)+'" width="10" height="10" />'; } else if(ureq.type == T_MARKER.MP200) { if(ureq.obj.resolvedOn !== null) { lmurMarkers[i].RID = "RID_"+i; svgSrc += '<circle id="RID_'+i+'" cx="'+ureq.px+'" cy="'+(ureq.py)+'" r="9" />'; } lmurMarkers[i].MID = "MID_"+i; svgSrc += '<circle id="MID_'+i+'" cx="'+ureq.px+'" cy="'+ureq.py+'" r="5" />'; } else if(ureq.type == T_MARKER.PUR) { lmurMarkers[i].MID = "MID_"+i; 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)+'" />'; } } } svgSrc += '</svg>'; lmurDiv.innerHTML = lmurModifyHTML(svgSrc); lmurDiv.style.visibility = ''; lmurUpdateSVGStyles(); } function lmurUpdateSVGStyles() { var sObj = null; for(let i = 0; i < lmurMarkers.length; ++i) { if(lmurMarkers[i].RID != null) { sObj = document.getElementById(lmurMarkers[i].RID); if(sObj != null) { sObj.style.fill = T_RESOLVED.FCOL; sObj.style.fillOpacity = lmurMarkers[i].fOpa; sObj.style.stroke = T_RESOLVED.SCOL; sObj.style.strokeOpacity = lmurMarkers[i].sOpa; } } if(lmurMarkers[i].MID != null) { sObj = document.getElementById(lmurMarkers[i].MID); if(sObj != null) { sObj.style.fill = lmurMarkers[i].fCol; sObj.style.fillOpacity = lmurMarkers[i].fOpa; sObj.style.stroke = lmurMarkers[i].sCol; sObj.style.strokeOpacity = lmurMarkers[i].sOpa; } } } for(let i = 0; i < lmurAreaHighlights.length; ++i) { sObj = document.getElementById(lmurAreaHighlights[i].SID); if(sObj != null) { sObj.style.fill = lmurAreaHighlights[i].fCol; sObj.style.fillOpacity = lmurAreaHighlights[i].fOpa; } } for(var i = 0; i < lmurClusterMarkers.length; ++i) { sObj = document.getElementById(lmurClusterMarkers[i].CID); if(sObj != null) { sObj.style.fill = "black"; sObj.style.stroke = "white"; sObj.style.fillOpacity = lmurClusterMarkers[i].opa; sObj.style.strokeOpacity = 1; sObj = document.getElementById(lmurClusterMarkers[i].TID); if(sObj != null) { sObj.style.textAnchor = "middle"; } } } } function lmurInitDrag() { lmurShowTrace('lmurInitDrag()'); lmurAddLog('inhibiting nudge detection'); lmurInhibitNudgeDetection = true; lmurDiv.style.visibility = 'hidden'; } function lmurEndDrag() { lmurShowTrace('lmurEndDrag()'); lmurAddLog('re-enabling nudge detection'); lmurInhibitNudgeDetection = false; lmurDiv.style.visibility = ''; } function lmurMouseInUI() { lmurShowTrace('lmurMouseInUI()'); lmurInhibitCacheRefresh = true; } function lmurMouseOutUI() { lmurShowTrace('lmurMouseOutUI()'); lmurInhibitCacheRefresh = false; } function lmurChangeDecayPeriod() { lmurShowTrace('lmurChangeDecayPeriod()'); var userDecayValue = document.getElementById('_inputCacheDecayPeriod').value; lmurCacheExpiryPeriod = (parseInt(userDecayValue) * 60); } function lmurCheckActivation() { lmurShowTrace('lmurCheckActivation()'); lmurEnabled = lmurGetCBChecked('_cbEnableLMUR'); var mapObj = document.getElementById("map"); mapObj.onmouseup = null; mapObj.onmousedown = null; if ( ((lmurGetCBChecked('_cbEnablePlayMode')) && (!lmurPlayModeEnabled)) || ((!lmurGetCBChecked('_cbEnablePlayMode')) && (lmurPlayModeEnabled)) ) { lmurInhibitCacheRefresh = false; lmurResetCaches(); } lmurPlayModeEnabled = lmurGetCBChecked('_cbEnablePlayMode'); lmurLSPUpdate(); lmurLOPUpdate(); lmurLMPUpdate(); if ( (!lmurGetCBChecked('_cbShowURs')) && (!lmurGetCBChecked('_cbShowProblems')) && (!lmurGetCBChecked('_cbShowTurnProbs')) && (!lmurGetCBChecked('_cbShowPlaceUpdates')) ) { lmurDiv.innerHTML = lmurModifyHTML(''); return; } lmurNoForcedRefreshThisCycle = false; lmurAddLog('re-visualising after CheckActivation call'); lmurUpdateRequestQueue(); if(lmurDownloadRequests.length === 0) lmurVisualiseMarkers(); mapObj.onmouseup = lmurEndDrag; mapObj.onmousedown = lmurInitDrag; } var lmurLSPObserver = new MutationObserver(function(mutations) { lmurLSPUpdate(); }); function lmurLSPUpdate() { var lsp = document.getElementsByClassName('leaflet-shadow-pane'); if(lsp.length > 0) { lmurLSPObserver.disconnect(); if(lmurGetCBChecked('_cbHideNativeMarkers')) { lsp[0].style.visibility = 'hidden'; } else { lsp[0].style.visibility = ''; } lmurLSPObserver.observe(lsp[0], { childList: true, subtree: true }); } } var lmurLOPObserver = new MutationObserver(function(mutations) { lmurLOPUpdate(); }); function lmurLOPUpdate() { var lop = document.getElementsByClassName('leaflet-overlay-pane'); if(lop.length > 0) { lmurLOPObserver.disconnect(); if(lmurGetCBChecked('_cbHideNativeMarkers')) { for(let p of lop[0].getElementsByTagName("path")) { if ( (p.classList.contains("wm-route") === false) && (p.classList.contains("wm-jam-layer__outline--closure") === false) && (p.classList.contains("wm-jam-layer__bg--closure") === false) && (p.classList.contains("wm-jam-layer__dotted--closure") === false) ) { p.setAttribute("visibility", "hidden"); } } } else { for(let p of lop[0].getElementsByTagName("path")) { p.setAttribute("visibility", ""); } } lmurLOPObserver.observe(lop[0], { childList: true, subtree: true }); } } var lmurLMPObserver = new MutationObserver(function(mutations) { lmurLMPUpdate(); }); function lmurLMPUpdate() { var lmp = document.getElementsByClassName('leaflet-marker-pane'); if(lmp.length > 0) { lmurLMPObserver.disconnect(); if(lmurGetCBChecked('_cbHideNativeMarkers')) { for(let m of lmp[0].getElementsByTagName("div")) { if ( (m.classList.contains("wm-user-icon") === true) || (m.classList.contains("wm-alert-icon") === true) || (m.classList.contains("wm-alert-cluster-icon") === true) ) { m.style.visibility = "hidden"; } } } else { for(let m of lmp[0].getElementsByTagName("div")) { m.style.visibility = ""; } } lmurLMPObserver.observe(lmp[0], { childList: true, subtree: true }); } } function lmurDateToDays(dateToConvert) { lmurShowTrace('lmurDateToDays('+dateToConvert+')'); if(dateToConvert === 0) { return 999999; } var dateNow = new Date(); var elapsedSinceEpoch = dateNow.getTime(); var elapsedSinceEvent = elapsedSinceEpoch - dateToConvert; dateNow.setHours(0); dateNow.setMinutes(0); dateNow.setSeconds(0); dateNow.setMilliseconds(0); var elapsedSinceMidnight = elapsedSinceEpoch - dateNow.getTime(); if(elapsedSinceEvent < elapsedSinceMidnight) { // event occurred today... return 0; } else { // event occurred at some point prior to midnight this morning, so return a minimum value of 1... return 1 + Math.floor((elapsedSinceEvent - elapsedSinceMidnight) / 86400000); } } function lmurGetURAge(urObj,whichAgeToGet) { lmurShowTrace('lmurGetURAge([urObj],'+whichAgeToGet+')'); var uroDate = -1; if(whichAgeToGet === 0) { if(urObj.driveDate !== null) { uroDate = urObj.driveDate; return lmurDateToDays(uroDate); } else return 999999; } else if(whichAgeToGet == 1) { if(urObj.updatedOn !== null) { uroDate = urObj.updatedOn; return lmurDateToDays(uroDate); } else return 999999; } else if(whichAgeToGet == 2) { if((urObj.resolvedOn !== undefined) && (urObj.resolvedOn !== null)) { uroDate = urObj.resolvedOn; return lmurDateToDays(uroDate); } else return 999999; } else if(whichAgeToGet == 3) { if((urObj.venueUpdateRequests.length > 0) && (urObj.venueUpdateRequests[0].dateAdded !== undefined)) { uroDate = urObj.venueUpdateRequests[0].dateAdded; return lmurDateToDays(uroDate); } else return 999999; } else return 999999; } function lmurParseDaysAgo(days) { lmurShowTrace('lmurParseDaysAgo('+days+')'); if(days === 0) return 'today'; else if(days == 1) return '1 day ago'; else return days+' days ago'; } function lmurGetMarkerUnderPointer(mouseX, mouseY) { var urpos = new L.LatLng(0,0); var urpix; var retval = null; var ureq; for(var i=0;i<lmurMarkers.length;i++) { if(!lmurMarkers[i].markerHidden) { ureq = lmurMarkers[i]; urpos.lng = ureq.pos.lng; urpos.lat = ureq.pos.lat; urpix = lmurLatLonToPix(urpos); if(lmurMarkers[i].type == T_MARKER.UR) { if((mouseX >= urpix.x - 5) && (mouseX < urpix.x + 10) && (mouseY >= urpix.y - 5) && (mouseY < urpix.y + 10)) { retval = i; break; } } else { if((mouseX >= urpix.x - 5) && (mouseX < urpix.x + 5) && (mouseY >= urpix.y - 10) && (mouseY < urpix.y + 5)) { retval = i; break; } } } } return retval; } function lmurCheckClickOnMarker(e) { lmurShowTrace('lmurCheckClickOnMarker([e])'); if(!lmurEnabled) { return; } var mouseX = e.pageX; var mouseY = e.pageY; var markerIdx = lmurGetMarkerUnderPointer(mouseX, mouseY); if(markerIdx != null) { var url = 'https://www.waze.com/editor?zoom=5'; url += '&lat=' + lmurMarkers[markerIdx].pos.lat; url += '&lon=' + lmurMarkers[markerIdx].pos.lng; if(lmurMarkers[markerIdx].type == T_MARKER.UR) { url += '&s=85980435&mapUpdateRequest=' + lmurMarkers[markerIdx].obj.id; } else if((lmurMarkers[markerIdx].type == T_MARKER.MP) || (lmurMarkers[markerIdx].type == T_MARKER.MP200)) { url += '&s=85980423&mapProblem=' + encodeURIComponent(lmurMarkers[markerIdx].obj.id); } else if(lmurMarkers[markerIdx].type == T_MARKER.PUR) { url += '&s=1159724501&showpur=' + lmurMarkers[markerIdx].obj.id + '&endshow'; } else { url = null; } if(url != null) { window.open(url); } } return lmurCancelEvent(e); } function lmurCheckOverMarker(e) { lmurShowTrace('lmurCheckOverMarker([e])'); if(!lmurEnabled) { return; } var mouseX = e.pageX; var mouseY = e.pageY; var markerIdx = lmurGetMarkerUnderPointer(mouseX, mouseY); var result = ''; if(markerIdx != null) { var ureq = lmurMarkers[markerIdx].obj; var urAge = lmurGetMarkerAge(lmurMarkers[markerIdx]); if(urAge === null) urAge = '>'+lmurCacheExpiryPeriod; var daysOld; if(lmurMarkers[markerIdx].type == T_MARKER.UR) { var ureqTypeText; if(ureq.type == 6) ureqTypeText = "Incorrect turn"; else if(ureq.type == 7) ureqTypeText = "Incorrect address"; else if(ureq.type == 8) ureqTypeText = "Incorrect route"; else if(ureq.type == 9) ureqTypeText = "Missing roundabout"; else if(ureq.type == 10) ureqTypeText = "General error"; else if(ureq.type == 11) ureqTypeText = "Turn not allowed"; else if(ureq.type == 12) ureqTypeText = "Incorrect junction"; else if(ureq.type == 13) ureqTypeText = "Missing bridge overpass"; else if(ureq.type == 14) ureqTypeText = "Wrong driving direction"; else if(ureq.type == 15) ureqTypeText = "Missing exit"; else if(ureq.type == 16) ureqTypeText = "Missing road"; else if(ureq.type == 19) ureqTypeText = "Blocked road"; else ureqTypeText = "Unknown"; result = '<b>Update Request: ' + ureqTypeText + '</b>'; result += '<br>ID: ' + ureq.id; if(ureq.description !== null) { result += '<br>' + ureq.description.replace(/<\/?[^>]+(>|$)/g, ""); } daysOld = lmurGetURAge(ureq,0); if(daysOld != 999999) { result += '<br><i>Submitted ' + lmurParseDaysAgo(daysOld) + '</i>'; } daysOld = lmurGetURAge(ureq,2); if(daysOld != 999999) { result += '<br><i>Resolved ' + lmurParseDaysAgo(daysOld) + '</i>'; } var nComments = lmurMarkers[markerIdx].nComments; if(nComments == -1) { result += '<br><i>Waiting for comment data...</i>'; } else { result += '<br><i>UR has ' + nComments + ' comment'; if(nComments != 1) result += 's'; result += '</i>'; } result += '<br><small>(Data refreshed '+urAge+'s ago)</small>'; } else { if((lmurMarkers[markerIdx].type == T_MARKER.MP)||(lmurMarkers[markerIdx].type == T_MARKER.MP200)) { if(ureq.subType == 200) { result = '<b>Turn Problem: '; } else { result = '<b>Map Problem: '; } if(ureq.subType == 101) result += 'Driving direction mismatch'; else if(ureq.subType == 102) result += 'Missing junction'; else if(ureq.subType == 103) result += 'Missing road'; else if(ureq.subType == 104) result += 'Cross roads junction missing'; else if(ureq.subType == 105) result += 'Road type mismatch'; else if(ureq.subType == 106) result += 'Restricted turn might be allowed'; else if(ureq.subType == 200) result += 'The displayed route is frequently not taken by users'; else if(ureq.subType == 300) result += 'Road closure request'; else result += 'Unknown problem type ('+ureq.subType+')'; result += '</b><br>'; if(ureq.priority <= 3) result += 'Severity: Low'; else if(ureq.priority <= 7) result += 'Severity: Medium'; else result += 'Severity: High'; } else if(lmurMarkers[markerIdx].type == T_MARKER.PUR) { result = '<b>Place Update</b><br>'; var putype; for(var loop=0; loop<ureq.venueUpdateRequests.length; loop++) { putype = ureq.venueUpdateRequests[loop].type; result += 'Type: '; if(putype == 'VENUE') result += 'New place'; else if(putype == 'IMAGE') result += 'New Photo'; else if(putype == 'REQUEST') result += 'Change Details'; else result += putype; result += '<br>'; } daysOld = lmurGetURAge(ureq,3); if(daysOld != 999999) { result += '<br><i>Received ' + lmurParseDaysAgo(daysOld) + '</i>'; } } daysOld = lmurGetURAge(ureq,2); if(daysOld != 999999) { result += '<br><i>Resolved ' + lmurParseDaysAgo(daysOld) + '</i>'; } result += '<br><small>(Data refreshed '+urAge+'s ago)</small>'; } } if(result === '') { lmurPopup.style.visibility = 'hidden'; } else if(lmurPopup.style.visibility == 'hidden') { lmurPopup.innerHTML = lmurModifyHTML(result); var posX = mouseX; var posY = mouseY; var vpSize = lmurGetVPSize(); if((posX + lmurPopup.clientWidth) > vpSize.x) posX = vpSize.x - lmurPopup.clientWidth; if((posY + lmurPopup.clientHeight + 10) > vpSize.y) posY = vpSize.y - lmurPopup.clientHeight - 10; else posY += 10; lmurPopup.style.left = posX + 'px'; lmurPopup.style.top = posY + 'px'; lmurPopup.style.visibility = 'visible'; } } function lmurToggleDebug() { lmurShowTrace('lmurToggleDebug()'); lmurShowDebugOutput = !lmurShowDebugOutput; var dbgMode = "none"; if(lmurShowDebugOutput) { dbgMode = "inline"; } document.getElementById('_lmurDebugMode').style.display = dbgMode; } function lmurDumpDebug() { lmurShowTrace('lmurDumpDebug()'); var debug = ''; for(var i=0;i<lmurMarkers.length;i++) { var ureq = lmurMarkers[i]; debug += ureq.pos.lng+','; debug += ureq.pos.lat+','; debug += ureq.type+','; debug += ureq.nComments+','; if(ureq.obj.resolvedOn === null) debug += '1<br>'; else debug += '0<br>'; } document.body.innerHTML = lmurModifyHTML(debug); } function lmurUpdateHeader() { lmurShowTrace('lmurUpdateHeader()'); if(document.getElementById('lmurHeader') === null) { window.setTimeout(lmurUpdateHeader,100); return; } lmurUpdateURL = 'https://greasyfork.org/en/scripts/1948-livemap-ur-overlay'; var tHTML = '<img id="_minimax" align=left valign=middle src="'; if(!lmurControlsHidden) { tHTML += lmurIcons[0]; } else { tHTML += lmurIcons[1]; } tHTML += '"/>'; tHTML += '<b><a href="'+lmurUpdateURL+'" target="_blank">LMUR</a></b> <label id="_lmurVersion">v'+lmurVersion+'</label>'; tHTML += '<label id="_lmurDebugMode">(dbg)</label>'; tHTML += ' <input type="checkbox" id="_cbEnableLMUR"'; if(lmurEnabled) tHTML += ' checked'; tHTML += '>Enabled</a>'; lmurDragBar.innerHTML = lmurModifyHTML(tHTML); var dbgMode = "none"; if(lmurShowDebugOutput) { dbgMode = "inline"; } document.getElementById('_lmurDebugMode').style.display = dbgMode; document.getElementById('_cbEnableLMUR').addEventListener("click", lmurCheckActivation, true); document.getElementById('_lmurVersion').addEventListener("click", lmurToggleDebug, true); document.getElementById('_lmurDebugMode').addEventListener("dblclick", lmurDumpDebug, true); } function lmurShowHideCtrls(tab) { lmurShowTrace('lmurShowHideCtrls('+tab+')'); if(lmurControlsMinimised[tab]) { lmurControlsMinimised[tab] = false; document.getElementById(lmurControlsID[tab]).style.height = 'auto'; document.getElementById(lmurControlsID[tab]).style.overflow = 'visible'; document.getElementById(lmurControlsImg[tab]).src = lmurIcons[0]; } else { lmurControlsMinimised[tab] = true; document.getElementById(lmurControlsID[tab]).style.height = '0px'; document.getElementById(lmurControlsID[tab]).style.overflow = 'hidden'; document.getElementById(lmurControlsImg[tab]).src = lmurIcons[1]; } lmurInnerHeight = -1; lmurShowControls(); } function lmurShowHideURCtrls() { lmurShowTrace('lmurShowHideURCtrls()'); lmurShowHideCtrls(0); } function lmurShowHideMPCtrls() { lmurShowTrace('lmurShowHideMPCtrls()'); lmurShowHideCtrls(1); } function lmurShowHidePURCtrls() { lmurShowTrace('lmurShowHidePURCtrls()'); lmurShowHideCtrls(2); } function lmurShowHideOptions() { lmurShowTrace('lmurShowHideOptions()'); lmurShowHideCtrls(3); } function lmurShowControls() { lmurShowTrace('lmurShowControls()'); lmurControlsHidden = false; lmurUpdateHeader(); document.getElementById('_minimax').addEventListener('click', lmurHideControls, false); if(window.innerHeight != lmurInnerHeight) { lmurInnerHeight = window.innerHeight; var htop = document.getElementsByClassName('leaflet-top')[0].offsetTop + document.getElementById('lmurHeader').offsetTop + 10; var hmax = window.innerHeight - htop - 100; document.getElementById('lmurCtrls').style.height = 'auto'; document.getElementById('lmurCtrls').style.height = document.getElementById('lmurCtrls').clientHeight + 1 + 'px'; if(document.getElementById('lmurCtrls').clientHeight > hmax) { document.getElementById('lmurCtrls').style.height = hmax+'px'; } lmurUIHeight = document.getElementById('lmurCtrls').style.height; document.getElementById('lmurCtrls').scrollTop = 0; } else { document.getElementById('lmurCtrls').style.height = lmurUIHeight; } document.getElementById('lmurCtrls').style.overflow = 'auto'; } function lmurHideControls() { lmurShowTrace('lmurHideControls()'); lmurControlsHidden = true; lmurUpdateHeader(); document.getElementById('_minimax').addEventListener('click', lmurShowControls, false); document.getElementById('lmurCtrls').style.height = '0px'; document.getElementById('lmurCtrls').style.overflow = 'hidden'; } function lmurAddCheckbox(id, text, addbr) { var retval = '<input type="checkbox" id="' + id + '">' + text + '</input>'; if(addbr) retval += '<br>'; return retval; } function lmurAddNumInput(id, text, min, size, addbr) { var retval = '<input type="number" min="' + min +'" size="' + size + '" id="' + id + '"> ' + text; if(addbr) retval += '<br>'; return retval; } function lmurAddTextInput(id, text, addbr) { var retval = '<input type="text" id="' + id + '"> ' + text; if(addbr) retval += '<br>'; return retval; } function lmurAddRadioBtn(id, group, text, ischecked, addbr) { var retval = '<input type="radio" name="' + group + '" id="' + id + '"'; if(ischecked) retval += ' checked'; retval += '/>' + text; if (addbr) retval += '<br>'; return retval; } function lmurRemoveWazeStyling() { var elm = null; var myStyle = ''; for(var i = 0; i < document.getElementById('lmurUI').getElementsByTagName('input').length; i++) { elm = document.getElementById('lmurUI').getElementsByTagName('input')[i]; myStyle = "opacity:1;position:relative;padding:0 0;color:#000000;"; if(elm.type == "number") myStyle += "width:50px;height:auto;"; else if(elm.type == "text") myStyle += "line-height:14px;height:auto;margin-bottom:4px;"; elm.style = myStyle; } } var lmurDragging = false; var lmurPrevMouseX; var lmurPrevMouseY; var lmurWindowLeft = 0; var lmurWindowTop = 0; function lmurCancelEvent(e) { e = e ? e : window.event; if(e.stopPropagation) { e.stopPropagation(); } if(e.preventDefault) { e.preventDefault(); } e.cancelBubble = true; e.cancel = true; e.returnValue = false; return false; } function lmurDragbarMouseDown(e) { lmurPrevMouseX = e.pageX; lmurPrevMouseY = e.pageY; lmurDragging = true; //lmurDragBar.style.cursor = 'move'; document.body.addEventListener('mousemove', lmurDragbarMouseMove, false); document.body.addEventListener('mouseup', lmurDragbarMouseUp, false); return true; } function lmurDragbarMouseUp() { if(lmurDragging) { lmurDragging = false; localStorage.LMURWindowLeft = lmurWindowLeft; localStorage.LMURWindowTop = lmurWindowTop; } //lmurDragBar.style.cursor = 'auto'; document.body.removeEventListener('mousemove', lmurDragbarMouseMove, false); document.body.removeEventListener('mouseup', lmurDragbarMouseUp, false); return true; } function lmurDragbarMouseMove(e) { var vpHeight = window.innerHeight; var vpWidth = window.innerWidth; lmurWindowTop = parseInt(lmurWindowTop) + parseInt((e.pageY - lmurPrevMouseY)); lmurWindowLeft = parseInt(lmurWindowLeft) + parseInt((e.pageX - lmurPrevMouseX)); lmurPrevMouseX = e.pageX; lmurPrevMouseY = e.pageY; if(lmurWindowTop < 0) lmurWindowTop = 0; if(lmurWindowTop + 16 >= vpHeight) lmurWindowTop = vpHeight-16; if(lmurWindowLeft < 0) lmurWindowLeft = 0; if(lmurWindowLeft + 32 >= vpWidth) lmurWindowLeft = vpWidth-32; lmurWindow.style.top = lmurWindowTop+'px'; lmurWindow.style.left = lmurWindowLeft+'px'; return lmurCancelEvent(e); } function lmurAddUIHeaderStyle(uID, bgCol) { var uObj = document.getElementById(uID); uObj.style.backgroundColor = bgCol; uObj.style.padding = "10px"; uObj.style.height = "auto"; } function lmurAddUIColStyle(uID, bgCol) { var uObj = document.getElementById(uID); uObj.style.float = "left"; uObj.style.paddingLeft = "10px"; uObj.style.paddingRight = "10px"; uObj.style.height = "auto"; if(bgCol != null) { uObj.style.backgroundColor = bgCol; } } function lmurAddUIDivSepStyle(uID) { var uObj = document.getElementById(uID); uObj.style.clear = "both"; } function lmurAddUIStyles() { if(document.getElementById("lmurCtrls") == null) { window.setTimeout(lmurAddUIStyles, 100); return; } lmurAddUIHeaderStyle("lmurURCtrlOuter", "#DDFFDD"); lmurAddUIHeaderStyle("lmurMPCtrlOuter", "#DDDDFF"); lmurAddUIHeaderStyle("lmurPURCtrlOuter", "#FFDDDD"); lmurAddUIHeaderStyle("lmurOptionsOuter", "#EEEEEE"); lmurAddUIColStyle("lmurURCtrls_lCol", null); lmurAddUIColStyle("lmurURCtrls_rCol", null); lmurAddUIColStyle("lmurMPCtrls_lCol", null); lmurAddUIColStyle("lmurMPCtrls_mCol", null); lmurAddUIColStyle("lmurMPCtrls_rCol", null); lmurAddUIColStyle("lmurPURCtrls_lCol", null); lmurAddUIColStyle("lmurURCtrls_Tags_lCol", "#CCEECC"); lmurAddUIColStyle("lmurURCtrls_Tags_lCol", "#CCEECC"); lmurAddUIDivSepStyle("lmurURCtrls_DivSep1"); lmurAddUIDivSepStyle("lmurURCtrls_DivSep2"); lmurAddUIDivSepStyle("lmurURCtrls_DivSep3"); lmurAddUIDivSepStyle("lmurURCtrls_DivSep4"); } function lmurEnhanceRouteDetails() { var ri = document.getElementsByClassName('wm-routes-item-desktop'); if(ri.length > 0) { RouteObserver.disconnect(); var lra = document.getElementsByClassName('lmurAreas'); var nLRA = lra.length; while(nLRA > 0) { --nLRA; document.getElementsByClassName('lmurAreas')[nLRA].remove(); } var rIdx = 0; for(let r of ri) { var rString; var routeTime = lmurRouteDetails[rIdx].rTime; var rtS = routeTime % 60; routeTime -= rtS; routeTime /= 60; var rtM = routeTime % 60; routeTime -= rtM; routeTime /= 60; var rtH = routeTime % 24; routeTime -= rtH; routeTime /= 24; rString = rtH + "h " + rtM + "m " + rtS + "s"; r.childNodes[0].childNodes[1].childNodes[0].innerText = rString; var rDist = lmurRouteDetails[rIdx].rDist; rString = (Math.round(rDist / 10) / 100) + 'km / '; rDist /= 1.609; rString += (Math.round(rDist / 10) / 100) + 'miles'; r.childNodes[1].childNodes[0].childNodes[1].innerText = rString; var nAreas = lmurRouteDetails[rIdx].rAreas.length; if(nAreas > 0) { var tSpan = document.createElement('span'); tSpan.className = "lmurAreas"; var iHTML = '<br>'; for(var i = 0; i < nAreas; ++i) { iHTML += lmurRouteDetails[rIdx].rAreas[i] + '<br>'; } tSpan.innerHTML = lmurModifyHTML(iHTML); r.childNodes[1].appendChild(tSpan); } ++rIdx; } RouteObserver.observe(document.getElementsByClassName('wm-card is-routing')[0], { childList: true, subtree: true }); } } var RouteObserver = new MutationObserver(function(mutations) { if(lmurRouteDetails.length > 0) { // Call this here in case our request promise handler fired before the native one, such // that we already have the info required to enhance the default route details which we // now know will be present in the DOM... lmurEnhanceRouteDetails(); } }); function lmurFakeOnload() { lmurShowTrace('lmurFakeOnload()'); lmurAddLog('onload'); if(document.getElementById('lmurUI') === null) { lmurAddLog(' adding lmurUI container...'); // add a new div to hold the OS Locator results, in the form of a draggable window lmurWindow = document.createElement('div'); lmurWindow.id = "lmurWindow"; lmurWindow.style.position = 'absolute'; lmurWindow.style.border = '1px solid #BBDDBB'; lmurWindow.style.borderRadius = '4px'; lmurWindow.style.overflow = 'hidden'; lmurWindow.style.zIndex = 2000; lmurWindow.style.opacity = 0; lmurWindow.style.transitionProperty = "opacity"; lmurWindow.style.transitionDuration = "1000ms"; lmurWindow.style.webkitTransitionProperty = "opacity"; lmurWindow.style.webkitTransitionDuration = "1000ms"; lmurWindow.style.boxShadow = '5px 5px 10px Silver'; document.body.appendChild(lmurWindow); // dragbar div lmurDragBar = document.createElement('div'); lmurDragBar.id = "lmurDragBar"; lmurDragBar.style.backgroundColor = '#D0D0D0'; lmurDragBar.style.padding = '4px'; lmurDragBar.style.fontSize = '16px'; lmurDragBar.style.lineHeight = '18px'; lmurWindow.appendChild(lmurDragBar); lmurWindow.appendChild(lmurUI); lmurUI.id = "lmurUI"; lmurUI.style.lineHeight = '16px'; lmurUI.style.overflow = 'hidden'; lmurUI.addEventListener('mouseover', lmurMouseInUI, false); lmurUI.addEventListener('mouseout', lmurMouseOutUI, false); lmurDragBar.addEventListener('mousedown', lmurDragbarMouseDown, false); lmurDragBar.addEventListener('mouseup', lmurDragbarMouseUp, false); lmurDragBar.innerHTML = lmurModifyHTML('<b>LMUR v'+lmurVersion+'</b>'); lmurWindow.style.opacity = 1; lmurAddLog('...done'); } else { lmurAddLog(' lmurUI container already present'); } var tHTML; if(!lmurIsLoggedIn) { tHTML = '<b><a href="'+lmurUpdateURL+'" target="_blank">LMUR</a></b> v'+lmurVersion; tHTML += ' - Please log-in to the Livemap server to enable LMUR operation.'; lmurDragBar.innerHTML = lmurModifyHTML(tHTML); } else if(document.location.protocol == 'https:') { lmurAddLog(' adding lmurUI contents...'); var gmapObj = document.getElementById('map'); gmapObj.addEventListener("mousemove", lmurCheckOverMarker, false); gmapObj.addEventListener("click", lmurCheckClickOnMarker, false); gmapObj.appendChild(lmurDiv); gmapObj.appendChild(lmurPopup); tHTML = '<div id="lmurHeader">'; tHTML += '</div>'; tHTML += '<div id="lmurCtrls">'; tHTML += '<div id="lmurURCtrlOuter">'; tHTML += '<img id="_minimaxURCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>UR Filtering</b> '; tHTML += lmurAddCheckbox("_cbShowURs", '', true); tHTML += '<div id="lmurURCtrls">'; tHTML += lmurAddRadioBtn("_radioShowURs", "lmurShowURs", 'Show or ', false, false); tHTML += lmurAddRadioBtn("_radioHideURs", "lmurShowURs", 'hide URs by type:', true, true); tHTML += '<div id="lmurURCtrls_lCol">'; tHTML += lmurAddCheckbox("_cbURFilterIncorrectTurn", 'Incorrect turn', true); tHTML += lmurAddCheckbox("_cbURFilterIncorrectAddress", 'Incorrect address', true); tHTML += lmurAddCheckbox("_cbURFilterIncorrectRoute", 'Incorrect route', true); tHTML += lmurAddCheckbox("_cbURFilterIncorrectJunction", 'Incorrect junction', true); tHTML += lmurAddCheckbox("_cbURFilterWazeAuto", 'Waze Automatic', true); tHTML += lmurAddCheckbox("_cbURFilterGeneralError", 'General error', true); tHTML += lmurAddCheckbox("_cbURFilterTurnNotAllowed", 'Turn not allowed', true); tHTML += lmurAddCheckbox("_cbURFilterUndefined", 'Undefined', true); tHTML += '</div>'; tHTML += '<div id="lmurURCtrls_rCol">'; tHTML += lmurAddCheckbox("_cbURFilterMissingRoundabout",'Missing roundabout', true); tHTML += lmurAddCheckbox("_cbURFilterMissingBridgeOverpass", 'Missing bridge overpass' ,true); tHTML += lmurAddCheckbox("_cbURFilterMissingExit", 'Missing exit', true); tHTML += lmurAddCheckbox("_cbURFilterMissingRoad", 'Missing road', true); tHTML += lmurAddCheckbox("_cbURFilterMissingLandmark", 'Missing landmark', true); tHTML += lmurAddCheckbox("_cbURFilterWrongDrivingDirection", 'Wrong driving direction', true); tHTML += lmurAddCheckbox("_cbURFilterBlockedRoad", 'Blocked Road', true); tHTML += '<br>'; tHTML += '</div>'; tHTML += '<div id="lmurURCtrls_DivSep1">'; tHTML += '</div>'; tHTML += '<div id="lmurURCtrls_Tags_lCol">'; tHTML += '<i>Tagged URs</i><br>'; tHTML += lmurAddCheckbox("_cbURFilterRoadworks", '[ROADWORKS]', true); tHTML += lmurAddCheckbox("_cbURFilterConstruction", '[CONSTRUCTION]', true); tHTML += lmurAddCheckbox("_cbURFilterNote", '[NOTE]', true); tHTML += '</div>'; tHTML += '<div id="lmurURCtrls_Tags_lCol">'; tHTML += '<br>'; tHTML += lmurAddCheckbox("_cbURFilterClosure", '[CLOSURE]', true); tHTML += lmurAddCheckbox("_cbURFilterEvent", '[EVENT]', true); tHTML += ' '; tHTML += '</div>'; tHTML += '<div id="lmurURCtrls_DivSep2">'; tHTML += '</div>'; tHTML += '<br>'; tHTML += lmurAddCheckbox("_cbUREnableResolvedFilter", 'Hide resolved URs', true); tHTML += lmurAddCheckbox("_cbUREnableMinAgeFilter", 'Hide URs less than ', false); tHTML += lmurAddNumInput("_inputURFilterMinDays", 'days old', 1, 3, true); tHTML += lmurAddCheckbox("_cbUREnableMaxAgeFilter", 'Hide URs more than ', false); tHTML += lmurAddNumInput("_inputURFilterMaxDays", 'days old', 1, 3, true); tHTML += '<br>'; tHTML += lmurAddCheckbox("_cbURHideWithNoDescription", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowWithNoDescription", 'show URs with no description', true); tHTML += lmurAddCheckbox("_cbUREnableKeywordMustBePresent", 'Hide URs not including ', false); tHTML += lmurAddTextInput("_textURKeywordPresent", 'in their description', true); tHTML += lmurAddCheckbox("_cbUREnableKeywordMustBeAbsent", 'Hide URs including ', false); tHTML += lmurAddTextInput("_textURKeywordAbsent", 'in their description', true); tHTML += lmurAddCheckbox("_cbURCaseInsensitive", 'Case-insensitive matching', true); tHTML += '<br><br>Filter URs by comments:<br>'; tHTML += lmurAddCheckbox("_cbURHideUnloadedComments", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowUnloadedComments", 'show URs where comment data has not been received from server', true); tHTML += '<br>'; tHTML += lmurAddCheckbox("_cbURHideWithMyComments", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowWithMyComments", 'show URs with comments from me', true); tHTML += lmurAddCheckbox("_cbURHideLastCommentByMe", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowLastCommentByMe", 'show URs last commented on by me', true); tHTML += lmurAddCheckbox("_cbURHideLastCommentByReporter", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowLastCommentByReporter", 'show URs last commented on by reporter', true); tHTML += lmurAddCheckbox("_cbURHideWithLessThanComments", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowWithLessThanComments", 'show with less than ', false); tHTML += lmurAddNumInput("_inputFilterMinComments", 'comments', 0, 3, true); tHTML += lmurAddCheckbox("_cbURHideFollowedURs", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowFollowedURs", 'show URs I\'m following', true); tHTML += lmurAddCheckbox("_cbURHideLastCommentAge", 'Hide or ', false); tHTML += lmurAddCheckbox("_cbURShowLastCommentAge", 'show if last comment made less than ', false); tHTML += lmurAddNumInput("_inputFilterCommentAge", 'days ago', 0, 3, true); tHTML += '<br>'; tHTML += lmurAddCheckbox("_cbEnablePlayMode", 'Show UR markers outside my editable area', true); tHTML += '</div>'; tHTML += '</div>'; tHTML += '<div id="lmurMPCtrlOuter">'; tHTML += '<img id="_minimaxMPCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>MP Filtering</b> '; tHTML += lmurAddCheckbox("_cbShowProblems", '', true); tHTML += '<div id="lmurMPCtrls">'; tHTML += lmurAddRadioBtn("_radioShowProblems", "lmurShowProblems", 'Show or ', false, false); tHTML += lmurAddRadioBtn("_radioHideProblems", "lmurShowProblems", 'hide map problems by type:', true, true); tHTML += '<div id="lmurMPCtrls_lCol">'; tHTML += lmurAddCheckbox("_cbMPFilterMissingJunction", 'Missing junction', true); tHTML += lmurAddCheckbox("_cbMPFilterMissingRoad", 'Missing road', true); tHTML += lmurAddCheckbox("_cbMPFilterCrossroadsJunctionMissing", 'Missing crossroads', true); tHTML += '</div>'; tHTML += '<div id="lmurMPCtrls_mCol">'; tHTML += lmurAddCheckbox("_cbMPFilterDrivingDirectionMismatch", 'Driving direction mismatch', true); tHTML += lmurAddCheckbox("_cbMPFilterRoadTypeMismatch", 'Road type mismatch', true); tHTML += lmurAddCheckbox("_cbMPFilterRoadClosure", 'Road closure', true); tHTML += '</div>'; tHTML += '<div id="lmurMPCtrls_rCol">'; tHTML += lmurAddCheckbox("_cbMPFilterRestrictedTurn", 'Restricted turn might be allowed', true); tHTML += lmurAddCheckbox("_cbMPFilterUnknownProblem", 'Unknown problem type', true); tHTML += '</div>'; tHTML += '<div id="lmurURCtrls_DivSep3">'; tHTML += '</div>'; tHTML += '<br>'; tHTML += lmurAddCheckbox("_cbMPEnableResolvedFilter", 'Hide resolved Problems', true); tHTML += '<br>'; tHTML += 'Hide problems by severity:<br>'; tHTML += lmurAddCheckbox("_cbMPFilterLowSeverity", 'Low', false); tHTML += lmurAddCheckbox("_cbMPFilterMediumSeverity", 'Medium', false); tHTML += lmurAddCheckbox("_cbMPFilterHighSeverity", 'High', true); tHTML += '<br>'; tHTML += lmurAddCheckbox("_cbShowTurnProbs", 'Show Turn Problems', true); tHTML += lmurAddCheckbox("_cbTPEnableResolvedFilter", 'Hide resolved Turn Problems', false); tHTML += '</div>'; tHTML += '</div>'; tHTML += '<div id="lmurPURCtrlOuter">'; tHTML += '<img id="_minimaxPURCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>PUR Filtering</b> '; tHTML += lmurAddCheckbox("_cbShowPlaceUpdates", '', true); tHTML += '<div id="lmurPURCtrls">'; tHTML += lmurAddRadioBtn("_radioShowPURs", "lmurShowPURs", 'Show or ', false, false); tHTML += lmurAddRadioBtn("_radioHidePURs", "lmurShowPURs", 'hide PURs by type:', true, true); tHTML += '<div id="lmurPURCtrls_lCol">'; tHTML += lmurAddCheckbox("_cbPURFilterNewPlace", 'New place', true); tHTML += lmurAddCheckbox("_cbPURFilterUpdateDetails", 'Updated details', true); tHTML += lmurAddCheckbox("_cbPURFilterNewPhoto", 'New photo', true); tHTML += lmurAddCheckbox("_cbPURFilterFlagged", 'Flagged for attention', true); tHTML += lmurAddCheckbox("_cbPURNonZeroLockRank", 'Non-zero lockRank', true); tHTML += '</div>'; tHTML += '<div id="lmurURCtrls_DivSep4">'; tHTML += '</div>'; tHTML += lmurAddCheckbox("_cbPUREnableMinAgeFilter", 'Hide PURs less than ', false); tHTML += lmurAddNumInput("_inputPURFilterMinDays", 'days old', 1, 3, true); tHTML += lmurAddCheckbox("_cbPUREnableMaxAgeFilter", 'Hide PURs more than ', false); tHTML += lmurAddNumInput("_inputPURFilterMaxDays", 'days old', 1, 3, true); tHTML += lmurAddCheckbox("_cbPURFilterResidential", 'Hide Residential PURs', true); tHTML += lmurAddCheckbox("_cbPURFilterNonResidential", 'Hide Non-residential PURs', true); tHTML += '<br>'; tHTML += '</div>'; tHTML += '</div>'; tHTML += '<div id="lmurOptionsOuter">'; tHTML += '<img id="_minimaxLMURCtrls" align=left valign=middle src="' + lmurIcons[0] + '"/><b>Options</b><br>'; tHTML += '<div id="lmurOptions">'; tHTML += 'Select Server: '; tHTML += lmurAddRadioBtn("_radioROWServer", "lmurSelectServer", 'RoW ', false, false); tHTML += lmurAddRadioBtn("_radioUSAServer", "lmurSelectServer", 'USA ', false, false); tHTML += lmurAddRadioBtn("_radioIsraelServer", "lmurSelectServer", 'Israel', false, true); tHTML += lmurAddCheckbox("_cbHideNativeMarkers", 'Hide Livemap markers', true); tHTML += lmurAddCheckbox("_cbClusteringDisabled", 'Disable marker clustering', true); tHTML += lmurAddCheckbox("_cbHighlightDisabled", 'Disable cached area highlight', true); tHTML += 'Removed cached blocks after '; tHTML += lmurAddNumInput("_inputCacheDecayPeriod", 'minutes', 0, 1440, true); tHTML += '<i>(Range is 0-1440 minutes, 0 = never remove)</i>'; tHTML += '</div>'; tHTML += '</div>'; tHTML += '</div>'; lmurUI.innerHTML = lmurModifyHTML(tHTML); lmurAddLog(' ...done'); lmurUI.style.backgroundColor = '#FFFFFF'; lmurAddUIStyles(); lmurShowHideURCtrls(); lmurShowHideMPCtrls(); lmurShowHidePURCtrls(); lmurShowHideOptions(); lmurHideControls(); lmurUI.addEventListener("click", lmurCheckActivation, true); document.getElementById('_inputCacheDecayPeriod').addEventListener("change", lmurChangeDecayPeriod, true); document.getElementById('_radioROWServer').addEventListener("click", lmurChangeServer, true); document.getElementById('_radioUSAServer').addEventListener("click", lmurChangeServer, true); document.getElementById('_radioIsraelServer').addEventListener("click", lmurChangeServer, true); document.getElementById('_minimaxURCtrls').addEventListener("click", lmurShowHideURCtrls, true); document.getElementById('_minimaxMPCtrls').addEventListener("click", lmurShowHideMPCtrls, true); document.getElementById('_minimaxPURCtrls').addEventListener("click", lmurShowHidePURCtrls, true); document.getElementById('_minimaxLMURCtrls').addEventListener("click", lmurShowHideOptions, true); lmurPopup.style.visibility = 'hidden'; lmurLoadSettings(); lmurCheckActivation(); lmurRemoveWazeStyling(); } else { tHTML = '<b><a href="'+lmurUpdateURL+'" target="_blank">LMUR</a></b> v'+lmurVersion; tHTML += ' - requires a HTTPS connection, please click '; tHTML += '<a href="https://' + document.location.host + document.location.pathname + '">here</a> to switch'; lmurDragBar.innerHTML = lmurModifyHTML(tHTML); } if ( (localStorage.LMURWindowTop === undefined)|| (localStorage.LMURWindowLeft === undefined)|| (localStorage.LMURWindowTop === "NaN")|| (localStorage.LMURWindowLeft === "NaN")|| (localStorage.LMURWindowTop > window.innerHeight)|| (localStorage.LMURWindowLeft > window.innerWidth)|| (localStorage.LMURWindowTop < 0)|| (localStorage.LMURWindowLeft < 0) ) { lmurWindow.style.top = '0px'; lmurWindow.style.left = '0px'; lmurWindowTop = 0; lmurWindowLeft = 0; } else { lmurWindowTop = localStorage.LMURWindowTop; lmurWindowLeft = localStorage.LMURWindowLeft; lmurWindow.style.top = lmurWindowTop +'px'; lmurWindow.style.left = lmurWindowLeft + 'px'; } RouteObserver.observe(document.getElementsByClassName('wm-card is-routing')[0], { childList: true, subtree: true }); var lsp = document.getElementsByClassName('leaflet-shadow-pane'); if(lsp.length > 0) { lmurLSPObserver.observe(lsp[0], { childList: true, subtree: true }); } var lop = document.getElementsByClassName('leaflet-overlay-pane'); if(lop.length > 0) { lmurLOPObserver.observe(lop[0], { childList: true, subtree: true }); } var lmp = document.getElementsByClassName('leaflet-marker-pane'); if(lmp.length > 0) { lmurLMPObserver.observe(lmp[0], { childList: true, subtree: true }); } lmurDoOnload = false; lmurAddLog('onload complete'); } function lmurHeartbeat() { //lmurShowTrace('lmurHeartbeat()'); var oldLoginState = lmurIsLoggedIn; var revisualise = false; lmurIsLoggedIn = (document.getElementsByClassName('wz-header__login-button').length === 0); if(oldLoginState != lmurIsLoggedIn) { if(!lmurIsLoggedIn) { // temporarily reinstate lmurIsLoggedIn so that lmurSaveSettings() won't just return as soon as it's called... lmurIsLoggedIn = true; lmurSaveSettings(); lmurIsLoggedIn = false; } lmurDoOnload = true; revisualise = true; } if(lmurIsLoggedIn) { if(lmurUserName.length === 0) { var lmurRequest = new XMLHttpRequest(); lmurRequest.onreadystatechange = function () { if (lmurRequest.readyState == 4) { lmurAddLog('Get user data response '+lmurRequest.status+' received'); if (lmurRequest.status == 200) { var lmurData = JSON.parse(lmurRequest.responseText); lmurUserName = lmurData.username; lmurUserID = lmurData.id; lmurAddLog('user '+lmurUserName+' (ID: '+lmurUserID+') has logged-in'); } } }; var lmurFetchURL = 'https://www.waze.com/UsersProfile/app/userInfo'; lmurAddLog('requesting '+lmurFetchURL); lmurRequest.open("GET", lmurFetchURL, true); lmurRequest.send(); } } else { if(lmurUserID !== null) { lmurAddLog('user has logged-out'); lmurUserID = null; } } // reload UI if it gets nuked by Livemap when the user closes the route options window if(document.getElementById('lmurUI') === null) { lmurDoOnload = true; } if(lmurDoOnload) { lmurFakeOnload(); if(revisualise) { lmurAddLog('re-visualising after login state change'); lmurNoForcedRefreshThisCycle = false; lmurVisualiseMarkers(); } } else { } if(lmurClearStartupCrud === true) { if(document.getElementsByClassName('wz-downloadbar__close-button').length > 0) { document.getElementsByClassName('wz-downloadbar__close-button')[0].click(); lmurClearStartupCrud = false; } } window.setTimeout(lmurHeartbeat,100); } function lmurDecayCache() { lmurShowTrace('lmurDecayCache()'); if(lmurInhibitNudgeDetection) return; if(lmurNoForcedRefreshThisCycle) { lmurVisualiseMarkers(); } else { lmurAddLog('auto cache decay blocked by manual cache reload'); } lmurNoForcedRefreshThisCycle = true; } function lmurRouteDetailObj(rTime, rDist, rAreas) { this.rTime = rTime; this.rDist = rDist; this.rAreas = rAreas; } function lmurParseRouteResponse(respBody) { // For each route returned in this response, store the bits of information we use to enhance the // route details... lmurRouteDetails = []; for(var rIdx = 0; rIdx < respBody.alternatives.length; ++rIdx) { let r = respBody.alternatives[rIdx].response; lmurRouteDetails.push(new lmurRouteDetailObj(r.totalSeconds, r.totalLength, r.areas)); } // ...and then attempt to apply the enhancements - this may or may not work at this point depending // on how the asynchronous nature of the response promises are handled... if ours is handled before // the native one then the basic details won't yet be present in the sidebar and so the enhancement // call will fail, whereas if the native one is handled first then the sidebar will now be ready for // us to tweak. lmurEnhanceRouteDetails(); } function lmurAddInterceptor() { // intercept XHR open so we can grab the current viewport lat/lon bounds from the request LM sends to // the servers to get its map data, now that access to this sort of stuff has been hidden from us // with the removal of W.app.map... // From https://lowrey.me/intercept-2/ const origXHRopen = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function() { if(arguments[1].indexOf("georss") != -1) { // the lat/lon bounds are passed up to the server as arguments in the XHR URL, so split these off into // an array for easier processing var argBits = arguments[1].split('&'); for(var i = 0; i < argBits.length; ++i) { // now iterate through the array looking for those entries containing the four bounding values // we're after... if(argBits[i].indexOf('left=') != -1) lmurVPLeft = parseFloat(argBits[i].split('=')[1]); if(argBits[i].indexOf('right=') != -1) lmurVPRight = parseFloat(argBits[i].split('=')[1]); if(argBits[i].indexOf('top=') != -1) lmurVPTop = parseFloat(argBits[i].split('=')[1]); if(argBits[i].indexOf('bottom=') != -1) lmurVPBottom = parseFloat(argBits[i].split('=')[1]); } // adjust the bounds to compensate for overscan var bWidth = lmurVPRight - lmurVPLeft; var bHeight = lmurVPTop - lmurVPBottom; var xCentre = (lmurVPRight + lmurVPLeft) / 2; var yCentre = (lmurVPTop + lmurVPBottom) / 2; // these scaling factors seem to work nicely at all zoom levels for the UK map in Chrome, need to // see if they're universal... bWidth *= 0.83; bHeight *= 0.83; lmurVPLeft = xCentre - (bWidth / 2); lmurVPRight = xCentre + (bWidth / 2); lmurVPTop = yCentre + (bHeight / 2); lmurVPBottom = yCentre - (bHeight / 2); if(!lmurInhibitNudgeDetection) { lmurAddLog('re-visualising after map nudge'); lmurNoForcedRefreshThisCycle = false; lmurUpdateRequestQueue(); lmurVisualiseMarkers(); } } origXHRopen.apply(this, arguments); } // also intercept fetch() so we can grab the responses to routing requests... // From https://blog.logrocket.com/intercepting-javascript-fetch-api-requests-responses/ // and https://stackoverflow.com/questions/45425169/intercept-fetch-api-requests-and-responses-in-javascript const origFetch = window.fetch; window.fetch = async (...args) => { let [resource, config ] = args; const response = await origFetch(resource, config); // let all responses through as-is, except for the ones related to routing requests, // which include the details we need to enhance the route results - these responses are // always originated from a request which includes "user-drive" in its URL... if(response.url.indexOf('user-drive') != -1) { response .clone() .json() .then(body => lmurParseRouteResponse(body)); } return response; }; } function lmurInitialise() { lmurShowTrace('lmurInitialise()'); lmurAddInterceptor(); lmurDiv = document.createElement('div'); lmurPopup = document.createElement('div'); lmurUI = document.createElement('div'); lmurResetCaches(); lmurAddLog('initialisation'); lmurDiv.id = 'lmurDiv'; lmurDiv.style.position = 'absolute'; lmurDiv.style.top = '0'; lmurDiv.style.left = '0'; lmurDiv.style.zIndex = 6; lmurDiv.style.pointerEvents = 'none'; lmurPopup.id = 'lmurPopup'; lmurPopup.style.position = 'absolute'; lmurPopup.style.top = '0'; lmurPopup.style.left = '0'; lmurPopup.style.zIndex = 6; lmurPopup.style.pointerEvents = 'none'; lmurPopup.style.backgroundColor = 'aliceblue'; lmurPopup.style.border = '1px solid blue'; lmurPopup.style.boxShadow = '5px 5px 10px Silver'; lmurPopup.style.padding = '4px'; window.addEventListener("beforeunload", lmurSaveSettings, false); window.setTimeout(lmurHeartbeat,2000); window.setTimeout(lmurGetMarkers,2500); window.setInterval(lmurDecayCache,30000); } lmurInitialise();