WME Virginia DOT Reports

Display VA transportation department reports in WME.

  1. // ==UserScript==
  2. // @name WME Virginia DOT Reports
  3. // @namespace https://gf.qytechs.cn/users/45389
  4. // @version 2020.01.19.001
  5. // @description Display VA transportation department reports in WME.
  6. // @author MapOMatic
  7. // @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
  8. // @grant GM_xmlhttpRequest
  9. // @connect iteriscdn.com
  10. // @connect 511virginia.org
  11.  
  12. // ==/UserScript==
  13.  
  14. /* global $ */
  15. /* global OpenLayers */
  16. /* global GM_info */
  17. /* global W */
  18. /* global GM_xmlhttpRequest */
  19. /* global unsafeWindow */
  20. /* global Waze */
  21. /* global Components */
  22. /* global I18n */
  23.  
  24. (function() {
  25. 'use strict';
  26.  
  27. var _window = unsafeWindow ? unsafeWindow : window;
  28.  
  29. var _settingsStoreName = 'va_dot_report_settings';
  30. var _alertUpdate = false;
  31. var _debugLevel = 0;
  32. var _scriptVersion = GM_info.script.version;
  33. var _scriptVersionChanges = [
  34. GM_info.script.name + '\nv' + _scriptVersion + '\n\nWhat\'s New\n------------------------------',
  35. '\n- All reports are displayed.'
  36. ].join('');
  37.  
  38. var _imagesPath = 'https://github.com/mapomatic/wme-virginia-dot-reports/raw/master/images/';
  39. var _mapLayer = null;
  40. var _settings = {};
  41. var _tabDiv = {}; // stores the user tab div so it can be restored after switching back from Events mode to Default mode
  42. var _reports = [];
  43. var _lastShownTooltipDiv;
  44. var _tableSortKeys = [];
  45. var _columnSortOrder = ['properties.icon','properties.location_description','archived'];
  46. var _reportTitles = {weather_closure: 'WEATHER CLOSURE', incident: 'INCIDENT', construction: 'CONSTRUCTION', high_impact_incident: 'HIGH PRIORTITY INCIDENT' };
  47.  
  48. function log(message, level) {
  49. if (message && level <= _debugLevel) {
  50. console.log('VA DOT Reports: ' + message);
  51. }
  52. }
  53.  
  54. function saveSettingsToStorage() {
  55. if (localStorage) {
  56. var settings = {
  57. lastVersion: _scriptVersion,
  58. layerVisible: _mapLayer.visibility,
  59. state: _settings.state,
  60. hideArchivedReports: $('#hideVADotArchivedReports').is(':checked'),
  61. archivedReports:_settings.archivedReports
  62. };
  63. localStorage.setItem(_settingsStoreName, JSON.stringify(settings));
  64. log('Settings saved', 1);
  65. }
  66. }
  67.  
  68. function dynamicSort(property) {
  69. var sortOrder = 1;
  70. if(property[0] === "-") {
  71. sortOrder = -1;
  72. property = property.substr(1);
  73. }
  74. return function (a,b) {
  75. var props = property.split('.');
  76. props.forEach(function(prop) {
  77. a = a[prop];
  78. b = b[prop];
  79. });
  80. var result = (a < b) ? -1 : (a > b) ? 1 : 0;
  81. return result * sortOrder;
  82. };
  83. }
  84.  
  85. function dynamicSortMultiple() {
  86. /*
  87. * save the arguments object as it will be overwritten
  88. * note that arguments object is an array-like object
  89. * consisting of the names of the properties to sort by
  90. */
  91. var props = arguments;
  92. if (arguments[0] && Array.isArray(arguments[0])) {
  93. props = arguments[0];
  94. }
  95. return function (obj1, obj2) {
  96. var i = 0, result = 0, numberOfProperties = props.length;
  97. /* try getting a different result from 0 (equal)
  98. * as long as we have extra properties to compare
  99. */
  100. while(result === 0 && i < numberOfProperties) {
  101. result = dynamicSort(props[i])(obj1, obj2);
  102. i++;
  103. }
  104. return result;
  105. };
  106. }
  107.  
  108. function getReport(reportId) {
  109. for (var i=0; i<_reports.length; i++) {
  110. if (_reports[i].id === reportId) { return _reports[i]; }
  111. }
  112. }
  113.  
  114. function isHideOptionChecked(reportType) {
  115. return $('#hideVADot' + reportType + 'Reports').is(':checked');
  116. }
  117.  
  118. function updateReportsVisibility() {
  119. hideAllReportPopovers();
  120. var hideArchived = isHideOptionChecked('Archived');
  121. var visibleCount = 0;
  122. _reports.forEach(function(report) {
  123. var hide =
  124. hideArchived && report.archived;
  125. if (hide) {
  126. report.dataRow.hide();
  127. if (report.imageDiv) { report.imageDiv.hide(); }
  128. } else {
  129. visibleCount += 1;
  130. report.dataRow.show();
  131. if (report.imageDiv) { report.imageDiv.show(); }
  132. }
  133. });
  134. $('.va-dot-report-count').text(visibleCount + ' of ' + _reports.length + ' reports');
  135. }
  136.  
  137. function hideAllPopovers($excludeDiv) {
  138. _reports.forEach(function(rpt) {
  139. var $div = rpt.imageDiv;
  140. if ((!$excludeDiv || $div[0] !== $excludeDiv[0]) && $div.data('state') === 'pinned') {
  141. $div.data('state', '');
  142. $div.popover('hide');
  143. }
  144. });
  145. }
  146.  
  147. function deselectAllDataRows() {
  148. _reports.forEach(function(rpt) {
  149. rpt.dataRow.css('background-color','white');
  150. });
  151. }
  152.  
  153. function toggleMarkerPopover($div) {
  154. hideAllPopovers($div);
  155. if ($div.data('state') !== 'pinned') {
  156. var id = $div.data('reportId');
  157. var report = getReport(id);
  158. $div.data('state', 'pinned');
  159. W.map.setCenter(report.marker.lonlat);
  160. $div.popover('show');
  161. if (report.archived) {
  162. $('.btn-archive-dot-report').text("Un-Archive");
  163. }
  164. $('.btn-archive-dot-report').click(function() {setArchiveReport(report,!report.archived, true); buildTable();});
  165. $('.btn-open-dot-report').click(function(evt) {evt.stopPropagation(); window.open($(this).data('dotReportUrl'),'_blank');});
  166. $('.reportPopover,.close-popover').click(function(evt) {evt.stopPropagation(); hideAllReportPopovers();});
  167. //$(".close-popover").click(function() {hideAllReportPopovers();});
  168. $div.data('report').dataRow.css('background-color','beige');
  169. } else {
  170. $div.data('state', '');
  171. $div.popover('hide');
  172. }
  173. }
  174.  
  175. function toggleReportPopover($div) {
  176. deselectAllDataRows();
  177. toggleMarkerPopover($div);
  178. }
  179.  
  180. function hideAllReportPopovers() {
  181. deselectAllDataRows();
  182. hideAllPopovers();
  183. }
  184.  
  185. function setArchiveReport(report, archive, updateUi) {
  186. report.archived = archive;
  187. if (archive) {
  188. _settings.archivedReports[report.id] = {updateNumber: report.id};
  189. report.imageDiv.addClass('va-dot-archived-marker');
  190. }else {
  191. delete _settings.archivedReports[report.id];
  192. report.imageDiv.removeClass('va-dot-archived-marker');
  193. }
  194. if (updateUi) {
  195. saveSettingsToStorage();
  196. updateReportsVisibility();
  197. hideAllReportPopovers();
  198. }
  199. }
  200.  
  201. function archiveAllReports(unarchive) {
  202. _reports.forEach(function(report) {
  203. setArchiveReport(report, !unarchive, false);
  204. });
  205. saveSettingsToStorage();
  206. buildTable();
  207. hideAllReportPopovers();
  208. }
  209.  
  210. function addRow($table, report) {
  211. var $img = $('<img>', {src:report.imgUrl, class:'table-img'});
  212. var $row = $('<tr> class="clickable"', {id:'va-dot-row-'+report.id}).append(
  213. $('<td>',{class:'centered'}).append(
  214. $('<input>',{type:'checkbox',title:'Archive',id:'va-archive-' + report.id, 'data-report-id':report.id}).prop('checked', report.archived).click(
  215. function(evt){
  216. evt.stopPropagation();
  217. var id = $(this).data('reportId');
  218. var report = getReport(id);
  219. setArchiveReport(report, $(this).is(':checked'), true);
  220. }
  221. )
  222. ),
  223. $('<td>',{class:'clickable centered'}).append($img),
  224. $('<td>').text(report.properties.location_description)
  225. )
  226. .click(function () {
  227. var $row = $(this);
  228. var id = $row.data('reportId');
  229. var marker = getReport(id).marker;
  230. var $imageDiv = report.imageDiv;
  231. //if (!marker.onScreen()) {
  232. W.map.setCenter(marker.lonlat);
  233. //}
  234. toggleReportPopover($imageDiv);
  235.  
  236. }).data('reportId', report.id);
  237. report.dataRow = $row;
  238. $table.append($row);
  239. $row.report = report;
  240. }
  241.  
  242.  
  243. function onClickColumnHeader(obj) {
  244. var prop;
  245. switch (/va-dot-table-(.*)-header/.exec(obj.id)[1]) {
  246. case 'category':
  247. prop = 'properties.icon';
  248. break;
  249. case 'begins':
  250. prop = 'beginTime.time';
  251. break;
  252. case 'desc':
  253. prop = 'properties.location_description';
  254. break;
  255. case 'priority':
  256. prop = 'priority';
  257. break;
  258. case 'archive':
  259. prop = 'archived';
  260. break;
  261. default:
  262. return;
  263. }
  264. var idx = _columnSortOrder.indexOf(prop);
  265. if (idx > -1) {
  266. _columnSortOrder.splice(idx, 1);
  267. _columnSortOrder.reverse();
  268. _columnSortOrder.push(prop);
  269. _columnSortOrder.reverse();
  270. buildTable();
  271. }
  272. }
  273.  
  274. function buildTable() {
  275. log('Building table', 1);
  276. var $table = $('<table>',{class:'va-dot-table'});
  277. var $th = $('<thead>').appendTo($table);
  278. $th.append(
  279. $('<tr>').append(
  280. $('<th>', {id:'va-dot-table-archive-header',class:'centered'}).append(
  281. $('<span>', {class:'fa fa-archive',style:'font-size:120%',title:'Sort by archived'}))).append(
  282. $('<th>', {id:'va-dot-table-category-header',title:'Sort by report type'})).append(
  283. $('<th>',{id:'va-dot-table-desc-header',title:'Sort by description'}).text('Description')
  284. ));
  285. _reports.sort(dynamicSortMultiple(_columnSortOrder));
  286. _reports.forEach(function(report) {
  287. addRow($table, report);
  288. });
  289. $('.va-dot-table').remove();
  290. $('#va-dot-report-table').append($table);
  291. $('.va-dot-table th').click(function() {onClickColumnHeader(this);});
  292.  
  293. updateReportsVisibility();
  294. }
  295.  
  296. function addReportToMap(report){
  297. var coord = report.geometry.coordinates;
  298. var imgName;
  299. switch (report.type) {
  300. case 'high_impact_incident':
  301. imgName = 'incident_major';
  302. break;
  303. default:
  304. imgName = report.type;
  305. }
  306. imgName += '.png';
  307. var size = new OpenLayers.Size(29,29);
  308. var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
  309. var now = new Date(Date.now());
  310.  
  311. report.imgUrl = _imagesPath + imgName;
  312. var icon = new OpenLayers.Icon(report.imgUrl,size,null);
  313. var marker = new OpenLayers.Marker(new OpenLayers.LonLat(coord[0],coord[1]).transform("EPSG:4326", "EPSG:900913"),icon);
  314.  
  315. var popoverTemplate = ['<div class="reportPopover popover" style="max-width:500px;width:500px;">',
  316. '<div class="arrow"></div>',
  317. '<div class="popover-title"></div>',
  318. '<div class="popover-content">',
  319. '</div>',
  320. '</div>'].join('');
  321. marker.report = report;
  322. //marker.events.register('click', marker, onMarkerClick);
  323. _mapLayer.addMarker(marker);
  324.  
  325. //var dt = new Date(report.details.unixtime * 1000);
  326. var content = [
  327. report.properties.location_description,
  328. '<br><br>',
  329. report.details,
  330. //'<br><br>',
  331. //'<span style="font-weight:bold">Display Time:</span>&nbsp;&nbsp;' + dt.toLocaleDateString() + '&nbsp;&nbsp;' + dt.toLocaleTimeString(),
  332. '<div"><hr style="margin-bottom:5px;margin-top:5px;border-color:gainsboro"><div style="display:table;width:100%"><button type="button" style="float:right;" class="btn btn-primary btn-archive-dot-report" data-dot-report-id="' + report.id + '">Archive</button></div></div></div>'
  333. ].join('');
  334. var $imageDiv = $(marker.icon.imageDiv)
  335. .css('cursor', 'pointer')
  336. .addClass('vaDotReport')
  337. .attr({
  338. 'data-toggle':'popover',
  339. title:'',
  340. 'data-content':content,
  341. 'data-original-title':'<div style"width:100%;"><div style="float:left;max-width:330px;color:#5989af;font-size:120%;">' + _reportTitles[report.type] + '</div><div style="float:right;"><a class="close-popover" href="javascript:void(0);">X</a></div><div style="clear:both;"</div></div>'
  342. })
  343.  
  344. .popover({trigger: 'manual', html:true,placement: 'auto top', template:popoverTemplate})
  345. .on('click', function() {toggleReportPopover($(this));})
  346. .data('reportId', report.id)
  347. .data('state', '');
  348.  
  349. $imageDiv.data('report', report);
  350. if (report.archived) { $imageDiv.addClass('va-dot-archived-marker'); }
  351. report.imageDiv = $imageDiv;
  352. report.marker = marker;
  353. }
  354.  
  355. function processReportDetails(reportDetails, reports) {
  356. _reports = [];
  357. _mapLayer.clearMarkers();
  358. log('Adding reports to map...', 1);
  359. reports.forEach(function(report, index) {
  360. if (report.geometry) {
  361. report.details = reportDetails[report.id];
  362. report.archived = false;
  363. if (_settings.archivedReports.hasOwnProperty(report.id)) {
  364. // if ( _settings.archivedReports[report.id].updateNumber < report.situationUpdateKey.updateNumber) {
  365. // delete _settings.archivedReports[report.id];
  366. // } else {
  367. report.archived = true;
  368. // }
  369. }
  370. addReportToMap(report);
  371. _reports.push(report);
  372. }
  373. });
  374. buildTable();
  375. }
  376.  
  377. function requestReportDetails(reports) {
  378. // Limit the # of details reports to 50 at a time, so we don't overflow the URL length limit.
  379. var limit = 50;
  380. var numberOfCalls = Math.floor((reports.length - 1) / limit) + 1;
  381. var parentContext = {reports: reports, details: {}, numberOfCalls: numberOfCalls, callsReceived: 0};
  382.  
  383. for (var i=0; i<numberOfCalls; i++) {
  384. var ids = reports.slice(i*limit,(i+1)*limit).map(report => report.id);
  385. var url = 'http://www.511virginia.org/report.pl?idents=' + ids.join('%2C');
  386. GM_xmlhttpRequest({
  387. method: 'GET',
  388. context: {parentContext: parentContext, ids: ids},
  389. url: url,
  390. onload: function(res) {
  391. var parentContext = res.context.parentContext;
  392. var text = res.responseText;
  393. var re = /<div>(.*?)<[/]div>/gi;
  394. var result;
  395. var idx = 0;
  396. while (result = re.exec(text)) {
  397. parentContext.details[res.context.ids[idx]] = result[1];
  398. idx++;
  399. }
  400. parentContext.callsReceived++;
  401. if (parentContext.callsReceived >= parentContext.numberOfCalls) {
  402. processReportDetails(parentContext.details, parentContext.reports);
  403. }
  404. },
  405. onerror: function(res) {
  406. console.log(res);
  407. }
  408. });
  409. }
  410. }
  411.  
  412. function processReports(reports, context) {
  413. reports.forEach(function(report) {
  414. report.type = context.type;
  415. });
  416. Array.prototype.push.apply(context.results.reports, reports);
  417.  
  418. if (context.results.callCount === context.results.expectedCallCount) {
  419. requestReportDetails(context.results.reports);
  420. }
  421. }
  422.  
  423. function requestReports(context) {
  424. GM_xmlhttpRequest({
  425. method: 'GET',
  426. context: context,
  427. url: 'http://files6.iteriscdn.com/WebApps/VA/SafeTravel/data/local/icons/metadata/icons.' + context.type + '.geojsonp',
  428. onload: function(res) { res.context.results.callCount += 1; processReports($.parseJSON(/\((.*)\)/.exec(res.responseText)[1]).features, res.context); },
  429. onError: function(err) { log(err,0); }
  430. });
  431. }
  432.  
  433. function fetchReports() {
  434. var results = {callCount: 0, reports: [], expectedCallCount: 4};
  435. var weatherClosureContext = { type:'weather_closure', results:results };
  436. var incidentContext= { type:'incident', results:results };
  437. var constructionContext = { type:'construction', results:results };
  438. var highImpactContext = { type: 'high_impact_incident', results: results};
  439.  
  440. requestReports(weatherClosureContext);
  441. requestReports(incidentContext);
  442. requestReports(constructionContext);
  443. requestReports(highImpactContext);
  444. }
  445.  
  446. function onLayerVisibilityChanged(evt) {
  447. saveSettingsToStorage();
  448. }
  449.  
  450. function installIcon() {
  451. OpenLayers.Icon = OpenLayers.Class({
  452. url: null,
  453. size: null,
  454. offset: null,
  455. calculateOffset: null,
  456. imageDiv: null,
  457. px: null,
  458. initialize: function(a,b,c,d){
  459. this.url=a;
  460. this.size=b||{w: 20,h: 20};
  461. this.offset=c||{x: -(this.size.w/2),y: -(this.size.h/2)};
  462. this.calculateOffset=d;
  463. a=OpenLayers.Util.createUniqueID("OL_Icon_");
  464. var div = this.imageDiv=OpenLayers.Util.createAlphaImageDiv(a);
  465. $(div.firstChild).removeClass('olAlphaImg'); // LEAVE THIS LINE TO PREVENT WME-HARDHATS SCRIPT FROM TURNING ALL ICONS INTO HARDHAT WAZERS --MAPOMATIC
  466. },
  467. destroy: function(){ this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null; },
  468. clone: function(){ return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset); },
  469. setSize: function(a){ null!==a&&(this.size=a); this.draw(); },
  470. setUrl: function(a){ null!==a&&(this.url=a); this.draw(); },
  471. draw: function(a){
  472. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");
  473. this.moveTo(a);
  474. return this.imageDiv;
  475. },
  476. erase: function(){ null!==this.imageDiv&&null!==this.imageDiv.parentNode&&OpenLayers.Element.remove(this.imageDiv); },
  477. setOpacity: function(a){ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,a); },
  478. moveTo: function(a){
  479. null!==a&&(this.px=a);
  480. null!==this.imageDiv&&(null===this.px?this.display(!1): (
  481. this.calculateOffset&&(this.offset=this.calculateOffset(this.size)),
  482. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x: this.px.x+this.offset.x,y: this.px.y+this.offset.y})
  483. ));
  484. },
  485. display: function(a){ this.imageDiv.style.display=a?"": "none"; },
  486. isDrawn: function(){ return this.imageDiv&&this.imageDiv.parentNode&&11!=this.imageDiv.parentNode.nodeType; },
  487. CLASS_NAME: "OpenLayers.Icon"
  488. });
  489. }
  490.  
  491. function init511ReportsOverlay(){
  492. installIcon();
  493. _mapLayer = new OpenLayers.Layer.Markers("VA DOT Reports", {
  494. displayInLayerSwitcher: true,
  495. uniqueName: "__vaDotReports",
  496. });
  497.  
  498. //I18n.translations[I18n.locale].layers.name.__stateDotReports = "VA DOT Reports";
  499. W.map.addLayer(_mapLayer);
  500. _mapLayer.setVisibility(_settings.layerVisible);
  501. _mapLayer.events.register('visibilitychanged',null,onLayerVisibilityChanged);
  502. }
  503.  
  504. function restoreUserTab() {
  505. $('#user-tabs > .nav-tabs').append(_tabDiv.tab);
  506. $('#user-info > .flex-parent > .tab-content').append(_tabDiv.panel);
  507. $('[id^=hideVADot]').change(function(){
  508. saveSettingsToStorage();
  509. updateReportsVisibility();
  510. });
  511. $('.va-dot-refresh-reports').click(function(e) {
  512. hideAllReportPopovers();
  513. fetchReports(processReports);
  514. var refreshPopup = $('#va-dot-refresh-popup');
  515. refreshPopup.show();
  516. setTimeout(function() { refreshPopup.hide(); }, 1500);
  517. e.stopPropagation();
  518. });
  519. }
  520.  
  521. function onModeChanged(model, modeId, context) {
  522. hideAllReportPopovers();
  523. if(!modeId || modeId === 1) {
  524. restoreUserTab();
  525. }
  526. }
  527.  
  528. function initUserPanel() {
  529. _tabDiv.tab = $('<li>').append(
  530. $('<a>', {'data-toggle':'tab', href:'#sidepanel-va-statedot'}).text('VA DOT').append(
  531. $('<span>', {title:'Click to refresh DOT reports', class:'fa fa-refresh refreshIcon nav-tab-icon va-dot-refresh-reports', style:'cursor:pointer;'})
  532. )
  533. );
  534.  
  535. _tabDiv.panel = $('<div>', {class:'tab-pane', id:'sidepanel-va-statedot'}).append(
  536. $('<div>', {class:'side-panel-section>'}).append(
  537. $('<label style="width:100%; cursor:pointer; border-bottom: 1px solid #e0e0e0; margin-top:9px;" data-toggle="collapse" data-target="#vaDotSettingsCollapse"><span class="fa fa-caret-down" style="margin-right:5px;font-size:120%;"></span>Hide reports...</label>')).append(
  538. $('<div>',{id:'vaDotSettingsCollapse',class:'collapse'}).append(
  539. $('<div>',{class:'controls-container'})
  540. .append($('<input>', {type:'checkbox',name:'hideVADotArchivedReports',id:'hideVADotArchivedReports'}))
  541. .append($('<label>', {for:'hideVADotArchivedReports'}).text('Archived'))
  542. )
  543. )
  544. ).append(
  545. $('<div>', {class:'side-panel-section>', id:'va-dot-report-table'}).append(
  546. $('<div>').append(
  547. $('<span>', {title:'Click to refresh DOT reports', class:'fa fa-refresh refreshIcon va-dot-refresh-reports va-dot-table-label', style:'cursor:pointer;'})
  548. ).append(
  549. $('<span>',{class:'va-dot-table-label va-dot-report-count count'})
  550. ).append(
  551. $('<span>',{class:'va-dot-table-label va-dot-table-action right'}).text('Archive all').click(function() {
  552. var r = confirm('Are you sure you want to archive all reports for ' + _settings.state + '?');
  553. if (r===true) {
  554. archiveAllReports(false);
  555. }
  556. })
  557. ).append(
  558. $('<span>', {class:'va-dot-table-label right'}).text('|')
  559. ).append(
  560. $('<span>',{class:'va-dot-table-label va-dot-table-action right'}).text('Un-Archive all').click(function() {
  561. var r = confirm('Are you sure you want to un-archive all reports for ' + _settings.state + '?');
  562. if (r===true) {
  563. archiveAllReports(true);
  564. }
  565. })
  566. )
  567. )
  568. );
  569.  
  570. restoreUserTab();
  571. $('<div>', {id: 'va-dot-refresh-popup',}).text('DOT Reports Refreshed').hide().appendTo($('div#editor-container'));
  572.  
  573. (function setChecks(settingProps, checkboxIds) {
  574. for (var i=0; i<settingProps.length; i++) {
  575. if (_settings[settingProps[i]]) { $('#' + checkboxIds[i]).attr('checked', 'checked'); }
  576. }
  577. })(['hideArchivedReports'],
  578. ['hideVADotArchivedReports']);
  579. }
  580.  
  581. function showScriptInfoAlert() {
  582. /* Check version and alert on update */
  583. if (_alertUpdate && _scriptVersion !== _settings.lastVersion) {
  584. alert(_scriptVersionChanges);
  585. }
  586. }
  587.  
  588. function initGui() {
  589. init511ReportsOverlay();
  590. initUserPanel();
  591. showScriptInfoAlert();
  592. fetchReports(processReports);
  593.  
  594. var classHtml = [
  595. '.va-dot-table th,td,tr {cursor:pointer;} ',
  596. '.va-dot-table .centered {text-align:center;} ',
  597. '.va-dot-table th:hover,tr:hover {background-color:aliceblue; outline: -webkit-focus-ring-color auto 5px;} ',
  598. '.va-dot-table th:hover {color:blue; border-color:whitesmoke; } ',
  599. '.va-dot-table {border:1px solid gray; border-collapse:collapse; width:100%; font-size:83%;margin:0px 0px 0px 0px} ',
  600. '.va-dot-table th,td {border:1px solid gainsboro;} ',
  601. '.va-dot-table td,th {color:black; padding:1px 4px;} ',
  602. '.va-dot-table th {background-color:gainsboro;} ',
  603. '.va-dot-table .table-img {max-width:24px; max-height:24px;} ',
  604. '.tooltip.top > .tooltip-arrow {border-top-color:white;} ',
  605. '.tooltip.bottom > .tooltip-arrow {border-bottom-color:white;} ',
  606. 'a.close-popover {text-decoration:none;padding:0px 3px;border-width:1px;background-color:white;border-color:ghostwhite} a.close-popover:hover {padding:0px 4px;border-style:outset;border-width:1px;background-color:white;border-color:ghostwhite;} ',
  607. '#va-dot-refresh-popup {position:absolute;z-index:9999;top:80px;left:650px;background-color:rgb(120,176,191);e;font-size:120%;padding:3px 11px;box-shadow:6px 8px rgba(20,20,20,0.6);border-radius:5px;color:white;} ',
  608. '.refreshIcon:hover {color:blue; text-shadow: 2px 2px #aaa;} .refreshIcon:active{ text-shadow: 0px 0px; }',
  609. '.va-dot-archived-marker {opacity:0.5;} ',
  610. '.va-dot-table-label {font-size:85%;} .va-dot-table-action:hover {color:blue;cursor:pointer} .va-dot-table-label.right {float:right} .va-dot-table-label.count {margin-left:4px;}'
  611. ].join('');
  612. $('<style type="text/css">' + classHtml + '</style>').appendTo('head');
  613.  
  614. _previousZoom = W.map.zoom;
  615. W.map.events.register('moveend',null,function() {if (_previousZoom !== W.map.zoom) {hideAllReportPopovers();} _previousZoom=W.map.zoom;});
  616. }
  617.  
  618. var _previousZoom;
  619.  
  620. function loadSettingsFromStorage() {
  621. var settings = $.parseJSON(localStorage.getItem(_settingsStoreName));
  622. if(!settings) {
  623. settings = {
  624. lastVersion:null,
  625. layerVisible:true,
  626. hideArchivedReports:true,
  627. archivedReports:{}
  628. };
  629. } else {
  630. settings.layerVisible = (settings.layerVisible === true);
  631. if(typeof settings.hideArchivedReports === 'undefined') { settings.hideArchivedReports = true; }
  632. settings.archivedReports = settings.archivedReports ? settings.archivedReports : {};
  633. }
  634. _settings = settings;
  635. }
  636.  
  637. function init() {
  638. loadSettingsFromStorage();
  639. initGui();
  640. _window.addEventListener('beforeunload', function saveOnClose() { saveSettingsToStorage(); }, false);
  641. W.app.modeController.model.bind('change:mode', onModeChanged);
  642. log('Initialized.', 0);
  643. }
  644.  
  645. function bootstrap() {
  646. var wz = _window.W;
  647. if (wz && wz.loginManager &&
  648. wz.loginManager.events.register &&
  649. wz.map && wz.loginManager.user) {
  650. log('Initializing...', 1);
  651. init();
  652. } else {
  653. log('Bootstrap failed. Trying again...', 1);
  654. _window.setTimeout(function () {
  655. bootstrap();
  656. }, 1000);
  657. }
  658. }
  659.  
  660. log('Bootstrap...', 0);
  661. bootstrap();
  662. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址