starshard/peafowl
Template
1
Fork 0
mirror of https://github.com/starshardstudio/peafowl.git synced 2024-11-25 14:34:20 +00:00
peafowl/_static/scripting/sort.js
2024-11-05 17:50:43 +01:00

272 lines
7 KiB
JavaScript

/**
* @param tableId {string}
* @param readFn {(a: HTMLTableRowElement) => string}
* @param compareFn {(a: string, b: string) => number}
*/
function sortTable(tableId, readFn, compareFn) {
console.debug("Sorting table `", tableId , "` with ", readFn, " and ", compareFn)
/**
* @type {HTMLTableElement | undefined}
*/
const table = document.getElementById(tableId)
if(!table) {
console.error("Table `", tableId, "` not found")
return
}
/**
* @type {HTMLTableSectionElement | undefined}
*/
const tbody = table.tBodies[0]
if(!tbody) {
console.error("Table body of`", tableId, "` not found")
return
}
/**
* @type {HTMLTableRowElement[]}
*/
const allRows = [...tbody.rows]
const undefinedRows = []
for(const row of allRows) {
if(readFn(row) === undefined) {
undefinedRows.push(row)
}
}
const definedRows = allRows.filter(row => readFn(row) !== undefined)
const sortedRows = definedRows.toSorted((a, b) => compareFn(readFn(a), readFn(b)))
let reverse = true
for(let idx = 0; idx < sortedRows.length; idx++) {
if(definedRows[idx] !== sortedRows[idx]) {
reverse = false
break
}
}
if(reverse) {
sortedRows.reverse()
}
const resultRows = sortedRows.concat(undefinedRows)
while(tbody.rows.length > 0) {
tbody.deleteRow(0)
}
for(const row of resultRows) {
tbody.appendChild(row)
}
}
/**
* @param a {HTMLTableRowElement}
*/
function readNameSort(a) {
for(const cell of a.cells) {
if(cell.classList.contains("review-namesort")) {
const value = cell.firstElementChild.value
if(value === "") return undefined
return value
}
}
}
/**
* @param a {HTMLTableRowElement}
*/
function readRating(a) {
for(const cell of a.cells) {
if(cell.classList.contains("review-rating")) {
const value = cell.firstElementChild.value
if(value === "") return undefined
return Number.parseInt(value)
}
}
}
/**
* @param a {HTMLTableRowElement}
*/
function readHoursPlayed(a) {
for(const cell of a.cells) {
if(cell.classList.contains("game-hoursplayed")) {
const value = cell.firstElementChild.value
if(value === "0") return undefined
return Number.parseInt(value)
}
}
}
/**
* @param a {HTMLTableRowElement}
*/
function readDate(a) {
for(const cell of a.cells) {
if(cell.classList.contains("review-date")) {
const value = cell.firstElementChild.dateTime
if(value === "") return undefined
return new Date(value)
}
}
}
/**
* @param a {HTMLTableRowElement}
*/
function readHasContent(a) {
for(const cell of a.cells) {
if(cell.classList.contains("review-hascontent")) {
const value = cell.firstElementChild.value
return value === "true"
}
}
}
/**
* @param a {HTMLTableRowElement}
*/
function readGameProgress(a) {
for(const cell of a.cells) {
if(cell.classList.contains("game-progress")) {
/**
* @type {HTMLDataElement}
*/
const data = cell.firstElementChild
switch (data.value) {
case undefined:
return undefined;
case "unset":
return undefined;
case "notapplicable":
return 5;
case "new":
return 10;
case "started":
return 20;
case "beaten":
return 30;
case "completed":
return 40;
case "mastered":
return 50;
}
}
}
}
/**
* @param a {HTMLTableRowElement}
*/
function readAnimeProgress(a) {
for(const cell of a.cells) {
if(cell.classList.contains("anime-progress")) {
/**
* @type {HTMLDataElement}
*/
const data = cell.firstElementChild
switch (data.value) {
case undefined:
return undefined;
case "unset":
return undefined;
case "new":
return 10;
case "started":
return 20;
case "completed":
return 35;
case "mastered":
return 50;
}
}
}
}
/**
* @param tableId {string}
*/
function installSort(tableId) {
console.debug("Installing sorting capabilities on `", tableId, "`...")
/**
* @type {HTMLTableElement | undefined}
*/
const table = document.getElementById(tableId)
if(!table) {
console.error("Table `", tableId, "` not found")
return
}
/**
* @type {HTMLTableSectionElement | undefined}
*/
const thead = table.tHead
if(!thead) {
console.error("Table header of `", tableId, "` not found")
return
}
/**
* @type {HTMLTableRowElement | undefined}
*/
const thRow = thead.rows[0]
if(!thRow) {
console.error("Table header of `", tableId, "` not found")
return
}
for(const cell of thRow.cells) {
if(cell.classList.contains("review-name")) {
cell.onclick = function() {
sortTable(tableId, readNameSort, (a, b) => a.localeCompare(b))
}
cell.classList.add("sortable")
}
else if(cell.classList.contains("review-rating")) {
cell.onclick = function() {
sortTable(tableId, readRating, (a, b) => b - a)
}
cell.classList.add("sortable")
}
else if(cell.classList.contains("review-date")) {
cell.onclick = function() {
sortTable(tableId, readDate, (a, b) => b - a)
}
cell.classList.add("sortable")
}
else if(cell.classList.contains("game-hoursplayed")) {
cell.onclick = function() {
sortTable(tableId, readHoursPlayed, (a, b) => b - a)
}
cell.classList.add("sortable")
}
else if(cell.classList.contains("review-hascontent")) {
cell.onclick = function() {
sortTable(tableId, readHasContent, (a, b) => b - a)
}
cell.classList.add("sortable")
}
else if(cell.classList.contains("game-progress")) {
cell.onclick = function() {
sortTable(tableId, readGameProgress, (a, b) => b - a)
}
cell.classList.add("sortable")
}
else if(cell.classList.contains("anime-progress")) {
cell.onclick = function() {
sortTable(tableId, readAnimeProgress, (a, b) => b - a)
}
cell.classList.add("sortable")
}
}
}