WME Color Highlights

Adds colours to road segments to show their status

当前为 2019-07-23 提交的版本,查看 最新版本

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