accessibility_scanner-8.x-1.0-alpha8/js/gchart-axecore-cli.js
js/gchart-axecore-cli.js
/**
* @file
* Provides some very basic filtering functionality for @axe-core/cli results.
*/
(function ($, Drupal, drupalSettings) {
'use strict';
var chartObj = {
defaultState: {
allTags: {},
currentUrl: '#all_urls',
disabledPassFail: { pass: false, fail: false },
disabledTags: { '#all_tags': true },
maxUrls: 50,
},
state: {},
stateKey: 'axecore-cli-history-state',
redrawTimeout: null,
tagLabels: {
'wcag2a': Drupal.t('WCAG 2.0 Level A'),
'wcag2aa': Drupal.t('WCAG 2.0 Level AA'),
'wcag21a': Drupal.t('WCAG 2.1 Level A'),
'wcag21aa': Drupal.t('WCAG 2.1 Level AA'),
'best-practice': Drupal.t('Common accessibility best practices'),
'ACT': Drupal.t('W3C approved Accessibility Conformance Testing rules'),
'section508': Drupal.t('Old Section 508 rules'),
'experimental': Drupal.t('Cutting-edge rules'),
},
drawCharts: function () {
clearTimeout(chartObj.redrawTimeout);
setTimeout(function () {
if (chartObj.hasHistoricalChart()) {
chartObj.init();
chartObj.drawHistoricalCharts();
chartObj.generateUrlFilter();
chartObj.generatePassFailFilter();
chartObj.generateTagFilter();
chartObj.generateResetButton();
localStorage.setItem(chartObj.stateKey, JSON.stringify(chartObj.state));
}
if (chartObj.hasPreviewChart()) {
chartObj.drawPreviewChart();
}
}, 100);
},
drawHistoricalChartGenericViolation: function (chart, chartTitle, violationType, countType) {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', Drupal.t('Critical'));
data.addColumn('number', Drupal.t('Serious'));
data.addColumn('number', Drupal.t('Moderate'));
data.addColumn('number', Drupal.t('Minor'));
Object.keys(drupalSettings.axeCoreCliReportData).forEach(function (timestamp) {
var details = drupalSettings.axeCoreCliReportData[timestamp][chartObj.state.currentUrl];
if (typeof details === 'undefined') {
return;
}
var row = [
new Date(1000 * timestamp),
];
var totals = {
critical: 0,
serious: 0,
moderate: 0,
minor: 0,
};
Object.keys(totals).forEach(function (severity) {
Object.keys(details).forEach(function (tag) {
if (!chartObj.state.disabledTags[tag]) {
totals[severity] += details[tag][violationType][severity][countType];
}
});
row.push(totals[severity]);
});
data.addRow(row);
});
var options = {
title: chartTitle,
chartArea: {
width: '90%',
},
curveType: 'function',
legend: { position: 'top', maxLines: 5 }
};
var gChart = new google.visualization.LineChart(chart);
gChart.draw(data, options);
},
drawHistoricalChartDistinctIncomplete: function (chart) {
chartObj.drawHistoricalChartGenericViolation(chart, Drupal.t('Distinct Rules Needing Review'), 'incomplete', 'distinct');
},
drawHistoricalChartDistinctViolations: function (chart) {
chartObj.drawHistoricalChartGenericViolation(chart, Drupal.t('Distinct Rule Violations'), 'violations', 'distinct');
},
drawHistoricalChartTotalIncomplete: function (chart) {
chartObj.drawHistoricalChartGenericViolation(chart, Drupal.t('Total Elements Needing Review'), 'incomplete', 'total');
},
drawHistoricalChartTotalViolations: function (chart) {
chartObj.drawHistoricalChartGenericViolation(chart, Drupal.t('Total Violations'), 'violations', 'total');
},
drawHistoricalChartPassFail: function (chart) {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
var isFirst = true;
var chartTags = [];
Object.keys(drupalSettings.axeCoreCliReportData).forEach(function (timestamp) {
var details = drupalSettings.axeCoreCliReportData[timestamp];
var row = [new Date(1000 * timestamp)];
isFirst && Object.keys(chartObj.state.allTags).sort().forEach(function (tag) {
if (!chartObj.state.disabledTags[tag]) {
if (!chartObj.state.disabledPassFail['pass']) {
data.addColumn('number', Drupal.t('Passing @standard', { '@standard': chartObj.tagLabels[tag] }));
}
if (!chartObj.state.disabledPassFail['fail']) {
data.addColumn('number', Drupal.t('Failing @standard', { '@standard': chartObj.tagLabels[tag] }));
}
chartTags.push(tag);
}
});
chartTags.forEach(function(tag) {
if (!chartObj.state.disabledTags[tag]) {
if (!chartObj.state.disabledPassFail['pass']) {
row.push(details['#passing'][tag] || 0);
}
if (!chartObj.state.disabledPassFail['fail']) {
row.push(details['#failing'][tag] || 0);
}
}
});
data.addRow(row);
isFirst && (isFirst = false);
});
var options = {
title: Drupal.t('Passing/Failing URLs'),
chartArea: {
width: '90%',
},
curveType: 'function',
legend: { position: 'top', maxLines: 5 }
};
var gChart = new google.visualization.LineChart(chart);
gChart.draw(data, options);
},
drawHistoricalCharts: function() {
var charts = document.getElementsByClassName('axecore-cli-history__chart');
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
chart.classList.add('axecore-cli-history__chart' + chart.dataset.type);
var chartKey = 'drawHistoricalChart' + chart.dataset.type;
if (typeof chartObj[chartKey] === 'function') {
chartObj[chartKey](chart);
}
}
},
drawPreviewChart: function () {
var colorPalette = ['#bb1818', '#f46d12', '#e7b416', '#1c6e8c', '#a8a8a8', '#2dc937'];
var charts = document.getElementsByClassName('axecore-cli-summary__chart');
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var total = +chart.dataset.violations + +chart.dataset.passes + +chart.dataset.incomplete;
var data = [
[Drupal.t('Type'), Drupal.t('Quantity')],
[Drupal.t('Violations (Critical)'), +chart.dataset.violationsCritical],
[Drupal.t('Violations (Serious)'), +chart.dataset.violationsSerious],
[Drupal.t('Violations (Moderate)'), +chart.dataset.violationsModerate],
[Drupal.t('Violations (Minor)'), +chart.dataset.violationsMinor],
[Drupal.t('Needs Review'), +chart.dataset.incomplete],
[Drupal.t('Passing'), +chart.dataset.passes],
];
var dataTable = google.visualization.arrayToDataTable(data);
var chart = new google.visualization.PieChart(chart);
var options = {
annotations: {
alwaysOutside: true,
textStyle: {
fontSize: 16,
auraColor: 'none',
color: '#555'
},
},
chart: {
title: '',
subtitle: '',
},
chartArea:{left:0,top:0,bottom:0,top:0, width: '100%'},
colors: colorPalette,
};
chart.draw(dataTable, options);
}
},
generateUrlFilter: function() {
var filterEl = document.querySelector('.axecore_cli-history__filterUrl');
filterEl.innerHTML = '';
var fieldSetEl = document.createElement('fieldset');
var legendEl = document.createElement('legend');
legendEl.innerText = Drupal.t('Filter by URL');
fieldSetEl.appendChild(legendEl);
var inputEl = document.createElement('input');
inputEl.type = 'text';
inputEl.id = 'filterUrl';
inputEl.name = 'filterUrl';
inputEl.value = chartObj.state.currentUrl !== '#all_urls' ? chartObj.state.currentUrl : '';
inputEl.classList.add('axecore_cli-history__filterUrl');
var labelEl = document.createElement('label');
labelEl.htmlFor = inputEl.id;
labelEl.appendChild(document.createTextNode('URL'));
var descriptionEl = document.createElement('div');
descriptionEl.classList.add('description');
descriptionEl.innerText = Drupal.t('Start typing a URL to filter the results for that URL. Empty field out if you want to see the summary report across all URLs.');
fieldSetEl.appendChild(labelEl);
fieldSetEl.appendChild(inputEl);
fieldSetEl.appendChild(descriptionEl);
filterEl.appendChild(fieldSetEl);
// We unfortunately have to use jQuery for the autocompletion to work.
$(inputEl).autocomplete({
source: Object.keys(chartObj.allUrls),
select: function (event, ui) {
chartObj.state.currentUrl = ui.item.value;
chartObj.drawCharts();
},
});
// If we blank out the field, we need to revert back to all URLs.
inputEl.addEventListener('keyup', function (el) {
if (el.target.value === '') {
chartObj.state.currentUrl = '#all_urls';
chartObj.drawCharts();
}
});
},
generateTagFilter: function () {
var filterEl = document.querySelector('.axecore_cli-history__filterTag');
filterEl.innerHTML = '';
var fieldSetEl = document.createElement('fieldset');
var legendEl = document.createElement('legend');
legendEl.innerText = Drupal.t('Filter by Accessibility Standard');
fieldSetEl.appendChild(legendEl);
Object.keys(chartObj.state.allTags).sort().forEach(function (tag) {
if (tag === '#all_tags') { return; }
var checkboxEl = document.createElement('input');
checkboxEl.type = 'checkbox';
checkboxEl.id = 'filterTag-' + tag;
checkboxEl.name = 'filterTag';
checkboxEl.value = tag;
if (!chartObj.state.disabledTags[tag]) {
checkboxEl.checked = true;
}
checkboxEl.addEventListener('change', chartObj.setFilterValues);
var labelEl = document.createElement('label');
labelEl.htmlFor = checkboxEl.id;
labelEl.appendChild(document.createTextNode(chartObj.tagLabels[tag]));
var checkboxWrapperEl = document.createElement('div');
checkboxWrapperEl.classList.add('axecore_cli-history__filterCheckboxWrapper');
checkboxWrapperEl.appendChild(checkboxEl);
checkboxWrapperEl.appendChild(labelEl);
fieldSetEl.appendChild(checkboxWrapperEl);
});
filterEl.appendChild(fieldSetEl);
},
generatePassFailFilter: function () {
var filterEl = document.querySelector('.axecore_cli-history__filterPassFail');
filterEl.innerHTML = '';
var fieldSetEl = document.createElement('fieldset');
var legendEl = document.createElement('legend');
legendEl.innerText = Drupal.t('Filter by Pass/Fail Status');
fieldSetEl.appendChild(legendEl);
var filters = {
pass: Drupal.t('Passing'),
fail: Drupal.t('Failing'),
};
Object.keys(filters).forEach(function (val) {
var checkboxEl = document.createElement('input');
checkboxEl.type = 'checkbox';
checkboxEl.id = 'filterPassFail-' + val;
checkboxEl.name = 'filterPassFail';
checkboxEl.value = val;
if (!chartObj.state.disabledPassFail[val]) {
checkboxEl.checked = true;
}
checkboxEl.addEventListener('change', chartObj.setFilterValues);
var labelEl = document.createElement('label');
labelEl.htmlFor = checkboxEl.id;
labelEl.appendChild(document.createTextNode(filters[val]));
var checkboxWrapperEl = document.createElement('div');
checkboxWrapperEl.classList.add('axecore_cli-history__filterCheckboxWrapper');
checkboxWrapperEl.appendChild(checkboxEl);
checkboxWrapperEl.appendChild(labelEl);
fieldSetEl.appendChild(checkboxWrapperEl);
});
filterEl.appendChild(fieldSetEl);
},
generateResetButton: function() {
var buttonWrapperEl = document.querySelector('.axecore_cli-history__filterReset');
buttonWrapperEl.innerHTML = '';
var buttonEl = document.createElement('button');
buttonEl.innerText = Drupal.t('Reset Filters');
buttonEl.type = 'reset';
buttonEl.addEventListener('click', function() {
chartObj.resetState();
chartObj.drawCharts();
});
buttonWrapperEl.appendChild(buttonEl);
},
hasHistoricalChart: function () {
return !!document.querySelector('.axecore-cli-history__chart');
},
hasPreviewChart: function() {
return !!document.querySelector('.axecore-cli-summary__chart');
},
setFilterValues: function(el) {
if (el.target.name === 'filterTag') {
chartObj.state.disabledTags[el.target.value] = !el.target.checked;
}
else if (el.target.name === 'filterPassFail') {
chartObj.state.disabledPassFail[el.target.value] = !el.target.checked;
}
chartObj.drawCharts();
},
setState: function(state) {
chartObj.state = state;
},
resetState: function() {
chartObj.state = chartObj.defaultState;
},
loadStateFromStorage: function() {
var state = null;
try {
state = JSON.parse(localStorage.getItem(chartObj.stateKey));
}
catch (exception) {
console.error(Drupal.t('State was malformed. Resetting to default value.'));
}
finally {
if (state) {
chartObj.setState(state);
}
else {
chartObj.resetState();
}
}
},
init: function() {
var reportDataKeys = Object.keys(drupalSettings.axeCoreCliReportData);
var relevantTags = [];
chartObj.allUrls = {};
// Set all relevant tags.
reportDataKeys.forEach(function (timestamp) {
var details = drupalSettings.axeCoreCliReportData[timestamp];
Object.keys(details['#tags']).forEach(function (tag) {
chartObj.state.allTags[tag] = true;
if (!chartObj.state.disabledTags[tag]) {
relevantTags[chartObj.tagLabels[tag]] = true;
}
});
Object.keys(details).forEach(function(url) {
if (url.charAt(0) !== '#') {
chartObj.allUrls[url] = true;
}
})
});
// Set results title.
var titleEl = document.querySelector('.axecore_cli-history__resultsTitle');
if (chartObj.state.currentUrl === '#all_urls') {
titleEl.innerText = Drupal.t('All Scanned URLs');
}
else {
titleEl.innerText = chartObj.state.currentUrl;
}
// Set date range.
var dateFrom = new Date(1000 * Math.min(...reportDataKeys));
var dateTo = new Date(1000 * Math.max(...reportDataKeys));
var dateRangeEl = document.querySelector('.axecore_cli-history__resultsDateRange');
dateRangeEl.innerText = Drupal.t('@from to @to', {
'@from': dateFrom.toLocaleDateString(),
'@to': dateTo.toLocaleDateString(),
});
// Set the standards details.
var standardsEl = document.querySelector('.axecore_cli-history__resultsStandards');
standardsEl.innerHTML = '';
Object.keys(relevantTags).sort().forEach(function (tag) {
var liEl = document.createElement('li');
liEl.innerText = tag;
standardsEl.appendChild(liEl);
});
// Hide/show elements that are supposed to show only when set to all urls.
var els = document.querySelectorAll('.axecore_cli-history__allUrlsOnly');
els.forEach(function (el) {
if (chartObj.state.currentUrl === '#all_urls') {
el.style.display = 'block';
// Update the URL list.
var listEl = document.querySelector('.axecore_cli-history__resultsUrlList');
listEl.innerHTML = '';
var urlList = Object.keys(chartObj.allUrls);
var totalUrls = urlList.length;
if (totalUrls > chartObj.state.maxUrls) {
var buttonEl = document.createElement('button');
buttonEl.innerText = Drupal.t('Load Full URL List');
buttonEl.type = 'button';
buttonEl.addEventListener('click', function() {
chartObj.state.maxUrls = totalUrls;
chartObj.drawCharts();
});
var liEl = document.createElement('li');
liEl.innerText = Drupal.t('There are too many URLs to show by default... ');
liEl.appendChild(buttonEl);
listEl.appendChild(liEl);
}
else {
for (var i = 0; i < totalUrls; i++) {
var url = urlList[i]
var liEl = document.createElement('li');
liEl.innerText = url;
listEl.appendChild(liEl)
}
}
}
else {
el.style.display = 'none';
}
});
}
}
Drupal.behaviors.accessibilityScannerAxeCoreCliGoogleChart = {
attached: false,
attach: function attach(context) {
if (!Drupal.behaviors.accessibilityScannerAxeCoreCliGoogleChart.attached) {
Drupal.behaviors.accessibilityScannerAxeCoreCliGoogleChart.attached = true;
chartObj.loadStateFromStorage();
google.charts.load('current', {packages: ['corechart', 'bar']});
google.charts.setOnLoadCallback(chartObj.drawCharts);
window.addEventListener('resize', chartObj.drawCharts);
}
}
};
})(jQuery, Drupal, drupalSettings);
