WME Advanced Closures

Recurrent and imported closures in the Waze Map Editor

目前为 2016-10-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name WME Advanced Closures
  3. // @version 1.4
  4. // @description Recurrent and imported closures in the Waze Map Editor
  5. // @namespace WMEAC
  6. // @include https://www.waze.com/editor/*
  7. // @include https://www.waze.com/*/editor/*
  8. // @include https://beta.waze.com/*
  9. // @exclude https://www.waze.com/user/*
  10. // @exclude https://www.waze.com/*/user/*
  11. // @icon data:image/png;base64,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
  12. // @grant unsafeWindow
  13. // @grant GM_xmlhttpRequest
  14. // @connect holidayapi.com
  15. // @copyright 2016, dummyd2, seb-d59
  16. // @author dummyd2, seb-d59
  17. // ==/UserScript==
  18.  
  19.  
  20. /*******
  21. *
  22. * You are free to:
  23. * Share, copy, and redistribute the script in any medium or format
  24. * under the following terms:
  25. * Attribution - You must give appropriate credit. You may do so in any
  26. * reasonable manner, but not in any way that suggests the licensor
  27. * endorses you or your use.
  28. *
  29. * NonCommercial - You may not use the script for commercial purposes.
  30. *
  31. * NoModifications - You may NOT MODIFY the script.
  32. *
  33. * You are invited to contact authors on waze forum for more details.
  34. *
  35. ********/
  36.  
  37. /*jshint multistr: true */
  38.  
  39. function WMEAC_downloadHelperInjected() {
  40. window.WMEAC_downloadHelper = {jobs:[], _waitForData:function(id) {
  41. if (this.jobs.length <= id) {
  42. this.jobs[id].callback({url:null, data:null, callback:this.jobs[id].callback, status:"error", error:"Request not found"});
  43. } else {
  44. if (this.jobs[id].status == "success" || this.jobs[id].status == "error") {
  45. this.jobs[id].callback(this.jobs[id]);
  46. } else {
  47. if (this.jobs[id].status == "downloading" && this.jobs[id].progressCallback) {
  48. this.jobs[id].progressCallback(this.jobs[id]);
  49. }
  50. var _this = this;
  51. window.setTimeout(function() {
  52. _this._waitForData(id);
  53. }, 500);
  54. }
  55. }
  56. }, add:function(url, callback, progressCallback) {
  57. this.jobs.push({url:url, data:null, callback:callback, progressCallback:progressCallback, status:"added", progression:0, error:""});
  58. var _this = this;
  59. window.setTimeout(function() {
  60. _this._waitForData(_this.jobs.length - 1);
  61. }, 500);
  62. }};
  63. }
  64. var WMEAC_downloadHelperInjectedScript = document.createElement("script");
  65. WMEAC_downloadHelperInjectedScript.textContent = "" + WMEAC_downloadHelperInjected.toString() + " \n" + "WMEAC_downloadHelperInjected();";
  66. WMEAC_downloadHelperInjectedScript.setAttribute("type", "application/javascript");
  67. document.body.appendChild(WMEAC_downloadHelperInjectedScript);
  68. function lookFordownloadHelperJob() {
  69. for (var i = 0;i < unsafeWindow.WMEAC_downloadHelper.jobs.length;i++) {
  70. if (unsafeWindow.WMEAC_downloadHelper.jobs[i].status == "added") {
  71. unsafeWindow.WMEAC_downloadHelper.jobs[i].status = cloneInto("downloading", unsafeWindow.WMEAC_downloadHelper.jobs[i]);
  72. var f = function() {
  73. var job = i;
  74. GM_xmlhttpRequest({method:"GET", headers:{"User-Agent":"Mozilla/5.0", "Accept":"text/plain"}, synchronous:false, timeout:1E4, url:unsafeWindow.WMEAC_downloadHelper.jobs[job].url, onerror:function(r) {
  75. unsafeWindow.WMEAC_downloadHelper.jobs[job].status = cloneInto("error", unsafeWindow.WMEAC_downloadHelper.jobs[job]);
  76. }, ontimeout:function(r) {
  77. console.debug("TOTO Timeout while getting area from server: ", r);
  78. unsafeWindow.WMEAC_downloadHelper.jobs[job].status = cloneInto("error", unsafeWindow.WMEAC_downloadHelper.jobs[job]);
  79. }, onload:function(r) {
  80. unsafeWindow.WMEAC_downloadHelper.jobs[job].status = cloneInto("success", unsafeWindow.WMEAC_downloadHelper.jobs[job]);
  81. unsafeWindow.WMEAC_downloadHelper.jobs[job].data = cloneInto(r.responseText, unsafeWindow.WMEAC_downloadHelper.jobs[job]);
  82. }, onprogress:function(r) {
  83. unsafeWindow.WMEAC_downloadHelper.jobs[job].progression = cloneInto(r.total == 0 ? 0 : r.loaded / r.total, unsafeWindow.WMEAC_downloadHelper.jobs[job]);
  84. }});
  85. }();
  86. }
  87. }
  88. window.setTimeout(lookFordownloadHelperJob, 2E3);
  89. }
  90. window.setTimeout(lookFordownloadHelperJob);
  91. function WMEAC_Injected() {
  92. var WMEAC = {};
  93. WMEAC.isDebug = false;
  94. WMEAC.ac_version = "1.4";
  95. WMEAC.closureTabTimeout = null;
  96. WMEAC.csv = [];
  97. WMEAC.csvCurrentClosureList = null;
  98. WMEAC.csvCurrentBatchClosureList = null;
  99. WMEAC.pendingOps = false;
  100. WMEAC.pb = null;
  101. WMEAC.daysOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
  102. WMEAC.lastGeneratedHolidays = [];
  103. WMEAC.presets = [];
  104. WMEAC.getElementsByClassName = function(classname, node) {
  105. if (!node) {
  106. node = document.getElementsByTagName("body")[0];
  107. }
  108. var a = [];
  109. var re = new RegExp("\\b" + classname + "\\b");
  110. var els = node.getElementsByTagName("*");
  111. for (var i = 0, j = els.length;i < j;i++) {
  112. if (re.test(els[i].className)) {
  113. a.push(els[i]);
  114. }
  115. }
  116. return a;
  117. };
  118. WMEAC.removeChildElements = function(node) {
  119. while (node.firstChild) {
  120. WMEAC.removeChildElements(node.firstChild);
  121. node.removeChild(node.firstChild);
  122. }
  123. };
  124. WMEAC.createElement = function(options) {
  125. if (options.hasOwnProperty("type") == false) {
  126. return null;
  127. }
  128. var el = document.createElement(options.type);
  129. if (options.hasOwnProperty("id") == true) {
  130. el.id = options.id;
  131. }
  132. if (options.hasOwnProperty("className") == true) {
  133. el.className = options.className;
  134. }
  135. return el;
  136. };
  137. WMEAC.getId = function(node) {
  138. var el = document.getElementById(node);
  139. return el;
  140. };
  141. WMEAC.logBeta = function(msg, obj) {
  142. };
  143. WMEAC.logDebug = function(msg, obj) {
  144. if (WMEAC.isDebug) {
  145. WMEAC.log("DEBUG - " + msg, obj);
  146. }
  147. };
  148. WMEAC.logError = function(msg, obj) {
  149. console.error("Advanced closures v" + WMEAC.ac_version + " - " + msg, obj);
  150. };
  151. WMEAC.log = function(msg, obj) {
  152. if (obj == null) {
  153. console.log("Advanced closures v" + WMEAC.ac_version + " - " + msg);
  154. } else {
  155. console.debug("Advanced closures v" + WMEAC.ac_version + " - " + msg + " ", obj);
  156. }
  157. };
  158. WMEAC.isValidDate = function(d) {
  159. if (Object.prototype.toString.call(d) === "[object Date]") {
  160. if (isNaN(d.getTime())) {
  161. return false;
  162. } else {
  163. return true;
  164. }
  165. } else {
  166. return false;
  167. }
  168. };
  169. WMEAC.dateToClosureStr = function(d) {
  170. var yyyy = d.getUTCFullYear().toString();
  171. var MM = (d.getUTCMonth() + 1).toString();
  172. var dd = d.getUTCDate().toString();
  173. var hh = d.getUTCHours().toString();
  174. var mm = d.getUTCMinutes().toString();
  175. return yyyy + "-" + (MM[1] ? MM : "0" + MM[0]) + "-" + (dd[1] ? dd : "0" + dd[0]) + " " + (hh[1] ? hh : "0" + hh[0]) + ":" + (mm[1] ? mm : "0" + mm[0]);
  176. };
  177. WMEAC.CSVtoArray = function(text) {
  178. var b = [];
  179. var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
  180. var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
  181. var lines = text.split("\n");
  182. lines.forEach(function(line) {
  183. if (!re_valid.test(line)) {
  184. return;
  185. }
  186. var a = [];
  187. line.replace(re_value, function(m0, m1, m2, m3) {
  188. if (m1 !== undefined) {
  189. a.push(m1.replace(/\\'/g, "'"));
  190. } else {
  191. if (m2 !== undefined) {
  192. a.push(m2.replace(/\\"/g, '"'));
  193. } else {
  194. if (m3 !== undefined) {
  195. a.push(m3);
  196. }
  197. }
  198. }
  199. return "";
  200. });
  201. if (/,\s*$/.test(line)) {
  202. a.push("");
  203. }
  204. b.push(a);
  205. });
  206. return b;
  207. };
  208. WMEAC.segmentsIDsToSegments = function(ids) {
  209. return ids.filter(function(e) {
  210. return Waze.model.segments.objects.hasOwnProperty(e);
  211. }).map(function(e) {
  212. return Waze.model.segments.objects[e];
  213. });
  214. };
  215. WMEAC.reloadRoadLayer = function() {
  216. var l = Waze.map.getLayersBy("uniqueName", "roads")[0];
  217. l.redraw({force:!0});
  218. l.removeBackBuffer();
  219. Waze.controller.reload();
  220. };
  221. WMEAC.reloadClosuresLayer = function(endHandler) {
  222. var l = Waze.map.getLayersBy("uniqueName", "closures")[0];
  223. l.redraw({force:!0});
  224. Waze.controller.reload();
  225. if (endHandler) {
  226. var tmp = function reloaded() {
  227. WMEAC.log("Test if reloaded...");
  228. if (WMEAC.pendingOps == true) {
  229. WMEAC.log("Not yet. Waiting for WME...");
  230. window.setTimeout(reloaded, 500);
  231. } else {
  232. endHandler();
  233. }
  234. };
  235. window.setTimeout(tmp, 500);
  236. }
  237. };
  238. WMEAC.showClosuresLayer = function(show) {
  239. var l = Waze.map.getLayersBy("uniqueName", "closures");
  240. if (l.length == 1) {
  241. l[0].setVisibility(show);
  242. }
  243. };
  244. WMEAC.setDraggable = function(element, options) {
  245. if (!options.hasOwnProperty("controller")) {
  246. options.controller = element;
  247. }
  248. if (!options.hasOwnProperty("container")) {
  249. options.container = $("body");
  250. }
  251. options.controller.css({cursor:"move"});
  252. options.controller.on("mousedown", function(e) {
  253. var x = e.pageX - element.offset().left;
  254. var y = e.pageY - element.offset().top;
  255. $("body").on("mouseup", function(e) {
  256. options.container.off("mousemove", elemmousemove);
  257. });
  258. function elemmousemove(e) {
  259. e.preventDefault();
  260. element.offset({top:e.pageY - y, left:e.pageX - x});
  261. }
  262. options.container.on("mousemove", elemmousemove);
  263. });
  264. };
  265. WMEAC.dateTimeOverlaps = function(dt1, dt2) {
  266. return dt1.startDate < dt2.endDate && dt1.endDate > dt2.startDate;
  267. };
  268. WMEAC.solveOverlaps = function(closureToAdd, existingClosureList, mode) {
  269. var ecs = existingClosureList.map(function(e) {
  270. return {isNew:false, ref:e, startDate:e.startDate, endDate:e.endDate};
  271. });
  272. closureToAdd.isNew = true;
  273. ecs.push(closureToAdd);
  274. var changes = true;
  275. while (changes) {
  276. changes = false;
  277. ecs.sort(function(a, b) {
  278. return new Date(a.startDate) - new Date(b.startDate);
  279. });
  280. for (var i = 1;i < ecs.length;i++) {
  281. if (WMEAC.dateTimeOverlaps(ecs[i - 1], ecs[i])) {
  282. var indexOfNew = i - 1;
  283. var indexOfExisting = i;
  284. if (ecs[i].isNew) {
  285. indexOfNew = i;
  286. indexOfExisting = i - 1;
  287. }
  288. var r1 = ecs[indexOfNew];
  289. var r2 = ecs[indexOfExisting];
  290. var range1 = {};
  291. var range2 = {};
  292. switch(mode) {
  293. case 0:
  294. return [];
  295. break;
  296. case 1:
  297. ecs.splice(indexOfExisting, 1);
  298. changes = true;
  299. break;
  300. case 2:
  301. range1.start = new Date(r1.startDate);
  302. range1.end = new Date(r1.endDate);
  303. range2.start = new Date(r2.startDate);
  304. range2.end = new Date(r2.endDate);
  305. changes = true;
  306. if (range1.start >= range2.start && range1.end <= range2.end) {
  307. ecs.splice(indexOfNew, 1);
  308. } else {
  309. if (range1.start < range2.start && range1.end > range2.end) {
  310. ecs.push({isNew:true, startDate:r2.endDate, endDate:r1.endDate});
  311. r1.endDate = r2.startDate;
  312. } else {
  313. if (range1.start < range2.start) {
  314. r1.endDate = r2.startDate;
  315. } else {
  316. r1.startDate = r2.endDate;
  317. }
  318. }
  319. }
  320. break;
  321. case 3:
  322. range1.start = new Date(r1.startDate);
  323. range1.end = new Date(r1.endDate);
  324. range2.start = new Date(r2.startDate);
  325. range2.end = new Date(r2.endDate);
  326. changes = true;
  327. if (range1.start > range2.start && range1.end < range2.end) {
  328. ecs.push({isNew:false, startDate:r1.endDate, endDate:r2.endDate, ref:r2.ref});
  329. r2.endDate = r1.startDate;
  330. } else {
  331. if (range1.start <= range2.start && range1.end >= range2.end) {
  332. ecs.splice(indexOfExisting, 1);
  333. } else {
  334. if (range1.start < range2.start) {
  335. r2.startDate = r1.endDate;
  336. } else {
  337. r2.endDate = r1.startDate;
  338. }
  339. }
  340. }
  341. break;
  342. }
  343. }
  344. }
  345. }
  346. return ecs;
  347. };
  348. WMEAC.getCountriesFromSegmentSet = function(segs) {
  349. var cids = segs.map(function(s) {
  350. if (s.attributes.hasOwnProperty("primaryStreetID") && s.attributes.primaryStreetID != null) {
  351. var stid = s.attributes.primaryStreetID;
  352. if (Waze.model.streets.objects.hasOwnProperty(stid)) {
  353. var st = Waze.model.streets.objects[stid];
  354. if (st.hasOwnProperty("cityID") && st.cityID != null && typeof st.cityID != "undefined") {
  355. var ctid = st.cityID;
  356. if (Waze.model.cities.objects.hasOwnProperty(ctid)) {
  357. return Waze.model.cities.objects[ctid].countryID;
  358. }
  359. }
  360. }
  361. }
  362. return null;
  363. }).filter(function(cid) {
  364. return cid != null;
  365. });
  366. return Waze.model.countries.getObjectArray(function(c) {
  367. return cids.indexOf(c.id) != -1;
  368. });
  369. };
  370. WMEAC.getOppositeClosure = function(closure) {
  371. return Waze.model.roadClosures.getObjectArray(function(c) {
  372. return closure.reason == c.reason && closure.startDate == c.startDate && closure.endDate == c.endDate && closure.segID == c.segID && closure.forward != c.forward;
  373. });
  374. };
  375. WMEAC.getCityStreetsFromSegmentSet = function(segs) {
  376. var r = {};
  377. function add(city, street) {
  378. if (!r.hasOwnProperty(city)) {
  379. r[city] = {};
  380. }
  381. if (!r[city].hasOwnProperty(street)) {
  382. r[city][street] = 0;
  383. }
  384. r[city][street]++;
  385. }
  386. segs.forEach(function(s) {
  387. var city = "noCity";
  388. if (s.attributes.primaryStreetID != null && Waze.model.streets.objects.hasOwnProperty(s.attributes.primaryStreetID)) {
  389. var st = Waze.model.streets.objects[s.attributes.primaryStreetID];
  390. if (st.hasOwnProperty("cityID") && st.cityID != null && typeof st.cityID != "undefined") {
  391. var ctid = st.cityID;
  392. if (Waze.model.cities.objects.hasOwnProperty(ctid)) {
  393. if (!Waze.model.cities.objects[ctid].isEmpty) {
  394. city = Waze.model.cities.objects[ctid].name;
  395. }
  396. }
  397. }
  398. if (Waze.model.streets.objects[s.attributes.primaryStreetID].isEmpty) {
  399. add(city, "noStreet");
  400. } else {
  401. add(city, Waze.model.streets.objects[s.attributes.primaryStreetID].name);
  402. }
  403. }
  404. });
  405. return r;
  406. };
  407. WMEAC.download = function(data, filename) {
  408. var element = document.createElement("a");
  409. element.style.display = "none";
  410. element.setAttribute("href", encodeURI("data:text/plain," + data));
  411. element.setAttribute("download", filename);
  412. document.body.appendChild(element);
  413. element.click();
  414. document.body.removeChild(element);
  415. };
  416. var cssElt = WMEAC.createElement({type:"style"});
  417. cssElt.type = "text/css";
  418. var css = "";
  419. css += ".slashed:after { content: ''; position: relative; width: 140%; height: 1px; display: block; background: red; transform: rotate(-30deg); margin-top: -50%; margin-left: -20%; }";
  420. css += ".wmeac-sidepanel button { border: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; background-color: #F1DDDB }";
  421. css += "#wmeac-progressBarInfo { display: none; width: 90%; float: left; position: absolute; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; margin-bottom: -100%; background-color: #c9e1e9; z-index: 999; margin: 5px; margin-right: 20px; }";
  422. css += ".wmeac-progressBarBG { margin-top: 2px; margin-bottom: 2px; margin-left: 2px; margin-right: 2px; padding-bottom: 0px; padding-top: 0px; padding-left: 0px; padding-right: 0px; width: 33%; background-color: #93c4d3; border: 3px rgb(147, 196, 211); border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; height: 22px;}";
  423. css += ".wmeac-progressBarFG { float: left; position: relative; bottom: 22px; height: 0px; text-align: center; width: 100% }";
  424. css += ".wmeac-button { border: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; background-color: #F1DDDB; display: inline-block; padding: 6px 12px; cursor: pointer; text-align: center; font-weight: bold; }";
  425. css += ".wmeac-closuredialog { border: 2px solid #F1DDDB; width: 100%; float: left; display: none; position: absolute; padding: 0 0px; border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; border-top-left-radius: 10px; border-top-right-radius: 10px; background-color: #FDEDEB; width: 500px; z-index: 9999; left: 80px; top: 10px;}";
  426. css += ".wmeac-closuredialog button { border: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; background-color: #F1DDDB; margin: 3px; }";
  427. css += ".wmeac-closuredialog h1 { background-color: #F1DDDB; text-align: center; font-size: medium; margin-top: 0px; padding: 10px;}";
  428. css += ".wmeac-closuredialog .content { padding: 10px;}";
  429. css += ".wmeac-closuredialog .content table { witdh: 100%; border: none; font-size: 10px; text-transform: uppercase;}";
  430. css += ".wmeac-closuredialog .content table tbody tr { vertical-align: top;}";
  431. css += ".wmeac-closuredialog .content table tbody tr td { padding-right: 2px; padding-left: 2px;}";
  432. css += ".wmeac-closuredialog-fromgroup { display: inline-block; }";
  433. css += ".wmeac-nav-tabs>ul { border-bottom: 1px solid #F6C3BE }";
  434. css += ".wmeac-nav-tabs>li { float: left; margin-bottom: -1px; }";
  435. css += ".wmeac-nav-tabs>li>a { border: 1px solid #F6C3BE; border-top-left-radius: 5px; border-top-right-radius: 5px; margin-right: 2px;}";
  436. css += ".wmeac-nav-tabs>li.active>a { background-color: rgba(0, 0, 0, 0); border-bottom: 1px solid #FDEDEB}";
  437. css += ".wmeac-nav-tabs>li:not(.active)>a { background-color: #DADBDC}";
  438. css += ".wmeac-tab-pane {border: 1px solid #F6C3BE; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 0px; border-top-right-radius: 0px; padding: 5px;}";
  439. css += ".wmeac-closuredialog .footer { height: 40px; padding: 0 10px;}";
  440. css += "#wmeac-csv-closures-list ul { list-style-type: none; padding: 0px;}";
  441. css += "#wmeac-csv-closures-list ul li { width: 100%; height: 42px; border-radius: 4px; margin-top: 1px; }";
  442. css += "#wmeac-csv-closures-list ul li > * { display: table-cell; vertical-align: middle;}";
  443. css += ".wmeac-csv-closures-list-add { background-color: #C6DFFF; }";
  444. css += ".wmeac-csv-closures-list-remove { background-color: #FFC65F; }";
  445. css += ".wmeac-csv-closures-list-failed { background-color: #FF8585; }";
  446. css += ".wmeac-csv-closures-list-done { background-color: #B9FAB1; }";
  447. css += ".wmeac-csv-closures-list-col-action { width: 14px; min-width: 14px; }";
  448. css += ".wmeac-csv-closures-list-col-lr { font-size: xx-small; width: 100%; }";
  449. css += ".wmeac-csv-closures-list-col-lr > * { height: 14px; overflow-y: hidden; vertical-align: middle; }";
  450. css += ".wmeac-csv-closures-list-col-dates { width: 75px; min-width: 75px; font-size: xx-small; text-align: center; }";
  451. css += ".wmeac-csv-closures-list-col-dates > * { height: 14px; overflow-y: hidden; vertical-align: center; }";
  452. css += ".wmeac-csv-closures-list-col-dir { width: 35px; min-width: 35px; text-align: center; }";
  453. css += ".wmeac-csv-closures-list-col-it { width: 15px; min-width: 15px; }";
  454. css += ".wmeac-csv-closures-list-col-target { width: 15px; min-width: 15px; }";
  455. css += ".wmeac-csv-closures-list-col-apply { width: 15px; min-width: 15px; }";
  456. css += ".wmeac-csv-closures-minilog { font-size: xx-small; font-family: monospace; border: 2px solid #F6C3BE; border-top: none; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: #FFFFFF; }";
  457. css += "#wmeac-csv-closures-log { font-size: xx-small; font-family: monospace; border: 2px solid #F6C3BE; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; padding-top: 8px; position: relative; margin-top: 10px; }";
  458. css += '#wmeac-csv-closures-log:before { content: "Logs"; position: absolute; top: -8px; left: 5px; float: left; background: #F6C3BE; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; padding: 2px; }';
  459. css += "#wmeac-csv-closures-preview { font-size: small; white-space: nowrap; font-family: monospace; border: 2px solid #F6C3BE; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; padding-top: 8px; position: relative; min-height: 20px; }";
  460. css += '#wmeac-csv-closures-preview:before { content: "Preview"; position: absolute; top: -8px; left: 5px; float: left; background: #F6C3BE; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; padding: 2px; }';
  461. css += '.wmeac-hl:after { content: "\\f018"; position: relative; display: block; margin-top: -100%; margin-left: 50%; font-family: FontAwesome; }';
  462. cssElt.innerHTML = css;
  463. document.body.appendChild(cssElt);
  464. WMEAC.bootstrapAC = function() {
  465. window.setTimeout(WMEAC.initialize, 500);
  466. };
  467. WMEAC.initialize = function() {
  468. WMEAC.log("init");
  469. WMEAC.waitForWaze(function() {
  470. WMEAC.load();
  471. WMEAC.log("presets", WMEAC.presets);
  472. WMEAC.initUI();
  473. });
  474. WMEAC.log("init done");
  475. };
  476. WMEAC.waitForWaze = function(handler) {
  477. var APIRequired = [{o:"Waze"}, {o:"Waze.model"}, {o:"Waze.map"}, {o:"Waze.loginManager"}];
  478. for (var i = 0;i < APIRequired.length;i++) {
  479. var path = APIRequired[i].o.split(".");
  480. var object = window;
  481. for (var j = 0;j < path.length;j++) {
  482. object = object[path[j]];
  483. if (typeof object == "undefined" || object == null) {
  484. window.setTimeout(function() {
  485. WMEAC.waitForWaze(handler);
  486. }, 500);
  487. return;
  488. }
  489. }
  490. }
  491. var userInfo = WMEAC.getId("user-info");
  492. if (userInfo == null) {
  493. window.setTimeout(function() {
  494. WMEAC.waitForWaze(handler);
  495. }, 500);
  496. return;
  497. }
  498. var navTabs = userInfo.getElementsByTagName("ul");
  499. if (navTabs.length == 0) {
  500. window.setTimeout(function() {
  501. WMEAC.waitForWaze(handler);
  502. }, 500);
  503. return;
  504. }
  505. if (typeof navTabs[0] == "undefined") {
  506. window.setTimeout(function() {
  507. WMEAC.waitForWaze(handler);
  508. }, 500);
  509. return;
  510. }
  511. var tabContents = userInfo.getElementsByTagName("div");
  512. if (tabContents.length == 0) {
  513. window.setTimeout(function() {
  514. WMEAC.waitForWaze(handler);
  515. }, 500);
  516. return;
  517. }
  518. if (typeof tabContents[0] == "undefined") {
  519. window.setTimeout(function() {
  520. WMEAC.waitForWaze(handler);
  521. }, 500);
  522. return;
  523. }
  524. handler();
  525. };
  526. WMEAC.initUI = function() {
  527. var addon = WMEAC.createElement({type:"section", id:"wmeac-addon"});
  528. WMEAC.pb = new WMEAC.ProgressBar("wmeac-progressBarInfo");
  529. addon.appendChild(WMEAC.pb.divpbi);
  530. var section = WMEAC.createElement({type:"p", id:"wmeac-main-title"});
  531. section.style.paddingTop = "0px";
  532. section.style.marginTop = "-15px";
  533. section.style.textIndent = "8px";
  534. var title = '<b><a target="_blank" href="https://greasyfork.org/scripts/20705-wme-advanced-closures"><u>Advanced Closures</u></a> <a target="_blank" href="https://www.waze.com/forum/viewtopic.php?f=1316&t=193462">Fr</a> <a target="_blank" href="https://www.waze.com/forum/viewtopic.php?f=819&t=193465">En</a> </b> v' + WMEAC.ac_version;
  535. section.innerHTML = title;
  536. addon.appendChild(section);
  537. var divAdvCl = WMEAC.createElement({type:"div", className:"wmeac-sidepanel", id:"wmeac-ac"});
  538. var addACBtn = WMEAC.createElement({type:"div", id:"wmeac-add-advanced-closure-button", className:"wmeac-button"});
  539. addACBtn.style.width = "100%";
  540. addACBtn.innerHTML = '<i class="fa fa-clock-o"></i> Add advanced closure';
  541. addACBtn.addEventListener("click", WMEAC.showAddAdvancedClosure);
  542. divAdvCl.appendChild(addACBtn);
  543. var divCSV = WMEAC.createElement({type:"div", className:"wmeac-sidepanel", id:"wmeac-csv"});
  544. var csvHTML = '<label for="wmeac-csv-file" class="wmeac-button">Parse CSV</label> <input id="wmeac-csv-file" type="file" name="files[]" style="display: none;" />';
  545. csvHTML += ' <div id="wmeac-csv-closures" style="display: none;"> <div id="wmeac-csv-closures-controls"> <input type="checkbox" id="wmeac-csv-closures-controls-check"> | <a href="#" id="wmeac-csv-closures-controls-apply">Apply</a> | <a href="#" id="wmeac-csv-closures-controls-segs">Check segments</a> </div> <div id="wmeac-csv-closures-list"> <ul id="wmeac-csv-closures-list-elts"> </ul> </div> </div> <div id="wmeac-csv-closures-log"> </div>';
  546. divCSV.innerHTML = csvHTML;
  547. addon.appendChild(divAdvCl);
  548. addon.appendChild(WMEAC.createElement({type:"hr"}));
  549. addon.appendChild(divCSV);
  550. var userTabs = WMEAC.getId("user-tabs");
  551. var userInfo = WMEAC.getId("user-info");
  552. var sidePanelPrefs = WMEAC.getId("sidepanel-prefs");
  553. var navTabs = WMEAC.getElementsByClassName("nav-tabs", userTabs)[0];
  554. var tabContent = sidePanelPrefs.parentNode;
  555. newtab = WMEAC.createElement({type:"li"});
  556. newtab.innerHTML = '<a title="Advanced closures" href="#sidepanel-wmeac" data-toggle="tab"><span class="fa fa-road slashed"></span></a>';
  557. navTabs.appendChild(newtab);
  558. addon.id = "sidepanel-wmeac";
  559. addon.className = "tab-pane";
  560. addon.style.marginLeft = "-10px";
  561. tabContent.appendChild(addon);
  562. var observer = new MutationObserver(function(mutations) {
  563. mutations.forEach(function(mutation) {
  564. function rescurse(node) {
  565. if (node.id == "segment-edit-closures") {
  566. WMEAC.installButtonInClosureTab(node);
  567. } else {
  568. if (node.className == "closures-list") {
  569. var target = WMEAC.getId("segment-edit-closures");
  570. if (target) {
  571. WMEAC.installButtonInClosureTab(target);
  572. }
  573. } else {
  574. for (var j = 0;j < node.childNodes.length;j++) {
  575. rescurse(node.childNodes[j]);
  576. }
  577. }
  578. }
  579. }
  580. for (var i = 0;i < mutation.addedNodes.length;i++) {
  581. rescurse(mutation.addedNodes[i]);
  582. }
  583. });
  584. });
  585. observer.observe(WMEAC.getId("edit-panel"), {childList:true, subtree:true});
  586. WMEAC.installButtonInClosureTab();
  587. Waze.vent.on("operationPending", function(e) {
  588. if (e.operation.id != "pending.road_data") {
  589. return;
  590. }
  591. WMEAC.pendingOps = true;
  592. });
  593. Waze.vent.on("operationDone", function(e) {
  594. if (e.operation.id != "pending.road_data") {
  595. return;
  596. }
  597. WMEAC.pendingOps = false;
  598. });
  599. Waze.model.events.register("mergeend", null, WMEAC.refreshHighlight);
  600. WMEAC.refreshHighlight();
  601. window.setTimeout(WMEAC.connectAdvancedClosureTabHandlers);
  602. };
  603. WMEAC.installButtonInClosureTab = function(node) {
  604. if (!node) {
  605. node = WMEAC.getId("segment-edit-closures");
  606. }
  607. if (!node) {
  608. return;
  609. }
  610. if ($(node).find("#wmeac-closuretab-add-advanced-closure-button").length == 0) {
  611. var addACBtn = WMEAC.createElement({type:"div", id:"wmeac-closuretab-add-advanced-closure-button", className:"wmeac-button"});
  612. addACBtn.style.width = "100%";
  613. addACBtn.style.marginBottom = "10px";
  614. addACBtn.innerHTML = '<i class="fa fa-clock-o"></i> Add advanced closure';
  615. addACBtn.addEventListener("click", WMEAC.showAddAdvancedClosure);
  616. $(node).find(".main").prepend(addACBtn);
  617. }
  618. };
  619. WMEAC.showAddAdvancedClosure = function() {
  620. var ACDiv = WMEAC.getId("wmeac-add-advanced-closure-dialog");
  621. if (ACDiv == null) {
  622. ACDiv = WMEAC.createElement({type:"div", id:"wmeac-add-advanced-closure-dialog", className:"wmeac-closuredialog"});
  623. ACDiv.innerHTML = WMEAC.HTMLTemplates.advancedClosureDialog;
  624. Waze.map.div.appendChild(ACDiv);
  625. window.setTimeout(WMEAC.connectAdvancedClosureDialogHandlers);
  626. ACDiv.style.display = "none";
  627. }
  628. if (ACDiv.style.display == "block") {
  629. $(ACDiv).css({left:"80px", top:"10px"});
  630. } else {
  631. ACDiv.style.display = "block";
  632. Waze.selectionManager.events.register("selectionchanged", null, WMEAC.refreshClosureList);
  633. Waze.selectionManager.events.register("selectionchanged", null, WMEAC.refreshClosureListFromSelection);
  634. WMEAC.refreshClosureListFromSelection();
  635. }
  636. WMEAC.showClosuresLayer(true);
  637. };
  638. WMEAC.HTMLTemplates = {};
  639. var rangeStartEndUI = ' <div class="form-group"> <label class="control-label" for="closure_rangestartDate">Range start (included)</label> <div class="controls"> <div style="width: 58%" class="date date-input-group input-group pull-left"> <input id="wmeac-advanced-closure-dialog-rangestartdate" class="form-control start-date" type="text" name="closure_rangestartDate"> <span class="input-group-addon"> <i class="fa fa-calendar"></i> </span> </div> </div> </div> <div class="form-group"> <label class="control-label" for="closure_rangeendDate">Range end (included)</label> <div class="controls"> <div style="width: 58%" class="date date-input-group input-group pull-left"> <input id="wmeac-advanced-closure-dialog-rangeenddate" class="form-control end-date" type="text" name="closure_rangeendDate"> <span class="input-group-addon"> <i class="fa fa-calendar"></i> </span> </div> </div> </div>';
  640. var startTimeAndDurationUI = ' <div class="wmeac-closuredialog-fromgroup"> <label class="control-label" for="closure_startTime">Start</label> <div class="controls"> <div style="width: 58%;" class="bootstrap-timepicker input-group pull-left"> <input id="wmeac-advanced-closure-dialog-starttime" class="form-control start-time" type="text" name="closure_startTime"> <span class="input-group-addon"> <i class="fa fa-clock-o"></i> </span> </div> </div> </div> <div class="wmeac-closuredialog-fromgroup"> <label class="control-label">Duration</label> <div style="width: 58%;" class="bootstrap-timepicker input-group"> <div class="controls" style="display: flex;"> <span class="input-group-addon pull-left"> <i class="fa fa-step-forward"></i> </span> <span class="form-control" style="padding: 1px; display: flex"> <input id="wmeac-advanced-closure-dialog-duration-day" name="value" value=0 size=3/> <span style="padding: 5px;">D</span> </span> </div> <div class="bootstrap-timepicker input-group pull-left"> <input id="wmeac-advanced-closure-dialog-durationtime" class="form-control start-time" type="text" name="closure_durationTime"> <span class="input-group-addon"> <i class="fa fa-clock-o"></i> </span> </div> </div> </div>';
  641. var descriptionUI = ' <div class="form-group"> <label class="control-label" for="closure_reason">Description</label> <div class="controls"> <input id="wmeac-advanced-closure-dialog-reason" class="form-control" type="text" name="closure_reason"> </div> </div>';
  642. var locationUI = ' <div class="form-group"> <label class="control-label" for="closure_location">Location</label> <div class="controls"> <input id="wmeac-advanced-closure-dialog-location" class="form-control" type="text" name="closure_location"> </div> </div>';
  643. var directionUI = ' <div class="form-group"> <label class="control-label" for="closure_direction">Direction</label> <div class="controls"> <select id="wmeac-advanced-closure-dialog-direction" style="font-family:\'FontAwesome\', Arial;" class="form-control" name="closure_direction"> <option value="3">Two way (&#xf0ec;)</option><option value="1">One way (A &#8594; B)</option><option value="2">One way (B &#8594; A)</option> </select> </div> </div>';
  644. var ignoreTrafficUI = ' <div class="checkbox"> <label class="control-label" style="font-weight: bold;"> <input id="wmeac-advanced-closure-dialog-ignoretraffic" type="checkbox" name="closure_permanent"> Ignore Traffic </label> </div>';
  645. var MTEUI = ' <div class="form-group"> <label class="control-label control-label-inline" for="closure_MTE">Link to MTE</label> <div class="controls"> <select id="wmeac-advanced-closure-dialog-mteid" class="form-control" name="closure_MTE" disabled><option value="">None</option></select> </div> </div>';
  646. var overlapModeUI = ' <div class="form-group"> <label class="control-label" for="closure_overlap">Overlap action</label> <div class="controls"> <select id="wmeac-advanced-closure-dialog-overlap" style="font-family:\'FontAwesome\', Arial;" class="form-control" name="closure_overlap"> <option value="0">Keep existing</option><option value="1">Delete existing</option><option value="2">Fill with new</option><option value="3">Force new</option> </select> </div> </div>';
  647. var tabRepeatUI = ' <div style="width: 150px;" class="input-group"> <div class="controls"> <div class="input-group pull-left"> <input id="wmeac-advanced-closure-dialog-repeat-ntimes" class="form-control" type="text" name="closure_repeat_ntimes"> <span class="input-group-addon" for="closure_repeat_ntimes">times</span> </div> </div> </div> <div style="width: 150px;" class="input-group"> <div class="controls"> <div style="width: 150px;" class="bootstrap-timepicker input-group"> <span class="input-group-addon"> every </span> <span class="form-control" style="padding: 1px; display: flex"> <input id="wmeac-advanced-closure-dialog-repeat-every-day" name="value" value=0 size=3/> <span style="padding: 5px;">D</span> <input id="wmeac-advanced-closure-dialog-repeat-every-hour" name="value" value=0 size=3/> <span style="padding: 5px;">H</span> <input id="wmeac-advanced-closure-dialog-repeat-every-minute" name="value" value=0 size=2/> <span style="padding: 5px;">M</span> </span> </div> </div> </div>';
  648. var daysOfWeekUI = WMEAC.daysOfWeek.clone();
  649. daysOfWeekUI.push(daysOfWeekUI.shift());
  650. var tabEachUI = '<div class="checkbox"> <label class="control-label" style="font-weight: bold;"> <input id="wmeac-advanced-closure-dialog-each-dayall" type="checkbox" name="closure_each_dayall"> All </label> </div> ' + daysOfWeekUI.map(function(d, i) {
  651. return '<div class="checkbox"> <label class="control-label" style="font-weight: bold;"> <input id="wmeac-advanced-closure-dialog-each-' + (i + 1) % 7 + '" type="checkbox" name="closure_each_' + d + '"> ' + d + " </label> </div>";
  652. }).join("");
  653. var tabHolidayUI = '<div class="content"> <a id="wmeac-advanced-closure-dialog-holiday-refresh" href="#">Refresh holidays</a><br> <i id="wmeac-advanced-closure-dialog-holiday-refresh-spinner" class="fa fa-spinner fa-pulse fa-3x fa-fw" style="display: none;"></i> <div id="wmeac-advanced-closure-dialog-holiday-list" class="form-group" style="overflow-y: scroll; max-height: 200px;"> </div></div>';
  654. var tabPresetsUI = '<div class="content"> <table><tr><td style="width: 50%; border-right: 1px solid #F6C3BE; padding-right: 5px;"> <div class="form-group"> <label class="control-label" for="presets_load">Load preset</label> <div class="controls"> <div class="input-group"> <select style="width: 100%;" id="wmeac-advanced-closure-dialog-presets-list" name="presets_load"> </select> <span id="wmeac-advanced-closure-dialog-presets-load" class="input-group-addon"> <i class="fa fa-folder-open-o"></i> </span> <span id="wmeac-advanced-closure-dialog-presets-delete" class="input-group-addon"> <i class="fa fa-trash"></i> </span> </div> </div> <label class="control-label" for="seg_load">Load from segment</label> <div class="controls"> <div class="input-group"> <select style="width: 100%;" id="wmeac-advanced-closure-dialog-segclosure-list" name="presets_load"> </select> <span id="wmeac-advanced-closure-dialog-presets-load-fromseg" class="input-group-addon"> <i class="fa fa-share"></i> </span> </div> </div> </div> </td><td style="padding-left: 5px;"> <div class="form-group"> <label class="control-label" for="presets_save">Save preset</label> <div class="controls"> <div class="input-group pull-left"> <input id="wmeac-advanced-closure-dialog-presets-name" class="form-control" type="text" name="presets_save"> <span id="wmeac-advanced-closure-dialog-presets-save" class="input-group-addon"> <i class="fa fa-floppy-o"></i> </span> </div> </div> </div> </td></tr></table></div>';
  655. var tabsUI = ' <ul class="nav wmeac-nav-tabs"> <li class="active"> <a id="wmeac-advanced-closure-dialog-repeat" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabrepeat">Repeat</a> </li> <li> <a id="wmeac-advanced-closure-dialog-each" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabeach">Each</a> </li> <li> <a id="wmeac-advanced-closure-dialog-holiday" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabholiday">Holidays</a> </li> <li style="float: right;"> <a id="wmeac-advanced-closure-dialog-presets" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabpresets"><i class="fa fa-floppy-o"></i></a> </li> </ul> <div class="tab-content"> <div class="tab-pane active wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabrepeat"> ' +
  656. tabRepeatUI + ' </div> <div class="tab-pane wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabeach"> ' + tabEachUI + ' </div> <div class="tab-pane wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabholiday"> ' + tabHolidayUI + ' </div> <div class="tab-pane wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabpresets"> ' + tabPresetsUI + " </div> </div>";
  657. var footerUI = '<div class="footer"> <div id="wmeac-csv-closures-preview"><div id="wmeac-csv-closures-preview-content" style="overflow: scroll; max-height: 100px;"></div></div> <button style="float: left;" id="wmeac-advanced-closure-dialog-exportCSV-button">Export CSV</button> <button style="float: right;" id="wmeac-advanced-closure-dialog-close-button">Close</button> <button style="float: right;" id="wmeac-advanced-closure-dialog-apply-button">Apply</button></div>';
  658. WMEAC.HTMLTemplates.advancedClosureDialog = '<h1>Advanced closures</h1><div class="content"> <table> <tr> <td style="width: 50%;">' + rangeStartEndUI + startTimeAndDurationUI + " </td> <td>" + descriptionUI + directionUI + ignoreTrafficUI + MTEUI + " </td> </tr> </table>" + tabsUI + "</div>" + footerUI;
  659. WMEAC.connectAdvancedClosureDialogHandlers = function() {
  660. var e = null;
  661. e = WMEAC.getId("wmeac-advanced-closure-dialog-exportCSV-button");
  662. if (e) {
  663. e.addEventListener("click", function() {
  664. var rc = WMEAC.buildClosuresListFromRecurringUI();
  665. if (rc.error != "") {
  666. alert("Can't apply closures.\nPlease, check all parameters.");
  667. return;
  668. }
  669. if (Waze.selectionManager.selectedItems.isEmpty() || Waze.selectionManager.selectedItems[0].model.type != "segment") {
  670. alert("Please, select segment(s) before.");
  671. return;
  672. }
  673. var reason = $("#wmeac-advanced-closure-dialog-reason").val();
  674. var direction = $("#wmeac-advanced-closure-dialog-direction").val();
  675. var isIT = $("#wmeac-advanced-closure-dialog-ignoretraffic").is(":checked");
  676. var mteId = $("#wmeac-advanced-closure-dialog-mteid").val();
  677. var mte = Waze.model.majorTrafficEvents.get(mteId);
  678. closureList = rc.list.map(function(e) {
  679. var details = {reason:reason, direction:direction, startDate:e.start, endDate:e.end, location:"", permanent:isIT};
  680. if (mte) {
  681. details.eventId = mte.id;
  682. }
  683. return details;
  684. });
  685. var selection = _.pluck(Waze.selectionManager.selectedItems, "model");
  686. var selectionReversed = [];
  687. if (direction != "3") {
  688. var rev = Waze.selectionManager.getReversedSegments();
  689. selection = selection.filter(function(e) {
  690. if (rev[e.attributes.id]) {
  691. selectionReversed.push(e);
  692. return false;
  693. }
  694. return true;
  695. });
  696. }
  697. var lonlat = Waze.map.center.transform(Waze.map.projection.projCode, "EPSG:4326");
  698. var csv = "header,reason,start date (yyyy-mm-dd hh:mm),end date (yyyy-mm-dd hh:mm),direction (A to B|B to A|TWO WAY),ignore trafic (Yes|No),segment IDs (id1;id2;...),lon/lat (like in a permalink: lon=xxx&lat=yyy),zoom (2 to 10),MTE id (empty cell if not),comment (optional)\n";
  699. closureList.forEach(function(e) {
  700. csv += 'add,"' + e.reason + '","' + e.startDate + '","' + e.endDate + '","' + (direction == 3 ? "TWO WAY" : direction == 2 ? "B to A" : "A to B") + '",' + (isIT ? "Yes" : "No") + ',"' + selection.map(function(s) {
  701. return s.attributes.id;
  702. }).join(";") + '","lon=' + lonlat.lon + "&lat=" + lonlat.lat + '",' + Waze.map.zoom + "," + mteId + ',"Generated by WMEAC"\n';
  703. });
  704. if (!selectionReversed.isEmpty()) {
  705. closureList.forEach(function(e) {
  706. csv += 'add,"' + e.reason + '","' + e.startDate + '","' + e.endDate + '","' + (direction == 3 ? "TWO WAY" : direction == 2 ? "A to B" : "B to A") + '",' + (isIT ? "Yes" : "No") + ',"' + selectionReversed.map(function(s) {
  707. return s.attributes.id;
  708. }).join(";") + '","lon=' + lonlat.lon + "&lat=" + lonlat.lat + '",' + Waze.map.zoom + "," + mteId + ',"Generated by WMEAC"\n';
  709. });
  710. }
  711. WMEAC.download(csv, "closures.csv");
  712. });
  713. }
  714. e = WMEAC.getId("wmeac-advanced-closure-dialog-close-button");
  715. if (e) {
  716. e.addEventListener("click", function() {
  717. var d = WMEAC.getId("wmeac-add-advanced-closure-dialog");
  718. if (d) {
  719. Waze.selectionManager.events.unregister("selectionchanged", null, WMEAC.refreshClosureList);
  720. Waze.selectionManager.events.unregister("selectionchanged", null, WMEAC.refreshClosureListFromSelection);
  721. d.style.display = "none";
  722. }
  723. });
  724. }
  725. e = WMEAC.getId("wmeac-advanced-closure-dialog-apply-button");
  726. if (e) {
  727. e.addEventListener("click", function() {
  728. var rc = WMEAC.buildClosuresListFromRecurringUI();
  729. if (rc.error != "") {
  730. alert("Can't apply closures.\nPlease, check all parameters.");
  731. return;
  732. }
  733. if (Waze.selectionManager.selectedItems.isEmpty() || Waze.selectionManager.selectedItems[0].model.type != "segment") {
  734. alert("Please, select segment(s) before.");
  735. return;
  736. }
  737. if (Waze.selectionManager.selectedItems.every(function(e) {
  738. return e.model.isAllowed(e.model.PERMISSIONS.EDIT_CLOSURES);
  739. }) == false) {
  740. alert("You don't have permission to edit closures on all those segments.");
  741. return;
  742. }
  743. var reason = $("#wmeac-advanced-closure-dialog-reason").val();
  744. var direction = $("#wmeac-advanced-closure-dialog-direction").val();
  745. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  746. direction = direction == "1" ? sc.DIRECTION.A_TO_B : direction == "2" ? sc.DIRECTION.B_TO_A : sc.DIRECTION.TWO_WAY;
  747. var directionStr = direction == 1 ? "(A &#8594; B)" : direction == 2 ? "(B &#8594; A)" : "(&#8646;)";
  748. var isIT = $("#wmeac-advanced-closure-dialog-ignoretraffic").is(":checked");
  749. var mte = Waze.model.majorTrafficEvents.get($("#wmeac-advanced-closure-dialog-mteid").val());
  750. closureList = rc.list.map(function(e) {
  751. var details = {reason:reason, direction:direction, startDate:e.start, endDate:e.end, location:"", permanent:isIT};
  752. if (mte) {
  753. details.eventId = mte.id;
  754. }
  755. return details;
  756. });
  757. var selection = _.pluck(Waze.selectionManager.selectedItems, "model");
  758. Waze.selectionManager.events.unregister("selectionchanged", null, WMEAC.refreshClosureList);
  759. WMEAC.addClosureListFromSelection(closureList, function(i, e) {
  760. $("#wmeac-advanced-closure-dialog-preview-" + i).html(e).css({color:"#44D544"});
  761. }, function(i, e) {
  762. $("#wmeac-advanced-closure-dialog-preview-" + i).html(e).css({color:"#D5444F"});
  763. }, function() {
  764. Waze.selectionManager.select(selection);
  765. var tmp = function selectionReady() {
  766. if (Waze.selectionManager.selectedItems.isEmpty()) {
  767. window.setTimeout(selectionReady, 500);
  768. } else {
  769. Waze.selectionManager.events.register("selectionchanged", null, WMEAC.refreshClosureList);
  770. $('a[href="#segment-edit-closures"]').click();
  771. }
  772. };
  773. window.setTimeout(tmp, 500);
  774. }, 0);
  775. });
  776. }
  777. if (typeof $.fn.datepicker !== "undefined") {
  778. $("#wmeac-advanced-closure-dialog-rangestartdate,#wmeac-advanced-closure-dialog-rangeenddate").datepicker({format:"yyyy-mm-dd", todayHighlight:!0, autoclose:!0});
  779. } else {
  780. if (typeof $.fn.daterangepicker !== "undefined") {
  781. $("#wmeac-advanced-closure-dialog-rangestartdate,#wmeac-advanced-closure-dialog-rangeenddate").daterangepicker({singleDatePicker:!0, locale:{format:"YYYY-MM-DD"}});
  782. }
  783. }
  784. $("#wmeac-advanced-closure-dialog-rangestartdate,#wmeac-advanced-closure-dialog-rangeenddate").on("change", function() {
  785. WMEAC.refreshMTEList();
  786. });
  787. $("#wmeac-advanced-closure-dialog-starttime,#wmeac-advanced-closure-dialog-durationtime").timepicker({defaultTime:"00:00", showMeridian:!1, template:!1});
  788. $("#wmeac-add-advanced-closure-dialog").find(".input-group").find(".input-group-addon").on("click", function(e) {
  789. $(e.target).parent().find("input").focus();
  790. }).find("i").on("click", function(e) {
  791. $(e.target).parent().parent().find("input").focus();
  792. });
  793. $("#wmeac-advanced-closure-dialog-each-dayall").on("click", function() {
  794. var atLeastOneChecked = false;
  795. for (var i = 0;i < 7;i++) {
  796. atLeastOneChecked = atLeastOneChecked || $("#wmeac-advanced-closure-dialog-each-" + i).is(":checked");
  797. }
  798. for (var i = 0;i < 7;i++) {
  799. $("#wmeac-advanced-closure-dialog-each-" + i).prop("checked", !atLeastOneChecked);
  800. }
  801. $("#wmeac-advanced-closure-dialog-each-dayall").prop("checked", !atLeastOneChecked);
  802. });
  803. if (typeof $.fn.spinner !== "undefined") {
  804. $("#wmeac-advanced-closure-dialog-repeat-every-day").spinner({min:0, spin:function(event, ui) {
  805. $(this).trigger("change");
  806. }});
  807. $("#wmeac-advanced-closure-dialog-repeat-every-hour").spinner({min:0, spin:function(event, ui) {
  808. if (ui.value >= 24) {
  809. $(this).spinner("value", ui.value - 24);
  810. $("#wmeac-advanced-closure-dialog-repeat-every-day").spinner("stepUp");
  811. return false;
  812. } else {
  813. if (ui.value < 0) {
  814. $(this).spinner("value", ui.value + 24);
  815. $("#wmeac-advanced-closure-dialog-repeat-every-day").spinner("stepDown");
  816. return false;
  817. }
  818. }
  819. $(this).trigger("change");
  820. }});
  821. $("#wmeac-advanced-closure-dialog-repeat-every-minute").spinner({spin:function(event, ui) {
  822. if (ui.value >= 60) {
  823. $(this).spinner("value", ui.value - 60);
  824. $("#wmeac-advanced-closure-dialog-repeat-every-hour").spinner("stepUp");
  825. return false;
  826. } else {
  827. if (ui.value < 0) {
  828. $(this).spinner("value", ui.value + 60);
  829. $("#wmeac-advanced-closure-dialog-repeat-every-hour").spinner("stepDown");
  830. return false;
  831. }
  832. }
  833. $(this).trigger("change");
  834. }, change:function(event) {
  835. if (event.target.value < 0 || event.target.value > 59) {
  836. $(this).spinner("value", 0);
  837. }
  838. }});
  839. $("#wmeac-advanced-closure-dialog-duration-day").spinner({min:0, spin:function(event, ui) {
  840. $(this).trigger("change");
  841. }});
  842. }
  843. $("#wmeac-advanced-closure-dialog-repeat,#wmeac-advanced-closure-dialog-each,#wmeac-advanced-closure-dialog-holiday").on("click", function(e) {
  844. window.setTimeout(WMEAC.refreshClosureList);
  845. });
  846. $("#wmeac-advanced-closure-dialog-holiday-refresh").on("click", function(e) {
  847. var hDiv = $("#wmeac-advanced-closure-dialog-holiday-list");
  848. $("#wmeac-advanced-closure-dialog-holiday-refresh-spinner").css({display:"block"});
  849. WMEAC.removeChildElements(hDiv[0]);
  850. window.setTimeout(function() {
  851. WMEAC.getHolidays({rangeStart:$("#wmeac-advanced-closure-dialog-rangestartdate").val(), rangeEnd:$("#wmeac-advanced-closure-dialog-rangeenddate").val(), countries:_.pluck(WMEAC.getCountriesFromSegmentSet(_.pluck(Waze.selectionManager.selectedItems, "model")), "abbr"), handlerFinished:function(holidays) {
  852. WMEAC.lastGeneratedHolidays = holidays;
  853. if (holidays.isEmpty()) {
  854. hDiv.html("No holiday found.");
  855. } else {
  856. holidays.forEach(function(h, i) {
  857. var chkBx = WMEAC.createElement({type:"div", className:"checkbox"});
  858. chkBx.innerHTML = '<label class="control-label" style="font-weight: bold;"> <input id="wmeac-advanced-closure-dialog-holidays-' + i + '" type="checkbox"> ' + h.date + ": " + h.name + " (" + h.country + ") </label> ";
  859. $(chkBx).on("click", function(e) {
  860. window.setTimeout(WMEAC.refreshClosureList);
  861. });
  862. hDiv.append(chkBx);
  863. });
  864. }
  865. $("#wmeac-advanced-closure-dialog-holiday-refresh-spinner").css({display:"none"});
  866. }});
  867. });
  868. });
  869. $("#wmeac-add-advanced-closure-dialog").on("change", function(e) {
  870. window.setTimeout(WMEAC.refreshClosureList);
  871. });
  872. WMEAC.reloadPresets();
  873. $("#wmeac-advanced-closure-dialog-presets-load").on("click", function(e) {
  874. var presetIndex = parseInt($("#wmeac-advanced-closure-dialog-presets-list").val());
  875. $("#wmeac-advanced-closure-dialog-starttime").val(WMEAC.presets[presetIndex].values.starttime);
  876. if (WMEAC.presets[presetIndex].values.duration.hasOwnProperty("day")) {
  877. $("#wmeac-advanced-closure-dialog-duration-day").val(WMEAC.presets[presetIndex].values.duration.day);
  878. } else {
  879. $("#wmeac-advanced-closure-dialog-duration-day").val(Math.floor(WMEAC.presets[presetIndex].values.duration.hour / 24));
  880. }
  881. $("#wmeac-advanced-closure-dialog-durationtime").val("" + WMEAC.presets[presetIndex].values.duration.hour % 24 + ":" + WMEAC.presets[presetIndex].values.duration.minute);
  882. $("#wmeac-advanced-closure-dialog-reason").val(WMEAC.presets[presetIndex].values.description);
  883. $("#wmeac-advanced-closure-dialog-direction").val(WMEAC.presets[presetIndex].values.direction);
  884. $("#wmeac-advanced-closure-dialog-ignoretraffic").prop("checked", WMEAC.presets[presetIndex].values.ignoretraffic);
  885. $("#wmeac-advanced-closure-dialog-repeat-ntimes").val(WMEAC.presets[presetIndex].values.repeat.ntimes);
  886. if (WMEAC.presets[presetIndex].values.repeat.hasOwnProperty("day")) {
  887. $("#wmeac-advanced-closure-dialog-repeat-every-day").val(WMEAC.presets[presetIndex].values.repeat.day);
  888. } else {
  889. $("#wmeac-advanced-closure-dialog-repeat-every-day").val(Math.floor(WMEAC.presets[presetIndex].values.repeat.hour / 24));
  890. }
  891. $("#wmeac-advanced-closure-dialog-repeat-every-hour").val(WMEAC.presets[presetIndex].values.repeat.hour % 24);
  892. $("#wmeac-advanced-closure-dialog-repeat-every-minute").val(WMEAC.presets[presetIndex].values.repeat.minute);
  893. for (var i = 0;i < 7;i++) {
  894. $("#wmeac-advanced-closure-dialog-each-" + i).prop("checked", WMEAC.presets[presetIndex].values.each[i]);
  895. }
  896. });
  897. $("#wmeac-advanced-closure-dialog-presets-load-fromseg").on("click", function() {
  898. closureId = $("#wmeac-advanced-closure-dialog-segclosure-list").val();
  899. if (closureId) {
  900. var c = Waze.model.roadClosures.objects[closureId];
  901. if (c) {
  902. $("#wmeac-advanced-closure-dialog-starttime").val(c.startDate.split(" ")[1]);
  903. var duration = new Date(c.endDate) - new Date(c.startDate);
  904. $("#wmeac-advanced-closure-dialog-duration-day").val(Math.floor(duration / 864E5));
  905. $("#wmeac-advanced-closure-dialog-durationtime").val("" + (new Date(duration)).getHours() + ":" + (new Date(duration)).getMinutes());
  906. $("#wmeac-advanced-closure-dialog-reason").val(c.reason.trim());
  907. if (WMEAC.getOppositeClosure(c).isEmpty()) {
  908. $("#wmeac-advanced-closure-dialog-direction").val(c.forward ? 1 : 2);
  909. } else {
  910. $("#wmeac-advanced-closure-dialog-direction").val(3);
  911. }
  912. $("#wmeac-advanced-closure-dialog-ignoretraffic").prop("checked", c.permanent);
  913. }
  914. }
  915. });
  916. $("#wmeac-advanced-closure-dialog-presets-delete").on("click", function(e) {
  917. var presetIndex = parseInt($("#wmeac-advanced-closure-dialog-presets-list").val());
  918. WMEAC.presets.splice(presetIndex, 1);
  919. WMEAC.save();
  920. WMEAC.reloadPresets();
  921. });
  922. $("#wmeac-advanced-closure-dialog-presets-save").on("click", function(e) {
  923. var name = $("#wmeac-advanced-closure-dialog-presets-name").val();
  924. var presetIndex = WMEAC.presets.findIndex(function(e) {
  925. return e.name == name;
  926. });
  927. var preset = {name:name, values:{duration:{}, repeat:{}, each:[]}};
  928. if (presetIndex != -1) {
  929. preset = WMEAC.presets[presetIndex];
  930. }
  931. preset.values.starttime = $("#wmeac-advanced-closure-dialog-starttime").val();
  932. preset.values.duration.day = $("#wmeac-advanced-closure-dialog-duration-day").val();
  933. preset.values.duration.hour = parseInt($("#wmeac-advanced-closure-dialog-durationtime").val().split(":")[0]);
  934. preset.values.duration.minute = parseInt($("#wmeac-advanced-closure-dialog-durationtime").val().split(":")[1]);
  935. preset.values.description = $("#wmeac-advanced-closure-dialog-reason").val();
  936. preset.values.direction = $("#wmeac-advanced-closure-dialog-direction").val();
  937. preset.values.ignoretraffic = $("#wmeac-advanced-closure-dialog-ignoretraffic").is(":checked");
  938. preset.values.repeat.ntimes = $("#wmeac-advanced-closure-dialog-repeat-ntimes").val();
  939. preset.values.repeat.day = $("#wmeac-advanced-closure-dialog-repeat-every-day").val();
  940. preset.values.repeat.hour = $("#wmeac-advanced-closure-dialog-repeat-every-hour").val();
  941. preset.values.repeat.minute = $("#wmeac-advanced-closure-dialog-repeat-every-minute").val();
  942. for (var i = 0;i < 7;i++) {
  943. preset.values.each[i] = $("#wmeac-advanced-closure-dialog-each-" + i).is(":checked");
  944. }
  945. if (presetIndex == -1) {
  946. WMEAC.presets.push(preset);
  947. }
  948. WMEAC.save();
  949. WMEAC.reloadPresets();
  950. });
  951. WMEAC.setDraggable($("#wmeac-add-advanced-closure-dialog"), {controller:$("#wmeac-add-advanced-closure-dialog h1:first-child"), container:$("#WazeMap")});
  952. };
  953. WMEAC.connectAdvancedClosureTabHandlers = function() {
  954. var e = null;
  955. e = WMEAC.getId("wmeac-csv-file");
  956. if (e) {
  957. e.addEventListener("change", WMEAC.CSVFileChanged);
  958. }
  959. e = WMEAC.getId("wmeac-csv-closures-controls-check");
  960. if (e) {
  961. e.addEventListener("change", function(e) {
  962. WMEAC.CSVCheckAll(e.target.checked);
  963. });
  964. }
  965. e = WMEAC.getId("wmeac-csv-closures-controls-apply");
  966. if (e) {
  967. e.addEventListener("click", WMEAC.CSVApplyChecked);
  968. }
  969. e = WMEAC.getId("wmeac-csv-closures-controls-segs");
  970. if (e) {
  971. e.addEventListener("click", WMEAC.CSVCheckSegsChecked);
  972. }
  973. };
  974. WMEAC.reloadPresets = function() {
  975. var optionList = WMEAC.presets.map(function(p, i) {
  976. return '<option value="' + i + '">' + p.name + "</option>";
  977. });
  978. $("#wmeac-advanced-closure-dialog-presets-list").html(optionList.join(""));
  979. };
  980. WMEAC.ProgressBar = function(id) {
  981. this.id = id;
  982. this.divpbi = WMEAC.createElement({type:"div", id:id, className:id});
  983. var elt = WMEAC.createElement({type:"div", id:"wmeac-progressBar"});
  984. elt.style.width = "100%";
  985. elt.style.display = "none";
  986. elt.innerHTML = '<div class="wmeac-progressBarBG"></div><span class="wmeac-progressBarFG">100%</span>';
  987. this.divpbi.appendChild(elt);
  988. elt = WMEAC.createElement({type:"div", id:"wmeac-progressBar-info"});
  989. this.divpbi.appendChild(elt);
  990. this.isShown = function() {
  991. return this.divpbi.style.display != "none";
  992. };
  993. this.show = function(toShow) {
  994. this.divpbi.style.display = toShow ? "block" : "none";
  995. };
  996. this.update = function(value) {
  997. if (value == -1) {
  998. this.divpbi.children[0].style.display = "none";
  999. this.divpbi.children[1].style.display = "none";
  1000. return;
  1001. }
  1002. value = Math.round(value);
  1003. this.divpbi.children[0].style.display = "block";
  1004. this.divpbi.children[1].style.display = "block";
  1005. this.divpbi.children[0].children[0].style.width = value + "%";
  1006. this.divpbi.children[0].children[1].innerHTML = value + "%";
  1007. };
  1008. this.info = function(text) {
  1009. this.divpbi.children[1].innerHTML = text;
  1010. };
  1011. };
  1012. WMEAC.ClassClosure = function(options) {
  1013. WMEAC.log("options", options);
  1014. this.isValid = false;
  1015. this.errorMessage = "";
  1016. var validProperties = ["reason", "startDate", "endDate", "direction", "segIDs", "lonlat", "permanent", "id", "zoom"];
  1017. var goodOptions = 0;
  1018. validProperties.forEach(function(p) {
  1019. if (options.hasOwnProperty(p)) {
  1020. this[p] = options[p];
  1021. goodOptions++;
  1022. } else {
  1023. this.errorMessage += "Missing property " + p + "\n";
  1024. }
  1025. }, this);
  1026. if (goodOptions == validProperties.length) {
  1027. this.isValid = true;
  1028. } else {
  1029. return;
  1030. }
  1031. this.comment = "";
  1032. if (options.hasOwnProperty("comment")) {
  1033. this.comment = options.comment;
  1034. }
  1035. this.eventId = null;
  1036. if (options.hasOwnProperty("eventId") && options.eventId != "") {
  1037. this.eventId = options.eventId;
  1038. }
  1039. this.segIDs = this.segIDs.split(";");
  1040. var matches = this.lonlat.match(/lon=(-?\d+\.?\d*)&lat=(-?\d+\.?\d*)/);
  1041. if (matches && matches.length == 3) {
  1042. this.lonlat = {lon:parseFloat(matches[1]), lat:parseFloat(matches[2])};
  1043. } else {
  1044. matches = this.lonlat.match(/lat=(-?\d+\.?\d*)&lon=(-?\d+\.?\d*)/);
  1045. if (matches && matches.length == 3) {
  1046. this.lonlat = {lon:parseFloat(matches[2]), lat:parseFloat(matches[1])};
  1047. } else {
  1048. this.isValid = false;
  1049. this.errorMessage = "Can't parse lonlat: " + this.lonlat + "\n";
  1050. return;
  1051. }
  1052. }
  1053. if (this.direction != "A to B" && this.direction != "B to A" && this.direction != "TWO WAY") {
  1054. this.isValid = false;
  1055. this.errorMessage = "Can't determine direction: " + this.direction + "\n";
  1056. return;
  1057. }
  1058. this.zoom = parseInt(this.zoom);
  1059. if (this.zoom < 2 || this.zoom > 10) {
  1060. this.isValid = false;
  1061. this.errorMessage = "Wrong zoom (2 to 10): " + this.zoom + "\n";
  1062. return;
  1063. }
  1064. this.applyInWME = function(successHandler, failureHandler) {
  1065. var segs = WMEAC.segmentsIDsToSegments(this.segIDs);
  1066. WMEAC.log("Segs: ", segs);
  1067. segs = segs.filter(function(seg) {
  1068. return seg.isAllowed(seg.PERMISSIONS.EDIT_CLOSURES);
  1069. });
  1070. if (segs.length == 0) {
  1071. failureHandler([{attributes:{details:"No segment. Check permissions or existence."}}]);
  1072. } else {
  1073. var cityStreets = WMEAC.getCityStreetsFromSegmentSet(segs);
  1074. var closureLocation = Object.keys(cityStreets).map(function(c) {
  1075. return Object.keys(cityStreets[c]).map(function(s) {
  1076. if (s == "noStreet") {
  1077. return I18n.translations[I18n.locale].edit.address.no_street;
  1078. }
  1079. return s;
  1080. }).join(", ") + (c == "noCity" ? "" : " (" + c + ")");
  1081. }).join(" ; ");
  1082. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  1083. var closureDetails = {reason:this.reason, direction:this.direction == "A to B" ? sc.DIRECTION.A_TO_B : this.direction == "B to A" ? sc.DIRECTION.B_TO_A : sc.DIRECTION.TWO_WAY, startDate:this.startDate, endDate:this.endDate, location:closureLocation, permanent:this.permanent == "Yes", segments:segs};
  1084. if (this.eventId != null) {
  1085. closureDetails.eventId = this.eventId;
  1086. }
  1087. WMEAC.addClosure(closureDetails, successHandler, failureHandler);
  1088. }
  1089. };
  1090. this.removeInWME = function(successHandler, failureHandler) {
  1091. var segs = WMEAC.segmentsIDsToSegments(this.segIDs);
  1092. segs = segs.filter(function(seg) {
  1093. return seg.isAllowed(seg.PERMISSIONS.EDIT_CLOSURES);
  1094. });
  1095. var allClosuresToRemove = [];
  1096. var countToMatch = this.segIDs.length * (this.direction == "TWO WAY" ? 2 : 1);
  1097. segs.forEach(function(s) {
  1098. var that = this;
  1099. var closures = Waze.model.roadClosures.getObjectArray(function(c) {
  1100. return c.startDate == that.startDate && c.endDate == that.endDate && c.reason.trim() == that.reason && c.segID == s.attributes.id && c.permanent == (that.permanent == "Yes");
  1101. });
  1102. if (this.direction == "TWO WAY" || this.direction == "A to B" && closures.length == 1 && closures[0].forward == true || this.direction == "B to A" && closures.length == 1 && closures[0].forward == false) {
  1103. allClosuresToRemove = allClosuresToRemove.concat(closures);
  1104. }
  1105. }, this);
  1106. if (allClosuresToRemove.isEmpty()) {
  1107. failureHandler([{attributes:{details:"No segment. Check permissions or existence."}}]);
  1108. } else {
  1109. WMEAC.removeClosure(allClosuresToRemove, successHandler, failureHandler);
  1110. }
  1111. };
  1112. };
  1113. WMEAC.buildClosuresListFromRecurringUI = function() {
  1114. var list = [];
  1115. var rangeStartDate = new Date($("#wmeac-advanced-closure-dialog-rangestartdate").val());
  1116. if (!WMEAC.isValidDate(rangeStartDate)) {
  1117. return {list:list, error:"Range start date is not valid"};
  1118. }
  1119. var rangeEndDate = new Date($("#wmeac-advanced-closure-dialog-rangeenddate").val());
  1120. if (!WMEAC.isValidDate(rangeEndDate)) {
  1121. return {list:list, error:"Range end date is not valid"};
  1122. }
  1123. if (rangeEndDate < rangeStartDate) {
  1124. return {list:list, error:"Range end date is before range start date"};
  1125. }
  1126. var dD = parseInt($("#wmeac-advanced-closure-dialog-duration-day").val());
  1127. if (isNaN(dD) || dH < 0) {
  1128. return {list:list, error:"Duration days is invalid"};
  1129. }
  1130. var dH = parseInt($("#wmeac-advanced-closure-dialog-durationtime").val().split(":")[0]);
  1131. var dM = parseInt($("#wmeac-advanced-closure-dialog-durationtime").val().split(":")[1]);
  1132. if (dD == 0 && dH == 0 && dM == 0) {
  1133. return {list:list, error:"Duration is null"};
  1134. }
  1135. var rangeStartTimeM = 0;
  1136. var rangeEndTimeM = 1440;
  1137. var rangeEndDateTime = rangeEndDate.clone();
  1138. rangeEndDateTime.addMinutes(rangeEndTimeM);
  1139. var startTimeM = $("#wmeac-advanced-closure-dialog-starttime").val().split(":").map(function(e) {
  1140. return parseInt(e);
  1141. }).reduce(function(p, c, i) {
  1142. return p * 60 + c;
  1143. });
  1144. if ($("#wmeac-advanced-closure-dialog-tabrepeat").attr("class").indexOf("active") != -1) {
  1145. var ntimes = parseInt($("#wmeac-advanced-closure-dialog-repeat-ntimes").val());
  1146. if (isNaN(ntimes) || ntimes < 1) {
  1147. return {list:list, error:"Repeat count is invalid"};
  1148. }
  1149. var evD = parseInt($("#wmeac-advanced-closure-dialog-repeat-every-day").val());
  1150. if (isNaN(evD) || evD < 0) {
  1151. return {list:list, error:"Repeat every day is invalid"};
  1152. }
  1153. var evH = parseInt($("#wmeac-advanced-closure-dialog-repeat-every-hour").val());
  1154. if (isNaN(evH) || evH < 0) {
  1155. return {list:list, error:"Repeat every hour is invalid"};
  1156. }
  1157. var evM = parseInt($("#wmeac-advanced-closure-dialog-repeat-every-minute").val());
  1158. if (isNaN(evM) || evM < 0 || evM >= 60) {
  1159. return {list:list, error:"Repeat every minute is invalid"};
  1160. }
  1161. if (evD * 1440 + evH * 60 + evM < dD * 1440 + dH * 60 + dM) {
  1162. return {list:list, error:"Repeat must be greater than duration"};
  1163. }
  1164. var firstDateTimeStart = rangeStartDate.clone();
  1165. if (startTimeM < rangeStartTimeM) {
  1166. firstDateTimeStart.addDays(1);
  1167. }
  1168. firstDateTimeStart.setMinutes(startTimeM);
  1169. var firstDateTimeEnd = firstDateTimeStart.clone();
  1170. firstDateTimeEnd.addMinutes(dD * 1440 + dH * 60 + dM);
  1171. for (var i = 0;i < ntimes;i++) {
  1172. var start = firstDateTimeStart.clone();
  1173. start.addMinutes((evD * 1440 + evH * 60 + evM) * i);
  1174. var end = start.clone();
  1175. end.addMinutes(dD * 1440 + dH * 60 + dM);
  1176. if (end > rangeEndDateTime) {
  1177. break;
  1178. }
  1179. list.push({start:WMEAC.dateToClosureStr(start), end:WMEAC.dateToClosureStr(end)});
  1180. }
  1181. return {list:list, error:""};
  1182. } else {
  1183. if ($("#wmeac-advanced-closure-dialog-tabeach").attr("class").indexOf("active") != -1) {
  1184. var dow = WMEAC.daysOfWeek.map(function(e, i) {
  1185. return $("#wmeac-advanced-closure-dialog-each-" + i).is(":checked");
  1186. });
  1187. var dayCount = Math.ceil((rangeEndDate - rangeStartDate + 1) / 864E5);
  1188. var day0 = rangeStartDate.clone();
  1189. day0.addMinutes(startTimeM);
  1190. if (startTimeM < rangeStartTimeM) {
  1191. day0.addDays(1);
  1192. }
  1193. for (var d = 0;d < dayCount;d++) {
  1194. var start = day0.clone();
  1195. start.addMinutes(d * 1440);
  1196. if (dow[start.getUTCDay()]) {
  1197. var end = start.clone();
  1198. end.addMinutes(dD * 1440 + dH * 60 + dM);
  1199. if (end > rangeEndDateTime) {
  1200. break;
  1201. }
  1202. list.push({start:WMEAC.dateToClosureStr(start), end:WMEAC.dateToClosureStr(end)});
  1203. }
  1204. }
  1205. return {list:list, error:""};
  1206. } else {
  1207. if ($("#wmeac-advanced-closure-dialog-tabholiday").attr("class").indexOf("active") != -1) {
  1208. WMEAC.lastGeneratedHolidays.forEach(function(e, i) {
  1209. if ($("#wmeac-advanced-closure-dialog-holidays-" + i).is(":checked")) {
  1210. var start = (new Date(e.date)).addMinutes(startTimeM);
  1211. var end = start.clone();
  1212. end.addMinutes(dD * 1440 + dH * 60 + dM);
  1213. list.push({start:WMEAC.dateToClosureStr(start), end:WMEAC.dateToClosureStr(end)});
  1214. }
  1215. });
  1216. return {list:list, error:""};
  1217. } else {
  1218. return {list:list, error:"Wrong tab active"};
  1219. }
  1220. }
  1221. }
  1222. };
  1223. WMEAC.refreshClosureList = function() {
  1224. try {
  1225. var rc = WMEAC.buildClosuresListFromRecurringUI();
  1226. if (rc.error != "") {
  1227. $("#wmeac-csv-closures-preview-content").html(rc.error);
  1228. } else {
  1229. var reason = $("#wmeac-advanced-closure-dialog-reason").val();
  1230. var direction = $("#wmeac-advanced-closure-dialog-direction").val();
  1231. var directionStr = direction == 1 ? "(A &#8594; B)" : direction == 2 ? "(B &#8594; A)" : "(&#8646;)";
  1232. var isIT = $("#wmeac-advanced-closure-dialog-ignoretraffic").is(":checked");
  1233. var existingClosures = Waze.selectionManager.selectedItems.reduce(function(p, c, i) {
  1234. var revSegs = Waze.selectionManager.getReversedSegments();
  1235. var isReversed = revSegs.hasOwnProperty(c.model.attributes.id) && revSegs[c.model.attributes.id];
  1236. var realWay = isReversed ? direction == 1 ? 2 : 1 : direction;
  1237. return p.concat(Waze.model.roadClosures.getObjectArray(function(e) {
  1238. return e.segID == c.model.attributes.id && (direction == 3 || e.forward && realWay == 1 || !e.forward && realWay == 2);
  1239. }));
  1240. }, []);
  1241. var mte = Waze.model.majorTrafficEvents.get($("#wmeac-advanced-closure-dialog-mteid").val());
  1242. $("#wmeac-csv-closures-preview-content").html("" + rc.list.length + " closure(s) to apply: <br>" + rc.list.map(function(e, i) {
  1243. var overlap = existingClosures.filter(function(c) {
  1244. return WMEAC.dateTimeOverlaps({startDate:e.start, endDate:e.end}, c);
  1245. }).map(function(c) {
  1246. var msg = (c.reason ? c.reason + " " : "") + "(" + c.segID + ")";
  1247. if (Waze.model.segments.objects.hasOwnProperty(c.segID) == false) {
  1248. return msg;
  1249. }
  1250. if (Waze.model.segments.objects[c.segID].attributes.primaryStreetID == null) {
  1251. return msg;
  1252. }
  1253. if (Waze.model.streets.objects.hasOwnProperty(Waze.model.segments.objects[c.segID].attributes.primaryStreetID) == false) {
  1254. return msg;
  1255. }
  1256. var street = Waze.model.streets.objects[Waze.model.segments.objects[c.segID].attributes.primaryStreetID];
  1257. if (!street.isEmpty) {
  1258. msg = street.name + ": " + msg;
  1259. }
  1260. return msg;
  1261. });
  1262. var mteOK = !(mte && (new Date(e.start) < new Date(mte.attributes.startDate) || new Date(e.end) > new Date(mte.attributes.endDate)));
  1263. return reason + ": " + e.start + " &#8594; " + e.end + " " + directionStr + ' <i class="fa fa-car' + (isIT ? " slashed" : "") + '"></i>' + (overlap.length != 0 ? ' <i title="Warning: overlap on existing closure!\n' + overlap.join("\n") + '" class="fa fa-exclamation-circle" style="color: orange"></i>' : "") + (mteOK ? "" : ' <i title="Warning: closure dates not inside MTE date!" class="fa fa-exclamation-circle" style="color: orange"></i>') + ' <span id="wmeac-advanced-closure-dialog-preview-' +
  1264. i + '"></span>';
  1265. }).join("<br>"));
  1266. }
  1267. } catch (e) {
  1268. WMEAC.logError("Error while refreshing closure list: ", e);
  1269. }
  1270. };
  1271. WMEAC.refreshMTEList = function() {
  1272. var currentMTEid = $("#wmeac-advanced-closure-dialog-mteid").val();
  1273. var rangeStart = new Date($("#wmeac-advanced-closure-dialog-rangestartdate").val());
  1274. var rangeEnd = new Date($("#wmeac-advanced-closure-dialog-rangeenddate").val());
  1275. var options = [{name:"none", value:""}];
  1276. $("#wmeac-advanced-closure-dialog-mteid").empty();
  1277. if (WMEAC.isValidDate(rangeStart) && WMEAC.isValidDate(rangeEnd)) {
  1278. rangeEnd.addDays(1);
  1279. Waze.model.majorTrafficEvents.getObjectArray(function(mte) {
  1280. return WMEAC.dateTimeOverlaps({startDate:rangeStart, endDate:rangeEnd}, {startDate:new Date(mte.attributes.startDate), endDate:new Date(mte.attributes.endDate)});
  1281. }).forEach(function(mte) {
  1282. options.push({name:mte.attributes.names[0].value, value:mte.attributes.id});
  1283. });
  1284. }
  1285. options.forEach(function(o) {
  1286. var el = WMEAC.createElement({type:"option"});
  1287. el.setAttribute("value", o.value);
  1288. if (currentMTEid == o.value) {
  1289. el.setAttribute("selected", "");
  1290. }
  1291. el.innerHTML = o.name;
  1292. $("#wmeac-advanced-closure-dialog-mteid").append(el);
  1293. });
  1294. if (options.length > 1) {
  1295. $("#wmeac-advanced-closure-dialog-mteid").removeAttr("disabled");
  1296. } else {
  1297. $("#wmeac-advanced-closure-dialog-mteid").attr("disabled", "");
  1298. }
  1299. };
  1300. WMEAC.refreshClosureListFromSelection = function() {
  1301. try {
  1302. var currentSegClosure = $("#wmeac-advanced-closure-dialog-segclosure-list").val();
  1303. $("#wmeac-advanced-closure-dialog-segclosure-list").empty();
  1304. if (Waze.selectionManager.selectedItems.length != 0) {
  1305. var blackList = [];
  1306. Waze.model.roadClosures.getObjectArray(function(c) {
  1307. return c.segID == Waze.selectionManager.selectedItems[0].model.attributes.id;
  1308. }).sort(function(a, b) {
  1309. return new Date(a.startDate) - new Date(b.startDate);
  1310. }).forEach(function(c) {
  1311. if (blackList.indexOf(c.id) != -1) {
  1312. return;
  1313. }
  1314. var direction = c.forward ? "A to B" : "B to A";
  1315. var oppositeClosure = WMEAC.getOppositeClosure(c);
  1316. if (!oppositeClosure.isEmpty()) {
  1317. direction = "Two way";
  1318. blackList.push(oppositeClosure[0].id);
  1319. }
  1320. var el = WMEAC.createElement({type:"option"});
  1321. el.setAttribute("value", c.id);
  1322. if (currentSegClosure == c.id) {
  1323. el.setAttribute("selected", "");
  1324. }
  1325. el.innerHTML = c.reason.trim() + " " + direction + " " + c.startDate + "&#8594;" + c.endDate;
  1326. $("#wmeac-advanced-closure-dialog-segclosure-list").append(el);
  1327. });
  1328. }
  1329. } catch (e) {
  1330. WMEAC.logError("Error while refreshing closure list from selection: ", e);
  1331. }
  1332. };
  1333. WMEAC.abbrToISO3166_1alpha2 = function(abbr) {
  1334. switch(abbr) {
  1335. case "GM":
  1336. return "DE";
  1337. break;
  1338. case "BU":
  1339. return "BG";
  1340. break;
  1341. case "EZ":
  1342. return "CZ";
  1343. break;
  1344. case "SP":
  1345. return "ES";
  1346. break;
  1347. case "UK":
  1348. return "GB";
  1349. break;
  1350. case "LO":
  1351. return "SK";
  1352. break;
  1353. default:
  1354. return abbr;
  1355. break;
  1356. }
  1357. return abbr;
  1358. };
  1359. WMEAC.getHolidays = function(options) {
  1360. var holidays = [];
  1361. var currentCountryIndex = 0;
  1362. var rangeStart = new Date(options.rangeStart);
  1363. var rangeEnd = (new Date(options.rangeEnd)).addDays(1);
  1364. var years = [];
  1365. for (y = parseInt(options.rangeStart.substring(0, 4));y <= parseInt(options.rangeEnd.substring(0, 4));y++) {
  1366. years.push(y);
  1367. }
  1368. var currentYearIndex = 0;
  1369. var tmp1 = function downloadNext() {
  1370. if (currentCountryIndex >= options.countries.length) {
  1371. if (options.handlerFinished) {
  1372. holidays.sort(function(a, b) {
  1373. return new Date(a.date) - new Date(b.date);
  1374. });
  1375. holidays = holidays.filter(function(h, i) {
  1376. if (i != 0) {
  1377. if (holidays[i - 1].date == h.date) {
  1378. holidays[i - 1].name += " / " + h.name;
  1379. holidays[i - 1].country += " / " + h.country;
  1380. return false;
  1381. }
  1382. }
  1383. return true;
  1384. });
  1385. options.handlerFinished(holidays);
  1386. return;
  1387. }
  1388. }
  1389. window.WMEAC_downloadHelper.add("https://holidayapi.com/v1/holidays?key=ca1a7925-0045-47da-bcf6-ee0de583e384&country=" + WMEAC.abbrToISO3166_1alpha2(options.countries[currentCountryIndex]) + "&year=" + years[currentYearIndex], function(data) {
  1390. if (data.status == "success") {
  1391. try {
  1392. nextHoliday = JSON.parse(data.data);
  1393. if (nextHoliday.hasOwnProperty("holidays")) {
  1394. for (var hd in nextHoliday.holidays) {
  1395. if (!nextHoliday.holidays.hasOwnProperty(hd)) {
  1396. continue;
  1397. }
  1398. if (nextHoliday.holidays[hd].length == 0) {
  1399. continue;
  1400. }
  1401. var name = _.pluck(nextHoliday.holidays[hd], "name").join(" / ");
  1402. var h = nextHoliday.holidays[hd][0];
  1403. var d = new Date(h.date);
  1404. if (d >= rangeStart && d < rangeEnd) {
  1405. holidays.push({date:h.date, name:name, country:h.country});
  1406. }
  1407. }
  1408. currentYearIndex++;
  1409. if (currentYearIndex < years.length) {
  1410. window.setTimeout(downloadNext);
  1411. return;
  1412. }
  1413. }
  1414. } catch (e) {
  1415. WMEAC.log("Error while getting holiday from server!", e);
  1416. WMEAC.log("data", data.data);
  1417. }
  1418. currentCountryIndex++;
  1419. currentYearIndex = 0;
  1420. window.setTimeout(downloadNext);
  1421. }
  1422. });
  1423. };
  1424. tmp1();
  1425. };
  1426. WMEAC.addClosure = function(options, successHandler, failureHandler) {
  1427. if (options && options.hasOwnProperty("segments") && options.hasOwnProperty("reason") && options.hasOwnProperty("direction") && options.hasOwnProperty("startDate") && options.hasOwnProperty("endDate") && options.hasOwnProperty("location") && options.hasOwnProperty("permanent")) {
  1428. WMEAC.log("Addinf closure: ", options);
  1429. var fail = function(e) {
  1430. return function(f) {
  1431. if (failureHandler) {
  1432. failureHandler(f);
  1433. } else {
  1434. WMEAC.log("Failed to create closure:", f);
  1435. }
  1436. };
  1437. };
  1438. var done = function(e) {
  1439. return function(f) {
  1440. if (successHandler) {
  1441. successHandler(f);
  1442. } else {
  1443. WMEAC.log("Closure successful:", f);
  1444. }
  1445. };
  1446. };
  1447. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  1448. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  1449. var t = {};
  1450. var closureDetails = {reason:options.reason + String.fromCharCode(160), direction:options.direction, startDate:options.startDate, endDate:options.endDate, location:options.location, permanent:options.permanent, segments:options.segments, reverseSegments:{}};
  1451. if (options.hasOwnProperty("eventId") && options.eventId != null) {
  1452. closureDetails.eventId = options.eventId;
  1453. }
  1454. var c = new sc(closureDetails);
  1455. t.actions = [cab.add(c)];
  1456. W.controller.save(t).done(done()).fail(fail());
  1457. return true;
  1458. }
  1459. return false;
  1460. };
  1461. WMEAC.addClosureListFromSelection = function(closureList, successHandler, failureHandler, endHandler, i) {
  1462. if (i >= closureList.length) {
  1463. WMEAC.reloadClosuresLayer(function() {
  1464. if (endHandler) {
  1465. endHandler();
  1466. }
  1467. });
  1468. return;
  1469. }
  1470. var c = closureList[i];
  1471. var fail = function(e) {
  1472. return function(f) {
  1473. if (failureHandler) {
  1474. var details = [];
  1475. f.forEach(function(err) {
  1476. if (err.hasOwnProperty("attributes") && err.attributes.hasOwnProperty("details")) {
  1477. details.push(err.attributes.details);
  1478. }
  1479. });
  1480. failureHandler(i, details.join(" | "));
  1481. } else {
  1482. WMEAC.log("Failed to create closure:", f);
  1483. }
  1484. WMEAC.addClosureListFromSelection(closureList, successHandler, failureHandler, endHandler, i + 1);
  1485. };
  1486. };
  1487. var done = function(e) {
  1488. return function(f) {
  1489. if (successHandler) {
  1490. successHandler(i, "OK");
  1491. } else {
  1492. WMEAC.log("Closure successful:", f);
  1493. }
  1494. WMEAC.addClosureListFromSelection(closureList, successHandler, failureHandler, endHandler, i + 1);
  1495. };
  1496. };
  1497. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  1498. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  1499. var t = {};
  1500. var segs = _.pluck(Waze.selectionManager.selectedItems, "model");
  1501. var cityStreets = WMEAC.getCityStreetsFromSegmentSet(segs);
  1502. var closureLocation = Object.keys(cityStreets).map(function(c) {
  1503. return Object.keys(cityStreets[c]).map(function(s) {
  1504. if (s == "noStreet") {
  1505. return I18n.translations[I18n.locale].edit.address.no_street;
  1506. }
  1507. return s;
  1508. }).join(", ") + (c == "noCity" ? "" : " (" + c + ")");
  1509. }).join(" ; ");
  1510. var closureDetails = {reason:closureList[i].reason + String.fromCharCode(160), direction:closureList[i].direction, startDate:closureList[i].startDate, endDate:closureList[i].endDate, location:closureLocation, permanent:closureList[i].permanent, segments:segs, reverseSegments:Waze.selectionManager.getReversedSegments()};
  1511. if (closureList[i].hasOwnProperty("eventId") && closureList[i].eventId != null) {
  1512. closureDetails.eventId = closureList[i].eventId;
  1513. }
  1514. var c = new sc(closureDetails);
  1515. t.actions = [cab.add(c)];
  1516. W.controller.save(t).done(done()).fail(fail());
  1517. };
  1518. WMEAC.addClosureFromSelection = function(options, successHandler, failureHandler) {
  1519. if (options && options.hasOwnProperty("reason") && options.hasOwnProperty("direction") && options.hasOwnProperty("startDate") && options.hasOwnProperty("endDate") && options.hasOwnProperty("location") && options.hasOwnProperty("permanent")) {
  1520. WMEAC.log("Addinf closure: ", options);
  1521. var fail = function(e) {
  1522. return function(f) {
  1523. if (failureHandler) {
  1524. failureHandler(f);
  1525. } else {
  1526. WMEAC.log("Failed to create closure:", f);
  1527. }
  1528. };
  1529. };
  1530. var done = function(e) {
  1531. return function(f) {
  1532. if (successHandler) {
  1533. successHandler(f);
  1534. } else {
  1535. WMEAC.log("Closure successful:", f);
  1536. }
  1537. };
  1538. };
  1539. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  1540. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  1541. var t = {};
  1542. var segs = _.pluck(Waze.selectionManager.selectedItems, "model");
  1543. var closureDetails = {reason:options.reason + String.fromCharCode(160), direction:options.direction, startDate:options.startDate, endDate:options.endDate, location:options.location, permanent:options.permanent, segments:segs, reverseSegments:Waze.selectionManager.getReversedSegments()};
  1544. if (options.hasOwnProperty("eventId") && options.eventId != null) {
  1545. closureDetails.eventId = options.eventId;
  1546. }
  1547. var c = new sc(closureDetails);
  1548. t.actions = [cab.add(c)];
  1549. W.controller.save(t).done(done()).fail(fail());
  1550. return true;
  1551. }
  1552. return false;
  1553. };
  1554. WMEAC.removeClosure = function(closures, successHandler, failureHandler) {
  1555. var fail = function(e) {
  1556. return function(f) {
  1557. if (failureHandler) {
  1558. failureHandler(f);
  1559. } else {
  1560. WMEAC.log("Failed to delete closure:", f);
  1561. }
  1562. };
  1563. };
  1564. var done = function(e) {
  1565. return function(f) {
  1566. if (successHandler) {
  1567. successHandler(f);
  1568. } else {
  1569. WMEAC.log("Closure deletion successful:", f);
  1570. }
  1571. };
  1572. };
  1573. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  1574. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  1575. var t = {};
  1576. var c = new sc({closures:[].concat(closures)});
  1577. t.actions = [cab["delete"](c)];
  1578. W.controller.save(t).done(done()).fail(fail());
  1579. return true;
  1580. };
  1581. WMEAC.save = function() {
  1582. WMEAC.log("save data...");
  1583. localStorage.WMEAC = JSON.stringify({presets:WMEAC.presets});
  1584. };
  1585. WMEAC.load = function() {
  1586. try {
  1587. var saved = JSON.parse(localStorage.WMEAC);
  1588. WMEAC.presets = saved.presets;
  1589. WMEAC.log("presets", WMEAC.presets);
  1590. } catch (err) {
  1591. WMEAC.log("Error while loading data from storage: ", err);
  1592. }
  1593. };
  1594. WMEAC.parseCSV = function(csvString) {
  1595. if (csvString != null) {
  1596. var csvArray = WMEAC.CSVtoArray(csvString);
  1597. WMEAC.log("CSV as array:", csvArray);
  1598. var isValid = WMEAC.csv[0].validate(csvArray);
  1599. if (isValid.isValid) {
  1600. WMEAC.log("CSV is valid!");
  1601. var closures = WMEAC.csv[0].filter(csvArray).map(function(e, i) {
  1602. return {action:e[0], closure:new WMEAC.ClassClosure({reason:e[1], startDate:e[2], endDate:e[3], direction:e[4], segIDs:e[6], lonlat:e[7], permanent:e[5], zoom:e[8], id:i, eventId:e[9], comment:e.length == 11 ? e[10] : ""}), UI:null};
  1603. });
  1604. WMEAC.log("Closure list:", closures);
  1605. WMEAC.csvCurrentClosureList = closures;
  1606. var listUI = WMEAC.getId("wmeac-csv-closures-list-elts");
  1607. WMEAC.removeChildElements(listUI);
  1608. closures.forEach(function(c) {
  1609. c.UI = WMEAC.buildInlineClosureUI(c.closure, c.action);
  1610. listUI.appendChild(c.UI);
  1611. });
  1612. WMEAC.csvShowList(true);
  1613. WMEAC.csvAddLog("CSV parse successful\n");
  1614. return true;
  1615. } else {
  1616. WMEAC.log("CSV is NOT valid!:" + isValid.feedBack + "\n");
  1617. WMEAC.csvAddLog(isValid.feedBack + "\n");
  1618. WMEAC.csvShowList(false);
  1619. WMEAC.csvCurrentClosureList = null;
  1620. return false;
  1621. }
  1622. return false;
  1623. }
  1624. return false;
  1625. };
  1626. WMEAC.CSVFileChanged = function(evt) {
  1627. var files = evt.target.files;
  1628. for (var i = 0, f;f = files[i];i++) {
  1629. var reader = new FileReader;
  1630. reader.onload = function(theFile) {
  1631. return function(e) {
  1632. WMEAC.log("import CSV file read");
  1633. WMEAC.csvClearLog();
  1634. if (WMEAC.parseCSV(e.target.result)) {
  1635. WMEAC.csvCurrentBatchClosureList = WMEAC.csvCurrentClosureList.slice();
  1636. }
  1637. };
  1638. }(f);
  1639. reader.readAsText(f);
  1640. }
  1641. this.value = null;
  1642. WMEAC.getId("wmeac-csv-closures-controls-check").checked = false;
  1643. };
  1644. WMEAC.ClassCSV = function(options) {
  1645. this.isValid = false;
  1646. if (options.hasOwnProperty("version")) {
  1647. this.version = options.version;
  1648. } else {
  1649. return;
  1650. }
  1651. if (options.hasOwnProperty("regexpValidation")) {
  1652. this.regexpValidation = options.regexpValidation;
  1653. } else {
  1654. return;
  1655. }
  1656. this.isValid = true;
  1657. this.validate = function(data) {
  1658. var regexps = this.regexpValidation;
  1659. var feedBack = "";
  1660. this.filter(data).forEach(function(line, l) {
  1661. var isLineValid = line.reduce(function(stillValid, cell, i) {
  1662. var isCellValid = cell.match(regexps[i]) != null;
  1663. if (!isCellValid) {
  1664. feedBack += "Error while parsing line " + l + " cell " + i + ': "' + cell + '" in line ' + line.join(",");
  1665. }
  1666. return stillValid && isCellValid;
  1667. }, true);
  1668. }, this);
  1669. return {isValid:feedBack == "", feedBack:feedBack};
  1670. };
  1671. this.filter = function(data) {
  1672. return data.filter(function(line) {
  1673. return line.length >= 1 && ["add", "remove"].indexOf(line[0]) != -1;
  1674. });
  1675. };
  1676. };
  1677. WMEAC.csv.push(new WMEAC.ClassCSV({version:1, regexpValidation:[/.*/, /.*/, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, /(^A to B$)|(^B to A$)|(^TWO WAY$)/, /(Yes)|(No)/, /^(\d+(;|$))+/, /(lon=(-?\d+\.?\d*)&lat=(-?\d+\.?\d*))|(lat=(-?\d+\.?\d*)&lon=(-?\d+\.?\d*))/, /^\d$/, /(^$)|(^-?\d+\.-?\d+\.-?\d+$)/]}));
  1678. WMEAC.buildInlineClosureUI = function(closure, action) {
  1679. var liElt = WMEAC.createElement({type:"li", className:"wmeac-csv-closures-list-" + action});
  1680. liElt.setAttribute("closureID", closure.id);
  1681. liElt.innerHTML = '<div class="wmeac-csv-closures-list-col-action"><input type="checkbox" /></div> <div class="wmeac-csv-closures-list-col-lr"><div title="' + closure.reason + '">' + closure.reason + '</div><div title="' + closure.comment + '">' + closure.comment + '</div></div> <div class="wmeac-csv-closures-list-col-dates"><div title="' + closure.startDate + '">' + closure.startDate + '</div><div title="' + closure.endDate + '">' + closure.endDate + '</div></div> <div class="wmeac-csv-closures-list-col-dir">' +
  1682. (closure.direction == "A to B" ? "A&#8594;B" : closure.direction == "B to A" ? "B&#8594;A" : "A&#8596;B") + '</div> <div class="wmeac-csv-closures-list-col-it"><input type="checkbox" ' + (closure.permanent == "Yes" ? "checked" : "") + ' disabled/></div> <div class="wmeac-csv-closures-list-col-target"><a href="#" title="Go there!"><i class="fa fa-crosshairs"></i></a></div> <div class="wmeac-csv-closures-list-col-apply"><a href="#" title="Apply action of this closure"><i class="fa fa-arrow-circle-right"></i></a></div> <div class="wmeac-csv-closures-minilog" style="display: block;">' +
  1683. (action == "add" ? "Ready to apply" : action == "remove" ? "Ready to remove" : "") + "</div>";
  1684. liElt.children[5].children[0].addEventListener("click", function(e) {
  1685. WMEAC.csvClearLog();
  1686. var cid = parseInt(e.target.parentNode.parentNode.parentNode.getAttribute("closureID"));
  1687. var closure = WMEAC.csvCurrentClosureList.find(function(c) {
  1688. return c.closure.id == cid;
  1689. });
  1690. WMEAC.log("Closure to target:", closure);
  1691. var xy = OpenLayers.Layer.SphericalMercator.forwardMercator(closure.closure.lonlat.lon, closure.closure.lonlat.lat);
  1692. Waze.map.setCenter(xy, closure.closure.zoom);
  1693. var tmp3 = function selectSegments() {
  1694. WMEAC.log("Now select segments...");
  1695. var segs = WMEAC.segmentsIDsToSegments(closure.closure.segIDs);
  1696. if (segs.length != closure.closure.segIDs.length) {
  1697. if (segs.length == 0) {
  1698. WMEAC.csvAddLog("No segment found: " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  1699. WMEAC.setCSVMiniLog(closure, "Selection failed: no segment found", 3);
  1700. } else {
  1701. WMEAC.csvAddLog("Partial selection (" + segs.length + "/" + closure.closure.segIDs.length + "): " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  1702. WMEAC.setCSVMiniLog(closure, "Partial selection: " + segs.length + "/" + closure.closure.segIDs.length, 2);
  1703. }
  1704. alert("Warning: missing segments.\nFound " + segs.length + "/" + closure.closure.segIDs.length + " segment(s)");
  1705. } else {
  1706. WMEAC.csvAddLog("Selection ok (" + segs.length + "): " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  1707. WMEAC.setCSVMiniLog(closure, "Selection OK: " + segs.length, 1);
  1708. }
  1709. if (segs.length != 0) {
  1710. Waze.selectionManager.select(segs);
  1711. var tmp = function selectionReady() {
  1712. if (Waze.selectionManager.selectedItems.isEmpty()) {
  1713. window.setTimeout(selectionReady, 500);
  1714. } else {
  1715. $('a[href="#segment-edit-closures"]').click();
  1716. }
  1717. };
  1718. window.setTimeout(tmp, 500);
  1719. }
  1720. };
  1721. var tmp2 = function readyToSelect() {
  1722. WMEAC.log("Test if ready to select...");
  1723. if (WMEAC.pendingOps == true) {
  1724. WMEAC.log("Not yet. Waiting for WME...");
  1725. window.setTimeout(readyToSelect, 500);
  1726. } else {
  1727. tmp3();
  1728. }
  1729. };
  1730. var tmp1 = function mapMovedEnd() {
  1731. WMEAC.log("Test if roads are reloaded...");
  1732. if (WMEAC.pendingOps == true) {
  1733. WMEAC.log("Not yet. Waiting for WME...");
  1734. window.setTimeout(mapMovedEnd, 500);
  1735. } else {
  1736. WMEAC.reloadRoadLayer();
  1737. tmp2();
  1738. }
  1739. };
  1740. window.setTimeout(tmp1, 500);
  1741. });
  1742. liElt.children[6].children[0].addEventListener("click", function(e) {
  1743. WMEAC.csvClearLog();
  1744. var liElt = e.target.parentNode.parentNode.parentNode;
  1745. var cid = parseInt(liElt.getAttribute("closureID"));
  1746. var closure = WMEAC.csvCurrentClosureList.find(function(c) {
  1747. return c.closure.id == cid;
  1748. });
  1749. WMEAC.log("Closure to apply:", closure);
  1750. WMEAC.csvApplyClosure(closure, null);
  1751. });
  1752. return liElt;
  1753. };
  1754. WMEAC.csvApplyClosure = function(closure, handler) {
  1755. var xy = OpenLayers.Layer.SphericalMercator.forwardMercator(closure.closure.lonlat.lon, closure.closure.lonlat.lat);
  1756. Waze.map.setCenter(xy, closure.closure.zoom);
  1757. function applySuccess(evt) {
  1758. WMEAC.csvAddLog("Closure OK: " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  1759. closure.UI.className = "wmeac-csv-closures-list-done";
  1760. WMEAC.setCSVMiniLog(closure, "OK", 1);
  1761. handler && handler(true);
  1762. }
  1763. function applyFailure(evt) {
  1764. var details = "";
  1765. evt.forEach(function(err) {
  1766. if (err.hasOwnProperty("attributes") && err.attributes.hasOwnProperty("details")) {
  1767. details += err.attributes.details + "\n";
  1768. }
  1769. });
  1770. WMEAC.csvAddLog("Closure KO: " + closure.closure.comment + " (" + closure.closure.reason + ")\n" + details + "\n");
  1771. WMEAC.setCSVMiniLog(closure, "KO: " + details, 3);
  1772. closure.UI.className = "wmeac-csv-closures-list-failed";
  1773. handler && handler(false);
  1774. }
  1775. var tmp3 = function applyClosure() {
  1776. WMEAC.log("Now apply closure...");
  1777. if (closure.action == "add") {
  1778. closure.closure.applyInWME(applySuccess, applyFailure);
  1779. } else {
  1780. if (closure.action == "remove") {
  1781. closure.closure.removeInWME(applySuccess, applyFailure);
  1782. }
  1783. }
  1784. };
  1785. var tmp2 = function readyToApply() {
  1786. WMEAC.log("Test if ready to apply...");
  1787. if (WMEAC.pendingOps == true) {
  1788. WMEAC.log("Not yet. Waiting for WME...");
  1789. window.setTimeout(readyToApply, 500);
  1790. } else {
  1791. tmp3();
  1792. }
  1793. };
  1794. var tmp1 = function mapMovedEnd() {
  1795. WMEAC.log("Test if roads are reloaded...");
  1796. if (WMEAC.pendingOps == true) {
  1797. WMEAC.log("Not yet. Waiting for WME...");
  1798. window.setTimeout(mapMovedEnd, 500);
  1799. } else {
  1800. WMEAC.reloadRoadLayer();
  1801. tmp2();
  1802. }
  1803. };
  1804. window.setTimeout(tmp1, 1500);
  1805. };
  1806. WMEAC.csvAddLog = function(text) {
  1807. var divLog = WMEAC.getId("wmeac-csv-closures-log");
  1808. divLog.innerHTML += text.replace(/\n/g, "<br>");
  1809. };
  1810. WMEAC.csvClearLog = function() {
  1811. var divLog = WMEAC.getId("wmeac-csv-closures-log");
  1812. divLog.innerHTML = "";
  1813. };
  1814. WMEAC.csvShowList = function(show) {
  1815. var divList = WMEAC.getId("wmeac-csv-closures");
  1816. divList.style.display = show ? "block" : "none";
  1817. };
  1818. WMEAC.csvCheckAllSegments = function(i) {
  1819. if (i == -1) {
  1820. WMEAC.pb.update(0);
  1821. WMEAC.pb.show(true);
  1822. window.setTimeout(function() {
  1823. WMEAC.csvCheckAllSegments(0);
  1824. });
  1825. return;
  1826. }
  1827. var continueSegmentCheck = function() {
  1828. window.setTimeout(function() {
  1829. WMEAC.csvCheckAllSegments(i + 1);
  1830. });
  1831. };
  1832. if (i < WMEAC.csvCurrentBatchClosureList.length) {
  1833. var currentClosure = WMEAC.csvCurrentBatchClosureList[i];
  1834. WMEAC.pb.update(i * 100 / WMEAC.csvCurrentBatchClosureList.length);
  1835. WMEAC.pb.info("Scanning segments. please wait...");
  1836. var c = OpenLayers.Layer.SphericalMercator.forwardMercator(currentClosure.closure.lonlat.lon, currentClosure.closure.lonlat.lat);
  1837. var b = Waze.map.calculateBounds();
  1838. var zoomRatio = Math.pow(2, Waze.map.zoom - currentClosure.closure.zoom);
  1839. var w = b.getWidth() * Waze.controller.ratio * zoomRatio;
  1840. var h = b.getHeight() * Waze.controller.ratio * zoomRatio;
  1841. var tileBounds = new OpenLayers.Bounds(c.lon - w / 2, c.lat - h / 2, c.lon + w / 2, c.lat + h / 2);
  1842. tileBounds = tileBounds.transform(Waze.map.getProjectionObject(), new OpenLayers.Projection("EPSG:4326")).toBBOX();
  1843. var roadTypes = Waze.model.repos.segments.zoomToRoadType[currentClosure.closure.zoom] == -1 ? _.range(1, 22) : Waze.model.repos.segments.zoomToRoadType[currentClosure.closure.zoom];
  1844. var WFVS = require("Waze/Feature/Vector/Segment");
  1845. var aseg = new WFVS;
  1846. var req = new XMLHttpRequest;
  1847. req.open("GET", document.location.protocol + "//" + document.location.host + Waze.Config.api_base + "/Features?roadTypes=" + roadTypes.join("%2C") + "&problemFilter=0&mapUpdateRequestFilter=0&roadClosures=true&userAreas=false&managedAreas=false&majorTrafficEvents=false&bbox=" + encodeURIComponent(tileBounds) + "&language=en", true);
  1848. req.onreadystatechange = function(e) {
  1849. if (req.readyState == 4) {
  1850. if (req.status == 200) {
  1851. try {
  1852. var data = JSON.parse(req.responseText);
  1853. WMEAC.log("data", data);
  1854. var existingSegs = currentClosure.closure.segIDs.filter(function(sid) {
  1855. return data.segments.objects.find(function(seg) {
  1856. return sid == seg.id;
  1857. }) != null;
  1858. });
  1859. var editableClosuresSegs = currentClosure.closure.segIDs.filter(function(sid) {
  1860. return data.segments.objects.find(function(seg) {
  1861. return sid == seg.id && seg.permissions & aseg.PERMISSIONS.EDIT_CLOSURES;
  1862. }) != null;
  1863. });
  1864. var overlaps = [];
  1865. var existingClosures = existingSegs.forEach(function(sid) {
  1866. var cl = data.roadClosures.objects.filter(function(c) {
  1867. return c.segID == sid;
  1868. });
  1869. console.log("cl", cl);
  1870. cl.forEach(function(c) {
  1871. var forwardMustBe = currentClosure.closure.direction == "A to B" ? true : currentClosure.closure.direction == "B to A" ? false : null;
  1872. console.log("forwardMustBe", forwardMustBe);
  1873. console.log("dateTimeOverlaps", currentClosure.closure);
  1874. console.log("dateTimeOverlaps", c);
  1875. if (WMEAC.dateTimeOverlaps(currentClosure.closure, c)) {
  1876. if (forwardMustBe == null || forwardMustBe == c.forward) {
  1877. var segment = data.segments.objects.find(function(seg) {
  1878. return seg.id == sid;
  1879. });
  1880. var streetName = null;
  1881. if (segment && segment.primaryStreetID != null) {
  1882. var street = data.streets.objects.find(function(st) {
  1883. return st.id == segment.primaryStreetID;
  1884. });
  1885. if (street && street.name != null) {
  1886. streetName = street.name;
  1887. }
  1888. }
  1889. overlaps.push("Overlap with " + c.reason + (streetName != null ? " :" + streetName : "") + " (" + sid + ")");
  1890. }
  1891. }
  1892. });
  1893. });
  1894. if (existingSegs.length == currentClosure.closure.segIDs.length && editableClosuresSegs.length == currentClosure.closure.segIDs.length && overlaps.length == 0) {
  1895. WMEAC.csvAddLog("Seg check OK: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\n" + existingSegs.length + " editable seg(s) found\n");
  1896. WMEAC.setCSVMiniLog(currentClosure, "segs OK: " + existingSegs.length + " editable seg(s) found", 1);
  1897. } else {
  1898. if (existingSegs.length == currentClosure.closure.segIDs.length && editableClosuresSegs.length == currentClosure.closure.segIDs.length && overlaps.length != 0) {
  1899. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nOverlap detected on existing closures:\n" + overlaps.join("\n") + "\n");
  1900. WMEAC.setCSVMiniLog(currentClosure, "segs KO: " + overlaps.length + " overlap(s) detected", 2);
  1901. } else {
  1902. if (existingSegs.length == currentClosure.closure.segIDs.length && editableClosuresSegs.length != currentClosure.closure.segIDs.length) {
  1903. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\n" + existingSegs.length + "/" + currentClosure.closure.segIDs.length + " seg(s) found but " + (currentClosure.closure.segIDs.length - editableClosuresSegs.length) + " are not editable\n");
  1904. WMEAC.setCSVMiniLog(currentClosure, "segs KO: " + existingSegs.length + "/" + currentClosure.closure.segIDs.length + " seg(s) found and " + (currentClosure.closure.segIDs.length - editableClosuresSegs.length) + " are not editable", 2);
  1905. } else {
  1906. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\n" + existingSegs.length + "/" + currentClosure.closure.segIDs.length + " seg(s) found\n");
  1907. WMEAC.setCSVMiniLog(currentClosure, "segs KO: " + existingSegs.length + "/" + currentClosure.closure.segIDs.length + " seg(s) found", 3);
  1908. }
  1909. }
  1910. }
  1911. } catch (err) {
  1912. WMEAC.log("Failed to parse Waze's server response: " + req.responseText);
  1913. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nFailed to parse response from Waze\n");
  1914. WMEAC.setCSVMiniLog(currentClosure, "segs KO: Failed to parse response from Waze", 3);
  1915. }
  1916. } else {
  1917. WMEAC.log("Error on road tile: " + e.target.status);
  1918. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nCommunication failed with Waze\n");
  1919. WMEAC.setCSVMiniLog(currentClosure, "segs KO: Communication failed with Waze", 3);
  1920. }
  1921. continueSegmentCheck();
  1922. }
  1923. };
  1924. req.onError = function(e) {
  1925. WMEAC.log("Error on road tile: " + e.target.status);
  1926. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nCommunication failed with Waze's server\n");
  1927. WMEAC.setCSVMiniLog(currentClosure, "segs KO: Communication failed with Waze", 3);
  1928. continueSegmentCheck();
  1929. };
  1930. req.send(null);
  1931. } else {
  1932. WMEAC.pb.show(false);
  1933. }
  1934. };
  1935. WMEAC.setCSVMiniLog = function(closure, text, level) {
  1936. var c = null;
  1937. if (closure.hasOwnProperty("UI")) {
  1938. c = closure;
  1939. } else {
  1940. c = WMEAC.csvCurrentClosureList.find(function(e) {
  1941. return e.closure.id == closure.id;
  1942. });
  1943. }
  1944. if (c != null) {
  1945. c.UI.children[7].innerHTML = text;
  1946. var colors = ["#000000", "#54C600", "#FFA000", "#FF0000"];
  1947. if (arguments.length == 3) {
  1948. c.UI.children[7].style.color = colors[level];
  1949. } else {
  1950. c.UI.children[7].style.color = colors[0];
  1951. }
  1952. }
  1953. };
  1954. WMEAC.CSVCheckAll = function(check) {
  1955. WMEAC.csvCurrentClosureList.forEach(function(e) {
  1956. e.UI.children[0].children[0].checked = check;
  1957. });
  1958. };
  1959. WMEAC.CSVApplyChecked = function() {
  1960. WMEAC.csvCurrentBatchClosureList = WMEAC.csvCurrentClosureList.filter(function(e) {
  1961. return e.UI.children[0].children[0].checked;
  1962. });
  1963. WMEAC.csvClearLog();
  1964. if (WMEAC.csvCurrentBatchClosureList.isEmpty()) {
  1965. WMEAC.csvAddLog("No closure checked!\n");
  1966. } else {
  1967. WMEAC.showClosuresLayer(true);
  1968. WMEAC.pb.update(0);
  1969. WMEAC.pb.info("Applying closures. please wait...");
  1970. WMEAC.pb.show(true);
  1971. WMEAC.csvAddLog("Start to apply selected closures\n");
  1972. window.setTimeout(function() {
  1973. WMEAC.CSVBatchApply(0);
  1974. });
  1975. }
  1976. };
  1977. WMEAC.CSVBatchApply = function(i) {
  1978. WMEAC.pb.update(i * 100 / WMEAC.csvCurrentBatchClosureList.length);
  1979. if (i < WMEAC.csvCurrentBatchClosureList.length) {
  1980. if (WMEAC.csvCurrentBatchClosureList[i].action != "add" && WMEAC.csvCurrentBatchClosureList[i].action != "remove") {
  1981. WMEAC.csvAddLog("Closure KO: " + WMEAC.csvCurrentBatchClosureList[i].closure.comment + " (" + WMEAC.csvCurrentBatchClosureList[i].closure.reason + "): action " + WMEAC.csvCurrentBatchClosureList[i].action + " not supported yet\n");
  1982. WMEAC.setCSVMiniLog(WMEAC.csvCurrentBatchClosureList[i], "KO: action " + WMEAC.csvCurrentBatchClosureList[i].action + " not supported yet", 2);
  1983. WMEAC.CSVBatchApply(i + 1);
  1984. } else {
  1985. WMEAC.csvApplyClosure(WMEAC.csvCurrentBatchClosureList[i], function(success) {
  1986. if (success) {
  1987. WMEAC.csvAddLog("Closure OK: " + WMEAC.csvCurrentBatchClosureList[i].closure.comment + " (" + WMEAC.csvCurrentBatchClosureList[i].closure.reason + ")\n");
  1988. } else {
  1989. WMEAC.csvAddLog("Closure KO: " + WMEAC.csvCurrentBatchClosureList[i].closure.comment + " (" + WMEAC.csvCurrentBatchClosureList[i].closure.reason + ")\n");
  1990. }
  1991. WMEAC.CSVBatchApply(i + 1);
  1992. });
  1993. }
  1994. } else {
  1995. WMEAC.csvAddLog("Apply selected closures ended\n");
  1996. WMEAC.reloadClosuresLayer();
  1997. WMEAC.pb.show(false);
  1998. }
  1999. };
  2000. WMEAC.CSVCheckSegsChecked = function() {
  2001. WMEAC.csvClearLog();
  2002. WMEAC.csvCurrentBatchClosureList = WMEAC.csvCurrentClosureList.filter(function(e) {
  2003. return e.UI.children[0].children[0].checked;
  2004. });
  2005. if (WMEAC.csvCurrentBatchClosureList.isEmpty()) {
  2006. WMEAC.csvAddLog("No closure checked!\n");
  2007. } else {
  2008. WMEAC.csvCheckAllSegments(-1);
  2009. }
  2010. };
  2011. WMEAC.refreshHighlight = function() {
  2012. try {
  2013. var l = Waze.map.getLayersBy("uniqueName", "closures");
  2014. if (l.length == 1) {
  2015. l = l[0];
  2016. }
  2017. for (var m in l.markers) {
  2018. if (!l.markers.hasOwnProperty(m)) {
  2019. continue;
  2020. }
  2021. var marker = l.markers[m];
  2022. if (marker.model.reason && marker.model.reason.length >= 1 && marker.model.reason.charCodeAt(marker.model.reason.length - 1) == 160) {
  2023. marker.icon.$div.addClass("wmeac-hl");
  2024. }
  2025. }
  2026. } catch (e) {
  2027. WMEAC.log("Highlight error: ", e);
  2028. }
  2029. };
  2030. WMEAC.log("Ready");
  2031. WMEAC.bootstrapAC();
  2032. }
  2033. var WMEAC_Injected_script = document.createElement("script");
  2034. WMEAC_Injected_script.textContent = "" + WMEAC_Injected.toString() + " \n" + "WMEAC_Injected();";
  2035. WMEAC_Injected_script.setAttribute("type", "application/javascript");
  2036. document.body.appendChild(WMEAC_Injected_script);