Files
bitvid/js/search/searchFilterState.js
T

113 lines
2.9 KiB
JavaScript

import {
DEFAULT_FILTERS,
parseFilterQuery,
serializeFiltersToQuery,
} from "./searchFilters.js";
const listeners = new Set();
const cloneFilters = (filters = DEFAULT_FILTERS) => ({
dateRange: {
after: filters?.dateRange?.after ?? null,
before: filters?.dateRange?.before ?? null,
},
sort: filters?.sort ?? DEFAULT_FILTERS.sort,
authorPubkeys: Array.isArray(filters?.authorPubkeys)
? [...filters.authorPubkeys]
: [],
tags: Array.isArray(filters?.tags) ? [...filters.tags] : [],
textScope: filters?.textScope ?? DEFAULT_FILTERS.textScope,
duration: {
minSeconds: filters?.duration?.minSeconds ?? null,
maxSeconds: filters?.duration?.maxSeconds ?? null,
},
hasMagnet:
typeof filters?.hasMagnet === "boolean" ? filters.hasMagnet : null,
hasUrl: typeof filters?.hasUrl === "boolean" ? filters.hasUrl : null,
nsfw: filters?.nsfw ?? DEFAULT_FILTERS.nsfw,
relay: filters?.relay ?? DEFAULT_FILTERS.relay,
kind:
Number.isFinite(filters?.kind) && filters.kind !== null
? filters.kind
: null,
});
let state = {
text: "",
filters: cloneFilters(DEFAULT_FILTERS),
};
function notify() {
const snapshot = getSearchFilterState();
listeners.forEach((listener) => listener(snapshot));
}
export function getSearchFilterState() {
return {
text: state.text,
filters: cloneFilters(state.filters),
};
}
export function setSearchFilterState(nextState = {}, options = {}) {
state = {
text: typeof nextState.text === "string" ? nextState.text : "",
filters: cloneFilters(nextState.filters),
};
if (options.notify !== false) {
notify();
}
}
export function resetSearchFilters(options = {}) {
state = {
text: state.text,
filters: cloneFilters(DEFAULT_FILTERS),
};
if (options.notify !== false) {
notify();
}
}
export function subscribeSearchFilterState(listener) {
if (typeof listener !== "function") {
return () => {};
}
listeners.add(listener);
return () => listeners.delete(listener);
}
export function syncSearchFilterStateFromHash(hash = "") {
const hashString =
typeof hash === "string" && hash ? hash : window?.location?.hash || "";
const hashParams = new URLSearchParams(
hashString.split("?")[1] || hashString.slice(1),
);
const rawQuery = hashParams.get("q") || "";
const rawFilters = hashParams.get("filters") || "";
const parsed = parseFilterQuery(
[rawQuery, rawFilters].filter(Boolean).join(" "),
);
setSearchFilterState(
{
text: parsed.text || "",
filters: parsed.filters,
},
{ notify: true },
);
return parsed;
}
export function buildSearchHashFromState(nextState = state) {
const params = new URLSearchParams();
if (nextState.text) {
params.set("q", nextState.text);
}
const serialized = serializeFiltersToQuery(nextState.filters);
if (serialized) {
params.set("filters", serialized);
}
const queryString = params.toString();
return queryString ? `search&${queryString}` : "search";
}