Files
bitvid/js/historyView.js
T

153 lines
3.3 KiB
JavaScript

// js/historyView.js
export const WATCH_HISTORY_EMPTY_COPY =
"Your watch history is empty. Watch some videos to populate this list.";
function resolveElement(selector) {
if (!selector || typeof selector !== "string") {
return null;
}
try {
return document.querySelector(selector);
} catch (error) {
console.warn("[historyView] Failed to query selector:", selector, error);
return null;
}
}
function setHidden(element, hidden) {
if (!(element instanceof HTMLElement)) {
return;
}
element.classList.toggle("hidden", hidden);
if (hidden) {
element.setAttribute("aria-hidden", "true");
} else {
element.removeAttribute("aria-hidden");
}
}
function setTextContent(element, text) {
if (!(element instanceof HTMLElement)) {
return;
}
element.textContent = text;
}
export function createWatchHistoryRenderer(config = {}) {
const {
viewSelector = "#watchHistoryView",
gridSelector = "#watchHistoryGrid",
loadingSelector = "#watchHistoryLoading",
statusSelector = "#watchHistoryStatus",
emptySelector = "#watchHistoryEmpty",
emptyCopy = WATCH_HISTORY_EMPTY_COPY,
} = config;
const state = {
initialized: false,
resolvedVideos: [],
hasMore: false,
isLoading: false,
actor: null,
};
let elements = {
view: null,
grid: null,
loading: null,
status: null,
empty: null,
};
const refreshElements = () => {
elements = {
view: resolveElement(viewSelector),
grid: resolveElement(gridSelector),
loading: resolveElement(loadingSelector),
status: resolveElement(statusSelector),
empty: resolveElement(emptySelector),
};
};
const hideLoading = () => {
setHidden(elements.loading, true);
if (elements.status) {
setHidden(elements.status, true);
}
};
const showEmpty = () => {
if (elements.grid) {
elements.grid.innerHTML = "";
setHidden(elements.grid, true);
}
if (elements.empty) {
setTextContent(elements.empty, emptyCopy);
setHidden(elements.empty, false);
}
};
const resetUi = () => {
refreshElements();
hideLoading();
showEmpty();
};
return {
async init() {
resetUi();
state.initialized = true;
state.resolvedVideos = [];
state.hasMore = false;
state.isLoading = false;
},
async ensureInitialLoad() {
if (!state.initialized) {
await this.init();
return;
}
resetUi();
},
async loadMore() {
return [];
},
resume() {},
pause() {},
destroy() {
state.initialized = false;
state.resolvedVideos = [];
state.hasMore = false;
state.isLoading = false;
hideLoading();
showEmpty();
},
async refresh() {
await this.ensureInitialLoad();
},
render() {
resetUi();
},
getState() {
return {
...state,
resolvedVideos: state.resolvedVideos.slice(),
};
},
};
}
export const watchHistoryRenderer = createWatchHistoryRenderer();
export async function initHistoryView() {
await watchHistoryRenderer.init();
}
if (typeof window !== "undefined") {
if (!window.bitvid) {
window.bitvid = {};
}
window.bitvid.initHistoryView = initHistoryView;
window.bitvid.watchHistoryRenderer = watchHistoryRenderer;
}