library/frontend/files/records/app.js
David Ashby 8bdf848cbf
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
finish up rewrite
2023-02-11 23:00:38 -05:00

169 lines
4.2 KiB
JavaScript

var sortState = {
sortBy: "sortArtist",
sortOrder: "asc",
};
function init() {
fetch("/api/records")
.then((response) => response.json())
.then((records) => {
// prepare response
records.forEach(apiResponseParsing);
document.getElementById("search").addEventListener("input", (e) => {
renderTable(search(records, e.target.value));
});
renderTable(records);
});
}
function renderTable(records, sortField) {
if (sortField) {
if (sortState.sortBy === sortField && sortState.sortOrder === "asc") {
sortState.sortOrder = "desc";
} else {
sortState.sortOrder = "asc";
}
sortState.sortBy = sortField;
}
records.sort((one, two) =>
(one[sortState.sortBy] + one["sortName"]).localeCompare(
two[sortState.sortBy] + two["sortName"]
)
);
if (sortState.sortOrder === "desc") {
records.reverse();
}
records.forEach((e, i) => (e.rowNumber = i)); // re-key
// rendering
var recordElement = document.getElementById("records");
recordElement.innerHTML = TableTemplate(records);
var recordCount = document.getElementById("recordCount");
recordCount.innerHTML = `${records.length} records`;
// add listeners for selecting record to view
Array.from(recordElement.querySelectorAll("tbody tr"))
.slice(1) // remove header from Array
.forEach((row) => {
row.addEventListener("click", (e) => {
// add listener to swap current record
document.getElementById("current").innerHTML = RecordTemplate(
records[e.currentTarget.id]
);
});
});
// add sorting callbacks
Array.from(
recordElement.querySelectorAll("tbody tr th[data-sort-by]")
).forEach((row) => {
row.addEventListener("click", function (e) {
renderTable(records, e.target.dataset.sortBy); // only add callback when there's a sortBy attribute
});
});
// mark currently active column
recordElement
.querySelector("tbody tr th[data-sort-by=" + sortState.sortBy + "]")
.classList.add(sortState.sortOrder);
}
function apiResponseParsing(record) {
record.sortName = titleCleaner(record.name);
record.artists = record.artists.map((artist) => {
return artist.replace(/ \([0-9]+\)$/, "");
});
record.label = record.label.replace(/ \([0-9]+\)$/, "");
record.sortArtist = record.artists.reduce((acc, curr) => {
return (
acc +
curr
.replace(/^(An?|The)\s/i, "")
.toLowerCase()
.replaceAll('"', "")
.replaceAll(":", "")
.replaceAll("'", "")
.replaceAll(" ", "")
);
}, "");
return record;
}
function search(records, searchBy) {
searchBy = searchCleaner(searchBy);
if (searchBy !== "") {
records = records.filter(({ name, artists, genre, label, year }) => {
return Object.values({
name,
artists: artists.join(" "),
genre,
label,
year,
}).find((field) => searchCleaner(field).indexOf(searchBy) !== -1);
});
}
return records;
}
function titleCleaner(title) {
return title
.replace('"', "")
.replace(":", "")
.replace(/^(An?|The)\s/i, "");
}
function searchCleaner(str) {
return str
.toLowerCase()
.replaceAll('"', "")
.replaceAll(":", "")
.replaceAll("'", "")
.replaceAll(" ", "");
}
function RecordTemplate({
name,
artists,
coverURL,
format,
genre,
identifier,
label,
year,
discogsURL,
}) {
return `${coverURL ? `<img src="${coverURL}"/>` : ""}
<h1>${name}</h1>
<h2>${artists.join(", ")}</h2>
<span>${identifier}</span><br/>
<span>${genre}, ${label}, ${year}</span><br/>
<span>${format}</span><br/>
<span>
<a
target="_blank"
href="${discogsURL}"
>
Data provided by Discogs.
</a>
</span>`;
}
function TableRowTemplate({ name, coverURL, discogsURL }) {
return `<div class="record">
<img class="cover" src="${coverURL}"/>
<span class="name">${name}</span>
<a
target="_blank"
href="${discogsURL}"
class="discogsLink"
>
Data provided by Discogs.
</a>
</div>`;
}
function TableTemplate(records) {
return `<div class="flow">${records.reduce((acc, record) => {
return acc.concat(TableRowTemplate(record));
}, "")} </div>`;
}