Files
UT-Registration-Plus/src/views/lib/loadNextCourseCatalogPage.ts
2023-03-05 14:34:26 -06:00

79 lines
3.0 KiB
TypeScript

import getCourseTableRows from './getCourseTableRows';
const NEXT_PAGE_BUTTON_SELECTOR = '#next_nav_link';
const PREV_PAGE_BUTTON_SELECTOR = '#prev_nav_link';
/**
* Represents all the states that we care about when autoloading the next page of courses
*/
export enum AutoLoadStatus {
LOADING = 'LOADING',
IDLE = 'IDLE',
ERROR = 'ERROR',
}
let isLoading = false;
let nextPageURL = getNextButton(document)?.href;
/**
* This will scrape the pagination buttons from the course list and use them to load the next page
* and then return the table rows from the next page
* @returns a tuple of the current LoadStatus (whether are currently loading the next page, or if we have reached the end of the course catalog,
* or if there was an error loading the next page) and an array of the table rows from the next page (or an empty array
* if we have reached the end of the course catalog
*/
export async function loadNextCourseCatalogPage(): Promise<[AutoLoadStatus, HTMLTableRowElement[]]> {
// if there is no more nextPageURL, then we have reached the end of the course catalog, so we can stop
if (!nextPageURL) {
return [AutoLoadStatus.IDLE, []];
}
// remove the next button so that we don't load the same page twice
removePaginationButtons(document);
if (isLoading) {
// if we are already loading the next page, then we don't need to do anything
return [AutoLoadStatus.LOADING, []];
}
// begin loading the next page
isLoading = true;
try {
const response = await fetch(nextPageURL);
const html = await response.text();
const parser = new DOMParser();
const newDocument = parser.parseFromString(html, 'text/html');
// extract the table rows from the document of the next page
const tableRows = getCourseTableRows(newDocument);
if (!tableRows) {
return [AutoLoadStatus.ERROR, []];
}
// extract the next page url from the document of the next page, so when we scroll again we can use that
nextPageURL = getNextButton(newDocument)?.href;
isLoading = false;
return [AutoLoadStatus.IDLE, Array.from(tableRows)];
} catch (e) {
console.error(e);
return [AutoLoadStatus.ERROR, []];
}
}
/**
* Scrapes the next button from the document
* @param doc the document to get the next button from
* @returns the next button from the document
*/
function getNextButton(doc: Document) {
return doc.querySelector<HTMLAnchorElement>(NEXT_PAGE_BUTTON_SELECTOR);
}
/**
* Removes the next and previous buttons from the document so that we don't load the same page twice
* @param doc the document to remove the next and previous buttons from
*/
export function removePaginationButtons(doc: Document) {
const nextButton = doc.querySelectorAll<HTMLAnchorElement>(NEXT_PAGE_BUTTON_SELECTOR);
nextButton.forEach(button => button.remove());
const prevButton = doc.querySelectorAll<HTMLAnchorElement>(PREV_PAGE_BUTTON_SELECTOR);
prevButton.forEach(button => button.remove());
}