mirror of
				https://github.com/searxng/searxng
				synced 2024-01-01 19:24:07 +01:00 
			
		
		
		
	Merge pull request #916 from dalf/pref_infinite_scroll2
Convert the infinite_scroll plugin as a preference (second version)
This commit is contained in:
		
						commit
						8230603f48
					
				
					 41 changed files with 528 additions and 171 deletions
				
			
		| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
from flask_babel import gettext
 | 
			
		||||
 | 
			
		||||
name = gettext('Infinite scroll')
 | 
			
		||||
description = gettext('Automatically load next page when scrolling to bottom of current page')
 | 
			
		||||
default_on = False
 | 
			
		||||
preference_section = 'ui'
 | 
			
		||||
 | 
			
		||||
js_dependencies = ('plugins/js/infinite_scroll.js',)
 | 
			
		||||
css_dependencies = ('plugins/css/infinite_scroll.css',)
 | 
			
		||||
| 
						 | 
				
			
			@ -394,6 +394,17 @@ class Preferences:
 | 
			
		|||
                    'False': False
 | 
			
		||||
                }
 | 
			
		||||
            ),
 | 
			
		||||
            'infinite_scroll': MapSetting(
 | 
			
		||||
                settings['ui']['infinite_scroll'],
 | 
			
		||||
                locked=is_locked('infinite_scroll'),
 | 
			
		||||
                map={
 | 
			
		||||
                    '': settings['ui']['infinite_scroll'],
 | 
			
		||||
                    '0': False,
 | 
			
		||||
                    '1': True,
 | 
			
		||||
                    'True': True,
 | 
			
		||||
                    'False': False
 | 
			
		||||
                }
 | 
			
		||||
            ),
 | 
			
		||||
            # fmt: on
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,7 +169,6 @@ outgoing:
 | 
			
		|||
#   - 'Ahmia blacklist'  # activation depends on outgoing.using_tor_proxy
 | 
			
		||||
#   # these plugins are disabled if nothing is configured ..
 | 
			
		||||
#   - 'Hostname replace'  # see hostname_replace configuration below
 | 
			
		||||
#   - 'Infinite scroll'
 | 
			
		||||
#   - 'Open Access DOI rewrite'
 | 
			
		||||
