From 680d70865f763aff45a9d5fea8649c6fa1725deb Mon Sep 17 00:00:00 2001 From: Alexandre Flament Date: Fri, 5 Nov 2021 09:51:27 +0100 Subject: [mod] SearXNG: remove "searx" from the searx*.js file names. --- .../themes/simple/src/js/main/00_searx_toolkit.js | 152 --------- .../static/themes/simple/src/js/main/00_toolkit.js | 152 +++++++++ searx/static/themes/simple/src/js/main/keyboard.js | 379 +++++++++++++++++++++ .../static/themes/simple/src/js/main/mapresult.js | 74 ++++ .../themes/simple/src/js/main/preferences.js | 28 ++ searx/static/themes/simple/src/js/main/results.js | 105 ++++++ searx/static/themes/simple/src/js/main/search.js | 107 ++++++ .../themes/simple/src/js/main/searx_keyboard.js | 379 --------------------- .../themes/simple/src/js/main/searx_mapresult.js | 74 ---- .../themes/simple/src/js/main/searx_preferences.js | 28 -- .../themes/simple/src/js/main/searx_results.js | 105 ------ .../themes/simple/src/js/main/searx_search.js | 107 ------ 12 files changed, 845 insertions(+), 845 deletions(-) delete mode 100644 searx/static/themes/simple/src/js/main/00_searx_toolkit.js create mode 100644 searx/static/themes/simple/src/js/main/00_toolkit.js create mode 100644 searx/static/themes/simple/src/js/main/keyboard.js create mode 100644 searx/static/themes/simple/src/js/main/mapresult.js create mode 100644 searx/static/themes/simple/src/js/main/preferences.js create mode 100644 searx/static/themes/simple/src/js/main/results.js create mode 100644 searx/static/themes/simple/src/js/main/search.js delete mode 100644 searx/static/themes/simple/src/js/main/searx_keyboard.js delete mode 100644 searx/static/themes/simple/src/js/main/searx_mapresult.js delete mode 100644 searx/static/themes/simple/src/js/main/searx_preferences.js delete mode 100644 searx/static/themes/simple/src/js/main/searx_results.js delete mode 100644 searx/static/themes/simple/src/js/main/searx_search.js diff --git a/searx/static/themes/simple/src/js/main/00_searx_toolkit.js b/searx/static/themes/simple/src/js/main/00_searx_toolkit.js deleted file mode 100644 index 7dc50108b..000000000 --- a/searx/static/themes/simple/src/js/main/00_searx_toolkit.js +++ /dev/null @@ -1,152 +0,0 @@ -/** - * @license - * (C) Copyright Contributors to the SearXNG project. - * (C) Copyright Contributors to the searx project (2014 - 2021). - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -window.searxng = (function(w, d) { - - 'use strict'; - - // not invented here tookit 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]; - }; - })(Element.prototype); - } - - function callbackSafe(callback, el, e) { - try { - callback.call(el, e); - } catch (exception) { - console.log(exception); - } - } - - var searxng = window.searxng || {}; - - searxng.on = function(obj, eventType, callback, useCapture) { - useCapture = useCapture || false; - 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); - } - }; - - searxng.ready = function(callback) { - if (document.readyState != 'loading') { - callback.call(w); - } else { - w.addEventListener('DOMContentLoaded', callback.bind(w)); - } - }; - - searxng.http = function(method, url) { - var req = new XMLHttpRequest(), - resolve = function() {}, - reject = function() {}, - promise = { - then: function(callback) { resolve = callback; return promise; }, - catch: function(callback) { reject = callback; return promise; } - }; - - try { - req.open(method, url, true); - - // On load - req.onload = function() { - if (req.status == 200) { - resolve(req.response, req.responseType); - } else { - reject(Error(req.statusText)); - } - }; - - // Handle network errors - req.onerror = function() { - reject(Error("Network Error")); - }; - - req.onabort = function() { - reject(Error("Transaction is aborted")); - }; - - // Make the request - req.send(); - } catch (ex) { - reject(ex); - } - - return promise; - }; - - searxng.loadStyle = function(src) { - var path = searxng.static_path + src, - 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); - d.body.appendChild(s); - } - }; - - searxng.loadScript = function(src, callback) { - var path = searxng.static_path + src, - id = "script_" + src.replace('.', '_'), - s = d.getElementById(id); - if (s === null) { - s = d.createElement('script'); - s.setAttribute('id', id); - s.setAttribute('src', path); - s.onload = callback; - s.onerror = function() { - s.setAttribute('error', '1'); - }; - d.body.appendChild(s); - } else if (!s.hasAttribute('error')) { - try { - callback.apply(s, []); - } catch (exception) { - console.log(exception); - } - } else { - console.log("callback not executed : script '" + path + "' not loaded."); - } - }; - - searxng.insertBefore = function (newNode, referenceNode) { - referenceNode.parentNode.insertBefore(newNode, referenceNode); - }; - - searxng.insertAfter = function(newNode, referenceNode) { - referenceNode.parentNode.insertAfter(newNode, referenceNode.nextSibling); - }; - - searxng.on('.close', 'click', function() { - this.parentNode.classList.add('invisible'); - }); - - return searxng; -})(window, document); diff --git a/searx/static/themes/simple/src/js/main/00_toolkit.js b/searx/static/themes/simple/src/js/main/00_toolkit.js new file mode 100644 index 000000000..7dc50108b --- /dev/null +++ b/searx/static/themes/simple/src/js/main/00_toolkit.js @@ -0,0 +1,152 @@ +/** + * @license + * (C) Copyright Contributors to the SearXNG project. + * (C) Copyright Contributors to the searx project (2014 - 2021). + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +window.searxng = (function(w, d) { + + 'use strict'; + + // not invented here tookit 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]; + }; + })(Element.prototype); + } + + function callbackSafe(callback, el, e) { + try { + callback.call(el, e); + } catch (exception) { + console.log(exception); + } + } + + var searxng = window.searxng || {}; + + searxng.on = function(obj, eventType, callback, useCapture) { + useCapture = useCapture || false; + 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); + } + }; + + searxng.ready = function(callback) { + if (document.readyState != 'loading') { + callback.call(w); + } else { + w.addEventListener('DOMContentLoaded', callback.bind(w)); + } + }; + + searxng.http = function(method, url) { + var req = new XMLHttpRequest(), + resolve = function() {}, + reject = function() {}, + promise = { + then: function(callback) { resolve = callback; return promise; }, + catch: function(callback) { reject = callback; return promise; } + }; + + try { + req.open(method, url, true); + + // On load + req.onload = function() { + if (req.status == 200) { + resolve(req.response, req.responseType); + } else { + reject(Error(req.statusText)); + } + }; + + // Handle network errors + req.onerror = function() { + reject(Error("Network Error")); + }; + + req.onabort = function() { + reject(Error("Transaction is aborted")); + }; + + // Make the request + req.send(); + } catch (ex) { + reject(ex); + } + + return promise; + }; + + searxng.loadStyle = function(src) { + var path = searxng.static_path + src, + 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); + d.body.appendChild(s); + } + }; + + searxng.loadScript = function(src, callback) { + var path = searxng.static_path + src, + id = "script_" + src.replace('.', '_'), + s = d.getElementById(id); + if (s === null) { + s = d.createElement('script'); + s.setAttribute('id', id); + s.setAttribute('src', path); + s.onload = callback; + s.onerror = function() { + s.setAttribute('error', '1'); + }; + d.body.appendChild(s); + } else if (!s.hasAttribute('error')) { + try { + callback.apply(s, []); + } catch (exception) { + console.log(exception); + } + } else { + console.log("callback not executed : script '" + path + "' not loaded."); + } + }; + + searxng.insertBefore = function (newNode, referenceNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode); + }; + + searxng.insertAfter = function(newNode, referenceNode) { + referenceNode.parentNode.insertAfter(newNode, referenceNode.nextSibling); + }; + + searxng.on('.close', 'click', function() { + this.parentNode.classList.add('invisible'); + }); + + return searxng; +})(window, document); diff --git a/searx/static/themes/simple/src/js/main/keyboard.js b/searx/static/themes/simple/src/js/main/keyboard.js new file mode 100644 index 000000000..394f97730 --- /dev/null +++ b/searx/static/themes/simple/src/js/main/keyboard.js @@ -0,0 +1,379 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +/*global searxng*/ + +searxng.ready(function() { + + searxng.on('.result', 'click', function() { + highlightResult(this)(true); + }); + + searxng.on('.result a', 'focus', function(e) { + var el = e.target; + while (el !== undefined) { + if (el.classList.contains('result')) { + if (el.getAttribute("data-vim-selected") === null) { + highlightResult(el)(true); + } + break; + } + el = el.parentNode; + } + }, true); + + var vimKeys = { + 27: { + key: 'Escape', + fun: removeFocus, + des: 'remove focus from the focused input', + cat: 'Control' + }, + 73: { + key: 'i', + fun: searchInputFocus, + des: 'focus on the search input', + cat: 'Control' + }, + 66: { + key: 'b', + fun: scrollPage(-window.innerHeight), + des: 'scroll one page up', + cat: 'Navigation' + }, + 70: { + key: 'f', + fun: scrollPage(window.innerHeight), + des: 'scroll one page down', + cat: 'Navigation' + }, + 85: { + key: 'u', + fun: scrollPage(-window.innerHeight / 2), + des: 'scroll half a page up', + cat: 'Navigation' + }, + 68: { + key: 'd', + fun: scrollPage(window.innerHeight / 2), + des: 'scroll half a page down', + cat: 'Navigation' + }, + 71: { + key: 'g', + fun: scrollPageTo(-document.body.scrollHeight, 'top'), + des: 'scroll to the top of the page', + cat: 'Navigation' + }, + 86: { + key: 'v', + fun: scrollPageTo(document.body.scrollHeight, 'bottom'), + des: 'scroll to the bottom of the page', + cat: 'Navigation' + }, + 75: { + key: 'k', + fun: highlightResult('up'), + des: 'select previous search result', + cat: 'Results' + }, + 74: { + key: 'j', + fun: highlightResult('down'), + des: 'select next search result', + cat: 'Results' + }, + 80: { + key: 'p', + fun: GoToPreviousPage(), + des: 'go to previous page', + cat: 'Results' + }, + 78: { + key: 'n', + fun: GoToNextPage(), + des: 'go to next page', + cat: 'Results' + }, + 79: { + key: 'o', + fun: openResult(false), + des: 'open search result', + cat: 'Results' + }, + 84: { + key: 't', + fun: openResult(true), + des: 'open the result in a new tab', + cat: 'Results' + }, + 82: { + key: 'r', + fun: reloadPage, + des: 'reload page from the server', + cat: 'Control' + }, + 72: { + key: 'h', + fun: toggleHelp, + des: 'toggle help window', + cat: 'Other' + } + }; + + searxng.on(document, "keydown", function(e) { + // check for modifiers so we don't break browser's hotkeys + if (Object.prototype.hasOwnProperty.call(vimKeys, e.keyCode) && !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) { + var tagName = e.target.tagName.toLowerCase(); + if (e.keyCode === 27) { + vimKeys[e.keyCode].fun(e); + } else { + if (e.target === document.body || tagName === 'a' || tagName === 'button') { + e.preventDefault(); + vimKeys[e.keyCode].fun(); + } + } + } + }); + + function highlightResult(which) { + return function(noScroll) { + var current = document.querySelector('.result[data-vim-selected]'), + effectiveWhich = which; + if (current === null) { + // no selection : choose the first one + current = document.querySelector('.result'); + if (current === null) { + // no first one : there are no results + return; + } + // replace up/down actions by selecting first one + if (which === "down" || which === "up") { + effectiveWhich = current; + } + } + + var next, results = document.querySelectorAll('.result'); + + 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; + } + } + break; + case 'down': + next = current.nextElementSibling; + if (next === null) { + next = results[0]; + } + break; + case 'up': + next = current.previousElementSibling; + if (next === null) { + next = results[results.length - 1]; + } + break; + case 'bottom': + next = results[results.length - 1]; + break; + case 'top': + /* falls through */ + default: + next = results[0]; + } + } + + if (next) { + current.removeAttribute('data-vim-selected'); + next.setAttribute('data-vim-selected', 'true'); + var link = next.querySelector('h3 a') || next.querySelector('a'); + if (link !== null) { + link.focus(); + } + if (!noScroll) { + scrollPageToSelected(); + } + } + }; + } + + function reloadPage() { + document.location.reload(true); + } + + function removeFocus(e) { + const tagName = e.target.tagName.toLowerCase(); + if (document.activeElement && (tagName === 'input' || tagName === 'select' || tagName === 'textarea')) { + document.activeElement.blur(); + } else { + searxng.closeDetail(); + } + } + + function pageButtonClick(css_selector) { + return function() { + var button = document.querySelector(css_selector); + if (button) { + button.click(); + } + }; + } + + function GoToNextPage() { + return pageButtonClick('nav#pagination .next_page button[type="submit"]'); + } + + function GoToPreviousPage() { + return pageButtonClick('nav#pagination .previous_page button[type="submit"]'); + } + + function scrollPageToSelected() { + var sel = document.querySelector('.result[data-vim-selected]'); + if (sel === null) { + return; + } + var wtop = document.documentElement.scrollTop || document.body.scrollTop, + wheight = document.documentElement.clientHeight, + etop = sel.offsetTop, + ebot = etop + sel.clientHeight, + offset = 120; + // first element ? + 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)) { + window.scroll(window.scrollX, etop - offset); + } else { + var wbot = wtop + wheight; + if (wbot < (ebot + offset)) { + window.scroll(window.scrollX, ebot - wheight + offset); + } + } + } + + function scrollPage(amount) { + return function() { + window.scrollBy(0, amount); + highlightResult('visible')(); + }; + } + + function scrollPageTo(position, nav) { + return function() { + window.scrollTo(0, position); + highlightResult(nav)(); + }; + } + + function searchInputFocus() { + window.scrollTo(0, 0); + document.querySelector('#q').focus(); + } + + function openResult(newTab) { + return function() { + var link = document.querySelector('.result[data-vim-selected] h3 a'); + if (link === null) { + link = document.querySelector('.result[data-vim-selected] > a'); + } + if (link !== null) { + var url = link.getAttribute('href'); + if (newTab) { + window.open(url); + } else { + window.location.href = url; + } + } + }; + } + + function initHelpContent(divElement) { + var categories = {}; + + for (var k in vimKeys) { + var key = vimKeys[k]; + categories[key.cat] = categories[key.cat] || []; + categories[key.cat].push(key); + } + + var sorted = Object.keys(categories).sort(function(a, b) { + return categories[b].length - categories[a].length; + }); + + if (sorted.length === 0) { + return; + } + + var html = '×'; + html += '

How to navigate searx with Vim-like hotkeys

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

' + cat[0].cat + '

'; + html += '
    '; + + for (var cj in cat) { + html += '
  • ' + cat[cj].key + ' ' + cat[cj].des + '
  • '; + } + + html += '
'; + html += '
'; + + divElement.innerHTML = html; + } + + function toggleHelp() { + var helpPanel = document.querySelector('#vim-hotkeys-help'); + console.log(helpPanel); + if (helpPanel === undefined || helpPanel === null) { + // first call + helpPanel = document.createElement('div'); + helpPanel.id = 'vim-hotkeys-help'; + helpPanel.className='dialog-modal'; + helpPanel.style='width: 40%'; + initHelpContent(helpPanel); + initHelpContent(helpPanel); + initHelpContent(helpPanel); + var body = document.getElementsByTagName('body')[0]; + body.appendChild(helpPanel); + } else { + // togggle hidden + helpPanel.classList.toggle('invisible'); + return; + } + } + + searxng.scrollPageToSelected = scrollPageToSelected; + searxng.selectNext = highlightResult('down'); + searxng.selectPrevious = highlightResult('up'); +}); diff --git a/searx/static/themes/simple/src/js/main/mapresult.js b/searx/static/themes/simple/src/js/main/mapresult.js new file mode 100644 index 000000000..75d13b515 --- /dev/null +++ b/searx/static/themes/simple/src/js/main/mapresult.js @@ -0,0 +1,74 @@ +/* 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) { + // no more request + this.classList.remove("searxng_init_map"); + + // + var leaflet_target = this.dataset.leafletTarget; + var map_lon = parseFloat(this.dataset.mapLon); + var map_lat = parseFloat(this.dataset.mapLat); + var map_zoom = parseFloat(this.dataset.mapZoom); + 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() { + var map_bounds = null; + if(map_boundingbox) { + var southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]); + var northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]); + map_bounds = L.latLngBounds(southWest, northEast); + } + + // 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 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}); + // init map view + if(map_bounds) { + // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021 + // Still useful ? + setTimeout(function () { + map.fitBounds(map_bounds, { + maxZoom:17 + }); + }, 0); + } else if (map_lon && map_lat) { + if(map_zoom) { + map.setView(new L.latLng(map_lat, map_lon),map_zoom); + } else { + map.setView(new L.latLng(map_lat, map_lon),8); + } + } + + map.addLayer(osmMapnik); + + var baseLayers = { + "OSM Mapnik": osmMapnik, + "OSM Wikimedia": osmWikimedia, + }; + + L.control.layers(baseLayers).addTo(map); + + if(map_geojson) { + L.geoJson(map_geojson).addTo(map); + } /*else if(map_bounds) { + L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map); + }*/ + }); + + // this event occour only once per element + event.preventDefault(); + }); + }); +})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/preferences.js b/searx/static/themes/simple/src/js/main/preferences.js new file mode 100644 index 000000000..b19026a43 --- /dev/null +++ b/searx/static/themes/simple/src/js/main/preferences.js @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +(function (w, d, searxng) { + 'use strict'; + + searxng.ready(function() { + let engine_descriptions = null; + function load_engine_descriptions() { + if (engine_descriptions == null) { + searxng.http("GET", "engine_descriptions.json").then(function(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'); + for(const element of elements) { + let source = ' (' + searxng.translations['Source'] + ': ' + description[1] + ')'; + element.innerHTML = description[0] + source; + } + } + }); + } + } + + if (d.querySelector('body[class="preferences_endpoint"]')) { + for(const el of d.querySelectorAll('[data-engine-name]')) { + searxng.on(el, 'mouseenter', load_engine_descriptions); + } + } + }); +})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/results.js b/searx/static/themes/simple/src/js/main/results.js new file mode 100644 index 000000000..5ccbb38b5 --- /dev/null +++ b/searx/static/themes/simple/src/js/main/results.js @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +(function(w, d, searxng) { + 'use strict'; + + searxng.ready(function() { + searxng.image_thumbnail_layout = new searxng.ImageLayout('#urls', '#urls .result-images', 'img.image_thumbnail', 14, 6, 200); + searxng.image_thumbnail_layout.watch(); + + 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')) { + html = html.replace(btnLabelCollapsed, btnLabelNotCollapsed); + } else { + html = html.replace(btnLabelNotCollapsed, btnLabelCollapsed); + } + this.innerHTML = html; + 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'); + if (srctest === null || srctest === undefined || srctest === false) { + iframe_load.setAttribute('src', iframe_load.getAttribute('data-src')); + } + }); + + function selectImage(e) { + /*eslint no-unused-vars: 0*/ + let t = e.target; + while (t && t.nodeName != 'ARTICLE') { + t = t.parentNode; + } + if (t) { + // load full size image in background + const imgElement = t.querySelector('.result-images-source img'); + const thumbnailElement = t.querySelector('.image_thumbnail'); + const detailElement = t.querySelector('.detail'); + if (imgElement) { + const imgSrc = imgElement.getAttribute('data-src'); + if (imgSrc) { + const loader = d.createElement('div'); + const imgLoader = new Image(); + + loader.classList.add('loader'); + detailElement.appendChild(loader); + + imgLoader.onload = e => { + imgElement.src = imgSrc; + loader.remove(); + }; + imgLoader.onerror = e => { + loader.remove(); + }; + imgLoader.src = imgSrc; + imgElement.src = thumbnailElement.src; + imgElement.removeAttribute('data-src'); + } + } + } + d.getElementById('results').classList.add('image-detail-open'); + searxng.image_thumbnail_layout.align(); + searxng.scrollPageToSelected(); + } + + searxng.closeDetail = function(e) { + d.getElementById('results').classList.remove('image-detail-open'); + searxng.image_thumbnail_layout.align(); + searxng.scrollPageToSelected(); + } + + searxng.on('.result-images', 'click', e => { + e.preventDefault(); + selectImage(e); + }); + searxng.on('.result-images a', 'focus', selectImage, true); + searxng.on('.result-detail-close', 'click', e => { + e.preventDefault(); + searxng.closeDetail(); + }); + searxng.on('.result-detail-previous', 'click', e => searxng.selectPrevious(false)); + searxng.on('.result-detail-next', 'click', e => searxng.selectNext(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'); + } + } + }, true); + + }); + +})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/search.js b/searx/static/themes/simple/src/js/main/search.js new file mode 100644 index 000000000..d3149340a --- /dev/null +++ b/searx/static/themes/simple/src/js/main/search.js @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +/* global AutoComplete */ +(function(w, d, searxng) { + 'use strict'; + + var firstFocus = true, qinput_id = "q", qinput; + + function placeCursorAtEnd(element) { + if (element.setSelectionRange) { + var len = element.value.length; + element.setSelectionRange(len, len); + } + } + + 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() { + if (qinput.value.length === 0) { + cs.classList.add("empty"); + } else { + cs.classList.remove("empty"); + } + }; + + // update status, event listener + updateClearButton(); + cs.addEventListener('click', function() { + qinput.value=''; + qinput.focus(); + updateClearButton(); + }); + qinput.addEventListener('keyup', updateClearButton, false); + } + + searxng.ready(function() { + qinput = d.getElementById(qinput_id); + + function placeCursorAtEndOnce() { + if (firstFocus) { + placeCursorAtEnd(qinput); + firstFocus = false; + } else { + // e.preventDefault(); + } + } + + if (qinput !== null) { + // clear button + createClearButton(qinput); + + // autocompleter + if (searxng.autocompleter) { + searxng.autocomplete = AutoComplete.call(w, { + Url: "./autocompleter", + EmptyMessage: searxng.translations.no_item_found, + HttpMethod: searxng.method, + HttpHeaders: { + "Content-type": "application/x-www-form-urlencoded", + "X-Requested-With": "XMLHttpRequest" + }, + MinChars: 4, + Delay: 300, + }, "#" + qinput_id); + + // hack, see : https://github.com/autocompletejs/autocomplete.js/issues/37 + w.addEventListener('resize', function() { + var event = new CustomEvent("position"); + qinput.dispatchEvent(event); + }); + } + + qinput.addEventListener('focus', placeCursorAtEndOnce, false); + qinput.focus(); + } + + // vanilla js version of search_on_category_select.js + if (qinput !== null && d.querySelector('.help') != null && searxng.search_on_category_select) { + d.querySelector('.help').className='invisible'; + + searxng.on('#categories input', 'change', function() { + var i, categories = d.querySelectorAll('#categories input[type="checkbox"]'); + for(i=0; i top)) { - break; - } - } - break; - case 'down': - next = current.nextElementSibling; - if (next === null) { - next = results[0]; - } - break; - case 'up': - next = current.previousElementSibling; - if (next === null) { - next = results[results.length - 1]; - } - break; - case 'bottom': - next = results[results.length - 1]; - break; - case 'top': - /* falls through */ - default: - next = results[0]; - } - } - - if (next) { - current.removeAttribute('data-vim-selected'); - next.setAttribute('data-vim-selected', 'true'); - var link = next.querySelector('h3 a') || next.querySelector('a'); - if (link !== null) { - link.focus(); - } - if (!noScroll) { - scrollPageToSelected(); - } - } - }; - } - - function reloadPage() { - document.location.reload(true); - } - - function removeFocus(e) { - const tagName = e.target.tagName.toLowerCase(); - if (document.activeElement && (tagName === 'input' || tagName === 'select' || tagName === 'textarea')) { - document.activeElement.blur(); - } else { - searxng.closeDetail(); - } - } - - function pageButtonClick(css_selector) { - return function() { - var button = document.querySelector(css_selector); - if (button) { - button.click(); - } - }; - } - - function GoToNextPage() { - return pageButtonClick('nav#pagination .next_page button[type="submit"]'); - } - - function GoToPreviousPage() { - return pageButtonClick('nav#pagination .previous_page button[type="submit"]'); - } - - function scrollPageToSelected() { - var sel = document.querySelector('.result[data-vim-selected]'); - if (sel === null) { - return; - } - var wtop = document.documentElement.scrollTop || document.body.scrollTop, - wheight = document.documentElement.clientHeight, - etop = sel.offsetTop, - ebot = etop + sel.clientHeight, - offset = 120; - // first element ? - 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)) { - window.scroll(window.scrollX, etop - offset); - } else { - var wbot = wtop + wheight; - if (wbot < (ebot + offset)) { - window.scroll(window.scrollX, ebot - wheight + offset); - } - } - } - - function scrollPage(amount) { - return function() { - window.scrollBy(0, amount); - highlightResult('visible')(); - }; - } - - function scrollPageTo(position, nav) { - return function() { - window.scrollTo(0, position); - highlightResult(nav)(); - }; - } - - function searchInputFocus() { - window.scrollTo(0, 0); - document.querySelector('#q').focus(); - } - - function openResult(newTab) { - return function() { - var link = document.querySelector('.result[data-vim-selected] h3 a'); - if (link === null) { - link = document.querySelector('.result[data-vim-selected] > a'); - } - if (link !== null) { - var url = link.getAttribute('href'); - if (newTab) { - window.open(url); - } else { - window.location.href = url; - } - } - }; - } - - function initHelpContent(divElement) { - var categories = {}; - - for (var k in vimKeys) { - var key = vimKeys[k]; - categories[key.cat] = categories[key.cat] || []; - categories[key.cat].push(key); - } - - var sorted = Object.keys(categories).sort(function(a, b) { - return categories[b].length - categories[a].length; - }); - - if (sorted.length === 0) { - return; - } - - var html = '×'; - html += '

How to navigate searx with Vim-like hotkeys

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

' + cat[0].cat + '

'; - html += '
    '; - - for (var cj in cat) { - html += '
  • ' + cat[cj].key + ' ' + cat[cj].des + '
  • '; - } - - html += '
'; - html += '
'; - - divElement.innerHTML = html; - } - - function toggleHelp() { - var helpPanel = document.querySelector('#vim-hotkeys-help'); - console.log(helpPanel); - if (helpPanel === undefined || helpPanel === null) { - // first call - helpPanel = document.createElement('div'); - helpPanel.id = 'vim-hotkeys-help'; - helpPanel.className='dialog-modal'; - helpPanel.style='width: 40%'; - initHelpContent(helpPanel); - initHelpContent(helpPanel); - initHelpContent(helpPanel); - var body = document.getElementsByTagName('body')[0]; - body.appendChild(helpPanel); - } else { - // togggle hidden - helpPanel.classList.toggle('invisible'); - return; - } - } - - searxng.scrollPageToSelected = scrollPageToSelected; - searxng.selectNext = highlightResult('down'); - searxng.selectPrevious = highlightResult('up'); -}); diff --git a/searx/static/themes/simple/src/js/main/searx_mapresult.js b/searx/static/themes/simple/src/js/main/searx_mapresult.js deleted file mode 100644 index 75d13b515..000000000 --- a/searx/static/themes/simple/src/js/main/searx_mapresult.js +++ /dev/null @@ -1,74 +0,0 @@ -/* 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) { - // no more request - this.classList.remove("searxng_init_map"); - - // - var leaflet_target = this.dataset.leafletTarget; - var map_lon = parseFloat(this.dataset.mapLon); - var map_lat = parseFloat(this.dataset.mapLat); - var map_zoom = parseFloat(this.dataset.mapZoom); - 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() { - var map_bounds = null; - if(map_boundingbox) { - var southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]); - var northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]); - map_bounds = L.latLngBounds(southWest, northEast); - } - - // 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 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}); - // init map view - if(map_bounds) { - // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021 - // Still useful ? - setTimeout(function () { - map.fitBounds(map_bounds, { - maxZoom:17 - }); - }, 0); - } else if (map_lon && map_lat) { - if(map_zoom) { - map.setView(new L.latLng(map_lat, map_lon),map_zoom); - } else { - map.setView(new L.latLng(map_lat, map_lon),8); - } - } - - map.addLayer(osmMapnik); - - var baseLayers = { - "OSM Mapnik": osmMapnik, - "OSM Wikimedia": osmWikimedia, - }; - - L.control.layers(baseLayers).addTo(map); - - if(map_geojson) { - L.geoJson(map_geojson).addTo(map); - } /*else if(map_bounds) { - L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map); - }*/ - }); - - // this event occour only once per element - event.preventDefault(); - }); - }); -})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/searx_preferences.js b/searx/static/themes/simple/src/js/main/searx_preferences.js deleted file mode 100644 index b19026a43..000000000 --- a/searx/static/themes/simple/src/js/main/searx_preferences.js +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -(function (w, d, searxng) { - 'use strict'; - - searxng.ready(function() { - let engine_descriptions = null; - function load_engine_descriptions() { - if (engine_descriptions == null) { - searxng.http("GET", "engine_descriptions.json").then(function(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'); - for(const element of elements) { - let source = ' (' + searxng.translations['Source'] + ': ' + description[1] + ')'; - element.innerHTML = description[0] + source; - } - } - }); - } - } - - if (d.querySelector('body[class="preferences_endpoint"]')) { - for(const el of d.querySelectorAll('[data-engine-name]')) { - searxng.on(el, 'mouseenter', load_engine_descriptions); - } - } - }); -})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/searx_results.js b/searx/static/themes/simple/src/js/main/searx_results.js deleted file mode 100644 index 5ccbb38b5..000000000 --- a/searx/static/themes/simple/src/js/main/searx_results.js +++ /dev/null @@ -1,105 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -(function(w, d, searxng) { - 'use strict'; - - searxng.ready(function() { - searxng.image_thumbnail_layout = new searxng.ImageLayout('#urls', '#urls .result-images', 'img.image_thumbnail', 14, 6, 200); - searxng.image_thumbnail_layout.watch(); - - 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')) { - html = html.replace(btnLabelCollapsed, btnLabelNotCollapsed); - } else { - html = html.replace(btnLabelNotCollapsed, btnLabelCollapsed); - } - this.innerHTML = html; - 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'); - if (srctest === null || srctest === undefined || srctest === false) { - iframe_load.setAttribute('src', iframe_load.getAttribute('data-src')); - } - }); - - function selectImage(e) { - /*eslint no-unused-vars: 0*/ - let t = e.target; - while (t && t.nodeName != 'ARTICLE') { - t = t.parentNode; - } - if (t) { - // load full size image in background - const imgElement = t.querySelector('.result-images-source img'); - const thumbnailElement = t.querySelector('.image_thumbnail'); - const detailElement = t.querySelector('.detail'); - if (imgElement) { - const imgSrc = imgElement.getAttribute('data-src'); - if (imgSrc) { - const loader = d.createElement('div'); - const imgLoader = new Image(); - - loader.classList.add('loader'); - detailElement.appendChild(loader); - - imgLoader.onload = e => { - imgElement.src = imgSrc; - loader.remove(); - }; - imgLoader.onerror = e => { - loader.remove(); - }; - imgLoader.src = imgSrc; - imgElement.src = thumbnailElement.src; - imgElement.removeAttribute('data-src'); - } - } - } - d.getElementById('results').classList.add('image-detail-open'); - searxng.image_thumbnail_layout.align(); - searxng.scrollPageToSelected(); - } - - searxng.closeDetail = function(e) { - d.getElementById('results').classList.remove('image-detail-open'); - searxng.image_thumbnail_layout.align(); - searxng.scrollPageToSelected(); - } - - searxng.on('.result-images', 'click', e => { - e.preventDefault(); - selectImage(e); - }); - searxng.on('.result-images a', 'focus', selectImage, true); - searxng.on('.result-detail-close', 'click', e => { - e.preventDefault(); - searxng.closeDetail(); - }); - searxng.on('.result-detail-previous', 'click', e => searxng.selectPrevious(false)); - searxng.on('.result-detail-next', 'click', e => searxng.selectNext(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'); - } - } - }, true); - - }); - -})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/searx_search.js b/searx/static/themes/simple/src/js/main/searx_search.js deleted file mode 100644 index d3149340a..000000000 --- a/searx/static/themes/simple/src/js/main/searx_search.js +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -/* global AutoComplete */ -(function(w, d, searxng) { - 'use strict'; - - var firstFocus = true, qinput_id = "q", qinput; - - function placeCursorAtEnd(element) { - if (element.setSelectionRange) { - var len = element.value.length; - element.setSelectionRange(len, len); - } - } - - 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() { - if (qinput.value.length === 0) { - cs.classList.add("empty"); - } else { - cs.classList.remove("empty"); - } - }; - - // update status, event listener - updateClearButton(); - cs.addEventListener('click', function() { - qinput.value=''; - qinput.focus(); - updateClearButton(); - }); - qinput.addEventListener('keyup', updateClearButton, false); - } - - searxng.ready(function() { - qinput = d.getElementById(qinput_id); - - function placeCursorAtEndOnce() { - if (firstFocus) { - placeCursorAtEnd(qinput); - firstFocus = false; - } else { - // e.preventDefault(); - } - } - - if (qinput !== null) { - // clear button - createClearButton(qinput); - - // autocompleter - if (searxng.autocompleter) { - searxng.autocomplete = AutoComplete.call(w, { - Url: "./autocompleter", - EmptyMessage: searxng.translations.no_item_found, - HttpMethod: searxng.method, - HttpHeaders: { - "Content-type": "application/x-www-form-urlencoded", - "X-Requested-With": "XMLHttpRequest" - }, - MinChars: 4, - Delay: 300, - }, "#" + qinput_id); - - // hack, see : https://github.com/autocompletejs/autocomplete.js/issues/37 - w.addEventListener('resize', function() { - var event = new CustomEvent("position"); - qinput.dispatchEvent(event); - }); - } - - qinput.addEventListener('focus', placeCursorAtEndOnce, false); - qinput.focus(); - } - - // vanilla js version of search_on_category_select.js - if (qinput !== null && d.querySelector('.help') != null && searxng.search_on_category_select) { - d.querySelector('.help').className='invisible'; - - searxng.on('#categories input', 'change', function() { - var i, categories = d.querySelectorAll('#categories input[type="checkbox"]'); - for(i=0; i