WME Advanced Closures

Recurrent and imported closures in the Waze Map Editor

  1. // ==UserScript==
  2. // @name WME Advanced Closures
  3. // @version 2025.03.26.01
  4. // @description Recurrent and imported closures in the Waze Map Editor
  5. // @namespace WMEAC
  6. // @match https://www.waze.com/*editor*
  7. // @match https://beta.waze.com/*editor*
  8. // @exclude https://beta.waze.com/*user/*editor/*
  9. // @exclude https://www.waze.com/*user/*editor/*
  10. // @exclude https://www.waze.com/discuss/*
  11. // @icon data:image/png;base64,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
  12. // @grant unsafeWindow
  13. // @grant GM_xmlhttpRequest
  14. // @grant GM_addElement
  15. // @connect holidayapi.com
  16. // @copyright 2018, dummyd2, seb-d59, WazeDev
  17. // @author dummyd2, seb-d59, WazeDev
  18. // ==/UserScript==
  19.  
  20.  
  21. /*******
  22. *
  23. * You are free to:
  24. * Share, copy, and redistribute the script in any medium or format
  25. * under the following terms:
  26. * Attribution - You must give appropriate credit. You may do so in any
  27. * reasonable manner, but not in any way that suggests the licensor
  28. * endorses you or your use.
  29. *
  30. * NonCommercial - You may not use the script for commercial purposes.
  31. *
  32. * NoModifications - You may NOT MODIFY the script.
  33. *
  34. * You are invited to contact authors on waze forum for more details.
  35. *
  36. ********/
  37.  
  38. /* global $ */
  39. /* global W */
  40. /* global OpenLayers */
  41. /* global require */
  42. /* global _ */
  43. /* global I18n */
  44. /*jshint multistr: true */
  45.  
  46.  
  47. // SKIP_FILE('include/downloadHelper.js');
  48.  
  49. (function()
  50. {
  51. // WMEAC object and members:
  52. /***********************************************
  53. *** IN INCLUDED FILE : ***
  54. *** include/globalDeclarations.js ***
  55. ***********************************************/
  56.  
  57. // create a custom date class with a few addl functions (originally in Datejs library).
  58. class JDate extends Date {
  59. clone() { return new JDate(this); }
  60. addMinutes(value) {
  61. this.setMinutes(this.getMinutes() + value);
  62. }
  63. addDays(value) {
  64. this.setDate(this.getDate() + value);
  65. }
  66. }
  67.  
  68. const scriptName = 'Advanced Closures';
  69. const scriptId = 'advclosures';
  70.  
  71. var WMEAC={};
  72.  
  73. WMEAC.isDebug=false;
  74. WMEAC.wmeSDK = null;
  75.  
  76. WMEAC.ac_version="2025.03.26.01";
  77.  
  78. WMEAC.closureTabTimeout=null;
  79.  
  80. WMEAC.csv=[];
  81.  
  82. WMEAC.csvCurrentClosureList=null;
  83.  
  84. WMEAC.csvCurrentBatchClosureList=null;
  85.  
  86. WMEAC.pendingOps=false;
  87.  
  88. WMEAC.pb = null;
  89.  
  90. WMEAC.daysOfWeek=[ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  91.  
  92. WMEAC.lastGeneratedHolidays = [];
  93.  
  94. WMEAC.presets=[];
  95.  
  96. WMEAC.closeInsideNodes = false;
  97.  
  98. /***********************************************
  99. *** END OF INCLUDED FILE : ***
  100. *** include/globalDeclarations.js ***
  101. ***********************************************/
  102.  
  103.  
  104.  
  105. // WMEAC usefull function member
  106. /***********************************************
  107. *** IN INCLUDED FILE : ***
  108. *** include/util.js ***
  109. ***********************************************/
  110.  
  111. WMEAC.getElementsByClassName=function (classname, node) {
  112. if(!node) node = document.getElementsByTagName("body")[0];
  113. var a = [];
  114. var re = new RegExp('\\b' + classname + '\\b');
  115. var els = node.getElementsByTagName("*");
  116. for (var i=0,j=els.length; i<j; i++)
  117. if (re.test(els[i].className)) a.push(els[i]);
  118. return a;
  119. };
  120.  
  121.  
  122. WMEAC.removeChildElements = function (node)
  123. {
  124. while (node.firstChild)
  125. {
  126. WMEAC.removeChildElements(node.firstChild);
  127. node.removeChild(node.firstChild);
  128. }
  129. };
  130.  
  131. WMEAC.createElement = function (options)
  132. {
  133. if (options.hasOwnProperty('type')==false)
  134. return null;
  135. var el=document.createElement(options.type);
  136.  
  137. if (options.hasOwnProperty('id')==true)
  138. el.id=options.id;
  139.  
  140. if (options.hasOwnProperty('className')==true)
  141. el.className=options.className;
  142.  
  143. return el;
  144. };
  145.  
  146. WMEAC.getId = function (node) {
  147. var el = document.getElementById(node);
  148. return el;
  149. };
  150.  
  151. WMEAC.logBeta = function (msg, obj)
  152. {
  153. //log("Beta - " + msg, obj);
  154. };
  155.  
  156. WMEAC.logDebug = function (msg, obj)
  157. {
  158. if (WMEAC.isDebug) WMEAC.log("DEBUG - " + msg, obj);
  159. };
  160.  
  161. WMEAC.logError = function (msg, obj)
  162. {
  163. console.error("Advanced closures: " + msg, obj);
  164. };
  165.  
  166.  
  167. WMEAC.log = function (msg, obj)
  168. {
  169. if (obj==null)
  170. console.log("Advanced closures: " + msg);
  171. else
  172. console.debug("Advanced closures: " + msg + " " ,obj);
  173. };
  174.  
  175. WMEAC.isValidDate = function(d) // http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript
  176. {
  177. if ( Object.prototype.toString.call(d) === "[object Date]" ) {
  178. // it is a date
  179. if ( isNaN( d.getTime() ) ) { // d.valueOf() could also work
  180. return false;
  181. }
  182. else {
  183. return true;
  184. }
  185. }
  186. else {
  187. return false;
  188. }
  189. };
  190.  
  191. WMEAC.dateToClosureStr = function(d) {
  192. var yyyy = d.getUTCFullYear().toString();
  193. var MM = (d.getUTCMonth()+1).toString(); // getMonth() is zero-based
  194. var dd = d.getUTCDate().toString();
  195. var hh = d.getUTCHours().toString();
  196. var mm = d.getUTCMinutes().toString();
  197. 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]); // padding
  198. };
  199.  
  200.  
  201. // http://stackoverflow.com/questions/8493195/how-can-i-parse-a-csv-string-with-javascript
  202. WMEAC.CSVtoArray = function (text) {
  203. var b = [];
  204. var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
  205. var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
  206. var lines = text.split('\n');
  207. lines.forEach(function (line) {
  208. if (!re_valid.test(line)) return;
  209. var a = []; // Initialize array to receive values.
  210. line.replace(re_value, // "Walk" the string using replace with callback.
  211. function(m0, m1, m2, m3) {
  212. // Remove backslash from \' in single quoted values.
  213. if (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
  214. // Remove backslash from \" in double quoted values.
  215. else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
  216. else if (m3 !== undefined) a.push(m3);
  217. return ''; // Return empty string.
  218. });
  219. // Handle special case of empty last value.
  220. if (/,\s*$/.test(line)) a.push('');
  221. b.push(a);
  222. });
  223. return b;
  224. };
  225.  
  226. WMEAC.segmentsIDsToSegments = function (idlist)
  227. {
  228. if (idlist.objectType !== undefined && idlist.objectType != 'segment') {
  229. return [];
  230. }
  231. const arr = (idlist.ids == undefined) ? idlist : idlist.ids;
  232. return arr.filter(function (e) {
  233. return (WMEAC.wmeSDK.DataModel.Segments.getById( { segmentId: Number(e) } ) != null);
  234. }).map (function (e) {
  235. return (WMEAC.wmeSDK.DataModel.Segments.getById( { segmentId: Number(e) } ));
  236. });
  237. };
  238.  
  239. WMEAC.reloadRoadLayer = function ()
  240. {
  241. // SDK - IS THIS NEEDED - var l=W.map.getLayerByName("roads");
  242. // 2024-04-09 these seem to be unneeded and causes flashing and delays
  243. // l.redraw({force:!0});
  244. // l.removeBackBuffer();
  245. // W.controller.reloadData();
  246. };
  247.  
  248. WMEAC.reloadClosuresLayer = function (endHandler)
  249. {
  250. // SDK - NEEDED ??
  251. /* var l=W.map.getLayerByName("closures");
  252. l.redraw({force:!0});
  253. // W.controller.reloadData();
  254. */
  255. if (endHandler) {
  256. WMEAC.waitMapLoaded();
  257. endHandler();
  258. }
  259. };
  260.  
  261. WMEAC.showClosuresLayer = function(show)
  262. {
  263. WMEAC.wmeSDK.Map.setLayerVisibility( { layerName: "closures", visibility: show });
  264. };
  265.  
  266. WMEAC.setDraggable = function (element, options)
  267. {
  268. if (!options.hasOwnProperty('controller'))
  269. options.controller=element;
  270. if (!options.hasOwnProperty('container'))
  271. options.container=[$('body')];
  272. options.controller.css({cursor: 'move'});
  273.  
  274. options.controller.on("mousedown", function(e) {
  275. var x = e.pageX-element.offset().left;
  276. var y = e.pageY-element.offset().top;
  277.  
  278. $('body').on("mouseup", function(e) {
  279. options.container.forEach(function (c) {
  280. c.off("mousemove", elemmousemove);
  281. });
  282. });
  283. function elemmousemove (e) {
  284. e.preventDefault();
  285. element.offset({
  286. top: e.pageY - y,
  287. left: e.pageX - x
  288. });
  289. }
  290. options.container.forEach(function (c) {
  291. c.on("mousemove", elemmousemove);
  292. });
  293.  
  294. });
  295. };
  296.  
  297. WMEAC.dateTimeOverlaps = function ( dt1, dt2 )
  298. {
  299. return (dt1.startDate < dt2.endDate && dt1.endDate > dt2.startDate );
  300. };
  301.  
  302. WMEAC.solveOverlaps = function (closureToAdd, existingClosureList, mode)
  303. {
  304. // sort existing closures:
  305. var ecs = existingClosureList.map(function (e) {
  306. return { isNew: false, ref: e, startDate: e.startDate, endDate: e.endDate};
  307. });
  308. // append new
  309. closureToAdd.isNew=true;
  310. ecs.push(closureToAdd);
  311. var changes=true;
  312. while (changes)
  313. {
  314. changes=false;
  315. ecs.sort(function (a, b) {
  316. return (new Date(a.startDate) - new Date(b.startDate));
  317. });
  318.  
  319. for (var i=1; i<ecs.length; i++)
  320. {
  321. if (WMEAC.dateTimeOverlaps(ecs[i-1], ecs[i]))
  322. {
  323. var indexOfNew = i-1;
  324. var indexOfExisting = i;
  325. if (ecs[i].isNew)
  326. {
  327. indexOfNew=i;
  328. indexOfExisting=i-1;
  329. }
  330. var r1 = ecs[indexOfNew];
  331. var r2 = ecs[indexOfExisting];
  332. var range1={};
  333. var range2={};
  334. switch (mode)
  335. {
  336. case 0: // keep existing. return empty
  337. return [];
  338. break;
  339. case 1: // delete existing.
  340. ecs.splice(indexOfExisting, 1);
  341. changes=true;
  342. break;
  343. case 2: // fill: keep all existing and cut/split new
  344. range1.start=new Date(r1.startDate);
  345. range1.end=new Date(r1.endDate);
  346. range2.start=new Date(r2.startDate);
  347. range2.end=new Date(r2.endDate);
  348. changes=true;
  349. if (range1.start>=range2.start && range1.end<=range2.end)
  350. {
  351. ecs.splice(indexOfNew, 1);
  352. }
  353. else if (range1.start<range2.start && range1.end>range2.end)
  354. {
  355. ecs.push({isNew: true, startDate: r2.endDate, endDate: r1.endDate});
  356. r1.endDate=r2.startDate;
  357. }
  358. else if (range1.start<range2.start)
  359. {
  360. r1.endDate=r2.startDate;
  361. }
  362. else //if (range1.end>range2.end)
  363. {
  364. r1.startDate = r2.endDate;
  365. }
  366. break;
  367. case 3: // force: cut/split/delete existing and keep new
  368. range1.start=new Date(r1.startDate);
  369. range1.end=new Date(r1.endDate);
  370. range2.start=new Date(r2.startDate);
  371. range2.end=new Date(r2.endDate);
  372. changes=true;
  373. if (range1.start>range2.start && range1.end<range2.end)
  374. {
  375. ecs.push({isNew: false, startDate: r1.endDate, endDate: r2.endDate, ref: r2.ref});
  376. r2.endDate=r1.startDate;
  377. }
  378. else if (range1.start<=range2.start && range1.end>=range2.end)
  379. {
  380. ecs.splice(indexOfExisting, 1);
  381. }
  382. else if (range1.start<range2.start)
  383. {
  384. r2.startDate=r1.endDate;
  385. }
  386. else //if (range1.end>range2.end)
  387. {
  388. r2.endDate = r1.startDate;
  389. }
  390. break;
  391. }
  392. }
  393. }
  394. }
  395. return ecs;
  396. };
  397.  
  398. // tests:
  399. // WMEAC.solveOverlaps({startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00'},
  400. // [ {startDate: '2016-01-05 00:00', endDate: '2016-01-15 00:00', reason: 'bla bla'}], 0);
  401. // WMEAC.solveOverlaps({startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00'},
  402. // [ {startDate: '2016-01-15 00:00', endDate: '2016-01-25 00:00', reason: 'bla bla'}], 0);
  403. // WMEAC.solveOverlaps({startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00'},
  404. // [ {startDate: '2016-01-05 00:00', endDate: '2016-01-25 00:00', reason: 'bla bla'}], 0);
  405. // WMEAC.solveOverlaps({startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00'},
  406. // [ {startDate: '2016-01-12 00:00', endDate: '2016-01-18 00:00', reason: 'bla bla'}], 0);
  407. // WMEAC.solveOverlaps({startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00'},
  408. // [ {startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00', reason: 'bla bla'}], 0);
  409. // WMEAC.solveOverlaps({startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00'},
  410. // [ {startDate: '2016-01-05 00:00', endDate: '2016-01-10 00:00', reason: 'bla bla'},
  411. // {startDate: '2016-01-20 00:00', endDate: '2016-01-25 00:00', reason: 'bla bla'}], 0);
  412. // WMEAC.solveOverlaps({startDate: '2016-01-10 00:00', endDate: '2016-01-20 00:00'},
  413. // [ {startDate: '2016-01-05 00:00', endDate: '2016-01-15 00:00', reason: 'bla bla'},
  414. // {startDate: '2016-01-16 00:00', endDate: '2016-01-25 00:00', reason: 'bla bla'}], 0);
  415.  
  416. // this is only used in disabled holidays code, commenting out
  417. /*
  418. WMEAC.getCountriesFromSegmentSet = function (segs)
  419. {
  420. var cids = segs.map(function (s) {
  421. const addr = WMEAC.wmeSDK.DataModel.Segments.getAddress( { segmentId: Number(s) } );
  422. if (addr.country ) {
  423. return addr.country.id;
  424. }
  425. return null;
  426. }).filter(function (cid) {
  427. return (cid!=null);
  428. });
  429. return cids; // SDK - does this work
  430. }; */
  431.  
  432. WMEAC.getOppositeClosure = function (closure)
  433. {
  434. return WMEAC.wmeSDK.DataModel.RoadClosures.getAll().filter(function (c) {
  435. return (closure.description == c.description &&
  436. closure.startDate == c.startDate &&
  437. closure.endDate == c.endDate &&
  438. closure.segmentId == c.segmentId &&
  439. closure.isForward != c.isForward);
  440. });
  441. };
  442.  
  443. WMEAC.getCityStreetsFromSegmentSet = function (segs)
  444. {
  445. var r={};
  446. function add(city, street)
  447. {
  448. if (!r.hasOwnProperty(city))
  449. r[city]={};
  450. if (!r[city].hasOwnProperty(street))
  451. r[city][street]=0;
  452. r[city][street]++;
  453. }
  454. segs.forEach(function (s) {
  455. var city='noCity';
  456. const addr = WMEAC.wmeSDK.DataModel.Segments.getAddress( { segmentId: Number(s.id) } );
  457. if (addr.street!=null) {
  458. city = addr.city.name;
  459. if (addr.street.isEmpty)
  460. add(city, 'noStreet');
  461. else
  462. add(city, addr.street.name);
  463. }
  464.  
  465. });
  466. return r;
  467. };
  468.  
  469. WMEAC.download = function (data, filename)
  470. {
  471. var element = document.createElement('a');
  472. element.style.display = 'none';
  473. element.setAttribute('href', encodeURI('data:text/plain,' + data));
  474. element.setAttribute('download', filename);
  475. document.body.appendChild(element);
  476. element.click();
  477. document.body.removeChild(element);
  478. };
  479.  
  480. WMEAC.buildPermalink = function (data)
  481. {
  482. var getvars = [];
  483. for (var m in data)
  484. {
  485. if (data.hasOwnProperty(m))
  486. {
  487. getvars.push('' + m + '=' + data[m]);
  488. }
  489. }
  490. return document.location.protocol + '//' + document.location.host + document.location.pathname + '?' + getvars.join('&amp;');
  491. };
  492.  
  493. WMEAC.sharedClosureDirection = {
  494. A_TO_B: 1,
  495. B_TO_A: 2,
  496. TWO_WAY: 3
  497. };
  498.  
  499. WMEAC.zoomToRoadType = function(e) {
  500. let allRoadTypes = [1,2,3,4,5,6,7,8,9,10,15,16,17,18,19,20,22];
  501. if (e < 14) {
  502. return [];
  503. }
  504. switch (e) {
  505. case 14:
  506. return [2, 3, 4, 6, 7, 14];
  507. case 15:
  508. return [2, 3, 4, 6, 7, 8, 9, 10, 14, 16,17, 18, 19, 20, 22];
  509. case 16:
  510. case 17:
  511. case 18:
  512. case 19:
  513. case 20:
  514. case 21:
  515. case 22:
  516. default:
  517. return allRoadTypes;
  518. }
  519. }
  520.  
  521.  
  522.  
  523.  
  524. /***********************************************
  525. *** END OF INCLUDED FILE : ***
  526. *** include/util.js ***
  527. ***********************************************/
  528.  
  529.  
  530.  
  531. /***********************************************
  532. *** IN INCLUDED FILE : ***
  533. *** include/css.js ***
  534. ***********************************************/
  535.  
  536. var cssElt = WMEAC.createElement({type: "style"});
  537. cssElt.type = "text/css";
  538. var css="";
  539. css += ".slashed:after { content: ''; position: relative; width: 140%; height: 1px; display: block; background: red; transform: rotate(-30deg); margin-top: -50%; margin-left: -20%; }";
  540.  
  541. 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; }";
  542. 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;}";
  543. css += ".wmeac-progressBarFG { float: left; position: relative; bottom: 22px; height: 0px; text-align: center; width: 100% }";
  544. css += "#wmeac-main-title { color: var(--content_p1); }";
  545. css += ".wmeac-closuredialog { border: 2px solid var(--primary); background-color: var(--surface_alt); width: 100%; float: left; display: none; position: absolute; padding: 0 0px; border-radius: 10px; width: 500px; z-index: 9999; left: 80px; top: 40px;}";
  546. css += ".wmeac-closuredialog button { border: none; border-radius: 50px; color: var(--on_primary); background-color: var(--primary); margin: 3px; }";
  547. css += ".wmeac-closuredialog h1 { text-align: center; background-color: var(--brand_waze); font-size: medium; margin-top: 0px; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: 1px;}";
  548. css += ".wmeac-closuredialog .content { padding: 10px; }";
  549. css += ".wmeac-closuredialog .content table { width: 100%; border: none; font-size: 10px; text-transform: uppercase;}";
  550. css += ".wmeac-closuredialog .content table tbody tr { vertical-align: top;}";
  551. css += ".wmeac-closuredialog .content table tbody tr td { padding-right: 2px; padding-left: 2px;}";
  552. css += ".wmeac-closuredialog-fromgroup { display: inline-block; }";
  553. css += ".wmeac-nav-tabs>ul { border-bottom: 1px solid var(--primary) }";
  554. css += ".wmeac-nav-tabs>li { float: left; margin-bottom: -1px; }";
  555. css += ".wmeac-nav-tabs>li>a { border: 1px solid var(--primary); border-top-left-radius: 5px; border-top-right-radius: 5px; margin-right: 2px;}";
  556. css += ".wmeac-nav-tabs>li.active>a { background-color: rgba(0, 0, 0, 0); border-bottom: 1px solid #FDEDEB}";
  557. css += ".wmeac-nav-tabs>li:not(.active)>a { background-color: #DADBDC}";
  558. //css += ".wmeac-nav-tabs>li:not(.active)>a:hover { background-color: #DADBDC}";
  559. css += ".wmeac-tab-pane {border: 1px solid var(--primary); border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 0px; border-top-right-radius: 0px; padding: 5px;}";
  560. css += ".wmeac-closuredialog .footer { height: 40px; padding: 0 10px;}";
  561. css += "#wmeac-csv-closures-list ul { list-style-type: none; padding: 0px;}";
  562. css += "#wmeac-csv-closures-list ul li { width: 100%; height: 42px; border-radius: 4px; margin-top: 1px; }";
  563. css += "#wmeac-csv-closures-list ul li > * { display: table-cell; vertical-align: middle;}";
  564. css += ".wmeac-csv-closures-list-add { background-color: #C6DFFF; }";
  565. css += ".wmeac-csv-closures-list-remove { background-color: #FFC65F; }";
  566. css += ".wmeac-csv-closures-list-failed { background-color: #FF8585; }";
  567. css += ".wmeac-csv-closures-list-done { background-color: #B9FAB1; }";
  568. css += ".wmeac-csv-closures-list-col-action { width: 14px; min-width: 14px; }";
  569. css += ".wmeac-csv-closures-list-col-lr { font-size: xx-small; width: 100%; }";
  570. css += ".wmeac-csv-closures-list-col-lr > * { height: 14px; overflow-y: hidden; vertical-align: middle; }";
  571. css += ".wmeac-csv-closures-list-col-dates { width: 75px; min-width: 75px; font-size: xx-small; text-align: center; }";
  572. css += ".wmeac-csv-closures-list-col-dates > * { height: 14px; overflow-y: hidden; vertical-align: center; }";
  573. css += ".wmeac-csv-closures-list-col-dir { width: 35px; min-width: 35px; text-align: center; }";
  574. css += ".wmeac-csv-closures-list-col-it { width: 15px; min-width: 15px; }";
  575. css += ".wmeac-csv-closures-list-col-target { width: 15px; min-width: 15px; }";
  576. css += ".wmeac-csv-closures-list-col-apply { width: 15px; min-width: 15px; }";
  577. css += ".wmeac-csv-closures-minilog { font-size: xx-small; font-family: monospace; background-color: var(--background_default); }";
  578. css += "#wmeac-csv-closures-log { font-size: xx-small; color: var(--content_p1); font-family: monospace; border: 2px solid var(--primary); border-radius: 5px; padding-top: 8px; position: relative; margin-top: 10px; }";
  579. css += "#wmeac-csv-closures-log:before { content: \"Logs\"; position: absolute; top: -8px; left: 5px; float: left; color: var(--on_primary); background-color: var(--primary); border-radius: 5px; padding: 2px; }";
  580. css += "#wmeac-csv-closures-preview { font-size: small; white-space: nowrap; font-family: monospace; border: 2px solid var(--primary); border-radius: 5px; padding-top: 8px; position: relative; min-height: 20px; }";
  581. css += "#wmeac-csv-closures-preview:before { content: \"Preview\"; position: absolute; top: -8px; left: 5px; float: left; background: #81c9ef; border-radius: 5px; padding: 2px; }";
  582. // old-highlight -- css += ".wmeac-hl:after { content: \"\\f018\"; position: relative; display: block; margin-top: -100%; margin-left: 50%; font-family: FontAwesome; }";
  583. cssElt.innerHTML = css;
  584. document.body.appendChild(cssElt);
  585.  
  586.  
  587. /***********************************************
  588. *** END OF INCLUDED FILE : ***
  589. *** include/css.js ***
  590. ***********************************************/
  591.  
  592.  
  593.  
  594. // boostrap and init (wait for waze UI and objects)
  595. /***********************************************
  596. *** IN INCLUDED FILE : ***
  597. *** include/init.js ***
  598. ***********************************************/
  599.  
  600. WMEAC.bootstrapAC = function ()
  601. {
  602. document.addEventListener("wme-ready", WMEAC.initialize, {
  603. once: true,
  604. });
  605. };
  606.  
  607.  
  608. WMEAC.initialize = function ()
  609. {
  610. // initialize the sdk with your script id and script name
  611. WMEAC.wmeSDK = getWmeSdk({scriptId, scriptName});
  612.  
  613. WMEAC.log ("init v" + WMEAC.ac_version);
  614. WMEAC.load();
  615. WMEAC.log("presets", WMEAC.presets);
  616. WMEAC.initUI();
  617. WMEAC.log ("init done");
  618. };
  619.  
  620.  
  621.  
  622.  
  623. /***********************************************
  624. *** END OF INCLUDED FILE : ***
  625. *** include/init.js ***
  626. ***********************************************/
  627.  
  628.  
  629.  
  630. // function to setup the UI dom
  631. /***********************************************
  632. *** IN INCLUDED FILE : ***
  633. *** include/setupUI.js ***
  634. ***********************************************/
  635.  
  636. WMEAC.HTMLTemplates={};
  637.  
  638. WMEAC.initUI = async function ()
  639. {
  640. WMEAC.initUIElements();
  641.  
  642. var addon = WMEAC.createElement({type: 'section', id: 'wmeac-addon'});
  643. WMEAC.pb = new WMEAC.ProgressBar('wmeac-progressBarInfo');
  644. addon.appendChild(WMEAC.pb.divpbi);
  645. var section = WMEAC.createElement({type: 'p', id: 'wmeac-main-title'});
  646. section.style.paddingTop = "0px";
  647. section.style.marginTop = "0px";
  648. section.style.textIndent = "8px";
  649. var title='<b><a target="_blank" href="https://greatest.deepsurf.us/scripts/370072-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/discuss/t/script-wme-advanced-closures/156277">En</a> </b> v' + WMEAC.ac_version;
  650. section.innerHTML = title;
  651. addon.appendChild(section);
  652. var divAdvCl = WMEAC.createElement({type: 'div', className: 'wmeac-sidepanel', id:'wmeac-ac'});
  653. var addACBtn = WMEAC.createElement({type: 'wz-button',
  654. id: 'wmeac-add-advanced-closure-button',
  655. className: 'wmeac-button'});
  656. addACBtn.innerHTML='<i class="fa fa-clock-o"></i> Add advanced closure';
  657. addACBtn.addEventListener('click', WMEAC.showAddAdvancedClosure);
  658. divAdvCl.appendChild(addACBtn);
  659. var divCSV = WMEAC.createElement({type: 'div', className: 'wmeac-sidepanel', id:'wmeac-csv'});
  660. var csvHTML = '<wz-file-input upload-button-label="Parse CSV" id="wmeac-file-input" enable-drag-and-drop="1" max-files-batch-size=10 ></wz-file-input>';
  661. csvHTML += '\
  662. <div id="wmeac-csv-closures" style="display: none;">\
  663. <div id="wmeac-csv-closures-controls">\
  664. <input type="checkbox" id="wmeac-csv-closures-controls-check"> | \
  665. <a href="#" id="wmeac-csv-closures-controls-apply">Apply</a> | \
  666. <a href="#" id="wmeac-csv-closures-controls-segs">Check segments</a>\
  667. </div>\
  668. <div id="wmeac-csv-closures-list">\
  669. <ul id="wmeac-csv-closures-list-elts">\
  670. </ul>\
  671. </div>\
  672. </div>\
  673. <div id="wmeac-csv-closures-log">\
  674. </div>';
  675. divCSV.innerHTML = csvHTML;
  676. addon.appendChild(divAdvCl);
  677. addon.appendChild(WMEAC.createElement({type: 'hr'}));
  678. addon.appendChild(divCSV);
  679.  
  680. var res = await WMEAC.wmeSDK.Sidebar.registerScriptTab();
  681. $(res.tabLabel.parentElement).append(
  682. $('<span>', { class:'fa fa-road slashed', title: 'Advanced Closures' })
  683. );
  684.  
  685. res.tabPane.appendChild(addon);
  686.  
  687. var observer = new MutationObserver(function(mutations) {
  688. mutations.forEach(function(mutation) {
  689. function rescurse(node)
  690. {
  691. if (node.className=='closures-list')
  692. {
  693. var target = WMEAC.getElementsByClassName('add-closure-button', node);
  694. if (target.length > 0)
  695. WMEAC.installButtonInClosureTab(node);
  696. }
  697. else
  698. {
  699. for (var j=0; j<node.childNodes.length; j++)
  700. rescurse(node.childNodes[j]);
  701. }
  702. }
  703. for (var i=0; i<mutation.addedNodes.length; i++)
  704. {
  705. rescurse(mutation.addedNodes[i]);
  706. }
  707. });
  708. });
  709. observer.observe(WMEAC.getId('edit-panel'), {childList: true, subtree: true});
  710. // test now if closure tab exists. It happens if WME is opened with a segment id in the url:
  711. WMEAC.installButtonInClosureTab();
  712. //W.selectionManager.addEventListener("selectionchanged", WMEAC.selectionChanged);
  713.  
  714. // refreshHighlight is not working, so commenting out these two lines
  715. // W.model.events.register("mergeend", null, WMEAC.refreshHighlight);
  716. // WMEAC.refreshHighlight();
  717. window.setTimeout(WMEAC.connectAdvancedClosureTabHandlers);
  718. window.setTimeout(WMEAC.setupMTEobserver, 2000);
  719. };
  720.  
  721. WMEAC.setupMTEobserver = function()
  722. {
  723. var mteObserver = new MutationObserver(function(mutations) {
  724. mutations.forEach(function(mutation) {
  725. for (var i = 0; i < mutation.addedNodes.length; i++) {
  726. var addedNode = mutation.addedNodes[i];
  727.  
  728. if (addedNode.nodeType === Node.TEXT_NODE && addedNode['s-nr'] ) {
  729. const x = $('.mte-edit-view > wz-section-header');
  730. if (x.length > 0) {
  731. const mtev = x[0].shadowRoot.querySelector('.subtitle');
  732. if (mtev) {
  733. mtev.style.overflow = 'visible';
  734. mtev.style.fontSize = '10px';
  735. break;
  736. }
  737. }
  738. }
  739. }
  740. });
  741. });
  742. mteObserver.observe(WMEAC.getId('sidepanel-mtes'), {childList: true, subtree: true});
  743. };
  744.  
  745. WMEAC.waitMapLoaded = async function()
  746. {
  747. for (let j=0; j<100; j++) {
  748. await new Promise(r => setTimeout(r,300));
  749. const ldf = W.app.layout.model.attributes.loadingFeatures; // SDK - need access to this status
  750. const pend = W.app.layout.model.attributes.pendingOperations.length;
  751. console.debug('AC - pendingOps: ' + pend + ' ldf: ' + ldf);
  752. if (pend > 0) {
  753. console.debug('AC - pendingOps: ' + pend);
  754. console.debug('AC - pending: ' + W.app.layout.model.attributes.pendingOperations[0]);
  755. }
  756. if (!ldf && pend==0) {
  757. await new Promise(r => setTimeout(r,50));
  758. break;
  759. }
  760. }
  761. }
  762. WMEAC.waitSelectionReady = async function()
  763. {
  764. for (let j=0; j<100; j++) {
  765. let selection = WMEAC.wmeSDK.Editing.getSelection();
  766. if (selection.ids.length > 0) break;
  767. await new Promise(r => setTimeout(r,300));
  768. }
  769. }
  770.  
  771. WMEAC.installButtonInClosureTab = function (node)
  772. {
  773. if (!node)
  774. node=WMEAC.getId('segment-edit-closures');
  775. if (!node) {
  776. var clist = WMEAC.getElementsByClassName('closures-list');
  777. if (clist.length >0) node = clist[0];
  778. }
  779. if (!node) return;
  780. // test if we already there
  781. if ($(node).find('#wmeac-closuretab-add-advanced-closure-button').length==0)
  782. {
  783. var addCL = WMEAC.getElementsByClassName('add-closure-button', node);
  784. var addACBtn = WMEAC.createElement({type: 'wz-button',
  785. id: 'wmeac-closuretab-add-advanced-closure-button',
  786. className: 'wmeac-button'});
  787. addACBtn.innerHTML='<i class="fa fa-clock-o"></i> Add advanced closure';
  788. addACBtn.addEventListener('click', WMEAC.showAddAdvancedClosure);
  789. if (addCL.length > 0) addCL[0].after(addACBtn);
  790. }
  791. };
  792.  
  793. WMEAC.showAddAdvancedClosure = function()
  794. {
  795. // init if needed and show modal dialog
  796. var ACDiv = WMEAC.getId('wmeac-add-advanced-closure-dialog');
  797. let left = 80;
  798. let top = 20;
  799. const $dc = $('#WazeMap'); // $('#dialog-container');
  800. if ($dc.length > 0) {
  801. //left += $('#drawer')[0].clientWidth;
  802. //left += $('#sidebar')[0].clientWidth;
  803. }
  804. const $head = $('#app-head');
  805. if ($head.length > 0) {
  806. top += $head[0].offsetTop + $head[0].offsetHeight;
  807. }
  808. if (ACDiv==null)
  809. {
  810. ACDiv = WMEAC.createElement({type: 'div',
  811. id: 'wmeac-add-advanced-closure-dialog',
  812. className: 'wmeac-closuredialog'});
  813. ACDiv.innerHTML=WMEAC.HTMLTemplates.advancedClosureDialog;
  814. let dlogs = WMEAC.wmeSDK.Map.getMapViewportElement();
  815. if ($dc.length > 0) {
  816. dlogs = $dc[0];
  817. }
  818. dlogs.appendChild(ACDiv);
  819. window.setTimeout(WMEAC.connectAdvancedClosureDialogHandlers);
  820. ACDiv.style.display="none";
  821. //W.selectionManager.addEventListener("selectionchanged", WMEAC.refreshClosureList);
  822. }
  823. if (ACDiv.style.display=="block") // already shown => reset position
  824. {
  825. $(ACDiv).css({left: (left+'px'), top: (top+'px') });
  826. }
  827. else
  828. {
  829. ACDiv.style.display="block";
  830. WMEAC.wmeSDK.Events.on({ eventName: "wme-selection-changed", eventHandler: WMEAC.refreshClosureList });
  831. WMEAC.wmeSDK.Events.on({ eventName: "wme-selection-changed", eventHandler:WMEAC.refreshClosureListFromSelection });
  832. WMEAC.refreshClosureListFromSelection();
  833. }
  834. //window.setTimeout(function () { $('#wmeac-add-advanced-closure-dialog').find('.input-group-addon').css({display:"table-cell"}); });
  835. $(ACDiv).find('.input-group-addon').css({display:"table-cell"});
  836. WMEAC.refreshMTEList();
  837. WMEAC.showClosuresLayer(true);
  838. };
  839.  
  840. WMEAC.initUIElements = function()
  841. {
  842. var rangeStartEndUI ='\
  843. <div class="form-group">\
  844. <label class="control-label" for="closure_rangestartDate">Range start (included)</label>\
  845. <div class="controls">\
  846. <div style="width: 58%" class="date date-input-group input-group pull-left">\
  847. <input id="wmeac-advanced-closure-dialog-rangestartdate" class="form-control start-date" type="text" name="closure_rangestartDate">\
  848. <span class="input-group-addon">\
  849. <i class="fa fa-calendar"></i>\
  850. </span>\
  851. </div>\
  852. </div>\
  853. </div>\
  854. <div class="form-group">\
  855. <label class="control-label" for="closure_rangeendDate">Range end (included)</label>\
  856. <div class="controls">\
  857. <div style="width: 58%" class="date date-input-group input-group pull-left">\
  858. <input id="wmeac-advanced-closure-dialog-rangeenddate" class="form-control end-date" type="text" name="closure_rangeendDate">\
  859. <span class="input-group-addon">\
  860. <i class="fa fa-calendar"></i>\
  861. </span>\
  862. </div>\
  863. </div>\
  864. </div>';
  865.  
  866. var startTimeAndDurationUI = '\
  867. <div class="wmeac-closuredialog-fromgroup">\
  868. <label class="control-label" for="closure_startTime">Start</label>\
  869. <div class="controls">\
  870. <div style="width: 58%;" class="bootstrap-timepicker input-group pull-left">\
  871. <input id="wmeac-advanced-closure-dialog-starttime" class="form-control start-time" type="text" name="closure_startTime">\
  872. <span class="input-group-addon">\
  873. <i class="fa fa-clock-o"></i>\
  874. </span>\
  875. </div>\
  876. </div>\
  877. </div>\
  878. <div class="wmeac-closuredialog-fromgroup">\
  879. <label class="control-label">Duration</label>\
  880. <div style="width: 58%;" class="bootstrap-timepicker input-group">\
  881. <div class="controls" style="display: flex;">\
  882. <span class="input-group-addon pull-left">\
  883. <i class="fa fa-step-forward"></i>\
  884. </span>\
  885. <span class="form-control" style="padding: 1px; display: flex">\
  886. <input id="wmeac-advanced-closure-dialog-duration-day" name="value" value=0 size=3/>\
  887. <span style="padding: 5px;">D</span>\
  888. </span>\
  889. </div>\
  890. <div class="bootstrap-timepicker input-group pull-left">\
  891. <input id="wmeac-advanced-closure-dialog-durationtime" class="form-control start-time" type="text" name="closure_durationTime">\
  892. <span class="input-group-addon">\
  893. <i class="fa fa-clock-o"></i>\
  894. </span>\
  895. </div>\
  896. </div>\
  897. </div>\
  898. ';
  899.  
  900. var descriptionUI = '\
  901. <div class="form-group">\
  902. <label class="control-label" for="closure_reason">Description</label>\
  903. <div class="controls">\
  904. <input id="wmeac-advanced-closure-dialog-reason" class="form-control" type="text" name="closure_reason">\
  905. </div>\
  906. </div>\
  907. ';
  908.  
  909. var locationUI = '\
  910. <div class="form-group">\
  911. <label class="control-label" for="closure_location">Location</label>\
  912. <div class="controls">\
  913. <input id="wmeac-advanced-closure-dialog-location" class="form-control" type="text" name="closure_location">\
  914. </div>\
  915. </div>\
  916. ';
  917.  
  918. var directionUI = '\
  919. <div class="form-group">\
  920. <label class="control-label" for="closure_direction">Direction</label>\
  921. <div class="controls">\
  922. <select id="wmeac-advanced-closure-dialog-direction" style="font-family:\'FontAwesome\', Arial;" class="form-control" name="closure_direction">\
  923. <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>\
  924. </select>\
  925. </div>\
  926. </div>\
  927. ';
  928.  
  929. var ignoreTrafficUI = '\
  930. <div class="checkbox">\
  931. <label class="control-label" style="font-weight: bold;">\
  932. <input id="wmeac-advanced-closure-dialog-ignoretraffic" type="checkbox" name="closure_permanent">\
  933. Ignore Traffic\
  934. </label>\
  935. </div>\
  936. ';
  937.  
  938. var MTEUI = '\
  939. <div class="form-group">\
  940. <label class="control-label control-label-inline" for="closure_MTE">Link to MTE</label>\
  941. <div class="controls">\
  942. <select id="wmeac-advanced-closure-dialog-mteid" class="form-control" name="closure_MTE" disabled><option value="">None</option></select>\
  943. </div>\
  944. </div>\
  945. ';
  946.  
  947. var overlapModeUI = '\
  948. <div class="form-group">\
  949. <label class="control-label" for="closure_overlap">Overlap action</label>\
  950. <div class="controls">\
  951. <select id="wmeac-advanced-closure-dialog-overlap" style="font-family:\'FontAwesome\', Arial;" class="form-control" name="closure_overlap">\
  952. <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>\
  953. </select>\
  954. </div>\
  955. </div>\
  956. ';
  957.  
  958. var tabRepeatUI = '\
  959. <div style="width: 150px;" class="input-group">\
  960. <div class="controls">\
  961. <div class="input-group pull-left">\
  962. <input id="wmeac-advanced-closure-dialog-repeat-ntimes" class="form-control" type="text" name="closure_repeat_ntimes">\
  963. <span class="input-group-addon" for="closure_repeat_ntimes">times</span>\
  964. </div>\
  965. </div>\
  966. </div>\
  967. <div style="width: 150px;" class="input-group">\
  968. <div class="controls">\
  969. <div style="width: 150px;" class="bootstrap-timepicker input-group">\
  970. <span class="input-group-addon">\
  971. every\
  972. </span>\
  973. <span class="form-control" style="padding: 1px; display: flex">\
  974. <input id="wmeac-advanced-closure-dialog-repeat-every-day" name="value" value=0 size=3/>\
  975. <span style="padding: 5px;">D</span>\
  976. <input id="wmeac-advanced-closure-dialog-repeat-every-hour" name="value" value=0 size=3/>\
  977. <span style="padding: 5px;">H</span>\
  978. <input id="wmeac-advanced-closure-dialog-repeat-every-minute" name="value" value=0 size=2/>\
  979. <span style="padding: 5px;">M</span>\
  980. </span>\
  981. </div>\
  982. </div>\
  983. </div>\
  984. ';
  985.  
  986. if(!I18n.translations[I18n.locale].date.abbr_day_names){
  987. I18n.translations[I18n.locale].date.abbr_day_names = [];
  988. _.forOwn(I18n.translations[I18n.locale].date, (v,k) => { if(k.indexOf("abbr_day_names_") > -1) { I18n.translations[I18n.locale].date.abbr_day_names.push(v)}});
  989. }
  990.  
  991. var daysOfWeekUI = _(I18n.translations[I18n.locale].date.abbr_day_names).clone();
  992. daysOfWeekUI.push(daysOfWeekUI.shift());
  993. var tabEachUI = '<div class="box" style="display:flex; flex-wrap:wrap;">\
  994. <div style="width:100%;">\
  995. <label class="control-label" style="font-weight: bold;">\
  996. <input id="wmeac-advanced-closure-dialog-each-dayall" type="checkbox" name="closure_each_dayall">\
  997. All\
  998. </label>\
  999. </div>\
  1000. ' +
  1001. daysOfWeekUI.map(function (d, i) {
  1002. return '<div style="width:14%;">\
  1003. <label class="control-label" style="font-weight: bold;">\
  1004. <input id="wmeac-advanced-closure-dialog-each-' + ((i+1)%7) + '" type="checkbox" name="closure_each_' + d + '">\
  1005. ' + d + '\
  1006. </label>\
  1007. </div>\
  1008. ';
  1009. }).join('') + '</div>';
  1010.  
  1011. var tabHolidayUI = '\
  1012. <div class="content">\
  1013. <a id="wmeac-advanced-closure-dialog-holiday-refresh" href="#">Refresh holidays</a><br>\
  1014. <i id="wmeac-advanced-closure-dialog-holiday-refresh-spinner" class="fa fa-spinner fa-pulse fa-3x fa-fw" style="display: none;"></i>\
  1015. <div id="wmeac-advanced-closure-dialog-holiday-list" class="form-group" style="overflow-y: scroll; max-height: 200px;">\
  1016. </div>\
  1017. </div>\
  1018. ';
  1019.  
  1020. var tabPresetsUI = '\
  1021. <div class="content">\
  1022. <table><tr><td style="width: 50%; border-right: 1px solid #F6C3BE; padding-right: 5px;">\
  1023. <div class="form-group">\
  1024. <label class="control-label" for="presets_load">Load preset</label>\
  1025. <div class="controls">\
  1026. <div class="input-group">\
  1027. <select style="width: 100%;" id="wmeac-advanced-closure-dialog-presets-list" name="presets_load">\
  1028. </select>\
  1029. <span id="wmeac-advanced-closure-dialog-presets-load" class="input-group-addon">\
  1030. <i class="fa fa-folder-open-o"></i>\
  1031. </span>\
  1032. <span id="wmeac-advanced-closure-dialog-presets-delete" class="input-group-addon">\
  1033. <i class="fa fa-trash"></i>\
  1034. </span>\
  1035. </div>\
  1036. </div>\
  1037. <label class="control-label" for="seg_load">Load from segment</label>\
  1038. <div class="controls">\
  1039. <div class="input-group">\
  1040. <select style="width: 100%;" id="wmeac-advanced-closure-dialog-segclosure-list" name="presets_load">\
  1041. </select>\
  1042. <span id="wmeac-advanced-closure-dialog-presets-load-fromseg" class="input-group-addon">\
  1043. <i class="fa fa-share"></i>\
  1044. </span>\
  1045. </div>\
  1046. </div>\
  1047. </div>\
  1048. </td><td style="padding-left: 5px;">\
  1049. <div class="form-group">\
  1050. <label class="control-label" for="presets_save">Save preset</label>\
  1051. <div class="controls">\
  1052. <div class="input-group pull-left">\
  1053. <input id="wmeac-advanced-closure-dialog-presets-name" class="form-control" type="text" name="presets_save">\
  1054. <span id="wmeac-advanced-closure-dialog-presets-save" class="input-group-addon">\
  1055. <i class="fa fa-floppy-o"></i>\
  1056. </span>\
  1057. </div>\
  1058. </div>\
  1059. </div>\
  1060. </td></tr></table>\
  1061. </div>\
  1062. ';
  1063.  
  1064. var tabsUI ='\
  1065. <ul class="nav wmeac-nav-tabs">\
  1066. <li class="active">\
  1067. <a id="wmeac-advanced-closure-dialog-repeat" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabrepeat">Repeat</a>\
  1068. </li>\
  1069. <li>\
  1070. <a id="wmeac-advanced-closure-dialog-each" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabeach">Each</a>\
  1071. </li>\
  1072. <li>\
  1073. <a id="wmeac-advanced-closure-dialog-holiday" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabholiday">Holidays</a>\
  1074. </li>\
  1075. <li style="float: right;">\
  1076. <a id="wmeac-advanced-closure-dialog-presets" data-toggle="tab" href="#wmeac-advanced-closure-dialog-tabpresets"><i class="fa fa-floppy-o"></i></a>\
  1077. </li>\
  1078. </ul>\
  1079. <div class="tab-content">\
  1080. <div class="tab-pane active wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabrepeat">\
  1081. ' + tabRepeatUI + '\
  1082. </div>\
  1083. <div class="tab-pane wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabeach">\
  1084. ' + tabEachUI + '\
  1085. </div>\
  1086. <div class="tab-pane wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabholiday">\
  1087. ' + tabHolidayUI + '\
  1088. </div>\
  1089. <div class="tab-pane wmeac-tab-pane" id="wmeac-advanced-closure-dialog-tabpresets">\
  1090. ' + tabPresetsUI + '\
  1091. </div>\
  1092. </div>';
  1093.  
  1094. var footerUI = '\
  1095. <div class="footer">\
  1096. <div id="wmeac-csv-closures-preview"><div id="wmeac-csv-closures-preview-content" style="overflow: scroll; max-height: 100px;"></div></div>\
  1097. <button style="float: left;" id="wmeac-advanced-closure-dialog-exportCSV-button">Export CSV</button>\
  1098. <button style="float: right;" id="wmeac-advanced-closure-dialog-close-button">Close</button>\
  1099. <button style="float: right;" id="wmeac-advanced-closure-dialog-apply-button">Apply</button>\
  1100. </div>';
  1101.  
  1102. WMEAC.HTMLTemplates.advancedClosureDialog='\
  1103. <h1>Advanced closures</h1>\
  1104. <div class="content">\
  1105. <table>\
  1106. <tr>\
  1107. <td style="width: 50%;">' +
  1108. rangeStartEndUI + startTimeAndDurationUI +
  1109. '\
  1110. </td>\
  1111. <td>' +
  1112. descriptionUI + directionUI + ignoreTrafficUI + MTEUI +// overlapModeUI +
  1113. '\
  1114. </td>\
  1115. </tr>\
  1116. </table>' +
  1117. tabsUI +
  1118. '</div>' + footerUI;
  1119. }
  1120.  
  1121. WMEAC.connectAdvancedClosureDialogHandlers = function ()
  1122. {
  1123. var e = null;
  1124. e=WMEAC.getId('wmeac-advanced-closure-dialog-exportCSV-button');
  1125. if (e)
  1126. {
  1127. e.addEventListener('click', function() {
  1128. var rc = WMEAC.buildClosuresListFromRecurringUI();
  1129. if (rc.error!="")
  1130. {
  1131. alert("Can't apply closures.\nPlease, check all parameters.");
  1132. return;
  1133. }
  1134. let selection = WMEAC.wmeSDK.Editing.getSelection();
  1135. if (selection.ids.length==0 || selection.objectType != "segment")
  1136. {
  1137. alert("Please, select segment(s) before.");
  1138. return;
  1139. }
  1140. var reason = $('#wmeac-advanced-closure-dialog-reason').val();
  1141. //var cllocation = $('#wmeac-advanced-closure-dialog-location').val();
  1142. var direction = $('#wmeac-advanced-closure-dialog-direction').val();
  1143. var isIT = $('#wmeac-advanced-closure-dialog-ignoretraffic').is(':checked');
  1144. var mteId = $("#wmeac-advanced-closure-dialog-mteid").val();
  1145. closureList = rc.list.map(function (e) {
  1146. //return {reason: reason, direction: direction, startDate: e.start, endDate: e.end, location: cllocation, permanent: isIT};
  1147. var details = {reason: reason, direction: direction, startDate: e.start, endDate: e.end, location: "", permanent: isIT};
  1148. if (mteId)
  1149. details.eventId = mteId;
  1150. return details;
  1151. });
  1152. var selectionReversed=[];
  1153. if (direction!='3') // not two way
  1154. {
  1155. var rev = W.selectionManager.getReversedSegments();
  1156. let ids = selection.ids.filter(function (e) {
  1157. if (rev[e])
  1158. {
  1159. selectionReversed.push(e);
  1160. return false;
  1161. }
  1162. return true;
  1163. });
  1164. selection.ids = ids;
  1165. }
  1166.  
  1167. var lonlat = WMEAC.wmeSDK.Map.getMapCenter();
  1168. 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 (14 to 22),MTE id (empty cell if not),comment (optional)\n';
  1169. closureList.forEach(function (e) {
  1170. csv+='add,"' + e.reason + '","' + e.startDate + '","' + e.endDate + '","' + (direction==3?"TWO WAY":(direction==2?"B to A":"A to B")) + '",' + (isIT?"Yes":"No") + ',"' + selection.ids.map(function (s) { return s;}).join(';') + '","lon=' + lonlat.lon + '&lat=' + lonlat.lat + '",' + WMEAC.wmeSDK.Map.getZoomLevel() + ',' + mteId + ',"Generated by WMEAC"\n';
  1171. });
  1172. if (!selectionReversed.length==0)
  1173. {
  1174. closureList.forEach(function (e) {
  1175. 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) { return s;}).join(';') + '","lon=' + lonlat.lon + '&lat=' + lonlat.lat + '",' + WMEAC.wmeSDK.Map.getZoomLevel() + ',' + mteId + ',"Generated by WMEAC"\n';
  1176. });
  1177. }
  1178. WMEAC.download(csv, 'closures.csv');
  1179. });
  1180. }
  1181. e=WMEAC.getId('wmeac-advanced-closure-dialog-close-button');
  1182. if (e)
  1183. {
  1184. e.addEventListener('click', function() {
  1185. var d = WMEAC.getId('wmeac-add-advanced-closure-dialog');
  1186. if (d) {
  1187. try {
  1188. WMEAC.wmeSDK.Events.off({ eventName: "wme-selection-changed", eventHandler: WMEAC.refreshClosureList });
  1189. WMEAC.wmeSDK.Events.off({ eventName: "wme-selection-changed", eventHandler: WMEAC.refreshClosureListFromSelection });
  1190. }
  1191. catch (e) {
  1192. console.warn("AC: Error in events.off: ", e);
  1193. }
  1194. d.style.display='none';
  1195. }
  1196. });
  1197. }
  1198.  
  1199. e=WMEAC.getId('wmeac-advanced-closure-dialog-apply-button');
  1200. if (e)
  1201. {
  1202. e.addEventListener('click', function() {
  1203. var rc = WMEAC.buildClosuresListFromRecurringUI();
  1204. if (rc.error!="")
  1205. {
  1206. alert("Can't apply closures.\nPlease, check all parameters.");
  1207. return;
  1208. }
  1209. const m = WMEAC.wmeSDK.Editing.getSelection();
  1210. if (m.ids.length==0 || m.objectType != "segment")
  1211. {
  1212. alert("Please, select segment(s) before.");
  1213. return;
  1214. }
  1215. var segs = WMEAC.segmentsIDsToSegments(m);
  1216. if (segs.every(function (e) {
  1217. return WMEAC.wmeSDK.DataModel.Segments.hasPermissions({permission: "EDIT_CLOSURES", segmentId: e.id });
  1218. })==false) {
  1219. alert("You don't have permission to edit closures on all those segments.");
  1220. return;
  1221. }
  1222. var reason = $('#wmeac-advanced-closure-dialog-reason').val();
  1223. //var cllocation = $('#wmeac-advanced-closure-dialog-location').val();
  1224. var direction = $('#wmeac-advanced-closure-dialog-direction').val();
  1225. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  1226. direction=(direction=="1"?WMEAC.sharedClosureDirection.A_TO_B:(direction=="2"?WMEAC.sharedClosureDirection.B_TO_A:WMEAC.sharedClosureDirection.TWO_WAY));
  1227. var directionStr = direction==1?"(A &#8594; B)":(direction==2?"(B &#8594; A)":"(&#8646;)");
  1228. var isIT = $('#wmeac-advanced-closure-dialog-ignoretraffic').is(':checked');
  1229. const mteId = $("#wmeac-advanced-closure-dialog-mteid").val();
  1230. closureList = rc.list.map(function (e) {
  1231. //return {reason: reason, direction: direction, startDate: e.start, endDate: e.end, location: cllocation, permanent: isIT};
  1232. var details = {reason: reason, direction: direction, startDate: e.start, endDate: e.end, location: "", permanent: isIT};
  1233. if (mteId)
  1234. details.eventId = mteId;
  1235. return details;
  1236. });
  1237. // save selection list
  1238. var selection = WMEAC.wmeSDK.Editing.getSelection();
  1239. try {
  1240. WMEAC.wmeSDK.Events.off({ eventName: "wme-selection-changed", eventHandler: WMEAC.refreshClosureList });
  1241. }
  1242. catch (e) {
  1243. console.warn("AC: Error in events.off: ", e);
  1244. }
  1245. WMEAC.addClosureListFromSelection(closureList, function (i, e) {
  1246. $('#wmeac-advanced-closure-dialog-preview-' + i).html(e).css({color: "var(--safe)"}); // green
  1247. }, function (i, e) {
  1248. $('#wmeac-advanced-closure-dialog-preview-' + i).html(e).css({color: "var(--alarming)"}); // red
  1249. }, function () {
  1250. WMEAC.wmeSDK.Editing.setSelection( { selection } );
  1251. //alert ('done');
  1252. var tmp = function selectionReady()
  1253. {
  1254. let sel = WMEAC.wmeSDK.Editing.getSelection();
  1255. if (sel.ids.length==0)
  1256. window.setTimeout(selectionReady, 500);
  1257. else
  1258. {
  1259. WMEAC.wmeSDK.Events.on({ eventName: "wme-selection-changed", eventHandler: WMEAC.refreshClosureList });
  1260. $('a[href="#segment-edit-closures"]').click();
  1261. }
  1262. };
  1263. window.setTimeout(tmp, 500);
  1264. }, 0);
  1265. });
  1266. }
  1267. // if (typeof $.fn.datepicker !== 'undefined')
  1268. // $("#wmeac-advanced-closure-dialog-rangestartdate,#wmeac-advanced-closure-dialog-rangeenddate").datepicker({ format: "yyyy-mm-dd", todayHighlight: !0, autoclose: !0});
  1269. // else
  1270. if (typeof $.fn.daterangepicker !== 'undefined')
  1271. $("#wmeac-advanced-closure-dialog-rangestartdate,#wmeac-advanced-closure-dialog-rangeenddate").daterangepicker({singleDatePicker: !0, autoApply: !0,
  1272. locale: {
  1273. format: "YYYY-MM-DD"
  1274. }});
  1275. else {
  1276. WMEAC.logError("daterangepicker not defined");
  1277. }
  1278. $("#wmeac-advanced-closure-dialog-rangestartdate,#wmeac-advanced-closure-dialog-rangeenddate").on("change", function () { WMEAC.refreshMTEList(); });
  1279. $("#wmeac-advanced-closure-dialog-starttime,#wmeac-advanced-closure-dialog-durationtime").timepicker({ defaultTime: "00:00", showMeridian: !1, template: !1});
  1280. $("#wmeac-add-advanced-closure-dialog").find(".input-group").find(".input-group-addon").on("click", function (e) {
  1281. $(e.target).parent().find("input").focus();
  1282. }).find("i").on("click", function (e) {
  1283. $(e.target).parent().parent().find("input").focus();
  1284. });
  1285. $('#wmeac-advanced-closure-dialog-each-dayall').on('click', function () {
  1286. var atLeastOneChecked=false;
  1287. for (var i=0; i<7; i++)
  1288. atLeastOneChecked = atLeastOneChecked || $("#wmeac-advanced-closure-dialog-each-"+i).is(':checked');
  1289. for (var i=0; i<7; i++)
  1290. $("#wmeac-advanced-closure-dialog-each-"+i).prop('checked', !atLeastOneChecked);
  1291. $('#wmeac-advanced-closure-dialog-each-dayall').prop('checked', !atLeastOneChecked);
  1292. });
  1293. if (typeof $.fn.spinner !== 'undefined')
  1294. {
  1295. $('#wmeac-advanced-closure-dialog-repeat-every-day').spinner({
  1296. min: 0,
  1297. spin: function (event, ui) {
  1298. $(this).trigger('change');
  1299. }
  1300. });
  1301. $('#wmeac-advanced-closure-dialog-repeat-every-hour').spinner({
  1302. min: 0,
  1303. spin: function (event, ui) {
  1304. if (ui.value >= 24) {
  1305. $(this).spinner('value', ui.value - 24);
  1306. $('#wmeac-advanced-closure-dialog-repeat-every-day').spinner('stepUp');
  1307. return false;
  1308. } else if (ui.value < 0) {
  1309. $(this).spinner('value', ui.value + 24);
  1310. $('#wmeac-advanced-closure-dialog-repeat-every-day').spinner('stepDown');
  1311. return false;
  1312. }
  1313. $(this).trigger('change');
  1314. }
  1315. });
  1316. $('#wmeac-advanced-closure-dialog-repeat-every-minute').spinner({
  1317. spin: function (event, ui) {
  1318. if (ui.value >= 60) {
  1319. $(this).spinner('value', ui.value - 60);
  1320. $('#wmeac-advanced-closure-dialog-repeat-every-hour').spinner('stepUp');
  1321. return false;
  1322. } else if (ui.value < 0) {
  1323. $(this).spinner('value', ui.value + 60);
  1324. $('#wmeac-advanced-closure-dialog-repeat-every-hour').spinner('stepDown');
  1325. return false;
  1326. }
  1327. $(this).trigger('change');
  1328. },
  1329. change: function (event) {
  1330. if (event.target.value<0 || event.target.value>59)
  1331. $(this).spinner('value', 0);
  1332. }
  1333. });
  1334. $('#wmeac-advanced-closure-dialog-duration-day').spinner({
  1335. min: 0,
  1336. spin: function (event, ui) {
  1337. $(this).trigger('change');
  1338. }
  1339. });
  1340. // $('#wmeac-advanced-closure-dialog-duration-hour').spinner({
  1341. // min: 0,
  1342. // spin: function (event, ui) {
  1343. // $(this).trigger('change');
  1344. // }
  1345. // });
  1346. // $('#wmeac-advanced-closure-dialog-duration-minute').spinner({
  1347. // spin: function (event, ui) {
  1348. // if (ui.value >= 60) {
  1349. // $(this).spinner('value', ui.value - 60);
  1350. // $('#wmeac-advanced-closure-dialog-duration-hour').spinner('stepUp');
  1351. // return false;
  1352. // } else if (ui.value < 0) {
  1353. // $(this).spinner('value', ui.value + 60);
  1354. // $('#wmeac-advanced-closure-dialog-duration-hour').spinner('stepDown');
  1355. // return false;
  1356. // }
  1357. // $(this).trigger('change');
  1358. // },
  1359. // change: function (event) {
  1360. // if (event.target.value<0 || event.target.value>59)
  1361. // $(this).spinner('value', 0);
  1362. // }
  1363. // });
  1364. }
  1365. $('#wmeac-advanced-closure-dialog-repeat,#wmeac-advanced-closure-dialog-each,#wmeac-advanced-closure-dialog-holiday').on('click', function(e){
  1366. window.setTimeout(WMEAC.refreshClosureList);
  1367. });
  1368. $('#wmeac-advanced-closure-dialog-holiday-refresh').on('click', function (e) {
  1369. var hDiv = $('#wmeac-advanced-closure-dialog-holiday-list');
  1370. // $('#wmeac-advanced-closure-dialog-holiday-refresh-spinner').css({display: 'block'});
  1371. WMEAC.removeChildElements(hDiv[0]);
  1372. /*
  1373. window.setTimeout(function () {
  1374. WMEAC.getHolidays({
  1375. rangeStart: $('#wmeac-advanced-closure-dialog-rangestartdate').val(),
  1376. rangeEnd: $('#wmeac-advanced-closure-dialog-rangeenddate').val(),
  1377. countries: _.map(WMEAC.getCountriesFromSegmentSet(_.map(W.selectionManager.getSelectedFeatures(), 'model')), 'abbr'),
  1378. handlerFinished: function (holidays)
  1379. {
  1380. WMEAC.lastGeneratedHolidays = holidays;
  1381. if (holidays.length==0)
  1382. hDiv.html("No holiday found.");
  1383. else
  1384. {
  1385. holidays.forEach(function (h, i) {
  1386. var chkBx = WMEAC.createElement({type: "div", className: "checkbox"});
  1387. chkBx.innerHTML='<label class="control-label" style="font-weight: bold;">\
  1388. <input id="wmeac-advanced-closure-dialog-holidays-' + i + '" type="checkbox">\
  1389. ' + h.date + ': ' + h.name + ' (' + h.country + ')\
  1390. </label>\
  1391. ';
  1392. $(chkBx).on('click', function(e){
  1393. window.setTimeout(WMEAC.refreshClosureList);
  1394. });
  1395. hDiv.append(chkBx);
  1396. });
  1397. }
  1398. $('#wmeac-advanced-closure-dialog-holiday-refresh-spinner').css({display: 'none'});
  1399. }
  1400. });
  1401. });
  1402. */
  1403. });
  1404. $('#wmeac-add-advanced-closure-dialog').on('change', function(e){
  1405. window.setTimeout(WMEAC.refreshClosureList);
  1406. });
  1407. WMEAC.reloadPresets();
  1408. $('#wmeac-advanced-closure-dialog-presets-load').on('click', function(e){
  1409. var presetIndex = parseInt($("#wmeac-advanced-closure-dialog-presets-list").val());
  1410. $("#wmeac-advanced-closure-dialog-starttime").val(WMEAC.presets[presetIndex].values.starttime);
  1411. // $("#wmeac-advanced-closure-dialog-duration-hour").val(WMEAC.presets[presetIndex].values.duration.hour);
  1412. // $("#wmeac-advanced-closure-dialog-duration-minute").val(WMEAC.presets[presetIndex].values.duration.minute);
  1413. if (WMEAC.presets[presetIndex].values.duration.hasOwnProperty('day'))
  1414. $("#wmeac-advanced-closure-dialog-duration-day").val(WMEAC.presets[presetIndex].values.duration.day);
  1415. else
  1416. $("#wmeac-advanced-closure-dialog-duration-day").val(Math.floor(WMEAC.presets[presetIndex].values.duration.hour/24));
  1417. $("#wmeac-advanced-closure-dialog-durationtime").val('' + (WMEAC.presets[presetIndex].values.duration.hour%24) + ':' + WMEAC.presets[presetIndex].values.duration.minute);
  1418. $("#wmeac-advanced-closure-dialog-reason").val(WMEAC.presets[presetIndex].values.description);
  1419. //$("#wmeac-advanced-closure-dialog-location").val(WMEAC.presets[presetIndex].values.location);
  1420. $("#wmeac-advanced-closure-dialog-direction").val(WMEAC.presets[presetIndex].values.direction);
  1421. $("#wmeac-advanced-closure-dialog-ignoretraffic").prop('checked', WMEAC.presets[presetIndex].values.ignoretraffic);
  1422. $("#wmeac-advanced-closure-dialog-repeat-ntimes").val(WMEAC.presets[presetIndex].values.repeat.ntimes);
  1423. if (WMEAC.presets[presetIndex].values.repeat.hasOwnProperty('day'))
  1424. $("#wmeac-advanced-closure-dialog-repeat-every-day").val(WMEAC.presets[presetIndex].values.repeat.day);
  1425. else
  1426. $("#wmeac-advanced-closure-dialog-repeat-every-day").val(Math.floor(WMEAC.presets[presetIndex].values.repeat.hour/24));
  1427. $("#wmeac-advanced-closure-dialog-repeat-every-hour").val(WMEAC.presets[presetIndex].values.repeat.hour%24);
  1428. $("#wmeac-advanced-closure-dialog-repeat-every-minute").val(WMEAC.presets[presetIndex].values.repeat.minute);
  1429. for (var i=0; i<7; i++)
  1430. $("#wmeac-advanced-closure-dialog-each-"+i).prop('checked', WMEAC.presets[presetIndex].values.each[i]);
  1431. });
  1432.  
  1433. $('#wmeac-advanced-closure-dialog-presets-load-fromseg').on('click', function () {
  1434. const closureId = $("#wmeac-advanced-closure-dialog-segclosure-list").val();
  1435. if (closureId)
  1436. {
  1437. var c = WMEAC.wmeSDK.DataModel.RoadClosures.getById( { roadClosureId: closureId });
  1438. if (c)
  1439. {
  1440. $("#wmeac-advanced-closure-dialog-starttime").val(c.startDate.split(' ')[1]);
  1441. var duration=new Date(c.endDate) - new Date(c.startDate);
  1442. // $("#wmeac-advanced-closure-dialog-duration-hour").val(Math.floor(duration/3600000));
  1443. // $("#wmeac-advanced-closure-dialog-duration-minute").val(new Date(duration).getMinutes());
  1444. var days = Math.floor(duration/86400000);
  1445. $("#wmeac-advanced-closure-dialog-duration-day").val(days);
  1446. var hours = Math.floor((duration - days * 86400000)/3600000);
  1447. var minutes = Math.floor((duration - days * 86400000 - hours * 3600000)/60000);
  1448. $("#wmeac-advanced-closure-dialog-durationtime").val('' + hours + ':' + minutes);
  1449. $("#wmeac-advanced-closure-dialog-reason").val(c.description.trim());
  1450. if (WMEAC.getOppositeClosure(c).length==0) // oneway
  1451. $("#wmeac-advanced-closure-dialog-direction").val(c.isForward?1:2);
  1452. else
  1453. $("#wmeac-advanced-closure-dialog-direction").val(3);
  1454. $("#wmeac-advanced-closure-dialog-ignoretraffic").prop('checked', c.isPermanent);
  1455. // MTE
  1456. if (c.trafficEventId!=null)
  1457. {
  1458. var options = [];
  1459. $("#wmeac-advanced-closure-dialog-mteid option").each(function () { options.push($(this).val()); });
  1460. if (options.indexOf(c.trafficEventId)!=-1)
  1461. $("#wmeac-advanced-closure-dialog-mteid").val(c.trafficEventId);
  1462. else
  1463. $("#wmeac-advanced-closure-dialog-mteid").val('');
  1464. }
  1465. }
  1466. }
  1467. });
  1468. $('#wmeac-advanced-closure-dialog-presets-delete').on('click', function(e){
  1469. var presetIndex = parseInt($("#wmeac-advanced-closure-dialog-presets-list").val());
  1470. WMEAC.presets.splice(presetIndex, 1);
  1471. WMEAC.save();
  1472. WMEAC.reloadPresets();
  1473. });
  1474.  
  1475. $('#wmeac-advanced-closure-dialog-presets-save').on('click', function(e){
  1476. var name = $("#wmeac-advanced-closure-dialog-presets-name").val();
  1477. var presetIndex = WMEAC.presets.findIndex(function (e) {
  1478. return e.name==name;
  1479. });
  1480. var preset = {name: name, values: { duration: {}, repeat: {}, each: []}};
  1481. if (presetIndex!=-1) // overwrite existing preset
  1482. preset=WMEAC.presets[presetIndex];
  1483. preset.values.starttime=$("#wmeac-advanced-closure-dialog-starttime").val();
  1484. preset.values.duration.day=$("#wmeac-advanced-closure-dialog-duration-day").val();
  1485. preset.values.duration.hour=parseInt($("#wmeac-advanced-closure-dialog-durationtime").val().split(':')[0]);
  1486. preset.values.duration.minute=parseInt($("#wmeac-advanced-closure-dialog-durationtime").val().split(':')[1]);
  1487. preset.values.description=$("#wmeac-advanced-closure-dialog-reason").val();
  1488. //preset.values.location=$("#wmeac-advanced-closure-dialog-location").val();
  1489. preset.values.direction=$("#wmeac-advanced-closure-dialog-direction").val();
  1490. preset.values.ignoretraffic=$("#wmeac-advanced-closure-dialog-ignoretraffic").is(':checked');
  1491. preset.values.repeat.ntimes=$("#wmeac-advanced-closure-dialog-repeat-ntimes").val();
  1492. preset.values.repeat.day=$("#wmeac-advanced-closure-dialog-repeat-every-day").val();
  1493. preset.values.repeat.hour=$("#wmeac-advanced-closure-dialog-repeat-every-hour").val();
  1494. preset.values.repeat.minute=$("#wmeac-advanced-closure-dialog-repeat-every-minute").val();
  1495. for (var i=0; i<7; i++)
  1496. preset.values.each[i]=$("#wmeac-advanced-closure-dialog-each-"+i).is(':checked');
  1497. if (presetIndex==-1)
  1498. WMEAC.presets.push(preset);
  1499. WMEAC.save();
  1500. WMEAC.reloadPresets();
  1501. });
  1502. WMEAC.setDraggable($('#wmeac-add-advanced-closure-dialog'), { controller: $('#wmeac-add-advanced-closure-dialog h1:first-child'), container: [$('#OpenLayers_Map_200_OpenLayers_ViewPort'), $('#WazeMap')] });
  1503. WMEAC.refreshMTEList();
  1504. };
  1505.  
  1506.  
  1507. WMEAC.connectAdvancedClosureTabHandlers = function ()
  1508. {
  1509. $('#wmeac-file-input')[0].addEventListener('filesSelected', (e) => WMEAC.ReadFiles(e.detail) );
  1510. var e = null;
  1511.  
  1512. e=WMEAC.getId('wmeac-csv-closures-controls-check');
  1513. if (e)
  1514. e.addEventListener('change', function (e) { WMEAC.CSVCheckAll(e.target.checked); });
  1515.  
  1516. e=WMEAC.getId('wmeac-csv-closures-controls-apply');
  1517. if (e)
  1518. e.addEventListener('click', WMEAC.CSVApplyChecked);
  1519.  
  1520. e=WMEAC.getId('wmeac-csv-closures-controls-segs');
  1521. if (e)
  1522. e.addEventListener('click', WMEAC.CSVCheckSegsChecked);
  1523.  
  1524. };
  1525.  
  1526. WMEAC.reloadPresets = function ()
  1527. {
  1528. var optionList=WMEAC.presets.map(function (p, i) {
  1529. return '<option value="' + i + '">' + p.name + '</option>';
  1530. });
  1531. $("#wmeac-advanced-closure-dialog-presets-list").html(optionList.join(''));
  1532. };
  1533.  
  1534.  
  1535. /***********************************************
  1536. *** END OF INCLUDED FILE : ***
  1537. *** include/setupUI.js ***
  1538. ***********************************************/
  1539.  
  1540.  
  1541.  
  1542. /***********************************************
  1543. *** IN INCLUDED FILE : ***
  1544. *** include/class.progressBar.js ***
  1545. ***********************************************/
  1546.  
  1547. WMEAC.ProgressBar = function (id)
  1548. {
  1549. this.id=id;
  1550. this.divpbi = WMEAC.createElement({type: 'div', id: id, className: id});
  1551. var elt = WMEAC.createElement({type: 'div', id: 'wmeac-progressBar'});
  1552. elt.style.width="100%";
  1553. elt.style.display="none";
  1554. elt.innerHTML='<div class="wmeac-progressBarBG"></div><span class="wmeac-progressBarFG">100%</span>';
  1555. this.divpbi.appendChild(elt);
  1556. elt = WMEAC.createElement({type: 'div', id: 'wmeac-progressBar-info'});
  1557. //elt.innerHTML="&nbsp;";
  1558. this.divpbi.appendChild(elt);
  1559.  
  1560. this.isShown = function () {
  1561. return (this.divpbi.style.display != "none");
  1562. };
  1563. this.show = function(toShow)
  1564. {
  1565. this.divpbi.style.display = (toShow?"block":"none");
  1566. };
  1567. this.update = function(value)
  1568. {
  1569. if (value==-1)
  1570. {
  1571. this.divpbi.children[0].style.display='none';
  1572. this.divpbi.children[1].style.display='none';
  1573. return;
  1574. }
  1575. value = Math.round(value);
  1576. this.divpbi.children[0].style.display='block';
  1577. this.divpbi.children[1].style.display='block';
  1578. this.divpbi.children[0].children[0].style.width = value+"%";
  1579. this.divpbi.children[0].children[1].innerHTML = value+"%";
  1580. };
  1581. this.info = function(text)
  1582. {
  1583. this.divpbi.children[1].innerHTML=text;
  1584. };
  1585. };
  1586.  
  1587.  
  1588.  
  1589.  
  1590. /***********************************************
  1591. *** END OF INCLUDED FILE : ***
  1592. *** include/class.progressBar.js ***
  1593. ***********************************************/
  1594.  
  1595.  
  1596.  
  1597. /***********************************************
  1598. *** IN INCLUDED FILE : ***
  1599. *** include/class.closure.js ***
  1600. ***********************************************/
  1601.  
  1602. WMEAC.ClassClosure = function (options)
  1603. {
  1604. WMEAC.log("options", options);
  1605. this.isValid=false;
  1606. this.errorMessage='';
  1607. var validProperties=['reason', 'startDate', 'endDate', 'direction', 'segIDs', 'lonlat', 'permanent', 'id', 'zoom'];
  1608. var goodOptions=0;
  1609. validProperties.forEach(function (p) {
  1610. if (options.hasOwnProperty(p))
  1611. {
  1612. this[p]=options[p];
  1613. goodOptions++;
  1614. }
  1615. else
  1616. {
  1617. this.errorMessage+="Missing property " + p + "\n";
  1618. }
  1619. }, this);
  1620. if (goodOptions==validProperties.length)
  1621. {
  1622. this.isValid=true;
  1623. }
  1624. else
  1625. {
  1626. return;
  1627. }
  1628. // optional options:
  1629. this.comment="";
  1630. if (options.hasOwnProperty('comment')) this.comment=options.comment;
  1631. this.eventId=null;
  1632. if (options.hasOwnProperty('eventId') && options.eventId!='') this.eventId=options.eventId;
  1633. this.segIDs = this.segIDs.split(';');
  1634. var matches = this.lonlat.match(/lon=(-?\d+\.?\d*)&lat=(-?\d+\.?\d*)/);
  1635. if (matches && matches.length==3)
  1636. this.lonlat = {lon: parseFloat(matches[1]), lat: parseFloat(matches[2])};
  1637. else
  1638. {
  1639. matches = this.lonlat.match(/lat=(-?\d+\.?\d*)&lon=(-?\d+\.?\d*)/);
  1640. if (matches && matches.length==3)
  1641. this.lonlat = {lon: parseFloat(matches[2]), lat: parseFloat(matches[1])};
  1642. else
  1643. {
  1644. this.isValid=false;
  1645. this.errorMessage="Can't parse lonlat: " + this.lonlat + "\n";
  1646. return;
  1647. }
  1648. }
  1649. if (this.direction!="A to B" && this.direction!="B to A" && this.direction!="TWO WAY")
  1650. {
  1651. this.isValid=false;
  1652. this.errorMessage="Can't determine direction: " + this.direction + "\n";
  1653. return;
  1654. }
  1655. this.zoom = parseInt(this.zoom);
  1656. if (this.zoom<14||this.zoom>22)
  1657. {
  1658. this.isValid=false;
  1659. this.errorMessage="Wrong zoom (14 to 22): " + this.zoom + "\n";
  1660. return;
  1661. }
  1662. this.applyInWME = function(successHandler, failureHandler)
  1663. {
  1664. // check if segments are on screen
  1665. var segs = WMEAC.segmentsIDsToSegments(this.segIDs);
  1666. WMEAC.log("Segs: ", segs);
  1667.  
  1668. // check perms
  1669. segs = segs.filter(function (seg) {
  1670. return WMEAC.wmeSDK.DataModel.Segments.hasPermissions({permission: "EDIT_CLOSURES", segmentId: seg.id });
  1671. });
  1672.  
  1673. // SDK - need old style segment objects for now since closure code called getID() on these objects
  1674. var oldsegs = segs.map (function (e) {
  1675. return (W.model.segments.getObjectById(e.id));
  1676. });
  1677. if (segs.length==0)
  1678. {
  1679. failureHandler( {errors: [{attributes: {details: "No segment. Check permissions or existence."}}]} );
  1680. }
  1681. else
  1682. {
  1683. var cityStreets = WMEAC.getCityStreetsFromSegmentSet(segs);
  1684. var closureLocation = Object.keys(cityStreets).map(function (c) {
  1685. return (Object.keys(cityStreets[c]).map(function (s) {
  1686. if (s=='noStreet') return I18n.translations[I18n.locale].edit.address.no_street;
  1687. return s;
  1688. }).join(', ') + (c=='noCity'?'':' (' + c + ')'));
  1689. }).join(' ; ');
  1690. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  1691. var closureDetails = {reason: this.reason, direction: (this.direction=="A to B"?WMEAC.sharedClosureDirection.A_TO_B:(this.direction=="B to A"?WMEAC.sharedClosureDirection.B_TO_A:WMEAC.sharedClosureDirection.TWO_WAY)), startDate: this.startDate, endDate: this.endDate, location: closureLocation, permanent: this.permanent=='Yes', segments: oldsegs};
  1692. if (this.eventId!=null) closureDetails.eventId = this.eventId;
  1693. WMEAC.addClosure(closureDetails, successHandler, failureHandler);
  1694. }
  1695. };
  1696. this.removeInWME = function(successHandler, failureHandler)
  1697. {
  1698. var segs = WMEAC.segmentsIDsToSegments(this.segIDs);
  1699. // check perms
  1700. segs = segs.filter(function (seg) {
  1701. return WMEAC.wmeSDK.DataModel.Segments.hasPermissions({permission: "EDIT_CLOSURES", segmentId: seg.id });
  1702. });
  1703. var allClosuresToRemove=[];
  1704. var countToMatch=this.segIDs.length*(this.direction=="TWO WAY"?2:1); // two way = 2 closures in WME
  1705. segs.forEach(function (s) {
  1706. // look for closure(s)
  1707. var that = this;
  1708. // SDK - closures array needs to be internal objects, not new SDK closure object
  1709. /*var closures = WMEAC.wmeSDK.DataModel.RoadClosures.getAll().filter(function (c) {
  1710. return (c.startDate==that.startDate &&
  1711. c.endDate==that.endDate &&
  1712. c.description.trim()==that.reason &&
  1713. c.segmentId==s.id &&
  1714. c.isPermanent == (that.permanent=='Yes'));
  1715. });*/
  1716. var closures = W.model.roadClosures.getObjectArray(function (c) {
  1717. return (c.attributes.startDate==that.startDate &&
  1718. c.attributes.endDate==that.endDate &&
  1719. c.attributes.reason.trim()==that.reason &&
  1720. c.attributes.segID==s.id &&
  1721. c.attributes.permanent == (that.permanent=='Yes'));
  1722. });
  1723. if ((this.direction=="TWO WAY") || // && closures.length==2 && closures[0].forward!=closures[1].forward) ||
  1724. (this.direction=="A to B" && closures.length==1 && closures[0].attributes.forward==true) ||
  1725. (this.direction=="B to A" && closures.length==1 && closures[0].attributes.forward==false))
  1726. {
  1727. allClosuresToRemove=allClosuresToRemove.concat(closures);
  1728. }
  1729. }, this);
  1730. if (allClosuresToRemove.length==0)
  1731. {
  1732. failureHandler( {errors: [{attributes: {details: "No segment. Check permissions or existence."}}]} );
  1733. }
  1734. else
  1735. WMEAC.removeClosure(allClosuresToRemove, successHandler, failureHandler);
  1736. };
  1737. };
  1738.  
  1739.  
  1740. /***********************************************
  1741. *** END OF INCLUDED FILE : ***
  1742. *** include/class.closure.js ***
  1743. ***********************************************/
  1744.  
  1745.  
  1746. /***********************************************
  1747. *** IN INCLUDED FILE : ***
  1748. *** include/recurringClosures.js ***
  1749. ***********************************************/
  1750.  
  1751. WMEAC.buildClosuresListFromRecurringUI = function ()
  1752. {
  1753. var list = [];
  1754. var rangeStartDate = new JDate($('#wmeac-advanced-closure-dialog-rangestartdate').val());
  1755. if (!WMEAC.isValidDate(rangeStartDate)) return {list: list, error: "Range start date is not valid"};
  1756. var rangeEndDate = new JDate($('#wmeac-advanced-closure-dialog-rangeenddate').val());
  1757. if (!WMEAC.isValidDate(rangeEndDate)) return {list: list, error: "Range end date is not valid"};
  1758. if (rangeEndDate<rangeStartDate) return {list: list, error: "Range end date is before range start date"};
  1759. var dD = parseInt($('#wmeac-advanced-closure-dialog-duration-day').val());
  1760. if (isNaN(dD) || dD<0) return {list: list, error: "Duration days is invalid"};
  1761. // var dM = parseInt($('#wmeac-advanced-closure-dialog-duration-minute').val());
  1762. // if (isNaN(dM) || dM<0 || dM>=60) return {list: list, error: "Duration minute is invalid"};
  1763. var dH = parseInt($('#wmeac-advanced-closure-dialog-durationtime').val().split(':')[0]);
  1764. var dM = parseInt($('#wmeac-advanced-closure-dialog-durationtime').val().split(':')[1]);
  1765. if (dD==0 && dH==0 && dM==0) return {list: list, error: "Duration is null"};
  1766. // var rangeStartTimeM = $('#wmeac-advanced-closure-dialog-rangestarttime').val().split(':').map(function (e) {
  1767. // return parseInt(e);
  1768. // }).reduce(function (p, c, i) {
  1769. // return (p*60+c);
  1770. // });
  1771. var rangeStartTimeM = 0;
  1772. // var rangeEndTimeM = $('#wmeac-advanced-closure-dialog-rangeendtime').val().split(':').map(function (e) {
  1773. // return parseInt(e);
  1774. // }).reduce(function (p, c, i) {
  1775. // return (p*60+c);
  1776. // });
  1777. var rangeEndTimeM = 1440;
  1778. var rangeEndDateTime = rangeEndDate.clone();
  1779. rangeEndDateTime.addMinutes(rangeEndTimeM);
  1780. var startTimeM = $('#wmeac-advanced-closure-dialog-starttime').val().split(':').map(function (e) {
  1781. return parseInt(e);
  1782. }).reduce(function (p, c, i) {
  1783. return (p*60+c);
  1784. });
  1785. // if mode is REPEAT
  1786. if ($('#wmeac-advanced-closure-dialog-tabrepeat').attr('class').indexOf('active')!=-1)
  1787. {
  1788. var ntimes = parseInt($('#wmeac-advanced-closure-dialog-repeat-ntimes').val());
  1789. if (isNaN(ntimes) || ntimes<1) return {list: list, error: "Repeat count is invalid"};
  1790. var evD = parseInt($('#wmeac-advanced-closure-dialog-repeat-every-day').val());
  1791. if (isNaN(evD) || evD<0) return {list: list, error: "Repeat every day is invalid"};
  1792. var evH = parseInt($('#wmeac-advanced-closure-dialog-repeat-every-hour').val());
  1793. if (isNaN(evH) || evH<0) return {list: list, error: "Repeat every hour is invalid"};
  1794. var evM = parseInt($('#wmeac-advanced-closure-dialog-repeat-every-minute').val());
  1795. if (isNaN(evM) || evM<0 || evM>=60) return {list: list, error: "Repeat every minute is invalid"};
  1796. // if repeat is smaller than duration
  1797. if (evD * 1440 + evH * 60 + evM < dD * 1440 + dH * 60 + dM) return {list: list, error: "Repeat must be greater than duration"};
  1798. var firstDateTimeStart = rangeStartDate.clone();
  1799. if (startTimeM<rangeStartTimeM) // starts the day after
  1800. firstDateTimeStart.addDays(1);
  1801. firstDateTimeStart.setMinutes(startTimeM);
  1802. var firstDateTimeEnd = firstDateTimeStart.clone();
  1803. firstDateTimeEnd.addMinutes(dD * 1440 + dH * 60 + dM);
  1804. // var now = new Date();
  1805. for (var i=0; i<ntimes; i++)
  1806. {
  1807. var start = firstDateTimeStart.clone();
  1808. start.addMinutes((evD * 1440 + evH * 60 + evM)*i);
  1809. var end = start.clone();
  1810. end.addMinutes(dD * 1440 + dH * 60 + dM);
  1811. if (end > rangeEndDateTime) // stop if after range end
  1812. break;
  1813. // WMEAC.log('end', end);
  1814. // WMEAC.log('now', now);
  1815. // if (end < now) // do not add closure that ends before now
  1816. // {
  1817. // ntimes++;
  1818. // continue;
  1819. // }
  1820. list.push({start: WMEAC.dateToClosureStr(start), end: WMEAC.dateToClosureStr(end)});
  1821. }
  1822. return {list: list, error: ""};
  1823. }
  1824. // if mode is EACH
  1825. else if ($('#wmeac-advanced-closure-dialog-tabeach').attr('class').indexOf('active')!=-1)
  1826. {
  1827. // build bits for a week:
  1828. var dow = WMEAC.daysOfWeek.map(function (e, i) {
  1829. return ($('#wmeac-advanced-closure-dialog-each-' + i)).is(':checked');
  1830. });
  1831. var dayCount = Math.ceil((rangeEndDate-rangeStartDate+1)/86400000);
  1832. var day0 = rangeStartDate.clone();
  1833. day0.addMinutes(startTimeM);
  1834. if (startTimeM<rangeStartTimeM) // starts the day after
  1835. day0.addDays(1);
  1836. for (var d=0; d<dayCount; d++)
  1837. {
  1838. var start = day0.clone();
  1839. start.addMinutes(d*1440);
  1840. if (dow[start.getUTCDay()])
  1841. {
  1842. var end = start.clone();
  1843. end.addMinutes(dD * 1440 + dH * 60 + dM);
  1844. if (end > rangeEndDateTime) // stop if after range end
  1845. break;
  1846. list.push({start: WMEAC.dateToClosureStr(start), end: WMEAC.dateToClosureStr(end)});
  1847. }
  1848. }
  1849. return {list: list, error: ""};
  1850. }
  1851. else if ($('#wmeac-advanced-closure-dialog-tabholiday').attr('class').indexOf('active')!=-1)
  1852. {
  1853. WMEAC.lastGeneratedHolidays.forEach(function (e, i) {
  1854. if (($('#wmeac-advanced-closure-dialog-holidays-' + i)).is(':checked'))
  1855. {
  1856. var start = new JDate(e.date).addMinutes(startTimeM);
  1857. var end = start.clone();
  1858. end.addMinutes(dD * 1440 + dH * 60 + dM);
  1859. list.push({start: WMEAC.dateToClosureStr(start), end: WMEAC.dateToClosureStr(end)});
  1860. }
  1861. });
  1862. return {list: list, error: ""};
  1863. }
  1864. else
  1865. return {list: list, error: "Wrong tab active"};
  1866.  
  1867. };
  1868.  
  1869. WMEAC.refreshClosureList = function ()
  1870. {
  1871. try {
  1872. var rc = WMEAC.buildClosuresListFromRecurringUI();
  1873. if (rc.error!="")
  1874. $('#wmeac-csv-closures-preview-content').html(rc.error);
  1875. else
  1876. {
  1877. var reason = $('#wmeac-advanced-closure-dialog-reason').val();
  1878. //var cllocation = $('#wmeac-advanced-closure-dialog-location').val();
  1879. var direction = $('#wmeac-advanced-closure-dialog-direction').val();
  1880. var directionStr = direction==1?"(A &#8594; B)":(direction==2?"(B &#8594; A)":"(&#8646;)");
  1881. var isIT = $('#wmeac-advanced-closure-dialog-ignoretraffic').is(':checked');
  1882. const selection = WMEAC.wmeSDK.Editing.getSelection();
  1883. var existingClosures = [];
  1884. if (selection.ids.length > 0 && selection.objectType == "segment") {
  1885. //existingClosures = W.selectionManager.getSelectedWMEFeatures().reduce(function (p, c, i) {
  1886. existingClosures = selection.ids.reduce(function (p, c, i) {
  1887. var revSegs = W.selectionManager.getReversedSegments();
  1888. var isReversed = revSegs.hasOwnProperty(c) && revSegs[c];
  1889. var realWay = isReversed?(direction==1?2:1):direction;
  1890. //return p.concat(W.model.roadClosures.getObjectArray(function (e) {
  1891. return p.concat(WMEAC.wmeSDK.DataModel.RoadClosures.getAll().filter(e => {
  1892. return (e.segmentId==c &&
  1893. (direction==3 || (e.isForward && realWay==1) || (!e.isForward && realWay==2)));
  1894. }));
  1895. }, []);
  1896. }
  1897. const mte = WMEAC.wmeSDK.DataModel.MajorTrafficEvents.getById( { majorTrafficEventId: $("#wmeac-advanced-closure-dialog-mteid").val() } );
  1898. $('#wmeac-csv-closures-preview-content').html('' + rc.list.length + ' closure(s) to apply: <br>' +
  1899. rc.list.map(function (e, i) {
  1900. var overlap = existingClosures.filter(function (c) {
  1901. return WMEAC.dateTimeOverlaps({startDate: e.start, endDate: e.end}, c);
  1902. }).map(function (c) {
  1903. var msg = (c.reason?c.reason + ' ':'') + '(' + c.segmentId + ')';
  1904. const segAddr = WMEAC.wmeSDK.DataModel.Segments.getAddress( { segmentId: c.segmentId } );
  1905. var street = segAddr.street.name;
  1906. if (!segAddr.isEmpty) msg = street + ': ' + msg;
  1907. return msg;
  1908. });
  1909. var mteOK=!(mte && (new Date(e.start) < new Date(mte.startDate) || new Date(e.end) > new Date(mte.endDate)));
  1910. return (reason +
  1911. //' (' + cllocation + '): ' +
  1912. ': ' +
  1913. e.start + ' &#8594; ' + e.end +
  1914. ' ' + directionStr +
  1915. ' <i class="fa fa-car' + (isIT?" slashed":"") + '"></i>' +
  1916. (overlap.length!=0?' <i title="Warning: overlap on existing closure!\n' + overlap.join('\n') + '" class="fa fa-exclamation-circle" style="color: orange"></i>':'') +
  1917. (mteOK?'':' <i title="Warning: closure dates not inside MTE date!" class="fa fa-exclamation-circle" style="color: orange"></i>') +
  1918. ' <span id="wmeac-advanced-closure-dialog-preview-' + i + '"></span>');
  1919. }).join('<br>'));
  1920. }
  1921. }
  1922. catch (e)
  1923. {
  1924. WMEAC.logError("Error while refreshing closure list: ", e);
  1925. }
  1926. };
  1927.  
  1928. WMEAC.refreshMTEList = function ()
  1929. {
  1930. var currentMTEid = $("#wmeac-advanced-closure-dialog-mteid").val();
  1931. var rangeStart = new JDate($("#wmeac-advanced-closure-dialog-rangestartdate").val());
  1932. var rangeEnd = new JDate($("#wmeac-advanced-closure-dialog-rangeenddate").val());
  1933. var mtelist = [];
  1934. $("#wmeac-advanced-closure-dialog-mteid").empty();
  1935. if (WMEAC.isValidDate(rangeStart) && WMEAC.isValidDate(rangeEnd))
  1936. {
  1937. rangeEnd.addDays(1);
  1938. // filter MTE loaded in WME:
  1939. WMEAC.wmeSDK.DataModel.MajorTrafficEvents.getAll().filter((mte) => (WMEAC.dateTimeOverlaps({startDate: rangeStart, endDate: rangeEnd}, {startDate: new JDate(mte.startDate), endDate: new JDate(mte.endDate)}))
  1940. ).forEach(function (mte) {
  1941. mtelist.push({name: mte.names[0].value, value: mte.id});
  1942. });
  1943. }
  1944. mtelist.sort(function(a,b) {
  1945. return a.name.localeCompare(b.name);
  1946. });
  1947. WMEAC.addMTEitem('None', '', currentMTEid);
  1948. mtelist.forEach(function (o) {
  1949. WMEAC.addMTEitem(o.name, o.value, currentMTEid);
  1950. });
  1951. if (mtelist.length>0)
  1952. $("#wmeac-advanced-closure-dialog-mteid").removeAttr('disabled');
  1953. else
  1954. $("#wmeac-advanced-closure-dialog-mteid").attr('disabled', '');
  1955. };
  1956.  
  1957. WMEAC.addMTEitem = function (n, v, curId)
  1958. {
  1959. var el = WMEAC.createElement({type: 'option'});
  1960. el.setAttribute('value', v);
  1961. if (curId==v)
  1962. el.setAttribute('selected', '');
  1963. el.innerHTML = n;
  1964. $("#wmeac-advanced-closure-dialog-mteid").append(el);
  1965. };
  1966.  
  1967. WMEAC.refreshClosureListFromSelection = function ()
  1968. {
  1969. try
  1970. {
  1971. var currentSegClosure = $("#wmeac-advanced-closure-dialog-segclosure-list").val();
  1972. $("#wmeac-advanced-closure-dialog-segclosure-list").empty();
  1973. const sel = WMEAC.wmeSDK.Editing.getSelection();
  1974. if (sel && sel.ids.length!=0 && sel.objectType == "segment") {
  1975. var blackList=[];
  1976. WMEAC.wmeSDK.DataModel.RoadClosures.getAll().filter(function (c) {
  1977. return c.segmentId==sel.ids[0];
  1978. }).sort(function (a,b) {
  1979. return (new Date(a.startDate)-new Date(b.startDate));
  1980. }).forEach(function (c) {
  1981. if (blackList.indexOf(c.id)!=-1) return;
  1982. var direction = c.isForward?"A to B":"B to A";
  1983. var oppositeClosure = WMEAC.getOppositeClosure(c);
  1984. if (!oppositeClosure.length==0)
  1985. {
  1986. direction = "Two way";
  1987. blackList.push(oppositeClosure[0].id);
  1988. }
  1989. var el = WMEAC.createElement({type: 'option'});
  1990. el.setAttribute('value', c.id);
  1991. if (currentSegClosure==c.id)
  1992. el.setAttribute('selected', '');
  1993. el.innerHTML = c.description.trim() + ' ' + direction + ' ' + c.startDate + '&#8594;' + c.endDate;
  1994. $("#wmeac-advanced-closure-dialog-segclosure-list").append(el);
  1995. });
  1996. }
  1997. }
  1998. catch (e)
  1999. {
  2000. WMEAC.logError("Error while refreshing closure list from selection: ", e);
  2001. }
  2002. };
  2003.  
  2004. // SKIP_FILE('include/holidays.js');
  2005.  
  2006.  
  2007. /***********************************************
  2008. *** END OF INCLUDED FILE : ***
  2009. *** include/recurringClosures.js ***
  2010. ***********************************************/
  2011.  
  2012.  
  2013. /***********************************************
  2014. *** IN INCLUDED FILE : ***
  2015. *** include/actionClosures.js ***
  2016. ***********************************************/
  2017.  
  2018. WMEAC.addClosure = function (options, successHandler, failureHandler)
  2019. {
  2020. if (options &&
  2021. options.hasOwnProperty('segments') &&
  2022. options.hasOwnProperty('reason') &&
  2023. options.hasOwnProperty('direction') &&
  2024. options.hasOwnProperty('startDate') &&
  2025. options.hasOwnProperty('endDate') &&
  2026. options.hasOwnProperty('location') &&
  2027. options.hasOwnProperty('permanent'))
  2028. {
  2029. WMEAC.log("Adding closure: ", options);
  2030. var fail = function (e) {
  2031. return function (f) {
  2032. if (failureHandler)
  2033. failureHandler(f);
  2034. else
  2035. WMEAC.log("Failed to create closure:", f);
  2036. };
  2037. };
  2038. var done = function (e) {
  2039. return function (f) {
  2040. if (successHandler)
  2041. successHandler(f);
  2042. else
  2043. WMEAC.log("Closure successful:", f);
  2044. };
  2045. };
  2046. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  2047. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  2048. var t = {};
  2049. var closureDetails = {closures: [], attributions: [], reason: options.reason + String.fromCharCode(160), direction: options.direction, startDate: options.startDate, endDate: options.endDate, location: options.location, permanent: options.permanent, segments: options.segments, closuresType: 'roadClosure', reverseSegments: {}};
  2050. if (options.hasOwnProperty('eventId') && options.eventId!=null) closureDetails.eventId = options.eventId;
  2051. var c = new sc(closureDetails, {dataModel: W.model, segmentSelection: W.selectionManager.getSegmentSelection(), isNewClosure: true, closedNodesMap: {} });
  2052. WMEAC.setClosureNodes(c);
  2053. t.actions=[cab.add(c, W.loginManager.user, W.model)];
  2054. W.controller.save(t).then(done()).catch(fail());
  2055. return true;
  2056. }
  2057. return false;
  2058. };
  2059.  
  2060. WMEAC.setClosureNodes = function(shClosure)
  2061. {
  2062. for (const n of shClosure.closureNodes.models) {
  2063. if (!WMEAC.closeInsideNodes) {
  2064. n.attributes.isClosed = false;
  2065. }
  2066. }
  2067. };
  2068.  
  2069. WMEAC.addClosureListFromSelection = function (closureList, successHandler, failureHandler, endHandler, i)
  2070. {
  2071. if (i>=closureList.length)
  2072. {
  2073. WMEAC.reloadClosuresLayer(function () {
  2074. if (endHandler) endHandler();
  2075. });
  2076. return;
  2077. }
  2078. var c=closureList[i];
  2079. var fail = function (e) {
  2080. return function (f) {
  2081. if (failureHandler)
  2082. {
  2083. var details = [];
  2084. if (f.message) { console.error('AC: ' + f.message + ' - ' + f.stack); }
  2085. f.errors.forEach(function (err) {
  2086. if (err.hasOwnProperty('attributes') && err.attributes.hasOwnProperty('details'))
  2087. details.push(err.attributes.details);
  2088. });
  2089. failureHandler(i, details.join (' | '));
  2090. }
  2091. else
  2092. WMEAC.log("Failed to create closure:", f);
  2093. WMEAC.addClosureListFromSelection(closureList, successHandler, failureHandler, endHandler, i+1);
  2094. };
  2095. };
  2096. var done = function (e) {
  2097. return function (f) {
  2098. if (successHandler)
  2099. {
  2100. successHandler(i, "OK");
  2101. }
  2102. else
  2103. WMEAC.log("Closure successful:", f);
  2104. WMEAC.addClosureListFromSelection(closureList, successHandler, failureHandler, endHandler, i+1);
  2105. };
  2106. };
  2107.  
  2108. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  2109. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  2110. var t = {};
  2111. var segIDs = WMEAC.wmeSDK.Editing.getSelection();
  2112. var segs = WMEAC.segmentsIDsToSegments(segIDs);
  2113. // SDK - need old style segment objects for now since closure code called getID() on these objects
  2114. var oldsegs = segs.map (function (e) {
  2115. return (W.model.segments.getObjectById(e.id));
  2116. });
  2117. var cityStreets = WMEAC.getCityStreetsFromSegmentSet(segs);
  2118. var closureLocation = Object.keys(cityStreets).map(function (c) {
  2119. return (Object.keys(cityStreets[c]).map(function (s) {
  2120. if (s=='noStreet') return I18n.translations[I18n.locale].edit.address.no_street;
  2121. return s;
  2122. }).join(', ') + (c=='noCity'?'':' (' + c + ')'));
  2123. }).join(' ; ');
  2124. var closureDetails = {closures: [], attributions: [], 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: oldsegs, closuresType: 'roadClosure', reverseSegments: W.selectionManager.getReversedSegments()};
  2125. if (closureList[i].hasOwnProperty('eventId') && closureList[i].eventId!=null) closureDetails.eventId = closureList[i].eventId;
  2126. const ssel = W.selectionManager.getSegmentSelection();
  2127. var c = new sc(closureDetails, {dataModel: W.model, segmentSelection: ssel, isNewClosure: true, closedNodesMap: {} });
  2128. WMEAC.setClosureNodes(c);
  2129. t.actions=[cab.add(c, W.loginManager.user, W.model)];
  2130. W.controller.save(t).then(done()).catch(fail());
  2131. };
  2132.  
  2133. WMEAC.addClosureFromSelection = function (options, successHandler, failureHandler)
  2134. {
  2135. if (options &&
  2136. options.hasOwnProperty('reason') &&
  2137. options.hasOwnProperty('direction') &&
  2138. options.hasOwnProperty('startDate') &&
  2139. options.hasOwnProperty('endDate') &&
  2140. options.hasOwnProperty('location') &&
  2141. options.hasOwnProperty('permanent'))
  2142. {
  2143. WMEAC.log("Adding closure: ", options);
  2144. var fail = function (e) {
  2145. return function (f) {
  2146. if (failureHandler)
  2147. failureHandler(f);
  2148. else
  2149. WMEAC.log("Failed to create closure:", f);
  2150. };
  2151. };
  2152. var done = function (e) {
  2153. return function (f) {
  2154. if (successHandler)
  2155. successHandler(f);
  2156. else
  2157. WMEAC.log("Closure successful:", f);
  2158. };
  2159. };
  2160. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  2161. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  2162. var t = {};
  2163. var segIDs = WMEAC.wmeSDK.Editing.getSelection();
  2164. var segs = WMEAC.segmentsIDsToSegments(segIDs);
  2165. // SDK - need old style segment objects for now since closure code called getID() on these objects
  2166. var oldsegs = segs.map (function (e) {
  2167. return (W.model.segments.getObjectById(e.id));
  2168. });
  2169. var closureDetails = {closures: [], attributions: [], reason: options.reason + String.fromCharCode(160), direction: options.direction, startDate: options.startDate, endDate: options.endDate, location: options.location, permanent: options.permanent, segments: oldsegs, closuresType: 'roadClosure', reverseSegments: W.selectionManager.getReversedSegments()};
  2170. if (options.hasOwnProperty('eventId') && options.eventId!=null) closureDetails.eventId = options.eventId;
  2171. var c = new sc(closureDetails, {dataModel: W.model, segmentSelection: W.selectionManager.getSegmentSelection(), isNewClosure: true, closedNodesMap: {} });
  2172. WMEAC.setClosureNodes(c);
  2173. t.actions=[cab.add(c, W.loginManager.user, W.model)];
  2174. W.controller.save(t).then(done()).catch(fail());
  2175. return true;
  2176. }
  2177. return false;
  2178. };
  2179.  
  2180. WMEAC.removeClosure = function (closures, successHandler, failureHandler)
  2181. {
  2182. var fail = function (e) {
  2183. return function (f) {
  2184. if (failureHandler)
  2185. failureHandler(f);
  2186. else
  2187. WMEAC.log("Failed to delete closure:", f);
  2188. };
  2189. };
  2190. var done = function (e) {
  2191. return function (f) {
  2192. if (successHandler)
  2193. successHandler(f);
  2194. else
  2195. WMEAC.log("Closure deletion successful:", f);
  2196. };
  2197. };
  2198.  
  2199. var cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
  2200. var sc = require("Waze/Modules/Closures/Models/SharedClosure");
  2201. var t = {};
  2202. let segs = WMEAC.segmentsIDsToSegments(closures.map(closure => closure.attributes.segID)); // SDK - closures is internal objects for now
  2203. // SDK - need old style segment objects for now since closure code called getID() on these objects
  2204. var oldsegs = segs.map (function (e) {
  2205. return (W.model.segments.getObjectById(e.id));
  2206. });
  2207. var sclo = new sc({segments: oldsegs, closures, reverseSegments: W.selectionManager.getReversedSegments()}, {dataModel: W.model, segmentSelection: W.selectionManager.getSegmentSelection(), isNew: true});
  2208. t.actions=[cab.delete(W.model,sclo)];
  2209. W.controller.save(t).then(done()).catch(fail());
  2210. return true;
  2211. };
  2212.  
  2213.  
  2214. /***********************************************
  2215. *** END OF INCLUDED FILE : ***
  2216. *** include/actionClosures.js ***
  2217. ***********************************************/
  2218.  
  2219.  
  2220. // functions to load and save settings
  2221. /***********************************************
  2222. *** IN INCLUDED FILE : ***
  2223. *** include/saveLoad.js ***
  2224. ***********************************************/
  2225.  
  2226. WMEAC.save = function ()
  2227. {
  2228. WMEAC.log("save data...");
  2229. localStorage.WMEAC = JSON.stringify({presets: WMEAC.presets});
  2230. };
  2231.  
  2232. WMEAC.load = function ()
  2233. {
  2234. try
  2235. {
  2236. if (localStorage.WMEAC!==undefined && localStorage.WMEAC.length > 0) {
  2237. var saved = JSON.parse(localStorage.WMEAC);
  2238. WMEAC.presets = saved.presets;
  2239. WMEAC.log("presets", WMEAC.presets);
  2240. }
  2241. }
  2242. catch (err)
  2243. {
  2244. WMEAC.log("Error while loading data from storage: " , err);
  2245. }
  2246. };
  2247.  
  2248.  
  2249. /***********************************************
  2250. *** END OF INCLUDED FILE : ***
  2251. *** include/saveLoad.js ***
  2252. ***********************************************/
  2253.  
  2254.  
  2255.  
  2256. /***********************************************
  2257. *** IN INCLUDED FILE : ***
  2258. *** include/csv.js ***
  2259. ***********************************************/
  2260.  
  2261. WMEAC.parseCSV = function (csvString)
  2262. {
  2263. if (csvString!=null)
  2264. {
  2265. var csvArray = WMEAC.CSVtoArray(csvString);
  2266. WMEAC.log("CSV as array:", csvArray);
  2267. var isValid = WMEAC.csv[0].validate(csvArray);
  2268. if (isValid.isValid)
  2269. {
  2270. var closures = WMEAC.csv[0].filter(csvArray).map(function (e, i) {
  2271. 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};
  2272. });
  2273. closures.forEach(function (c) {
  2274. if (!c.closure.isValid) {
  2275. isValid.isValid = false;
  2276. isValid.feedBack += c.closure.errorMessage;
  2277. }
  2278. });
  2279. }
  2280. if (isValid.isValid) {
  2281. WMEAC.log("CSV is valid!");
  2282. WMEAC.log("Closure list:", closures);
  2283. WMEAC.csvCurrentClosureList = closures;
  2284. var listUI = WMEAC.getId('wmeac-csv-closures-list-elts');
  2285. // remove all closures before:
  2286. WMEAC.removeChildElements(listUI);
  2287. closures.forEach(function (c) {
  2288. c.UI = WMEAC.buildInlineClosureUI(c.closure, c.action);
  2289. listUI.appendChild(c.UI);
  2290. });
  2291. WMEAC.csvShowList(true);
  2292. WMEAC.csvAddLog("CSV parse successful\n");
  2293. return true;
  2294. // aply closures: TEST ONLY: this should not be done there!
  2295. /*closures.forEach(function (c) {
  2296. c.closure.applyInWME(function () { WMEAC.log("Closure success:", c);});
  2297. });*/
  2298. // END OF aply closures: TEST ONLY: this should not be done there!
  2299. }
  2300. else
  2301. {
  2302. WMEAC.log("CSV is NOT valid!:" + isValid.feedBack + "\n");
  2303. WMEAC.csvAddLog(isValid.feedBack + '\n');
  2304. WMEAC.csvShowList(false);
  2305. WMEAC.csvCurrentClosureList = null;
  2306. return false;
  2307. }
  2308. return false;
  2309. }
  2310. return false;
  2311. };
  2312.  
  2313. WMEAC.ReadFiles = function (files)
  2314. {
  2315. for (var i = 0, f; f = files[i]; i++)
  2316. {
  2317. var reader = new FileReader();
  2318. reader.onload = (function(theFile) {
  2319. return function(e) {
  2320. WMEAC.log("import CSV file read");
  2321. WMEAC.csvClearLog();
  2322. if (WMEAC.parseCSV(e.target.result))
  2323. {
  2324. WMEAC.csvCurrentBatchClosureList=WMEAC.csvCurrentClosureList.slice();
  2325. // WMEAC.csvCheckAllSegments(-1);
  2326. }
  2327. };
  2328. })(f);
  2329.  
  2330. // Read in the image file as a data URL.
  2331. reader.readAsText(f);
  2332. }
  2333. this.value = null;
  2334. WMEAC.getId('wmeac-csv-closures-controls-check').checked=false;
  2335. };
  2336.  
  2337. WMEAC.ClassCSV = function (options)
  2338. {
  2339. this.isValid=false;
  2340. if (options.hasOwnProperty('version'))
  2341. this.version=options.version;
  2342. else return;
  2343. if (options.hasOwnProperty('regexpValidation'))
  2344. this.regexpValidation=options.regexpValidation;
  2345. else return;
  2346. this.isValid=true;
  2347. this.validate = function(data)
  2348. {
  2349. var regexps = this.regexpValidation;
  2350. var feedBack = "";
  2351. this.filter(data).forEach(function (line, l) {
  2352. var isLineValid = line.reduce(function (stillValid, cell, i) {
  2353. var isCellValid = cell.match(regexps[i])!=null;
  2354. if (!isCellValid)
  2355. feedBack+="Error while parsing line " + l + " cell " + i + ": \"" + cell + "\" in line " + line.join(',');
  2356. return (stillValid && isCellValid);
  2357. }, true);
  2358. }, this);
  2359. return {isValid: feedBack=="", feedBack: feedBack};
  2360. };
  2361. this.filter = function(data)
  2362. {
  2363. return data.filter(function (line) {
  2364. // return (line.length>=1 && line[0]!="header" && line[0]!="comment");
  2365. return (line.length>=1 && ['add','remove'].indexOf(line[0])!=-1);
  2366. });
  2367. };
  2368. };
  2369.  
  2370. WMEAC.csv.push(new WMEAC.ClassCSV({version: 1, regexpValidation: [/.*/, // 1st cell: action is free keyword. It will be filtered later
  2371. /.*/, // reason is free
  2372. // /.*/, // location is free
  2373. /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, // start date
  2374. /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, // end date
  2375. /(^A to B$)|(^B to A$)|(^TWO WAY$)/, // direction
  2376. /(Yes)|(No)/, // ignore trafic = permanent
  2377. /^(\d+(;|$))+/, // seg ID list
  2378. /(lon=(-?\d+\.?\d*)&lat=(-?\d+\.?\d*))|(lat=(-?\d+\.?\d*)&lon=(-?\d+\.?\d*))/, // lonlat
  2379. /^\d+$/, // zoom
  2380. /(^$)|(^-?\d+\.-?\d+\.-?[0-9a-fA-F\-]{4,36}$)/ // MTE ID is empty or digits.digits.[digits-or-guid]
  2381. ]}));
  2382. WMEAC.buildInlineClosureUI = function (closure, action)
  2383. {
  2384. var liElt = WMEAC.createElement({type: 'li', className: 'wmeac-csv-closures-list-' + action});
  2385. liElt.setAttribute('closureID', closure.id);
  2386. liElt.innerHTML='<div class="wmeac-csv-closures-list-col-action"><input type="checkbox" /></div>\
  2387. <div class="wmeac-csv-closures-list-col-lr"><div title="' + closure.reason + '">' + closure.reason + '</div><div title="' + closure.comment + '">' + closure.comment + '</div></div>\
  2388. <div class="wmeac-csv-closures-list-col-dates"><div title="' + closure.startDate + '">' + closure.startDate + '</div><div title="' + closure.endDate + '">' + closure.endDate + '</div></div>\
  2389. <div class="wmeac-csv-closures-list-col-dir">' + (closure.direction=="A to B"?'A&#8594;B':(closure.direction=="B to A"?'B&#8594;A':'A&#8596;B')) + '</div>\
  2390. <div class="wmeac-csv-closures-list-col-it"><input type="checkbox" ' + (closure.permanent=="Yes"?'checked':'') + ' disabled/></div>\
  2391. <div class="wmeac-csv-closures-list-col-target"><a href="' + WMEAC.buildPermalink({lon: closure.lonlat.lon, lat: closure.lonlat.lat, segments: closure.segIDs.join(','), zoom: closure.zoom}) + '" title="Go there!"><i class="fa fa-crosshairs"></i></a></div>\
  2392. <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>\
  2393. <div class="wmeac-csv-closures-minilog" style="display: block;">' + (action=='add'?'Ready to apply':(action=='remove'?'Ready to remove':'')) + '</div>';
  2394. // attach handlers
  2395. liElt.children[5].children[0].addEventListener('click', function (e) { // select the segs on this line of the CSV
  2396. WMEAC.csvClearLog();
  2397. // get closure id:
  2398. var cid = parseInt(e.target.parentNode.parentNode.parentNode.getAttribute('closureID'));
  2399. var closure = WMEAC.csvCurrentClosureList.find(function (c) {
  2400. return (c.closure.id==cid);
  2401. });
  2402. WMEAC.log('Closure to target:', closure);
  2403. WMEAC.wmeSDK.Map.setMapCenter( { lonLat: closure.closure.lonlat, zoomLevel: closure.closure.zoom } );
  2404. var tmp3 = function selectSegments()
  2405. {
  2406. WMEAC.log("Now select segments...");
  2407. var segs = WMEAC.segmentsIDsToSegments(closure.closure.segIDs);
  2408. if (segs.length!=closure.closure.segIDs.length)
  2409. {
  2410. if (segs.length==0)
  2411. {
  2412. WMEAC.csvAddLog("No segment found: " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  2413. WMEAC.setCSVMiniLog(closure, "Selection failed: no segment found", 3);
  2414. }
  2415. else
  2416. {
  2417. WMEAC.csvAddLog("Partial selection (" + segs.length + "/" + closure.closure.segIDs.length + "): " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  2418. WMEAC.setCSVMiniLog(closure, "Partial selection: " + segs.length + "/" + closure.closure.segIDs.length, 2);
  2419. }
  2420. alert ("Warning: missing segments.\nFound " + segs.length + "/" + closure.closure.segIDs.length + " segment(s)");
  2421. }
  2422. else
  2423. {
  2424. WMEAC.csvAddLog("Selection ok (" + segs.length + "): " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  2425. WMEAC.setCSVMiniLog(closure, "Selection OK: " + segs.length, 1);
  2426. }
  2427. if (segs.length!=0)
  2428. {
  2429. const selection = { ids: closure.closure.segIDs, objectType: 'segment' };
  2430. WMEAC.wmeSDK.Editing.setSelection( { selection } );
  2431. var tmp = function selectionReady()
  2432. {
  2433. if (W.selectionManager.getSelectedFeatures().length==0)
  2434. window.setTimeout(selectionReady, 500);
  2435. else
  2436. {
  2437. const ed = document.getElementsByClassName('segment-feature-editor');
  2438. const tabs = ed[0].querySelector('wz-tabs');
  2439. const tl = tabs.shadowRoot.querySelectorAll('.wz-tab-label');
  2440. if ( tl && tl.length > 0) {
  2441. tl[1].click(); // do we want to select the closures tab ?
  2442. }
  2443. }
  2444. };
  2445. window.setTimeout(tmp, 500);
  2446. }
  2447. };
  2448. var tmp2 = function readyToSelect() {
  2449. WMEAC.log("Test if ready to select...");
  2450. if (W.app.layout.model.attributes.pendingOperations.length > 0 || W.app.layout.model.attributes.loadingFeatures==true)
  2451. {
  2452. WMEAC.log("Not yet. Waiting for WME...");
  2453. window.setTimeout(readyToSelect, 500);
  2454. }
  2455. else
  2456. {
  2457. tmp3();
  2458. }
  2459. };
  2460. var tmp1 = function mapMovedEnd() {
  2461. WMEAC.log("Test if roads are reloaded...");
  2462. if (W.app.layout.model.attributes.pendingOperations.length > 0 || W.app.layout.model.attributes.loadingFeatures==true)
  2463. {
  2464. WMEAC.log("Not yet. Waiting for WME...");
  2465. window.setTimeout(mapMovedEnd, 500);
  2466. }
  2467. else
  2468. {
  2469. WMEAC.reloadRoadLayer();
  2470. tmp2();
  2471. }
  2472. };
  2473. window.setTimeout(tmp1, 500);
  2474. e.preventDefault();
  2475. });
  2476. liElt.children[6].children[0].addEventListener('click', function (e) { // apply closure on the segs on this line of the CSV
  2477. // get closure id:
  2478. WMEAC.csvClearLog();
  2479. var liElt = e.target.parentNode.parentNode.parentNode;
  2480. var cid = parseInt(liElt.getAttribute('closureID'));
  2481. var closure = WMEAC.csvCurrentClosureList.find(function (c) {
  2482. return (c.closure.id==cid);
  2483. });
  2484. WMEAC.log('Closure to apply:', closure);
  2485. WMEAC.csvApplyClosure(closure, null);
  2486. });
  2487. return liElt;
  2488. };
  2489.  
  2490. WMEAC.csvApplyClosure = function(closure, handler)
  2491. {
  2492. WMEAC.wmeSDK.Map.setMapCenter( { lonLat: closure.closure.lonlat, zoomLevel: closure.closure.zoom } );
  2493. function applySuccess(evt)
  2494. {
  2495. WMEAC.csvAddLog("Closure OK: " + closure.closure.comment + "(" + closure.closure.reason + ")\n");
  2496. closure.UI.className="wmeac-csv-closures-list-done";
  2497. WMEAC.setCSVMiniLog(closure, "OK", 1);
  2498. handler && handler(true);
  2499. };
  2500. function applyFailure(evt)
  2501. {
  2502. var details="";
  2503. evt.errors.forEach(function (err) {
  2504. if (err.hasOwnProperty('attributes') && err.attributes.hasOwnProperty('details'))
  2505. details += err.attributes.details + "\n";
  2506. });
  2507. WMEAC.csvAddLog("Closure KO: " + closure.closure.comment + " (" + closure.closure.reason + ")\n" + details + "\n");
  2508. WMEAC.setCSVMiniLog(closure, "KO: " + details, 3);
  2509. closure.UI.className="wmeac-csv-closures-list-failed";
  2510. handler && handler(false);
  2511. };
  2512. var tmp3 = function applyClosure()
  2513. {
  2514. WMEAC.log("Now apply closure...");
  2515. if (closure.action=="add")
  2516. closure.closure.applyInWME(applySuccess, applyFailure);
  2517. else if (closure.action=='remove')
  2518. closure.closure.removeInWME(applySuccess, applyFailure);
  2519. };
  2520. var tmp2 = function readyToApply() {
  2521. WMEAC.log("Test if ready to apply...");
  2522. if (W.app.layout.model.attributes.pendingOperations.length > 0 || W.app.layout.model.attributes.loadingFeatures==true)
  2523. {
  2524. WMEAC.log("Not yet. Waiting for WME...");
  2525. window.setTimeout(readyToApply, 500);
  2526. }
  2527. else
  2528. {
  2529. tmp3();
  2530. }
  2531. };
  2532. var tmp1 = function mapMovedEnd() {
  2533. WMEAC.log("Test if roads are reloaded...");
  2534. if (W.app.layout.model.attributes.pendingOperations.length > 0 || W.app.layout.model.attributes.loadingFeatures==true)
  2535. {
  2536. WMEAC.log("Not yet. Waiting for WME...");
  2537. window.setTimeout(mapMovedEnd, 500);
  2538. }
  2539. else
  2540. {
  2541. WMEAC.reloadRoadLayer();
  2542. tmp2();
  2543. }
  2544. };
  2545. window.setTimeout(tmp1, 1500);
  2546. };
  2547.  
  2548. WMEAC.csvAddLog = function(text)
  2549. {
  2550. var divLog = WMEAC.getId('wmeac-csv-closures-log');
  2551. divLog.innerHTML += text.replace(/\n/g, "<br>");
  2552. };
  2553.  
  2554. WMEAC.csvClearLog = function()
  2555. {
  2556. var divLog = WMEAC.getId('wmeac-csv-closures-log');
  2557. divLog.innerHTML = "";
  2558. };
  2559.  
  2560. WMEAC.csvShowList = function(show)
  2561. {
  2562. var divList = WMEAC.getId('wmeac-csv-closures');
  2563. divList.style.display=(show?"block":"none");
  2564. };
  2565.  
  2566. WMEAC.csvCheckAllSegments = function (i)
  2567. {
  2568. if (i==-1) // firt call: init progressbar
  2569. {
  2570. WMEAC.pb.update(0);
  2571. WMEAC.pb.show(true);
  2572. // and call the check on first closure
  2573. window.setTimeout(function () { WMEAC.csvCheckAllSegments(0); });
  2574. return;
  2575. }
  2576. var continueSegmentCheck = function()
  2577. {
  2578. window.setTimeout(function () { WMEAC.csvCheckAllSegments(i+1); });
  2579. };
  2580. if (i<WMEAC.csvCurrentBatchClosureList.length)
  2581. {
  2582. var currentClosure = WMEAC.csvCurrentBatchClosureList[i];
  2583. WMEAC.pb.update(i*100/WMEAC.csvCurrentBatchClosureList.length);
  2584. WMEAC.pb.info("Scanning segments. please wait...");
  2585. // check segments
  2586. // catch window tile
  2587. var c = OpenLayers.Layer.SphericalMercator.forwardMercator(currentClosure.closure.lonlat.lon, currentClosure.closure.lonlat.lat);
  2588. var b = W.map.calculateBounds();
  2589. var b1 = new OpenLayers.Bounds(b[0],b[1],b[2],b[3]);
  2590. b1 = b1.transform(new OpenLayers.Projection("EPSG:4326"), W.map.getProjectionObject());
  2591. var zoomRatio = Math.pow(2, W.map.zoom - currentClosure.closure.zoom);
  2592. var w = b1.getWidth()*1.7*zoomRatio;
  2593. var h = b1.getHeight()*1.7*zoomRatio;
  2594.  
  2595. var tileBounds = new OpenLayers.Bounds(c.lon - w / 2, c.lat - h / 2, c.lon + w / 2, c.lat + h / 2);
  2596. tileBounds=tileBounds.transform(W.map.getProjectionObject(), new OpenLayers.Projection("EPSG:4326")).toBBOX();
  2597. var roadTypes = (WMEAC.zoomToRoadType(currentClosure.closure.zoom)==-1?_.range(1, 22):WMEAC.zoomToRoadType(currentClosure.closure.zoom));
  2598. var req = new XMLHttpRequest();
  2599. req.open('GET', document.location.protocol + '//' + document.location.host + W.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);
  2600. req.onreadystatechange = function (e) {
  2601. if (req.readyState == 4) {
  2602. if(req.status == 200)
  2603. {
  2604. //WMEAC.log(req.responseText);
  2605. try {
  2606. var data = JSON.parse(req.responseText);
  2607. WMEAC.log("data", data);
  2608. var existingSegs = currentClosure.closure.segIDs.filter(function (sid) {
  2609. return (data.segments.objects.find(function (seg) {
  2610. return (sid == seg.id);
  2611. })!=null);
  2612. });
  2613. var editableClosuresSegs = currentClosure.closure.segIDs.filter(function (sid) {
  2614. return (data.segments.objects.find(function (seg) {
  2615. let editable = false;
  2616. if (sid == seg.id) {
  2617. try {
  2618. editable = WMEAC.wmeSDK.DataModel.Segments.hasPermissions({permission: "EDIT_CLOSURES", segmentId: seg.id });
  2619. } catch(e) {
  2620. // console.debug('AC: err checking perm: ',e);
  2621. editable = true; // not in current data model, assume editable
  2622. }
  2623. }
  2624. return editable;
  2625. })!=null);
  2626. });
  2627. // look for closures on existing segs and build overlap list
  2628. var overlaps=[];
  2629. var removeMatches = 0;
  2630. var existingClosures = existingSegs.forEach(function (sid) {
  2631. var cl = data.roadClosures.objects.filter(function (c) {
  2632. return (c.segID==sid);
  2633. });
  2634. // console.log('cl', cl);
  2635. cl.forEach(function (c) {
  2636. if (currentClosure.action == 'remove') {
  2637. if (currentClosure.closure.startDate == c.startDate && currentClosure.closure.endDate == c.endDate) {
  2638. removeMatches++;
  2639. }
  2640. }
  2641. else {
  2642. var forwardMustBe = currentClosure.closure.direction=="A to B"?true:(currentClosure.closure.direction=="B to A"?false:null);
  2643. console.log('forwardMustBe', forwardMustBe);
  2644. console.log('dateTimeOverlaps', currentClosure.closure);
  2645. console.log('dateTimeOverlaps', c);
  2646. if (WMEAC.dateTimeOverlaps(currentClosure.closure, c))
  2647. {
  2648. if (forwardMustBe==null || forwardMustBe==c.forward)
  2649. {
  2650. var segment = data.segments.objects.find(function (seg) {
  2651. return seg.id==sid;
  2652. });
  2653. var streetName=null;
  2654. if (segment && segment.primaryStreetID!=null)
  2655. {
  2656. var street = data.streets.objects.find(function (st) {
  2657. return st.id==segment.primaryStreetID;
  2658. });
  2659. if (street && street.name!=null)
  2660. streetName=street.name;
  2661. }
  2662. overlaps.push('Overlap with ' + c.reason + (streetName!=null?' :'+streetName:'') + ' (' + sid + ')');
  2663. }
  2664. }
  2665. }
  2666. });
  2667. });
  2668. if (existingSegs.length == currentClosure.closure.segIDs.length &&
  2669. editableClosuresSegs.length == currentClosure.closure.segIDs.length &&
  2670. overlaps.length==0 && (currentClosure.action == 'add' || removeMatches >= existingSegs.length) )
  2671. {
  2672. WMEAC.csvAddLog("Seg check OK: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\n" + existingSegs.length + " editable seg(s) found\n");
  2673. WMEAC.setCSVMiniLog(currentClosure, "segs OK: " + existingSegs.length + " editable seg(s) found", 1);
  2674. }
  2675. else if (currentClosure.action == 'remove') {
  2676. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + ") No matching closures\n");
  2677. WMEAC.setCSVMiniLog(currentClosure, "segs KO: no matches", 2);
  2678. }
  2679. else if (existingSegs.length == currentClosure.closure.segIDs.length &&
  2680. editableClosuresSegs.length == currentClosure.closure.segIDs.length &&
  2681. overlaps.length!=0)
  2682. {
  2683. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nOverlap detected on existing closures:\n" + overlaps.join('\n') + '\n');
  2684. WMEAC.setCSVMiniLog(currentClosure, "segs KO: " + overlaps.length + " overlap(s) detected", 2);
  2685. }
  2686. else if (existingSegs.length == currentClosure.closure.segIDs.length &&
  2687. editableClosuresSegs.length != currentClosure.closure.segIDs.length)
  2688. {
  2689. 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");
  2690. 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);
  2691. }
  2692. else
  2693. {
  2694. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\n" + existingSegs.length + "/" + currentClosure.closure.segIDs.length + " seg(s) found\n");
  2695. WMEAC.setCSVMiniLog(currentClosure, "segs KO: " + existingSegs.length + "/" + currentClosure.closure.segIDs.length + " seg(s) found", 3);
  2696. }
  2697. }
  2698. catch (err)
  2699. {
  2700. WMEAC.log("Failed to parse Waze's server response: " + req.responseText);
  2701. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nFailed to parse response from Waze\n");
  2702. WMEAC.setCSVMiniLog(currentClosure, "segs KO: Failed to parse response from Waze", 3);
  2703. }
  2704. }
  2705. else
  2706. {
  2707. WMEAC.log("Error on road tile: " + e.target.status);
  2708. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nCommunication failed with Waze\n");
  2709. WMEAC.setCSVMiniLog(currentClosure, "segs KO: Communication failed with Waze", 3);
  2710. }
  2711. continueSegmentCheck();
  2712. }
  2713. };
  2714. req.onError = function (e) {
  2715. WMEAC.log("Error on road tile: " + e.target.status);
  2716. WMEAC.csvAddLog("Seg check KO: " + currentClosure.closure.comment + " (" + currentClosure.closure.reason + "):\nCommunication failed with Waze's server\n");
  2717. WMEAC.setCSVMiniLog(currentClosure, "segs KO: Communication failed with Waze", 3);
  2718. continueSegmentCheck();
  2719. };
  2720. /* // Useless since waze server never send content length... :/
  2721. req.onprogress = function(e) {
  2722. WMEAC.pb.update((i+(e.position / e.totalSize))*100/WMEAC.csvCurrentClosureList.length);
  2723. };*/
  2724. req.send(null);
  2725. }
  2726. else // end of check
  2727. {
  2728. WMEAC.pb.show(false);
  2729. }
  2730.  
  2731. };
  2732.  
  2733. WMEAC.setCSVMiniLog = function(closure, text, level) // level=0: black 1: green, 2:orange, 3: red
  2734. {
  2735. var c=null;
  2736. if (closure.hasOwnProperty('UI'))
  2737. c=closure;
  2738. else
  2739. c = WMEAC.csvCurrentClosureList.find(function (e) {
  2740. return (e.closure.id == closure.id);
  2741. });
  2742.  
  2743. if (c!=null)
  2744. {
  2745. c.UI.children[7].innerHTML=text;
  2746. var colors = ["var(--content_p1)", "var(--safe)", "var(--cautious)", "var(--alarming)"];
  2747. if (arguments.length==3)
  2748. c.UI.children[7].style.color=colors[level];
  2749. else
  2750. c.UI.children[7].style.color=colors[0];
  2751. }
  2752. };
  2753.  
  2754. WMEAC.CSVCheckAll = function (check)
  2755. {
  2756. WMEAC.csvCurrentClosureList.forEach(function (e) {
  2757. e.UI.children[0].children[0].checked = check;
  2758. });
  2759. };
  2760.  
  2761. WMEAC.CSVApplyChecked = function ()
  2762. {
  2763. WMEAC.csvCurrentBatchClosureList = WMEAC.csvCurrentClosureList.filter(function (e) {
  2764. return (e.UI.children[0].children[0].checked);
  2765. });
  2766. WMEAC.csvClearLog();
  2767. if (WMEAC.csvCurrentBatchClosureList.length==0)
  2768. {
  2769. WMEAC.csvAddLog("No closure checked!\n");
  2770. }
  2771. else
  2772. {
  2773. WMEAC.showClosuresLayer(true);
  2774. WMEAC.pb.update(0);
  2775. WMEAC.pb.info("Applying closures. please wait...");
  2776. WMEAC.pb.show(true);
  2777. WMEAC.csvAddLog("Start to apply selected closures\n");
  2778. window.setTimeout(function () { WMEAC.CSVBatchApply(0); });
  2779. }
  2780. };
  2781.  
  2782. WMEAC.CSVBatchApply = function(i)
  2783. {
  2784. WMEAC.pb.update(i*100/WMEAC.csvCurrentBatchClosureList.length);
  2785.  
  2786. if (i<WMEAC.csvCurrentBatchClosureList.length)
  2787. {
  2788. if (WMEAC.csvCurrentBatchClosureList[i].action!='add' &&
  2789. WMEAC.csvCurrentBatchClosureList[i].action!='remove')
  2790. {
  2791. WMEAC.csvAddLog("Closure KO: " + WMEAC.csvCurrentBatchClosureList[i].closure.comment + " (" + WMEAC.csvCurrentBatchClosureList[i].closure.reason + "): action " + WMEAC.csvCurrentBatchClosureList[i].action + " not supported yet\n");
  2792. WMEAC.setCSVMiniLog(WMEAC.csvCurrentBatchClosureList[i], "KO: action " + WMEAC.csvCurrentBatchClosureList[i].action + " not supported yet", 2);
  2793. WMEAC.CSVBatchApply(i+1);
  2794. }
  2795. else
  2796. {
  2797. WMEAC.csvApplyClosure(WMEAC.csvCurrentBatchClosureList[i], function (success) {
  2798. //if (success)
  2799. // WMEAC.csvAddLog("Closure OK: " + WMEAC.csvCurrentBatchClosureList[i].closure.comment + " (" + WMEAC.csvCurrentBatchClosureList[i].closure.reason + ")\n");
  2800. //else
  2801. // WMEAC.csvAddLog("Closure KO: " + WMEAC.csvCurrentBatchClosureList[i].closure.comment + " (" + WMEAC.csvCurrentBatchClosureList[i].closure.reason + ")\n");
  2802. WMEAC.CSVBatchApply(i+1);
  2803. });
  2804. }
  2805. }
  2806. else
  2807. {
  2808. WMEAC.csvAddLog("Apply selected closures ended\n");
  2809. WMEAC.reloadClosuresLayer();
  2810. WMEAC.pb.show(false);
  2811. }
  2812. };
  2813.  
  2814. WMEAC.CSVCheckSegsChecked = function ()
  2815. {
  2816. WMEAC.csvClearLog();
  2817. WMEAC.csvCurrentBatchClosureList = WMEAC.csvCurrentClosureList.filter(function (e) {
  2818. return (e.UI.children[0].children[0].checked);
  2819. });
  2820. if (WMEAC.csvCurrentBatchClosureList.length==0)
  2821. {
  2822. WMEAC.csvAddLog("No closure checked!\n");
  2823. }
  2824. else
  2825. {
  2826. WMEAC.csvCheckAllSegments(-1);
  2827. }
  2828. };
  2829.  
  2830.  
  2831. /***********************************************
  2832. *** END OF INCLUDED FILE : ***
  2833. *** include/csv.js ***
  2834. ***********************************************/
  2835.  
  2836.  
  2837. // DONT_INCL_FILE('include/highlight.js');
  2838. //2023-08-20 remove obsolete require patch
  2839.  
  2840. WMEAC.WMEAPI={require: window.require};
  2841. // start normally
  2842. WMEAC.log("starting");
  2843. WMEAC.bootstrapAC();
  2844.  
  2845. })();