WME Color Highlights

Adds colours to road segments to show their status

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