#   - 'Vim-like hotkeys'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -186,6 +186,7 @@ SCHEMA = {
 | 
			
		|||
        'results_on_new_tab': SettingsValue(bool, False),
 | 
			
		||||
        'advanced_search': SettingsValue(bool, False),
 | 
			
		||||
        'query_in_title': SettingsValue(bool, False),
 | 
			
		||||
        'infinite_scroll': SettingsValue(bool, False),
 | 
			
		||||
    },
 | 
			
		||||
    'preferences': {
 | 
			
		||||
        'lock': SettingsValue(list, []),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,40 +0,0 @@
 | 
			
		|||
function hasScrollbar() {
 | 
			
		||||
    var root = document.compatMode=='BackCompat'? document.body : document.documentElement;
 | 
			
		||||
    return root.scrollHeight>root.clientHeight;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function loadNextPage() {
 | 
			
		||||
    var formData = $('#pagination form:last').serialize();
 | 
			
		||||
    if (formData) {
 | 
			
		||||
        $('#pagination').html('<div class="loading-spinner"></div>');
 | 
			
		||||
        $.ajax({
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            url: $('#search_form').prop('action'),
 | 
			
		||||
            data: formData,
 | 
			
		||||
            dataType: 'html',
 | 
			
		||||
            success: function(data) {
 | 
			
		||||
                var body = $(data);
 | 
			
		||||
                $('#pagination').remove();
 | 
			
		||||
                $('#main_results').append('<hr/>');
 | 
			
		||||
                $('#main_results').append(body.find('.result'));
 | 
			
		||||
                $('#main_results').append(body.find('#pagination'));
 | 
			
		||||
                if(!hasScrollbar()) {
 | 
			
		||||
                    loadNextPage();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$(document).ready(function() {
 | 
			
		||||
    var win = $(window);
 | 
			
		||||
    if(!hasScrollbar()) {
 | 
			
		||||
        loadNextPage();
 | 
			
		||||
    }
 | 
			
		||||
    win.scroll(function() {
 | 
			
		||||
        $("#pagination button").css("visibility", "hidden");
 | 
			
		||||
        if ($(document).height() - win.height() - win.scrollTop() < 150) {
 | 
			
		||||
            loadNextPage();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +29,8 @@
 | 
			
		|||
    this.verticalMargin = verticalMargin;
 | 
			
		||||
    this.horizontalMargin = horizontalMargin;
 | 
			
		||||
    this.maxHeight = maxHeight;
 | 
			
		||||
    this.isAlignDone = true;
 | 
			
		||||
    this.trottleCallToAlign = null;
 | 
			
		||||
    this.alignAfterThrotteling = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
| 
						 | 
				
			
			@ -72,12 +73,12 @@
 | 
			
		|||
        // not loaded image : make it square as _getHeigth said it
 | 
			
		||||
        imgWidth = height;
 | 
			
		||||
      }
 | 
			
		||||
      img.style.width = imgWidth + 'px';
 | 
			
		||||
      img.style.height = height + 'px';
 | 
			
		||||
      img.style.marginLeft = this.horizontalMargin + 'px';
 | 
			
		||||
      img.style.marginTop = this.horizontalMargin + 'px';
 | 
			
		||||
      img.style.marginRight = this.verticalMargin - 7 + 'px'; // -4 is the negative margin of the inline element
 | 
			
		||||
      img.style.marginBottom = this.verticalMargin - 7 + 'px';
 | 
			
		||||
      img.setAttribute('width', Math.round(imgWidth));
 | 
			
		||||
      img.setAttribute('height', Math.round(height));
 | 
			
		||||
      img.style.marginLeft = Math.round(this.horizontalMargin) + 'px';
 | 
			
		||||
      img.style.marginTop = Math.round(this.horizontalMargin) + 'px';
 | 
			
		||||
      img.style.marginRight = Math.round(this.verticalMargin - 7) + 'px'; // -4 is the negative margin of the inline element
 | 
			
		||||
      img.style.marginBottom = Math.round(this.verticalMargin - 7) + 'px';
 | 
			
		||||
      resultNode = img.parentNode.parentNode;
 | 
			
		||||
      if (!resultNode.classList.contains('js')) {
 | 
			
		||||
        resultNode.classList.add('js');
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +113,23 @@
 | 
			
		|||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.throttleAlign = function () {
 | 
			
		||||
    var obj = this;
 | 
			
		||||
    if (obj.trottleCallToAlign) {
 | 
			
		||||
      obj.alignAfterThrotteling = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      obj.alignAfterThrotteling = false;
 | 
			
		||||
      obj.align();
 | 
			
		||||
      obj.trottleCallToAlign = setTimeout(function () {
 | 
			
		||||
        if (obj.alignAfterThrotteling) {
 | 
			
		||||
          obj.align();
 | 
			
		||||
        }
 | 
			
		||||
        obj.alignAfterThrotteling = false;
 | 
			
		||||
        obj.trottleCallToAlign = null;
 | 
			
		||||
      }, 20);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.align = function () {
 | 
			
		||||
    var i;
 | 
			
		||||
    var results_selectorNode = d.querySelectorAll(this.results_selector);
 | 
			
		||||
| 
						 | 
				
			
			@ -141,9 +159,9 @@
 | 
			
		|||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.watch = function () {
 | 
			
		||||
  ImageLayout.prototype._monitorImages = function () {
 | 
			
		||||
    var i, img;
 | 
			
		||||
    var obj = this;
 | 
			
		||||
    var objthrottleAlign = this.throttleAlign.bind(this);
 | 
			
		||||
    var results_nodes = d.querySelectorAll(this.results_selector);
 | 
			
		||||
    var results_length = results_nodes.length;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -152,34 +170,53 @@
 | 
			
		|||
      event.originalTarget.src = w.searxng.static_path + w.searxng.theme.img_load_error;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function throttleAlign () {
 | 
			
		||||
      if (obj.isAlignDone) {
 | 
			
		||||
        obj.isAlignDone = false;
 | 
			
		||||
        setTimeout(function () {
 | 
			
		||||
          obj.align();
 | 
			
		||||
          obj.isAlignDone = true;
 | 
			
		||||
        }, 100);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
 | 
			
		||||
    w.addEventListener('pageshow', throttleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/FileReader/load_event
 | 
			
		||||
    w.addEventListener('load', throttleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event
 | 
			
		||||
    w.addEventListener('resize', throttleAlign);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < results_length; i++) {
 | 
			
		||||
      img = results_nodes[i].querySelector(this.img_selector);
 | 
			
		||||
      if (img !== null && img !== undefined) {
 | 
			
		||||
        img.addEventListener('load', throttleAlign);
 | 
			
		||||
      if (img !== null && img !== undefined && !img.classList.contains('aligned')) {
 | 
			
		||||
        img.addEventListener('load', objthrottleAlign);
 | 
			
		||||
        // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror
 | 
			
		||||
        img.addEventListener('error', throttleAlign);
 | 
			
		||||
        img.addEventListener('error', objthrottleAlign);
 | 
			
		||||
        img.addEventListener('timeout', objthrottleAlign);
 | 
			
		||||
        if (w.searxng.theme.img_load_error) {
 | 
			
		||||
          img.addEventListener('error', img_load_error, {once: true});
 | 
			
		||||
        }
 | 
			
		||||
        img.classList.add('aligned');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.watch = function () {
 | 
			
		||||
    var objthrottleAlign = this.throttleAlign.bind(this);
 | 
			
		||||
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
 | 
			
		||||
    w.addEventListener('pageshow', objthrottleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/FileReader/load_event
 | 
			
		||||
    w.addEventListener('load', objthrottleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event
 | 
			
		||||
    w.addEventListener('resize', objthrottleAlign);
 | 
			
		||||
 | 
			
		||||
    this._monitorImages();
 | 
			
		||||
 | 
			
		||||
    var obj = this;
 | 
			
		||||
 | 
			
		||||
    let observer = new MutationObserver(entries => {
 | 
			
		||||
      let newElement = false;
 | 
			
		||||
      for (let i = 0; i < entries.length; i++) {
 | 
			
		||||
        if (entries[i].addedNodes.length > 0 && entries[i].addedNodes[0].classList.contains('result')) {
 | 
			
		||||
          newElement = true;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (newElement) {
 | 
			
		||||
        obj._monitorImages();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    observer.observe(d.querySelector(this.container_selector), {
 | 
			
		||||
      childList: true,
 | 
			
		||||
      subtree: true,
 | 
			
		||||
      attributes: false,
 | 
			
		||||
      characterData: false,
 | 
			
		||||
    })
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  w.searxng.ImageLayout = ImageLayout;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -382,6 +382,29 @@
 | 
			
		|||
.col-stat {
 | 
			
		||||
  width: 10rem;
 | 
			
		||||
}
 | 
			
		||||
@keyframes rotate-forever {
 | 
			
		||||
  0% {
 | 
			
		||||
    transform: rotate(0deg);
 | 
			
		||||
  }
 | 
			
		||||
  100% {
 | 
			
		||||
    transform: rotate(360deg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.loading-spinner {
 | 
			
		||||
  animation-duration: 0.75s;
 | 
			
		||||
  animation-iteration-count: infinite;
 | 
			
		||||
  animation-name: rotate-forever;
 | 
			
		||||
  animation-timing-function: linear;
 | 
			
		||||
  height: 30px;
 | 
			
		||||
  width: 30px;
 | 
			
		||||
  border: 8px solid #666;
 | 
			
		||||
  border-right-color: transparent;
 | 
			
		||||
  border-radius: 50% !important;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
html.infinite_scroll #pagination button {
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
   this file is generated automatically by searxng_extra/update/update_pygments.py
 | 
			
		||||
   using pygments version 2.11.2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -382,6 +382,29 @@
 | 
			
		|||
.col-stat {
 | 
			
		||||
  width: 10rem;
 | 
			
		||||
}
 | 
			
		||||
@keyframes rotate-forever {
 | 
			
		||||
  0% {
 | 
			
		||||
    transform: rotate(0deg);
 | 
			
		||||
  }
 | 
			
		||||
  100% {
 | 
			
		||||
    transform: rotate(360deg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.loading-spinner {
 | 
			
		||||
  animation-duration: 0.75s;
 | 
			
		||||
  animation-iteration-count: infinite;
 | 
			
		||||
  animation-name: rotate-forever;
 | 
			
		||||
  animation-timing-function: linear;
 | 
			
		||||
  height: 30px;
 | 
			
		||||
  width: 30px;
 | 
			
		||||
  border: 8px solid #666;
 | 
			
		||||
  border-right-color: transparent;
 | 
			
		||||
  border-radius: 50% !important;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
html.infinite_scroll #pagination button {
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
   this file is generated automatically by searxng_extra/update/update_pygments.py
 | 
			
		||||
   using pygments version 2.11.2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -382,6 +382,29 @@
 | 
			
		|||
.col-stat {
 | 
			
		||||
  width: 10rem;
 | 
			
		||||
}
 | 
			
		||||
@keyframes rotate-forever {
 | 
			
		||||
  0% {
 | 
			
		||||
    transform: rotate(0deg);
 | 
			
		||||
  }
 | 
			
		||||
  100% {
 | 
			
		||||
    transform: rotate(360deg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.loading-spinner {
 | 
			
		||||
  animation-duration: 0.75s;
 | 
			
		||||
  animation-iteration-count: infinite;
 | 
			
		||||
  animation-name: rotate-forever;
 | 
			
		||||
  animation-timing-function: linear;
 | 
			
		||||
  height: 30px;
 | 
			
		||||
  width: 30px;
 | 
			
		||||
  border: 8px solid #666;
 | 
			
		||||
  border-right-color: transparent;
 | 
			
		||||
  border-radius: 50% !important;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
html.infinite_scroll #pagination button {
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
   this file is generated automatically by searxng_extra/update/update_pygments.py
 | 
			
		||||
   using pygments version 2.11.2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -78,7 +78,7 @@ module.exports = function(grunt) {
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    jshint: {
 | 
			
		||||
      files: ['gruntfile.js', 'src/js/*.js', '../__common__/js/image_layout.js'],
 | 
			
		||||
      files: ['gruntfile.js', 'src/js/*.js'],  // files in __common__ are linted by es lint in simple theme
 | 
			
		||||
      options: {
 | 
			
		||||
        reporterOutput: "",
 | 
			
		||||
        esversion: 6,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ window.searxng = (function(d) {
 | 
			
		|||
 | 
			
		||||
    return {
 | 
			
		||||
        autocompleter: script.getAttribute('data-autocompleter') === 'true',
 | 
			
		||||
        infinite_scroll: script.getAttribute('data-infinite-scroll') === 'true',
 | 
			
		||||
        method: script.getAttribute('data-method'),
 | 
			
		||||
        translations: JSON.parse(script.getAttribute('data-translations'))
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -189,6 +190,56 @@ $(document).ready(function(){
 | 
			
		|||
 * SPDX-License-Identifier: AGPL-3.0-or-later
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
$(document).ready(function() {
 | 
			
		||||
    function hasScrollbar() {
 | 
			
		||||
        var root = document.compatMode=='BackCompat'? document.body : document.documentElement;
 | 
			
		||||
        return root.scrollHeight>root.clientHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function loadNextPage() {
 | 
			
		||||
        var formData = $('#pagination form:last').serialize();
 | 
			
		||||
        if (formData) {
 | 
			
		||||
            $('#pagination').html('<div class="loading-spinner"></div>');
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                url: $('#search_form').prop('action'),
 | 
			
		||||
                data: formData,
 | 
			
		||||
                dataType: 'html',
 | 
			
		||||
                success: function(data) {
 | 
			
		||||
                    var body = $(data);
 | 
			
		||||
                    $('#pagination').remove();
 | 
			
		||||
                    $('#main_results').append('<hr/>');
 | 
			
		||||
                    $('#main_results').append(body.find('.result'));
 | 
			
		||||
                    $('#main_results').append(body.find('#pagination'));
 | 
			
		||||
                    if(!hasScrollbar()) {
 | 
			
		||||
                        loadNextPage();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (searxng.infinite_scroll) {
 | 
			
		||||
        var win = $(window);
 | 
			
		||||
        $("html").addClass('infinite_scroll');
 | 
			
		||||
        if(!hasScrollbar()) {
 | 
			
		||||
            loadNextPage();
 | 
			
		||||
        }
 | 
			
		||||
        win.on('scroll', function() {
 | 
			
		||||
            if ($(document).height() - win.height() - win.scrollTop() < 150) {
 | 
			
		||||
                loadNextPage();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
;/**
 | 
			
		||||
 * @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.addEventListener('load', function() {
 | 
			
		||||
    // Hide infobox toggle if shrunk size already fits all content.
 | 
			
		||||
    $('.infobox').each(function() {
 | 
			
		||||
| 
						 | 
				
			
			@ -348,7 +399,8 @@ $(document).ready(function(){
 | 
			
		|||
    this.verticalMargin = verticalMargin;
 | 
			
		||||
    this.horizontalMargin = horizontalMargin;
 | 
			
		||||
    this.maxHeight = maxHeight;
 | 
			
		||||
    this.isAlignDone = true;
 | 
			
		||||
    this.trottleCallToAlign = null;
 | 
			
		||||
    this.alignAfterThrotteling = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
| 
						 | 
				
			
			@ -391,12 +443,12 @@ $(document).ready(function(){
 | 
			
		|||
        // not loaded image : make it square as _getHeigth said it
 | 
			
		||||
        imgWidth = height;
 | 
			
		||||
      }
 | 
			
		||||
      img.style.width = imgWidth + 'px';
 | 
			
		||||
      img.style.height = height + 'px';
 | 
			
		||||
      img.style.marginLeft = this.horizontalMargin + 'px';
 | 
			
		||||
      img.style.marginTop = this.horizontalMargin + 'px';
 | 
			
		||||
      img.style.marginRight = this.verticalMargin - 7 + 'px'; // -4 is the negative margin of the inline element
 | 
			
		||||
      img.style.marginBottom = this.verticalMargin - 7 + 'px';
 | 
			
		||||
      img.setAttribute('width', Math.round(imgWidth));
 | 
			
		||||
      img.setAttribute('height', Math.round(height));
 | 
			
		||||
      img.style.marginLeft = Math.round(this.horizontalMargin) + 'px';
 | 
			
		||||
      img.style.marginTop = Math.round(this.horizontalMargin) + 'px';
 | 
			
		||||
      img.style.marginRight = Math.round(this.verticalMargin - 7) + 'px'; // -4 is the negative margin of the inline element
 | 
			
		||||
      img.style.marginBottom = Math.round(this.verticalMargin - 7) + 'px';
 | 
			
		||||
      resultNode = img.parentNode.parentNode;
 | 
			
		||||
      if (!resultNode.classList.contains('js')) {
 | 
			
		||||
        resultNode.classList.add('js');
 | 
			
		||||
| 
						 | 
				
			
			@ -431,6 +483,23 @@ $(document).ready(function(){
 | 
			
		|||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.throttleAlign = function () {
 | 
			
		||||
    var obj = this;
 | 
			
		||||
    if (obj.trottleCallToAlign) {
 | 
			
		||||
      obj.alignAfterThrotteling = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      obj.alignAfterThrotteling = false;
 | 
			
		||||
      obj.align();
 | 
			
		||||
      obj.trottleCallToAlign = setTimeout(function () {
 | 
			
		||||
        if (obj.alignAfterThrotteling) {
 | 
			
		||||
          obj.align();
 | 
			
		||||
        }
 | 
			
		||||
        obj.alignAfterThrotteling = false;
 | 
			
		||||
        obj.trottleCallToAlign = null;
 | 
			
		||||
      }, 20);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.align = function () {
 | 
			
		||||
    var i;
 | 
			
		||||
    var results_selectorNode = d.querySelectorAll(this.results_selector);
 | 
			
		||||
| 
						 | 
				
			
			@ -460,9 +529,9 @@ $(document).ready(function(){
 | 
			
		|||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.watch = function () {
 | 
			
		||||
  ImageLayout.prototype._monitorImages = function () {
 | 
			
		||||
    var i, img;
 | 
			
		||||
    var obj = this;
 | 
			
		||||
    var objthrottleAlign = this.throttleAlign.bind(this);
 | 
			
		||||
    var results_nodes = d.querySelectorAll(this.results_selector);
 | 
			
		||||
    var results_length = results_nodes.length;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -471,34 +540,53 @@ $(document).ready(function(){
 | 
			
		|||
      event.originalTarget.src = w.searxng.static_path + w.searxng.theme.img_load_error;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function throttleAlign () {
 | 
			
		||||
      if (obj.isAlignDone) {
 | 
			
		||||
        obj.isAlignDone = false;
 | 
			
		||||
        setTimeout(function () {
 | 
			
		||||
          obj.align();
 | 
			
		||||
          obj.isAlignDone = true;
 | 
			
		||||
        }, 100);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
 | 
			
		||||
    w.addEventListener('pageshow', throttleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/FileReader/load_event
 | 
			
		||||
    w.addEventListener('load', throttleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event
 | 
			
		||||
    w.addEventListener('resize', throttleAlign);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < results_length; i++) {
 | 
			
		||||
      img = results_nodes[i].querySelector(this.img_selector);
 | 
			
		||||
      if (img !== null && img !== undefined) {
 | 
			
		||||
        img.addEventListener('load', throttleAlign);
 | 
			
		||||
      if (img !== null && img !== undefined && !img.classList.contains('aligned')) {
 | 
			
		||||
        img.addEventListener('load', objthrottleAlign);
 | 
			
		||||
        // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror
 | 
			
		||||
        img.addEventListener('error', throttleAlign);
 | 
			
		||||
        img.addEventListener('error', objthrottleAlign);
 | 
			
		||||
        img.addEventListener('timeout', objthrottleAlign);
 | 
			
		||||
        if (w.searxng.theme.img_load_error) {
 | 
			
		||||
          img.addEventListener('error', img_load_error, {once: true});
 | 
			
		||||
        }
 | 
			
		||||
        img.classList.add('aligned');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ImageLayout.prototype.watch = function () {
 | 
			
		||||
    var objthrottleAlign = this.throttleAlign.bind(this);
 | 
			
		||||
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
 | 
			
		||||
    w.addEventListener('pageshow', objthrottleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/FileReader/load_event
 | 
			
		||||
    w.addEventListener('load', objthrottleAlign);
 | 
			
		||||
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event
 | 
			
		||||
    w.addEventListener('resize', objthrottleAlign);
 | 
			
		||||
 | 
			
		||||
    this._monitorImages();
 | 
			
		||||
 | 
			
		||||
    var obj = this;
 | 
			
		||||
 | 
			
		||||
    let observer = new MutationObserver(entries => {
 | 
			
		||||
      let newElement = false;
 | 
			
		||||
      for (let i = 0; i < entries.length; i++) {
 | 
			
		||||
        if (entries[i].addedNodes.length > 0 && entries[i].addedNodes[0].classList.contains('result')) {
 | 
			
		||||
          newElement = true;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (newElement) {
 | 
			
		||||
        obj._monitorImages();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    observer.observe(d.querySelector(this.container_selector), {
 | 
			
		||||
      childList: true,
 | 
			
		||||
      subtree: true,
 | 
			
		||||
      attributes: false,
 | 
			
		||||
      characterData: false,
 | 
			
		||||
    })
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  w.searxng.ImageLayout = ImageLayout;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								searx/static/themes/oscar/js/searxng.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								searx/static/themes/oscar/js/searxng.min.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -4,7 +4,7 @@
 | 
			
		|||
 * (C) Copyright Contributors to the searx project (2014 - 2021).
 | 
			
		||||
 * SPDX-License-Identifier: AGPL-3.0-or-later
 | 
			
		||||
 */
 | 
			
		||||
window.searxng=function(t){"use strict";t.getElementsByTagName("html")[0].className="js";t=t.currentScript||(t=t.getElementsByTagName("script"))[t.length-1];return{autocompleter:"true"===t.getAttribute("data-autocompleter"),method:t.getAttribute("data-method"),translations:JSON.parse(t.getAttribute("data-translations"))}}(document),
 | 
			
		||||
window.searxng=function(t){"use strict";t.getElementsByTagName("html")[0].className="js";t=t.currentScript||(t=t.getElementsByTagName("script"))[t.length-1];return{autocompleter:"true"===t.getAttribute("data-autocompleter"),infinite_scroll:"true"===t.getAttribute("data-infinite-scroll"),method:t.getAttribute("data-method"),translations:JSON.parse(t.getAttribute("data-translations"))}}(document),
 | 
			
		||||
/**
 | 
			
		||||
 * @license
 | 
			
		||||
 * (C) Copyright Contributors to the SearXNG project.
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ window.searxng=function(t){"use strict";t.getElementsByTagName("html")[0].classN
 | 
			
		|||
 * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
 | 
			
		||||
 * SPDX-License-Identifier: AGPL-3.0-or-later
 | 
			
		||||
 */
 | 
			
		||||
$(document).ready(function(){var t,a="";searxng.autocompleter&&((t=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:{url:"./autocompleter?q=%QUERY",wildcard:"%QUERY"}})).initialize(),$("#q").on("keydown",function(t){13==t.which&&(a=$("#q").val())}),$("#q").typeahead({name:"search-results",highlight:!1,hint:!0,displayKey:function(t){return t},classNames:{input:"tt-input",hint:"tt-hint",menu:"tt-dropdown-menu",dataset:"tt-dataset-search-results"}},{name:"autocomplete",source:t}),$("#q").bind("typeahead:select",function(t,e){a&&$("#q").val(a),$("#search_form").submit()}))}),
 | 
			
		||||
$(document).ready(function(){var t,n="";searxng.autocompleter&&((t=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:{url:"./autocompleter?q=%QUERY",wildcard:"%QUERY"}})).initialize(),$("#q").on("keydown",function(t){13==t.which&&(n=$("#q").val())}),$("#q").typeahead({name:"search-results",highlight:!1,hint:!0,displayKey:function(t){return t},classNames:{input:"tt-input",hint:"tt-hint",menu:"tt-dropdown-menu",dataset:"tt-dataset-search-results"}},{name:"autocomplete",source:t}),$("#q").bind("typeahead:select",function(t,e){n&&$("#q").val(n),$("#search_form").submit()}))}),
 | 
			
		||||
/**
 | 
			
		||||
 * @license
 | 
			
		||||
 * (C) Copyright Contributors to the SearXNG project.
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,14 @@ $(document).ready(function(){var t,a="";searxng.autocompleter&&((t=new Bloodhoun
 | 
			
		|||
 * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
 | 
			
		||||
 * SPDX-License-Identifier: AGPL-3.0-or-later
 | 
			
		||||
 */
 | 
			
		||||
$(document).ready(function(){$("#q.autofocus").focus(),$("#clear_search").click(function(){document.getElementById("q").value=""}),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var t=$(this).data("btn-text-collapsed"),e=$(this).data("btn-text-not-collapsed");""!==t&&""!==e&&(new_html=$(this).hasClass("collapsed")?$(this).html().replace(t,e):$(this).html().replace(e,t),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var t="btn-"+$(this).data("btn-class"),e=$(this).data("btn-label-default"),a=$(this).data("btn-label-toggled");""!==a&&(new_html=$(this).hasClass("btn-default")?$(this).html().replace(e,a):$(this).html().replace(a,e),$(this).html(new_html)),$(this).toggleClass(t),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var t=$(this).data("target"),t=$(t+" > iframe"),e=t.attr("src");void 0!==e&&!1!==e||t.attr("src",t.data("src"))}),$(".btn-sm").dblclick(function(){var t="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(t),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(t),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))}),$(".nav-tabs").click(function(t){$(t.target).parents("ul").children().attr("aria-selected","false"),$(t.target).parent().attr("aria-selected","true")}),searxng.image_thumbnail_layout=new searxng.ImageLayout("#main_results","#main_results .result-images","img.img-thumbnail",15,3,200),searxng.image_thumbnail_layout.watch()}),
 | 
			
		||||
$(document).ready(function(){$("#q.autofocus").focus(),$("#clear_search").click(function(){document.getElementById("q").value=""}),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var t=$(this).data("btn-text-collapsed"),e=$(this).data("btn-text-not-collapsed");""!==t&&""!==e&&(new_html=$(this).hasClass("collapsed")?$(this).html().replace(t,e):$(this).html().replace(e,t),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var t="btn-"+$(this).data("btn-class"),e=$(this).data("btn-label-default"),n=$(this).data("btn-label-toggled");""!==n&&(new_html=$(this).hasClass("btn-default")?$(this).html().replace(e,n):$(this).html().replace(n,e),$(this).html(new_html)),$(this).toggleClass(t),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var t=$(this).data("target"),t=$(t+" > iframe"),e=t.attr("src");void 0!==e&&!1!==e||t.attr("src",t.data("src"))}),$(".btn-sm").dblclick(function(){var t="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(t),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(t),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))}),$(".nav-tabs").click(function(t){$(t.target).parents("ul").children().attr("aria-selected","false"),$(t.target).parent().attr("aria-selected","true")}),searxng.image_thumbnail_layout=new searxng.ImageLayout("#main_results","#main_results .result-images","img.img-thumbnail",15,3,200),searxng.image_thumbnail_layout.watch()}),
 | 
			
		||||
/**
 | 
			
		||||
 * @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
 | 
			
		||||
 */
 | 
			
		||||
$(document).ready(function(){function e(){var t="BackCompat"==document.compatMode?document.body:document.documentElement;return t.scrollHeight>t.clientHeight}function n(){var t=$("#pagination form:last").serialize();t&&($("#pagination").html('<div class="loading-spinner"></div>'),$.ajax({type:"POST",url:$("#search_form").prop("action"),data:t,dataType:"html",success:function(t){t=$(t);$("#pagination").remove(),$("#main_results").append("<hr/>"),$("#main_results").append(t.find(".result")),$("#main_results").append(t.find("#pagination")),e()||n()}}))}var t;searxng.infinite_scroll&&(t=$(window),$("html").addClass("infinite_scroll"),e()||n(),t.on("scroll",function(){$(document).height()-t.height()-t.scrollTop()<150&&n()}))}),
 | 
			
		||||
/**
 | 
			
		||||
 * @license
 | 
			
		||||
 * (C) Copyright Contributors to the SearXNG project.
 | 
			
		||||
| 
						 | 
				
			
			@ -35,14 +42,14 @@ window.addEventListener("load",function(){$(".infobox").each(function(){var t=$(
 | 
			
		|||
 * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
 | 
			
		||||
 * SPDX-License-Identifier: AGPL-3.0-or-later
 | 
			
		||||
 */
 | 
			
		||||
$(document).ready(function(){$(".searxng_init_map").on("click",function(t){var e=$(this).data("leaflet-target"),a=$(this).data("map-lon"),n=$(this).data("map-lat"),i=$(this).data("map-zoom"),s=$(this).data("map-boundingbox"),o=$(this).data("map-geojson"),r=(s&&(southWest=L.latLng(s[0],s[2]),northEast=L.latLng(s[1],s[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/css/images/",L.map(e)),s=new L.TileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'}),e=(new L.TileLayer("https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'}),setTimeout(function(){map_bounds?r.fitBounds(map_bounds,{maxZoom:17}):a&&n&&(i?r.setView(new L.LatLng(n,a),i):r.setView(new L.LatLng(n,a),8))},0),r.addLayer(s),{"OSM Mapnik":s});L.control.layers(e).addTo(r),o&&L.geoJson(o).addTo(r),$(this).off(t)})}),
 | 
			
		||||
$(document).ready(function(){$(".searxng_init_map").on("click",function(t){var e=$(this).data("leaflet-target"),n=$(this).data("map-lon"),a=$(this).data("map-lat"),i=$(this).data("map-zoom"),o=$(this).data("map-boundingbox"),s=$(this).data("map-geojson"),r=(o&&(southWest=L.latLng(o[0],o[2]),northEast=L.latLng(o[1],o[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/css/images/",L.map(e)),o=new L.TileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'}),e=(new L.TileLayer("https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'}),setTimeout(function(){map_bounds?r.fitBounds(map_bounds,{maxZoom:17}):n&&a&&(i?r.setView(new L.LatLng(a,n),i):r.setView(new L.LatLng(a,n),8))},0),r.addLayer(o),{"OSM Mapnik":o});L.control.layers(e).addTo(r),s&&L.geoJson(s).addTo(r),$(this).off(t)})}),
 | 
			
		||||
/**
 | 
			
		||||
 * @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
 | 
			
		||||
 */
 | 
			
		||||
$(document).ready(function(){let s=null;document.querySelector('body[class="preferences_endpoint"]')&&$("[data-engine-name]").hover(function(){null==s&&$.ajax("engine_descriptions.json",dataType="json").done(function(t){s=t;for(var[e,a]of Object.entries(t))for(const i of $('[data-engine-name="'+e+'"] .description')){var n=" (<i>"+searxng.translations.Source+": "+a[1]+"</i>)";i.innerHTML=a[0]+n}})})}),
 | 
			
		||||
$(document).ready(function(){let o=null;document.querySelector('body[class="preferences_endpoint"]')&&$("[data-engine-name]").hover(function(){null==o&&$.ajax("engine_descriptions.json",dataType="json").done(function(t){o=t;for(var[e,n]of Object.entries(t))for(const i of $('[data-engine-name="'+e+'"] .description')){var a=" (<i>"+searxng.translations.Source+": "+n[1]+"</i>)";i.innerHTML=n[0]+a}})})}),
 | 
			
		||||
/**
 | 
			
		||||
 * @license
 | 
			
		||||
 * (C) Copyright Contributors to the SearXNG project.
 | 
			
		||||
| 
						 | 
				
			
			@ -71,5 +78,5 @@ $(document).ready(function(){$("#allow-all-engines").click(function(){$(".onoffs
 | 
			
		|||
* );
 | 
			
		||||
* searxng.image_thumbnail_layout.watch();
 | 
			
		||||
*/
 | 
			
		||||
function(r,c){function t(t,e,a,n,i,s){this.container_selector=t,this.results_selector=e,this.img_selector=a,this.verticalMargin=n,this.horizontalMargin=i,this.maxHeight=s,this.isAlignDone=!0}t.prototype._getHeigth=function(t,e){for(var a,n=0,i=0;i<t.length;i++)0<(a=t[i]).naturalWidth&&0<a.naturalHeight?n+=a.naturalWidth/a.naturalHeight:n+=1;return(e-t.length*this.verticalMargin)/n},t.prototype._setSize=function(t,e){for(var a,n,i=t.length,s=0;s<i;s++)n=0<(a=t[s]).naturalWidth&&0<a.naturalHeight?e*a.naturalWidth/a.naturalHeight:e,a.style.width=n+"px",a.style.height=e+"px",a.style.marginLeft=this.horizontalMargin+"px",a.style.marginTop=this.horizontalMargin+"px",a.style.marginRight=this.verticalMargin-7+"px",a.style.marginBottom=this.verticalMargin-7+"px",(n=a.parentNode.parentNode).classList.contains("js")||n.classList.add("js")},t.prototype._alignImgs=function(t){for(var e,a,n,i,s=c.querySelector(this.container_selector),o=window.getComputedStyle(s),r=parseInt(o.getPropertyValue("padding-left"),10),o=parseInt(o.getPropertyValue("padding-right"),10),l=s.clientWidth-r-o;0<t.length;){for(e=!0,n=1;n<=t.length&&e;n++)a=t.slice(0,n),(i=this._getHeigth(a,l))<this.maxHeight&&(this._setSize(a,i),t=t.slice(n),e=!1);if(e){this._setSize(a,Math.min(this.maxHeight,i));break}}},t.prototype.align=function(){for(var t=c.querySelectorAll(this.results_selector),e=t.length,a=null,n=null,i=[],s=0;s<e;s++)(n=t[s]).previousElementSibling!==a&&0<i.length&&(this._alignImgs(i),i=[]),i.push(n.querySelector(this.img_selector)),a=n;0<i.length&&this._alignImgs(i)},t.prototype.watch=function(){var t,e,a=this,n=c.querySelectorAll(this.results_selector),i=n.length;function s(t){t.originalTarget.src=r.searxng.static_path+r.searxng.theme.img_load_error}function o(){a.isAlignDone&&(a.isAlignDone=!1,setTimeout(function(){a.align(),a.isAlignDone=!0},100))}for(r.addEventListener("pageshow",o),r.addEventListener("load",o),r.addEventListener("resize",o),t=0;t<i;t++)null!=(e=n[t].querySelector(this.img_selector))&&(e.addEventListener("load",o),e.addEventListener("error",o),r.searxng.theme.img_load_error&&e.addEventListener("error",s,{once:!0}))},r.searxng.ImageLayout=t}(window,document);
 | 
			
		||||
function(s,c){function t(t,e,n,a,i,o){this.container_selector=t,this.results_selector=e,this.img_selector=n,this.verticalMargin=a,this.horizontalMargin=i,this.maxHeight=o,this.trottleCallToAlign=null,this.alignAfterThrotteling=!1}t.prototype._getHeigth=function(t,e){for(var n,a=0,i=0;i<t.length;i++)0<(n=t[i]).naturalWidth&&0<n.naturalHeight?a+=n.naturalWidth/n.naturalHeight:a+=1;return(e-t.length*this.verticalMargin)/a},t.prototype._setSize=function(t,e){for(var n,a,i=t.length,o=0;o<i;o++)a=0<(n=t[o]).naturalWidth&&0<n.naturalHeight?e*n.naturalWidth/n.naturalHeight:e,n.setAttribute("width",Math.round(a)),n.setAttribute("height",Math.round(e)),n.style.marginLeft=Math.round(this.horizontalMargin)+"px",n.style.marginTop=Math.round(this.horizontalMargin)+"px",n.style.marginRight=Math.round(this.verticalMargin-7)+"px",n.style.marginBottom=Math.round(this.verticalMargin-7)+"px",(a=n.parentNode.parentNode).classList.contains("js")||a.classList.add("js")},t.prototype._alignImgs=function(t){for(var e,n,a,i,o=c.querySelector(this.container_selector),s=window.getComputedStyle(o),r=parseInt(s.getPropertyValue("padding-left"),10),s=parseInt(s.getPropertyValue("padding-right"),10),l=o.clientWidth-r-s;0<t.length;){for(e=!0,a=1;a<=t.length&&e;a++)n=t.slice(0,a),(i=this._getHeigth(n,l))<this.maxHeight&&(this._setSize(n,i),t=t.slice(a),e=!1);if(e){this._setSize(n,Math.min(this.maxHeight,i));break}}},t.prototype.throttleAlign=function(){var t=this;t.trottleCallToAlign?t.alignAfterThrotteling=!0:(t.alignAfterThrotteling=!1,t.align(),t.trottleCallToAlign=setTimeout(function(){t.alignAfterThrotteling&&t.align(),t.alignAfterThrotteling=!1,t.trottleCallToAlign=null},20))},t.prototype.align=function(){for(var t=c.querySelectorAll(this.results_selector),e=t.length,n=null,a=null,i=[],o=0;o<e;o++)(a=t[o]).previousElementSibling!==n&&0<i.length&&(this._alignImgs(i),i=[]),i.push(a.querySelector(this.img_selector)),n=a;0<i.length&&this._alignImgs(i)},t.prototype._monitorImages=function(){var t,e,n=this.throttleAlign.bind(this),a=c.querySelectorAll(this.results_selector),i=a.length;function o(t){t.originalTarget.src=s.searxng.static_path+s.searxng.theme.img_load_error}for(t=0;t<i;t++)null==(e=a[t].querySelector(this.img_selector))||e.classList.contains("aligned")||(e.addEventListener("load",n),e.addEventListener("error",n),e.addEventListener("timeout",n),s.searxng.theme.img_load_error&&e.addEventListener("error",o,{once:!0}),e.classList.add("aligned"))},t.prototype.watch=function(){var t=this.throttleAlign.bind(this),a=(s.addEventListener("pageshow",t),s.addEventListener("load",t),s.addEventListener("resize",t),this._monitorImages(),this);let e=new MutationObserver(e=>{let n=!1;for(let t=0;t<e.length;t++)if(0<e[t].addedNodes.length&&e[t].addedNodes[0].classList.contains("result")){n=!0;break}n&&a._monitorImages()});e.observe(c.querySelector(this.container_selector),{childList:!0,subtree:!0,attributes:!1,characterData:!1})},s.searxng.ImageLayout=t}(window,document);
 | 
			
		||||
//# sourceMappingURL=searxng.min.js.map
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -19,6 +19,7 @@ window.searxng = (function(d) {
 | 
			
		|||
 | 
			
		||||
    return {
 | 
			
		||||
        autocompleter: script.getAttribute('data-autocompleter') === 'true',
 | 
			
		||||
        infinite_scroll: script.getAttribute('data-infinite-scroll') === 'true',
 | 
			
		||||
        method: script.getAttribute('data-method'),
 | 
			
		||||
        translations: JSON.parse(script.getAttribute('data-translations'))
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										50
									
								
								searx/static/themes/oscar/src/js/infinite_scroll.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								searx/static/themes/oscar/src/js/infinite_scroll.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
$(document).ready(function() {
 | 
			
		||||
    function hasScrollbar() {
 | 
			
		||||
        var root = document.compatMode=='BackCompat'? document.body : document.documentElement;
 | 
			
		||||
        return root.scrollHeight>root.clientHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function loadNextPage() {
 | 
			
		||||
        var formData = $('#pagination form:last').serialize();
 | 
			
		||||
        if (formData) {
 | 
			
		||||
            $('#pagination').html('<div class="loading-spinner"></div>');
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                url: $('#search_form').prop('action'),
 | 
			
		||||
                data: formData,
 | 
			
		||||
                dataType: 'html',
 | 
			
		||||
                success: function(data) {
 | 
			
		||||
                    var body = $(data);
 | 
			
		||||
                    $('#pagination').remove();
 | 
			
		||||
                    $('#main_results').append('<hr/>');
 | 
			
		||||
                    $('#main_results').append(body.find('.result'));
 | 
			
		||||
                    $('#main_results').append(body.find('#pagination'));
 | 
			
		||||
                    if(!hasScrollbar()) {
 | 
			
		||||
                        loadNextPage();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (searxng.infinite_scroll) {
 | 
			
		||||
        var win = $(window);
 | 
			
		||||
        $("html").addClass('infinite_scroll');
 | 
			
		||||
        if(!hasScrollbar()) {
 | 
			
		||||
            loadNextPage();
 | 
			
		||||
        }
 | 
			
		||||
        win.on('scroll', function() {
 | 
			
		||||
            if ($(document).height() - win.height() - win.scrollTop() < 150) {
 | 
			
		||||
                loadNextPage();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
    0%   { transform: rotate(0deg) }
 | 
			
		||||
    100% { transform: rotate(360deg) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.loading-spinner {
 | 
			
		||||
    animation-duration: 0.75s;
 | 
			
		||||
    animation-iteration-count: infinite;
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,7 @@
 | 
			
		|||
    border-radius: 50% !important;
 | 
			
		||||
    margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
#pagination button {
 | 
			
		||||
 | 
			
		||||
html.infinite_scroll #pagination button {
 | 
			
		||||
	visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
@import "../../../../__common__/less/result_templates.less";
 | 
			
		||||
@import "../../less/result_templates.less";
 | 
			
		||||
@import "../../less/preferences.less";
 | 
			
		||||
@import "../infinite_scroll.less";
 | 
			
		||||
@import "../../generated/pygments-logicodev.less";
 | 
			
		||||
 | 
			
		||||
@stacked-bar-chart: rgb(213, 216, 215, 1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
@import "../../../../__common__/less/result_templates.less";
 | 
			
		||||
@import "../../less/result_templates.less";
 | 
			
		||||
@import "../../less/preferences.less";
 | 
			
		||||
@import "../infinite_scroll.less";
 | 
			
		||||
@import "../../generated/pygments-logicodev.less";
 | 
			
		||||
 | 
			
		||||
@import "navbar.less";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
@import "../../../../__common__/less/result_templates.less";
 | 
			
		||||
@import "../../less/result_templates.less";
 | 
			
		||||
@import "../../less/preferences.less";
 | 
			
		||||
@import "../infinite_scroll.less";
 | 
			
		||||
@import "../../generated/pygments-pointhi.less";
 | 
			
		||||
 | 
			
		||||
@import "footer.less";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6
									
								
								searx/static/themes/simple/js/searxng.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								searx/static/themes/simple/js/searxng.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -59,43 +59,45 @@ window.searxng = (function (w, d) {
 | 
			
		|||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  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; }
 | 
			
		||||
      };
 | 
			
		||||
  searxng.http = function (method, url, data = null) {
 | 
			
		||||
    return new Promise(function (resolve, reject) {
 | 
			
		||||
      try {
 | 
			
		||||
        var req = new XMLHttpRequest();
 | 
			
		||||
        req.open(method, url, true);
 | 
			
		||||
        req.timeout = 20000;
 | 
			
		||||
 | 
			
		||||
    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));
 | 
			
		||||
          }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
      // 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"));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        req.ontimeout = function () {
 | 
			
		||||
          reject(Error("Timeout"));
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // 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;
 | 
			
		||||
        // Make the request
 | 
			
		||||
        if (data) {
 | 
			
		||||
          req.send(data)
 | 
			
		||||
        } else {
 | 
			
		||||
          req.send();
 | 
			
		||||
        }
 | 
			
		||||
      } catch (ex) {
 | 
			
		||||
        reject(ex);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  searxng.loadStyle = function (src) {
 | 
			
		||||
| 
						 | 
				
			
			@ -148,5 +150,16 @@ window.searxng = (function (w, d) {
 | 
			
		|||
    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];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  searxng.endpoint = getEndpoint();
 | 
			
		||||
 | 
			
		||||
  return searxng;
 | 
			
		||||
})(window, document);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										88
									
								
								searx/static/themes/simple/src/js/main/infinite_scroll.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								searx/static/themes/simple/src/js/main/infinite_scroll.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
// SPDX-License-Identifier: AGPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
/* global searxng */
 | 
			
		||||
 | 
			
		||||
searxng.ready(function () {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  searxng.infinite_scroll_supported = (
 | 
			
		||||
    'IntersectionObserver' in window &&
 | 
			
		||||
    'IntersectionObserverEntry' in window &&
 | 
			
		||||
    'intersectionRatio' in window.IntersectionObserverEntry.prototype);
 | 
			
		||||
 | 
			
		||||
  if (searxng.endpoint !== 'results') {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!searxng.infinite_scroll_supported) {
 | 
			
		||||
    console.log('IntersectionObserver not supported');
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let d = document;
 | 
			
		||||
  var onlyImages = d.getElementById('results').classList.contains('only_template_images');
 | 
			
		||||
 | 
			
		||||
  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 loadNextPage (callback) {
 | 
			
		||||
    var form = d.querySelector('#pagination form.next_page');
 | 
			
		||||
    if (!form) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    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();
 | 
			
		||||
        if (articleList.length > 0 && !onlyImages) {
 | 
			
		||||
          // do not add <hr> element when there are only images
 | 
			
		||||
          d.querySelector('#urls').appendChild(d.createElement('hr'));
 | 
			
		||||
        }
 | 
			
		||||
        articleList.forEach(articleElement => {
 | 
			
		||||
          d.querySelector('#urls').appendChild(articleElement);
 | 
			
		||||
        });
 | 
			
		||||
        if (paginationElement) {
 | 
			
		||||
          d.querySelector('#results').appendChild(paginationElement);
 | 
			
		||||
          callback();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    ).catch(
 | 
			
		||||
      function (err) {
 | 
			
		||||
        console.log(err);
 | 
			
		||||
        var e = d.createElement('div');
 | 
			
		||||
        e.textContent = searxng.translations.error_loading_next_page;
 | 
			
		||||
        e.classList.add('dialog-error');
 | 
			
		||||
        e.setAttribute('role', 'alert');
 | 
			
		||||
        replaceChildrenWith(d.querySelector('#pagination'), [ e ]);
 | 
			
		||||
      }
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (searxng.infinite_scroll && searxng.infinite_scroll_supported) {
 | 
			
		||||
    const intersectionObserveOptions = {
 | 
			
		||||
      rootMargin: "20rem",
 | 
			
		||||
    };
 | 
			
		||||
    const observedSelector = 'article.result:last-child';
 | 
			
		||||
    const observer = new IntersectionObserver(entries => {
 | 
			
		||||
      const paginationEntry = entries[0];
 | 
			
		||||
      if (paginationEntry.isIntersecting) {
 | 
			
		||||
        observer.unobserve(paginationEntry.target);
 | 
			
		||||
        loadNextPage(() => observer.observe(d.querySelector(observedSelector), intersectionObserveOptions));
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    observer.observe(d.querySelector(observedSelector), intersectionObserveOptions);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,10 @@
 | 
			
		|||
(function (w, d, searxng) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  if (searxng.endpoint !== 'preferences') {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  searxng.ready(function () {
 | 
			
		||||
    let engine_descriptions = null;
 | 
			
		||||
    function load_engine_descriptions () {
 | 
			
		||||
| 
						 | 
				
			
			@ -19,10 +23,8 @@
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (d.querySelector('body[class="preferences_endpoint"]')) {
 | 
			
		||||
      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);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
})(window, document, window.searxng);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,10 @@
 | 
			
		|||
(function (w, d, searxng) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  if (searxng.endpoint !== 'results') {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -771,15 +771,19 @@ article[data-vim-selected].category-social {
 | 
			
		|||
  margin: 1rem @results-tablet-offset 0 @results-tablet-offset;
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 100%;
 | 
			
		||||
  grid-template-rows: min-content min-content 1fr min-content min-content;
 | 
			
		||||
  grid-template-rows: min-content min-content min-content 1fr min-content;
 | 
			
		||||
  gap: 0;
 | 
			
		||||
  grid-template-areas:
 | 
			
		||||
    "corrections"
 | 
			
		||||
    "urls"
 | 
			
		||||
    "answers"
 | 
			
		||||
    "sidebar"
 | 
			
		||||
    "urls"
 | 
			
		||||
    "pagination";
 | 
			
		||||
 | 
			
		||||
  #sidebar {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  #urls {
 | 
			
		||||
    width: inherit;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,6 +100,7 @@
 | 
			
		|||
    <script src="{{ url_for('static', filename='js/searxng.min.js') }}"
 | 
			
		||||
            data-method="{{ method or 'POST' }}"
 | 
			
		||||
            data-autocompleter="{% if autocomplete %}true{% else %}false{% endif %}"
 | 
			
		||||
            data-infinite-scroll="{% if infinite_scroll %}true{% else %}false{% endif %}"
 | 
			
		||||
            data-translations="{{ translations }}"></script>
 | 
			
		||||
    {% for script in scripts %}
 | 
			
		||||
    {{""}}<script src="{{ url_for('static', filename=script) }}"></script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -248,6 +248,17 @@
 | 
			
		|||
                        {{ preferences_item_footer(info, label, rtl) }}
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
 | 
			
		||||
                        {% if 'infinite_scroll' not in locked_preferences %}
 | 
			
		||||
                        {% set label = _('Infinite scroll') %}
 | 
			
		||||
                        {% set info = _('Automatically load next page when scrolling to bottom of current page') %}
 | 
			
		||||
                        {{ preferences_item_header(info, label, rtl, 'infinite_scroll') }}
 | 
			
		||||
                            <select class="form-control {{ custom_select_class(rtl) }}" name="infinite_scroll" id="infinite_scroll">
 | 
			
		||||
                                <option value="1" {% if infinite_scroll %}selected="selected"{% endif %}>{{ _('On') }}</option>
 | 
			
		||||
                                <option value="0" {% if not infinite_scroll %}selected="selected"{% endif %}>{{ _('Off')}}</option>
 | 
			
		||||
                            </select>
 | 
			
		||||
                        {{ preferences_item_footer(info, label, rtl) }}
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
 | 
			
		||||
                        {{ plugin_of_category('ui' )}}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </fieldset>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
          data-method="{{ method or 'POST' }}"
 | 
			
		||||
          data-autocompleter="{% if autocomplete %}true{% else %}false{% endif %}"
 | 
			
		||||
          data-search-on-category-select="{{ 'true' if 'plugins/js/search_on_category_select.js' in scripts else 'false'}}"
 | 
			
		||||
          data-infinite-scroll="{{ 'true' if 'plugins/js/infinite_scroll.js' in scripts else 'false' }}"
 | 
			
		||||
          data-infinite-scroll="{% if infinite_scroll %}true{% else %}false{% endif %}"
 | 
			
		||||
          data-hotkeys="{{ 'true' if 'plugins/js/vim_hotkeys.js' in scripts else 'false' }}"
 | 
			
		||||
          data-static-path="{{ url_for('static', filename='themes/simple') }}/"
 | 
			
		||||
          data-translations="{{ translations }}"></script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -226,6 +226,18 @@
 | 
			
		|||
      <div class="description">{{_('Open result links on new browser tabs') }}</div>
 | 
			
		||||
    </fieldset>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {% if 'infinite_scroll' not in locked_preferences %}
 | 
			
		||||
    <fieldset>
 | 
			
		||||
      <legend>{{ _('Infinite scroll') }}</legend>
 | 
			
		||||
      <p class="value">
 | 
			
		||||
        <select name='infinite_scroll'>
 | 
			
		||||
          <option value="1" {% if infinite_scroll %}selected="selected"{% endif %}>{{ _('On') }}</option>
 | 
			
		||||
          <option value="0" {% if not infinite_scroll %}selected="selected"{% endif %}>{{ _('Off')}}</option>
 | 
			
		||||
        </select>
 | 
			
		||||
      </p>
 | 
			
		||||
      <div class="description">{{ _('Automatically load next page when scrolling to bottom of current page') }}</div>
 | 
			
		||||
    </fieldset>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {{ plugin_preferences('ui') }}
 | 
			
		||||
  {{ tab_footer() }}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -431,6 +431,8 @@ def get_translations():
 | 
			
		|||
        'no_item_found': gettext('No item found'),
 | 
			
		||||
        # /preferences: the source of the engine description (wikipedata, wikidata, website)
 | 
			
		||||
        'Source': gettext('Source'),
 | 
			
		||||
        # infinite scroll
 | 
			
		||||
        'error_loading_next_page': gettext('Error loading the next page'),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -463,6 +465,7 @@ def render(template_name: str, override_theme: str = None, **kwargs):
 | 
			
		|||
    kwargs['preferences'] = request.preferences
 | 
			
		||||
    kwargs['method'] = request.preferences.get_value('method')
 | 
			
		||||
    kwargs['autocomplete'] = request.preferences.get_value('autocomplete')
 | 
			
		||||
    kwargs['infinite_scroll'] = request.preferences.get_value('infinite_scroll')
 | 
			
		||||
    kwargs['results_on_new_tab'] = request.preferences.get_value('results_on_new_tab')
 | 
			
		||||
    kwargs['advanced_search'] = request.preferences.get_value('advanced_search')
 | 
			
		||||
    kwargs['query_in_title'] = request.preferences.get_value('query_in_title')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue