Browse Source

[feat] search on category select without JS

Co-authored-by: Alexandre Flament <alex@al-f.net>
Bnyro 1 year ago
parent
commit
a55e0ac553

+ 4 - 0
docs/admin/settings/settings_ui.rst

@@ -19,6 +19,7 @@
      default_theme: simple
      default_theme: simple
      theme_args:
      theme_args:
        simple_style: auto
        simple_style: auto
+     search_on_category_select: true
 
 
 .. _static_use_hash:
 .. _static_use_hash:
 
 
@@ -60,3 +61,6 @@
 
 
 ``results_on_new_tab``:
 ``results_on_new_tab``:
   Open result links in a new tab by default.
   Open result links in a new tab by default.
+
+``search_on_category_select``:
+  Perform search immediately if a category selected. Disable to select multiple categories.

+ 4 - 6
docs/dev/search_api.rst

@@ -92,16 +92,14 @@ Parameters
   List of enabled plugins.
   List of enabled plugins.
 
 
   :default:
   :default:
-     ``Hash_plugin``, ``Search_on_category_select``,
-     ``Self_Information``, ``Tracker_URL_remover``,
-     ``Ahmia_blacklist``
+     ``Hash_plugin``, ``Self_Information``,
+     ``Tracker_URL_remover``, ``Ahmia_blacklist``
 
 
   :values:
   :values:
      .. enabled by default
      .. enabled by default
 
 
-     ``Hash_plugin``, ``Search_on_category_select``,
-     ``Self_Information``, ``Tracker_URL_remover``,
-     ``Ahmia_blacklist``,
+     ``Hash_plugin``, ``Self_Information``,
+     ``Tracker_URL_remover``, ``Ahmia_blacklist``,
 
 
      .. disabled by default
      .. disabled by default
 
 

+ 0 - 24
searx/plugins/search_on_category_select.py

@@ -1,24 +0,0 @@
-'''
-searx is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-searx is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with searx. If not, see < http://www.gnu.org/licenses/ >.
-
-(C) 2015 by Adam Tauber, <asciimoo@gmail.com>
-'''
-from flask_babel import gettext
-
-name = gettext('Search on category select')
-description = gettext(
-    'Perform search immediately if a category selected. Disable to select multiple categories. (JavaScript required)'
-)
-default_on = True
-preference_section = 'ui'

+ 4 - 0
searx/preferences.py

@@ -461,6 +461,10 @@ class Preferences:
                 settings['ui']['infinite_scroll'],
                 settings['ui']['infinite_scroll'],
                 locked=is_locked('infinite_scroll')
                 locked=is_locked('infinite_scroll')
             ),
             ),
+            'search_on_category_select': BooleanSetting(
+                settings['ui']['search_on_category_select'],
+                locked=is_locked('search_on_category_select')
+            ),
             # fmt: on
             # fmt: on
         }
         }
 
 

+ 3 - 0
searx/settings.yml

@@ -123,6 +123,9 @@ ui:
   theme_args:
   theme_args:
     # style of simple theme: auto, light, dark
     # style of simple theme: auto, light, dark
     simple_style: auto
     simple_style: auto
+  # Perform search immediately if a category selected.
+  # Disable to select multiple categories at once and start the search manually.
+  search_on_category_select: true
 
 
 # Lock arbitrary settings on the preferences page.  To find the ID of the user
 # Lock arbitrary settings on the preferences page.  To find the ID of the user
 # setting you want to lock, check the ID of the form on the page "preferences".
 # setting you want to lock, check the ID of the form on the page "preferences".

+ 1 - 0
searx/settings_defaults.py

@@ -199,6 +199,7 @@ SCHEMA = {
         'query_in_title': SettingsValue(bool, False),
         'query_in_title': SettingsValue(bool, False),
         'infinite_scroll': SettingsValue(bool, False),
         'infinite_scroll': SettingsValue(bool, False),
         'cache_url': SettingsValue(str, 'https://web.archive.org/web/'),
         'cache_url': SettingsValue(str, 'https://web.archive.org/web/'),
+        'search_on_category_select': SettingsValue(bool, True),
     },
     },
     'preferences': {
     'preferences': {
         'lock': SettingsValue(list, []),
         'lock': SettingsValue(list, []),

+ 16 - 17
searx/static/themes/simple/src/js/main/search.js

@@ -151,28 +151,27 @@
     }
     }
 
 
     // vanilla js version of search_on_category_select.js
     // vanilla js version of search_on_category_select.js
-    if (qinput !== null && d.querySelector('.help') != null && searxng.settings.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 < categories.length; i++) {
-          if (categories[i] !== this && categories[i].checked) {
-            categories[i].click();
-          }
-        }
-        if (! this.checked) {
-          this.click();
-        }
-        submitIfQuery();
-        return false;
-      });
-
+    if (qinput !== null && searxng.settings.search_on_category_select) {
       searxng.on(d.getElementById('safesearch'), 'change', submitIfQuery);
       searxng.on(d.getElementById('safesearch'), 'change', submitIfQuery);
       searxng.on(d.getElementById('time_range'), 'change', submitIfQuery);
       searxng.on(d.getElementById('time_range'), 'change', submitIfQuery);
       searxng.on(d.getElementById('language'), 'change', submitIfQuery);
       searxng.on(d.getElementById('language'), 'change', submitIfQuery);
     }
     }
 
 
