All checks were successful
		
		
	
	ci/woodpecker/push/woodpecker Pipeline was successful
				
			
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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}" loading="lazy"/>` : ""}
 | |
|   <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}" loading="lazy"/>
 | |
|     <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>`;
 | |
| }
 |