WME Color Highlights

Adds colours to road segments to show their status

当前为 2015-11-22 提交的版本,查看 最新版本

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