+    // most common browsers at the time of writing this support :has, except for Firefox
+    // can be removed when Firefox / Firefox ESL starts supporting it as well
+    try {
+      // this fails when the browser does not support :has
+      d.querySelector("html:has(body)");
+    } catch (_) {
+      // manually deselect the old selection when a new category is selected
+      for (let button of d.querySelectorAll("button.category_button")) {
+        searxng.on(button, 'click', () => {
+          const selected = d.querySelector("button.category_button.selected");
+          console.log(selected);
+          selected.classList.remove("selected");
+        })
+      }
+    }
   });
   });
 
 
 })(window, document, window.searxng);
 })(window, document, window.searxng);

+ 45 - 11
searx/static/themes/simple/src/less/search.less

@@ -23,12 +23,15 @@
     "spacer categories";
     "spacer categories";
 }
 }
 
 
-.category {
+.category_checkbox,
+.category_button {
   display: inline-block;
   display: inline-block;
   position: relative;
   position: relative;
   .ltr-margin-right(1rem);
   .ltr-margin-right(1rem);
   padding: 0;
   padding: 0;
+}
 
 
+.category_checkbox {
   input {
   input {
     display: none;
     display: none;
   }
   }
@@ -57,6 +60,35 @@
   }
   }
 }
 }
 
 
+button.category_button {
+  background-color: inherit;
+  color: var(--color-base-font);
+  cursor: pointer;
+  padding: 0.2rem 0;
+  display: inline-flex;
+  align-items: center;
+  text-transform: capitalize;
+  font-size: 0.9em;
+  border: none;
+  border-bottom: 2px solid transparent;
+
+  svg {
+    padding-right: 0.2rem;
+  }
+
+  &.selected,
+  &:active,
+  &:focus-within {
+    color: var(--color-categories-item-selected-font);
+    border-bottom: 2px solid var(--color-categories-item-border-selected);
+  }
+}
+
+#categories_container:has(button.category_button:focus-within) button.category_button.selected {
+  color: var(--color-base-font);
+  border-bottom: none;
+}
+
 #search_logo {
 #search_logo {
   grid-area: logo;
   grid-area: logo;
   display: flex;
   display: flex;
@@ -205,11 +237,6 @@ html.no-js #clear_search.hide_if_nojs {
   #categories {
   #categories {
     font-size: 90%;
     font-size: 90%;
     clear: both;
     clear: both;
-
-    .checkbox_container {
-      margin: auto;
-      margin-top: 2px;
-    }
   }
   }
 }
 }
 
 
@@ -219,7 +246,7 @@ html.no-js #clear_search.hide_if_nojs {
     #categories_container {
     #categories_container {
       width: max-content;
       width: max-content;
 
 
-      .category {
+      .category_checkbox {
         display: inline-block;
         display: inline-block;
         width: auto;
         width: auto;
       }
       }
@@ -271,16 +298,23 @@ html.no-js #clear_search.hide_if_nojs {
     width: auto;
     width: auto;
     margin: 0;
     margin: 0;
 
 
+    svg {
+      display: none;
+    }
+  }
+
+  .category_checkbox {
     label {
     label {
       padding: 1rem !important;
       padding: 1rem !important;
       margin: 0 !important;
       margin: 0 !important;
-
-      svg {
-        display: none;
-      }
     }
     }
   }
   }
 
 
+  .category_button {
+    padding: 1rem !important;
+    margin: 0 !important;
+  }
+
   #search_view:focus-within {
   #search_view:focus-within {
     display: block;
     display: block;
     background-color: var(--color-search-background);
     background-color: var(--color-search-background);

+ 20 - 9
searx/templates/simple/categories.html

@@ -13,14 +13,25 @@
 }  -%}
 }  -%}
 <div id="categories" class="search_categories">{{- '' -}}
 <div id="categories" class="search_categories">{{- '' -}}
     <div id="categories_container">
     <div id="categories_container">
