TISWAS

Lists all turn instructions defined within the current map view

  1. // ==UserScript==
  2. // @name TISWAS
  3. // @namespace http://greasemonkey.chizzum.com
  4. // @description Lists all turn instructions defined within the current map view
  5. // @include https://*.waze.com/*editor*
  6. // @include https://editor-beta.waze.com/*
  7. // @include https://beta.waze.com/*
  8. // @exclude https://www.waze.com/user/*editor/*
  9. // @exclude https://www.waze.com/*/user/*editor/*
  10. // @grant none
  11. // @version 0.8
  12. // ==/UserScript==
  13.  
  14. /* JSHint Directives */
  15. /* globals W: true */
  16. /* globals trustedTypes: */
  17. /* jshint bitwise: false */
  18. /* jshint eqnull: true */
  19. /* jshint esversion: 11 */
  20. /* jshint undef: true */
  21. /* jshint unused: true */
  22.  
  23. const TISWAS =
  24. {
  25. graphEntries: [],
  26.  
  27. ModifyHTML: function(htmlIn)
  28. {
  29. if(typeof trustedTypes === "undefined")
  30. {
  31. return htmlIn;
  32. }
  33. else
  34. {
  35. const escapeHTMLPolicy = trustedTypes.createPolicy("forceInner", {createHTML: (to_escape) => to_escape});
  36. return escapeHTMLPolicy.createHTML(htmlIn);
  37. }
  38. },
  39. AddEventListener: function(elm,eventType,eventFn,eventBool)
  40. {
  41. try
  42. {
  43. document.getElementById(elm).addEventListener(eventType, eventFn, eventBool);
  44. }
  45. catch(err)
  46. {
  47. TISWAS.AddLog('AddEventListener() - '+elm+' not found!');
  48. }
  49. },
  50. AddLog: function(logtext)
  51. {
  52. console.log('TISWAS: '+Date()+' '+logtext);
  53. },
  54. RegexContains: function(text, contains)
  55. {
  56. let retval = false;
  57. if(text !== null)
  58. {
  59. let re = RegExp(contains, 'i');
  60. if(text.search(re) != -1)
  61. {
  62. retval = true;
  63. }
  64. }
  65. return retval;
  66. },
  67.  
  68. GraphEntry: function(segID, es, rs, t, tts, vi)
  69. {
  70. this.segID = segID;
  71. this.es = es;
  72. this.rs = rs;
  73. this.t = t;
  74. this.tts = tts;
  75. this.vi = vi;
  76. },
  77. PushGraphEntry: function(e)
  78. {
  79. for(let i in e)
  80. {
  81. if(e.hasOwnProperty(i))
  82. {
  83. let tg = e[i].turnGuidance;
  84. if(tg !== null)
  85. {
  86. let segID = i;
  87. segID = segID.replace("f","");
  88. segID = segID.replace("r","");
  89.  
  90. let es = [];
  91. let rs = [];
  92.  
  93. if(tg.exitSigns !== null)
  94. {
  95. for(let j = 0; j < tg.exitSigns.length; ++j)
  96. {
  97. es.push(tg.exitSigns[j]);
  98. }
  99. }
  100. if(tg.roadShields !== null)
  101. {
  102. for(let j in tg.roadShields)
  103. {
  104. if(tg.roadShields.hasOwnProperty(j))
  105. {
  106. rs.push(tg.roadShields[j]);
  107. }
  108. }
  109. }
  110.  
  111. let entry = new TISWAS.GraphEntry(segID, es, rs, tg.towards, tg.tts, tg.visualInstruction);
  112. TISWAS.graphEntries.push(entry);
  113. }
  114. }
  115. }
  116. },
  117. SegSelect: function(e)
  118. {
  119. let segID = e.currentTarget.attributes.tag.value;
  120. let segObj = W.model.segments.objects[segID];
  121. let segCenter = segObj.attributes.geometry.getBounds().getCenterLonLat();
  122. W.selectionManager.setSelectedModels(segObj);
  123. W.map.setCenter(segCenter);
  124. },
  125. ReplaceShieldIDs: function(textIn, rs)
  126. {
  127. while(textIn.indexOf("$RS") !== -1)
  128. {
  129. let start = textIn.indexOf("$RS");
  130. let end = textIn.indexOf(" ", start);
  131. let rsID = null;
  132. if(end === -1)
  133. {
  134. rsID = parseInt(textIn.slice(start + 4));
  135. }
  136. else
  137. {
  138. rsID = parseInt(textIn.slice(start + 4, end));
  139. }
  140.  
  141. let rsImg = "";
  142. if(rsID !== null)
  143. {
  144. rsImg = '<img src="https://renderer-row.waze.com/renderer/v1/signs/' + rs[rsID].type + '?text=' + rs[rsID].text + '" height="40px" style="margin-top:-8px;margin-bottom:-8px;">';
  145. if(rs[rsID].direction !== null)
  146. {
  147. rsImg += rs[rsID].direction;
  148. }
  149. }
  150.  
  151. if(end === -1)
  152. {
  153. textIn = textIn.slice(0, start) + rsImg;
  154. }
  155. else
  156. {
  157. textIn = textIn.slice(0, start) + rsImg + textIn.slice(end + 1);
  158. }
  159. }
  160. return textIn;
  161. },
  162. FormatTI: function(ge, idx, useFilter, contains)
  163. {
  164. let showTI;
  165. if(useFilter === false)
  166. {
  167. showTI = true;
  168. }
  169. else
  170. {
  171. showTI = false;
  172. }
  173.  
  174. let innerHTML = '<div style="background-color: yellow;"><i class="fa fa-road" style="scale:150%;;padding-right:10px;"></i><b>' + ge.segID + '</b></div>';
  175. innerHTML += '<div style="padding-left:10px;padding-top:4px;">';
  176. if(ge.es.length !== 0)
  177. {
  178. innerHTML += '<i class="fa fa-sign-out" style="scale:150%;;padding-right:10px;"></i>';
  179. for(let j = 0; j < ge.es.length; ++j)
  180. {
  181. innerHTML += '<img src="https://renderer-row.waze.com/renderer/v1/signs/' + ge.es[j].type + '?text=' + ge.es[j].text + '" height="25px" style="padding-right:10px;">';
  182. }
  183. innerHTML += '<br>';
  184. }
  185. if(ge.vi !== null)
  186. {
  187. innerHTML += '<i class="fa fa-eye" style="scale:150%;;padding-right:10px;"></i>';
  188. innerHTML += TISWAS.ReplaceShieldIDs(ge.vi, ge.rs);
  189. innerHTML += '<br>';
  190.  
  191. if(useFilter === true)
  192. {
  193. showTI = showTI || TISWAS.RegexContains(ge.vi, contains);
  194. }
  195. }
  196. if(ge.rs.length > 0)
  197. {
  198. for(let j = 0; j < ge.rs.length; ++j)
  199. {
  200. if(useFilter === true)
  201. {
  202. showTI = showTI || TISWAS.RegexContains(ge.rs[j].text, contains);
  203. showTI = showTI || TISWAS.RegexContains(ge.rs[j].direction, contains);
  204. }
  205. }
  206. }
  207. if(ge.t !== "")
  208. {
  209. innerHTML += '<i class="fa fa-reply" style="scale:150%;;padding-right:10px;"></i>';
  210. innerHTML += TISWAS.ReplaceShieldIDs(ge.t, ge.rs);
  211. innerHTML += '<br>';
  212.  
  213. if(useFilter === true)
  214. {
  215. showTI = showTI || TISWAS.RegexContains(ge.t, contains);
  216. }
  217. }
  218. if(ge.tts !== null)
  219. {
  220. innerHTML += '<i class="fa fa-comment" style="scale:150%;;padding-right:10px;"></i>';
  221. innerHTML += ge.tts + '<br>';
  222. if(useFilter === true)
  223. {
  224. showTI = showTI || TISWAS.RegexContains(ge.tts, contains);
  225. }
  226. }
  227. innerHTML += '</div>';
  228.  
  229. let resHTML = '<div id="_tdiv-' + idx + '" tag="' + ge.segID + '" style="padding:2px; margin:6px; cursor:pointer;';
  230. if(showTI === false)
  231. {
  232. resHTML += ' display:none;';
  233. }
  234. resHTML += '">';
  235. resHTML += innerHTML;
  236. resHTML += '</div>';
  237.  
  238. return resHTML;
  239. },
  240. DisplayTIs: function()
  241. {
  242. let resHTML = '';
  243. let filterEnabled = document.querySelector('#_tisEnableFilter').checked;
  244. let filterContains = document.querySelector('#_tisContains').value;
  245.  
  246. for(let i = 0; i < TISWAS.graphEntries.length; ++i)
  247. {
  248. let ge = TISWAS.graphEntries[i];
  249. resHTML += TISWAS.FormatTI(ge, i, filterEnabled, filterContains);
  250. }
  251. return resHTML;
  252. },
  253. UpdateList: function()
  254. {
  255. let outPane = document.querySelector('#_tisOutput');
  256. if(outPane !== null)
  257. {
  258. let resHTML = '';
  259. let nEntries = 0;
  260.  
  261. if(W.map.getZoom() >= 17)
  262. {
  263. nEntries = TISWAS.graphEntries.length;
  264.  
  265. if(nEntries > 0)
  266. {
  267. resHTML += TISWAS.DisplayTIs();
  268. }
  269. else
  270. {
  271. resHTML += "No TIs here...";
  272. }
  273. }
  274. else
  275. {
  276. resHTML += "TIs only available at zoom 17+";
  277. }
  278. outPane.innerHTML = TISWAS.ModifyHTML(resHTML);
  279.  
  280. if(nEntries > 0)
  281. {
  282. for(let i = 0; i < nEntries; ++i)
  283. {
  284. let linkID = "_tdiv-" + i;
  285. TISWAS.AddEventListener(linkID, "click", TISWAS.SegSelect, true);
  286. }
  287. }
  288. }
  289. },
  290. SurfaceTIs: function()
  291. {
  292. TISWAS.graphEntries = [];
  293.  
  294. if(W.map.getZoom() >= 17)
  295. {
  296. W.model.turnGraph.reverseAdjacencyList.forEach(TISWAS.PushGraphEntry);
  297. }
  298.  
  299. TISWAS.UpdateList();
  300. },
  301.  
  302. PopulateUI: function()
  303. {
  304. var iHTML = '';
  305. iHTML += '<div id="_tisControl">';
  306. iHTML += '<i class="fa fa-filter" style="scale:150%;padding-right:10px;"></i><input type="checkbox" id="_tisEnableFilter" />&nbsp;';
  307. iHTML += '<input type="text" style="font-size:14px; line-height:16px; height:22px; margin-bottom:4px;" id="_tisContains">';
  308. iHTML += '</div>';
  309.  
  310. iHTML += '<div id="_tisOutput" />';
  311. return iHTML;
  312. },
  313. Initialise: function()
  314. {
  315. TISWAS.AddLog("Initialise");
  316. if(document.getElementsByClassName("sandbox").length > 0)
  317. {
  318. TISWAS.AddLog('WME practice mode detected, script is disabled...');
  319. return;
  320. }
  321. if(document.location.href.indexOf('user/') !== -1)
  322. {
  323. TISWAS.AddLog('User profile page detected, script is disabled...');
  324. return;
  325. }
  326. TISWAS.WaitForW();
  327. },
  328. WaitForW: function()
  329. {
  330. if(window.W === undefined)
  331. {
  332. window.setTimeout(TISWAS.WaitForW, 100);
  333. return;
  334. }
  335. if (W.userscripts?.state?.isReady)
  336. {
  337. TISWAS.AddTab_API();
  338. }
  339. else
  340. {
  341. document.addEventListener("wme-ready", TISWAS.AddTab_API, {once: true});
  342. }
  343. },
  344. AddTab_API: async function()
  345. {
  346. TISWAS.AddLog("Registering with sidepanel...");
  347. let {tabLabel, tabPane} = W.userscripts.registerSidebarTab("TISWAS");
  348. tabLabel.innerText = "TISWAS";
  349. tabPane.innerHTML = TISWAS.ModifyHTML(TISWAS.PopulateUI());
  350. await W.userscripts.waitForElementConnected(tabPane);
  351. TISWAS.CompleteUISetup();
  352. },
  353. CompleteUISetup: function()
  354. {
  355. W.map.events.register("moveend", null, TISWAS.SurfaceTIs);
  356. W.map.events.register("zoomend", null, TISWAS.SurfaceTIs);
  357. TISWAS.AddEventListener("_tisEnableFilter", "change", TISWAS.UpdateList, true);
  358. TISWAS.AddEventListener("_tisContains", "keyup", TISWAS.UpdateList, true);
  359. }
  360. };
  361. TISWAS.Initialise();