WME Route Checker

Allows editors to check the route between two segments

当前为 2015-10-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WME Route Checker
  3. // @namespace http://userscripts.org/users/419370
  4. // @description Allows editors to check the route between two segments
  5. // @include https://www.waze.com/editor/*
  6. // @include https://www.waze.com/*/editor/*
  7. // @include https://editor-beta.waze.com/*
  8. // @version 1.17
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. // globals
  13. var wmerc_version = "1.17";
  14.  
  15. var AVOID_TOLLS = 1;
  16. var AVOID_FREEWAYS = 2;
  17. var AVOID_DIRT = 4;
  18. var ALLOW_UTURNS = 16;
  19. var ROUTE_DIST = 32;
  20.  
  21. var route_options = ALLOW_UTURNS; // default
  22.  
  23. var routeZIndex = 0;
  24.  
  25. var routeColors = ["#8309e1", "#52BAD9", "#888800" ];
  26.  
  27.  
  28. function showRouteOptions() {
  29. if (Waze.selectionManager.selectedItems.length != 2) {
  30. WMERC_lineLayer_route.destroyFeatures();
  31. WMERC_lineLayer_route.setZIndex(-999);
  32. return;
  33. }
  34.  
  35. if (getId('routeOptions') !== null) {
  36. return;
  37. }
  38.  
  39. // hook into edit panel on the left
  40. var userTabs = getId('edit-panel');
  41. var segmentBox = getElementsByClassName('segment', userTabs)[0];
  42. var tabContent = getElementsByClassName('tab-content', segmentBox)[0];
  43.  
  44. // add new edit tab to left of the map
  45. var addon = document.createElement('div');
  46. addon.id = "routeOptions";
  47. addon.style.borderTop = "solid 2px #E9E9E9";
  48. addon.style.borderBottom = "solid 2px #E9E9E9";
  49. if (location.hostname.match(/editor.*.waze.com/)) {
  50. var coords1 = getCoords(Waze.selectionManager.selectedItems[0]);
  51. var coords2 = getCoords(Waze.selectionManager.selectedItems[1]);
  52. var url = getLivemap()
  53. + "&from_lon="+coords1.lon + "&from_lat="+coords1.lat
  54. + "&to_lon="+coords2.lon + "&to_lat="+coords2.lat;
  55.  
  56. addon.innerHTML = '<p><b><a href="'+url+'" title="Opens in new tab" target="LiveMap" style="color:#8309e1">Show routes in LiveMap</a> &raquo;</b></p>';
  57. segmentBox.insertBefore(addon, tabContent);
  58. } else {
  59. addon.innerHTML = '<p><b><a href="#" id="goroutes" title="WME Route Checker v'+wmerc_version+'" style="color:#8309e1">'
  60. + 'Show routes between these two segments</a> &raquo;</b><br>'
  61. + '<b>Route:</b>'
  62. + ' <input type="radio" name="_routeType" id="_routeType_fast" value="0" checked> Fastest'
  63. + ' <input type="radio" name="_routeType" id="_routeType_short" value="'+ROUTE_DIST+'"> Shortest<br>'
  64. + '<b>Avoid:</b>'
  65. + ' <input type="checkbox" id="_avoidTolls" /> Tolls'
  66. + ' <input type="checkbox" id="_avoidFreeways" /> Freeways'
  67. + ' <input type="checkbox" id="_avoidDirt" /> Dirt Trails<br>'
  68. + '<b>Allow:</b>'
  69. + ' <input type="checkbox" id="_allowUTurns" /> U-Turns</p>';
  70. segmentBox.insertBefore(addon, tabContent);
  71.  
  72. getId('_avoidTolls').checked = route_options & AVOID_TOLLS;
  73. getId('_avoidFreeways').checked = route_options & AVOID_FREEWAYS;
  74. getId('_avoidDirt').checked = route_options & AVOID_DIRT;
  75. getId('_allowUTurns').checked = route_options & ALLOW_UTURNS;
  76. getId('_routeType_short').checked = route_options & ROUTE_DIST;
  77. // automatically start getting route when user clicks on link
  78. getId('goroutes').onclick = fetchRoute;
  79. }
  80.  
  81. // create empty div ready for instructions
  82. var routeTest = document.createElement('div');
  83. routeTest.id = "routeTest";
  84. segmentBox.insertBefore(routeTest, tabContent);
  85.  
  86. return;
  87. }
  88.  
  89. function saveOptions() {
  90. route_options = (getId('_avoidTolls').checked ? AVOID_TOLLS : 0)
  91. + (getId('_avoidFreeways').checked ? AVOID_FREEWAYS : 0)
  92. + (getId('_avoidDirt').checked ? AVOID_DIRT : 0)
  93. + (getId('_allowUTurns').checked ? ALLOW_UTURNS : 0)
  94. + (getId('_routeType_short').checked ? ROUTE_DIST : 0);
  95.  
  96. console.log("WME Route Checker: saving options: " + route_options);
  97. localStorage.WMERouteChecker = JSON.stringify(route_options);
  98. }
  99.  
  100. function getOptions() {
  101. var list = 'AVOID_TOLL_ROADS' + (route_options & AVOID_TOLLS ? ':t' : ':f') + ','
  102. + 'AVOID_PRIMARIES' + (route_options & AVOID_FREEWAYS ? ':t' : ':f') + ','
  103. + 'AVOID_TRAILS' + (route_options & AVOID_DIRT ? ':t' : ':f') + ','
  104. + 'ALLOW_UTURNS' + (route_options & ALLOW_UTURNS ? ':t' : ':f');
  105. return list;
  106. }
  107.  
  108. function getCoords(segment) {
  109. var numpoints = segment.geometry.components.length;
  110. var middle = Math.floor(numpoints / 2);
  111.  
  112. var seglat, seglon;
  113. if (numpoints % 2 == 1 || numpoints < 2) { // odd number, middle point
  114. seglat = segment.geometry.components[middle].y;
  115. seglon = segment.geometry.components[middle].x;
  116. }
  117. else { // even number - take average of middle two points
  118. seglat = (segment.geometry.components[middle].y
  119. + segment.geometry.components[middle-1].y) / 2.0;
  120. seglon = (segment.geometry.components[middle].x
  121. + segment.geometry.components[middle-1].x) / 2.0;
  122. }
  123. return OpenLayers.Layer.SphericalMercator.inverseMercator(seglon,seglat);
  124. }
  125.  
  126. function fetchRoute(reverse) {
  127. saveOptions();
  128.  
  129. var coords1, coords2;
  130. reverse = (reverse !== false);
  131. if (reverse) {
  132. coords1 = getCoords(Waze.selectionManager.selectedItems[0]);
  133. coords2 = getCoords(Waze.selectionManager.selectedItems[1]);
  134. } else {
  135. coords1 = getCoords(Waze.selectionManager.selectedItems[1]);
  136. coords2 = getCoords(Waze.selectionManager.selectedItems[0]);
  137. }
  138.  
  139. var img = '<img src="https://www.waze.com/images/search_indicator.gif" hspace="4">';
  140.  
  141. // get the route, fix and parse the json
  142. getId('routeTest').innerHTML = "<p><b>Fetching route from LiveMap " + img + "</b></p>";
  143. var url = getRoutingManager();
  144. var data = {
  145. from: "x:" + coords1.lon + " y:" + coords1.lat + " bd:true",
  146. to: "x:" + coords2.lon + " y:" + coords2.lat + " bd:true",
  147. returnJSON: true,
  148. returnGeometries: true,
  149. returnInstructions: true,
  150. type: (route_options & ROUTE_DIST ? 'DISTANCE' : 'HISTORIC_TIME'),
  151. clientVersion: '4.0.0',
  152. timeout: 60000,
  153. nPaths: 3,
  154. options: getOptions()};
  155.  
  156. $.ajax({
  157. dataType: "json",
  158. url: url,
  159. data: data,
  160. dataFilter: function(data, dataType) {
  161. return data.replace(/NaN/g, '0');
  162. },
  163. success: function(json) {
  164. showNavigation(json, reverse);
  165. }
  166. });
  167. return false;
  168. }
  169.  
  170. function getLivemap() {
  171. var center_lonlat=new OpenLayers.LonLat(Waze.map.center.lon,Waze.map.center.lat);
  172. center_lonlat.transform(new OpenLayers.Projection ("EPSG:900913"),new OpenLayers.Projection("EPSG:4326"));
  173. var coords = '?lon='+center_lonlat.lon+'&lat='+center_lonlat.lat;
  174.  
  175. return 'https://www.waze.com/livemap'+coords;
  176. }
  177.  
  178. function getRoutingManager() {
  179. if (Waze.model.countries.get(235) || Waze.model.countries.get(40)) { // US & Canada
  180. return '/RoutingManager/routingRequest';
  181. } else if (Waze.model.countries.get(106)) { // Israel
  182. return '/il-RoutingManager/routingRequest';
  183. } else {
  184. return '/row-RoutingManager/routingRequest';
  185. }
  186. }
  187.  
  188. function plotRoute(coords, index) {
  189. var points = [];
  190. for (var i in coords) {
  191. if (i > 0) {
  192. var point = OpenLayers.Layer.SphericalMercator.forwardMercator(coords[i].x, coords[i].y);
  193. points.push(new OL.Geometry.Point(point.lon,point.lat));
  194. }
  195. }
  196. var newline = new OL.Geometry.LineString(points);
  197.  
  198. var style = {
  199. strokeColor: routeColors[index],
  200. strokeOpacity: 0.7,
  201. strokeWidth: 8 - index * 2,
  202. };
  203. var lineFeature = new OL.Feature.Vector(newline, {type: "routeArrow"}, style);
  204.  
  205. // Display new segment
  206. WMERC_lineLayer_route.addFeatures([lineFeature]);
  207. }
  208.  
  209. function showNavigation(nav_json, reverse) {
  210. // plot the route
  211. WMERC_lineLayer_route.destroyFeatures();
  212. if (typeof nav_json.alternatives !== "undefined"){
  213. for (var r = nav_json.alternatives.length-1; r >= 0; r--) {
  214. plotRoute(nav_json.alternatives[r].coords, r);
  215. }
  216. } else {
  217. plotRoute(nav_json.coords, 0);
  218. }
  219. WMERC_lineLayer_route.setVisibility(true);
  220. WMERC_lineLayer_route.setZIndex(routeZIndex);
  221.  
  222. // hide segment details
  223. var userTabs = getId('edit-panel');
  224. var segmentBox = getElementsByClassName('segment', userTabs)[0];
  225. var tabContent = getElementsByClassName('tab-content', segmentBox)[0];
  226. tabContent.style.display = 'none';
  227.  
  228. // write instructions
  229. instructions = getId('routeTest');
  230. instructions.innerHTML = '';
  231. instructions.style.display = 'block';
  232. instructions.style.height = document.getElementById('map').style.height;
  233.  
  234. var nav_coords;
  235. if (typeof nav_json.alternatives !== "undefined") {
  236. for (var r = 0; r < nav_json.alternatives.length; r++) {
  237. showInstructions(nav_json.alternatives[r], r);
  238. }
  239. nav_coords = nav_json.alternatives[0].coords;
  240. } else {
  241. showInstructions(nav_json, 0);
  242. nav_coords = nav_json.coords;
  243. }
  244. var lon1 = nav_coords[0].x;
  245. var lat1 = nav_coords[0].y;
  246.  
  247. var end = nav_coords.length - 1;
  248. var lon2 = nav_coords[end].x;
  249. var lat2 = nav_coords[end].y;
  250.  
  251. var rerouteArgs = '{lon:'+lon1+',lat:'+lat1+'},{lon:'+lon2+',lat:'+lat2+'}';
  252.  
  253. // footer for extra links
  254. var footer = document.createElement('div');
  255. footer.className = 'routes_footer';
  256.  
  257. // create link to reverse the route
  258. var reverseLink = document.createElement('a');
  259. reverseLink.innerHTML = '&laquo; Reverse Route';
  260. reverseLink.href = '#';
  261. reverseLink.setAttribute('onClick', 'fetchRoute('+!reverse+');');
  262. reverseLink.addEventListener('click', function() { fetchRoute(!reverse); }, false);
  263. footer.appendChild(reverseLink);
  264.  
  265. footer.appendChild(document.createTextNode(' | '));
  266.  
  267. var url = getLivemap()
  268. + "&from_lon="+lon1 + "&from_lat="+lat1
  269. + "&to_lon="+lon2 + "&to_lat="+lat2;
  270.  
  271. // create link to view the navigation instructions
  272. var livemapLink = document.createElement('a');
  273. livemapLink.innerHTML = 'View in LiveMap &raquo;';
  274. livemapLink.href = url;
  275. livemapLink.target="LiveMap";
  276. footer.appendChild(livemapLink);
  277.  
  278. footer.appendChild(document.createElement('br'));
  279.  
  280. // add link to script homepage and version
  281. var scriptLink = document.createElement('a');
  282. scriptLink.innerHTML = 'WME Route Checker v' + wmerc_version;
  283. scriptLink.href = 'https://www.waze.com/forum/viewtopic.php?t=64777';
  284. scriptLink.style.fontStyle = 'italic';
  285. scriptLink.target="_blank";
  286. footer.appendChild(scriptLink);
  287.  
  288. instructions.appendChild(footer);
  289.  
  290. return false;
  291. }
  292.  
  293. function showInstructions(nav_json, r) {
  294. // for each route returned by Waze...
  295. var route = nav_json.response;
  296. var streetNames = route.streetNames;
  297.  
  298. if (r > 0) { // divider
  299. instructions.appendChild(document.createElement('p'));
  300. }
  301.  
  302. // name of the route, with coloured icon
  303. var route_name = document.createElement('p');
  304. route_name.className = 'route';
  305. route_name.style.borderColor = routeColors[r];
  306. route_name.innerHTML = '<b style="color:'+routeColors[r]+'">Via ' + route.routeName + '</b>';
  307. instructions.appendChild(route_name);
  308.  
  309. if (route.tollMeters > 0) {
  310. route_name.innerHTML = '<span style="float: right">TOLL</span>' + route_name.innerHTML;
  311. }
  312.  
  313. var optail = '';
  314. var prevStreet = '';
  315. var currentItem = null;
  316. var totalDist = 0;
  317. var totalTime = 0;
  318. //var detourSaving = 0;
  319. // street name at starting point
  320. var streetName = streetNames[route.results[0].street];
  321. var departFrom = 'depart';
  322. if (!streetName || streetName === null)
  323. streetName = '';
  324. else {
  325. departFrom = 'depart from ' + streetName;
  326. streetName = ' from <span style="color: blue">' + streetName + '<span>';
  327. }
  328. // turn icon at starting coordinates
  329. if (r == 0) {
  330. addTurnImageToMap(nav_json.coords[0], "big_direction_forward", departFrom);
  331. }
  332.  
  333. // add first instruction (depart)
  334. currentItem = document.createElement('a');
  335. currentItem.className = 'step';
  336. currentItem.innerHTML = getTurnImageSrc('big_direction_forward') + 'depart' + streetName;
  337. instructions.appendChild(currentItem);
  338.  
  339. // iterate over all the steps in the list
  340. for (var i = 0; i < route.results.length; i++) {
  341. totalDist += route.results[i].length;
  342. totalTime += route.results[i].crossTime;
  343. //detourSaving += route.results[i].detourSavings;
  344.  
  345. if (!route.results[i].instruction)
  346. continue;
  347. var opcode = route.results[i].instruction.opcode;
  348. if (!opcode)
  349. continue;
  350.  
  351. // ignore these
  352. if (opcode.match(/ROUNDABOUT_EXIT|CONTINUE|NONE/)) {
  353. continue;
  354. }
  355.  
  356. // the image for the turn
  357. var dirImage = getTurnImage(opcode);
  358. var dirImageSrc = '';
  359. if (dirImage !== '') {
  360. dirImageSrc = '';
  361. }
  362. // the name that TTS will read out (in blue)
  363. streetName = getNextStreetName(route.results, i, route.streetNames);
  364.  
  365. // roundabouts with nth exit instructions
  366. if (opcode == 'ROUNDABOUT_ENTER') {
  367. opcode += route.results[i].instruction.arg + 'th exit';
  368. opcode = opcode.replace(/1th/, '1st');
  369. opcode = opcode.replace(/2th/, '2nd');
  370. opcode = opcode.replace(/3th/, '3rd');
  371. }
  372.  
  373. // convert opcode to pretty text
  374. opcode = opcode.replace(/APPROACHING_DESTINATION/, 'arrive');
  375. opcode = opcode.replace(/ROUNDABOUT_(EXIT_)?LEFT/, 'at the roundabout, turn left');
  376. opcode = opcode.replace(/ROUNDABOUT_(EXIT_)?RIGHT/, 'at the roundabout, turn right');
  377. opcode = opcode.replace(/ROUNDABOUT_(EXIT_)?STRAIGHT/, 'at the roundabout, continue straight');
  378. opcode = opcode.replace(/ROUNDABOUT_ENTER/, 'at the roundabout, take ');
  379. opcode = opcode.toLowerCase().replace(/_/, ' ');
  380. opcode = opcode.replace(/uturn/, 'make a U-turn');
  381. opcode = opcode.replace(/roundabout u/, 'at the roundabout, make a U-turn');
  382.  
  383. // convert keep to exit if needed
  384. var keepSide = Waze.model.isLeftHand ? /keep left/ : /keep right/;
  385. if (opcode.match(keepSide) && i+1 < route.results.length &&
  386. isKeepForExit(route.results[i].roadType, route.results[i+1].roadType)) {
  387. opcode = opcode.replace(/keep (.*)/, 'exit $1');
  388. }
  389.  
  390. // show turn symbol on the map (for first route only)
  391. if (r == 0) {
  392. if (opcode == 'arrive') {
  393. var end = nav_json.coords.length - 1;
  394. var title = 'arrive at ' + (streetName != '' ? streetName : 'destination');
  395. addTurnImageToMap(nav_json.coords[end], dirImage, title);
  396. } else {
  397. //var title = opcode + (streetName != '' ? ' onto ' + streetName : '');
  398. var title = opcode.replace(/at the roundabout, /, '');
  399. if (streetName != '') title += ' onto ' + streetName;
  400. addTurnImageToMap(route.results[i+1].path, dirImage, title);
  401. }
  402. }
  403.  
  404. // pretty street name
  405. if (streetName != '') {
  406. if (opcode == 'arrive') {
  407. streetName = ' at <span style="color: blue">' + streetName + '</span>';
  408. } else {
  409. streetName = ' onto <span style="color: blue">' + streetName + '</span>';
  410. }
  411. }
  412. // display new instruction
  413. currentItem = document.createElement('a');
  414. currentItem.className = 'step';
  415. currentItem.innerHTML = getTurnImageSrc(dirImage) + opcode + streetName;
  416. if (opcode.match(/0th exit/)) {
  417. currentItem.style.color = 'red';
  418. }
  419. instructions.appendChild(currentItem);
  420. }
  421.  
  422. // append distance and time to last instruction
  423. currentItem.title = (totalDist/1609).toFixed(3) + " miles";
  424. currentItem.innerHTML += ' - ' + totalDist/1000 + ' km';
  425. currentItem.innerHTML += ' - ' + timeFromSecs(totalTime);
  426. //if (detourSaving > 0) {
  427. // currentItem.innerHTML += '<br>&nbsp; <i>detour saved ' + timeFromSecs(detourSaving) + '</i>';
  428. //}
  429. };
  430.  
  431. function getNextStreetName(results, index, streetNames) {
  432. var streetName = '';
  433. var unnamedCount = 0;
  434. var unnamedLength = 0;
  435.  
  436. // destination
  437. if (index == results.length-1) {
  438. streetName = streetNames[results[index].street];
  439. if (!streetName || streetName === null)
  440. streetName = '';
  441. }
  442. // look ahead to next street name
  443. while (++index < results.length && streetName == '') {
  444. streetName = streetNames[results[index].street];
  445. if (!streetName || streetName === null)
  446. streetName = '';
  447.  
  448. // "Navigation instructions for unnamed segments" <- in the Wiki
  449. if (streetName == '' && !isFreewayOrRamp(results[index].roadType)
  450. && !isRoundabout(results[index].path.segmentId)) {
  451. unnamedLength += length;
  452. unnamedCount++;
  453. if (unnamedCount >= 4 || unnamedLength >= 400) {
  454. //console.log("- unnamed segments too long; break");
  455. break;
  456. }
  457. }
  458. }
  459. return streetName;
  460. }
  461.  
  462. function getTurnImage(opcode) {
  463. var dirImage = '';
  464. switch (opcode) {
  465. case "CONTINUE":
  466. case "NONE": dirImage = "big_direction_forward"; break;
  467. case "TURN_LEFT": dirImage = "big_direction_left"; break;
  468. case "TURN_RIGHT": dirImage = "big_direction_right"; break;
  469. case "KEEP_LEFT":
  470. case "EXIT_LEFT": dirImage = "big_direction_exit_left"; break;
  471. case "KEEP_RIGHT":
  472. case "EXIT_RIGHT": dirImage = "big_direction_exit_right"; break;
  473. case "UTURN": dirImage = "big_directions_roundabout_u"; break;
  474. case "APPROACHING_DESTINATION": dirImage = "big_direction_end"; break;
  475. case "ROUNDABOUT_LEFT":
  476. case "ROUNDABOUT_EXIT_LEFT": dirImage = "big_directions_roundabout_l"; break;
  477. case "ROUNDABOUT_RIGHT":
  478. case "ROUNDABOUT_EXIT_RIGHT": dirImage = "big_directions_roundabout_r"; break;
  479. case "ROUNDABOUT_STRAIGHT":
  480. case "ROUNDABOUT_EXIT_STRAIGHT": dirImage = "big_directions_roundabout_s"; break;
  481. case "ROUNDABOUT_ENTER":
  482. case "ROUNDABOUT_EXIT": dirImage = "big_directions_roundabout"; break;
  483. case "ROUNDABOUT_U": dirImage = "big_directions_roundabout_u"; break;
  484. default: dirImage = '';
  485. }
  486. return dirImage;
  487. }
  488.  
  489. function getTurnImageSrc(dirImage) {
  490. var imgRoot = '/assets-editor/images/vectors/routeInstructions/';
  491. if (dirImage != '') {
  492. return '<img src="' + imgRoot + dirImage + '.png" style="float: left; top: 0; padding-right: 4px" width="16" height="16" />';
  493. }
  494. return '';
  495. }
  496.  
  497. function isKeepForExit(fromType, toType) {
  498. // primary to non-primary
  499. if (isPrimaryRoad(fromType) && !isPrimaryRoad(toType)) {
  500. return true;
  501. }
  502. // ramp to non-primary or non-ramp
  503. if (isRamp(fromType) && !isPrimaryRoad(toType) && !isRamp(toType)) {
  504. return true;
  505. }
  506. return false;
  507. }
  508.  
  509. function isFreewayOrRamp(t) {
  510. return t === 3 /*FREEWAY*/ || t === 4 /*RAMP*/;
  511. }
  512.  
  513. function isPrimaryRoad(t) {
  514. return t === 3 /*FREEWAY*/ || t === 6 /*MAJOR_HIGHWAY*/ || t === 7 /*MINOR_HIGHWAY*/;
  515. }
  516.  
  517. function isRamp(t) {
  518. return t === 4 /*RAMP*/;
  519. }
  520.  
  521. function isRoundabout(id) {
  522. segment = Waze.model.segments.get(id);
  523. if (typeof segment != "undefined") {
  524. return segment.attributes.junctionId !== null;
  525. }
  526. return false;
  527. }
  528.  
  529. function timeFromSecs(seconds)
  530. {
  531. var hh = '00'+Math.floor(((seconds/86400)%1)*24);
  532. var mm = '00'+Math.floor(((seconds/3600)%1)*60);
  533. var ss = '00'+Math.round(((seconds/60)%1)*60);
  534. return hh.slice(-2) + ':' + mm.slice(-2) + ':' + ss.slice(-2);
  535. }
  536.  
  537. function addTurnImageToMap(location, image, title) {
  538. if (image == '') return;
  539. var coords = OpenLayers.Layer.SphericalMercator.forwardMercator(location.x, location.y);
  540. var point = new OL.Geometry.Point(coords.lon,coords.lat);
  541. var imgRoot = '/assets-editor/images/vectors/routeInstructions/';
  542.  
  543. var style = {
  544. externalGraphic: imgRoot + image + ".png",
  545. graphicWidth: 30,
  546. graphicHeight: 32,
  547. graphicZIndex: 9999,
  548. label: title,
  549. labelXOffset: 20,
  550. labelAlign: 'l',
  551. labelOutlineColor: 'white',
  552. labelOutlineWidth: 3,
  553. fontWeight: 'bold',
  554. fontColor: routeColors[0]
  555. };
  556. if (title.match(/0th exit/)) {
  557. style.fontColor = 'red';
  558. }
  559.  
  560. var imageFeature = new OL.Feature.Vector(point, null, style);
  561. // Display new segment
  562. WMERC_lineLayer_route.addFeatures([imageFeature]);
  563. }
  564.  
  565. /* helper function */
  566. function getElementsByClassName(classname, node) {
  567. if(!node) node = document.getElementsByTagName("body")[0];
  568. var a = [];
  569. var re = new RegExp('\\b' + classname + '\\b');
  570. var els = node.getElementsByTagName("*");
  571. for (var i=0,j=els.length; i<j; i++)
  572. if (re.test(els[i].className)) a.push(els[i]);
  573. return a;
  574. }
  575.  
  576. function getId(node) {
  577. return document.getElementById(node);
  578. }
  579.  
  580. function initialiseRouteChecker() {
  581. if (typeof Waze == 'undefined') {
  582. return; // not WME
  583. }
  584.  
  585. console.log("WME Route Checker: initialising v" + wmerc_version);
  586. if (localStorage.WMERouteChecker) {
  587. route_options = JSON.parse(localStorage.WMERouteChecker);
  588. console.log("WME Route Checker: loaded options: " + route_options);
  589. }
  590.  
  591. /* dirty hack to inject stylesheet in to the DOM */
  592. var style = document.createElement('style');
  593. style.innerHTML = "#routeTest {padding: 0 4px 0 0; overflow-y: auto;}\n"
  594. + "#routeTest p.route {margin: 0; padding: 4px 8px; border-bottom: silver solid 3px; background: #eee}\n"
  595. + "#routeTest a.step {display: block; margin: 0; padding: 3px 8px; text-decoration: none; color:black;border-bottom: silver solid 1px;}\n"
  596. + "#routeTest a.step:hover {background: #ffd;}\n"
  597. + "#routeTest a.step:active {background: #dfd;}\n"
  598. + "#routeTest div.routes_footer {text-align: center; margin-bottom: 25px;}\n";
  599. (document.body || document.head || document.documentElement).appendChild(style);
  600.  
  601. // add a new layer for routes
  602. WMERC_lineLayer_route = new OL.Layer.Vector("Route Checker Script",
  603. { rendererOptions: { zIndexing: true },
  604. shortcutKey: "S+t",
  605. uniqueName: 'route_checker' }
  606. );
  607. Waze.map.addLayer(WMERC_lineLayer_route);
  608. Waze.map.addControl(new OL.Control.DrawFeature(WMERC_lineLayer_route, OL.Handler.Path));
  609.  
  610. // find best ZIndex
  611. for (var i = 0; i < Waze.map.layers.length; i++) {
  612. var l = Waze.map.layers[i];
  613. if (/Waze.Control.SelectHighlightFeature/.test(l.name)) {
  614. routeZIndex = l.getZIndex()+1;
  615. }
  616. }
  617.  
  618. // hack in translation:
  619. I18n.translations[I18n.locale].layers.name.route_checker = "Route Checker Script";
  620.  
  621. // ...and then hide it
  622. $("label:contains('Route Checker Script')").parent().remove();
  623.  
  624. // add listener for whenever selection changes
  625. Waze.selectionManager.events.register("selectionchanged", null, showRouteOptions);
  626.  
  627. showRouteOptions(); // for permalinks
  628. }
  629.  
  630. // bootstrap!
  631. (function()
  632. {
  633. setTimeout(initialiseRouteChecker, 1003);
  634. })();
  635.  
  636. /* end ======================================================================= */