element clicked, i.e. Sort column
const table = document.getElementById(table_id);
const tbody = table.querySelector('tbody');
Array.from(tbody.querySelectorAll('tr')).sort(
comparer(
th_idx, this.asc = !this.asc)).
forEach(tr =>
tbody.appendChild(tr)
);
Array.from(th.parentNode.children).forEach(th => {th.classList.remove("asc_triangle");th.classList.remove("desc_triangle"); } );
this.asc ? th.parentNode.children[th_idx].classList.add("asc_triangle") : th.parentNode.children[th_idx].classList.add("desc_triangle");
}
)
)
)
}
}
function showReportlist(str) { // str is the name of the 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;
var org = document.getElementById('selOrganisation').options[document.getElementById('selOrganisation').selectedIndex].value;
var period = document.getElementById('selPeriod').options[document.getElementById('selPeriod').selectedIndex].value;
var dmarc = document.getElementById('selDMARC').options[document.getElementById('selDMARC').selectedIndex].value;
var report_status = document.getElementById('selReportStatus').options[document.getElementById('selReportStatus').selectedIndex].value;
GETstring += "d=" + domain;
GETstring += "&o=" + org;
GETstring += "&p=" + period;
GETstring += "&dmarc=" + dmarc;
GETstring += "&rptstat=" + report_status;
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange =
function() {
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();
}
};
xhttp.open("GET", "dmarcts-report-viewer-report-list.php" + GETstring, true);
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;
}
function set_heights() {
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";
}
}
function set_report_data_heights() {
report_data_table_div_height =
document.getElementById('report_data').offsetHeight - document.getElementById('report_desc_container').offsetHeight
+ "px"
;
document.getElementById('report_data_table_div').style.height = report_data_table_div_height;
document.getElementById('report_data_xml').style.height = report_data_table_div_height;
}
function report_data_xml_display_toggle() {
if (xml_data_open == 0) {
xml_data_open = 1;
cursor('pointer')
set_report_data_widths();
} else {
unpin_all();
xml_data_open = 0;
cursor('default')
set_report_data_widths();
}
}
function cursor(type) {
document.getElementById('report_desc').style.cursor = type;
document.getElementById('report_data_table').getElementsByTagName('tbody')[0].style.cursor = type
}
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;
}
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';
document.getElementById('xml_html_img').src = 'html.png';
document.getElementById('xml_html_img').title = 'Hide Raw Report XML';
document.getElementById('xml_html_img').alt = 'Hide Raw Report XML';
document.getElementById('resizer_vertical').style.display = "block";
} else {
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 = '';
document.getElementById('xml_html_img').src = 'xml.png';
document.getElementById('xml_html_img').title = 'Show Raw Report XML';
document.getElementById('xml_html_img').alt = 'Show Raw Report XML';
document.getElementById('resizer_vertical').style.display = "none";
}
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";
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 == "") {
// Remove screen overlay
document.getElementById('screen_overlay').style.display = "none";
document.getElementById('screen_overlay').style.cursor = "default";
return;
}
setSelected(str); // setSelected function highlights the report row that is selcted
current_report = str;
var xhttp;
var GETstring = "report=" + str;
var HostLookup = document.getElementsByName('HostLookup');
for ( var i = 0; i < HostLookup.length; i++) {
if(HostLookup[i].checked) {
GETstring += "&hostlookup=" + HostLookup[i].value;
break;
}
}
GETstring += "&p=" + document.getElementById('selPeriod').value;
GETstring += "&dmarc=" + document.getElementById('selDMARC').options[document.getElementById('selDMARC').selectedIndex].value;
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange =
function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("report_data").innerHTML = this.responseText;
sorttable('report_data_table');
set_report_data_heights();
document.getElementById('screen_overlay').style.cursor = "default";
document.getElementById('screen_overlay').style.display = "none";
showResizers();
// current_report = "";
if ( xml_data_open == 1 ) {
set_report_data_widths();
cursor('pointer')
}
if ( xml_data_hljs ) {
hljs.highlightAll();
}
}
};
xhttp.open("GET", "dmarcts-report-viewer-report-data.php?" + GETstring, true);
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() {
if ( document.getElementById('report_desc_container') || document.getElementById('report_data_xml') ) {
document.getElementById('resizer_horizontal').style.display = "block";
document.getElementById('resizer_horizontal').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('resizer_horizontal').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
- (document.getElementById('resizer_vertical').offsetWidth)/2
+ 1 // Need to offset div by borderWidth/2 to centre the resizing handle on the border
// But for some reason, some browsers (Google, Firefox; any others?) won't return the borderWidth (or even borderTopWidth) property if it set in a css file (but WILL return it if set inline with style="")
// + parseInt(document.getElementById('resizer_vertical').style.borderWidth)/2
+ "px";
}
}
function makeResizableDiv() {
if (document.getElementById('resizer_horizontal') != 'undefined' && document.getElementById('resizer_vertical') != null) {
document.getElementById('resizer_horizontal').addEventListener(
'mousedown',
function (e) {
e.preventDefault();
original_width = document.getElementById('resizer_vertical').style.top;
original_height_report_data = document.getElementById('report_data').offsetHeight;
original_height_report_list = document.getElementById('report_list').offsetHeight;
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 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;
original_mouse_y = e.pageY;
window.addEventListener('mousemove', resize);
window.addEventListener('mouseup', stopResize);
}
);
}
function resize(e) {
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 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 original_height_resizer_vertical) {
document.getElementById('resizer_vertical').style.height = original_height_resizer_vertical + 'px';
} else {
document.getElementById('resizer_vertical').style.height = document.getElementById('report_data_xml').offsetHeight - 4 + 'px';
if ( document.getElementById('report_data_xml').offsetHeight <= 4) {
document.getElementById('resizer_vertical').style.display = 'none';
} else {
document.getElementById('resizer_vertical').style.display = 'block';
}
}
}
}
function stopResize() {
// Change all cursors back to default
var cursors = document.getElementById("reportlistTbl").getElementsByTagName("tr");
for(var i=0;i 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';
document.getElementById('report_data_table_div').style.width =+ original_width_report_data_table_div + mouse_movement -5 + 'px';
document.getElementById('resizer_vertical').style.left =
document.getElementById('report_data_xml').offsetLeft
- document.getElementById('resizer_vertical').offsetWidth/2
+ 1
+ 'px'
;
}
report_data_xml_width_percent = parseInt( document.getElementById('report_data_xml').offsetWidth / document.getElementById('report_data').offsetWidth * 100);
}
function stopResize_vertical() {
document.getElementById('body').style.cursor = "default";
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 ,
"xml_data_highlight" : xml_data_highlight,
"xml_data_hljs" : xml_data_hljs
};
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 |