Update upstream sources to 0.9
This commit is contained in:
parent
88e17d06a8
commit
9c7a55e0c0
|
@ -0,0 +1,20 @@
|
|||
[run]
|
||||
branch = True
|
||||
source =
|
||||
searx/engines
|
||||
searx/__init__.py
|
||||
searx/autocomplete.py
|
||||
searx/https_rewrite.py
|
||||
searx/languages.py
|
||||
searx/search.py
|
||||
searx/testing.py
|
||||
searx/utils.py
|
||||
searx/webapp.py
|
||||
|
||||
[report]
|
||||
show_missing = True
|
||||
exclude_lines =
|
||||
if __name__ == .__main__.:
|
||||
|
||||
[html]
|
||||
directory = coverage
|
|
@ -0,0 +1,17 @@
|
|||
.coverage
|
||||
.installed.cfg
|
||||
engines.cfg
|
||||
env
|
||||
robot_log.html
|
||||
robot_output.xml
|
||||
robot_report.html
|
||||
test_basic/
|
||||
setup.cfg
|
||||
|
||||
*.pyc
|
||||
*/*.pyc
|
||||
*~
|
||||
|
||||
node_modules/
|
||||
|
||||
.tx/
|
|
@ -0,0 +1,3 @@
|
|||
strictness: high
|
||||
ignore-paths:
|
||||
- bootstrap.py
|
|
@ -0,0 +1,32 @@
|
|||
sudo: false
|
||||
cache:
|
||||
- pip
|
||||
- npm
|
||||
- directories:
|
||||
- $HOME/.cache/pip
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
before_install:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
- npm install less grunt-cli
|
||||
- ( cd searx/static/themes/oscar;npm install; cd - )
|
||||
install:
|
||||
- ./manage.sh update_dev_packages
|
||||
- pip install coveralls
|
||||
script:
|
||||
- ./manage.sh pep8_check
|
||||
- ./manage.sh styles
|
||||
- ./manage.sh grunt_build
|
||||
- ./manage.sh py_test_coverage
|
||||
- ./manage.sh robot_tests
|
||||
after_success:
|
||||
coveralls
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#searx"
|
||||
template:
|
||||
- "%{repository}/#%{build_number}/%{branch} (%{author}): %{message} %{build_url}"
|
||||
on_success: change
|
|
@ -44,3 +44,10 @@ generally made searx better:
|
|||
- Kirill Isakov
|
||||
- Guilhem Bonnefille
|
||||
- Marc Abonce Seguin
|
||||
|
||||
- @jibe-b
|
||||
- Christian Pietsch @pietsch
|
||||
- @Maxqia
|
||||
- Ashutosh Das @pyprism
|
||||
- YuLun Shih @imZack
|
||||
- Dmitry Mikhirev @mikhirev
|
||||
|
|
|
@ -1,3 +1,41 @@
|
|||
0.9.0 2016.05.24
|
||||
================
|
||||
|
||||
- New search category: science
|
||||
- New engines
|
||||
|
||||
- Wolframalpha (science)
|
||||
- Frinkiac (images)
|
||||
- Arch Linux (it)
|
||||
- BASE - Bielefeld Academic Search Engine (science)
|
||||
- Dokuwiki (general)
|
||||
- Nyaa.se (files, images, music, video)
|
||||
- Reddit (general, images, news, social media)
|
||||
- Torrentz.eu (files, music, video)
|
||||
- Tokyo Toshokan (files, music, video)
|
||||
- F-Droid (files)
|
||||
- Erowid (general)
|
||||
- Bitbucket (it)
|
||||
- GitLab (it)
|
||||
- Geektimes (it)
|
||||
- Habrahabr (it)
|
||||
- New plugins
|
||||
|
||||
- Open links in new tab
|
||||
- Vim hotkeys for better navigation
|
||||
- Wikipedia/Mediawiki engine improvements
|
||||
- Configurable instance name
|
||||
- Configurable connection pool size
|
||||
- Fixed broken google engine
|
||||
- Better docker image
|
||||
- Images in standard results
|
||||
- Fixed and refactored user settings (Warning: backward incompatibility - you have to reset your custom engine preferences)
|
||||
- Suspending engines on errors
|
||||
- Simplified development/deployment tooling
|
||||
- Translation updates
|
||||
- Multilingual autocompleter
|
||||
- Qwant autocompleter backend
|
||||
|
||||
0.8.1 2015.12.22
|
||||
================
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ Installation
|
|||
``git clone git@github.com:asciimoo/searx.git && cd searx``
|
||||
- install dependencies: ``./manage.sh update_packages``
|
||||
- edit your
|
||||
`settings.yml <https://github.com/asciimoo/searx/blob/master/settings.yml>`__
|
||||
`settings.yml <https://github.com/asciimoo/searx/blob/master/searx/settings.yml>`__
|
||||
(set your ``secret_key``!)
|
||||
- run ``python searx/webapp.py`` to start the application
|
||||
|
||||
|
|
|
@ -54,6 +54,12 @@ def response(resp):
|
|||
|
||||
dom = html.fromstring(resp.text)
|
||||
|
||||
try:
|
||||
results.append({'number_of_results': int(dom.xpath('//span[@class="sb_count"]/text()')[0]
|
||||
.split()[0].replace(',', ''))})
|
||||
except:
|
||||
pass
|
||||
|
||||
# parse results
|
||||
for result in dom.xpath('//div[@class="sa_cc"]'):
|
||||
link = result.xpath('.//h3/a')[0]
|
||||
|
@ -66,10 +72,6 @@ def response(resp):
|
|||
'title': title,
|
||||
'content': content})
|
||||
|
||||
# return results if something is found
|
||||
if results:
|
||||
return results
|
||||
|
||||
# parse results again if nothing is found yet
|
||||
for result in dom.xpath('//li[@class="b_algo"]'):
|
||||
link = result.xpath('.//h2/a')[0]
|
||||
|
|
|
@ -9,13 +9,13 @@ categories = []
|
|||
url = 'https://download.finance.yahoo.com/d/quotes.csv?e=.csv&f=sl1d1t1&s={query}=X'
|
||||
weight = 100
|
||||
|
||||
parser_re = re.compile(u'^\W*(\d+(?:\.\d+)?)\W*([^.0-9].+)\W+in?\W+([^\.]+)\W*$', re.I) # noqa
|
||||
parser_re = re.compile(u'.*?(\d+(?:\.\d+)?) ([^.0-9]+) (?:in|to) ([^.0-9]+)', re.I) # noqa
|
||||
|
||||
db = 1
|
||||
|
||||
|
||||
def normalize_name(name):
|
||||
name = name.lower().replace('-', ' ')
|
||||
name = name.lower().replace('-', ' ').rstrip('s')
|
||||
name = re.sub(' +', ' ', name)
|
||||
return unicodedata.normalize('NFKD', name).lower()
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ search_string = 'search?{query}'\
|
|||
'&s={offset}'\
|
||||
'&format=json'\
|
||||
'&qh=0'\
|
||||
'&rxiwd={rxiwd}'\
|
||||
'&qlang={lang}'\
|
||||
'&ff={safesearch}'
|
||||
'&ff={safesearch}'\
|
||||
'&rxikd={rxikd}' # random number - 9 digits
|
||||
|
||||
# specific xpath variables
|
||||
results_xpath = '//response//result'
|
||||
|
@ -59,8 +59,7 @@ def request(query, params):
|
|||
search_path = search_string.format(query=urlencode({'q': query}),
|
||||
offset=offset,
|
||||
number_of_results=number_of_results,
|
||||
rxiwd=1,
|
||||
# rand=int(time()),
|
||||
rxikd=str(time())[:9],
|
||||
lang=language,
|
||||
safesearch=safesearch)
|
||||
|
||||
|
|
|
@ -77,6 +77,13 @@ def response(resp):
|
|||
|
||||
dom = html.fromstring(resp.text)
|
||||
|
||||
try:
|
||||
results_num = int(dom.xpath('//div[@class="compPagination"]/span[last()]/text()')[0]
|
||||
.split()[0].replace(',', ''))
|
||||
results.append({'number_of_results': results_num})
|
||||
except:
|
||||
pass
|
||||
|
||||
# parse results
|
||||
for result in dom.xpath(results_xpath):
|
||||
try:
|
||||
|
|
|
@ -23,7 +23,8 @@ from searx.plugins import (https_rewrite,
|
|||
open_results_on_new_tab,
|
||||
self_info,
|
||||
search_on_category_select,
|
||||
tracker_url_remover)
|
||||
tracker_url_remover,
|
||||
vim_hotkeys)
|
||||
|
||||
required_attrs = (('name', str),
|
||||
('description', str),
|
||||
|
@ -77,3 +78,4 @@ plugins.register(open_results_on_new_tab)
|
|||
plugins.register(self_info)
|
||||
plugins.register(search_on_category_select)
|
||||
plugins.register(tracker_url_remover)
|
||||
plugins.register(vim_hotkeys)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
from flask.ext.babel import gettext
|
||||
|
||||
name = gettext('Vim-like hotkeys')
|
||||
description = gettext('Navigate search results with Vim-like hotkeys '
|
||||
'(JavaScript required). '
|
||||
'Press "h" key on main or result page to get help.')
|
||||
default_on = False
|
||||
|
||||
js_dependencies = ('plugins/js/vim_hotkeys.js',)
|
||||
css_dependencies = ('plugins/css/vim_hotkeys.css',)
|
|
@ -41,14 +41,18 @@ class HTTPAdapterWithConnParams(requests.adapters.HTTPAdapter):
|
|||
block=self._pool_block, **self._conn_params)
|
||||
|
||||
|
||||
connect = settings['outgoing'].get('pool_connections', 100) # Magic number kept from previous code
|
||||
maxsize = settings['outgoing'].get('pool_maxsize', requests.adapters.DEFAULT_POOLSIZE) # Picked from constructor
|
||||
if settings['outgoing'].get('source_ips'):
|
||||
http_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=100, source_address=(source_ip, 0))
|
||||
http_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize,
|
||||
source_address=(source_ip, 0))
|
||||
for source_ip in settings['outgoing']['source_ips'])
|
||||
https_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=100, source_address=(source_ip, 0))
|
||||
https_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize,
|
||||
source_address=(source_ip, 0))
|
||||
for source_ip in settings['outgoing']['source_ips'])
|
||||
else:
|
||||
http_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=100), ))
|
||||
https_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=100), ))
|
||||
http_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize), ))
|
||||
https_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize), ))
|
||||
|
||||
|
||||
class SessionSinglePool(requests.Session):
|
||||
|
|
|
@ -181,7 +181,7 @@ class EnginesSetting(SwitchableSetting):
|
|||
return [item[len('engine_'):].replace('_', ' ').replace(' ', '__') for item in items]
|
||||
|
||||
def transform_values(self, values):
|
||||
if len(values) == 1 and values[0] == '':
|
||||
if len(values) == 1 and next(iter(values)) == '':
|
||||
return list()
|
||||
transformed_values = []
|
||||
for value in values:
|
||||
|
@ -229,6 +229,7 @@ class Preferences(object):
|
|||
|
||||
self.engines = EnginesSetting('engines', choices=engines)
|
||||
self.plugins = PluginsSetting('plugins', choices=plugins)
|
||||
self.unknown_params = {}
|
||||
|
||||
def parse_cookies(self, input_data):
|
||||
for user_setting_name, user_setting in input_data.iteritems():
|
||||
|
@ -254,6 +255,8 @@ class Preferences(object):
|
|||
enabled_categories.append(user_setting_name[len('category_'):])
|
||||
elif user_setting_name.startswith('plugin_'):
|
||||
disabled_plugins.append(user_setting_name)
|
||||
else:
|
||||
self.unknown_params[user_setting_name] = user_setting
|
||||
self.key_value_settings['categories'].parse_form(enabled_categories)
|
||||
self.engines.parse_form(disabled_engines)
|
||||
self.plugins.parse_form(disabled_plugins)
|
||||
|
@ -268,4 +271,6 @@ class Preferences(object):
|
|||
user_setting.save(user_setting_name, resp)
|
||||
self.engines.save(resp)
|
||||
self.plugins.save(resp)
|
||||
for k, v in self.unknown_params.items():
|
||||
resp.set_cookie(k, v, max_age=COOKIE_MAX_AGE)
|
||||
return resp
|
||||
|
|
|
@ -99,6 +99,7 @@ class ResultContainer(object):
|
|||
self._infobox_ids = {}
|
||||
self.suggestions = set()
|
||||
self.answers = set()
|
||||
self.number_of_results = 0
|
||||
|
||||
def extend(self, engine_name, results):
|
||||
for result in list(results):
|
||||
|
@ -111,6 +112,9 @@ class ResultContainer(object):
|
|||
elif 'infobox' in result:
|
||||
self._merge_infobox(result)
|
||||
results.remove(result)
|
||||
elif 'number_of_results' in result:
|
||||
self.number_of_results = max(self.number_of_results, result['number_of_results'])
|
||||
results.remove(result)
|
||||
|
||||
with RLock():
|
||||
engines[engine_name].stats['search_count'] += 1
|
||||
|
|
|
@ -21,6 +21,8 @@ ui:
|
|||
outgoing: # communication with search engines
|
||||
request_timeout : 2.0 # seconds
|
||||
useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
|
||||
pool_connections : 100 # Number of different hosts
|
||||
pool_maxsize : 10 # Number of simultaneous requests by host
|
||||
# uncomment below section if you want to use a proxy
|
||||
# see http://docs.python-requests.org/en/latest/user/advanced/#proxies
|
||||
# SOCKS proxies are not supported : see https://github.com/kennethreitz/requests/pull/478
|
||||
|
@ -38,6 +40,17 @@ engines:
|
|||
engine : archlinux
|
||||
shortcut : al
|
||||
|
||||
- name : archive is
|
||||
engine : xpath
|
||||
search_url : https://archive.is/{query}
|
||||
url_xpath : (//div[@class="TEXT-BLOCK"]/a)/@href
|
||||
title_xpath : (//div[@class="TEXT-BLOCK"]/a)
|
||||
content_xpath : //div[@class="TEXT-BLOCK"]/ul/li
|
||||
categories : general
|
||||
timeout : 7.0
|
||||
disabled : True
|
||||
shortcut : ai
|
||||
|
||||
- name : base
|
||||
engine : base
|
||||
shortcut : bs
|
||||
|
@ -221,8 +234,8 @@ engines:
|
|||
engine : xpath
|
||||
paging : True
|
||||
search_url : https://geektimes.ru/search/page{pageno}/?q={query}
|
||||
url_xpath : //div[@class="search_results"]//a[@class="post_title"]/@href
|
||||
title_xpath : //div[@class="search_results"]//a[@class="post_title"]
|
||||
url_xpath : //div[@class="search_results"]//a[@class="post__title_link"]/@href
|
||||
title_xpath : //div[@class="search_results"]//a[@class="post__title_link"]
|
||||
content_xpath : //div[@class="search_results"]//div[contains(@class, "content")]
|
||||
categories : it
|
||||
timeout : 4.0
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
.vim-hotkeys-help {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 9999999;
|
||||
overflow-y: auto;
|
||||
max-height: 80%;
|
||||
box-shadow: 0 0 1em;
|
||||
}
|
||||
|
||||
.dflex {
|
||||
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
|
||||
display: -ms-flexbox; /* TWEENER - IE 10 */
|
||||
display: -webkit-flex; /* NEW - Chrome */
|
||||
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||
}
|
||||
|
||||
.iflex {
|
||||
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
-moz-box-flex: 1; /* OLD - Firefox 19- */
|
||||
-webkit-flex: 1; /* Chrome */
|
||||
-ms-flex: 1; /* IE 10 */
|
||||
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||
}
|
|
@ -0,0 +1,336 @@
|
|||
$(document).ready(function() {
|
||||
highlightResult('top')();
|
||||
|
||||
$('.result').on('click', function() {
|
||||
highlightResult($(this))();
|
||||
});
|
||||
|
||||
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: pageButtonClick(0),
|
||||
des: 'go to previous page',
|
||||
cat: 'Results'
|
||||
},
|
||||
78: {
|
||||
key: 'n',
|
||||
fun: pageButtonClick(1),
|
||||
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'
|
||||
}
|
||||
};
|
||||
|
||||
$(document).keyup(function(e) {
|
||||
// check for modifiers so we don't break browser's hotkeys
|
||||
if (vimKeys.hasOwnProperty(e.keyCode)
|
||||
&& !e.ctrlKey
|
||||
&& !e.altKey
|
||||
&& !e.shiftKey
|
||||
&& !e.metaKey)
|
||||
{
|
||||
if (e.keyCode === 27) {
|
||||
if (e.target.tagName.toLowerCase() === 'input') {
|
||||
vimKeys[e.keyCode].fun();
|
||||
}
|
||||
} else {
|
||||
if (e.target === document.body) {
|
||||
vimKeys[e.keyCode].fun();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function highlightResult(which) {
|
||||
return function() {
|
||||
var current = $('.result[data-vim-selected]');
|
||||
if (current.length === 0) {
|
||||
current = $('.result:first');
|
||||
if (current.length === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var next;
|
||||
|
||||
if (typeof which !== 'string') {
|
||||
next = which;
|
||||
} else {
|
||||
switch (which) {
|
||||
case 'visible':
|
||||
var top = $(window).scrollTop();
|
||||
var bot = top + $(window).height();
|
||||
var results = $('.result');
|
||||
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
next = $(results[i]);
|
||||
var etop = next.offset().top;
|
||||
var ebot = etop + next.height();
|
||||
|
||||
if ((ebot <= bot) && (etop > top)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'down':
|
||||
next = current.next('.result');
|
||||
if (next.length === 0) {
|
||||
next = $('.result:first');
|
||||
}
|
||||
break;
|
||||
case 'up':
|
||||
next = current.prev('.result');
|
||||
if (next.length === 0) {
|
||||
next = $('.result:last');
|
||||
}
|
||||
break;
|
||||
case 'bottom':
|
||||
next = $('.result:last');
|
||||
break;
|
||||
case 'top':
|
||||
default:
|
||||
next = $('.result:first');
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
current.removeAttr('data-vim-selected').removeClass('well well-sm');
|
||||
next.attr('data-vim-selected', 'true').addClass('well well-sm');
|
||||
scrollPageToSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reloadPage() {
|
||||
document.location.reload(false);
|
||||
}
|
||||
|
||||
function removeFocus() {
|
||||
if (document.activeElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
}
|
||||
|
||||
function pageButtonClick(num) {
|
||||
return function() {
|
||||
var buttons = $('div#pagination button[type="submit"]');
|
||||
if (buttons.length !== 2) {
|
||||
console.log('page navigation with this theme is not supported');
|
||||
return;
|
||||
}
|
||||
if (num >= 0 && num < buttons.length) {
|
||||
buttons[num].click();
|
||||
} else {
|
||||
console.log('pageButtonClick(): invalid argument');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function scrollPageToSelected() {
|
||||
var sel = $('.result[data-vim-selected]');
|
||||
if (sel.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var wnd = $(window);
|
||||
|
||||
var wtop = wnd.scrollTop();
|
||||
var etop = sel.offset().top;
|
||||
|
||||
var offset = 30;
|
||||
|
||||
if (wtop > etop) {
|
||||
wnd.scrollTop(etop - offset);
|
||||
} else {
|
||||
var ebot = etop + sel.height();
|
||||
var wbot = wtop + wnd.height();
|
||||
|
||||
if (wbot < ebot) {
|
||||
wnd.scrollTop(ebot - wnd.height() + 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() {
|
||||
$('input#q').focus();
|
||||
}
|
||||
|
||||
function openResult(newTab) {
|
||||
return function() {
|
||||
var link = $('.result[data-vim-selected] .result_header a');
|
||||
if (link.length) {
|
||||
var url = link.attr('href');
|
||||
if (newTab) {
|
||||
window.open(url);
|
||||
} else {
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function toggleHelp() {
|
||||
var helpPanel = $('#vim-hotkeys-help');
|
||||
if (helpPanel.length) {
|
||||
helpPanel.toggleClass('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
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 = '<div id="vim-hotkeys-help" class="well vim-hotkeys-help">';
|
||||
html += '<div class="container-fluid">';
|
||||
|
||||
html += '<div class="row">';
|
||||
html += '<div class="col-sm-12">';
|
||||
html += '<h3>How to navigate searx with Vim-like hotkeys</h3>';
|
||||
html += '</div>'; // col-sm-12
|
||||
html += '</div>'; // row
|
||||
|
||||
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 += '<div class="row dflex">';
|
||||
}
|
||||
html += '<div class="col-sm-' + (first && lastCategory ? 12 : 6) + ' dflex">';
|
||||
|
||||
html += '<div class="panel panel-default iflex">';
|
||||
html += '<div class="panel-heading">' + cat[0].cat + '</div>';
|
||||
html += '<div class="panel-body">';
|
||||
html += '<ul class="list-unstyled">';
|
||||
|
||||
for (var cj in cat) {
|
||||
html += '<li><kbd>' + cat[cj].key + '</kbd> ' + cat[cj].des + '</li>';
|
||||
}
|
||||
|
||||
html += '</ul>';
|
||||
html += '</div>'; // panel-body
|
||||
html += '</div>'; // panel
|
||||
html += '</div>'; // col-sm-*
|
||||
|
||||
if (!first || lastCategory) {
|
||||
html += '</div>'; // row
|
||||
}
|
||||
}
|
||||
|
||||
html += '</div>'; // container-fluid
|
||||
html += '</div>'; // vim-hotkeys-help
|
||||
|
||||
$('body').append(html);
|
||||
}
|
||||
});
|
File diff suppressed because one or more lines are too long
|
@ -1,88 +0,0 @@
|
|||
html{position:relative;min-height:100%}
|
||||
body{margin-bottom:80px}
|
||||
.footer{position:absolute;bottom:0;width:100%;height:60px}
|
||||
input[type=checkbox]:checked+.label_hide_if_checked,input[type=checkbox]:checked+.label_hide_if_not_checked+.label_hide_if_checked{display:none}
|
||||
input[type=checkbox]:not(:checked)+.label_hide_if_not_checked,input[type=checkbox]:not(:checked)+.label_hide_if_checked+.label_hide_if_not_checked{display:none}
|
||||
.result_header{margin-bottom:5px;margin-top:20px}.result_header .favicon{margin-bottom:-3px}
|
||||
.result_header a{vertical-align:bottom}.result_header a .highlight{font-weight:bold}
|
||||
.result-content{margin-top:5px;word-wrap:break-word}.result-content .highlight{font-weight:bold}
|
||||
.result-default{clear:both}
|
||||
.result-images{float:left !important}
|
||||
.img-thumbnail{margin:5px;max-height:128px;min-height:128px}
|
||||
.result-videos{clear:both}
|
||||
.result-torrents{clear:both}
|
||||
.result-map{clear:both}
|
||||
.result-code{clear:both}
|
||||
.suggestion_item{margin:2px 5px}
|
||||
.result_download{margin-right:5px}
|
||||
#pagination{margin-top:30px;padding-bottom:50px}
|
||||
.label-default{color:#aaa;background:#fff}
|
||||
.infobox .infobox_part{margin-bottom:20px;word-wrap:break-word;table-layout:fixed}
|
||||
.infobox .infobox_part:last-child{margin-bottom:0}
|
||||
.search_categories{margin:10px 0;text-transform:capitalize}
|
||||
.cursor-text{cursor:text !important}
|
||||
.cursor-pointer{cursor:pointer !important}
|
||||
.highlight .hll{background-color:#ffc}
|
||||
.highlight{background:#f8f8f8}
|
||||
.highlight .c{color:#408080;font-style:italic}
|
||||
.highlight .err{border:1px solid #f00}
|
||||
.highlight .k{color:#008000;font-weight:bold}
|
||||
.highlight .o{color:#666}
|
||||
.highlight .cm{color:#408080;font-style:italic}
|
||||
.highlight .cp{color:#bc7a00}
|
||||
.highlight .c1{color:#408080;font-style:italic}
|
||||
.highlight .cs{color:#408080;font-style:italic}
|
||||
.highlight .gd{color:#a00000}
|
||||
.highlight .ge{font-style:italic}
|
||||
.highlight .gr{color:#f00}
|
||||
.highlight .gh{color:#000080;font-weight:bold}
|
||||
.highlight .gi{color:#00a000}
|
||||
.highlight .go{color:#888}
|
||||
.highlight .gp{color:#000080;font-weight:bold}
|
||||
.highlight .gs{font-weight:bold}
|
||||
.highlight .gu{color:#800080;font-weight:bold}
|
||||
.highlight .gt{color:#04d}
|
||||
.highlight .kc{color:#008000;font-weight:bold}
|
||||
.highlight .kd{color:#008000;font-weight:bold}
|
||||
.highlight .kn{color:#008000;font-weight:bold}
|
||||
.highlight .kp{color:#008000}
|
||||
.highlight .kr{color:#008000;font-weight:bold}
|
||||
.highlight .kt{color:#b00040}
|
||||
.highlight .m{color:#666}
|
||||
.highlight .s{color:#ba2121}
|
||||
.highlight .na{color:#7d9029}
|
||||
.highlight .nb{color:#008000}
|
||||
.highlight .nc{color:#00f;font-weight:bold}
|
||||
.highlight .no{color:#800}
|
||||
.highlight .nd{color:#a2f}
|
||||
.highlight .ni{color:#999;font-weight:bold}
|
||||
.highlight .ne{color:#d2413a;font-weight:bold}
|
||||
.highlight .nf{color:#00f}
|
||||
.highlight .nl{color:#a0a000}
|
||||
.highlight .nn{color:#00f;font-weight:bold}
|
||||
.highlight .nt{color:#008000;font-weight:bold}
|
||||
.highlight .nv{color:#19177c}
|
||||
.highlight .ow{color:#a2f;font-weight:bold}
|
||||
.highlight .w{color:#bbb}
|
||||
.highlight .mf{color:#666}
|
||||
.highlight .mh{color:#666}
|
||||
.highlight .mi{color:#666}
|
||||
.highlight .mo{color:#666}
|
||||
.highlight .sb{color:#ba2121}
|
||||
.highlight .sc{color:#ba2121}
|
||||
.highlight .sd{color:#ba2121;font-style:italic}
|
||||
.highlight .s2{color:#ba2121}
|
||||
.highlight .se{color:#b62;font-weight:bold}
|
||||
.highlight .sh{color:#ba2121}
|
||||
.highlight .si{color:#b68;font-weight:bold}
|
||||
.highlight .sx{color:#008000}
|
||||
.highlight .sr{color:#b68}
|
||||
.highlight .s1{color:#ba2121}
|
||||
.highlight .ss{color:#19177c}
|
||||
.highlight .bp{color:#008000}
|
||||
.highlight .vc{color:#19177c}
|
||||
.highlight .vg{color:#19177c}
|
||||
.highlight .vi{color:#19177c}
|
||||
.highlight .il{color:#666}
|
||||
.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.highlight .lineno::selection{background:transparent;}
|
||||
.highlight .lineno::-moz-selection{background:transparent;}
|
|
@ -0,0 +1 @@
|
|||
html{position:relative;min-height:100%}body{margin-bottom:80px}.footer{position:absolute;bottom:0;width:100%;height:60px}input[type=checkbox]:checked+.label_hide_if_checked,input[type=checkbox]:checked+.label_hide_if_not_checked+.label_hide_if_checked{display:none}input[type=checkbox]:not(:checked)+.label_hide_if_not_checked,input[type=checkbox]:not(:checked)+.label_hide_if_checked+.label_hide_if_not_checked{display:none}.result_header{margin-bottom:5px;margin-top:20px}.result_header .favicon{margin-bottom:-3px}.result_header a{vertical-align:bottom}.result_header a .highlight{font-weight:700}.result-content{margin-top:5px;word-wrap:break-word}.result-content .highlight{font-weight:700}.result-default{clear:both}.result-images{float:left!important}.img-thumbnail{margin:5px;max-height:128px;min-height:128px}.result-videos{clear:both}.result-torrents{clear:both}.result-map{clear:both}.result-code{clear:both}.suggestion_item{margin:2px 5px}.result_download{margin-right:5px}#pagination{margin-top:30px;padding-bottom:50px}.label-default{color:#AAA;background:#FFF}.infobox .infobox_part{margin-bottom:20px;word-wrap:break-word;table-layout:fixed}.infobox .infobox_part:last-child{margin-bottom:0}.search_categories{margin:10px 0;text-transform:capitalize}.cursor-text{cursor:text!important}.cursor-pointer{cursor:pointer!important}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#408080;font-style:italic}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .cm{color:#408080;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#408080;font-style:italic}.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04d}.highlight .kc{color:green;font-weight:700}.highlight .kd{color:green;font-weight:700}.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#b00040}.highlight .m{color:#666}.highlight .s{color:#ba2121}.highlight .na{color:#7d9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00f}.highlight .nl{color:#a0a000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177c}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mf{color:#666}.highlight .mh{color:#666}.highlight .mi{color:#666}.highlight .mo{color:#666}.highlight .sb{color:#ba2121}.highlight .sc{color:#ba2121}.highlight .sd{color:#BA2121;font-style:italic}.highlight .s2{color:#ba2121}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#ba2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#b68}.highlight .s1{color:#ba2121}.highlight .ss{color:#19177c}.highlight .bp{color:green}.highlight .vc{color:#19177c}.highlight .vg{color:#19177c}.highlight .vi{color:#19177c}.highlight .il{color:#666}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}
|
|
@ -36,18 +36,20 @@ module.exports = function(grunt) {
|
|||
less: {
|
||||
development: {
|
||||
options: {
|
||||
paths: ["less/oscar"]
|
||||
paths: ["less/pointhi", "less/logicodev"]
|
||||
//banner: '/*! less/oscar/oscar.css | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n'
|
||||
},
|
||||
files: {"css/oscar.css": "less/oscar/oscar.less"}
|
||||
files: {"css/pointhi.css": "less/pointhi/oscar.less",
|
||||
"css/logicodev.css": "less/logicodev/oscar.less"}
|
||||
},
|
||||
production: {
|
||||
options: {
|
||||
paths: ["less/oscar"],
|
||||
paths: ["less/pointhi", "less/logicodev"],
|
||||
//banner: '/*! less/oscar/oscar.css | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n',
|
||||
cleancss: true
|
||||
},
|
||||
files: {"css/oscar.min.css": "less/oscar/oscar.less"}
|
||||
files: {"css/pointhi.min.css": "less/pointhi/oscar.less",
|
||||
"css/logicodev.min.css": "less/logicodev/oscar.less"}
|
||||
},
|
||||
bootstrap: {
|
||||
options: {
|
||||
|
@ -63,7 +65,7 @@ module.exports = function(grunt) {
|
|||
tasks: ['jshint', 'concat', 'uglify']
|
||||
},
|
||||
oscar_styles: {
|
||||
files: ['less/oscar/**/*.less'],
|
||||
files: ['less/pointhi/**/*.less'],
|
||||
tasks: ['less:development', 'less:production']
|
||||
},
|
||||
bootstrap_styles: {
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
|
@ -0,0 +1,103 @@
|
|||
pre, code{
|
||||
font-family: 'Ubuntu Mono', 'Courier New', 'Lucida Console', monospace !important;
|
||||
}
|
||||
|
||||
.lineno{
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.highlight .hll { background-color: #ffffcc }
|
||||
.highlight { background: #f8f8f8; }
|
||||
.highlight .c { color: #556366; font-style: italic } /* Comment */
|
||||
.highlight .err { border: 1px solid @orange } /* Error */
|
||||
.highlight .k { color: #BE74D5; font-weight: bold } /* Keyword */
|
||||
.highlight .o { color: #D19A66 } /* Operator */
|
||||
.highlight .cm { color: #556366; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
|
||||
.highlight .c1 { color: #556366; font-style: italic } /* Comment.Single */
|
||||
.highlight .cs { color: #556366; font-style: italic } /* Comment.Special */
|
||||
.highlight .gd { color: #A00000 } /* Generic.Deleted */
|
||||
.highlight .ge { font-style: italic } /* Generic.Emph */
|
||||
.highlight .gr { color: #FF0000 } /* Generic.Error */
|
||||
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.highlight .gi { color: #00A000 } /* Generic.Inserted */
|
||||
.highlight .go { color: #888888 } /* Generic.Output */
|
||||
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
||||
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
.highlight .gt { color: #0044DD } /* Generic.Traceback */
|
||||
.highlight .kc { color: #BE74D5; font-weight: bold } /* Keyword.Constant */
|
||||
.highlight .kd { color: #BE74D5; font-weight: bold } /* Keyword.Declaration */
|
||||
.highlight .kn { color: #BE74D5; font-weight: bold } /* Keyword.Namespace */
|
||||
.highlight .kp { color: #BE74D5 } /* Keyword.Pseudo */
|
||||
.highlight .kr { color: #BE74D5; font-weight: bold } /* Keyword.Reserved */
|
||||
.highlight .kt { color: #D46C72 } /* Keyword.Type */
|
||||
.highlight .m { color: #D19A66 } /* Literal.Number */
|
||||
.highlight .s { color: #86C372 } /* Literal.String */
|
||||
.highlight .na { color: #7D9029 } /* Name.Attribute */
|
||||
.highlight .nb { color: #BE74D5 } /* Name.Builtin */
|
||||
.highlight .nc { color: #61AFEF; font-weight: bold } /* Name.Class */
|
||||
.highlight .no { color: #D19A66 } /* Name.Constant */
|
||||
.highlight .nd { color: #AA22FF } /* Name.Decorator */
|
||||
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
|
||||
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
|
||||
.highlight .nf { color: #61AFEF } /* Name.Function */
|
||||
.highlight .nl { color: #A0A000 } /* Name.Label */
|
||||
.highlight .nn { color: #61AFEF; font-weight: bold } /* Name.Namespace */
|
||||
.highlight .nt { color: #BE74D5; font-weight: bold } /* Name.Tag */
|
||||
.highlight .nv { color: #DFC06F } /* Name.Variable */
|
||||
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||||
.highlight .w { color: #D7DAE0 } /* Text.Whitespace */
|
||||
.highlight .mf { color: #D19A66 } /* Literal.Number.Float */
|
||||
.highlight .mh { color: #D19A66 } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #D19A66 } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #D19A66 } /* Literal.Number.Oct */
|
||||
.highlight .sb { color: #86C372 } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #86C372 } /* Literal.String.Char */
|
||||
.highlight .sd { color: #86C372; font-style: italic } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #86C372 } /* Literal.String.Double */
|
||||
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #86C372 } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #BE74D5 } /* Literal.String.Other */
|
||||
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #86C372 } /* Literal.String.Single */
|
||||
.highlight .ss { color: #DFC06F } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #BE74D5 } /* Name.Builtin.Pseudo */
|
||||
.highlight .vc { color: #DFC06F } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #DFC06F } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #DFC06F } /* Name.Variable.Instance */
|
||||
.highlight .il { color: #D19A66 } /* Literal.Number.Integer.Long */
|
||||
|
||||
.highlight .lineno {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
color: #556366;
|
||||
|
||||
&::selection {
|
||||
background: transparent; /* WebKit/Blink Browsers */
|
||||
}
|
||||
&::-moz-selection {
|
||||
background: transparent; /* Gecko Browsers */
|
||||
}
|
||||
}
|
||||
|
||||
.highlight pre {
|
||||
background-color: #282C34;
|
||||
color: #D7DAE0;
|
||||
border: none;
|
||||
margin-bottom: 25px;
|
||||
font-size: 15px;
|
||||
padding: 20px 10px;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Sticky footer styles
|
||||
*{
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
body {
|
||||
/* Margin bottom by footer height */
|
||||
font-family: 'Roboto', Helvetica, Arial, sans-serif;
|
||||
margin-bottom: 80px;
|
||||
background-color: white;
|
||||
|
||||
a{
|
||||
color: @blue;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
/* Set the fixed height of the footer here */
|
||||
height: 60px;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
.infobox {
|
||||
|
||||
.panel-heading{
|
||||
background-color: @dim-gray;
|
||||
|
||||
.panel-title{
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
p{
|
||||
font-family: "DejaVu Serif", Georgia, Cambria, "Times New Roman", Times, serif !important;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.btn{
|
||||
background-color: @green;
|
||||
border: none;
|
||||
|
||||
a{
|
||||
color: white;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.infobox_part {
|
||||
margin-bottom: 20px;
|
||||
word-wrap: break-word;
|
||||
table-layout: fixed;
|
||||
|
||||
}
|
||||
|
||||
.infobox_part:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus{
|
||||
background: @black;
|
||||
color: @light-green;
|
||||
}
|
||||
|
||||
.navbar > li > a {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-nav > li > a {
|
||||
background: @black;
|
||||
padding: 0 8px;
|
||||
margin: 0;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.navbar, .navbar-default{
|
||||
background-color: @black;
|
||||
border: none;
|
||||
border-top: 4px solid @light-green;
|
||||
padding-top: 5px;
|
||||
color: @dim-gray !important;
|
||||
font-weight: 700;
|
||||
font-size: 1.1em;
|
||||
text-transform: lowercase;
|
||||
margin-bottom: 24px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
.navbar-nav > li > a{
|
||||
color: @dim-gray;
|
||||
}
|
||||
|
||||
.navbar-brand{
|
||||
font-weight: 700;
|
||||
color: @light-green;
|
||||
line-height: 30px;
|
||||
padding: 0 30px;
|
||||
margin: 0;
|
||||
}
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
// Hover color
|
||||
// http://stackoverflow.com/users/114029/leniel-macaferi
|
||||
.navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus {
|
||||
color: @light-green;
|
||||
background: @black;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
margin-top: 0;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
@import "variables.less";
|
||||
|
||||
@import "navbar.less";
|
||||
|
||||
@import "footer.less";
|
||||
|
||||
@import "checkbox.less";
|
||||
|
||||
@import "results.less";
|
||||
|
||||
@import "infobox.less";
|
||||
|
||||
@import "search.less";
|
||||
|
||||
@import "cursor.less";
|
||||
|
||||
@import "code.less";
|
|
@ -0,0 +1,150 @@
|
|||
.result_header {
|
||||
margin-top: 6px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 16px;
|
||||
|
||||
.favicon {
|
||||
margin-bottom:-3px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: @black;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover{
|
||||
color: @blue;
|
||||
}
|
||||
|
||||
&:visited{
|
||||
color: @violet;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: @dim-gray;
|
||||
// Chrome hack: bold is different size than normal
|
||||
// https://stackoverflow.com/questions/20713988/weird-text-alignment-issue-in-css-when-bolded-lucida-sans
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-content {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 0;
|
||||
word-wrap: break-word;
|
||||
color: @dark-gray;
|
||||
font-size: 13px;
|
||||
|
||||
|
||||
.highlight {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.external-link, .external-link a{
|
||||
color: @green;
|
||||
|
||||
a{
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
// default formating of results
|
||||
.result-default, .result-code, .result-torrent, .result-videos, .result-map {
|
||||
clear: both;
|
||||
padding: 2px 4px;
|
||||
&:hover{
|
||||
background-color: @dim-gray;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// image formating of results
|
||||
.result-images {
|
||||
float: left !important;
|
||||
width: 24%;
|
||||
margin: .5%;
|
||||
a{
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 170px;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.img-thumbnail {
|
||||
margin: 5px;
|
||||
max-height: 128px;
|
||||
min-height: 128px;
|
||||
}
|
||||
|
||||
// video formating of results
|
||||
.result-videos {
|
||||
clear: both;
|
||||
|
||||
hr{
|
||||
margin: 5px 0 15px 0;
|
||||
}
|
||||
|
||||
.collapse{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.in{
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
// torrent formating of results
|
||||
.result-torrent {
|
||||
clear: both;
|
||||
|
||||
b{
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.seeders{
|
||||
color: @green;
|
||||
}
|
||||
|
||||
.leechers{
|
||||
color: @red;
|
||||
}
|
||||
}
|
||||
|
||||
// map formating of results
|
||||
.result-map {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
// code formating of results
|
||||
.result-code {
|
||||
clear: both;
|
||||
|
||||
.code-fork, .code-fork a{
|
||||
color: @dark-gray;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// suggestion
|
||||
.suggestion_item {
|
||||
margin: 2px 5px;
|
||||
}
|
||||
|
||||
// download result
|
||||
.result_download {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
// page forward, backward
|
||||
#pagination {
|
||||
margin-top: 30px;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
.label-default {
|
||||
color: @gray;
|
||||
background: transparent;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
.search_categories, #categories {
|
||||
margin: 10px 0 4px 0;
|
||||
text-transform: capitalize;
|
||||
|
||||
label{
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
font-size: 13px;
|
||||
padding-bottom: 2px;
|
||||
color: @gray;
|
||||
margin-bottom: 5px;
|
||||
|
||||
&:hover{
|
||||
color: @black;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:active{
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.active, .btn-primary{
|
||||
color: @black;
|
||||
font-weight: 700;
|
||||
border-bottom: 5px solid @light-green;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#categories{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#main-logo{
|
||||
margin-top: 10vh;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
#main-logo > img {
|
||||
max-width: 350px;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#q{
|
||||
box-shadow: none;
|
||||
border-right: none;
|
||||
border-color: @gray;
|
||||
}
|
||||
|
||||
#search_form .input-group-btn .btn{
|
||||
border-color: @gray;
|
||||
}
|
||||
|
||||
#search_form .input-group-btn .btn:hover{
|
||||
background-color: @green;
|
||||
color: white;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
@black: #29314D;
|
||||
@gray: #A4A4A4;
|
||||
@dim-gray: #F6F9FA;
|
||||
@dark-gray: #666;
|
||||
@blue: #0088CC;
|
||||
@red: #F35E77;
|
||||
@violet: #684898;
|
||||
@green: #2ecc71;
|
||||
@light-green: #01D7D4;
|
||||
@orange: #FFA92F;
|
|
@ -0,0 +1,9 @@
|
|||
// Hide element if checkbox is checked
|
||||
input[type=checkbox]:checked + .label_hide_if_checked, input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
|
||||
display:none;
|
||||
}
|
||||
|
||||
// Hide element if checkbox is not checked
|
||||
input[type=checkbox]:not(:checked) + .label_hide_if_not_checked, input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
|
||||
display:none;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// display cursor
|
||||
.cursor-text {
|
||||
cursor: text !important;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer !important;
|
||||
}
|
|
@ -12,7 +12,11 @@
|
|||
<title>{% block title %}{% endblock %}{{ instance_name }}</title>
|
||||
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/oscar.min.css') }}" type="text/css" />
|
||||
{% if cookies['oscar-style'] %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/'+cookies['oscar-style']+'.min.css') }}" type="text/css" />
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/logicodev.min.css') }}" type="text/css" />
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/leaflet.min.css') }}" type="text/css" />
|
||||
{% for css in styles %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename=css) }}" type="text/css" />
|
||||
|
@ -48,8 +52,8 @@
|
|||
</noscript>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{% include 'oscar/navbar.html' %}
|
||||
<div class="container">
|
||||
|
||||
{% block site_alert_error %}
|
||||
{% endblock %}
|
||||
|
@ -75,7 +79,7 @@
|
|||
<div class="container">
|
||||
{% block footer %}
|
||||
{% endblock %}
|
||||
<p class="text-muted">{{ _('Powered by') }} <a href="https://asciimoo.github.io/searx/">searx</a> - {{ searx_version }} - {{ _('a privacy-respecting, hackable metasearch engine') }}</p>
|
||||
<p class="text-muted"><small>{{ _('Powered by') }} <a href="https://asciimoo.github.io/searx/">searx</a> - {{ searx_version }} - {{ _('a privacy-respecting, hackable metasearch engine') }}</small></p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/jquery-1.11.1.min.js') }}"></script>
|
||||
|
|
|
@ -3,7 +3,14 @@
|
|||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="text-center col-sm-12 col-md-12">
|
||||
{% if cookies['oscar-style'] == 'pointhi' %}
|
||||
<h1 class="text-hide center-block"><img class="center-block img-responsive" src="{{ url_for('static', filename='img/searx_logo.png') }}" alt="searx logo"/>searx</h1>
|
||||
{% else %}
|
||||
<h1 class="text-hide center-block" id="main-logo">
|
||||
<img class="center-block img-responsive" src="{{ url_for('static', filename='img/logo_searx_a.png') }}" alt="searx logo" />
|
||||
searx
|
||||
</h1>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
<!-- Draw result sub header -->
|
||||
{% macro result_sub_header(result) -%}
|
||||
{% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
|
||||
<small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}" rel="noreferrer">{{ icon('link') }} {{ _('cached') }}</a></small>
|
||||
{% if result.magnetlink %}<small> • <a href="{{ result.magnetlink }}" class="magnetlink">{{ icon('magnet') }} {{ _('magnet link') }}</a></small>{% endif %}
|
||||
{% if result.torrentfile %}<small> • <a href="{{ result.torrentfile }}" class="torrentfile" rel="noreferrer">{{ icon('download-alt') }} {{ _('torrent file') }}</a></small>{% endif %}
|
||||
{%- endmacro %}
|
||||
|
@ -29,15 +28,19 @@
|
|||
{% for engine in result.engines %}
|
||||
<span class="label label-default">{{ engine }}</span>
|
||||
{% endfor %}
|
||||
<small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}" rel="noreferrer">{{ icon('link') }} {{ _('cached') }}</a></small>
|
||||
</div>
|
||||
<p class="text-muted">{{ result.pretty_url }}</p>
|
||||
<div class="text-muted"><small>{{ result.pretty_url }}</small></div>
|
||||
{%- endmacro %}
|
||||
|
||||
<!-- Draw result footer -->
|
||||
{% macro result_footer_rtl(result) -%}
|
||||
<div class="clearfix"></div>
|
||||
<span class="label label-default pull-left">{{ result.engine }}</span>
|
||||
<p class="text-muted">{{ result.pretty_url }}‎</p>
|
||||
{% for engine in result.engines %}
|
||||
<span class="label label-default">{{ engine }}</span>
|
||||
{% endfor %}
|
||||
<small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}" rel="noreferrer">{{ icon('link') }} {{ _('cached') }}</a></small>
|
||||
<div class="text-muted"><small>{{ result.pretty_url }}</small></div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro preferences_item_header(info, label, rtl) -%}
|
||||
|
|
|
@ -110,6 +110,13 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
{{ preferences_item_footer(theme_info, theme_label, rtl) }}
|
||||
|
||||
{{ preferences_item_header(_('Choose style for this theme'), _('Style'), rtl) }}
|
||||
<select class="form-control" name='oscar-style'>
|
||||
<option value="logicodev" >Logicodev</option>
|
||||
<option value="pointhi" {% if cookies['oscar-style'] == 'pointhi' %}selected="selected"{% endif %}>Pointhi</option>
|
||||
</select>
|
||||
{{ preferences_item_footer(_('Choose style for this theme'), _('Style'), rtl) }}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
|
|
@ -78,6 +78,16 @@
|
|||
</div><!-- /#main_results -->
|
||||
|
||||
<div class="col-sm-4" id="sidebar_results">
|
||||
{% if number_of_results != '0' %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">{{ _('Number of results') }}</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ number_of_results }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if infoboxes %}
|
||||
{% for infobox in infoboxes %}
|
||||
{% include 'oscar/infobox.html' %}
|
||||
|
|
|
@ -18,8 +18,8 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
|
|||
|
||||
# version of searx
|
||||
VERSION_MAJOR = 0
|
||||
VERSION_MINOR = 8
|
||||
VERSION_BUILD = 1
|
||||
VERSION_MINOR = 9
|
||||
VERSION_BUILD = 0
|
||||
|
||||
VERSION_STRING = "{0}.{1}.{2}".format(VERSION_MAJOR,
|
||||
VERSION_MINOR,
|
||||
|
|
|
@ -48,7 +48,8 @@ from flask import (
|
|||
Flask, request, render_template, url_for, Response, make_response,
|
||||
redirect, send_from_directory
|
||||
)
|
||||
from flask.ext.babel import Babel, gettext, format_date
|
||||
from flask.ext.babel import Babel, gettext, format_date, format_decimal
|
||||
from flask.json import jsonify
|
||||
from searx import settings, searx_dir
|
||||
from searx.engines import (
|
||||
categories, engines, get_engines_stats, engine_shortcuts
|
||||
|
@ -64,7 +65,7 @@ from searx.search import Search
|
|||
from searx.query import Query
|
||||
from searx.autocomplete import searx_bang, backends as autocomplete_backends
|
||||
from searx.plugins import plugins
|
||||
from searx.preferences import Preferences
|
||||
from searx.preferences import Preferences, ValidationException
|
||||
|
||||
# check if the pyopenssl, ndg-httpsclient, pyasn1 packages are installed.
|
||||
# They are needed for SSL connection without trouble, see #298
|
||||
|
@ -419,6 +420,7 @@ def index():
|
|||
|
||||
if search.request_data.get('format') == 'json':
|
||||
return Response(json.dumps({'query': search.query,
|
||||
'number_of_results': search.result_container.number_of_results,
|
||||
'results': search.result_container.get_ordered_results()}),
|
||||
mimetype='application/json')
|
||||
elif search.request_data.get('format') == 'csv':
|
||||
|
@ -438,7 +440,7 @@ def index():
|
|||
'opensearch_response_rss.xml',
|
||||
results=search.result_container.get_ordered_results(),
|
||||
q=search.request_data['q'],
|
||||
number_of_results=search.result_container.results_length(),
|
||||
number_of_results=search.result_container.number_of_results,
|
||||
base_url=get_base_url()
|
||||
)
|
||||
return Response(response_rss, mimetype='text/xml')
|
||||
|
@ -449,6 +451,7 @@ def index():
|
|||
q=search.request_data['q'],
|
||||
selected_categories=search.categories,
|
||||
paging=search.paging,
|
||||
number_of_results=format_decimal(search.result_container.number_of_results),
|
||||
pageno=search.pageno,
|
||||
base_url=get_base_url(),
|
||||
suggestions=search.result_container.suggestions,
|
||||
|
@ -685,6 +688,24 @@ def clear_cookies():
|
|||
return resp
|
||||
|
||||
|
||||
@app.route('/config')
|
||||
def config():
|
||||
return jsonify({'categories': categories.keys(),
|
||||
'engines': [{'name': engine_name,
|
||||
'categories': engine.categories,
|
||||
'enabled': not engine.disabled}
|
||||
for engine_name, engine in engines.items()],
|
||||
'plugins': [{'name': plugin.name,
|
||||
'enabled': plugin.default_on}
|
||||
for plugin in plugins],
|
||||
'instance_name': settings['general']['instance_name'],
|
||||
'locales': settings['locales'],
|
||||
'default_locale': settings['ui']['default_locale'],
|
||||
'autocomplete': settings['search']['autocomplete'],
|
||||
'safe_search': settings['search']['safe_search'],
|
||||
'default_theme': settings['ui']['default_theme']})
|
||||
|
||||
|
||||
def run():
|
||||
app.run(
|
||||
debug=settings['general']['debug'],
|
||||
|
|
|
@ -53,6 +53,8 @@ setup(
|
|||
'searx': [
|
||||
'settings.yml',
|
||||
'../README.rst',
|
||||
'../requirements.txt',
|
||||
'../requirements-dev.txt',
|
||||
'data/*',
|
||||
'plugins/*/*',
|
||||
'static/*.*',
|
||||
|
|
|
@ -14,23 +14,19 @@ class TestCurrencyConvertEngine(SearxTestCase):
|
|||
params = currency_convert.request(query, dicto)
|
||||
self.assertNotIn('url', params)
|
||||
|
||||
query = '1.1.1 EUR in USD'
|
||||
params = currency_convert.request(query, dicto)
|
||||
self.assertNotIn('url', params)
|
||||
|
||||
query = '10 eur in usd'
|
||||
query = 'convert 10 Pound Sterlings to United States Dollars'
|
||||
params = currency_convert.request(query, dicto)
|
||||
self.assertIn('url', params)
|
||||
self.assertIn('finance.yahoo.com', params['url'])
|
||||
self.assertIn('EUR', params['url'])
|
||||
self.assertIn('GBP', params['url'])
|
||||
self.assertIn('USD', params['url'])
|
||||
|
||||
def test_response(self):
|
||||
dicto = defaultdict(dict)
|
||||
dicto['ammount'] = float(10)
|
||||
dicto['from'] = "EUR"
|
||||
dicto['from'] = "GBP"
|
||||
dicto['to'] = "USD"
|
||||
dicto['from_name'] = "euro"
|
||||
dicto['from_name'] = "pound sterling"
|
||||
dicto['to_name'] = "United States dollar"
|
||||
response = mock.Mock(text='a,b,c,d', search_params=dicto)
|
||||
self.assertEqual(currency_convert.response(response), [])
|
||||
|
@ -40,7 +36,8 @@ class TestCurrencyConvertEngine(SearxTestCase):
|
|||
results = currency_convert.response(response)
|
||||
self.assertEqual(type(results), list)
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0]['answer'], '10.0 EUR = 5.0 USD, 1 EUR (euro) = 0.5 USD (United States dollar)')
|
||||
self.assertEqual(results[0]['answer'], '10.0 GBP = 5.0 USD, 1 GBP (pound sterling)' +
|
||||
' = 0.5 USD (United States dollar)')
|
||||
now_date = datetime.now().strftime('%Y%m%d')
|
||||
self.assertEqual(results[0]['url'], 'https://finance.yahoo.com/currency/converter-results/' +
|
||||
now_date + '/10.0-eur-to-usd.html')
|
||||
now_date + '/10.0-gbp-to-usd.html')
|
||||
|
|
Loading…
Reference in New Issue