From 95172213f69c8fe85a0af69dd2654c7a77327968 Mon Sep 17 00:00:00 2001 From: Ivan Gabaldon Date: Sat, 28 Jun 2025 10:19:15 +0200 Subject: [PATCH] [mod] theme/simple: fmt/lint minor pass *Safe* changes, no behaviour changes. - Initial ES5 to ES2015+ conversion. - Plenty of styling diff changes. --- client/simple/src/js/head/00_init.js | 23 +- client/simple/src/js/main/00_toolkit.js | 121 +++--- client/simple/src/js/main/infinite_scroll.js | 84 ++-- client/simple/src/js/main/keyboard.js | 427 ++++++++++--------- client/simple/src/js/main/mapresult.js | 31 +- client/simple/src/js/main/preferences.js | 29 +- client/simple/src/js/main/results.js | 140 +++--- client/simple/src/js/main/search.js | 92 ++-- client/simple/theme_icons.js | 71 +-- client/simple/tools/img.js | 70 ++- client/simple/tools/jinja_svg_catalog.js | 67 ++- client/simple/tools/plg.js | 19 +- client/simple/vite.config.js | 96 ++--- 13 files changed, 620 insertions(+), 650 deletions(-) diff --git a/client/simple/src/js/head/00_init.js b/client/simple/src/js/head/00_init.js index a7c61c43e..d6abd6b6f 100644 --- a/client/simple/src/js/head/00_init.js +++ b/client/simple/src/js/head/00_init.js @@ -1,20 +1,19 @@ /* SPDX-License-Identifier: AGPL-3.0-or-later */ -(function (w, d) { - 'use strict'; - +((w, d) => { // add data- properties - var script = d.currentScript || (function () { - var scripts = d.getElementsByTagName('script'); - return scripts[scripts.length - 1]; - })(); + var script = + d.currentScript || + (() => { + var scripts = d.getElementsByTagName("script"); + return scripts[scripts.length - 1]; + })(); w.searxng = { - settings: JSON.parse(atob(script.getAttribute('client_settings'))) + settings: JSON.parse(atob(script.getAttribute("client_settings"))) }; // update the css - var htmlElement = d.getElementsByTagName("html")[0]; - htmlElement.classList.remove('no-js'); - htmlElement.classList.add('js'); - + const htmlElement = d.getElementsByTagName("html")[0]; + htmlElement.classList.remove("no-js"); + htmlElement.classList.add("js"); })(window, document); diff --git a/client/simple/src/js/main/00_toolkit.js b/client/simple/src/js/main/00_toolkit.js index 4e374a019..ca5e1d0e0 100644 --- a/client/simple/src/js/main/00_toolkit.js +++ b/client/simple/src/js/main/00_toolkit.js @@ -4,29 +4,28 @@ * (C) Copyright Contributors to the searx project (2014 - 2021). * SPDX-License-Identifier: AGPL-3.0-or-later */ -window.searxng = (function (w, d) { - - 'use strict'; - +window.searxng = ((w, d) => { // not invented here toolkit with bugs fixed elsewhere // purposes : be just good enough and as small as possible // from https://plainjs.com/javascript/events/live-binding-event-handlers-14/ if (w.Element) { - (function (ElementPrototype) { - ElementPrototype.matches = ElementPrototype.matches || - ElementPrototype.matchesSelector || - ElementPrototype.webkitMatchesSelector || - ElementPrototype.msMatchesSelector || - function (selector) { - var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1; - while (nodes[++i] && nodes[i] != node); - return !!nodes[i]; - }; + ((ElementPrototype) => { + ElementPrototype.matches = + ElementPrototype.matches || + ElementPrototype.matchesSelector || + ElementPrototype.webkitMatchesSelector || + ElementPrototype.msMatchesSelector || + function (selector) { + var nodes = (this.parentNode || this.document).querySelectorAll(selector), + i = -1; + while (nodes[++i] && nodes[i] !== this); + return !!nodes[i]; + }; })(Element.prototype); } - function callbackSafe (callback, el, e) { + function callbackSafe(callback, el, e) { try { callback.call(el, e); } catch (exception) { @@ -36,39 +35,44 @@ window.searxng = (function (w, d) { var searxng = window.searxng || {}; - searxng.on = function (obj, eventType, callback, useCapture) { + searxng.on = (obj, eventType, callback, useCapture) => { useCapture = useCapture || false; - if (typeof obj !== 'string') { + if (typeof obj !== "string") { // obj HTMLElement, HTMLDocument obj.addEventListener(eventType, callback, useCapture); } else { // obj is a selector - d.addEventListener(eventType, function (e) { - var el = e.target || e.srcElement, found = false; - while (el && el.matches && el !== d && !(found = el.matches(obj))) el = el.parentElement; - if (found) callbackSafe(callback, el, e); - }, useCapture); + d.addEventListener( + eventType, + (e) => { + var el = e.target || e.srcElement, + found = false; + while (el?.matches && el !== d && !(found = el.matches(obj))) el = el.parentElement; + if (found) callbackSafe(callback, el, e); + }, + useCapture + ); } }; - searxng.ready = function (callback) { - if (document.readyState != 'loading') { + searxng.ready = (callback) => { + if (document.readyState !== "loading") { callback.call(w); } else { - w.addEventListener('DOMContentLoaded', callback.bind(w)); + w.addEventListener("DOMContentLoaded", callback.bind(w)); } }; - searxng.http = function (method, url, data = null) { - return new Promise(function (resolve, reject) { + searxng.http = (method, url, data = null) => + new Promise((resolve, reject) => { try { var req = new XMLHttpRequest(); req.open(method, url, true); req.timeout = 20000; // On load - req.onload = function () { - if (req.status == 200) { + req.onload = () => { + if (req.status === 200) { resolve(req.response, req.responseType); } else { reject(Error(req.statusText)); @@ -76,21 +80,21 @@ window.searxng = (function (w, d) { }; // Handle network errors - req.onerror = function () { + req.onerror = () => { reject(Error("Network Error")); }; - req.onabort = function () { + req.onabort = () => { reject(Error("Transaction is aborted")); }; - req.ontimeout = function () { + req.ontimeout = () => { reject(Error("Timeout")); - } + }; // Make the request if (data) { - req.send(data) + req.send(data); } else { req.send(); } @@ -98,36 +102,35 @@ window.searxng = (function (w, d) { reject(ex); } }); - }; - searxng.loadStyle = function (src) { + searxng.loadStyle = (src) => { var path = searxng.settings.theme_static_path + "/" + src, - id = "style_" + src.replace('.', '_'), + id = "style_" + src.replace(".", "_"), s = d.getElementById(id); if (s === null) { - s = d.createElement('link'); - s.setAttribute('id', id); - s.setAttribute('rel', 'stylesheet'); - s.setAttribute('type', 'text/css'); - s.setAttribute('href', path); + s = d.createElement("link"); + s.setAttribute("id", id); + s.setAttribute("rel", "stylesheet"); + s.setAttribute("type", "text/css"); + s.setAttribute("href", path); d.body.appendChild(s); } }; - searxng.loadScript = function (src, callback) { + searxng.loadScript = (src, callback) => { var path = searxng.settings.theme_static_path + "/" + src, - id = "script_" + src.replace('.', '_'), + id = "script_" + src.replace(".", "_"), s = d.getElementById(id); if (s === null) { - s = d.createElement('script'); - s.setAttribute('id', id); - s.setAttribute('src', path); + s = d.createElement("script"); + s.setAttribute("id", id); + s.setAttribute("src", path); s.onload = callback; - s.onerror = function () { - s.setAttribute('error', '1'); + s.onerror = () => { + s.setAttribute("error", "1"); }; d.body.appendChild(s); - } else if (!s.hasAttribute('error')) { + } else if (!s.hasAttribute("error")) { try { callback.apply(s, []); } catch (exception) { @@ -138,25 +141,25 @@ window.searxng = (function (w, d) { } }; - searxng.insertBefore = function (newNode, referenceNode) { + searxng.insertBefore = (newNode, referenceNode) => { referenceNode.parentNode.insertBefore(newNode, referenceNode); }; - searxng.insertAfter = function (newNode, referenceNode) { + searxng.insertAfter = (newNode, referenceNode) => { referenceNode.parentNode.insertAfter(newNode, referenceNode.nextSibling); }; - searxng.on('.close', 'click', function () { - this.parentNode.classList.add('invisible'); + searxng.on(".close", "click", function () { + this.parentNode.classList.add("invisible"); }); - function getEndpoint () { - for (var className of d.getElementsByTagName('body')[0].classList.values()) { - if (className.endsWith('_endpoint')) { - return className.split('_')[0]; + function getEndpoint() { + for (var className of d.getElementsByTagName("body")[0].classList.values()) { + if (className.endsWith("_endpoint")) { + return className.split("_")[0]; } } - return ''; + return ""; } searxng.endpoint = getEndpoint(); diff --git a/client/simple/src/js/main/infinite_scroll.js b/client/simple/src/js/main/infinite_scroll.js index 07db3305a..b3d308c0c 100644 --- a/client/simple/src/js/main/infinite_scroll.js +++ b/client/simple/src/js/main/infinite_scroll.js @@ -2,80 +2,77 @@ /* global searxng */ -searxng.ready(function () { - 'use strict'; +searxng.ready(() => { + searxng.infinite_scroll_supported = + "IntersectionObserver" in window && + "IntersectionObserverEntry" in window && + "intersectionRatio" in window.IntersectionObserverEntry.prototype; - searxng.infinite_scroll_supported = ( - 'IntersectionObserver' in window && - 'IntersectionObserverEntry' in window && - 'intersectionRatio' in window.IntersectionObserverEntry.prototype); - - if (searxng.endpoint !== 'results') { + if (searxng.endpoint !== "results") { return; } if (!searxng.infinite_scroll_supported) { - console.log('IntersectionObserver not supported'); + console.log("IntersectionObserver not supported"); return; } - let d = document; - var onlyImages = d.getElementById('results').classList.contains('only_template_images'); + const d = document; + var onlyImages = d.getElementById("results").classList.contains("only_template_images"); - function newLoadSpinner () { - var loader = d.createElement('div'); - loader.classList.add('loader'); + function newLoadSpinner() { + var loader = d.createElement("div"); + loader.classList.add("loader"); return loader; } - function replaceChildrenWith (element, children) { - element.textContent = ''; - children.forEach(child => element.appendChild(child)); + function replaceChildrenWith(element, children) { + element.textContent = ""; + children.forEach((child) => element.appendChild(child)); } - function loadNextPage (callback) { - var form = d.querySelector('#pagination form.next_page'); + function loadNextPage(callback) { + var form = d.querySelector("#pagination form.next_page"); if (!form) { - return + return; } - replaceChildrenWith(d.querySelector('#pagination'), [ newLoadSpinner() ]); + replaceChildrenWith(d.querySelector("#pagination"), [newLoadSpinner()]); var formData = new FormData(form); - searxng.http('POST', d.querySelector('#search').getAttribute('action'), formData).then( - function (response) { - var nextPageDoc = new DOMParser().parseFromString(response, 'text/html'); - var articleList = nextPageDoc.querySelectorAll('#urls article'); - var paginationElement = nextPageDoc.querySelector('#pagination'); - d.querySelector('#pagination').remove(); + searxng + .http("POST", d.querySelector("#search").getAttribute("action"), formData) + .then((response) => { + var nextPageDoc = new DOMParser().parseFromString(response, "text/html"); + var articleList = nextPageDoc.querySelectorAll("#urls article"); + var paginationElement = nextPageDoc.querySelector("#pagination"); + d.querySelector("#pagination").remove(); if (articleList.length > 0 && !onlyImages) { // do not add
element when there are only images - d.querySelector('#urls').appendChild(d.createElement('hr')); + d.querySelector("#urls").appendChild(d.createElement("hr")); } - articleList.forEach(articleElement => { - d.querySelector('#urls').appendChild(articleElement); + articleList.forEach((articleElement) => { + d.querySelector("#urls").appendChild(articleElement); }); if (paginationElement) { - d.querySelector('#results').appendChild(paginationElement); + d.querySelector("#results").appendChild(paginationElement); callback(); } - } - ).catch( - function (err) { + }) + .catch((err) => { console.log(err); - var e = d.createElement('div'); + var e = d.createElement("div"); e.textContent = searxng.settings.translations.error_loading_next_page; - e.classList.add('dialog-error'); - e.setAttribute('role', 'alert'); - replaceChildrenWith(d.querySelector('#pagination'), [ e ]); - } - ) + e.classList.add("dialog-error"); + e.setAttribute("role", "alert"); + replaceChildrenWith(d.querySelector("#pagination"), [e]); + }); } if (searxng.settings.infinite_scroll && searxng.infinite_scroll_supported) { const intersectionObserveOptions = { - rootMargin: "20rem", + rootMargin: "20rem" }; - const observedSelector = 'article.result:last-child'; - const observer = new IntersectionObserver(entries => { + const observedSelector = "article.result:last-child"; + const observer = new IntersectionObserver((entries) => { const paginationEntry = entries[0]; if (paginationEntry.isIntersecting) { observer.unobserve(paginationEntry.target); @@ -84,5 +81,4 @@ searxng.ready(function () { }); observer.observe(d.querySelector(observedSelector), intersectionObserveOptions); } - }); diff --git a/client/simple/src/js/main/keyboard.js b/client/simple/src/js/main/keyboard.js index e16134579..bc878c561 100644 --- a/client/simple/src/js/main/keyboard.js +++ b/client/simple/src/js/main/keyboard.js @@ -1,14 +1,13 @@ /* SPDX-License-Identifier: AGPL-3.0-or-later */ /* global searxng */ -searxng.ready(function () { - - function isElementInDetail (el) { +searxng.ready(() => { + function isElementInDetail(el) { while (el !== undefined) { - if (el.classList.contains('detail')) { + if (el.classList.contains("detail")) { return true; } - if (el.classList.contains('result')) { + if (el.classList.contains("result")) { // we found a result, no need to go to the root of the document: // el is not inside a
element return false; @@ -18,9 +17,9 @@ searxng.ready(function () { return false; } - function getResultElement (el) { + function getResultElement(el) { while (el !== undefined) { - if (el.classList.contains('result')) { + if (el.classList.contains("result")) { return el; } el = el.parentNode; @@ -28,14 +27,14 @@ searxng.ready(function () { return undefined; } - function isImageResult (resultElement) { - return resultElement && resultElement.classList.contains('result-images'); + function isImageResult(resultElement) { + return resultElement && resultElement.classList.contains("result-images"); } - searxng.on('.result', 'click', function (e) { + searxng.on(".result", "click", function (e) { if (!isElementInDetail(e.target)) { highlightResult(this)(true, true); - let resultElement = getResultElement(e.target); + const resultElement = getResultElement(e.target); if (isImageResult(resultElement)) { e.preventDefault(); searxng.selectImage(resultElement); @@ -43,166 +42,179 @@ searxng.ready(function () { } }); - searxng.on('.result a', 'focus', function (e) { - if (!isElementInDetail(e.target)) { - let resultElement = getResultElement(e.target); - if (resultElement && resultElement.getAttribute("data-vim-selected") === null) { - highlightResult(resultElement)(true); + searxng.on( + ".result a", + "focus", + (e) => { + if (!isElementInDetail(e.target)) { + const resultElement = getResultElement(e.target); + if (resultElement && resultElement.getAttribute("data-vim-selected") === null) { + highlightResult(resultElement)(true); + } + if (isImageResult(resultElement)) { + searxng.selectImage(resultElement); + } } - if (isImageResult(resultElement)) { - searxng.selectImage(resultElement); - } - } - }, true); + }, + true + ); /* common base for layouts */ var baseKeyBinding = { - 'Escape': { - key: 'ESC', + Escape: { + key: "ESC", fun: removeFocus, - des: 'remove focus from the focused input', - cat: 'Control' + des: "remove focus from the focused input", + cat: "Control" }, - 'c': { - key: 'c', + c: { + key: "c", fun: copyURLToClipboard, - des: 'copy url of the selected result to the clipboard', - cat: 'Results' + des: "copy url of the selected result to the clipboard", + cat: "Results" }, - 'h': { - key: 'h', + h: { + key: "h", fun: toggleHelp, - des: 'toggle help window', - cat: 'Other' + des: "toggle help window", + cat: "Other" }, - 'i': { - key: 'i', + i: { + key: "i", fun: searchInputFocus, - des: 'focus on the search input', - cat: 'Control' + des: "focus on the search input", + cat: "Control" }, - 'n': { - key: 'n', + n: { + key: "n", fun: GoToNextPage(), - des: 'go to next page', - cat: 'Results' + des: "go to next page", + cat: "Results" }, - 'o': { - key: 'o', + o: { + key: "o", fun: openResult(false), - des: 'open search result', - cat: 'Results' + des: "open search result", + cat: "Results" }, - 'p': { - key: 'p', + p: { + key: "p", fun: GoToPreviousPage(), - des: 'go to previous page', - cat: 'Results' + des: "go to previous page", + cat: "Results" }, - 'r': { - key: 'r', + r: { + key: "r", fun: reloadPage, - des: 'reload page from the server', - cat: 'Control' + des: "reload page from the server", + cat: "Control" }, - 't': { - key: 't', + t: { + key: "t", fun: openResult(true), - des: 'open the result in a new tab', - cat: 'Results' - }, + des: "open the result in a new tab", + cat: "Results" + } }; var keyBindingLayouts = { - - "default": Object.assign( - { /* SearXNG layout */ - 'ArrowLeft': { - key: '←', - fun: highlightResult('up'), - des: 'select previous search result', - cat: 'Results' + default: Object.assign( + { + /* SearXNG layout */ + ArrowLeft: { + key: "←", + fun: highlightResult("up"), + des: "select previous search result", + cat: "Results" }, - 'ArrowRight': { - key: '→', - fun: highlightResult('down'), - des: 'select next search result', - cat: 'Results' - }, - }, baseKeyBinding), + ArrowRight: { + key: "→", + fun: highlightResult("down"), + des: "select next search result", + cat: "Results" + } + }, + baseKeyBinding + ), - 'vim': Object.assign( - { /* Vim-like Key Layout. */ - 'b': { - key: 'b', + vim: Object.assign( + { + /* Vim-like Key Layout. */ + b: { + key: "b", fun: scrollPage(-window.innerHeight), - des: 'scroll one page up', - cat: 'Navigation' + des: "scroll one page up", + cat: "Navigation" }, - 'f': { - key: 'f', + f: { + key: "f", fun: scrollPage(window.innerHeight), - des: 'scroll one page down', - cat: 'Navigation' + des: "scroll one page down", + cat: "Navigation" }, - 'u': { - key: 'u', + u: { + key: "u", fun: scrollPage(-window.innerHeight / 2), - des: 'scroll half a page up', - cat: 'Navigation' + des: "scroll half a page up", + cat: "Navigation" }, - 'd': { - key: 'd', + d: { + key: "d", fun: scrollPage(window.innerHeight / 2), - des: 'scroll half a page down', - cat: 'Navigation' + des: "scroll half a page down", + cat: "Navigation" }, - 'g': { - key: 'g', - fun: scrollPageTo(-document.body.scrollHeight, 'top'), - des: 'scroll to the top of the page', - cat: 'Navigation' + g: { + key: "g", + fun: scrollPageTo(-document.body.scrollHeight, "top"), + des: "scroll to the top of the page", + cat: "Navigation" }, - 'v': { - key: 'v', - fun: scrollPageTo(document.body.scrollHeight, 'bottom'), - des: 'scroll to the bottom of the page', - cat: 'Navigation' + v: { + key: "v", + fun: scrollPageTo(document.body.scrollHeight, "bottom"), + des: "scroll to the bottom of the page", + cat: "Navigation" }, - 'k': { - key: 'k', - fun: highlightResult('up'), - des: 'select previous search result', - cat: 'Results' + k: { + key: "k", + fun: highlightResult("up"), + des: "select previous search result", + cat: "Results" }, - 'j': { - key: 'j', - fun: highlightResult('down'), - des: 'select next search result', - cat: 'Results' + j: { + key: "j", + fun: highlightResult("down"), + des: "select next search result", + cat: "Results" }, - 'y': { - key: 'y', + y: { + key: "y", fun: copyURLToClipboard, - des: 'copy url of the selected result to the clipboard', - cat: 'Results' - }, - }, baseKeyBinding) - } + des: "copy url of the selected result to the clipboard", + cat: "Results" + } + }, + baseKeyBinding + ) + }; var keyBindings = keyBindingLayouts[searxng.settings.hotkeys] || keyBindingLayouts.default; - searxng.on(document, "keydown", function (e) { + searxng.on(document, "keydown", (e) => { // check for modifiers so we don't break browser's hotkeys if ( - Object.prototype.hasOwnProperty.call(keyBindings, e.key) - && !e.ctrlKey && !e.altKey - && !e.shiftKey && !e.metaKey + // biome-ignore lint/suspicious/noPrototypeBuiltins: FIXME: support for Chromium 93-87, Firefox 92-78, Safari 15.4-14 + Object.prototype.hasOwnProperty.call(keyBindings, e.key) && + !e.ctrlKey && + !e.altKey && + !e.shiftKey && + !e.metaKey ) { var tagName = e.target.tagName.toLowerCase(); - if (e.key === 'Escape') { + if (e.key === "Escape") { keyBindings[e.key].fun(e); } else { - if (e.target === document.body || tagName === 'a' || tagName === 'button') { + if (e.target === document.body || tagName === "a" || tagName === "button") { e.preventDefault(); keyBindings[e.key].fun(); } @@ -210,13 +222,13 @@ searxng.ready(function () { } }); - function highlightResult (which) { - return function (noScroll, keepFocus) { - var current = document.querySelector('.result[data-vim-selected]'), + function highlightResult(which) { + return (noScroll, keepFocus) => { + var current = document.querySelector(".result[data-vim-selected]"), effectiveWhich = which; if (current === null) { // no selection : choose the first one - current = document.querySelector('.result'); + current = document.querySelector(".result"); if (current === null) { // no first one : there are no results return; @@ -227,48 +239,50 @@ searxng.ready(function () { } } - var next, results = document.querySelectorAll('.result'); - results = Array.from(results); // convert NodeList to Array for further use + var next, + results = document.querySelectorAll(".result"); + results = Array.from(results); // convert NodeList to Array for further use - if (typeof effectiveWhich !== 'string') { + if (typeof effectiveWhich !== "string") { next = effectiveWhich; } else { switch (effectiveWhich) { - case 'visible': - var top = document.documentElement.scrollTop || document.body.scrollTop; - var bot = top + document.documentElement.clientHeight; + case "visible": { + var top = document.documentElement.scrollTop || document.body.scrollTop; + var bot = top + document.documentElement.clientHeight; - for (var i = 0; i < results.length; i++) { - next = results[i]; - var etop = next.offsetTop; - var ebot = etop + next.clientHeight; + for (var i = 0; i < results.length; i++) { + next = results[i]; + var etop = next.offsetTop; + var ebot = etop + next.clientHeight; - if ((ebot <= bot) && (etop > top)) { - break; + if (ebot <= bot && etop > top) { + break; + } } + break; } - break; - case 'down': - next = results[results.indexOf(current) + 1] || current; - break; - case 'up': - next = results[results.indexOf(current) - 1] || current; - break; - case 'bottom': - next = results[results.length - 1]; - break; - case 'top': + case "down": + next = results[results.indexOf(current) + 1] || current; + break; + case "up": + next = results[results.indexOf(current) - 1] || current; + break; + case "bottom": + next = results[results.length - 1]; + break; + case "top": /* falls through */ - default: - next = results[0]; + default: + next = results[0]; } } if (next) { - current.removeAttribute('data-vim-selected'); - next.setAttribute('data-vim-selected', 'true'); + current.removeAttribute("data-vim-selected"); + next.setAttribute("data-vim-selected", "true"); if (!keepFocus) { - var link = next.querySelector('h3 a') || next.querySelector('a'); + var link = next.querySelector("h3 a") || next.querySelector("a"); if (link !== null) { link.focus(); } @@ -280,21 +294,21 @@ searxng.ready(function () { }; } - function reloadPage () { + function reloadPage() { document.location.reload(true); } - function removeFocus (e) { + function removeFocus(e) { const tagName = e.target.tagName.toLowerCase(); - if (document.activeElement && (tagName === 'input' || tagName === 'select' || tagName === 'textarea')) { + if (document.activeElement && (tagName === "input" || tagName === "select" || tagName === "textarea")) { document.activeElement.blur(); } else { searxng.closeDetail(); } } - function pageButtonClick (css_selector) { - return function () { + function pageButtonClick(css_selector) { + return () => { var button = document.querySelector(css_selector); if (button) { button.click(); @@ -302,16 +316,16 @@ searxng.ready(function () { }; } - function GoToNextPage () { + function GoToNextPage() { return pageButtonClick('nav#pagination .next_page button[type="submit"]'); } - function GoToPreviousPage () { + function GoToPreviousPage() { return pageButtonClick('nav#pagination .previous_page button[type="submit"]'); } - function scrollPageToSelected () { - var sel = document.querySelector('.result[data-vim-selected]'); + function scrollPageToSelected() { + var sel = document.querySelector(".result[data-vim-selected]"); if (sel === null) { return; } @@ -321,39 +335,39 @@ searxng.ready(function () { ebot = etop + sel.clientHeight, offset = 120; // first element ? - if ((sel.previousElementSibling === null) && (ebot < wheight)) { + if (sel.previousElementSibling === null && ebot < wheight) { // set to the top of page if the first element // is fully included in the viewport window.scroll(window.scrollX, 0); return; } - if (wtop > (etop - offset)) { + if (wtop > etop - offset) { window.scroll(window.scrollX, etop - offset); } else { var wbot = wtop + wheight; - if (wbot < (ebot + offset)) { + if (wbot < ebot + offset) { window.scroll(window.scrollX, ebot - wheight + offset); } } } - function scrollPage (amount) { - return function () { + function scrollPage(amount) { + return () => { window.scrollBy(0, amount); - highlightResult('visible')(); + highlightResult("visible")(); }; } - function scrollPageTo (position, nav) { - return function () { + function scrollPageTo(position, nav) { + return () => { window.scrollTo(0, position); highlightResult(nav)(); }; } - function searchInputFocus () { + function searchInputFocus() { window.scrollTo(0, 0); - var q = document.querySelector('#q'); + var q = document.querySelector("#q"); q.focus(); if (q.setSelectionRange) { var len = q.value.length; @@ -361,14 +375,14 @@ searxng.ready(function () { } } - function openResult (newTab) { - return function () { - var link = document.querySelector('.result[data-vim-selected] h3 a'); + function openResult(newTab) { + return () => { + var link = document.querySelector(".result[data-vim-selected] h3 a"); if (link === null) { - link = document.querySelector('.result[data-vim-selected] > a'); + link = document.querySelector(".result[data-vim-selected] > a"); } if (link !== null) { - var url = link.getAttribute('href'); + var url = link.getAttribute("href"); if (newTab) { window.open(url); } else { @@ -378,7 +392,7 @@ searxng.ready(function () { }; } - function initHelpContent (divElement) { + function initHelpContent(divElement) { var categories = {}; for (var k in keyBindings) { @@ -387,75 +401,72 @@ searxng.ready(function () { categories[key.cat].push(key); } - var sorted = Object.keys(categories).sort(function (a, b) { - return categories[b].length - categories[a].length; - }); + var sorted = Object.keys(categories).sort((a, b) => categories[b].length - categories[a].length); if (sorted.length === 0) { return; } var html = '×'; - html += '

How to navigate SearXNG with hotkeys

'; - html += ''; + html += "

How to navigate SearXNG with hotkeys

"; + html += "
"; for (var i = 0; i < sorted.length; i++) { var cat = categories[sorted[i]]; - var lastCategory = i === (sorted.length - 1); + var lastCategory = i === sorted.length - 1; var first = i % 2 === 0; if (first) { - html += ''; + html += ""; } - html += ''; // col-sm-* + html += ""; + html += ""; // col-sm-* if (!first || lastCategory) { - html += ''; // row + html += ""; // row } } - html += '
'; + html += ""; - html += '

' + cat[0].cat + '

'; + html += "

" + cat[0].cat + "

"; html += '
    '; for (var cj in cat) { - html += '
  • ' + cat[cj].key + ' ' + cat[cj].des + '
  • '; + html += "
  • " + cat[cj].key + " " + cat[cj].des + "
  • "; } - html += '
'; - html += '
'; + html += ""; divElement.innerHTML = html; } - function toggleHelp () { - var helpPanel = document.querySelector('#vim-hotkeys-help'); + function toggleHelp() { + var helpPanel = document.querySelector("#vim-hotkeys-help"); if (helpPanel === undefined || helpPanel === null) { // first call - helpPanel = document.createElement('div'); - helpPanel.id = 'vim-hotkeys-help'; - helpPanel.className = 'dialog-modal'; + helpPanel = document.createElement("div"); + helpPanel.id = "vim-hotkeys-help"; + helpPanel.className = "dialog-modal"; initHelpContent(helpPanel); - var body = document.getElementsByTagName('body')[0]; + var body = document.getElementsByTagName("body")[0]; body.appendChild(helpPanel); } else { // toggle hidden - helpPanel.classList.toggle('invisible'); - return; + helpPanel.classList.toggle("invisible"); } } - function copyURLToClipboard () { - var currentUrlElement = document.querySelector('.result[data-vim-selected] h3 a'); + function copyURLToClipboard() { + var currentUrlElement = document.querySelector(".result[data-vim-selected] h3 a"); if (currentUrlElement === null) return; - const url = currentUrlElement.getAttribute('href'); + const url = currentUrlElement.getAttribute("href"); navigator.clipboard.writeText(url); } searxng.scrollPageToSelected = scrollPageToSelected; - searxng.selectNext = highlightResult('down'); - searxng.selectPrevious = highlightResult('up'); + searxng.selectNext = highlightResult("down"); + searxng.selectPrevious = highlightResult("up"); }); diff --git a/client/simple/src/js/main/mapresult.js b/client/simple/src/js/main/mapresult.js index 2c3777678..0d212f7c5 100644 --- a/client/simple/src/js/main/mapresult.js +++ b/client/simple/src/js/main/mapresult.js @@ -1,10 +1,8 @@ /* SPDX-License-Identifier: AGPL-3.0-or-later */ /* global L */ -(function (w, d, searxng) { - 'use strict'; - - searxng.ready(function () { - searxng.on('.searxng_init_map', 'click', function (event) { +((w, d, searxng) => { + searxng.ready(() => { + searxng.on(".searxng_init_map", "click", function (event) { // no more request this.classList.remove("searxng_init_map"); @@ -16,8 +14,8 @@ var map_boundingbox = JSON.parse(this.dataset.mapBoundingbox); var map_geojson = JSON.parse(this.dataset.mapGeojson); - searxng.loadStyle('css/leaflet.css'); - searxng.loadScript('js/leaflet.js', function () { + searxng.loadStyle("css/leaflet.css"); + searxng.loadScript("js/leaflet.js", () => { var map_bounds = null; if (map_boundingbox) { var southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]); @@ -28,17 +26,22 @@ // init map var map = L.map(leaflet_target); // create the tile layer with correct attribution - var osmMapnikUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + var osmMapnikUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; var osmMapnikAttrib = 'Map data © OpenStreetMap contributors'; - var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib}); - var osmWikimediaUrl = 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png'; - var osmWikimediaAttrib = 'Wikimedia maps | Maps data © OpenStreetMap contributors'; - var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib}); + var osmMapnik = new L.TileLayer(osmMapnikUrl, { minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib }); + var osmWikimediaUrl = "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png"; + var osmWikimediaAttrib = + 'Wikimedia maps | Maps data © OpenStreetMap contributors'; + var osmWikimedia = new L.TileLayer(osmWikimediaUrl, { + minZoom: 1, + maxZoom: 19, + attribution: osmWikimediaAttrib + }); // init map view if (map_bounds) { // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021 // Still useful ? - setTimeout(function () { + setTimeout(() => { map.fitBounds(map_bounds, { maxZoom: 17 }); @@ -55,7 +58,7 @@ var baseLayers = { "OSM Mapnik": osmMapnik, - "OSM Wikimedia": osmWikimedia, + "OSM Wikimedia": osmWikimedia }; L.control.layers(baseLayers).addTo(map); diff --git a/client/simple/src/js/main/preferences.js b/client/simple/src/js/main/preferences.js index a0b853d61..2760d589d 100644 --- a/client/simple/src/js/main/preferences.js +++ b/client/simple/src/js/main/preferences.js @@ -1,21 +1,20 @@ /* SPDX-License-Identifier: AGPL-3.0-or-later */ -(function (w, d, searxng) { - 'use strict'; - - if (searxng.endpoint !== 'preferences') { +((w, d, searxng) => { + if (searxng.endpoint !== "preferences") { return; } - searxng.ready(function () { + searxng.ready(() => { let engine_descriptions = null; - function load_engine_descriptions () { + + function load_engine_descriptions() { if (engine_descriptions == null) { - searxng.http("GET", "engine_descriptions.json").then(function (content) { + searxng.http("GET", "engine_descriptions.json").then((content) => { engine_descriptions = JSON.parse(content); for (const [engine_name, description] of Object.entries(engine_descriptions)) { - let elements = d.querySelectorAll('[data-engine-name="' + engine_name + '"] .engine-description'); + const elements = d.querySelectorAll('[data-engine-name="' + engine_name + '"] .engine-description'); for (const element of elements) { - let source = ' (' + searxng.settings.translations.Source + ': ' + description[1] + ')'; + const source = " (" + searxng.settings.translations.Source + ": " + description[1] + ")"; element.innerHTML = description[0] + source; } } @@ -23,13 +22,13 @@ } } - for (const el of d.querySelectorAll('[data-engine-name]')) { - searxng.on(el, 'mouseenter', load_engine_descriptions); + for (const el of d.querySelectorAll("[data-engine-name]")) { + searxng.on(el, "mouseenter", load_engine_descriptions); } const enableAllEngines = d.querySelectorAll(".enable-all-engines"); const disableAllEngines = d.querySelectorAll(".disable-all-engines"); - const engineToggles = d.querySelectorAll('tbody input[type=checkbox][class~=checkbox-onoff]'); + const engineToggles = d.querySelectorAll("tbody input[type=checkbox][class~=checkbox-onoff]"); const toggleEngines = (enable) => { for (const el of engineToggles) { // check if element visible, so that only engines of the current category are modified @@ -37,14 +36,14 @@ } }; for (const el of enableAllEngines) { - searxng.on(el, 'click', () => toggleEngines(true)); + searxng.on(el, "click", () => toggleEngines(true)); } for (const el of disableAllEngines) { - searxng.on(el, 'click', () => toggleEngines(false)); + searxng.on(el, "click", () => toggleEngines(false)); } const copyHashButton = d.querySelector("#copy-hash"); - searxng.on(copyHashButton, 'click', (e) => { + searxng.on(copyHashButton, "click", (e) => { e.preventDefault(); navigator.clipboard.writeText(copyHashButton.dataset.hash); copyHashButton.innerText = copyHashButton.dataset.copiedText; diff --git a/client/simple/src/js/main/results.js b/client/simple/src/js/main/results.js index bdd76a3a6..67d28cc65 100644 --- a/client/simple/src/js/main/results.js +++ b/client/simple/src/js/main/results.js @@ -2,55 +2,54 @@ import "../../../node_modules/swiped-events/src/swiped-events.js"; -(function (w, d, searxng) { - 'use strict'; - - if (searxng.endpoint !== 'results') { +((w, d, searxng) => { + if (searxng.endpoint !== "results") { return; } - searxng.ready(function () { - d.querySelectorAll('#urls img').forEach( - img => - img.addEventListener( - 'error', () => { - // console.log("ERROR can't load: " + img.src); - img.src = window.searxng.settings.theme_static_path + "/img/img_load_error.svg"; - }, - {once: true} - )); + searxng.ready(() => { + d.querySelectorAll("#urls img").forEach((img) => + img.addEventListener( + "error", + () => { + // console.log("ERROR can't load: " + img.src); + img.src = window.searxng.settings.theme_static_path + "/img/img_load_error.svg"; + }, + { once: true } + ) + ); - if (d.querySelector('#search_url button#copy_url')) { - d.querySelector('#search_url button#copy_url').style.display = "block"; + if (d.querySelector("#search_url button#copy_url")) { + d.querySelector("#search_url button#copy_url").style.display = "block"; } - searxng.on('.btn-collapse', 'click', function () { - var btnLabelCollapsed = this.getAttribute('data-btn-text-collapsed'); - var btnLabelNotCollapsed = this.getAttribute('data-btn-text-not-collapsed'); - var target = this.getAttribute('data-target'); + searxng.on(".btn-collapse", "click", function () { + var btnLabelCollapsed = this.getAttribute("data-btn-text-collapsed"); + var btnLabelNotCollapsed = this.getAttribute("data-btn-text-not-collapsed"); + var target = this.getAttribute("data-target"); var targetElement = d.querySelector(target); var html = this.innerHTML; - if (this.classList.contains('collapsed')) { + if (this.classList.contains("collapsed")) { html = html.replace(btnLabelCollapsed, btnLabelNotCollapsed); } else { html = html.replace(btnLabelNotCollapsed, btnLabelCollapsed); } this.innerHTML = html; - this.classList.toggle('collapsed'); - targetElement.classList.toggle('invisible'); + this.classList.toggle("collapsed"); + targetElement.classList.toggle("invisible"); }); - searxng.on('.media-loader', 'click', function () { - var target = this.getAttribute('data-target'); - var iframe_load = d.querySelector(target + ' > iframe'); - var srctest = iframe_load.getAttribute('src'); + searxng.on(".media-loader", "click", function () { + var target = this.getAttribute("data-target"); + var iframe_load = d.querySelector(target + " > iframe"); + var srctest = iframe_load.getAttribute("src"); if (srctest === null || srctest === undefined || srctest === false) { - iframe_load.setAttribute('src', iframe_load.getAttribute('data-src')); + iframe_load.setAttribute("src", iframe_load.getAttribute("data-src")); } }); - searxng.on('#copy_url', 'click', function () { - var target = this.parentElement.querySelector('pre'); + searxng.on("#copy_url", "click", function () { + var target = this.parentElement.querySelector("pre"); navigator.clipboard.writeText(target.innerText); this.innerText = this.dataset.copiedText; }); @@ -62,8 +61,8 @@ import "../../../node_modules/swiped-events/src/swiped-events.js"; let imgTimeoutID; // progress spinner, while an image is loading - const imgLoaderSpinner = d.createElement('div'); - imgLoaderSpinner.classList.add('loader'); + const imgLoaderSpinner = d.createElement("div"); + imgLoaderSpinner.classList.add("loader"); // singleton image object, which is used for all loading processes of a // detailed image @@ -89,15 +88,14 @@ import "../../../node_modules/swiped-events/src/swiped-events.js"; }; searxng.selectImage = (resultElement) => { - // add a class that can be evaluated in the CSS and indicates that the // detail view is open - d.getElementById('results').classList.add('image-detail-open'); + d.getElementById("results").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'; + window.location.hash = "#image-viewer"; searxng.scrollPageToSelected(); @@ -105,21 +103,21 @@ import "../../../node_modules/swiped-events/src/swiped-events.js"; if (!resultElement) return; // find object in the element, if there is none, stop here. - const img = resultElement.querySelector('.result-images-source img'); + const img = resultElement.querySelector(".result-images-source img"); if (!img) return; // - const src = img.getAttribute('data-src'); + const src = img.getAttribute("data-src"); // already loaded high-res image or no high-res image available if (!src) return; // use the image thumbnail until the image is fully loaded - const thumbnail = resultElement.querySelector('.image_thumbnail'); + const thumbnail = resultElement.querySelector(".image_thumbnail"); img.src = thumbnail.src; // show a progress spinner - const detailElement = resultElement.querySelector('.detail'); + const detailElement = resultElement.querySelector(".detail"); detailElement.appendChild(imgLoaderSpinner); // load full size image in background @@ -127,58 +125,58 @@ import "../../../node_modules/swiped-events/src/swiped-events.js"; // after the singelton loadImage has loaded the detail image into the // cache, it can be used in the origin as src property. img.src = src; - img.removeAttribute('data-src'); + img.removeAttribute("data-src"); }); }; - searxng.closeDetail = function () { - d.getElementById('results').classList.remove('image-detail-open'); + searxng.closeDetail = () => { + d.getElementById("results").classList.remove("image-detail-open"); // remove #image-viewer hash from url by navigating back - if (window.location.hash == '#image-viewer') window.history.back(); + if (window.location.hash === "#image-viewer") window.history.back(); searxng.scrollPageToSelected(); }; - searxng.on('.result-detail-close', 'click', e => { + searxng.on(".result-detail-close", "click", (e) => { e.preventDefault(); searxng.closeDetail(); }); - searxng.on('.result-detail-previous', 'click', e => { + searxng.on(".result-detail-previous", "click", (e) => { e.preventDefault(); searxng.selectPrevious(false); }); - searxng.on('.result-detail-next', 'click', e => { + searxng.on(".result-detail-next", "click", (e) => { e.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(); + window.addEventListener("hashchange", () => { + if (window.location.hash !== "#image-viewer") searxng.closeDetail(); }); - d.querySelectorAll('.swipe-horizontal').forEach( - obj => { - obj.addEventListener('swiped-left', function () { - searxng.selectNext(false); - }); - obj.addEventListener('swiped-right', function () { - searxng.selectPrevious(false); - }); - } - ); + d.querySelectorAll(".swipe-horizontal").forEach((obj) => { + obj.addEventListener("swiped-left", () => { + searxng.selectNext(false); + }); + obj.addEventListener("swiped-right", () => { + searxng.selectPrevious(false); + }); + }); - w.addEventListener('scroll', function () { - var e = d.getElementById('backToTop'), - scrollTop = document.documentElement.scrollTop || document.body.scrollTop, - results = d.getElementById('results'); - if (e !== null) { - if (scrollTop >= 100) { - results.classList.add('scrolling'); - } else { - results.classList.remove('scrolling'); + w.addEventListener( + "scroll", + () => { + var e = d.getElementById("backToTop"), + scrollTop = document.documentElement.scrollTop || document.body.scrollTop, + results = d.getElementById("results"); + if (e !== null) { + if (scrollTop >= 100) { + results.classList.add("scrolling"); + } else { + results.classList.remove("scrolling"); + } } - } - }, true); - + }, + true + ); }); - })(window, document, window.searxng); diff --git a/client/simple/src/js/main/search.js b/client/simple/src/js/main/search.js index c252dfdb5..aac2fb2b4 100644 --- a/client/simple/src/js/main/search.js +++ b/client/simple/src/js/main/search.js @@ -1,24 +1,23 @@ /* SPDX-License-Identifier: AGPL-3.0-or-later */ /* exported AutoComplete */ -(function (w, d, searxng) { - 'use strict'; - - var qinput_id = "q", qinput; +((w, d, searxng) => { + var qinput_id = "q", + qinput; const isMobile = window.matchMedia("only screen and (max-width: 50em)").matches; - const isResultsPage = document.querySelector("main").id == "main_results"; + const isResultsPage = document.querySelector("main").id === "main_results"; - function submitIfQuery () { - if (qinput.value.length > 0) { - var search = document.getElementById('search'); + function submitIfQuery() { + if (qinput.value.length > 0) { + var search = document.getElementById("search"); setTimeout(search.submit.bind(search), 0); } } - function createClearButton (qinput) { - var cs = document.getElementById('clear_search'); - var updateClearButton = function () { + function createClearButton(qinput) { + var cs = document.getElementById("clear_search"); + var updateClearButton = () => { if (qinput.value.length === 0) { cs.classList.add("empty"); } else { @@ -28,18 +27,18 @@ // update status, event listener updateClearButton(); - cs.addEventListener('click', function (ev) { - qinput.value = ''; + cs.addEventListener("click", (ev) => { + qinput.value = ""; qinput.focus(); updateClearButton(); ev.preventDefault(); }); - qinput.addEventListener('input', updateClearButton, false); + qinput.addEventListener("input", updateClearButton, false); } const fetchResults = async (query) => { let request; - if (searxng.settings.method === 'GET') { + if (searxng.settings.method === "GET") { const reqParams = new URLSearchParams(); reqParams.append("q", query); request = fetch("./autocompleter?" + reqParams.toString()); @@ -47,12 +46,12 @@ const formData = new FormData(); formData.append("q", query); request = fetch("./autocompleter", { - method: 'POST', - body: formData, + method: "POST", + body: formData }); } - request.then(async function (response) { + request.then(async (response) => { const results = await response.json(); if (!results) return; @@ -63,30 +62,30 @@ autocompleteList.innerHTML = ""; // show an error message that no result was found - if (!results[1] || results[1].length == 0) { + if (!results[1] || results[1].length === 0) { const noItemFoundMessage = document.createElement("li"); - noItemFoundMessage.classList.add('no-item-found'); + noItemFoundMessage.classList.add("no-item-found"); noItemFoundMessage.innerHTML = searxng.settings.translations.no_item_found; autocompleteList.appendChild(noItemFoundMessage); return; } - for (let result of results[1]) { + for (const result of results[1]) { const li = document.createElement("li"); li.innerText = result; - searxng.on(li, 'mousedown', () => { + searxng.on(li, "mousedown", () => { qinput.value = result; const form = d.querySelector("#search"); form.submit(); - autocomplete.classList.remove('open'); + autocomplete.classList.remove("open"); }); autocompleteList.appendChild(li); } }); }; - searxng.ready(function () { + searxng.ready(() => { // focus search input on large screens if (!isMobile && !isResultsPage) document.getElementById("q").focus(); @@ -100,20 +99,20 @@ // autocompleter if (searxng.settings.autocomplete) { - searxng.on(qinput, 'input', () => { + searxng.on(qinput, "input", () => { const query = qinput.value; if (query.length < searxng.settings.autocomplete_min) return; setTimeout(() => { - if (query == qinput.value) fetchResults(query); + if (query === qinput.value) fetchResults(query); }, 300); }); - searxng.on(qinput, 'keyup', (e) => { + searxng.on(qinput, "keyup", (e) => { let currentIndex = -1; const listItems = autocompleteList.children; for (let i = 0; i < listItems.length; i++) { - if (listItems[i].classList.contains('active')) { + if (listItems[i].classList.contains("active")) { currentIndex = i; break; } @@ -121,22 +120,22 @@ let newCurrentIndex = -1; if (e.key === "ArrowUp") { - if (currentIndex >= 0) listItems[currentIndex].classList.remove('active'); + if (currentIndex >= 0) listItems[currentIndex].classList.remove("active"); // we need to add listItems.length to the index calculation here because the JavaScript modulos // operator doesn't work with negative numbers newCurrentIndex = (currentIndex - 1 + listItems.length) % listItems.length; } else if (e.key === "ArrowDown") { - if (currentIndex >= 0) listItems[currentIndex].classList.remove('active'); + if (currentIndex >= 0) listItems[currentIndex].classList.remove("active"); newCurrentIndex = (currentIndex + 1) % listItems.length; } else if (e.key === "Tab" || e.key === "Enter") { - autocomplete.classList.remove('open'); + autocomplete.classList.remove("open"); } - if (newCurrentIndex != -1) { + if (newCurrentIndex !== -1) { const selectedItem = listItems[newCurrentIndex]; - selectedItem.classList.add('active'); + selectedItem.classList.add("active"); - if (!selectedItem.classList.contains('no-item-found')) qinput.value = selectedItem.innerText; + if (!selectedItem.classList.contains("no-item-found")) qinput.value = selectedItem.innerText; } }); } @@ -147,20 +146,20 @@ // filter (safesearch, time range or language) (this requires JavaScript // though) if ( - qinput !== null - && searxng.settings.search_on_category_select + qinput !== null && + searxng.settings.search_on_category_select && // If .search_filters is undefined (invisible) we are on the homepage and // hence don't have to set any listeners - && d.querySelector(".search_filters") != null + d.querySelector(".search_filters") != null ) { - searxng.on(d.getElementById('safesearch'), 'change', submitIfQuery); - searxng.on(d.getElementById('time_range'), 'change', submitIfQuery); - searxng.on(d.getElementById('language'), 'change', submitIfQuery); + searxng.on(d.getElementById("safesearch"), "change", submitIfQuery); + searxng.on(d.getElementById("time_range"), "change", submitIfQuery); + searxng.on(d.getElementById("language"), "change", submitIfQuery); } const categoryButtons = d.querySelectorAll("button.category_button"); - for (let button of categoryButtons) { - searxng.on(button, 'click', (event) => { + for (const button of categoryButtons) { + searxng.on(button, "click", (event) => { if (event.shiftKey) { event.preventDefault(); button.classList.toggle("selected"); @@ -169,7 +168,7 @@ // manually deselect the old selection when a new category is selected const selectedCategories = d.querySelectorAll("button.category_button.selected"); - for (let categoryButton of selectedCategories) { + for (const categoryButton of selectedCategories) { categoryButton.classList.remove("selected"); } button.classList.add("selected"); @@ -179,12 +178,12 @@ // override form submit action to update the actually selected categories const form = d.querySelector("#search"); if (form != null) { - searxng.on(form, 'submit', (event) => { + searxng.on(form, "submit", (event) => { event.preventDefault(); const categoryValuesInput = d.querySelector("#selected-categories"); if (categoryValuesInput) { - let categoryValues = []; - for (let categoryButton of categoryButtons) { + const categoryValues = []; + for (const categoryButton of categoryButtons) { if (categoryButton.classList.contains("selected")) { categoryValues.push(categoryButton.name.replace("category_", "")); } @@ -195,5 +194,4 @@ }); } }); - })(window, document, window.searxng); diff --git a/client/simple/theme_icons.js b/client/simple/theme_icons.js index b7d695cc8..d65e1aa2a 100644 --- a/client/simple/theme_icons.js +++ b/client/simple/theme_icons.js @@ -2,8 +2,8 @@ * Generate icons.html for the jinja templates of the simple theme. */ -import { argv } from "node:process"; import { dirname, resolve } from "node:path"; +import { argv } from "node:process"; import { jinja_svg_sets } from "./tools/jinja_svg_catalog.js"; const HERE = dirname(argv[1]) + "/"; @@ -11,62 +11,65 @@ const dest = resolve(HERE, "../../searx/templates/simple/icons.html"); /** @type import("./tools/jinja_svg_catalog.js").JinjaMacro[] */ const searxng_jinja_macros = [ - { name: "icon", class: "sxng-icon-set" }, + { name: "icon", class: "sxng-icon-set" }, { name: "icon_small", class: "sxng-icon-set-small" }, - { name: "icon_big", class: "sxng-icon-set-big" }, + { name: "icon_big", class: "sxng-icon-set-big" } ]; - -const sxng_icon_opts ={ +const sxng_icon_opts = { multipass: true, plugins: [ { name: "removeTitle" }, { name: "removeXMLNS" }, - { name: "addAttributesToSVGElement", + { + name: "addAttributesToSVGElement", params: { attributes: [ { - "aria-hidden": "true", - }]}}] + "aria-hidden": "true" + } + ] + } + } + ] }; - /** @type import("./tools/jinja_svg_catalog.js").IconSet */ const simple_icons = [ { base: resolve(HERE, "node_modules/ionicons/dist/svg"), set: { - "alert": "alert-outline.svg", - "appstore": "apps-outline.svg", - "book": "book-outline.svg", - "close": "close-outline.svg", - "download": "download-outline.svg", + alert: "alert-outline.svg", + appstore: "apps-outline.svg", + book: "book-outline.svg", + close: "close-outline.svg", + download: "download-outline.svg", "ellipsis-vertical": "ellipsis-vertical-outline.svg", "file-tray-full": "file-tray-full-outline.svg", - "film": "film-outline.svg", - "globe": "globe-outline.svg", - "heart": "heart-outline.svg", - "image": "image-outline.svg", - "layers": "layers-outline.svg", - "leecher": "arrow-down.svg", - "location": "location-outline.svg", - "magnet": "magnet-outline.svg", + film: "film-outline.svg", + globe: "globe-outline.svg", + heart: "heart-outline.svg", + image: "image-outline.svg", + layers: "layers-outline.svg", + leecher: "arrow-down.svg", + location: "location-outline.svg", + magnet: "magnet-outline.svg", "musical-notes": "musical-notes-outline.svg", "navigate-down": "chevron-down-outline.svg", "navigate-left": "chevron-back-outline.svg", "navigate-right": "chevron-forward-outline.svg", "navigate-up": "chevron-up-outline.svg", - "people": "people-outline.svg", - "play": "play-outline.svg", - "radio": "radio-outline.svg", - "save": "save-outline.svg", - "school": "school-outline.svg", - "search": "search-outline.svg", - "seeder": "swap-vertical.svg", - "settings": "settings-outline.svg", - "tv": "tv-outline.svg", + people: "people-outline.svg", + play: "play-outline.svg", + radio: "radio-outline.svg", + save: "save-outline.svg", + school: "school-outline.svg", + search: "search-outline.svg", + seeder: "swap-vertical.svg", + settings: "settings-outline.svg", + tv: "tv-outline.svg" }, - svgo_opts: sxng_icon_opts, + svgo_opts: sxng_icon_opts }, // some of the ionicons are not suitable for a dark theme, we fixed the svg // manually in src/svg/ionicons @@ -75,9 +78,9 @@ const simple_icons = [ base: resolve(HERE, "src/svg/ionicons"), set: { "information-circle": "information-circle-outline.svg", - "newspaper": "newspaper-outline.svg", + newspaper: "newspaper-outline.svg" }, - svgo_opts: sxng_icon_opts, + svgo_opts: sxng_icon_opts } ]; diff --git a/client/simple/tools/img.js b/client/simple/tools/img.js index 8f815970a..3f79f5ac5 100644 --- a/client/simple/tools/img.js +++ b/client/simple/tools/img.js @@ -9,40 +9,35 @@ import { optimize as svgo } from "svgo"; * @property {string} dest - Name of the destination file. */ - /** * Convert a list of SVG files to PNG. * * @param {Src2Dest[]} items - Array of SVG files (src: SVG, dest:PNG) to convert. */ -async function svg2png (items) { - items.forEach( - async (item) => { - try { - fs.mkdir(path.dirname(item.dest), { recursive: true }, (err) => { - if (err) - throw err; - }); +async function svg2png(items) { + items.forEach(async (item) => { + try { + fs.mkdir(path.dirname(item.dest), { recursive: true }, (err) => { + if (err) throw err; + }); - const info = await sharp(item.src).png({ + const info = await sharp(item.src) + .png({ force: true, compressionLevel: 9, - palette: true, - }).toFile(item.dest); + palette: true + }) + .toFile(item.dest); - console.log( - `[svg2png] created ${item.dest} -- bytes: ${info.size}, w:${info.width}px, h:${info.height}px` - ); - } catch (err) { - console.error(`ERROR: ${item.dest} -- ${err}`); - throw(err); - } + console.log(`[svg2png] created ${item.dest} -- bytes: ${info.size}, w:${info.width}px, h:${info.height}px`); + } catch (err) { + console.error(`ERROR: ${item.dest} -- ${err}`); + throw err; } - ); + }); } - /** * Optimize SVG images for WEB. * @@ -51,28 +46,21 @@ async function svg2png (items) { */ async function svg2svg(svgo_opts, items) { - items.forEach( - async (item) => { - try { - fs.mkdir(path.dirname(item.dest), { recursive: true }, (err) => { - if (err) - throw err; - }); + items.forEach(async (item) => { + try { + fs.mkdir(path.dirname(item.dest), { recursive: true }, (err) => { + if (err) throw err; + }); - const raw = fs.readFileSync(item.src, "utf8"); - const opt = svgo(raw, svgo_opts); - fs.writeFileSync(item.dest, opt.data); - console.log( - `[svg2svg] optimized: ${item.dest} -- src: ${item.src}` - ); - - } catch (err) { - console.error(`ERROR: optimize src: ${item.src} -- ${err}`); - throw(err); - } + const raw = fs.readFileSync(item.src, "utf8"); + const opt = svgo(raw, svgo_opts); + fs.writeFileSync(item.dest, opt.data); + console.log(`[svg2svg] optimized: ${item.dest} -- src: ${item.src}`); + } catch (err) { + console.error(`ERROR: optimize src: ${item.src} -- ${err}`); + throw err; } - ); + }); } - export { svg2png, svg2svg }; diff --git a/client/simple/tools/jinja_svg_catalog.js b/client/simple/tools/jinja_svg_catalog.js index e3e8f1216..a3e4fd166 100644 --- a/client/simple/tools/jinja_svg_catalog.js +++ b/client/simple/tools/jinja_svg_catalog.js @@ -1,8 +1,8 @@ +import { Edge } from "edge.js"; import fs from "fs"; -import { resolve, dirname } from "path"; -import { Edge } from 'edge.js'; +import { dirname, resolve } from "path"; import { optimize as svgo } from "svgo"; -import { fileURLToPath } from 'url'; +import { fileURLToPath } from "url"; const __dirname = dirname(fileURLToPath(import.meta.url)); const __jinja_class_placeholder__ = "__jinja_class_placeholder__"; @@ -30,7 +30,6 @@ const __jinja_class_placeholder__ = "__jinja_class_placeholder__"; * @property {string} class - SVG's class name (value of XML class attribute) */ - // -- functions /** @@ -43,34 +42,30 @@ const __jinja_class_placeholder__ = "__jinja_class_placeholder__"; */ function jinja_svg_catalog(dest, macros, items) { - const svg_catalog = {}; const edge_template = resolve(__dirname, "jinja_svg_catalog.html.edge"); - items.forEach( - (item) => { - - /** @type {import("svgo").Config} */ - // JSON.stringify & JSON.parse are used to create a deep copy of the - // item.svgo_opts object - const svgo_opts = JSON.parse(JSON.stringify(item.svgo_opts)); - svgo_opts.plugins.push({ - name: "addClassesToSVGElement", - params: { - classNames: [__jinja_class_placeholder__] - }} - ); - - try { - const raw = fs.readFileSync(item.src, "utf8"); - const opt = svgo(raw, svgo_opts); - svg_catalog[item.name] = opt.data; - } catch (err) { - console.error(`ERROR: jinja_svg_catalog processing ${item.name} src: ${item.src} -- ${err}`); - throw(err); + items.forEach((item) => { + /** @type {import("svgo").Config} */ + // JSON.stringify & JSON.parse are used to create a deep copy of the + // item.svgo_opts object + const svgo_opts = JSON.parse(JSON.stringify(item.svgo_opts)); + svgo_opts.plugins.push({ + name: "addClassesToSVGElement", + params: { + classNames: [__jinja_class_placeholder__] } + }); + + try { + const raw = fs.readFileSync(item.src, "utf8"); + const opt = svgo(raw, svgo_opts); + svg_catalog[item.name] = opt.data; + } catch (err) { + console.error(`ERROR: jinja_svg_catalog processing ${item.name} src: ${item.src} -- ${err}`); + throw err; } - ); + }); fs.mkdir(dirname(dest), { recursive: true }, (err) => { if (err) throw err; @@ -82,20 +77,16 @@ function jinja_svg_catalog(dest, macros, items) { edge_template: edge_template, __jinja_class_placeholder__: __jinja_class_placeholder__, // see https://github.com/edge-js/edge/issues/162 - open_curly_brace : "{{", - close_curly_brace : "}}" + open_curly_brace: "{{", + close_curly_brace: "}}" }; - const jinjatmpl = Edge.create().renderRawSync( - fs.readFileSync(edge_template, "utf-8"), - ctx - ); + const jinjatmpl = Edge.create().renderRawSync(fs.readFileSync(edge_template, "utf-8"), ctx); fs.writeFileSync(dest, jinjatmpl); console.log(`[jinja_svg_catalog] created: ${dest}`); } - /** * Calls jinja_svg_catalog for a collection of icon sets where each set has its * own parameters. @@ -109,7 +100,6 @@ function jinja_svg_sets(dest, macros, sets) { const items = []; const all = []; for (const obj of sets) { - for (const [name, file] of Object.entries(obj.set)) { if (all.includes(name)) { throw new Error(`ERROR: ${name} has already been defined`); @@ -117,7 +107,7 @@ function jinja_svg_sets(dest, macros, sets) { items.push({ name: name, src: resolve(obj.base, file), - svgo_opts: obj.svgo_opts, + svgo_opts: obj.svgo_opts }); } jinja_svg_catalog(dest, macros, items); @@ -126,7 +116,4 @@ function jinja_svg_sets(dest, macros, sets) { // -- exports -export { - jinja_svg_sets, - jinja_svg_catalog, -}; +export { jinja_svg_sets, jinja_svg_catalog }; diff --git a/client/simple/tools/plg.js b/client/simple/tools/plg.js index 16ec268b6..6cd4d491d 100644 --- a/client/simple/tools/plg.js +++ b/client/simple/tools/plg.js @@ -8,8 +8,7 @@ * needed. */ -import { svg2png } from "./img.js"; -import { svg2svg } from "./img.js"; +import { svg2png, svg2svg } from "./img.js"; /** * Vite plugin to convert a list of SVG files to PNG. @@ -18,9 +17,11 @@ import { svg2svg } from "./img.js"; */ function plg_svg2png(items) { return { - name: 'searxng-simple-svg2png', - apply: 'build', // or 'serve' - async writeBundle() { svg2png(items); }, + name: "searxng-simple-svg2png", + apply: "build", // or 'serve' + async writeBundle() { + svg2png(items); + } }; } @@ -32,9 +33,11 @@ function plg_svg2png(items) { */ function plg_svg2svg(svgo_opts, items) { return { - name: 'searxng-simple-svg2png', - apply: 'build', // or 'serve' - async writeBundle() { svg2svg(items, svgo_opts); }, + name: "searxng-simple-svg2png", + apply: "build", // or 'serve' + async writeBundle() { + svg2svg(items, svgo_opts); + } }; } diff --git a/client/simple/vite.config.js b/client/simple/vite.config.js index 850cc6168..e5eacbd58 100644 --- a/client/simple/vite.config.js +++ b/client/simple/vite.config.js @@ -5,14 +5,11 @@ import { resolve } from "node:path"; import { defineConfig } from "vite"; import { viteStaticCopy } from "vite-plugin-static-copy"; -import { plg_svg2png } from "./tools/plg.js"; -import { plg_svg2svg } from "./tools/plg.js"; +import { plg_svg2png, plg_svg2svg } from "./tools/plg.js"; - -const ROOT = "../.."; // root of the git reposetory +const ROOT = "../.."; // root of the git reposetory const PATH = { - dist: resolve(ROOT, "searx/static/themes/simple"), // dist: resolve(ROOT, "client/simple/dist"), @@ -21,27 +18,18 @@ const PATH = { brand: "src/brand", static: resolve(ROOT, "client/simple/static"), leaflet: resolve(ROOT, "client/simple/node_modules/leaflet/dist"), - templates: resolve(ROOT, "searx/templates/simple"), + templates: resolve(ROOT, "searx/templates/simple") }; const svg2svg_opts = { - plugins: [ - { name: "preset-default" }, - "sortAttrs", - "convertStyleToAttrs", - ] + plugins: [{ name: "preset-default" }, "sortAttrs", "convertStyleToAttrs"] }; const svg2svg_favicon_opts = { - plugins: [ - { name: "preset-default" }, - "sortAttrs", - ] + plugins: [{ name: "preset-default" }, "sortAttrs"] }; - export default defineConfig({ - root: PATH.src, mode: "production", // mode: "development", @@ -62,21 +50,25 @@ export default defineConfig({ // FIXME: missing CCS sourcemaps!! sourceMap: { outputSourceFiles: true, - sourceMapURL: (name) => { const s = name.split('/'); return s[s.length - 1] + '.map'; }, - }, + sourceMapURL: (name) => { + const s = name.split("/"); + return s[s.length - 1] + ".map"; + } + } // env: 'development', // relativeUrls: true, // javascriptEnabled: true, - }, - }, - }, // end: css + } + } + }, // end: css - esbuild : { + esbuild: { // FIXME: missing CCS sourcemaps!! sourcemap: true }, build: { + target: "es2016", manifest: "manifest.json", emptyOutDir: true, assetsDir: "", @@ -92,7 +84,6 @@ export default defineConfig({ rollupOptions: { input: { - // build CSS files "css/searxng.min.css": PATH.src + "/less/style-ltr.less", "css/searxng-rtl.min.css": PATH.src + "/less/style-rtl.less", @@ -100,25 +91,22 @@ export default defineConfig({ // build JS files "js/searxng.head.min": PATH.src + "/js/searxng.head.js", - "js/searxng.min": PATH.src + "/js/searxng.js", - + "js/searxng.min": PATH.src + "/js/searxng.js" }, // file naming conventions / pathnames are relative to outDir (PATH.dist) output: { entryFileNames: "[name].js", chunkFileNames: "[name].js", - assetFileNames: "[name].[ext]", + assetFileNames: "[name].[ext]" // Vite does not support "rollupOptions.output.sourcemap". // Please use "build.sourcemap" instead. // sourcemap: true, - }, - - }, - }, // end: build + } + } + }, // end: build plugins: [ - // Leaflet viteStaticCopy({ @@ -126,7 +114,7 @@ export default defineConfig({ { src: PATH.leaflet + "/leaflet.{js,js.map}", dest: PATH.dist + "/js" }, { src: PATH.leaflet + "/images/*.png", dest: PATH.dist + "/css/images/" }, { src: PATH.leaflet + "/*.{css,css.map}", dest: PATH.dist + "/css" }, - { src: PATH.static + "/**/*", dest: PATH.dist }, + { src: PATH.static + "/**/*", dest: PATH.dist } ] }), @@ -136,43 +124,37 @@ export default defineConfig({ [ { src: PATH.src + "/svg/empty_favicon.svg", dest: PATH.dist + "/img/empty_favicon.svg" }, { src: PATH.src + "/svg/select-dark.svg", dest: PATH.dist + "/img/select-dark.svg" }, - { src: PATH.src + "/svg/select-light.svg", dest: PATH.dist + "/img/select-light.svg" }, + { src: PATH.src + "/svg/select-light.svg", dest: PATH.dist + "/img/select-light.svg" } ], - svg2svg_opts, + svg2svg_opts ), // SearXNG brand (static) - plg_svg2png( - [ - { src: PATH.brand + "/searxng-wordmark.svg", dest: PATH.dist + "/img/favicon.png" }, - { src: PATH.brand + "/searxng.svg", dest: PATH.dist + "/img/searxng.png" }, - ], - ), + plg_svg2png([ + { src: PATH.brand + "/searxng-wordmark.svg", dest: PATH.dist + "/img/favicon.png" }, + { src: PATH.brand + "/searxng.svg", dest: PATH.dist + "/img/searxng.png" } + ]), // -- svg plg_svg2svg( [ { src: PATH.brand + "/searxng.svg", dest: PATH.dist + "/img/searxng.svg" }, - { src: PATH.brand + "/img_load_error.svg", dest: PATH.dist + "/img/img_load_error.svg" }, - ], - svg2svg_opts, - ), - - // -- favicon - plg_svg2svg( - [ { src: PATH.brand + "/searxng-wordmark.svg", dest: PATH.dist + "/img/favicon.svg" } ], - svg2svg_favicon_opts, - ), - - // -- simple templates - plg_svg2svg( - [ - { src: PATH.brand + "/searxng-wordmark.svg", dest: PATH.templates + "/searxng-wordmark.min.svg" }, + { src: PATH.brand + "/img_load_error.svg", dest: PATH.dist + "/img/img_load_error.svg" } ], svg2svg_opts ), - ] // end: plugins + // -- favicon + plg_svg2svg( + [{ src: PATH.brand + "/searxng-wordmark.svg", dest: PATH.dist + "/img/favicon.svg" }], + svg2svg_favicon_opts + ), + // -- simple templates + plg_svg2svg( + [{ src: PATH.brand + "/searxng-wordmark.svg", dest: PATH.templates + "/searxng-wordmark.min.svg" }], + svg2svg_opts + ) + ] // end: plugins });