Browse Source

[mod] theme/simple: fmt/lint minor pass

*Safe* changes, no behaviour changes.

- Initial ES5 to ES2015+ conversion.
- Plenty of styling diff changes.
Ivan Gabaldon 1 week ago
parent
commit
95172213f6

+ 11 - 12
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);

+ 62 - 59
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();

+ 40 - 44
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 <hr> 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);
   }
-
 });

+ 222 - 211
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 <div class="detail"> 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);
-      }
-      if (isImageResult(resultElement)) {
-        searxng.selectImage(resultElement);
+  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);
+        }
       }
-    }
-  }, 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'
-        },
-        'ArrowRight': {
-          key: '→',
-          fun: highlightResult('down'),
-          des: 'select next search result',
-          cat: 'Results'
+    default: Object.assign(
+      {
+        /* SearXNG layout */
+        ArrowLeft: {
+          key: "←",
+          fun: highlightResult("up"),
+          des: "select previous search result",
+          cat: "Results"
         },
-      }, baseKeyBinding),
-
-    'vim': Object.assign(
-      { /* Vim-like Key Layout. */
-        'b': {
-          key: 'b',
+        ArrowRight: {
+          key: "→",
+          fun: highlightResult("down"),
+          des: "select next search result",
+          cat: "Results"
+        }
+      },
+      baseKeyBinding
+    ),
+
+    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;
-
-          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;
+          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;
+
+              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 = '<a href="#" class="close" aria-label="close" title="close">×</a>';
-    html += '<h3>How to navigate SearXNG with hotkeys</h3>';
-    html += '<table>';
+    html += "<h3>How to navigate SearXNG with hotkeys</h3>";
+    html += "<table>";
 
     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 += '<tr>';
+        html += "<tr>";
       }
-      html += '<td>';
+      html += "<td>";
 
-      html += '<h4>' + cat[0].cat + '</h4>';
+      html += "<h4>" + cat[0].cat + "</h4>";
       html += '<ul class="list-unstyled">';
 
       for (var cj in cat) {
-        html += '<li><kbd>' + cat[cj].key + '</kbd> ' + cat[cj].des + '</li>';
+        html += "<li><kbd>" + cat[cj].key + "</kbd> " + cat[cj].des + "</li>";
       }
 
-      html += '</ul>';
-      html += '</td>'; // col-sm-*
+      html += "</ul>";
+      html += "</td>"; // col-sm-*
 
       if (!first || lastCategory) {
-        html += '</tr>'; // row
+        html += "</tr>"; // row
       }
     }
 
-    html += '</table>';
+    html += "</table>";
 
     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");
 });

+ 17 - 14
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 © <a href="https://openstreetmap.org">OpenStreetMap</a> 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 © <a href="https://openstreetmap.org">OpenStreetMap contributors</a>';
-        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 © <a href="https://openstreetmap.org">OpenStreetMap contributors</a>';
+        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);

+ 14 - 15
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 = ' (<i>' + searxng.settings.translations.Source + ':&nbsp;' + description[1] + '</i>)';
+              const source = " (<i>" + searxng.settings.translations.Source + ":&nbsp;" + description[1] + "</i>)";
               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;

+ 70 - 72
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}
-        ));
-
-    if (d.querySelector('#search_url button#copy_url')) {
-      d.querySelector('#search_url button#copy_url').style.display = "block";
+  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";
     }
 
-    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 <img> 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;
 
       // <img src="" data-src="http://example.org/image.jpg">
-      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 <img> 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);

+ 45 - 47
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);

+ 37 - 34
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
   }
 ];
 

+ 29 - 41
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 };

+ 27 - 40
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 };

+ 11 - 8
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);
+    }
   };
 }
 

+ 33 - 51
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" },
+        { src: PATH.brand + "/img_load_error.svg", dest: PATH.dist + "/img/img_load_error.svg" }
       ],
-      svg2svg_opts,
+      svg2svg_opts
     ),
 
     // -- favicon
     plg_svg2svg(
-      [ { src: PATH.brand + "/searxng-wordmark.svg", dest: PATH.dist + "/img/favicon.svg" } ],
-      svg2svg_favicon_opts,
+      [{ 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 + "/searxng-wordmark.svg", dest: PATH.templates + "/searxng-wordmark.min.svg" }],
       svg2svg_opts
-    ),
-
+    )
   ] // end: plugins
-
 });