WME Form Filler

Use info from WME to automatically fill out related forms

当前为 2022-09-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WME Form Filler
  3. // @description Use info from WME to automatically fill out related forms
  4. // @namespace https://greasyfork.org/users/6605
  5. // @version 1.4.9.1
  6. // @homepage https://github.com/WazeDev/WME-Form-Filler
  7. // @supportURL https://github.com/WazeDev/WME-Form-Filler/issues
  8. // @include https://www.waze.com/editor
  9. // @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor.*$/
  10. // @author crazycaveman
  11. // @license MIT
  12. // @run-at document-end
  13. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NUIzRDdFNzAwRTlGMTFFNkIyRDZGMzNERUFDMUM1NDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NUIzRDdFNzEwRTlGMTFFNkIyRDZGMzNERUFDMUM1NDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1QjNEN0U2RTBFOUYxMUU2QjJENkYzM0RFQUMxQzU0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1QjNEN0U2RjBFOUYxMUU2QjJENkYzM0RFQUMxQzU0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PtdrqLIAAAOCSURBVHjatJdLaBNBGMdn81ITQ2mLNqlIKInGkpSgFooPpKGHIlZPJqgoIvQivooPfFUsxYNVW62KiuItPah48RaUSlFEaDzEqgeV+sBUxag1rZa8Nv6nfMKaZpNssx34kdnN7sx/5nvNCtFolAUCAW8ymdwtCIKZMZZh6jQBjIIL4EkikWA+n485HI7/HtLFYjHH0NDQnXQ6XQkBbAbaGrAsHo+PNDc3T/lTF4lEVouiWKnX62O4DgBRpYn1YBuoAkuxwBGNRjNVAP7QZjKTu/4V7FJ59euAEWjlHtBg2//ZXEOq1WpzaUyWz690Ms5jUDhZcrqm0+UYyAPuKxyH2zqohgC++j/gmcJxRot5yGAwFBTAr9+AtWrHIqKMBYNBFgqFmlKpVLympuax1+udIiBD9reUON/nLMcTtFotC4fDBoR8H5JSVV1dXVdjY+OxbAEpUA8GSxRQC95KrkUe6jABzwnbkQ/OmUwmPSJQzBbAw+YL6C5hcr7y72TO2TTeI9AA7oErELNBp9NF5HzgEziogtnNZM6j4BfoAfNBB0XZu1wCuAkWggMKJ7sBXmbd4xmwH1wHW8FKut/Hi5NcFIiUu/cpFNCfQ0ACHKGdOM0LHbx/DE54HJWX92XDMEy7oKRFc9z7SXSBBZiYWSyWs0aj8QMvzVarVTYRJckP1GhLwN7J7Ugkhv1+f4/H48mbiPi+LOKeWmIUtIKP4AxFAiNn/F0oE/KX5wB3iQLSoAmsp3sPwW0q+3kF8HL8HFgVTqrJqvn8upf6XMyhYotRhsKnVqEAXj9ikuv9wEX9m/mKWy4fWA6eKhSwEdylfjVop/4PcEJJOebbOAz2KDgdC1kr7ATl1O+gUFwMXhcjgNvuG7g8TQdcAXZQ/xW4RLvxXk6ARmagBhqoTHJvFdhCUSLX2iVjttH7h8GEEh9wggEwiw4mfirRA2Sia2CnzHjV9HuLCs5FOpwmlERBGU3Om41+50nCzJ4nFCM0eTftlI/XAJ778WHCeDou5kg2SNtXLzkXPAAnKbWeymOCzWCM+nwRGT55S0sLs9lszG635xQgSCphivq9OU7LnQUcUJRMzts4T0JozOl0Ci6Xq6AJ+GHhPGUuNRo/jJRTGZbPAyiLIZzRJrBVZXi4bQY+TsfNZvMLWQEVFRVht9u9CQJaIcCk8uf5GArQVRxAh+Ue+ivAAAY7DIf3WTuXAAAAAElFTkSuQmCC
  14. // @grant none
  15. // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
  16. // ==/UserScript==
  17.  
  18. /*global W, $, GM_info, WazeWrap */
  19.  
  20. (function () {
  21. "use strict";
  22. var WMEFFName = GM_info.script.name;
  23. var WMEFFVersion = GM_info.script.version;
  24. var WMEFFIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NUIzRDdFNzAwRTlGMTFFNkIyRDZGMzNERUFDMUM1NDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NUIzRDdFNzEwRTlGMTFFNkIyRDZGMzNERUFDMUM1NDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1QjNEN0U2RTBFOUYxMUU2QjJENkYzM0RFQUMxQzU0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1QjNEN0U2RjBFOUYxMUU2QjJENkYzM0RFQUMxQzU0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PtdrqLIAAAOCSURBVHjatJdLaBNBGMdn81ITQ2mLNqlIKInGkpSgFooPpKGHIlZPJqgoIvQivooPfFUsxYNVW62KiuItPah48RaUSlFEaDzEqgeV+sBUxag1rZa8Nv6nfMKaZpNssx34kdnN7sx/5nvNCtFolAUCAW8ymdwtCIKZMZZh6jQBjIIL4EkikWA+n485HI7/HtLFYjHH0NDQnXQ6XQkBbAbaGrAsHo+PNDc3T/lTF4lEVouiWKnX62O4DgBRpYn1YBuoAkuxwBGNRjNVAP7QZjKTu/4V7FJ59euAEWjlHtBg2//ZXEOq1WpzaUyWz690Ms5jUDhZcrqm0+UYyAPuKxyH2zqohgC++j/gmcJxRot5yGAwFBTAr9+AtWrHIqKMBYNBFgqFmlKpVLympuax1+udIiBD9reUON/nLMcTtFotC4fDBoR8H5JSVV1dXVdjY+OxbAEpUA8GSxRQC95KrkUe6jABzwnbkQ/OmUwmPSJQzBbAw+YL6C5hcr7y72TO2TTeI9AA7oErELNBp9NF5HzgEziogtnNZM6j4BfoAfNBB0XZu1wCuAkWggMKJ7sBXmbd4xmwH1wHW8FKut/Hi5NcFIiUu/cpFNCfQ0ACHKGdOM0LHbx/DE54HJWX92XDMEy7oKRFc9z7SXSBBZiYWSyWs0aj8QMvzVarVTYRJckP1GhLwN7J7Ugkhv1+f4/H48mbiPi+LOKeWmIUtIKP4AxFAiNn/F0oE/KX5wB3iQLSoAmsp3sPwW0q+3kF8HL8HFgVTqrJqvn8upf6XMyhYotRhsKnVqEAXj9ikuv9wEX9m/mKWy4fWA6eKhSwEdylfjVop/4PcEJJOebbOAz2KDgdC1kr7ATl1O+gUFwMXhcjgNvuG7g8TQdcAXZQ/xW4RLvxXk6ARmagBhqoTHJvFdhCUSLX2iVjttH7h8GEEh9wggEwiw4mfirRA2Sia2CnzHjV9HuLCs5FOpwmlERBGU3Om41+50nCzJ4nFCM0eTftlI/XAJ778WHCeDou5kg2SNtXLzkXPAAnKbWeymOCzWCM+nwRGT55S0sLs9lszG635xQgSCphivq9OU7LnQUcUJRMzts4T0JozOl0Ci6Xq6AJ+GHhPGUuNRo/jJRTGZbPAyiLIZzRJrBVZXi4bQY+TsfNZvMLWQEVFRVht9u9CQJaIcCk8uf5GArQVRxAh+Ue+ivAAAY7DIf3WTuXAAAAAElFTkSuQmCC";
  25. var forms = [];
  26.  
  27. function formfiller_bootstrap() {
  28. formfiller_log("Running bootstrap");
  29.  
  30. if (typeof W.app === "undefined" || !window.W.map) {
  31. setTimeout(formfiller_bootstrap, 500);
  32. return;
  33. }
  34. formfiller_log("Starting init");
  35. formfiller_init();
  36. }
  37.  
  38. function formfiller_waitForSegmentEditDiv(callback, callCount = 0) {
  39. const div = $('div.segment-edit-section');
  40. if (div.length) {
  41. callback();
  42. } else if (callCount < 30) { // try for about 3 seconds
  43. setTimeout(() => formfiller_waitForSegmentEditDiv(callback, ++callCount), 100);
  44. }
  45. }
  46.  
  47. function formfiller_init() {
  48. // Check document elements are ready
  49. var userInfo = document.getElementById("user-info");
  50. if (userInfo === null) {
  51. window.setTimeout(formfiller_init, 500);
  52. return;
  53. }
  54. var userTabs = document.getElementById("user-tabs");
  55. if (userTabs === null) {
  56. window.setTimeout(formfiller_init, 500);
  57. return;
  58. }
  59. var navTab = userInfo.getElementsByTagName("ul");
  60. if (navTab.length === 0) {
  61. window.setTimeout(formfiller_init, 500);
  62. return;
  63. }
  64. if (typeof navTab[0] === "undefined") {
  65. window.setTimeout(formfiller_init, 500);
  66. return;
  67. }
  68. var tabContent = userInfo.getElementsByTagName("div");
  69. if (tabContent.length === 0) {
  70. window.setTimeout(formfiller_init, 500);
  71. return;
  72. }
  73. if (typeof tabContent[0] === "undefined") {
  74. window.setTimeout(formfiller_init, 500);
  75. return;
  76. }
  77.  
  78. ff_addUserTab();
  79. ff_addFormBtn();
  80.  
  81. W.selectionManager.events.on('selectionchanged', evt => {
  82. const model = evt.selected[0]?.model;
  83. if (model?.type === 'segment') {
  84. formfiller_waitForSegmentEditDiv(ff_addFormBtn);
  85. }
  86. });
  87.  
  88. if (W.app.modeController) {
  89. W.app.modeController.model.bind("change:mode", function (model, modeId) {
  90. if (modeId === 0) {
  91. ff_addUserTab();
  92. }
  93. });
  94. }
  95.  
  96. // Unit switched (imperial/metric)
  97. if (W.prefs) {
  98. W.prefs.on("change:isImperial", ff_addUserTab);
  99. }
  100.  
  101. if (!W.selectionManager.getSelectedFeatures) {
  102. W.selectionManager.getSelectedFeatures = W.selectionManager.getSelectedItems;
  103. }
  104. formfiller_log("Init done");
  105. return;
  106. }
  107.  
  108. //Shamelessly copied from https://gist.github.com/CalebGrove/c285a9510948b633aa47
  109. function abbrState(input, to) {
  110. var states = [
  111. ["ALABAMA", "AL"],
  112. ["ALASKA", "AK"],
  113. ["ARIZONA", "AZ"],
  114. ["ARKANSAS", "AR"],
  115. ["CALIFORNIA", "CA"],
  116. ["COLORADO", "CO"],
  117. ["CONNECTICUT", "CT"],
  118. ["DELAWARE", "DE"],
  119. ["DISTRICT OF COLUMBIA", "DC"],
  120. ["FLORIDA", "FL"],
  121. ["GEORGIA", "GA"],
  122. ["HAWAII", "HI"],
  123. ["IDAHO", "ID"],
  124. ["ILLINOIS", "IL"],
  125. ["INDIANA", "IN"],
  126. ["IOWA", "IA"],
  127. ["KANSAS", "KS"],
  128. ["KENTUCKY", "KY"],
  129. ["LOUISIANA", "LA"],
  130. ["MAINE", "ME"],
  131. ["MARYLAND", "MD"],
  132. ["MASSACHUSETTS", "MA"],
  133. ["MICHIGAN", "MI"],
  134. ["MINNESOTA", "MN"],
  135. ["MISSISSIPPI", "MS"],
  136. ["MISSOURI", "MO"],
  137. ["MONTANA", "MT"],
  138. ["NEBRASKA", "NE"],
  139. ["NEVADA", "NV"],
  140. ["NEW HAMPSHIRE", "NH"],
  141. ["NEW JERSEY", "NJ"],
  142. ["NEW MEXICO", "NM"],
  143. ["NEW YORK", "NY"],
  144. ["NORTH CAROLINA", "NC"],
  145. ["NORTH DAKOTA", "ND"],
  146. ["OHIO", "OH"],
  147. ["OKLAHOMA", "OK"],
  148. ["OREGON", "OR"],
  149. ["PENNSYLVANIA", "PA"],
  150. ["RHODE ISLAND", "RI"],
  151. ["SOUTH CAROLINA", "SC"],
  152. ["SOUTH DAKOTA", "SD"],
  153. ["TENNESSEE", "TN"],
  154. ["TEXAS", "TX"],
  155. ["UTAH", "UT"],
  156. ["VERMONT", "VT"],
  157. ["VIRGINIA", "VA"],
  158. ["WASHINGTON", "WA"],
  159. ["WEST VIRGINIA", "WV"],
  160. ["WISCONSIN", "WI"],
  161. ["WYOMING", "WY"],
  162. ["PUERTO RICO", "PR"],
  163. ["VIRGIN ISLANDS (U.S.)", "VI"]
  164. ];
  165.  
  166. var i;
  167. if (to === "abbr") {
  168. input = input.toUpperCase();
  169. for (i = 0; i < states.length; i += 1) {
  170. if (states[i][0] === input) {
  171. return (states[i][1]);
  172. }
  173. }
  174. } else if (to === "name") {
  175. input = input.toUpperCase();
  176. for (i = 0; i < states.length; i += 1) {
  177. if (states[i][1] === input) {
  178. return (states[i][0]);
  179. }
  180. }
  181. }
  182. }
  183.  
  184. function formfiller_log(message) {
  185. if (typeof message === "string") {
  186. console.log("FormFiller: " + message);
  187. } else {
  188. console.log("FormFiller: ", message);
  189. }
  190. }
  191.  
  192. function ff_getStreetName(selection) {
  193. var streetName = [],
  194. i;
  195.  
  196. for (i = 0; i < selection.length; i += 1) {
  197. var newStreet = W.model.streets.getObjectById(selection[i].model.attributes.primaryStreetID);
  198. if (typeof newStreet === "undefined" || newStreet.name === null) {
  199. newStreet = { name: "No Name" };
  200. }
  201. if (streetName.indexOf(newStreet.name) === -1) {
  202. streetName.push(newStreet.name);
  203. }
  204. }
  205. return streetName.join(", ");
  206. }
  207.  
  208. function ff_getState(selection) {
  209. var stateName = "",
  210. i;
  211.  
  212. for (i = 0; i < selection.length; i += 1) {
  213. var cID = W.model.streets.getObjectById(selection[i].model.attributes.primaryStreetID).cityID;
  214. var sID = W.model.cities.getObjectById(cID).attributes.stateID;
  215. var newState = W.model.states.getObjectById(sID).name;
  216.  
  217. if (newState === "") {
  218. sID = W.model.cities.getObjectById(cID).attributes.countryID;
  219. newState = W.model.countries.getObjectById(sID).name;
  220. formfiller_log("cID: " + cID);
  221. formfiller_log("sID: " + sID);
  222. formfiller_log("newState: " + newState);
  223. }
  224.  
  225. if (stateName === "") {
  226. stateName = newState;
  227. } else if (stateName !== newState) {
  228. stateName = "";
  229. break;
  230. }
  231. }
  232. return stateName;
  233. }
  234.  
  235. function ff_getCity(selection) {
  236. var cityName = "",
  237. i;
  238. for (i = 0; i < selection.length; i += 1) {
  239. var cID = W.model.streets.getObjectById(selection[i].model.attributes.primaryStreetID).cityID;
  240. var newCity = W.model.cities.getObjectById(cID).attributes.name;
  241. if (cityName === "") {
  242. cityName = newCity;
  243. } else if (cityName !== newCity) {
  244. cityName = "";
  245. break;
  246. }
  247. }
  248. return cityName;
  249. }
  250.  
  251. function ff_getCounty(selection) {
  252. var county = "";
  253. // Disable county for now, currently broken
  254. /*var center = W.map.center.clone().transform(W.map.projection.projCode, W.map.displayProjection.projCode);
  255. //formfiller_log("Getting county for "+center.lat.toString()+","+center.lon.toString());
  256. var xhr = new XMLHttpRequest();
  257. xhr.open("GET", "https://maps.googleapis.com/maps/api/geocode/json?latlng=" + center.lat + "," + center.lon, false);
  258. xhr.onload = function () {
  259. if (xhr.readyState === 4) {
  260. if (xhr.status === 200) {
  261. var response = JSON.parse(xhr.responseText);
  262. if (response.status !== "OK") {
  263. formfiller_log(`Error getting county name (${response.status})`);
  264. return county;
  265. }
  266. var addrComps = response.results[0].address_components;
  267. var comp;
  268. for (comp = 0; comp < addrComps.length; comp += 1) {
  269. if (addrComps[comp].types.indexOf("administrative_area_level_2") !== -1) {
  270. county = addrComps[comp].long_name;
  271. //formfiller_log("ff_getCounty: "+county);
  272. var countyIndex = (county.indexOf(" County") !== -1 ? county.indexOf(" County") : county.indexOf(" Parish"));
  273. if (countyIndex !== -1) {
  274. county = county.slice(0, countyIndex);
  275. }
  276. break;
  277. }
  278. }
  279. }
  280. }
  281. };
  282. xhr.send(null);*/
  283. return county;
  284. }
  285.  
  286. function ff_closureActive(selection) {
  287. var i;
  288. for (i = 0; i < selection.length; i += 1) {
  289. if (selection[i].model.hasClosures()) {
  290. if (W.model.roadClosures.getByAttributes({
  291. segID: selection[i].model.attributes.id
  292. })[0].active) {
  293. return true;
  294. }
  295. }
  296. }
  297. return false;
  298. }
  299.  
  300. function ff_getClosureInfo(seg) {
  301. var closureInfo = {
  302. closedDir: "",
  303. endDate: "",
  304. idFwd: "",
  305. idRev: "",
  306. closedReason: ""
  307. };
  308. var segID = seg.model.attributes.id;
  309. var closureList = W.model.roadClosures.getByAttributes({
  310. segID,
  311. active: true
  312. });
  313. var i;
  314.  
  315. for (i = 0; i < closureList.length; i += 1) {
  316. if (closureList[i].active === true) {
  317. if (closureInfo.endDate === "") {
  318. closureInfo.endDate = closureList[i].endDate;
  319. } else if (closureInfo.endDate > closureList[i].endDate) {
  320. closureInfo.endDate = closureList[i].endDate;
  321. }
  322. if (closureList[i].forward === true) {
  323. closureInfo.idFwd = closureList[i].id;
  324. } else {
  325. closureInfo.idRev = closureList[i].id;
  326. }
  327. if (closureInfo.closedReason === "") {
  328. closureInfo.closedReason = closureList[i].reason;
  329. }
  330. }
  331. }
  332.  
  333. if (closureInfo.idFwd !== "" && closureInfo.idRev !== "") {
  334. closureInfo.closedDir = "Two-Way";
  335. } else {
  336. closureInfo.closedDir = "One-Way";
  337. }
  338.  
  339. return closureInfo;
  340. }
  341.  
  342. function ff_createPermalink(selection) {
  343. //https://www.waze.com/editor/?env=usa&lon=-79.79248&lat=32.86150&layers=12709&zoom=5&mode=0&mapProblemFilter=1&mapUpdateRequestFilter=0&venueFilter=0&segments=504534141
  344. //https://www.waze.com/editor/?env=usa&lon=-79.79248&lat=32.86150&layers=12709&zoom=5&mode=0&mapProblemFilter=1&mapUpdateRequestFilter=0&venueFilter=0&venues=183632201.1836387542.3102948
  345. var permalink = "https://www.waze.com/editor/?",
  346. segIDs = [];
  347.  
  348. var latLon = WazeWrap.Geometry.ConvertTo4326(W.map.getOLMap().center.lon, W.map.getOLMap().center.lat)
  349. var lat = latLon.lat,
  350. lon = latLon.lon;
  351. var env = W.location ? W.location.code : W.app.getAppRegionCode();
  352. var type = "segments";
  353. var zoom = W.map.getOLMap().zoom;
  354. var zoomToRoadType = function (e) {
  355. switch (e) {
  356. case 0:
  357. case 1:
  358. return [];
  359. case 2:
  360. return [2, 3, 4, 6, 7, 15];
  361. case 3:
  362. return [2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22];
  363. case 4:
  364. case 5:
  365. case 6:
  366. case 7:
  367. case 8:
  368. case 9:
  369. case 10:
  370. default:
  371. return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22];
  372. }
  373. };
  374. var i;
  375.  
  376. //To get lat and long centered on segment
  377. if (selection.length === 1) {
  378. latLon = selection[0].model.getCenter().clone();
  379. latLon = WazeWrap.Geometry.ConvertTo4326(latLon.x,latLon.y)
  380. lat = latLon.lat;
  381. lon = latLon.lon;
  382. }
  383.  
  384. for (i = 0; i < selection.length; i += 1) {
  385. var segment = selection[i].model;
  386. if (segment.type === "segment") {
  387. segIDs.push(segment.attributes.id);
  388. if (zoomToRoadType(zoom) === 0 || zoomToRoadType(zoom).indexOf(segment.attributes.roadType) === -1) {
  389. alert("This zoom level (" + zoom.toString() + ") cannot be used for this road type! Please increase your zoom:\n" +
  390. "Streets: 4+\nOther drivable and Non-drivable: 3+\nHighways and PS: 2+");
  391. formfiller_log("Zoom level not correct for segment: " + zoom.toString() + " " + segment.attributes.roadType.toString());
  392. return;
  393. }
  394. }
  395. }
  396. permalink += "env=" + env + "&lon=" + lon + "&lat=" + lat + "&zoomLevel=" + zoom.toString() + "&" + type + "=" + segIDs.join();
  397. return permalink;
  398. }
  399.  
  400. function ff_getLastEditor(selection) {
  401. var eID;
  402. var editorNames = "";
  403. var newEdName = "";
  404. //selection[0].model.attributes.updatedBy;
  405. selection.forEach(function (selected) {
  406. eID = selected.model.attributes.updatedBy;
  407. if (typeof eID !== "undefined") {
  408. formfiller_log("Unable to get updatedBy on " + selected.model.attributes.id);
  409. eID = selected.model.attributes.createdBy;
  410. }
  411. newEdName = W.model.users.getObjectById(eID).userName;
  412. if (editorNames.indexOf(newEdName) === -1) {
  413. editorNames += ", " + newEdName;
  414. }
  415.  
  416. });
  417. editorNames = editorNames.substr(2);
  418. return editorNames;
  419. }
  420.  
  421. function ff_createFormLink(formSel) {
  422. var selection = W.selectionManager.getSelectedFeatures();
  423. var formValues = {};
  424. var formFields = formSel.fields;
  425. var formLink = formSel.url + "?entry.";
  426. var formArgs = [];
  427. if (selection.length === 0 || selection[0].model.type !== "segment") {
  428. formfiller_log("No segments selected.");
  429. return;
  430. }
  431.  
  432. /*Fields expected:
  433. username
  434. permalink
  435. closedDir
  436. closureStatus
  437. closedReason
  438. endDate
  439. streetname
  440. fromStreet
  441. toStreet
  442. stateabbr
  443. county
  444. city
  445. source
  446. notes
  447. */
  448.  
  449. Object.keys(formFields).forEach((key, index) => {
  450. switch (key) {
  451. case "username":
  452. formValues[key] = W.loginManager.user.userName;
  453. break;
  454. case "permalink":
  455. formValues[key] = ff_createPermalink(selection);
  456. if (typeof formValues.permalink === "undefined") {
  457. formfiller_log("No permalink generated");
  458. return;
  459. }
  460. break;
  461. case "streetname":
  462. formValues[key] = W.model.hasStates ? ff_getStreetName(selection) : "";
  463. break;
  464. case "editorName":
  465. formValues[key] = ff_getLastEditor(selection);
  466. break;
  467. case "stateabbr":
  468. formValues[key] = abbrState(ff_getState(selection), "abbr");
  469. break;
  470. case "state":
  471. formValues[key] = ff_getState(selection);
  472. break;
  473. case "county":
  474. formValues.county = ff_getCounty(selection);
  475. break;
  476. case "city":
  477. formValues[key] = ff_getCity(selection);
  478. break;
  479. case "notes":
  480. formValues[key] = "Form filled by " + WMEFFName + " v" + WMEFFVersion;
  481. break;
  482. case "closureStatus":
  483. if (selection[0].model.type === "segment") {
  484. if (ff_closureActive(selection)) {
  485. formValues.closureStatus = "CLOSED";
  486. var closureInfo = ff_getClosureInfo(selection[0]);
  487. formValues.closedDir = closureInfo.closedDir;
  488. formValues.closedReason = closureInfo.closedReason;
  489. formValues.endDate = closureInfo.endDate;
  490. } else {
  491. formValues.closureStatus = "REPORTED";
  492. formValues.closedDir = "Two-Way";
  493. formValues.closedReason = document.getElementById("ff-closure-reason").value;
  494. formValues.endDate = document.getElementById("ff-closure-endDate").value + "+" + document.getElementById("ff-closure-endTime").value;
  495. }
  496. }
  497. break;
  498. default:
  499. formfiller_log("Nothing defined for " + key);
  500. break;
  501. }
  502.  
  503. //Add entry to form URL, if there's something to add
  504. if (typeof formValues[key] !== "undefined" && formValues[key] !== "") {
  505. formArgs[index] = formFields[key] + "=" + encodeURIComponent(formValues[key]);
  506. }
  507. });
  508. formLink += formArgs.join("&entry.");
  509.  
  510. formfiller_log(formLink);
  511. return formLink;
  512. }
  513.  
  514. function ff_addFormBtn() {
  515. var selection = W.selectionManager.getSelectedFeatures();
  516. var ffDiv = document.createElement("div"),
  517. ffMnu = document.createElement("select"),
  518. ffBtn = document.createElement("button");
  519. var formWindowName = "WME Form Filler result",
  520. formWindowSpecs = "resizable=1,menubar=0,scrollbars=1,status=0,toolbar=0";
  521. var editPanel,
  522. selElem,
  523. formLink;
  524. ffDiv.id = "formfillerDiv";
  525. editPanel = document.getElementById("edit-panel");
  526. selElem = document.querySelector("div.segment-feature-editor");
  527. if (selection.length === 0 || selection[0].model.type !== "segment") {
  528. //formfiller_log("No segments selected.");
  529. return;
  530. }
  531. if (document.getElementById("formfillerDiv")) {
  532. //formfiller_log("Div already created");
  533. return;
  534. }
  535.  
  536. forms = [{
  537. //https://docs.google.com/forms/d/e/1FAIpQLScxs_FMsjcEeTD0gjWUahb3Qb0XjeB2K32n_vWLm_HV2fUweQ/viewform?entry.1553765347=username&entry.1264424583=CLOSED&entry.1811077109=permalink&entry.792657790=Two-Way&entry.345142186=reason&entry.1102521735=2016-09-20+03:00&entry.2015424420=street+name&entry.1547375393=from+street&entry.1335391716=to+street&entry.1867193205=NSW&entry.1714138473=county&entry.1803937317=source&entry.1648634142=notes
  538. name: "AUS VEOC closures",
  539. url: "https://docs.google.com/forms/d/e/1FAIpQLScxs_FMsjcEeTD0gjWUahb3Qb0XjeB2K32n_vWLm_HV2fUweQ/viewform",
  540. fields: {
  541. username: "1553765347",
  542. closureStatus: "1264424583",
  543. permalink: "1811077109",
  544. closedDir: "792657790",
  545. closedReason: "345142186",
  546. endDate: "1102521735",
  547. streetname: "2015424420",
  548. fromStreet: "1547375393",
  549. toStreet: "1335391716",
  550. stateabbr: "1867193205",
  551. county: "1714138473",
  552. source: "1803937317",
  553. notes: "1648634142"
  554. }
  555. }, {
  556. //https://docs.google.com/forms/d/e/1FAIpQLSduBiLMhbg6nRpsEVCTcVbV4eWmHDXdIKGtuaOvzy6NZLbSgw/viewform?entry.1553765347=username&entry.1264424583=CLOSED&entry.1811077109=permalink&entry.792657790=Two-Way&entry.345142186=reason&entry.1102521735=2016-09-20+03:00&entry.2015424420=street+name&entry.1547375393=from+street&entry.1335391716=to+street&entry.1867193205=SC&entry.1714138473=county&entry.1803937317=source&entry.1648634142=notes
  557. name: "USA VEOC closures",
  558. url: "https://docs.google.com/forms/d/e/1FAIpQLSduBiLMhbg6nRpsEVCTcVbV4eWmHDXdIKGtuaOvzy6NZLbSgw/viewform",
  559. fields: {
  560. username: "1553765347",
  561. closureStatus: "1264424583",
  562. permalink: "1811077109",
  563. closedDir: "792657790",
  564. closedReason: "345142186",
  565. endDate: "1102521735",
  566. streetname: "2015424420",
  567. fromStreet: "1547375393",
  568. toStreet: "1335391716",
  569. stateabbr: "1867193205",
  570. county: "1714138473",
  571. source: "1803937317",
  572. notes: "1648634142"
  573. }
  574. }, {
  575. name: "US Jane TTS Pronunciation",
  576. url: "https://docs.google.com/forms/d/e/1FAIpQLSeuCmC0zy7GEQDJQP5R8dndxYhXCkqzadrPgP89BvatVl1bdg/viewform",
  577. fields: {
  578. username: "324217272",
  579. state: "1065619417",
  580. issue: "1086951221",
  581. streetname: "1163516948",
  582. incorrectp: "1191620241",
  583. correctp: "1649051316",
  584. permalink: "2028167849",
  585. instructions: "2120232339",
  586. comments: "1917392591"
  587. }
  588. }, {
  589. //https://docs.google.com/forms/d/e/1FAIpQLSff7nsBw8qxCojBdxrjTPl6tercqyyzGy92Vif_SBdHkYDchw/viewform?entry.1204781462=Reporter&entry.828228572=Reported&entry.1647952662=Street+name+&entry.1501712688=From+street+&entry.2094306654=To+street+&entry.1414240321=Two-Way&entry.900957975=10/27/2016+00:00&entry.1051351191=Adams&entry.1093044522=City+&entry.1540676081=IDOT&entry.430378754=Reason+&entry.1754051160=Permalink+&entry.172235277=Source+&entry.1722909714=Notes+
  590. name: "IL closures",
  591. url: "https://docs.google.com/forms/d/e/1FAIpQLSff7nsBw8qxCojBdxrjTPl6tercqyyzGy92Vif_SBdHkYDchw/viewform",
  592. fields: {
  593. username: "1204781462",
  594. closureStatus: "828228572",
  595. permalink: "1754051160",
  596. closedDir: "1414240321",
  597. closedReason: "430378754",
  598. endDate: "900957975",
  599. streetname: "1647952662",
  600. fromStreet: "1501712688",
  601. toStreet: "2094306654",
  602. county: "1051351191",
  603. city: "1093044522",
  604. source: "172235277",
  605. notes: "1722909714"
  606. }
  607. }, {
  608. //https://docs.google.com/forms/d/e/1FAIpQLSd8wouEY6DhA4ifMb_Ub0rEE7X4TCM7WIEqFiT4Lq1hySxEWw/viewform?entry.1553765347=username&entry.1264424583=CLOSED&entry.1811077109=permalink&entry.792657790=Two-Way&entry.345142186=reason&entry.1102521735=2016-09-20+03:00&entry.2015424420=street+name&entry.1547375393=from+street&entry.1335391716=to+street&entry.1867193205=OK&entry.1714138473=county&entry.1803937317=source&entry.1648634142=notes
  609. name: "OK closures",
  610. url: "https://docs.google.com/forms/d/e/1FAIpQLSd8wouEY6DhA4ifMb_Ub0rEE7X4TCM7WIEqFiT4Lq1hySxEWw/viewform",
  611. fields: {
  612. username: "1553765347",
  613. closureStatus: "1264424583",
  614. permalink: "1811077109",
  615. closedDir: "792657790",
  616. closedReason: "345142186",
  617. endDate: "1102521735",
  618. streetname: "2015424420",
  619. fromStreet: "1547375393",
  620. toStreet: "1335391716",
  621. stateabbr: "1867193205",
  622. county: "1714138473",
  623. source: "1803937317",
  624. notes: "1648634142"
  625. }
  626. }, {
  627. //https://docs.google.com/forms/d/e/1FAIpQLScwEyNVqiHHdFjc4hr82zlFXW2bAsff9pqIzFUqT8Evh6YROg/viewform?usp=pp_url&entry.1553765347=kwrigh01&entry.1264424583=CLOSED&entry.1811077109=https://www.waze.com/editor/?env%3Dusa%26lon%3D-79.99979%26lat%3D37.89567%26zoom%3D5%26segments%3D82457306,82457308,82457338&entry.792657790=Two-Way&entry.345142186=Bridge+Work&entry.1102521735=2018-07-01+23:59&entry.2015424420=Morris+Hollow+Rd&entry.1547375393=1st&entry.1335391716=2nd&entry.1867193205=VA&entry.1714138473=Alleghany&entry.1803937317=VDOT&entry.1648634142=Test+Closure
  628. name: "VA Closures",
  629. url: "https://docs.google.com/forms/d/e/1FAIpQLScwEyNVqiHHdFjc4hr82zlFXW2bAsff9pqIzFUqT8Evh6YROg/viewform",
  630. fields: {
  631. username: "1553765347",
  632. closureStatus: "1264424583",
  633. permalink: "1811077109",
  634. closedDir: "792657790",
  635. closedReason: "345142186",
  636. endDate: "1102521735",
  637. streetname: "2015424420",
  638. fromStreet: "1547375393",
  639. toStreet: "1335391716",
  640. stateabbr: "1867193205",
  641. county: "1714138473",
  642. source: "1803937317",
  643. notes: "1648634142"
  644. }
  645. }, {
  646. //https://docs.google.com/forms/d/e/1FAIpQLSeiKY0KsO0xN69Asw77MARQFmxOy6zQXF-k2OQdWOfwtiCp7Q/viewform?entry.1204781462=ojlaw&entry.828228572=CLOSED&entry.1647952662=Test1&entry.1501712688=Test2&entry.2094306654=Test3&entry.1414240321=One-Way&entry.900957975=00/00/0000+00:00&entry.1051351191=Adams&entry.1093044522=Test4&entry.1540676081=City&entry.430378754=Test5&entry.1754051160=Test6&entry.172235277=Test7&entry.1722909714=Test8
  647. name: "WI closures",
  648. url: "https://docs.google.com/forms/d/e/1FAIpQLSeiKY0KsO0xN69Asw77MARQFmxOy6zQXF-k2OQdWOfwtiCp7Q/viewform",
  649. fields: {
  650. username: "1204781462",
  651. closureStatus: "828228572",
  652. permalink: "1754051160",
  653. closedDir: "1414240321",
  654. closedReason: "430378754",
  655. endDate: "900957975",
  656. streetname: "1647952662",
  657. fromStreet: "1501712688",
  658. toStreet: "2094306654",
  659. county: "1051351191",
  660. city: "1093044522",
  661. source: "172235277",
  662. notes: "1722909714"
  663. }
  664. }, {
  665. //https://docs.google.com/forms/d/e/1FAIpQLSd2Stl1DabZRVZ315HT6kdF78e9ysqjItR09pYtE7WiKmPotg/viewform?usp=pp_url&entry.1677745178=user&entry.1292331655=CLOSED&entry.408708691=http://waze.com&entry.52585226=Two-Way&entry.1079033335=reason&entry.1176076628=2020-05-05+05:00&entry.223275032=street&entry.1159260930=from&entry.1582819664=to&entry.2135402288=Monongalia&entry.858860694=source&entry.1440969572=notes
  666. name: "WV Closures",
  667. url: "https://docs.google.com/forms/d/e/1FAIpQLSd2Stl1DabZRVZ315HT6kdF78e9ysqjItR09pYtE7WiKmPotg/viewform",
  668. fields: {
  669. username: "1677745178",
  670. closureStatus: "1292331655",
  671. permalink: "408708691",
  672. closedDir: "52585226",
  673. closedReason: "1079033335",
  674. endDate: "1176076628",
  675. streetname: "223275032",
  676. fromStreet: "1159260930",
  677. toStreet: "1582819664",
  678. county: "2135402288",
  679. source: "858860694",
  680. notes: "1440969572"
  681. }
  682. }
  683. ];
  684.  
  685. forms.forEach(function (key, i) {
  686. ffMnu.options.add(new Option(forms[i].name, i));
  687. });
  688. const lastIndex = localStorage.getItem("ff-last-form-index");
  689. if (lastIndex > -1 && lastIndex < forms.length) {
  690. ffMnu.value = lastIndex;
  691. }
  692. $(ffMnu).change(() => { localStorage.setItem("ff-last-form-index", ffMnu.value); });
  693. ffBtn.innerHTML = "Go to Form";
  694. ffBtn.onclick = function () {
  695. //alert(ffMnu.options[ffMnu.selectedIndex].value+": "+forms[ffMnu.options[ffMnu.selectedIndex].value].name);
  696. ff_saveSettings();
  697. formLink = ff_createFormLink(forms[ffMnu.options[ffMnu.selectedIndex].value]);
  698. if (typeof formLink === "undefined") {
  699. return;
  700. }
  701.  
  702. if ($("#ff-open-in-tab").prop("checked")) {
  703. window.open(formLink, "_blank");
  704. } else {
  705. window.open(formLink, formWindowName, formWindowSpecs);
  706. }
  707. };
  708. ffDiv.appendChild(ffMnu);
  709. ffDiv.appendChild(ffBtn);
  710. $('div.segment-edit-section').prepend(ffDiv);
  711. return;
  712. }
  713.  
  714. function ff_loadSettings() {
  715. var todayDate = new Date(),
  716. futureDate = new Date(),
  717. daysInFuture = 3;
  718. var today = todayDate.getFullYear() + "-" + (todayDate.getMonth() + 1 < 10 ? "0" + (todayDate.getMonth() + 1) : todayDate.getMonth() + 1) + "-" + todayDate.getDate();
  719. futureDate.setDate(futureDate.getDate() + daysInFuture);
  720.  
  721. var ffOpenInTab = localStorage.getItem("ff-open-in-tab");
  722. if (ffOpenInTab === "1") {
  723. $("#ff-open-in-tab").trigger("click");
  724. }
  725. var ffClosureReason = localStorage.getItem("ff-closure-reason");
  726. if (ffClosureReason !== null) {
  727. $("#ff-closure-reason").val(ffClosureReason);
  728. }
  729. var ffClosureEndDate = localStorage.getItem("ff-closure-endDate");
  730. if (ffClosureEndDate !== null && ffClosureEndDate !== "" && ffClosureEndDate >= today) {
  731. $("#ff-closure-endDate").val(ffClosureEndDate);
  732. } else {
  733. var closureDate = futureDate.getFullYear() + "-" + (futureDate.getMonth() + 1 < 10 ? "0" + (futureDate.getMonth() + 1) : futureDate.getMonth() + 1) + "-" + (futureDate.getDate() < 10 ? "0" + futureDate.getDate() : futureDate.getDate());
  734. $("#ff-closure-endDate").val(closureDate);
  735. }
  736. var ffClosureEndTime = localStorage.getItem("ff-closure-endTime");
  737. if (ffClosureEndTime !== null && ffClosureEndTime !== "") {
  738. $("#ff-closure-endTime").val(ffClosureEndTime);
  739. }
  740. //formfiller_log("Settings loaded");
  741. return;
  742. }
  743.  
  744. function ff_saveSettings() {
  745. if ($("#ff-open-in-tab").prop("checked")) {
  746. localStorage.setItem("ff-open-in-tab", "1");
  747. } else {
  748. localStorage.setItem("ff-open-in-tab", "0");
  749. }
  750. localStorage.setItem("ff-closure-reason", $("#ff-closure-reason").val());
  751. localStorage.setItem("ff-closure-endDate", $("#ff-closure-endDate").val());
  752. localStorage.setItem("ff-closure-endTime", $("#ff-closure-endTime").val());
  753. //formfiller_log("Settings saved");
  754. return;
  755. }
  756.  
  757. function ff_addUserTab() {
  758. var userInfo = document.getElementById("user-info"),
  759. userTabs = document.getElementById("user-tabs"),
  760. navTabs = userTabs.getElementsByClassName("nav-tabs"),
  761. tabContent = userInfo.getElementsByClassName("tab-content");
  762. var ffTab = document.createElement("li"),
  763. ffPanel = document.createElement("div"),
  764. ffReason = document.createElement("div"),
  765. ffEndDate = document.createElement("div"),
  766. ffNewTabBox = document.createElement("input"),
  767. ffNewTabLabel = document.createElement("label"),
  768. ffTabInfo = document.createElement("div");
  769.  
  770. ffTab.innerHTML = '<a title="Form Filler" href="#sidepanel-formfill" data-toggle="tab"><img class="fa" src="' + WMEFFIcon + '" width="15px" /></a>';
  771. ffPanel.id = "sidepanel-formfill";
  772. ffPanel.className = "tab-pane";
  773.  
  774. ffTabInfo.innerHTML = '<b>' + WMEFFName + '</b> v' + WMEFFVersion;
  775.  
  776. ffNewTabBox.id = "ff-open-in-tab";
  777. ffNewTabBox.type = "checkbox";
  778. ffNewTabBox.name = "ff_open_tab";
  779.  
  780. ffNewTabLabel.innerHTML = "Open form in new tab";
  781. ffNewTabLabel.for = "ff_open_tab";
  782.  
  783. ffReason.className = "form-group";
  784. ffReason.innerHTML = '<label class="control-label" for="ff_closure_reason">Closures reason:</label><div class="controls"><input id="ff-closure-reason" class="form-control" type="text" name="ff_closure_reason"></div>';
  785.  
  786. ffEndDate.className = "form-group";
  787. ffEndDate.innerHTML = '<label class="control-label" for="ff_closure_endDate">Closures end:</label><div class="controls"><div class="date date-input-group input-group pull-left" style="width: 62%"><input id="ff-closure-endDate" class="form-control end-date" type="text" name="ff_closure_endDate"><span class="input-group-addon"><i class="fa fa-calendar"></i></span></div><div class="bootstrap-timepicker input-group style="width: 38%""><input id="ff-closure-endTime" class="end-time form-control" type="text" name="ff_closure_endTime"><span class="input-group-addon"><i class="fa fa-clock-o"></i></span></div></div>';
  788.  
  789. ffPanel.appendChild(ffTabInfo);
  790. ffPanel.appendChild(ffNewTabBox);
  791. ffPanel.appendChild(ffNewTabLabel);
  792. ffPanel.appendChild(ffReason);
  793. ffPanel.appendChild(ffEndDate);
  794. navTabs[0].appendChild(ffTab);
  795. tabContent[0].appendChild(ffPanel);
  796.  
  797. if (typeof $.fn.datepicker !== "undefined") {
  798. $("#ff-closure-endDate").datepicker({
  799. format: "yyyy-mm-dd",
  800. todayHighlight: true,
  801. autoclose: true
  802. });
  803. } else {
  804. if (typeof $.fn.daterangepicker !== "undefined") {
  805. $("#ff-closure-endDate").daterangepicker({
  806. singleDatePicker: true,
  807. locale: {
  808. format: "YYYY-MM-DD"
  809. }
  810. });
  811. }
  812. }
  813.  
  814. if (typeof $.fn.timepicker !== "undefined") {
  815. $("#ff-closure-endTime").timepicker({
  816. template: false,
  817. defaultTime: "00:00",
  818. showMeridian: false
  819. });
  820. }
  821.  
  822. ff_loadSettings();
  823. $("#ff-closure-reason").change(function () {
  824. ff_saveSettings();
  825. });
  826. $("#ff-closure-endDate").change(function () {
  827. ff_saveSettings();
  828. });
  829. $("#ff-closure-endTime").change(function () {
  830. ff_saveSettings();
  831. });
  832. $("#ff-open-in-tab").click(function () {
  833. ff_saveSettings();
  834. });
  835. }
  836.  
  837. setTimeout(formfiller_bootstrap, 2000);
  838. }());