Files
searxng/client/simple/src/js/main/results.ts
T
dependabot[bot] aa607a379a [upd] web-client (simple): Bump the minor group
Bumps the minor group in /client/simple with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.3.8` | `2.3.10` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.0.1` | `25.0.3` |
| [edge.js](https://github.com/edge-js/edge) | `6.3.0` | `6.4.0` |
| [less](https://github.com/less/less.js) | `4.4.2` | `4.5.1` |
| [sort-package-json](https://github.com/keithamus/sort-package-json) | `3.5.1` | `3.6.0` |
| [vite-bundle-analyzer](https://github.com/nonzzz/vite-bundle-analyzer) | `1.3.1` | `1.3.2` |

Updates `@biomejs/biome` from 2.3.8 to 2.3.10
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.3.10/packages/@biomejs/biome)

Updates `@types/node` from 25.0.1 to 25.0.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `edge.js` from 6.3.0 to 6.4.0
- [Release notes](https://github.com/edge-js/edge/releases)
- [Changelog](https://github.com/edge-js/edge/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/edge-js/edge/compare/v6.3.0...v6.4.0)

Updates `less` from 4.4.2 to 4.5.1
- [Release notes](https://github.com/less/less.js/releases)
- [Changelog](https://github.com/less/less.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/less/less.js/commits)

Updates `sort-package-json` from 3.5.1 to 3.6.0
- [Release notes](https://github.com/keithamus/sort-package-json/releases)
- [Commits](https://github.com/keithamus/sort-package-json/compare/v3.5.1...v3.6.0)

Updates `vite-bundle-analyzer` from 1.3.1 to 1.3.2
- [Release notes](https://github.com/nonzzz/vite-bundle-analyzer/releases)
- [Changelog](https://github.com/nonzzz/vite-bundle-analyzer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nonzzz/vite-bundle-analyzer/compare/v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.3.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
- dependency-name: "@types/node"
  dependency-version: 25.0.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
- dependency-name: edge.js
  dependency-version: 6.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: less
  dependency-version: 4.5.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: sort-package-json
  dependency-version: 3.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: vite-bundle-analyzer
  dependency-version: 1.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-19 17:50:23 +00:00

190 lines
6.0 KiB
TypeScript

// SPDX-License-Identifier: AGPL-3.0-or-later
import "../../../node_modules/swiped-events/src/swiped-events.js";
import { listen, mutable, settings } from "../toolkit.ts";
import { assertElement } from "../util/assertElement.ts";
let imgTimeoutID: number;
const imageLoader = (resultElement: HTMLElement): void => {
if (imgTimeoutID) clearTimeout(imgTimeoutID);
const imgElement = resultElement.querySelector<HTMLImageElement>(".result-images-source img");
if (!imgElement) return;
// use thumbnail until full image loads
const thumbnail = resultElement.querySelector<HTMLImageElement>(".image_thumbnail");
if (thumbnail) {
if (thumbnail.src === `${settings.theme_static_path}/img/img_load_error.svg`) return;
imgElement.onerror = (): void => {
imgElement.src = thumbnail.src;
};
imgElement.src = thumbnail.src;
}
const imgSource = imgElement.getAttribute("data-src");
if (!imgSource) return;
// unsafe nodejs specific, cast to https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout#return_value
// https://github.com/searxng/searxng/pull/5073#discussion_r2265767231
imgTimeoutID = setTimeout(() => {
imgElement.src = imgSource;
imgElement.removeAttribute("data-src");
}, 1000) as unknown as number;
};
const imageThumbnails: NodeListOf<HTMLImageElement> =
document.querySelectorAll<HTMLImageElement>("#urls img.image_thumbnail");
for (const thumbnail of imageThumbnails) {
if (thumbnail.complete && thumbnail.naturalWidth === 0) {
thumbnail.src = `${settings.theme_static_path}/img/img_load_error.svg`;
}
thumbnail.onerror = (): void => {
thumbnail.src = `${settings.theme_static_path}/img/img_load_error.svg`;
};
}
const copyUrlButton: HTMLButtonElement | null =
document.querySelector<HTMLButtonElement>("#search_url button#copy_url");
copyUrlButton?.style.setProperty("display", "block");
mutable.selectImage = (resultElement: HTMLElement): 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";
mutable.scrollPageToSelected?.();
// if there is no element given by the caller, stop here
if (!resultElement) return;
imageLoader(resultElement);
};
mutable.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();
}
mutable.scrollPageToSelected?.();
};
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");
});
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);
}
}
});
listen("click", "#copy_url", async function (this: HTMLElement) {
const target = this.parentElement?.querySelector<HTMLPreElement>("pre");
assertElement(target);
if (window.isSecureContext) {
await navigator.clipboard.writeText(target.innerText);
} else {
const selection = window.getSelection();
if (selection) {
const range = document.createRange();
range.selectNodeContents(target);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand("copy");
}
}
if (this.dataset.copiedText) {
this.innerText = this.dataset.copiedText;
}
});
listen("click", ".result-detail-close", (event: Event) => {
event.preventDefault();
mutable.closeDetail?.();
});
listen("click", ".result-detail-previous", (event: Event) => {
event.preventDefault();
mutable.selectPrevious?.(false);
});
listen("click", ".result-detail-next", (event: Event) => {
event.preventDefault();
mutable.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") {
mutable.closeDetail?.();
}
});
const swipeHorizontal: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(".swipe-horizontal");
for (const element of swipeHorizontal) {
listen("swiped-left", element, () => {
mutable.selectNext?.(false);
});
listen("swiped-right", element, () => {
mutable.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
);