WME Color Highlights

Adds colours to road segments to show their status

当前为 2014-10-27 提交的版本,查看 最新版本

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