summaryrefslogtreecommitdiff
path: root/client/simple/src/js/main/results.ts
diff options
context:
space:
mode:
Diffstat (limited to 'client/simple/src/js/main/results.ts')
-rw-r--r--client/simple/src/js/main/results.ts181
1 files changed, 181 insertions, 0 deletions
diff --git a/client/simple/src/js/main/results.ts b/client/simple/src/js/main/results.ts
new file mode 100644
index 000000000..e278c894a
--- /dev/null
+++ b/client/simple/src/js/main/results.ts
@@ -0,0 +1,181 @@
+import "../../../node_modules/swiped-events/src/swiped-events.js";
+import { assertElement, searxng } from "./00_toolkit.ts";
+
+const loadImage = (imgSrc: string, onSuccess: () => void): void => {
+ // singleton image object, which is used for all loading processes of a detailed image
+ const imgLoader = new Image();
+
+ // set handlers in the on-properties
+ imgLoader.onload = () => {
+ onSuccess();
+ };
+
+ imgLoader.src = imgSrc;
+};
+
+searxng.ready(
+ () => {
+ const imageThumbnails = document.querySelectorAll<HTMLImageElement>("#urls img.image_thumbnail");
+ for (const thumbnail of imageThumbnails) {
+ if (thumbnail.complete && thumbnail.naturalWidth === 0) {
+ thumbnail.src = `${searxng.settings.theme_static_path}/img/img_load_error.svg`;
+ }
+
+ thumbnail.onerror = () => {
+ thumbnail.src = `${searxng.settings.theme_static_path}/img/img_load_error.svg`;
+ };
+ }
+
+ const copyUrlButton = document.querySelector<HTMLButtonElement>("#search_url button#copy_url");
+ copyUrlButton?.style.setProperty("display", "block");
+
+ searxng.listen("click", ".btn-collapse", function (this: HTMLElement) {
+ const btnLabelCollapsed = this.getAttribute("data-btn-text-collapsed");
+ const btnLabelNotCollapsed = this.getAttribute("data-btn-text-not-collapsed");
+ const target = this.getAttribute("data-target");
+
+ if (!target || !btnLabelCollapsed || !btnLabelNotCollapsed) return;
+
+ const targetElement = document.querySelector<HTMLElement>(target);
+ assertElement(targetElement);
+
+ const isCollapsed = this.classList.contains("collapsed");
+ const newLabel = isCollapsed ? btnLabelNotCollapsed : btnLabelCollapsed;
+ const oldLabel = isCollapsed ? btnLabelCollapsed : btnLabelNotCollapsed;
+
+ this.innerHTML = this.innerHTML.replace(oldLabel, newLabel);
+ this.classList.toggle("collapsed");
+
+ targetElement.classList.toggle("invisible");
+ });
+
+ searxng.listen("click", ".media-loader", function (this: HTMLElement) {
+ const target = this.getAttribute("data-target");
+ if (!target) return;
+
+ const iframeLoad = document.querySelector<HTMLIFrameElement>(`${target} > iframe`);
+ assertElement(iframeLoad);
+
+ const srctest = iframeLoad.getAttribute("src");
+ if (!srctest) {
+ const dataSrc = iframeLoad.getAttribute("data-src");
+ if (dataSrc) {
+ iframeLoad.setAttribute("src", dataSrc);
+ }
+ }
+ });
+
+ searxng.listen("click", "#copy_url", async function (this: HTMLElement) {
+ const target = this.parentElement?.querySelector<HTMLPreElement>("pre");
+ assertElement(target);
+
+ await navigator.clipboard.writeText(target.innerText);
+ const copiedText = this.dataset.copiedText;
+ if (copiedText) {
+ this.innerText = copiedText;
+ }
+ });
+
+ searxng.selectImage = (resultElement: Element): void => {
+ // add a class that can be evaluated in the CSS and indicates that the
+ // detail view is open
+ const resultsElement = document.getElementById("results");
+ resultsElement?.classList.add("image-detail-open");
+
+ // add a hash to the browser history so that pressing back doesn't return
+ // to the previous page this allows us to dismiss the image details on
+ // pressing the back button on mobile devices
+ window.location.hash = "#image-viewer";
+
+ searxng.scrollPageToSelected?.();
+
+ // if there is no element given by the caller, stop here
+ if (!resultElement) return;
+
+ // find image element, if there is none, stop here
+ const img = resultElement.querySelector<HTMLImageElement>(".result-images-source img");
+ if (!img) return;
+
+ // <img src="" data-src="http://example.org/image.jpg">
+ const src = img.getAttribute("data-src");
+ if (!src) return;
+
+ // use thumbnail until full image loads
+ const thumbnail = resultElement.querySelector<HTMLImageElement>(".image_thumbnail");
+ if (thumbnail) {
+ img.src = thumbnail.src;
+ }
+
+ // load full size image
+ loadImage(src, () => {
+ img.src = src;
+ img.onerror = () => {
+ img.src = `${searxng.settings.theme_static_path}/img/img_load_error.svg`;
+ };
+
+ img.removeAttribute("data-src");
+ });
+ };
+
+ searxng.closeDetail = (): void => {
+ const resultsElement = document.getElementById("results");
+ resultsElement?.classList.remove("image-detail-open");
+
+ // remove #image-viewer hash from url by navigating back
+ if (window.location.hash === "#image-viewer") {
+ window.history.back();
+ }
+
+ searxng.scrollPageToSelected?.();
+ };
+
+ searxng.listen("click", ".result-detail-close", (event: Event) => {
+ event.preventDefault();
+ searxng.closeDetail?.();
+ });
+
+ searxng.listen("click", ".result-detail-previous", (event: Event) => {
+ event.preventDefault();
+ searxng.selectPrevious?.(false);
+ });
+
+ searxng.listen("click", ".result-detail-next", (event: Event) => {
+ event.preventDefault();
+ searxng.selectNext?.(false);
+ });
+
+ // listen for the back button to be pressed and dismiss the image details when called
+ window.addEventListener("hashchange", () => {
+ if (window.location.hash !== "#image-viewer") {
+ searxng.closeDetail?.();
+ }
+ });
+
+ const swipeHorizontal = document.querySelectorAll<HTMLElement>(".swipe-horizontal");
+ for (const element of swipeHorizontal) {
+ searxng.listen("swiped-left", element, () => {
+ searxng.selectNext?.(false);
+ });
+
+ searxng.listen("swiped-right", element, () => {
+ searxng.selectPrevious?.(false);
+ });
+ }
+
+ window.addEventListener(
+ "scroll",
+ () => {
+ const backToTopElement = document.getElementById("backToTop");
+ const resultsElement = document.getElementById("results");
+
+ if (backToTopElement && resultsElement) {
+ const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+ const isScrolling = scrollTop >= 100;
+ resultsElement.classList.toggle("scrolling", isScrolling);
+ }
+ },
+ true
+ );
+ },
+ { on: [searxng.endpoint === "results"] }
+);