-        {%- for category in categories -%}
-        <div class="category"><input type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}"{% if category in selected_categories %} checked="checked"{% endif %}/>
-            <label for="checkbox_{{ category|replace(' ', '_') }}" class="tooltips">
-                {{- icon_big(category_icons[category]) if category in category_icons  else icon_big('globe-outline') -}}
-                <div class="category_name">{{- _(category) -}}</div>
-            </label>
-        </div>
-        {%- endfor -%}
-        {%- if display_tooltip %}<div class="help">{{ _('Click on the magnifier to perform search') }}</div>{% endif -%}
+        {%- if not search_on_category_select or not display_tooltip -%}
+            {%- for category in categories_as_tabs -%}
+                <div class="category category_checkbox">{{- '' -}}
+                    <input type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}"{% if category in selected_categories %} checked="checked"{% endif %}/>
+                    <label for="checkbox_{{ category|replace(' ', '_') }}" class="tooltips">
+                        {{- icon_big(category_icons[category]) if category in category_icons  else icon_big('globe-outline') -}}
+                        <div class="category_name">{{- _(category) -}}</div>
+                    </label>
+                </div>
+            {%- endfor -%}
+            {%- if display_tooltip %}<div class="help">{{ _('Click on the magnifier to perform search') }}</div>{% endif -%}
+        {%- else -%}
+            {%- for category in categories_as_tabs -%}{{- '\n' -}}
+                <button type="submit" name="category_{{ category|replace(' ', '_') }}" class="category category_button {% if category in selected_categories %}selected{% endif %}">
+                    {{- icon_big(category_icons[category]) if category in category_icons else icon_big('globe-outline') -}}
+                    <div class="category_name">{{- _(category) -}}</div>{{- '' -}}
+                </button>{{- '' -}}
+            {%- endfor -%}
+            {{- '\n' -}}
+        {%- endif -%}
     </div>{{- '' -}}
     </div>{{- '' -}}
 </div>
 </div>

+ 3 - 0
searx/templates/simple/preferences.html

@@ -197,6 +197,9 @@
     {%- if 'infinite_scroll' not in locked_preferences -%}
     {%- if 'infinite_scroll' not in locked_preferences -%}
       {%- include 'simple/preferences/infinite_scroll.html' -%}
       {%- include 'simple/preferences/infinite_scroll.html' -%}
     {%- endif -%}
     {%- endif -%}
+    {%- if 'search_on_category_select' not in locked_preferences -%}
+      {%- include 'simple/preferences/search_on_category_select.html' -%}
+    {%- endif -%}
     {{- plugin_preferences('ui') -}}
     {{- plugin_preferences('ui') -}}
     {{- tab_footer() -}}
     {{- tab_footer() -}}
 
 

+ 16 - 0
searx/templates/simple/preferences/search_on_category_select.html

@@ -0,0 +1,16 @@
+<fieldset>{{- '' -}}
+  <legend>{{ _('Search on category select') }}</legend>{{- '' -}}
+  <p class="value">{{- '' -}}
+    <input type="checkbox" {{- ' ' -}}
+           name="search_on_category_select" {{- ' ' -}}
+           aria-labelledby="pref_search_on_category_select" {{- ' ' -}}
+           class="checkbox-onoff" {{- ' ' -}}
+           {%- if preferences.get_value('search_on_category_select') -%}
+             checked
+           {%- endif -%}{{- ' ' -}}
+           />{{- '' -}}
+  </p>{{- '' -}}
+  <div class="description">
+    {{- _('Perform search immediately if a category selected. Disable to select multiple categories') -}}
+  </div>{{- '' -}}
+</fieldset>{{- '' -}}

+ 2 - 1
searx/webapp.py

@@ -361,7 +361,7 @@ def get_client_settings():
         'http_method': req_pref.get_value('method'),
         'http_method': req_pref.get_value('method'),
         'infinite_scroll': req_pref.get_value('infinite_scroll'),
         'infinite_scroll': req_pref.get_value('infinite_scroll'),
         'translations': get_translations(),
         'translations': get_translations(),
-        'search_on_category_select': req_pref.plugins.choices['searx.plugins.search_on_category_select'],
+        'search_on_category_select': req_pref.get_value('searx.plugins.search_on_category_select'),
         'hotkeys': req_pref.plugins.choices['searx.plugins.vim_hotkeys'],
         'hotkeys': req_pref.plugins.choices['searx.plugins.vim_hotkeys'],
         'theme_static_path': custom_url_for('static', filename='themes/simple'),
         'theme_static_path': custom_url_for('static', filename='themes/simple'),
     }
     }
@@ -389,6 +389,7 @@ def render(template_name: str, **kwargs):
     kwargs['preferences'] = request.preferences
     kwargs['preferences'] = request.preferences
     kwargs['autocomplete'] = request.preferences.get_value('autocomplete')
     kwargs['autocomplete'] = request.preferences.get_value('autocomplete')
     kwargs['infinite_scroll'] = request.preferences.get_value('infinite_scroll')
     kwargs['infinite_scroll'] = request.preferences.get_value('infinite_scroll')
+    kwargs['search_on_category_select'] = request.preferences.get_value('search_on_category_select')
     kwargs['results_on_new_tab'] = request.preferences.get_value('results_on_new_tab')
     kwargs['results_on_new_tab'] = request.preferences.get_value('results_on_new_tab')
     kwargs['advanced_search'] = request.preferences.get_value('advanced_search')
     kwargs['advanced_search'] = request.preferences.get_value('advanced_search')
     kwargs['query_in_title'] = request.preferences.get_value('query_in_title')
     kwargs['query_in_title'] = request.preferences.get_value('query_in_title')