WME Color Highlights

Adds colours to road segments to show their status

当前为 2016-07-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WME Color Highlights
  3. // @namespace http://userscripts.org/users/419370
  4. // @description Adds colours to road segments to show their status
  5. // @include https://*.waze.com/editor/*
  6. // @include https://*.waze.com/*/editor/*
  7. // @exclude https://*.waze.com/user/editor/*
  8. // @exclude https://*.waze.com/*/user/editor/*
  9. // @version 2.10
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function()
  14. {
  15.  
  16. // global variables
  17. var wmech_version = "2.10"
  18.  
  19. var advancedMode = false;
  20. var lastModified = false;
  21. var selectedLines = [];
  22. var wmechinit = false;
  23.  
  24. /* =========================================================================== */
  25. function highlightSegments(event) {
  26. if (!wmechinit) return;
  27. var showLocked = getId('_cbHighlightLocked').checked;
  28. var showToll = getId('_cbHighlightToll').checked;
  29. var showNoCity = getId('_cbHighlightNoCity').checked;
  30. var showAltName = getId('_cbHighlightAltName').checked;
  31. var showNoName = getId('_cbHighlightUnnamed').checked;
  32. var showOneWay = getId('_cbHighlightOneWay').checked;
  33. var showNoDirection = getId('_cbHighlightNoDirection').checked;
  34. var showRestrictions = getId('_cbHighlightRestrictions').checked;
  35. var showSpeedLimits = getId('_cbHighlightSpeedLimits').checked;
  36. var showAvgSpeedCams = getId('_cbHighlightAvgSpeedCams').checked;
  37. var plusRamps = getId('_cbHighlightPlusRampLimits').checked;
  38. var plusStreets = getId('_cbHighlightPlusStreetLimits').checked;
  39. var specificCity = getId('_cbHighlightCity').checked;
  40. var specificCityInvert = getId('_cbHighlightCityInvert').checked;
  41. var specificRoadType = getId('_cbHighlightRoadType').checked;
  42. var showNoTerm = getId('_cbHighlightNoTerm').checked;
  43. var showRoutingPref = getId('_cbHighlightRoutingPref').checked;
  44. var showRecent = advancedMode ? getId('_cbHighlightRecent').checked : false;
  45. var specificEditor = getId('_cbHighlightEditor').checked;
  46.  
  47. // master switch when all options are off
  48. if (event && event.type && event.type == 'click') {
  49. if ( (showLocked | showToll | showNoCity | showNoName | showAltName | showOneWay | showNoDirection | showRestrictions
  50. | specificCity | specificEditor | specificRoadType | showNoTerm | showRecent | showSpeedLimits | showAvgSpeedCams) == false) {
  51. for (var seg in Waze.model.segments.objects) {
  52. var segment = Waze.model.segments.get(seg);
  53. var line = getId(segment.geometry.id);
  54.  
  55. if (line === null) {
  56. continue;
  57. }
  58.  
  59. // turn off all highlights
  60. var opacity = line.getAttribute("stroke-opacity");
  61. if (opacity > 0.1 && opacity < 1) {
  62. line.setAttribute("stroke","#dd7700");
  63. line.setAttribute("stroke-opacity",0.001);
  64. line.setAttribute("stroke-dasharray", "none");
  65. }
  66. }
  67. return;
  68. }
  69. }
  70. var today = new Date();
  71. var recentDays;
  72. var selectedUserId = null;
  73. var selectedCityId = null;
  74. if (specificEditor) {
  75. var selectUser = getId('_selectUser');
  76. if (selectUser.selectedIndex >= 0)
  77. selectedUserId = selectUser.options[selectUser.selectedIndex].value;
  78. else
  79. specificEditor = false;
  80. }
  81.  
  82. if (specificCity) {
  83. var selectCity = getId('_selectCity');
  84. if (selectCity.selectedIndex >= 0)
  85. selectedCityId = selectCity.options[selectCity.selectedIndex].value;
  86. else
  87. specificCity = false;
  88. }
  89.  
  90. if (specificRoadType) {
  91. var selectRoadType = getId('_selectRoadType');
  92. if (selectRoadType.selectedIndex >= 0)
  93. selectedRoadType = selectRoadType.options[selectRoadType.selectedIndex].value;
  94. else
  95. specificRoadType = false;
  96. }
  97.  
  98. if (showRecent) {
  99. recentDays = getId('_numRecentDays').value;
  100. if (recentDays === undefined) recentDays = 0;
  101. }
  102.  
  103. // counters
  104. var numUserHighlighted = 0;
  105. var numCityHighlighted = 0;
  106.  
  107. for (var seg in Waze.model.segments.objects) {
  108. var segment = Waze.model.segments.get(seg);
  109. var attributes = segment.attributes;
  110. var line = getId(segment.geometry.id);
  111.  
  112. if (line === null) {
  113. continue;
  114. }
  115. var sid = attributes.primaryStreetID;
  116.  
  117. // check that WME hasn't highlighted this segment
  118. var opacity = line.getAttribute("stroke-opacity");
  119. var lineWidth = line.getAttribute("stroke-width");
  120. if (opacity == 1 || lineWidth == 9)
  121. continue;
  122. // turn off highlights when roads are no longer visible
  123. var roadType = attributes.roadType;
  124. if (Waze.map.zoom <= 3 && (roadType < 2 || roadType > 7) ) {
  125. if (opacity > 0.1) {
  126. line.setAttribute("stroke","#dd7700");
  127. line.setAttribute("stroke-opacity",0.001);
  128. line.setAttribute("stroke-dasharray", "none");
  129. }
  130. continue;
  131. }
  132.  
  133. // highlight all newly paved roads (or roads without any nodes)
  134. if (sid === null || (attributes.toNodeID === null && attributes.fromNodeID === null && roadType < 9)) {
  135. if (opacity < 0.1 && showNoName) {
  136. line.setAttribute("stroke","#f00");
  137. line.setAttribute("stroke-opacity",0.75);
  138. line.setAttribute("stroke-width", 10);
  139. }
  140. continue;
  141. }
  142. var street = Waze.model.streets.get(sid);
  143.  
  144. // get attributes for this segment
  145. var toll = attributes.fwdToll;
  146. var locked = attributes.lockRank !== null;
  147. var ranked = attributes.rank > 0 && attributes.lockRank === null;
  148. var noEdit = attributes.permissions == 0;
  149. var noName = (street != null) && street.isEmpty;
  150. var cityID = (street != null) && street.cityID;
  151. var noCity = false;
  152. var countryID = 0;
  153. if (cityID != null && Waze.model.cities.get(cityID) != null) {
  154. noCity = Waze.model.cities.get(cityID).isEmpty;
  155. countryID = Waze.model.cities.get(cityID).countryID;
  156. }
  157. var oneWay = ((attributes.fwdDirection + attributes.revDirection) == 1); // it is 1-way only if either is true
  158. var noDirection = (!attributes.fwdDirection && !attributes.revDirection); // Could use the .attribute.allowNoDirection?
  159. var hasRestrictions = (attributes.fwdRestrictions.length + attributes.revRestrictions.length > 0);
  160. var updatedBy = attributes.updatedBy;
  161. var roundabout = attributes.junctionID !== null;
  162. // get current state of the line
  163. var lineColor = line.getAttribute("stroke");
  164.  
  165. // default colours
  166. var newColor = "#dd7700";
  167. var newOpacity = 0.001;
  168. var newDashes = "none";
  169. var newWidth = 6;
  170.  
  171. // Recent Edits within X days, with decaying green opacity
  172. if (showRecent) {
  173. var editDays = (today.getTime() - attributes.createdOn) / 86400000;
  174. if (attributes.updatedOn !== null) {
  175. editDays = (today.getTime() - attributes.updatedOn) / 86400000;
  176. }
  177. if (recentDays >= 0 && editDays <= recentDays) {
  178. if ((updatedBy == selectedUserId) || (!specificEditor)) {
  179. //var heatScale = 0.75 / recentDays;
  180. //newColor = "#0f0";
  181. var shade = Math.floor(editDays * 128 / recentDays);
  182. newColor = "rgb(" + (0) + ", " + (255-shade) + ", " + (0) + ")";
  183. newOpacity = 0.5;
  184. //newOpacity = Math.min(0.999999, 1 - (editDays * heatScale));
  185. }
  186. }
  187. }
  188.  
  189. // Toll = Dashed
  190. else if (toll && showToll) {
  191. newColor = "#00f";
  192. newOpacity = 0.5;
  193. newDashes = "10 10";
  194. }
  195.  
  196. // No Edit = Black
  197. else if (noEdit && showLocked) {
  198. newColor = "#000";
  199. newOpacity = 0.75;
  200. newWidth = 3;
  201. }
  202.  
  203. // Locked = Red
  204. else if (locked && showLocked) {
  205. newColor = "#f00";
  206. newWidth = 6;
  207. newOpacity = 0.2 * Math.min(5, attributes.lockRank);
  208. }
  209.  
  210. else if (ranked && showLocked) {
  211. newColor = "#f00";
  212. newWidth = 6;
  213. newDashes = "2 8";
  214. newOpacity = 0.2 * Math.min(5, attributes.rank);
  215. }
  216.  
  217. else if (hasRestrictions && showRestrictions) {
  218. newColor = "#909";
  219. newDashes = "10 10";
  220. newOpacity = 0.5;
  221. }
  222.  
  223. // bad roundabouts = Lime
  224. //else if (roundabout && (!oneWay || !noName) && showNoTerm) {
  225. // newColor = "#BE0";
  226. // newOpacity = 0.5;
  227. //}
  228.  
  229. // alternate names
  230. else if (showAltName && attributes.streetIDs.length > 0) {
  231. newColor = "#9C0";
  232. newOpacity = 0.75;
  233. if (noName) {
  234. newDashes = "10 10";
  235. }
  236. }
  237.  
  238. // No Speed Limits = Orange
  239. else if (showSpeedLimits && (plusStreets && attributes.roadType == 1 || plusRamps && attributes.roadType == 4 || attributes.roadType > 1 && attributes.roadType != 4)
  240. && attributes.roadType < 8 && attributes.roadType != 5
  241. && (plusStreets || attributes.junctionID == null)
  242. && ((attributes.fwdDirection && (attributes.fwdMaxSpeed == null || attributes.fwdMaxSpeedUnverified)) ||
  243. (attributes.revDirection && (attributes.revMaxSpeed == null || attributes.revMaxSpeedUnverified)) )) {
  244. newColor = "#f80";
  245. newOpacity = 0.8;
  246. newWidth = 4;
  247. }
  248. else if (showAvgSpeedCams && (attributes.fwdFlags & 1 || attributes.revFlags & 1)) {
  249. newColor = "#00f";
  250. newOpacity = 0.4;
  251. newWidth = 4;
  252. }
  253.  
  254. // Unnamed (No Name) = Orange
  255. // except roundabouts and non-Streets
  256. else if (noName && showNoName && !roundabout && attributes.roadType < 8) {
  257. newColor = "#fb0";
  258. newOpacity = 0.6;
  259. }
  260.  
  261. // No City = Gray
  262. else if (noCity && showNoCity) {
  263. newColor = "#888";
  264. newOpacity = 0.5;
  265. }
  266.  
  267. // No Direction = Cyan
  268. else if (noDirection && showNoDirection) {
  269. newColor = "#0ff";
  270. newOpacity = 0.3;
  271. newWidth = 4;
  272. }
  273.  
  274. // One Way = Blue
  275. else if (oneWay && showOneWay) {
  276. newColor = "#00f";
  277. newOpacity = 0.4;
  278. newWidth = 4;
  279. }
  280.  
  281. // Unterminated segments: no end node or not connected = Lime
  282. else if (showNoTerm && (attributes.toNodeID === null || attributes.fromNodeID === null || attributes.toNodeID === attributes.fromNodeID) && attributes.length > 10) {
  283. newColor = "#BE0";
  284. newOpacity = 0.5;
  285. }
  286.  
  287.  
  288. // segment with special flags
  289. else if (specificRoadType && (selectedRoadType & 64) > 0) {
  290. if (selectedRoadType == 64 && attributes.flags > 0) {
  291. newColor = "#909";
  292. newOpacity = 0.5;
  293. newWidth = 4;
  294. }
  295. // - tunnel
  296. else if (selectedRoadType == 65 && attributes.flags & 1) {
  297. newColor = "#909";
  298. newOpacity = 0.5;
  299. newWidth = 4;
  300. }
  301. }
  302.  
  303.  
  304. // selected road type = purple
  305. else if (specificRoadType && attributes.roadType == selectedRoadType) {
  306. newColor = "#909";
  307. newOpacity = 0.5;
  308. newWidth = 4;
  309. }
  310.  
  311. // special road types: non-drivable / non-routable
  312. else if (specificRoadType && selectedRoadType == 98 && nonRoutableTypes.contains(attributes.roadType)) {
  313. newColor = "#909";
  314. newOpacity = 0.5;
  315. newWidth = 4;
  316. }
  317. else if (specificRoadType && selectedRoadType == 99 && nonDrivableTypes.contains(attributes.roadType)) {
  318. newColor = "#909";
  319. newOpacity = 0.5;
  320. newWidth = 4;
  321. }
  322.  
  323. // highlight roads with a routing preferrence set
  324. else if (showRoutingPref && attributes.routingRoadType != null) {
  325. newColor = "#0ff";
  326. newOpacity = 0.5;
  327. newWidth = 6;
  328. }
  329.  
  330. // highlight segments by selected user, unless already highlighted
  331. if (specificEditor && !showRecent) {
  332. if (updatedBy == selectedUserId && newColor == "#dd7700") {
  333. newColor = "#00ff00";
  334. newOpacity = 0.5;
  335. numUserHighlighted++;
  336. }
  337. else if (selectedUserId < -1 && updatedBy != -selectedUserId && newColor == "#dd7700") {
  338. newColor = "#00ff00";
  339. newOpacity = 0.5;
  340. numUserHighlighted++;
  341. }
  342. else if (updatedBy != selectedUserId) {
  343. newColor = "#dd7700";
  344. newOpacity = 0.001;
  345. newDashes = "none";
  346. }
  347. }
  348.  
  349. // highlight segments by selected City, unless already highlighted
  350. // if city is only on an alternate street highlight it with dashes
  351. if (specificCity) {
  352. var altCityMatch = false;
  353. var specificCityMatch = (cityID == selectedCityId);
  354. if (specificCityInvert)
  355. specificCityMatch = (cityID != selectedCityId && !noCity);
  356.  
  357. if (!specificCityMatch) {
  358. // look for matching city in alternate streets
  359. for (var i in attributes.streetIDs) {
  360. var streetID = attributes.streetIDs[i];
  361. var currentStreet = Waze.model.streets.get(streetID);
  362. if (currentStreet == null)
  363. continue;
  364. var cityMatch = (currentStreet.cityID == selectedCityId);
  365. if (specificCityInvert)
  366. cityMatch = !cityMatch
  367. if (cityMatch) {
  368. altCityMatch = true;
  369. break;
  370. }
  371. }
  372. }
  373.  
  374. if (specificCityMatch && (newColor == "#dd7700" || newColor == "#888")) {
  375. newColor = "#ff0";
  376. newOpacity = 0.75;
  377. newDashes = "none";
  378. numCityHighlighted++;
  379. } else if (altCityMatch && (newColor == "#dd7700" || newColor == "#888")) {
  380. newColor = "#ffff01";
  381. newOpacity = 0.75;
  382. newDashes = "10 10";
  383. newWidth = 6;
  384. numCityHighlighted++;
  385. } else if (!specificCityMatch && !altCityMatch && !noCity) {
  386. newColor = "#dd7700";
  387. newOpacity = 0.001;
  388. newDashes = "none";
  389. }
  390. }
  391.  
  392. // if colour has changed, update the line attributes
  393. if (lineColor != newColor) {
  394. line.setAttribute("stroke", newColor);
  395. line.setAttribute("stroke-opacity", newOpacity);
  396. line.setAttribute("stroke-dasharray", newDashes);
  397. if (newColor != "#dd7700") { //default
  398. line.setAttribute("stroke-width", newWidth);
  399. } else {
  400. line.setAttribute("stroke-width", 6);
  401. }
  402. }
  403. } // end of loop
  404. numUserHighlightedText = getId('_numUserHighlighted');
  405. if (specificEditor)
  406. numUserHighlightedText.innerHTML = ' = ' + numUserHighlighted;
  407. else
  408. numUserHighlightedText.innerHTML = '';
  409.  
  410. numCityHighlightedText = getId('_numCityHighlighted');
  411. if (specificCity)
  412. numCityHighlightedText.innerHTML = ' = ' + numCityHighlighted;
  413. else
  414. numCityHighlightedText.innerHTML = '';
  415. } // end of function
  416.  
  417. function highlightPlaces(event) {
  418. if (!wmechinit) return;
  419. if (typeof Waze.model.venues == "undefined") {
  420. return;
  421. }
  422. if (Waze.model.active == false) {
  423. return;
  424. }
  425. // refreshing, reset places to original style
  426. if (event && event.type && /click|change/.test(event.type)) {
  427. for (var mark in Waze.model.venues.objects) {
  428. var venue = Waze.model.venues.get(mark);
  429. var poly = getId(venue.geometry.id);
  430. if (poly !== null && poly.getAttribute("stroke-opacity") == 0.987) {
  431. if (venue.isPoint()) {
  432. poly.setAttribute("stroke","white");
  433. } else {
  434. poly.setAttribute("stroke","#ca9ace");
  435. poly.setAttribute("stroke-width",2);
  436. poly.setAttribute("stroke-dash-array","none");
  437. }
  438. poly.setAttribute("fill","#c290c6");
  439. poly.setAttribute("stroke-opacity", 1)
  440. }
  441. }
  442. }
  443.  
  444. // if option is disabled, stop now
  445. if (!getId('_cbHighlightPlaces').checked) {
  446. if (event && event.type && event.type == 'click') {
  447. getId('_cbHighlightLockedPlaces').disabled = true;
  448. getId('_cbHighlightIncompletePlaces').disabled = true;
  449. }
  450. return;
  451. } else {
  452. if (event && event.type && event.type == 'click') {
  453. getId('_cbHighlightLockedPlaces').disabled = false;
  454. getId('_cbHighlightIncompletePlaces').disabled = false;
  455. }
  456. }
  457. var showLocked = getId('_cbHighlightLockedPlaces').checked;
  458. var showIncomplete = getId('_cbHighlightIncompletePlaces').checked;
  459. var specificCity = getId('_cbHighlightCity').checked;
  460. var specificCityInvert = getId('_cbHighlightCityInvert').checked;
  461. var showRecent = advancedMode ? getId('_cbHighlightRecent').checked : false;
  462.  
  463. if (specificCity) {
  464. var selectCity = getId('_selectCity');
  465. if (selectCity.selectedIndex >= 0) {
  466. selectedCityId = selectCity.options[selectCity.selectedIndex].value;
  467. } else
  468. specificCity = false;
  469. }
  470.  
  471. var specificEditor = getId('_cbHighlightEditor').checked;
  472. if (specificEditor) {
  473. var selectEditor = getId('_selectUser');
  474. var selectedEditorId = 0;
  475. if (selectEditor.selectedIndex >= 0) {
  476. selectedEditorId = selectEditor.options[selectEditor.selectedIndex].value;
  477. } else
  478. specificEditor = false;
  479. }
  480.  
  481. if (showRecent) {
  482. recentDays = getId('_numRecentDays').value;
  483. if (recentDays === undefined) recentDays = 0;
  484. if (recentDays == 0) showRecent = false;
  485. }
  486.  
  487. var updates = 0;
  488. for (var mark in Waze.model.venues.objects) {
  489. var venue = Waze.model.venues.get(mark);
  490. var poly = getId(venue.geometry.id);
  491. // check that WME hasn't highlighted this object already
  492. if (poly == null || mark.state == "Update" || venue.selected) {
  493. continue;
  494. }
  495.  
  496. // if highlighted by mouse over, skip this one
  497. if (poly.getAttribute("fill") == poly.getAttribute("stroke")) {
  498. continue;
  499. }
  500. // if already highlighted by us, skip
  501. if (poly.getAttribute("stroke-opacity") == 0.987) {
  502. continue;
  503. }
  504. // flag this venue as highlighted so we don't update it next time
  505. poly.setAttribute("stroke-opacity", 0.987);
  506. updates++;
  507.  
  508. var categories = venue.attributes.categories;
  509. if (showIncomplete) {
  510. venueStreet = Waze.model.streets.get(venue.attributes.streetID);
  511. var incomplete = false;
  512. var colorhilite = false;
  513. // check for missing venue name
  514. if (venue.attributes.name == null || venue.attributes.name == "") {
  515. incomplete = !venue.attributes.residential;
  516. colorhilite = true;
  517. }
  518. // check for missing street name
  519. if (venueStreet == null || venueStreet.name == null || venueStreet.name == "") {
  520. incomplete = true;
  521. colorhilite = true;
  522. }
  523. // check for missing house number
  524. else if (venue.attributes.residential && venue.attributes.houseNumber == null) {
  525. incomplete = true;
  526. colorhilite = true;
  527. }
  528. // check for category group used as category
  529. else if (categories.length == 0
  530. || categories.indexOf("CAR_SERVICES") > -1
  531. || categories.indexOf("TRANSPORTATION") > -1
  532. || categories.indexOf("PROFESSIONAL_AND_PUBLIC") > -1
  533. || categories.indexOf("SHOPPING_AND_SERVICES") > -1
  534. || categories.indexOf("FOOD_AND_DRINK") > -1
  535. || categories.indexOf("CULTURE_AND_ENTERTAINMENT") > -1
  536. || categories.indexOf("OTHER") > -1
  537. || categories.indexOf("LODGING") > -1
  538. || categories.indexOf("OUTDOORS") > -1
  539. || categories.indexOf("NATURAL_FEATURES") > -1) {
  540. incomplete = (venue.attributes.lockRank == 0);
  541. }
  542. else if (typeof venue.attributes.externalProviderIDs === 'undefined' || venue.attributes.externalProviderIDs.length === 0) {
  543. incomplete = true;
  544. }
  545. if (incomplete &&
  546. (categories.indexOf("JUNCTION_INTERCHANGE") > -1
  547. || categories.indexOf("CANAL") > -1
  548. || categories.indexOf("RIVER_STREAM") > -1
  549. || categories.indexOf("SEA_LAKE_POOL") > -1
  550. || categories.indexOf("PARK") > -1
  551. || categories.indexOf("SWAMP_MARSH") > -1
  552. || categories.indexOf("FOREST_GROVE") > -1
  553. || categories.indexOf("GOLF_COURSE") > -1) ) {
  554. incomplete = false;
  555. colorhilite = false;
  556. }
  557. if (incomplete) {
  558. if (colorhilite) {
  559. highlightAPlace(venue, "orange", "white");
  560. }
  561. if (venue.isPoint())
  562. poly.setAttribute("stroke-dasharray", "3 3");
  563. else {
  564. poly.setAttribute("stroke-dasharray", "3 6");
  565. poly.setAttribute("stroke-width", "3");
  566. }
  567. }
  568. }
  569.  
  570. // highlight places which have the City field set in the address = yellow
  571. if (specificCity) {
  572. venueStreet = Waze.model.streets.get(venue.attributes.streetID);
  573. selectedCityMatch = (specificCity && venueStreet.cityID == selectedCityId);
  574. if (specificCityInvert) selectedCityMatch = !selectedCityMatch;
  575.  
  576. if (selectedCityMatch) {
  577. highlightAPlace(venue, "#cc0", "#ff8");
  578. continue;
  579. }
  580. }
  581. // highlight places which have been edited by selected editor = green
  582. if (specificEditor) {
  583. var selectedEditorMatch = false
  584. if (selectedEditorId >= -1) {
  585. selectedEditorMatch = (selectedEditorId == venue.attributes.createdBy);
  586. if (typeof venue.attributes.updatedBy != 'undefined') {
  587. selectedEditorMatch = (selectedEditorId == venue.attributes.updatedBy);
  588. }
  589. }
  590. else {
  591. selectedEditorMatch = (selectedEditorId != -venue.attributes.createdBy);
  592. if (typeof venue.attributes.updatedBy != 'undefined') {
  593. selectedEditorMatch = (selectedEditorId != -venue.attributes.updatedBy);
  594. }
  595. }
  596. if (selectedEditorMatch) {
  597. highlightAPlace(venue, "#0f0", "#8f8");
  598. continue;
  599. }
  600. }
  601. // highlight places that have been edited recently
  602. if (showRecent) {
  603. var today = new Date();
  604. var editDays = (today.getTime() - venue.attributes.createdOn) / 86400000;
  605. if (typeof venue.attributes.updatedOn != 'undefined') {
  606. editDays = (today.getTime() - venue.attributes.updatedOn) / 86400000;
  607. }
  608. if (editDays <= recentDays) {
  609. var shade = Math.floor(editDays * 128 / recentDays);
  610. var colour = "rgb(" + (0) + ", " + (255-shade) + ", " + (0) + ")";
  611. highlightAPlace(venue, colour, colour);
  612. continue;
  613. }
  614. }
  615. // residential = cyan edges, like house numbers
  616. if (venue.attributes.residential) {
  617. highlightAPlace(venue, "#44afcf", "4ac");
  618. }
  619. // gas station = orange
  620. else if (categories.indexOf("GAS_STATION") > -1) {
  621. highlightAPlace(venue, "#f90", "#f91");
  622. }
  623.  
  624. // parking lot = cyan
  625. else if (categories.indexOf("PARKING_LOT") > -1) {
  626. highlightAPlace(venue, "#099", "#0cc");
  627. }
  628.  
  629. // water = blue
  630. else if (categories.indexOf("RIVER_STREAM") > -1 ||
  631. categories.indexOf("CANAL") > -1 ||
  632. categories.indexOf("SEA_LAKE_POOL") > -1) {
  633. highlightAPlace(venue, "#06c", "#09f");
  634. poly.setAttribute("stroke-dasharray", "none");
  635. }
  636.  
  637. // park/grass/trees = green
  638. else if (!showRecent && !specificEditor && (
  639. categories.indexOf("PARK") > -1 ||
  640. categories.indexOf("SWAMP_MARSH") > -1 ||
  641. categories.indexOf("FOREST_GROVE") > -1 ||
  642. categories.indexOf("GOLF_COURSE") > -1) ) {
  643. highlightAPlace(venue, "#0b0", "#4f4");
  644. poly.setAttribute("stroke-dasharray", "none");
  645. }
  646. // locked venues have red border (overrides all other options)
  647. if (showLocked && venue.attributes.lockRank > 0) {
  648. poly.setAttribute("stroke", "red");
  649. }
  650. } // for
  651. //if (updates > 0)
  652. // getId("wmedebug").innerText = updates;
  653. }
  654.  
  655. function highlightAPlace(venue, fg, bg) {
  656. var poly = getId(venue.geometry.id);
  657. if (venue.isPoint()) {
  658. poly.setAttribute("fill", fg);
  659. }
  660.  
  661. else { // area
  662. poly.setAttribute("stroke", fg);
  663. poly.setAttribute("fill", bg);
  664. }
  665. }
  666.  
  667. // used when clicking an option that affects both Segments and Places
  668. function highlightSegmentsAndPlaces(event) {
  669. if (!wmechinit) return;
  670.  
  671. highlightSegments(event);
  672. highlightPlaces(event);
  673. }
  674.  
  675. var lastSelected = null;
  676. function highlightSelectedNodes() {
  677. if (!wmechinit || Waze.map.zoom <= 3 || !advancedMode)
  678. return true;
  679.  
  680. var showTurns = advancedMode ? getId('_cbHighlightTurns').checked : false;
  681.  
  682. // look for a selected node or segment (there can only be 1)
  683. var currentNodes = [];
  684. var selectType = '';
  685. if (Waze.selectionManager.selectedItems.length == 1){
  686. var selection = Waze.selectionManager.selectedItems[0].model;
  687. var selAttr = selection.attributes;
  688.  
  689. if (selection !== null){
  690. if (selection.state == "Update" && lastModified == false){
  691. lastSelected = null;
  692. lastModified = true;
  693. } else if (selection.state != "Update" && lastModified == true){
  694. lastSelected = null;
  695. lastModified = false;
  696. }
  697. selectType = selection.type;
  698. if (selection.type == "node"){
  699. currentNodes.push(selAttr.id);
  700. }else if (selection.type == "segment"){
  701. if (selAttr.fromNodeID !== null)
  702. currentNodes.push(selAttr.fromNodeID);
  703. if (selAttr.toNodeID !== null)
  704. currentNodes.push(selAttr.toNodeID);
  705. }
  706. }
  707. }
  708.  
  709. // selection changed, then reset previous highlights | selectType == 'node'
  710. if ((lastSelected != currentNodes[0] || !showTurns) && selectedLines.length > 0){
  711. for (var i = 0; i < selectedLines.length; i++){
  712. line = getId(selectedLines[i]);
  713. if (line !== null && line.getAttribute("stroke-width") == 8)
  714. line.setAttribute("stroke-opacity", 0.0001);
  715. }
  716. selectedLines = [];
  717. }
  718.  
  719. // no node selected, quit now
  720. if (currentNodes.length === 0){
  721. lastSelected = null;
  722. lastModified = false;
  723. return true;
  724. }
  725.  
  726. var numSoftTurns = 0;
  727. var numRevConns = 0;
  728. var numUTurns = 0;
  729. var showWarning = false;
  730.  
  731. for (var i = 0; i < currentNodes.length; i++){
  732. var currentNode = currentNodes[i];
  733. var node = Waze.model.nodes.get(currentNode);
  734. var nodeAttr = node.attributes;
  735. if (node === undefined) continue;
  736.  
  737. // ignore dead-end nodes
  738. if (nodeAttr.segIDs.length <= 1){
  739. lastSelected = currentNode[0];
  740. continue;
  741. }
  742. var newColor = null;
  743. var segmentColor = [];
  744. var segment1, segment2, seg1Attr, seg2Attr;
  745. // find segments that connect to this node
  746. for (var j = 0; j < nodeAttr.segIDs.length; j++){
  747. segment1 = Waze.model.segments.get(node.attributes.segIDs[j]);
  748. seg1Attr = segment1.attributes;
  749.  
  750. if (segment1 === undefined)
  751. continue;
  752. if (nonDrivableTypes.indexOf(seg1Attr.roadType) != -1)
  753. continue; // For look at all drivable road
  754.  
  755. // highlight U-turns
  756. if(segment1.isTurnAllowed(segment1, node)){
  757. segmentColor[j] = "#0ff";
  758. numUTurns++;
  759. }
  760.  
  761. // highlight soft-turns
  762. if (nodeAttr.id == seg1Attr.fromNodeID){
  763. var nodeLocked = (seg1Attr.revTurnsLocked);
  764. }else if (nodeAttr.id == seg1Attr.toNodeID){
  765. var nodeLocked = (seg1Attr.fwdTurnsLocked);
  766. }
  767. if (nodeLocked === false){
  768. segmentColor[j] = "#ff0";
  769. numSoftTurns++;
  770. }
  771. }
  772. for (var j = 0; j < nodeAttr.segIDs.length - 1; j++){
  773. segment1 = Waze.model.segments.get(node.attributes.segIDs[j]);
  774. seg1Attr = segment1.attributes;
  775.  
  776. if (nonDrivableTypes.indexOf(seg1Attr.roadType) != -1)
  777. continue; // For look at all drivable road
  778.  
  779. for (var k = 1; k < nodeAttr.segIDs.length; k++){
  780. segment2 = Waze.model.segments.get(node.attributes.segIDs[k]);
  781. seg2Attr = segment2.attributes;
  782.  
  783. if (nonDrivableTypes.indexOf(seg2Attr.roadType) != -1)
  784. continue; // For look at all drivable road
  785.  
  786. // highlight RevCons
  787. /******************************************************************************************************************
  788. | segment1.isTurnAllowed(segment2, node): --> Test if Turn to segment1 into segment2 at node is allowed |
  789. | node.isTurnAllowedBySegDirections(segment1, segment2): --> Test if Direction of segment1 into segment2 at node |
  790. ******************************************************************************************************************/
  791. if (seg1Attr.id != seg2Attr.id){
  792. if (segment1.isTurnAllowed(segment2, node) && !node.isTurnAllowedBySegDirections(segment1, segment2)){
  793. segmentColor[j] = "#f0f";
  794. numRevConns++;
  795. }
  796. if (segment2.isTurnAllowed(segment1, node) && !node.isTurnAllowedBySegDirections(segment2, segment1)){
  797. segmentColor[j] = "#f0f";
  798. numRevConns++;
  799. }
  800. }
  801. }
  802. }
  803. for (var j = 0; j < nodeAttr.segIDs.length; j++){
  804. var segment = Waze.model.segments.get(node.attributes.segIDs[j]);
  805. var segAttr = segment.attributes;
  806. var line = getId(segAttr.geometry.id);
  807. if (line === null) return;
  808. if (segmentColor[j]){
  809. newColor = segmentColor[j];
  810. } else newColor = null;
  811.  
  812. var oldOpacity = line.getAttribute("stroke-opacity");
  813. if (newColor !== null && oldOpacity < 1 && showTurns){
  814. line.setAttribute("stroke", newColor);
  815. line.setAttribute("stroke-opacity", 1);
  816. line.setAttribute("stroke-width", 8);
  817. line.setAttribute("stroke-dasharray", "none");
  818. selectedLines.push(segAttr.geometry.id);
  819. }
  820. if (newColor !== null) {
  821. showWarning = true;
  822. }
  823. }
  824. }
  825.  
  826. if (currentNodes.length > 0){
  827. var currentNode = currentNodes[0];
  828.  
  829. if (showWarning === true){
  830. // setup new box for warnings about this node
  831. var selectionBox;
  832. if (selectType == 'segment')
  833. selectionBox = getId('segment-edit-general');
  834. else
  835. selectionBox = getId('node-edit-general');
  836.  
  837. var nodeDetails = getId('nodeTipsBox');
  838. if (!nodeDetails){
  839. nodeDetails = document.createElement('div');
  840. nodeDetails.id = 'nodeTipsBox';
  841. selectionBox.appendChild(nodeDetails);
  842. } else{
  843. return;
  844. }
  845.  
  846. nodeHelp = '';
  847. if (numSoftTurns > 0){
  848. nodeText = document.createElement('div');
  849. if (selectType == 'node')
  850. nodeHelp = "Press <b>Q</b> and then re-enable each allowed turn.";
  851. else
  852. nodeHelp = "Select individual nodes to see details.";
  853. nodeText.style.padding = "4px 2px";
  854. nodeText.innerHTML = "<b>Warning:</b> " + selectType + " has " + numSoftTurns + " soft turns.";
  855. nodeText.style.backgroundColor = '#ffc';
  856. nodeDetails.appendChild(nodeText);
  857. }
  858. if (numRevConns > 0){
  859. nodeText = document.createElement('div');
  860. if (selectType == 'node')
  861. nodeHelp = "Press <b>Q</b> and then re-enable each allowed turn.";
  862. else
  863. nodeHelp = "Select individual nodes to see details.";
  864. nodeText.style.padding = "4px 2px";
  865. nodeText.innerHTML = "<b>Warning:</b> " + selectType + " has " + numRevConns + " reverse connections.";
  866. nodeText.style.backgroundColor = '#fcf';
  867. nodeDetails.appendChild(nodeText);
  868. }
  869. if (numUTurns > 0){
  870. nodeText = document.createElement('div');
  871. nodeText.title = "Use the U-Turn arrows to set when a U-Turn is allowed.";
  872. nodeText.style.padding = "4px 2px";
  873. nodeText.innerHTML = "<b>Notice:</b> " + selectType + " has " + numUTurns + " U-Turns enabled.";
  874. nodeText.style.backgroundColor = '#cff';
  875. nodeDetails.appendChild(nodeText);
  876. }
  877. nodeText = document.createElement('div');
  878. nodeText.style.padding = "4px 2px";
  879. nodeText.innerHTML = nodeHelp + '<br><i>For a full explanation, <a href="https://wiki.waze.com/wiki/Soft_and_hard_turns" target="_blank">see this page</a>.</i><br>';
  880. nodeDetails.appendChild(nodeText);
  881. }
  882. }
  883. lastSelected = currentNodes[0];
  884. return true;
  885. }
  886.  
  887. function highlightBadNodes() {
  888. if (!wmechinit || Waze.map.zoom <= 3 || !advancedMode)
  889. return true;
  890.  
  891. var showTurns = advancedMode ? getId('_cbHighlightTurns').checked : false;
  892. var showRestrictions = getId('_cbHighlightRestrictions').checked;
  893.  
  894. for (var currentNode in Waze.model.nodes.objects){
  895. var node = Waze.model.nodes.get(currentNode);
  896. var nodeAttr = node.attributes;
  897. if (node === undefined) continue;
  898.  
  899. var numRestrictions = 0;
  900. var numSoftTurns = 0;
  901. var numRevConns = 0;
  902. var numUTurns = 0;
  903. var segment1, segment2, seg1Attr, seg2Attr;
  904.  
  905. // ignore dead-end nodes
  906. if (nodeAttr.segIDs.length <= 1) {
  907. continue;
  908. }
  909.  
  910. // find segments that connect to this node
  911. /******************************************************************************************************************
  912. | highlight RevCons |
  913. | |
  914. | segment1.isTurnAllowed(segment2, node): --> Test if Turn to segment1 into segment2 at node is allowed |
  915. | node.isTurnAllowedBySegDirections(segment1, segment2): --> Test if Direction of segment1 into segment2 at node |
  916. ******************************************************************************************************************/
  917. for (var j = 0; j < nodeAttr.segIDs.length - 1; j++){
  918. segment1 = Waze.model.segments.get(node.attributes.segIDs[j]);
  919. seg1Attr = segment1.attributes;
  920. if (nonDrivableTypes.indexOf(seg1Attr.roadType) == -1)
  921. continue;
  922.  
  923. for (var k = 1; k < nodeAttr.segIDs.length; k++){
  924. segment2 = Waze.model.segments.get(node.attributes.segIDs[k]);
  925. seg2Attr = segment2.attributes;
  926. if (nonDrivableTypes.indexOf(seg2Attr.roadType) == -1)
  927. continue; // For look at all drivable road
  928.  
  929. if (seg1Attr.id != seg2Attr.id){
  930. if (segment1.isTurnAllowed(segment2, node) && !node.isTurnAllowedBySegDirections(segment1, segment2)){
  931. numRevConns++;
  932. }
  933. if (segment2.isTurnAllowed(segment1, node) && !node.isTurnAllowedBySegDirections(segment2, segment1)){
  934. numRevConns++;
  935. }
  936. }
  937. }
  938. }
  939. //******************************************************************************************************************
  940. for (var j = 0; j < nodeAttr.segIDs.length; j++){
  941. segment1 = Waze.model.segments.get(node.attributes.segIDs[j]);
  942. seg1Attr = segment1.attributes;
  943. // count restictions
  944. if (showRestrictions) {
  945. if (nodeAttr.id == seg1Attr.fromNodeID){
  946. if (seg1Attr.fromRestrictions){
  947. for (key in seg1Attr.fromRestrictions){
  948. numRestrictions++;
  949. }
  950. }
  951. }
  952. if (nodeAttr.id == seg1Attr.toNodeID){
  953. if (seg1Attr.toRestrictions){
  954. for (key in seg1Attr.toRestrictions){
  955. numRestrictions++;
  956. }
  957. }
  958. }
  959. }
  960. if (majorRoadTypes.indexOf(seg1Attr.roadType) == -1)
  961. continue; // For look at all drivable road
  962.  
  963. // highlight U-turns
  964. if(segment1.isTurnAllowed(segment1, node)){
  965. numUTurns++;
  966. }
  967.  
  968. // highlight soft-turns
  969. if (nodeAttr.id == seg1Attr.fromNodeID){
  970. var nodeLocked = (seg1Attr.revTurnsLocked);
  971. } else if (nodeAttr.id == seg1Attr.toNodeID){
  972. var nodeLocked = (seg1Attr.fwdTurnsLocked);
  973. }
  974. if (nodeLocked === false){
  975. numSoftTurns++;
  976. }
  977. }
  978. var newColor = null;
  979. if (numUTurns > 0) newColor = "#0ff";
  980. else if (numSoftTurns > 0) newColor = "#ff0"; // yellow
  981. else if (numRevConns > 0) newColor = "#f0f";
  982. else if (numRestrictions > 0) newColor = "#909";
  983.  
  984. var circle = getId(nodeAttr.geometry.id);
  985. if (newColor != null && circle != null) {
  986. opacity = circle.getAttribute("fill-opacity");
  987. if (opacity < 0.1) {
  988. circle.setAttribute("fill-opacity", 0.75);
  989. circle.setAttribute("fill", newColor);
  990. }
  991. }
  992. }
  993. return true;
  994. }
  995.  
  996. // add logged in user to drop-down list
  997. function initUserList() {
  998. if (!advancedMode) return;
  999.  
  1000. var thisUser = Waze.loginManager.user;
  1001. if (thisUser === null) return;
  1002.  
  1003. var selectUser = getId('_selectUser');
  1004. var usrOption = document.createElement('option');
  1005. var usrRank = thisUser.normalizedLevel;
  1006. var usrText = document.createTextNode(thisUser.userName + " (" + usrRank + ")");
  1007. usrOption.setAttribute('value',thisUser.id);
  1008. usrOption.appendChild(usrText);
  1009. selectUser.appendChild(usrOption);
  1010. console.info("WME Highlights: Init User list: " + thisUser.userName);
  1011. }
  1012.  
  1013. // add current city in to drop-down list
  1014. function initCityList() {
  1015. var thisCity = Waze.model.segments.topCityID;
  1016. if (thisCity === null) return;
  1017. var thisName = Waze.model.cities.get(thisCity).name;
  1018.  
  1019. var selectCity = getId('_selectCity');
  1020. var cityOption = document.createElement('option');
  1021. var cityText = document.createTextNode(thisName);
  1022. cityOption.appendChild(cityText);
  1023. cityOption.setAttribute('value',thisCity);
  1024. selectCity.appendChild(cityOption);
  1025. console.info("WME Highlights: Init City list: " + thisName);
  1026.  
  1027. // stop listening for this event
  1028. Waze.model.events.unregister("mergeend", null, initCityList);
  1029. }
  1030.  
  1031. // populate drop-down list of editors
  1032. function updateUserList() {
  1033. // update list of users - for high zoom and AMs only
  1034. if (!advancedMode)
  1035. return;
  1036.  
  1037. var selectUser = getId('_selectUser');
  1038. var numUsers = Waze.model.users.objects.length;
  1039. if (numUsers === 0)
  1040. return;
  1041.  
  1042. // preserve current selection
  1043. var currentId = null;
  1044. if (selectUser.selectedIndex >= 0)
  1045. currentId = selectUser.options[selectUser.selectedIndex].value;
  1046.  
  1047. // collect array of users who have edited segments
  1048. var editorIds = [];
  1049. for (var seg in Waze.model.segments.objects) {
  1050. var segment = Waze.model.segments.get(seg);
  1051. if (typeof segment == 'undefined')
  1052. continue;
  1053. var editedBy = segment.attributes.createdBy;
  1054. if (typeof segment.attributes.updatedBy != 'undefined') {
  1055. editedBy = segment.attributes.updatedBy;
  1056. }
  1057. if (editorIds.indexOf(editedBy) == -1)
  1058. editorIds.push(editedBy);
  1059. }
  1060. // collect array of users who have edited places
  1061. for (var ven in Waze.model.venues.objects) {
  1062. var venue = Waze.model.venues.get(ven);
  1063. if (typeof venue == 'undefined')
  1064. continue;
  1065. var editedBy = venue.attributes.createdBy;
  1066. if (typeof venue.attributes.updatedBy != 'undefined') {
  1067. editedBy = venue.attributes.updatedBy;
  1068. }
  1069. if (editorIds.indexOf(editedBy) == -1)
  1070. editorIds.push(editedBy);
  1071. }
  1072. if (editorIds.length === 0)
  1073. return;
  1074.  
  1075. // sort IDs by name
  1076. var editorList = [];
  1077. for (var i = 0; i < editorIds.length; i++) {
  1078. var id = editorIds[i];
  1079. var user = Waze.model.users.get(id);
  1080. if (user === null || typeof user === "undefined" || typeof user.userName === "undefined")
  1081. continue;
  1082. var name = user.userName;
  1083. editorList.push({ id: id, name: name});
  1084. }
  1085. editorList.sort(function (a, b) {
  1086. return a.name.localeCompare(b.name);
  1087. });
  1088.  
  1089. // reset list
  1090. selectUser.options.length = 0;
  1091.  
  1092. // add all users in field of view
  1093. for (var i = 0; i < editorList.length; i++) {
  1094. var id = editorList[i].id;
  1095. var user = Waze.model.users.get(id);
  1096. if (user === null || typeof(user) === "undefined")
  1097. continue;
  1098.  
  1099. var usrOption = document.createElement('option');
  1100. var usrRank = user.normalizedLevel;
  1101. var usrText = document.createTextNode(user.userName + " (" + usrRank + ")");
  1102. if (currentId !== null && id == currentId)
  1103. usrOption.setAttribute('selected',true);
  1104. usrOption.setAttribute('value',id);
  1105. usrOption.appendChild(usrText);
  1106. selectUser.appendChild(usrOption);
  1107. }
  1108. var thisUser = Waze.loginManager.user;
  1109. if (thisUser !== null) {
  1110. var usrOption = document.createElement('option');
  1111. var usrText = document.createTextNode("(all except me)");
  1112. if (currentId !== null && -thisUser.id == currentId)
  1113. usrOption.setAttribute('selected',true);
  1114. usrOption.setAttribute('value',-thisUser.id);
  1115. usrOption.appendChild(usrText);
  1116. selectUser.appendChild(usrOption);
  1117. }
  1118. }
  1119.  
  1120. // populate drop-down list of Cities
  1121. function updateCityList() {
  1122. var selectCity = getId('_selectCity');
  1123. var numCities = Waze.model.cities.objects.length;
  1124.  
  1125. if (numCities === 0)
  1126. return;
  1127.  
  1128. // preserve current selection
  1129. var currentId = null;
  1130. if (selectCity.selectedIndex >= 0)
  1131. currentId = selectCity.options[selectCity.selectedIndex].value;
  1132.  
  1133. // collect array of Cities
  1134. var cityIds = [];
  1135. var cityObjs = [];
  1136.  
  1137. //=========================================================================================
  1138. // This new block of code checks the following assumed conditions:
  1139. // * Every U.S. city should have an associated state
  1140. // * Every 'No city' U.S. city should be properly numbered (not an orphan blank city)
  1141. // * We only care about states if get.cities shows us close enough to the U.S. to matter
  1142. // * Any non US's city state code should be 99 (None/other)
  1143. //========================================================================================
  1144.  
  1145. // collect list if unique cities from the segments
  1146. for (var sid in Waze.model.streets.objects) {
  1147. var cid = Waze.model.streets.get(sid).cityID;
  1148. var city = Waze.model.cities.get(cid);
  1149. if (cityIds.indexOf(cid) == -1) {
  1150. cityIds.push(cid);
  1151. cityObjs.push({id: city.id, name: city.name, state: city.stateID, country: city.countryID});
  1152. }
  1153. }
  1154.  
  1155. if (cityIds.length === 0)
  1156. return;
  1157.  
  1158. // reset list
  1159. selectCity.options.length = 0;
  1160.  
  1161. // count how many (non empty) states there are here
  1162. var numStates = 0
  1163. for (var obj in Waze.model.states.objects) {
  1164. state = Waze.model.states.get(obj);
  1165. if (state.id != 1 && state.name != "")
  1166. numStates++;
  1167. }
  1168.  
  1169. // count how many countries there are here
  1170. var numCountries = 0;
  1171. for (var obj in Waze.model.countries.objects) {
  1172. numCountries++;
  1173. }
  1174.  
  1175. // add all cities in field of view
  1176. cityObjs.sort(function(a,b) {return a.name.localeCompare(b.name)});
  1177. for (var i = 0; i < cityObjs.length; i++) {
  1178. var cityID = cityObjs[i].id;
  1179. // "State-like CityIDs" to ignore. These are consistently over 100,000,000.
  1180. if (cityID > 100000000) continue;
  1181. var cityName = cityObjs[i].name;
  1182. var stateID = cityObjs[i].state;
  1183. var countryID = cityObjs[i].country;
  1184.  
  1185. if (countryID == 235) { // for U.S. only
  1186. // 'No City' segments in the U.S. should have an assigned state.
  1187. // This ID has a prescribed range. If not in this range, we get 'other' state pollution in map,
  1188. // or a bogus blank city associated to the state.
  1189.  
  1190. if (cityName === "") {
  1191. if (cityID >= 999900 && cityID <= 999999) {
  1192. cityName = "No City";
  1193. } else {
  1194. cityName = "EMPTY CITY";
  1195. }
  1196. }
  1197. }
  1198.  
  1199. else { // for non U.S. segments
  1200. if (cityName === "") cityName = "No City";
  1201. }
  1202.  
  1203. var stateObj = Waze.model.states.get(stateID);
  1204. var countryObj = Waze.model.countries.get(countryID);
  1205.  
  1206. // State handling. All cities should have an associated state. Throw an error if not.
  1207. if (numStates > 0) {
  1208. // If more than one state, we're appending it. No brainer.
  1209. if (numStates > 1) {
  1210. // ... and, if one of those states is 'Other', that's an error. Report it.
  1211. if (stateObj.id === 99) {
  1212. cityName += ", " + "NO STATE";
  1213. }
  1214. // If we get here, the state ID should be fine. Append it.
  1215. else {
  1216. cityName += ", " + stateObj.name;
  1217. }
  1218. }
  1219.  
  1220. // If we have more than one country and are in the US, append the state for sanity.
  1221. if (numStates == 1 && numCountries > 1) {
  1222. cityName += ", " + stateObj.name;
  1223. }
  1224. }
  1225.  
  1226. // If we're on a non-US street, state should always be 99, 'Other/none'.
  1227. // Append if this is the case. Otherwise don't add anything.
  1228. else if (stateID != 99 && stateID > 1) {
  1229. cityName += ", INVALID STATE";
  1230. }
  1231.  
  1232. if (numCountries > 1) {
  1233. cityName += ", " + countryObj.name.replace('United States', 'U.S.');
  1234. }
  1235.  
  1236. // create option in select menu
  1237. var cityOption = document.createElement('option');
  1238. var cityText = document.createTextNode(cityName);
  1239.  
  1240. if (currentId !== null && cityID == currentId)
  1241. cityOption.setAttribute('selected',true);
  1242. cityOption.setAttribute('value',cityID);
  1243. cityOption.appendChild(cityText);
  1244. selectCity.appendChild(cityOption);
  1245. }
  1246. }
  1247.  
  1248. var RoadTypes = {
  1249. 1: "Streets",
  1250. 98: "Non-Routable Roads", // --------------
  1251. 108: "- Dirt roads",
  1252. 120: "- Parking Lot Road",
  1253. 117: "- Private Road",
  1254. 114: "- Ferry",
  1255. 199: "Non-Drivable Roads", // --------------
  1256. 210: "- Pedestrian Bw",
  1257. 205: "- Walking Trails",
  1258. 216: "- Stairway",
  1259. 219: "- Runway/Taxiway",
  1260. // 2: "Primary Street",
  1261. // 3: "Freeways",
  1262. // 4: "Ramps",
  1263. // 6: "Major Highway",
  1264. // 7: "Minor Highway",
  1265. // 18: "Railroad",
  1266. // 14: "Ferry',
  1267. 364: "Special Flags", // --------------
  1268. 365: "- Tunnel",
  1269. };
  1270.  
  1271. var majorRoadTypes = new Array(2, 3, 4, 6, 7);
  1272. var nonRoutableTypes = new Array(8, 20, 17);
  1273. var nonDrivableTypes = new Array(5, 10, 16, 18, 19, 14);
  1274.  
  1275. // populate drop-down list of editors
  1276. function populateRoadTypes() {
  1277. var selectRoadType = getId('_selectRoadType');
  1278.  
  1279. for (var id in RoadTypes) {
  1280. var type = RoadTypes[id]
  1281. var usrOption = document.createElement('option');
  1282. var usrText = document.createTextNode(type);
  1283. if (id == 1)
  1284. usrOption.setAttribute('selected',true);
  1285. usrOption.setAttribute('value',id % 100);
  1286. usrOption.appendChild(usrText);
  1287. selectRoadType.appendChild(usrOption);
  1288. }
  1289. }
  1290.  
  1291. // enable advanced options if user is logged in and at least an AM
  1292. function enableAdvancedOptions()
  1293. {
  1294. if (advancedMode) return;
  1295.  
  1296. if (typeof Waze == 'undefined')
  1297. Waze = unsafeWindow.Waze;
  1298.  
  1299. if (typeof Waze.loginManager == 'undefined')
  1300. Waze.loginManager = unsafeWindow.Waze.loginManager;
  1301.  
  1302. if (typeof Waze.loginManager == 'undefined')
  1303. Waze.loginManager = unsafeWindow.loginManager;
  1304.  
  1305. if (Waze.loginManager !== null && Waze.loginManager.isLoggedIn()) {
  1306. thisUser = Waze.loginManager.user;
  1307. if (thisUser !== null && (thisUser.normalizedLevel >= 3 || thisUser.isAreaManager)) {
  1308. Waze.loginManager.events.unregister("afterloginchanged", null, enableAdvancedOptions);
  1309. console.info('WME Highlights: Advanced Options enabled for ' + thisUser.userName);
  1310. getId('advancedOptions').style.display = 'block';
  1311. advancedMode = true;
  1312. initUserList();
  1313. initCityList();
  1314. }
  1315. }
  1316. }
  1317.  
  1318. /* helper function */
  1319. function getElementsByClassName(classname, node) {
  1320. if(!node) node = document.getElementsByTagName("body")[0];
  1321. var a = [];
  1322. var re = new RegExp('\\b' + classname + '\\b');
  1323. var els = node.getElementsByTagName("*");
  1324. for (var i=0,j=els.length; i<j; i++)
  1325. if (re.test(els[i].className)) a.push(els[i]);
  1326. return a;
  1327. }
  1328.  
  1329. function getId(node) {
  1330. return document.getElementById(node);
  1331. }
  1332.  
  1333. /* =========================================================================== */
  1334. function initialiseHighlights()
  1335. {
  1336. if (wmechinit) {
  1337. return;
  1338. }
  1339.  
  1340. // init shortcuts
  1341. if(!window.Waze.map)
  1342. {
  1343. window.console.warn("WME Color Highlights "
  1344. + ": waiting for WME...");
  1345. setTimeout(initialiseHighlights, 789);
  1346. return;
  1347. }
  1348. // check if sidebar is hidden
  1349. var sidebar = getId('sidebar');
  1350. if (sidebar.style.display == 'none') {
  1351. console.warn("WME Highlights: not logged in yet - will initialise at login");
  1352. Waze.loginManager.events.register("login", null, initialiseHighlights);
  1353. return;
  1354. }
  1355. // check that user-info section is defined
  1356. var userTabs = getId('user-info');
  1357. if (userTabs === null) {
  1358. console.warn("WME Highlights: editor not initialised yet - trying again in a bit...");
  1359. setTimeout(initialiseHighlights, 789);
  1360. }
  1361. console.group("WME Color Highlights: " + wmech_version);
  1362.  
  1363. // add new box to left of the map
  1364. var navTabs = getElementsByClassName('nav-tabs', userTabs)[0];
  1365. var tabContent = getElementsByClassName('tab-content', userTabs)[0];
  1366. var addon = document.createElement('section');
  1367. addon.id = "highlight-addon";
  1368.  
  1369. // highlight segements
  1370. var section = document.createElement('p');
  1371. section.style.paddingTop = "0px";
  1372. //section.style.textIndent = "16px";
  1373. section.id = "hiliteOptions";
  1374. section.innerHTML = '<b>Highlight Segments</b><br>'
  1375. + '<input type="checkbox" id="_cbHighlightLocked" title="Locked Segments" /> '
  1376. + '<span title="Dotted = Automatic Locks (if available)">Locks*</span> (Red)<br>'
  1377. + '<input type="checkbox" id="_cbHighlightToll" /> '
  1378. + 'Toll (Dashed)<br>'
  1379. + '<input type="checkbox" id="_cbHighlightAltName" /> '
  1380. + '<span title="Dotted = No Name">Alternate Name</span> (Lime)<br>'
  1381. + '<input type="checkbox" id="_cbHighlightSpeedLimits" /> '
  1382. + '<span title="Segments with unverified speed limits (Orange)">No Speed Limit</span>'
  1383. + ' <input type="checkbox" id="_cbHighlightPlusRampLimits" />&nbsp;+Ramps'
  1384. + ' <input type="checkbox" id="_cbHighlightPlusStreetLimits" />&nbsp;+Streets<br>'
  1385. + '<input type="checkbox" id="_cbHighlightAvgSpeedCams" /> '
  1386. + '<span title="Average Speed Camera Zone">Avg Speed Cams (Blue)<br></span>'
  1387. + '<input type="checkbox" id="_cbHighlightUnnamed" /> '
  1388. + 'No Name (Orange)<br>'
  1389. + '<input type="checkbox" id="_cbHighlightNoCity" /> '
  1390. + 'No City (Gray)<br>'
  1391. + '<input type="checkbox" id="_cbHighlightOneWay" /> '
  1392. + 'One Way (Blue)<br>'
  1393. + '<input type="checkbox" id="_cbHighlightNoDirection" /> '
  1394. + 'Unknown Direction (Cyan)<br>'
  1395. + '<input type="checkbox" id="_cbHighlightRestrictions" /> '
  1396. + 'Time/Vehicle Restrictions (Purple)<br>'
  1397. + '<input type="checkbox" id="_cbHighlightNoTerm" /> '
  1398. + '<span title="*Dead-end roads should have terminating nodes on the end, or Waze cannot route to or from them.">Unterminated Roads* (Lime)</span><br>'
  1399. + '<input type="checkbox" id="_cbHighlightCity" /> '
  1400. + 'Filter by City (Yellow) &nbsp;'
  1401. + ' <input type="checkbox" id="_cbHighlightCityInvert" /> invert <br> '
  1402. + ' <select id="_selectCity" name="_selectCity" style="margin: 0 0 4px 16px"></select>'
  1403. + '<span id="_numCityHighlighted"></span><br>'
  1404. + '<input type="checkbox" id="_cbHighlightRoadType" /> Highlight a Road Type (Purple)<br> '
  1405. + ' <select id="_selectRoadType" name="_selectRoadType" style="margin: 0 0 4px 16px"></select><br>'
  1406. ;
  1407. addon.appendChild(section);
  1408.  
  1409. // advanced options
  1410. section = document.createElement('p');
  1411. section.style.paddingTop = "0px";
  1412. section.style.textIndent = "16px";
  1413. section.style.display = "none";
  1414. section.id = 'advancedOptions';
  1415. section.innerHTML = '<b>Advanced Options</b><br>'
  1416. + '<input type="checkbox" id="_cbHighlightRecent" /> Recently Edited (Green)<br> '
  1417. + ' <input type="number" min="0" max="365" size="3" id="_numRecentDays" style="margin: 0 0 4px 16px"/> days<br>'
  1418. + '<input type="checkbox" id="_cbHighlightEditor" /> Filter by Editor (Green)<br> '
  1419. + ' <select id="_selectUser" name="_selectUser" style="margin: 0 0 4px 16px"></select>'
  1420. + '<span id="_numUserHighlighted"></span><br>'
  1421. + '<input type="checkbox" id="_cbHighlightTurns" /> <span title="*Highlight turn errors when a segment or node is selected, and on major roads">Turn Warnings for Selected Nodes*</span><br>'
  1422. + '<input type="checkbox" id="_cbHighlightRoutingPref" /> Routing Preference (Cyan)<br>'
  1423. ;
  1424. addon.appendChild(section);
  1425.  
  1426. // highlight places
  1427. section = document.createElement('p');
  1428. section.id = "hilitePlaces";
  1429. section.innerHTML = '<input type="checkbox" id="_cbHighlightPlaces" /> <b title="'
  1430. + 'parks/trees = green, water = blue, parking lot = cyan, '
  1431. + 'everything else = pink">Highlight Places</b> '
  1432. + '<span id="wmedebug" style="color: gray"></span><br>'
  1433. + '<input type="checkbox" id="_cbHighlightLockedPlaces" /> Locked Places (Red)<br>'
  1434. + '<input type="checkbox" id="_cbHighlightIncompletePlaces" /> '
  1435. + '<span title="If blank name or street, or wrong category">Incomplete Places</span> (Dashed Orange)<br>'
  1436. ;
  1437. addon.appendChild(section);
  1438.  
  1439. if (/Chrome/.test(navigator.userAgent)) {
  1440. addon.innerHTML += '<b><a href="https://chrome.google.com/webstore/detail/wme-color-highlights/ijnldkoicbhinlgnoigchihmegdjobjc" target="_blank"><u>'
  1441. + 'WME Color Highlights</u></a></b> &nbsp; v' + wmech_version;
  1442. } else {
  1443. addon.innerHTML += '<b><a href="https://greasyfork.org/scripts/3206-wme-color-highlights" target="_blank"><u>'
  1444. + 'WME Color Highlights</u></a></b> &nbsp; v' + wmech_version;
  1445. + ' <a href="https://greasyfork.org/scripts/3206-wme-color-highlights" target="_blank">'
  1446. + '<img src="http://waze.cryosphere.co.uk/scripts/update.php?version=' + wmech_version + '" /></a>';
  1447. }
  1448.  
  1449. newtab = document.createElement('li');
  1450. newtab.innerHTML = '<a href="#sidepanel-highlights" data-toggle="tab">Highlight</a>';
  1451. navTabs.appendChild(newtab);
  1452.  
  1453. addon.id = "sidepanel-highlights";
  1454. addon.className = "tab-pane";
  1455. tabContent.appendChild(addon);
  1456.  
  1457. // check for AM or CM, and unhide Advanced options
  1458. enableAdvancedOptions();
  1459.  
  1460. // always populate road types
  1461. populateRoadTypes();
  1462.  
  1463. // setup onclick handlers for instant update:
  1464. getId('_cbHighlightLocked').onclick = highlightSegments;
  1465. getId('_cbHighlightToll').onclick = highlightSegments;
  1466. getId('_cbHighlightUnnamed').onclick = highlightSegments;
  1467. getId('_cbHighlightNoCity').onclick = highlightSegments;
  1468. getId('_cbHighlightOneWay').onclick = highlightSegments;
  1469. getId('_cbHighlightNoDirection').onclick = highlightSegments;
  1470. getId('_cbHighlightRestrictions').onclick = highlightSegments;
  1471. getId('_cbHighlightSpeedLimits').onclick = highlightSegments;
  1472. getId('_cbHighlightPlusRampLimits').onclick = highlightSegments;
  1473. getId('_cbHighlightPlusStreetLimits').onclick = highlightSegments;
  1474. getId('_cbHighlightAvgSpeedCams').onclick = highlightSegments;
  1475. getId('_cbHighlightRoutingPref').onclick = highlightSegments;
  1476.  
  1477. getId('_cbHighlightRecent').onclick = highlightSegmentsAndPlaces;
  1478. getId('_cbHighlightEditor').onclick = highlightSegmentsAndPlaces;
  1479. getId('_cbHighlightCity').onclick = highlightSegmentsAndPlaces;
  1480. getId('_cbHighlightCityInvert').onclick = highlightSegmentsAndPlaces;
  1481. getId('_cbHighlightRoadType').onclick = highlightSegments;
  1482. getId('_cbHighlightNoTerm').onclick = highlightSegments;
  1483. getId('_cbHighlightTurns').onclick = highlightSelectedNodes;
  1484.  
  1485. getId('_selectUser').onfocus = updateUserList;
  1486. getId('_selectUser').onchange = highlightSegmentsAndPlaces;
  1487.  
  1488. getId('_selectCity').onfocus = updateCityList;
  1489. getId('_selectCity').onchange = highlightSegmentsAndPlaces;
  1490.  
  1491. getId('_numRecentDays').onchange = highlightSegmentsAndPlaces;
  1492. getId('_selectRoadType').onchange = highlightSegments;
  1493.  
  1494. getId('_cbHighlightPlaces').onclick = highlightPlaces;
  1495. getId('_cbHighlightLockedPlaces').onclick = highlightPlaces;
  1496. getId('_cbHighlightIncompletePlaces').onclick = highlightPlaces;
  1497.  
  1498.  
  1499. // restore saved settings
  1500. if (localStorage.WMEHighlightScript) {
  1501. //console.debug("WME Highlights: loading options");
  1502. options = JSON.parse(localStorage.WMEHighlightScript);
  1503.  
  1504. getId('_cbHighlightLocked').checked = (options[1] % 2 == 1);
  1505. getId('_cbHighlightToll').checked = options[2];
  1506. getId('_cbHighlightUnnamed').checked = options[3];
  1507. getId('_cbHighlightNoCity').checked = options[4];
  1508. getId('_cbHighlightOneWay').checked = options[5];
  1509. getId('_cbHighlightNoDirection').checked = options[6];
  1510. getId('_cbHighlightNoTerm').checked = options[14];
  1511. getId('_cbHighlightCity').checked = options[15];
  1512. getId('_cbHighlightRoadType').checked = options[16];
  1513. getId('_selectRoadType').selectedIndex = options[17];
  1514. getId('_cbHighlightPlaces').checked = options[7];
  1515. getId('_cbHighlightRestrictions').checked = options[19];
  1516. getId('_cbHighlightLockedPlaces').checked = options[20]; //(options[1] > 1);
  1517. getId('_cbHighlightIncompletePlaces').checked = options[21];
  1518. getId('_cbHighlightAltName').checked = options[22];
  1519. getId('_cbHighlightSpeedLimits').checked = options[23];
  1520. getId('_cbHighlightPlusRampLimits').checked = options[26];
  1521. getId('_cbHighlightPlusStreetLimits').checked = options[24];
  1522. getId('_cbHighlightAvgSpeedCams').checked = options[27];
  1523. if (options[12] === undefined) options[12] = 7;
  1524. getId('_cbHighlightRecent').checked = options[11];
  1525. getId('_numRecentDays').value = options[12];
  1526. getId('_cbHighlightEditor').checked = options[13];
  1527. getId('_cbHighlightTurns').checked = options[18];
  1528. getId('_cbHighlightRoutingPref').checked = options[25];
  1529. } else {
  1530. getId('_cbHighlightPlaces').checked = true;
  1531. getId('_cbHighlightTurns').checked = true;
  1532. }
  1533.  
  1534. if (typeof Waze.model.venues == "undefined") {
  1535. getId('_cbHighlightPlaces').checked = false;
  1536. getId('_cbHighlightPlaces').disabled = true;
  1537. }
  1538.  
  1539. if (!getId('_cbHighlightPlaces').checked) {
  1540. getId('_cbHighlightLockedPlaces').disabled = true;
  1541. getId('_cbHighlightIncompletePlaces').disabled = true;
  1542. }
  1543.  
  1544. // overload the WME exit function
  1545. saveHighlightOptions = function() {
  1546. if (localStorage) {
  1547. //console.debug("WME Highlights: saving options");
  1548. var options = [];
  1549.  
  1550. // preserve previous options which may get lost after logout
  1551. if (localStorage.WMEHighlightScript)
  1552. options = JSON.parse(localStorage.WMEHighlightScript);
  1553.  
  1554. options[1] = 1 * getId('_cbHighlightLocked').checked + 2 * getId('_cbHighlightLockedPlaces').checked;
  1555. options[2] = getId('_cbHighlightToll').checked;
  1556. options[3] = getId('_cbHighlightUnnamed').checked;
  1557. options[4] = getId('_cbHighlightNoCity').checked;
  1558. options[5] = getId('_cbHighlightOneWay').checked;
  1559. options[6] = getId('_cbHighlightNoDirection').checked;
  1560. options[7] = getId('_cbHighlightPlaces').checked;
  1561. options[14] = getId('_cbHighlightNoTerm').checked;
  1562. options[15] = getId('_cbHighlightCity').checked;
  1563. options[16] = getId('_cbHighlightRoadType').checked;
  1564. options[17] = getId('_selectRoadType').selectedIndex;
  1565. options[19] = getId('_cbHighlightRestrictions').checked;
  1566. options[20] = getId('_cbHighlightLockedPlaces').checked;
  1567. options[21] = getId('_cbHighlightIncompletePlaces').checked;
  1568. options[22] = getId('_cbHighlightAltName').checked;
  1569. options[23] = getId('_cbHighlightSpeedLimits').checked;
  1570. options[24] = getId('_cbHighlightPlusStreetLimits').checked;
  1571. options[26] = getId('_cbHighlightPlusRampLimits').checked;
  1572. options[27] = getId('_cbHighlightAvgSpeedCams').checked;
  1573. if (advancedMode) {
  1574. options[11] = getId('_cbHighlightRecent').checked;
  1575. options[12] = getId('_numRecentDays').value;
  1576. options[13] = getId('_cbHighlightEditor').checked;
  1577. options[18] = getId('_cbHighlightTurns').checked;
  1578. options[25] = getId('_cbHighlightRoutingPref').checked;
  1579. }
  1580.  
  1581. localStorage.WMEHighlightScript = JSON.stringify(options);
  1582. }
  1583. }
  1584. window.addEventListener("beforeunload", saveHighlightOptions, false);
  1585.  
  1586. // begin periodic updates
  1587. window.setInterval(highlightSegments,333);
  1588. window.setInterval(highlightPlaces,500);
  1589. window.setInterval(highlightBadNodes,444);
  1590. window.setInterval(highlightSelectedNodes,250);
  1591.  
  1592. // trigger code when page is fully loaded, to catch any missing bits
  1593. window.addEventListener("load", function(e) {
  1594. var mapProblems = getId('map-problems-explanation')
  1595. if (mapProblems !== null) mapProblems.style.display = "none";
  1596. enableAdvancedOptions();
  1597. });
  1598.  
  1599. // register some events...
  1600. Waze.map.events.register("zoomend", null, highlightSegments);
  1601. Waze.map.events.register("zoomend", null, highlightPlaces);
  1602. Waze.map.events.register("zoomend", null, highlightSelectedNodes);
  1603.  
  1604. Waze.selectionManager.events.register("selectionchanged", null, highlightSelectedNodes);
  1605.  
  1606. //Waze.loginManager.events.register("afterloginchanged", null, enableAdvancedOptions);
  1607. Waze.model.events.register("mergeend", null, initCityList);
  1608.  
  1609. wmechinit = true;
  1610. console.groupEnd();
  1611. }
  1612.  
  1613. // recreate my tab when MTE mode is exited
  1614. function onModeChange(model, modeId) {
  1615. wmechinit = false;
  1616. if (modeId == 0) {
  1617. //initialiseHighlights(); // FIXME
  1618. }
  1619. }
  1620. Waze.app.modeController.model.bind('change:mode', onModeChange);
  1621.  
  1622. /* engage! =================================================================== */
  1623. setTimeout(initialiseHighlights, 789);
  1624.  
  1625. })();
  1626. /* end ======================================================================= */