diff options
Diffstat (limited to 'dmarcts-report-viewer.js')
-rw-r--r-- | dmarcts-report-viewer.js | 430 |
1 files changed, 319 insertions, 111 deletions
diff --git a/dmarcts-report-viewer.js b/dmarcts-report-viewer.js index b778672..046479f 100644 --- a/dmarcts-report-viewer.js +++ b/dmarcts-report-viewer.js @@ -26,22 +26,21 @@ // dmarcts-report-viewer-config.php and edit with the appropriate info // for your database authentication and location. // -// Edit the configuration variables in dmarcts-report-viewer.js with your preferences. +//#################################################################### // ---------------------------------------------------------------------------- +// Main Program // ---------------------------------------------------------------------------- -// Supplemental Configuration - -var default_reportlist_height = 60; // Main Report List height as a percentage of browser window height (without the % mark) -// End Supplemental Configuration -// ---------------------------------------------------------------------------- +var current_report = ""; +var report_list_height = 0; +var available_height = 0; +var report_data_xml_width = 0; -var current_report; const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent; const comparer = (idx, asc) => (a, b) => ((v1, v2) => v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2))(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx)); -var report_data_xml_width_last = 0; +var cookie_name = "dmarcts-options"; // ---------------------------------------------------------------------------- //Functions @@ -92,6 +91,9 @@ function sorttable (table_id) { function showReportlist(str) { // str is the name of the <div> to be filled + // Clear current reportid because Report List is being reset + current_report = ""; + var GETstring = "?"; var domain = document.getElementById('selDomain').options[document.getElementById('selDomain').selectedIndex].value; @@ -112,17 +114,10 @@ function showReportlist(str) { // str is the name of the <div> to be filled if (this.readyState == 4 && this.status == 200) { document.getElementById("report_list").innerHTML = this.responseText; document.getElementById("report_data").innerHTML = ""; + set_heights(); sorttable(str); set_title(domain); makeResizableDiv(); - if ( - (document.getElementById('resizer_horizontal') != 'undefined' && document.getElementById('resizer_horizontal') != null) - || - (document.getElementById('resizer_vertical') != 'undefined' && document.getElementById('resizer_vertical') != null) - ) { - document.getElementById('resizer_horizontal').style.display = 'none'; - document.getElementById('resizer_vertical').style.display = 'none'; - } } }; @@ -130,6 +125,38 @@ function showReportlist(str) { // str is the name of the <div> to be filled xhttp.send(); } +function showMenu() { + + document.getElementById('menu').style.display = 'block'; + document.getElementById('screen_overlay').style.display = 'block'; +} + +function hideMenu() { + + document.getElementById('menu').style.display = 'none'; + document.getElementById('screen_overlay').style.display = 'none'; +} + +function optionMenu(_element) { + + var _div = document.getElementById('menu'); + var input = _element.getBoundingClientRect(); + + _div.style.right = window.innerWidth - input.right + 'px'; + _div.style.top = document.getElementById('optionblock').bottom + 'px'; + + if ( document.getElementById('menu').style.display == 'none' || document.getElementById('menu').style.display == '' ) { + showMenu(); + } else { + hideMenu(); + } +} + +function change_stylesheet() { + + document.getElementById('css_stylesheet').href = document.getElementById('selcssfile').value; +} + function set_title(domain) { domain == 'all' ? document.getElementById('title').innerText = "DMARC Reports" : document.getElementById('title').innerText = "DMARC Reports for " + domain; @@ -137,22 +164,43 @@ function set_title(domain) { function set_heights() { - var report_list_height_percentage = default_reportlist_height/100; - var taken_height = - parseInt(window.getComputedStyle(document.getElementById('body')).getPropertyValue('margin-top')) - + parseInt(window.getComputedStyle(document.getElementById('body')).getPropertyValue('margin-bottom')) - + document.getElementById('optionblock').offsetHeight - + document.getElementById('title').offsetHeight - + document.getElementById('footer').offsetHeight - + parseInt(window.getComputedStyle(document.getElementById('footer')).getPropertyValue('margin-top')) - ; - var available_height = window.innerHeight - taken_height; - var report_list_height = parseInt(report_list_height_percentage * available_height); - var report_data_height = available_height - report_list_height; + if ( document.getElementById('reportlistTbl') != 'undefined' && document.getElementById('reportlistTbl') != null ) { + var taken_height = + parseInt(window.getComputedStyle(document.getElementById('body')).getPropertyValue('margin-top')) + + parseInt(window.getComputedStyle(document.getElementById('body')).getPropertyValue('margin-bottom')) + + document.getElementById('optionblock').offsetHeight + + document.getElementById('title').offsetHeight + + document.getElementById('footer').offsetHeight + + parseInt(window.getComputedStyle(document.getElementById('footer')).getPropertyValue('margin-top')) + ; + + available_height = window.innerHeight - taken_height; + report_list_height = parseInt(report_list_height_percent * available_height / 100 ); + + // See at least the header and the first row of the Report List even if the Report List-Initial Height is set to 0 percent + var min_height_report_list = + + document.getElementById('title').offsetHeight + + document.getElementById('reportlistTbl').getElementsByTagName('thead')[0].offsetHeight + ; + // The Report List should not be large enough to cover the Report Data description div (report_desc) but that div has not been rendered yet, so we can't get its height. + // However, a good proxy for the height of the description is about 3 times the height of the first row of the Report List + var max_height_report_list = + available_height + - document.getElementById('reportlistTbl').getElementsByTagName('thead')[0].offsetHeight * 3 + ; + + if ( report_list_height < min_height_report_list ) { + report_list_height = min_height_report_list; + } + if ( report_list_height > max_height_report_list ) { + report_list_height = max_height_report_list; + } + var report_data_height = available_height - report_list_height; - document.getElementById('report_list').style.height = report_list_height + "px"; - document.getElementById('report_data').style.height = report_data_height + "px"; + document.getElementById('report_list').style.height = report_list_height + "px"; + document.getElementById('report_data').style.height = report_data_height + "px"; + } } function set_report_data_heights() { @@ -166,11 +214,42 @@ function set_report_data_heights() { document.getElementById('report_data_xml').style.height = report_data_table_div_height; } -function showXML() { +function report_data_xml_display_toggle() { + + if (xml_data_open == 0) { + xml_data_open = 1; + set_report_data_widths(); + } else { + xml_data_open = 0; + set_report_data_widths(); + } +} + +function set_report_data_widths () { + + // An allowance to accomodate Report Data table width expanding/contracting when sorting arrow is added to/removed from the column title + // HTML5 doesn't seem to currently have a built-in onresize event for divs, so to do this automatically would take some decent JS library like https://github.com/marcj/css-element-queries + // May not need this anymore + allowance = getScrollBarWidth() * 2; + // allowance = 30; + + if ( xml_data_open == 1 ) { + var min_width_xml_data = + document.getElementById('report_data_table').getElementsByTagName('thead')[0].getElementsByTagName('tr')[0].getElementsByTagName('th')[0].offsetWidth // i.e. the width of the first column of the Report Data table + ; + var max_width_xml_data = + document.getElementById('report_data').offsetWidth + - min_width_xml_data + ; + report_data_xml_width = parseInt(document.getElementById('report_data').offsetWidth * report_data_xml_width_percent / 100); + if ( report_data_xml_width < min_width_xml_data ) { + report_data_xml_width = min_width_xml_data; + } + if ( report_data_xml_width > max_width_xml_data ) { + report_data_xml_width = max_width_xml_data; + } - if (document.getElementById('report_data_xml').style.display == 'none') { - var div_height = document.getElementById('report_data_table_div').style.height - set_report_data_widths("open_xml"); + report_data_table_div_width = document.getElementById('report_data').offsetWidth - report_data_xml_width - allowance; document.getElementById('report_data_xml').style.display = 'inline-block'; document.getElementById('report_data_table_div').style.display = 'inline-block'; document.getElementById('report_data_table_div').style.float = 'left'; @@ -179,8 +258,8 @@ function showXML() { document.getElementById('xml_html_img').alt = 'Hide Raw Report XML'; document.getElementById('resizer_vertical').style.display = "block"; } else { - var div_height = document.getElementById('report_data_xml').style.height - set_report_data_widths("close_xml"); + report_data_xml_width = 0; + report_data_table_div_width = document.getElementById('report_data').offsetWidth; document.getElementById('report_data_xml').style.display = 'none'; document.getElementById('report_data_table_div').style.display = 'block'; document.getElementById('report_data_table_div').style.float = ''; @@ -189,54 +268,53 @@ function showXML() { document.getElementById('xml_html_img').alt = 'Show Raw Report XML'; document.getElementById('resizer_vertical').style.display = "none"; } - showResizers(); -} - -function set_report_data_widths (open_close) { - - report_data_xml_width_percent = .20; - - // An allowance to accomodate Report Data table width expanding/contracting when sorting arrow is added to/removed from the column title - // HTML5 doesn't seem to currently have a built-in onresize event for divs, so to do this automatically would take some decent JS library like https://github.com/marcj/css-element-queries - allowance = 30; - - if ( open_close == "open_xml" ) { - if ( report_data_xml_width_last == 0){ - report_data_xml_width = parseInt(document.getElementById('report_data').offsetWidth * report_data_xml_width_percent); - report_data_table_div_width = document.getElementById('report_data').offsetWidth - report_data_xml_width - allowance; - } else { - report_data_xml_width = report_data_xml_width_last - - document.getElementById('resizer_vertical').offsetWidth / 2 - -2 - ; - // Why '-2'? Because when the report_data_xml div is resized and another report is chosen, the handle and separator jump by 2 pixels - // If someone can find out why, please fix it (it's probably because of all the other tiny fudges all over the place) - report_data_table_div_width = document.getElementById('report_data').offsetWidth - report_data_xml_width - allowance; - } - } else { - report_data_xml_width = 0; - report_data_table_div_width = document.getElementById('report_data').offsetWidth; - } document.getElementById('report_data_xml').style.width = report_data_xml_width + "px"; document.getElementById('report_data_table_div').style.width = report_data_table_div_width + "px"; -// document.getElementById('report_data').style.overflow = "hidden"; - + showResizers(); } +// From https://stackoverflow.com/a/986977 +function getScrollBarWidth() { + var inner = document.createElement('p'); + inner.style.width = "100%"; + inner.style.height = "200px"; + + var outer = document.createElement('div'); + outer.style.position = "absolute"; + outer.style.top = "0px"; + outer.style.left = "0px"; + outer.style.visibility = "hidden"; + outer.style.width = "200px"; + outer.style.height = "150px"; + outer.style.overflow = "hidden"; + outer.appendChild (inner); + + document.body.appendChild (outer); + var w1 = inner.offsetWidth; + outer.style.overflow = 'scroll'; + var w2 = inner.offsetWidth; + if (w1 == w2) w2 = outer.clientWidth; + + document.body.removeChild (outer); + + return (w1 - w2); +}; + function showReport(str) { + if ( (typeof(document.getElementById('no_reports')) != 'undefined' && document.getElementById('no_reports') != null) || (typeof(str) == 'undefined' && str == null) ) { + return; + } + document.getElementById('screen_overlay').style.display = "block"; document.getElementById('screen_overlay').style.cursor = "wait"; - if (str == null) { - // Hide handles - document.getElementById('resizer_horizontal').display = 'none'; - document.getElementById('resizer_vertical').display = 'none'; + if (str == "") { + // Remove screen overlay document.getElementById('screen_overlay').style.display = "none"; document.getElementById('screen_overlay').style.cursor = "default"; - alert('No report is selected.'); return; } setSelected(str); // setSelected function highlights the report row that is selcted @@ -244,15 +322,10 @@ function showReport(str) { current_report = str; var xhttp; - if (str == "") { - document.getElementById("report_data").innerHTML = ""; - return; - } - var GETstring = "report=" + str; - var HostLookup = document.getElementsByName('selHostLookup'); - var HostLookup_value = false; + var HostLookup = document.getElementsByName('HostLookup'); + for ( var i = 0; i < HostLookup.length; i++) { if(HostLookup[i].checked) { GETstring += "&hostlookup=" + HostLookup[i].value; @@ -273,8 +346,10 @@ function showReport(str) { document.getElementById('screen_overlay').style.cursor = "default"; document.getElementById('screen_overlay').style.display = "none"; showResizers(); - if ( typeof report_data_xml_width !== 'undefined' && report_data_xml_width > 0 ) { - showXML("open_xml"); + // current_report = ""; + + if ( xml_data_open == 1 ) { + set_report_data_widths(); } } }; @@ -283,6 +358,18 @@ function showReport(str) { xhttp.send(); } +function setSelected(str) { + + const table = document.getElementById("reportlistTbl"); + const rows = table.getElementsByTagName("tr"); + for (i = 0; i < rows.length; i++) { + var currentRow = table.rows[i]; + currentRow.classList.remove("selected"); + } + document.getElementById("report"+str).className += " selected"; +} + + // Functions that allow resizing of the data and raw xml divs // Inspired by the code at https://medium.com/the-z/making-a-resizable-div-in-js-is-not-easy-as-you-think-bda19a1bc53d function showResizers() { @@ -298,15 +385,11 @@ function showResizers() { - (document.getElementById('resizer_horizontal').offsetHeight)/2 + "px"; - document.getElementById('resizer_vertical').style.top = - parseInt(window.getComputedStyle(document.getElementById('body')).getPropertyValue('margin-top')) - + document.getElementById('optionblock').offsetHeight - + document.getElementById('title').offsetHeight - + document.getElementById('report_list').offsetHeight - + document.getElementById('report_desc_container').offsetHeight - + document.getElementById('report_data_xml').offsetHeight/2 - - (document.getElementById('resizer_vertical').offsetHeight)/2 - + "px"; + document.getElementById('resizer_vertical').style.top = + document.getElementById('report_data_xml').offsetTop + + document.getElementById('report_data_xml').offsetHeight/2 + - document.getElementById('resizer_vertical').offsetHeight/2 + + 'px' document.getElementById('resizer_vertical').style.left = + document.getElementById('report_data_xml').offsetLeft @@ -318,20 +401,9 @@ function showResizers() { } } -function setSelected(str) { - - const table = document.getElementById("reportlistTbl"); - const rows = table.getElementsByTagName("tr"); - for (i = 0; i < rows.length; i++) { - var currentRow = table.rows[i]; - currentRow.classList.remove("selected"); - } - document.getElementById("report"+str).className += " selected"; -} - function makeResizableDiv() { - if (document.getElementById('resizer_horizontal') != 'undefined' && document.getElementById('resizer_horizontal') != null) { + if (document.getElementById('resizer_horizontal') != 'undefined' && document.getElementById('resizer_vertical') != null) { document.getElementById('resizer_horizontal').addEventListener( 'mousedown', function (e) { @@ -342,7 +414,7 @@ function makeResizableDiv() { if ( document.getElementById('report_data_table_div') ) { original_height_report_data_table_div = document.getElementById('report_data_table_div').offsetHeight; } - original_height_resizer_vertical = 30; // Should be equal to the in css file + original_height_resizer_vertical = 30; // Should be equal to the resizer_vertical.height in css file original_x = document.getElementById('resizer_horizontal').getBoundingClientRect().left; original_y = document.getElementById('resizer_horizontal').getBoundingClientRect().top; original_mouse_x = e.pageX; @@ -355,10 +427,23 @@ function makeResizableDiv() { function resize(e) { - const height = original_height_report_list - - document.getElementById('optionblock').offsetHeight + var mouse_max_y = + parseInt(window.getComputedStyle(document.getElementById('body')).getPropertyValue('margin-top')) + + document.getElementById('optionblock').offsetHeight + + document.getElementById('title').offsetHeight + + document.getElementById('reportlistTbl').getElementsByTagName('thead')[0].offsetHeight + + document.getElementById('reportlistTbl').getElementsByTagName('thead')[0].getElementsByTagName('tr')[0].offsetHeight + ; + + var mouse_min_y = + window.innerHeight + - document.getElementById('footer').offsetHeight + - (document.getElementById('resizer_horizontal').offsetHeight / 2) + - document.getElementById('report_desc').offsetHeight + ; ; - if ( (original_mouse_y - e.pageY) < height && e.pageY < (window.innerHeight - document.getElementById('footer').offsetHeight - (document.getElementById('resizer_horizontal').offsetHeight / 2)) ) { + // if statement prevents report list div from contracting small enough to hide the first row && expanding large enough to hide the Report Data description + if ( e.pageY > mouse_max_y && e.pageY < mouse_min_y ) { // Change all cursors over Report List table to ns-cursor var cursors = document.getElementById("reportlistTbl").getElementsByTagName("tr"); for(var i=0;i<cursors.length;i++){ @@ -406,12 +491,14 @@ function makeResizableDiv() { } document.getElementById('body').style.cursor = "default"; - window.removeEventListener('mousemove', resize); - } + report_list_height_percent = parseInt(document.getElementById('report_list').offsetHeight * 100 / available_height); + + window.removeEventListener('mousemove', resize); + } if (document.getElementById('resizer_vertical') != 'undefined' && document.getElementById('resizer_vertical') != null) { document.getElementById('resizer_vertical').addEventListener('mousedown', function (e) { - e.preventDefault();// ; + e.preventDefault(); original_width_report_data_xml = document.getElementById('report_data_xml').offsetWidth; original_width_report_data_table_div = document.getElementById('report_data_table_div').offsetWidth; original_x = document.getElementById('resizer_vertical').getBoundingClientRect().left; @@ -425,7 +512,11 @@ function makeResizableDiv() { function resize_vertical(e) { - if ( e.pageX > document.getElementById('resizer_vertical').offsetWidth && e.pageX < window.innerWidth - document.getElementById('resizer_vertical').offsetWidth ) { + var mouse_min_x = + document.getElementById('report_data_table').getElementsByTagName('thead')[0].getElementsByTagName('tr')[0].getElementsByTagName('th')[0].offsetWidth // i.e. the width of the first column of the Report Data table + var mouse_max_x = window.innerWidth - mouse_min_x; + + if ( e.pageX > mouse_min_x && e.pageX < mouse_max_x ) { document.getElementById('body').style.cursor = "ew-resize"; mouse_movement = e.pageX - original_mouse_x; document.getElementById('report_data_xml').style.width =+ original_width_report_data_xml - mouse_movement + 'px'; @@ -437,8 +528,7 @@ function makeResizableDiv() { + 'px' ; } - - report_data_xml_width_last = document.getElementById('report_data_xml').offsetWidth; + report_data_xml_width_percent = parseInt( document.getElementById('report_data_xml').offsetWidth / document.getElementById('report_data').offsetWidth * 100); } function stopResize_vertical() { @@ -447,3 +537,121 @@ function makeResizableDiv() { window.removeEventListener('mousemove', resize_vertical); } } + +// Cookie Functions +// ---------------------------------------------------------------------------- +function build_cookie() { + + // Don't allow cookie to be set if there are no reports displayed + if ( document.getElementById('reportlistTbl') != "undefined" && document.getElementById('reportlistTbl') != null ) { + // There are reports showing + + // Build cookie from various sources + + // Change the Period option from the value of the select to (i.e. 'all' or a date) to a boolean, to match the radio button option on the options page + if ( document.getElementById('selPeriod').value == "all" ) { + period = 0; + } else { + period = 1; + } + + // Host lookup + if ( document.getElementsByName('HostLookup')[0].checked ) { + hostlookup = 1; + } else { + hostlookup = 0; + } + + // Sort column and sort direction + if ( document.getElementById('reportlistTbl').getElementsByTagName('thead')[0].getElementsByTagName('tr')[0].getElementsByClassName('desc_triangle').length != 0 ) { + sort_column = document.getElementById('reportlistTbl').getElementsByTagName('thead')[0].getElementsByTagName('tr')[0].getElementsByClassName('desc_triangle')[0].id; + sort = 0; + } else { + sort_column = document.getElementById('reportlistTbl').getElementsByTagName('thead')[0].getElementsByTagName('tr')[0].getElementsByClassName('asc_triangle')[0].id; + sort = 1; + } + + if ( sort_column == "" ) { + sort_column = "maxdate"; + alert("Unfortuantely at this time, neither the DMARC Result nor the Report Status columns can be saved as initial sort columns. The initial sort column has been set to End Date, " + (sort == 0 ? "descending." : "ascending.")); + } + + // Create cookie_value object that gets placed into cookie + + // When a new option is added, check the size of the cookie stored. The cookie size should be less than half of the maximum cookie size allowed per domain. + // Less than half because sometimes the cookie is stored twice (once as dmarcts-options and once as dmarcts-options-tmp). Most browsers have a cookie limit of 4KB. + // Currently, the following options generate a cookie of about 0.5KB + cookie_value = { + "cssfile" : document.styleSheets[0].href.split('/').pop() , + "report_list_height_percent" : report_list_height_percent , + "report_data_xml_width_percent" : report_data_xml_width_percent , + "xml_data_open" : xml_data_open , + "HostLookup" : hostlookup , + "Period" : period , + "DMARC" : document.getElementById('selDMARC').value , + "ReportStatus" : document.getElementById('selReportStatus').value , + "Domain" : document.getElementById('selDomain').value , + "Organisation" : document.getElementById('selOrganisation').value , + "sort_column" : sort_column , + "sort" : sort , + // "alignment_unknown" : 0 , + "dmarc_results_matching_only" : 0 + }; + + cookie_value = JSON.stringify(cookie_value); + setCookie(cookie_name, cookie_value, 365) + } else { + // There are NO reports showing + alert("Settings cannot be saved if there are no reports to display.\n\nChange the filters to show some reports."); + } + setCookie("dmarcts-options-tmp", "", -365) + hideMenu(); +} + +function get_cookie(name) { + + name = name + "="; + var cookie_str = decodeURIComponent(document.cookie); + var cookie_array = cookie_str.split(';'); + for(var i = 0; i <cookie_array.length; i++) { + var c = cookie_array[i]; + while ( c.charAt(0) == " " ) { + c = c.substring(1); + } + if ( c.indexOf(name) == 0 ) { + return c.substring(name.length, c.length); + } + } + return ""; +} + +function setCookie(name, value, exp_days) { + + var d = new Date(); + d.setTime(d.getTime() + (exp_days*24*60*60*1000)); + var expires = "expires="+ d.toUTCString(); + document.cookie = name + "=" + encodeURI(value) + ";" + expires + ";path=/"; +} + +function resetOptions() { + + stored_cookie = get_cookie('dmarcts-options-tmp'); + + if ( stored_cookie == "" || stored_cookie == null ){ + stored_cookie = get_cookie('dmarcts-options'); + setCookie("dmarcts-options-tmp", stored_cookie, 365) + setCookie("dmarcts-options", "", 365) + } + window.location.href = 'dmarcts-report-viewer-options.php'; +} + +function cancelOptions() { + + stored_cookie = get_cookie('dmarcts-options-tmp'); + + if ( stored_cookie ){ + setCookie("dmarcts-options", stored_cookie, 365) + setCookie("dmarcts-options-tmp", "", -365) + } + window.location.href = 'dmarcts-report-viewer.php'; +} |