103 lines
3.5 KiB
JavaScript
103 lines
3.5 KiB
JavaScript
|
// Make the class reference table sortable in ascending or descending order
|
||
|
// when a header is clicked.
|
||
|
|
||
|
|
||
|
// Helper function to return the content from the idx-th cell of row tr
|
||
|
const getCellValue = (tr, idx) => tr.children[idx].textContent;
|
||
|
|
||
|
// Array sorting functions for different columns used by the comparer
|
||
|
|
||
|
// Compares the Desc. and Brief Desc. columns
|
||
|
// "MISSING" comes first in ascending order
|
||
|
const descriptionComparer = function(v1, v2) {
|
||
|
if(v1 == v2) return 0
|
||
|
if(v1 == "OK") return 1
|
||
|
return -1
|
||
|
}
|
||
|
|
||
|
// Compares the Name and Docs URL columns using a basic string sort
|
||
|
const stringComparer = (new Intl.Collator()).compare
|
||
|
|
||
|
// Compares the Overall column by completion percentage
|
||
|
const overallComparer = function(v1, v2) {
|
||
|
return Number(v1.replace("%", "")) - Number(v2.replace("%", ""))
|
||
|
}
|
||
|
|
||
|
// Compares the other columns (constructors, methods, members, etc.)
|
||
|
// by the percentage they're finished.
|
||
|
// If two have the same percentage, they're compared by denominator size.
|
||
|
const fractionComparer = (asc) => function(v1, v2) {
|
||
|
if(v1 == v2) return 0
|
||
|
|
||
|
// Always send 0/0 values to the bottom
|
||
|
// The "asc" parameter is needed for that purpose.
|
||
|
if(v1 == "0/0") {
|
||
|
return asc ? 1 : -1
|
||
|
}
|
||
|
|
||
|
if(v2 == "0/0") {
|
||
|
return asc ? -1 : 1
|
||
|
}
|
||
|
|
||
|
var v1fraction = v1.split("/")
|
||
|
var v2fraction = v2.split("/")
|
||
|
|
||
|
var v1decimal = Number(v1fraction[0]) / Number(v1fraction[1])
|
||
|
var v2decimal = Number(v2fraction[0]) / Number(v2fraction[1])
|
||
|
if(v1decimal == v2decimal) return v1fraction[1] - v2fraction[1]
|
||
|
|
||
|
return v1decimal - v2decimal
|
||
|
}
|
||
|
|
||
|
// Returns a function responsible for sorting a specific table column
|
||
|
// (column = column object, asc = ascending order?).
|
||
|
const comparer = function(column, asc) {
|
||
|
|
||
|
// This is used by the array.sort() function...
|
||
|
return function(a, b) {
|
||
|
const colIdx = Array.from(column.parentNode.children).indexOf(column)
|
||
|
const colName = column.textContent
|
||
|
|
||
|
// Select a function based on which column is being called.
|
||
|
var columnComparer
|
||
|
switch(colName) {
|
||
|
case "Brief Desc.":
|
||
|
case "Desc.":
|
||
|
columnComparer = descriptionComparer
|
||
|
break
|
||
|
case "Name":
|
||
|
case "Docs URL":
|
||
|
columnComparer = stringComparer
|
||
|
break
|
||
|
case "Overall":
|
||
|
columnComparer = overallComparer
|
||
|
break
|
||
|
default:
|
||
|
columnComparer = fractionComparer(column.asc)
|
||
|
break
|
||
|
}
|
||
|
|
||
|
// Switch the order of the values depending on whether it's an ascending or descending sort.
|
||
|
return columnComparer(getCellValue(asc ? a : b, colIdx), getCellValue(asc ? b : a, colIdx));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const SKIP_END_ROWS = 5 // The number of footer rows generated by doc_status.py
|
||
|
|
||
|
// Set up event listeners that will sort the table when headers are clicked.
|
||
|
window.onload = function()
|
||
|
{
|
||
|
document.querySelectorAll('th')
|
||
|
.forEach(th =>
|
||
|
th.addEventListener('click', (() =>
|
||
|
{
|
||
|
const table = th.closest('table');
|
||
|
const tbody = table.querySelector('tbody')
|
||
|
const trows = Array.from(tbody.querySelectorAll('tr'))
|
||
|
trows.slice(0, -SKIP_END_ROWS)
|
||
|
.sort(comparer(th, th.asc = !th.asc)) // Give each column an individual sort direction
|
||
|
.concat(trows.splice(-SKIP_END_ROWS)) // Don't sort the last rows, as they are not class reference entries.
|
||
|
.forEach(tr => tbody.appendChild(tr) );
|
||
|
})));
|
||
|
}
|