WME Color Highlights

Adds colours to road segments to show their status

当前为 2018-05-09 提交的版本,查看 最新版本

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