Greasy Fork is available in English.

WME Color Highlights

Adds colours to road segments to show their status

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