commit: 7369fbd54c7a4441065490d2940e6de129cb1b98
parent: 3386e21cdf30bf0accb84e2dcc4dea0076af1b90
Author: Adam Tauber <asciimoo@gmail.com>
Date: Tue, 10 Jun 2014 01:18:37 +0200
Merge pull request #70 from matejc/theming_support
add multi theming support
Diffstat:
49 files changed, 390 insertions(+), 315 deletions(-)
diff --git a/Makefile b/Makefile
@@ -44,13 +44,13 @@ minimal: bin/buildout minimal.cfg setup.py
bin/buildout -c minimal.cfg $(options)
styles:
- @lessc -x searx/static/less/style.less > searx/static/css/style.css
+ @lessc -x searx/static/default/less/style.less > searx/static/default/css/style.css
locales:
@pybabel compile -d searx/translations
clean:
@rm -rf .installed.cfg .mr.developer.cfg bin parts develop-eggs \
- searx.egg-info lib include .coverage coverage searx/static/css/*.css
+ searx.egg-info lib include .coverage coverage searx/static/default/css/*.css
.PHONY: all tests robot flake8 coverage production minimal styles locales clean
diff --git a/searx/settings.yml b/searx/settings.yml
@@ -4,6 +4,8 @@ server:
debug : True
request_timeout : 2.0 # seconds
base_url : False
+ themes_path : ""
+ default_theme : default
engines:
- name : wikipedia
diff --git a/searx/static/css/style.css b/searx/static/default/css/style.css
diff --git a/searx/static/img/favicon.png b/searx/static/default/img/favicon.png
Binary files differ.
diff --git a/searx/static/img/github_ribbon.png b/searx/static/default/img/github_ribbon.png
Binary files differ.
diff --git a/searx/static/img/icon_github.ico b/searx/static/default/img/icon_github.ico
Binary files differ.
diff --git a/searx/static/img/icon_soundcloud.ico b/searx/static/default/img/icon_soundcloud.ico
Binary files differ.
diff --git a/searx/static/img/icon_stackoverflow.ico b/searx/static/default/img/icon_stackoverflow.ico
Binary files differ.
diff --git a/searx/static/img/icon_twitter.ico b/searx/static/default/img/icon_twitter.ico
Binary files differ.
diff --git a/searx/static/img/icon_vimeo.ico b/searx/static/default/img/icon_vimeo.ico
Binary files differ.
diff --git a/searx/static/img/icon_wikipedia.ico b/searx/static/default/img/icon_wikipedia.ico
Binary files differ.
diff --git a/searx/static/img/icon_youtube.ico b/searx/static/default/img/icon_youtube.ico
Binary files differ.
diff --git a/searx/static/img/preference-icon.png b/searx/static/default/img/preference-icon.png
Binary files differ.
diff --git a/searx/static/img/search-icon.png b/searx/static/default/img/search-icon.png
Binary files differ.
diff --git a/searx/static/img/searx.png b/searx/static/default/img/searx.png
Binary files differ.
diff --git a/searx/static/img/searx_logo.svg b/searx/static/default/img/searx_logo.svg
diff --git a/searx/static/js/mootools-autocompleter-1.1.2-min.js b/searx/static/default/js/mootools-autocompleter-1.1.2-min.js
diff --git a/searx/static/js/mootools-core-1.4.5-min.js b/searx/static/default/js/mootools-core-1.4.5-min.js
diff --git a/searx/static/js/searx.js b/searx/static/default/js/searx.js
diff --git a/searx/static/less/autocompleter.less b/searx/static/default/less/autocompleter.less
diff --git a/searx/static/less/definitions.less b/searx/static/default/less/definitions.less
diff --git a/searx/static/less/mixins.less b/searx/static/default/less/mixins.less
diff --git a/searx/static/less/search.less b/searx/static/default/less/search.less
diff --git a/searx/static/less/style.less b/searx/static/default/less/style.less
diff --git a/searx/templates/about.html b/searx/templates/about.html
@@ -1,66 +0,0 @@
-{% extends 'base.html' %}
-{% block content %}
-{% include 'github_ribbon.html' %}
-<div class="row">
- <h1>About <a href="{{ url_for('index') }}">searx</a></h1>
-
- <p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>, aggregating the results of other <a href="{{ url_for('preferences') }}">search engines</a> while not storing information about its users.
- </p>
- <h2>Why use Searx?</h2>
- <ul>
- <li>Searx may not offer you as personalised results as Google, but it doesn't generate a profile about you</li>
- <li>Searx doesn't care about what you search for, never shares anything with a third party, and it can't be used to compromise you</li>
- <li>Searx is free software, the code is 100% open and you can help to make it better. See more on <a href="https://github.com/asciimoo/searx">github</a></li>
- </ul>
- <p>If you do care about privacy, want to be a conscious user, or otherwise believe
- in digital freedom, make Searx your default search engine or run it on your own server</p>
-
-<h2>Technical details - How does it work?</h2>
-
-<p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>,
-inspired by the <a href="http://seeks-project.info/">seeks project</a>.<br />
-It provides basic privacy by mixing your queries with searches on other platforms without storing search data. Queries are made using a POST request on every browser (except chrome*). Therefore they show up in neither our logs, nor your url history. In case of Chrome* users there is an exception, Searx uses the search bar to perform GET requests.<br />
-Searx can be added to your browser's search bar; moreover, it can be set as the default search engine.
-</p>
-
-<h2>How can I make it my own?</h2>
-
-<p>Searx appreciates your concern regarding logs, so take the <a href="https://github.com/asciimoo/searx">code</a> and run it yourself! <br />Add your Searx to this <a href="https://github.com/asciimoo/searx/wiki/Searx-instances">list</a> to help other people reclaim their privacy and make the Internet freer!
-<br />The more decentralized the Internet, is the more freedom we have!</p>
-
-
-<h2>More about searx</h2>
-
-<ul>
- <li><a href="https://github.com/asciimoo/searx">github</a></li>
- <li><a href="https://www.ohloh.net/p/searx/">ohloh</a></li>
- <li><a href="https://twitter.com/Searx_engine">twitter</a></li>
- <li>IRC: #searx @ freenode (<a href="https://kiwiirc.com/client/irc.freenode.com/searx">webclient</a>)</li>
- <li><a href="https://www.transifex.com/projects/p/searx/">transifex</a></li>
-</ul>
-
-
-<hr />
-
-<h2 id="faq">FAQ</h2>
-
-<h3>How to add to firefox?</h3>
-<p><a href="#" onclick="window.external.AddSearchProvider(window.location.protocol + '//' + window.location.host + '{{ url_for('opensearch') }}');">Install</a> searx as a search engine on any version of Firefox! (javascript required)</p>
-
-<h2 id="dev_faq">Developer FAQ</h2>
-
-<h3>New engines?</h3>
-<ul>
- <li>Edit your <a href="https://raw.github.com/asciimoo/searx/master/searx/settings.yml">settings.yml</a></li>
- <li>Create your custom engine module, check the <a href="https://github.com/asciimoo/searx/blob/master/examples/basic_engine.py">example engine</a></li>
-</ul>
-<p>Don't forget to restart searx after config edit!</p>
-
-<h3>Installation/WSGI support?</h3>
-<p>See the <a href="https://github.com/asciimoo/searx/wiki/Installation">installation and setup</a> wiki page</p>
-
-<h3>How to debug engines?</h3>
-<p><a href="{{ url_for('stats') }}">Stats page</a> contains some useful data about the engines used.</p>
-
-</div>
-{% endblock %}
diff --git a/searx/templates/default/about.html b/searx/templates/default/about.html
@@ -0,0 +1,66 @@
+{% extends 'default/base.html' %}
+{% block content %}
+{% include 'default/github_ribbon.html' %}
+<div class="row">
+ <h1>About <a href="{{ url_for('index') }}">searx</a></h1>
+
+ <p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>, aggregating the results of other <a href="{{ url_for('preferences') }}">search engines</a> while not storing information about its users.
+ </p>
+ <h2>Why use Searx?</h2>
+ <ul>
+ <li>Searx may not offer you as personalised results as Google, but it doesn't generate a profile about you</li>
+ <li>Searx doesn't care about what you search for, never shares anything with a third party, and it can't be used to compromise you</li>
+ <li>Searx is free software, the code is 100% open and you can help to make it better. See more on <a href="https://github.com/asciimoo/searx">github</a></li>
+ </ul>
+ <p>If you do care about privacy, want to be a conscious user, or otherwise believe
+ in digital freedom, make Searx your default search engine or run it on your own server</p>
+
+<h2>Technical details - How does it work?</h2>
+
+<p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>,
+inspired by the <a href="http://seeks-project.info/">seeks project</a>.<br />
+It provides basic privacy by mixing your queries with searches on other platforms without storing search data. Queries are made using a POST request on every browser (except chrome*). Therefore they show up in neither our logs, nor your url history. In case of Chrome* users there is an exception, Searx uses the search bar to perform GET requests.<br />
+Searx can be added to your browser's search bar; moreover, it can be set as the default search engine.
+</p>
+
+<h2>How can I make it my own?</h2>
+
+<p>Searx appreciates your concern regarding logs, so take the <a href="https://github.com/asciimoo/searx">code</a> and run it yourself! <br />Add your Searx to this <a href="https://github.com/asciimoo/searx/wiki/Searx-instances">list</a> to help other people reclaim their privacy and make the Internet freer!
+<br />The more decentralized the Internet, is the more freedom we have!</p>
+
+
+<h2>More about searx</h2>
+
+<ul>
+ <li><a href="https://github.com/asciimoo/searx">github</a></li>
+ <li><a href="https://www.ohloh.net/p/searx/">ohloh</a></li>
+ <li><a href="https://twitter.com/Searx_engine">twitter</a></li>
+ <li>IRC: #searx @ freenode (<a href="https://kiwiirc.com/client/irc.freenode.com/searx">webclient</a>)</li>
+ <li><a href="https://www.transifex.com/projects/p/searx/">transifex</a></li>
+</ul>
+
+
+<hr />
+
+<h2 id="faq">FAQ</h2>
+
+<h3>How to add to firefox?</h3>
+<p><a href="#" onclick="window.external.AddSearchProvider(window.location.protocol + '//' + window.location.host + '{{ url_for('opensearch') }}');">Install</a> searx as a search engine on any version of Firefox! (javascript required)</p>
+
+<h2 id="dev_faq">Developer FAQ</h2>
+
+<h3>New engines?</h3>
+<ul>
+ <li>Edit your <a href="https://raw.github.com/asciimoo/searx/master/searx/settings.yml">settings.yml</a></li>
+ <li>Create your custom engine module, check the <a href="https://github.com/asciimoo/searx/blob/master/examples/basic_engine.py">example engine</a></li>
+</ul>
+<p>Don't forget to restart searx after config edit!</p>
+
+<h3>Installation/WSGI support?</h3>
+<p>See the <a href="https://github.com/asciimoo/searx/wiki/Installation">installation and setup</a> wiki page</p>
+
+<h3>How to debug engines?</h3>
+<p><a href="{{ url_for('stats') }}">Stats page</a> contains some useful data about the engines used.</p>
+
+</div>
+{% endblock %}
diff --git a/searx/templates/base.html b/searx/templates/default/base.html
diff --git a/searx/templates/categories.html b/searx/templates/default/categories.html
diff --git a/searx/templates/github_ribbon.html b/searx/templates/default/github_ribbon.html
diff --git a/searx/templates/default/index.html b/searx/templates/default/index.html
@@ -0,0 +1,11 @@
+{% extends "default/base.html" %}
+{% block content %}
+<div class="center">
+ <div class="title"><h1>searx</h1></div>
+ {% include 'default/search.html' %}
+ <p class="top_margin">
+ <a href="{{ url_for('about') }}" class="hmarg">{{ _('about') }}</a>
+ <a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
+ </p>
+</div>
+{% endblock %}
diff --git a/searx/templates/opensearch.xml b/searx/templates/default/opensearch.xml
diff --git a/searx/templates/opensearch_response_rss.xml b/searx/templates/default/opensearch_response_rss.xml
diff --git a/searx/templates/default/preferences.html b/searx/templates/default/preferences.html
@@ -0,0 +1,101 @@
+{% extends "default/base.html" %}
+{% block head %} {% endblock %}
+{% block content %}
+<div class="row">
+ <h2>{{ _('Preferences') }}</h2>
+
+ <form method="post" action="{{ url_for('preferences') }}" id="search_form">
+ <fieldset>
+ <legend>{{ _('Default categories') }}</legend>
+ <p>
+ {% include 'default/categories.html' %}
+ </p>
+ </fieldset>
+ <fieldset>
+ <legend>{{ _('Search language') }}</legend>
+ <p>
+ <select name='language'>
+ <option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Automatic') }}</option>
+ {% for lang_id,lang_name,country_name in language_codes %}
+ <option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>{{ lang_name }} ({{ country_name }}) - {{ lang_id }}</option>
+ {% endfor %}
+ </select>
+ </p>
+ </fieldset>
+ <fieldset>
+ <legend>{{ _('Interface language') }}</legend>
+ <p>
+ <select name='locale'>
+ {% for locale_id,locale_name in locales.items() %}
+ <option value="{{ locale_id }}" {% if locale_id == current_locale %}selected="selected"{% endif %}>{{ locale_name }}</option>
+ {% endfor %}
+ </select>
+ </p>
+ </fieldset>
+ <fieldset>
+ <legend>{{ _('Autocomplete') }}</legend>
+ <p>
+ <select name="autocomplete">
+ <option value=""> - </option>
+ {% for backend in autocomplete_backends %}
+ <option value="{{ backend }}" {% if backend == autocomplete %}selected="selected"{% endif %}>{{ backend }}</option>
+ {% endfor %}
+ </select>
+ </p>
+ </fieldset>
+ <fieldset>
+ <legend>{{ _('Method') }}</legend>
+ <p>
+ <select name='method'>
+ <option value="POST" {% if method == 'POST' %}selected="selected"{% endif %}>POST</option>
+ <option value="GET" {% if method == 'GET' %}selected="selected"{% endif %}>GET</option>
+ </select>
+ </p>
+ </fieldset>
+ <fieldset>
+ <legend>{{ _('Themes') }}</legend>
+ <p>
+ <select name="theme">
+ {% for name in themes %}
+ <option value="{{ name }}" {% if name == theme %}selected="selected"{% endif %}>{{ name }}</option>
+ {% endfor %}
+ </select>
+ </p>
+ </fieldset>
+ <fieldset>
+ <legend>{{ _('Currently used search engines') }}</legend>
+
+ <table>
+ <tr>
+ <th>{{ _('Engine name') }}</th>
+ <th>{{ _('Category') }}</th>
+ <th>{{ _('Allow') }} / {{ _('Block') }}</th>
+ </tr>
+ {% for (categ,search_engines) in categs %}
+ {% for search_engine in search_engines %}
+
+ {% if not search_engine.private %}
+ <tr>
+ <td>{{ search_engine.name }} ({{ shortcuts[search_engine.name] }})</td>
+ <td>{{ _(categ) }}</td>
+ <td class="engine_checkbox">
+ <input type="checkbox" id="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}" name="engine_{{ search_engine.name }}"{% if search_engine.name in blocked_engines %} checked="checked"{% endif %} />
+ <label class="allow" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Allow') }}</label>
+ <label class="deny" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Block') }}</label>
+ </td>
+ </tr>
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+ </table>
+ </fieldset>
+ <p class="small_font">{{ _('These settings are stored in your cookies, this allows us not to store this data about you.') }}
+ <br />
+ {{ _("These cookies serve your sole convenience, we don't use these cookies to track you.") }}
+ </p>
+
+ <input type="submit" value="{{ _('save') }}" />
+ <div class="right preferences_back"><a href="{{ url_for('index') }}">{{ _('back') }}</a></div>
+ </form>
+</div>
+{% endblock %}
diff --git a/searx/templates/default/result_templates/default.html b/searx/templates/default/result_templates/default.html
@@ -0,0 +1,13 @@
+<div class="result {{ result.class }}">
+
+ {% if result['favicon'] %}
+ <img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" />
+ {% endif %}
+
+ <div>
+ <h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
+ {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
+ <p class="content">{% if result.content %}{{ result.content|safe }}<br />{% endif %}</p>
+ <p class="url">{{ result.pretty_url }}</p>
+ </div>
+</div>
diff --git a/searx/templates/result_templates/images.html b/searx/templates/default/result_templates/images.html
diff --git a/searx/templates/result_templates/torrent.html b/searx/templates/default/result_templates/torrent.html
diff --git a/searx/templates/default/result_templates/videos.html b/searx/templates/default/result_templates/videos.html
@@ -0,0 +1,12 @@
+<div class="result">
+ {% if result['favicon'] %}
+ <img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" />
+ {% endif %}
+
+ <p>
+ <h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
+ {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
+ <a href="{{ result.url }}"><img width="400px" src="{{ result.thumbnail }}" title={{ result.title }} alt=" {{ result.title }}"/></a>
+ <p class="url">{{ result.url }}</p>
+ </p>
+</div>
diff --git a/searx/templates/default/results.html b/searx/templates/default/results.html
@@ -0,0 +1,79 @@
+{% extends "default/base.html" %}
+{% block title %}{{ q }} - {% endblock %}
+{% block content %}
+<div class="right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
+<div class="small search center">
+ {% include 'default/search.html' %}
+</div>
+<div id="results">
+ <div id="sidebar">
+
+ <div id="search_url">
+ {{ _('Search URL') }}:
+ <input type="text" value="{{ base_url }}?q={{ q|urlencode }}&pageno={{ pageno }}{% if selected_categories %}&category_{{ selected_categories|join("&category_") }}{% endif %}" readonly="" />
+ </div>
+ <div id="apis">
+ {{ _('Download results') }}
+ {% for output_type in ('csv', 'json', 'rss') %}
+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
+ <div class="left">
+ <input type="hidden" name="q" value="{{ q }}" />
+ <input type="hidden" name="format" value="{{ output_type }}" />
+ {% for category in selected_categories %}
+ <input type="hidden" name="category_{{ category }}" value="1"/>
+ {% endfor %}
+ <input type="hidden" name="pageno" value="{{ pageno }}" />
+ <input type="submit" value="{{ output_type }}" />
+ </div>
+ </form>
+ {% endfor %}
+ </div>
+ </div>
+
+ {% if suggestions %}
+ <div id="suggestions"><span>{{ _('Suggestions') }}</span>
+ {% for suggestion in suggestions %}
+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
+ <input type="hidden" name="q" value="{{ suggestion }}">
+ <input type="submit" value="{{ suggestion }}" />
+ </form>
+ {% endfor %}
+ </div>
+ {% endif %}
+
+ {% for result in results %}
+ {% if result['template'] %}
+ {% include 'default/result_templates/'+result['template'] %}
+ {% else %}
+ {% include 'default/result_templates/default.html' %}
+ {% endif %}
+ {% endfor %}
+
+ {% if paging %}
+ <div id="pagination">
+ {% if pageno > 1 %}
+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
+ <div class="left">
+ <input type="hidden" name="q" value="{{ q }}" />
+ {% for category in selected_categories %}
+ <input type="hidden" name="category_{{ category }}" value="1"/>
+ {% endfor %}
+ <input type="hidden" name="pageno" value="{{ pageno-1 }}" />
+ <input type="submit" value="<< {{ _('previous page') }}" />
+ </div>
+ </form>
+ {% endif %}
+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
+ <div class="left">
+ {% for category in selected_categories %}
+ <input type="hidden" name="category_{{ category }}" value="1"/>
+ {% endfor %}
+ <input type="hidden" name="q" value="{{ q }}" />
+ <input type="hidden" name="pageno" value="{{ pageno+1 }}" />
+ <input type="submit" value="{{ _('next page') }} >>" />
+ </div>
+ </form>
+ </div>
+ {% endif %}
+</div>
+{% endblock %}
diff --git a/searx/templates/default/search.html b/searx/templates/default/search.html
@@ -0,0 +1,7 @@
+<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form">
+ <div id="search_wrapper">
+ <input type="text" placeholder="{{ _('Search for...') }}" id="q" class="q" name="q" tabindex="1" autocomplete="off" {% if q %}value="{{ q }}"{% endif %}/>
+ <input type="submit" value="search" id="search_submit" />
+ </div>
+ {% include 'default/categories.html' %}
+</form>
diff --git a/searx/templates/default/stats.html b/searx/templates/default/stats.html
@@ -0,0 +1,22 @@
+{% extends "default/base.html" %}
+{% block head %} {% endblock %}
+{% block content %}
+<h2>{{ _('Engine stats') }}</h2>
+
+{% for stat_name,stat_category in stats %}
+<div class="left">
+ <table>
+ <tr colspan="3">
+ <th>{{ stat_name }}</th>
+ </tr>
+ {% for engine in stat_category %}
+ <tr>
+ <td>{{ engine.name }}</td>
+ <td>{{ '%.02f'|format(engine.avg) }}</td>
+ <td class="percentage"><div style="width: {{ engine.percentage }}%"> </div></td>
+ </tr>
+ {% endfor %}
+ </table>
+</div>
+{% endfor %}
+{% endblock %}
diff --git a/searx/templates/index.html b/searx/templates/index.html
@@ -1,11 +0,0 @@
-{% extends "base.html" %}
-{% block content %}
-<div class="center">
- <div class="title"><h1>searx</h1></div>
- {% include 'search.html' %}
- <p class="top_margin">
- <a href="{{ url_for('about') }}" class="hmarg">{{ _('about') }}</a>
- <a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
- </p>
-</div>
-{% endblock %}
diff --git a/searx/templates/preferences.html b/searx/templates/preferences.html
@@ -1,91 +0,0 @@
-{% extends "base.html" %}
-{% block head %} {% endblock %}
-{% block content %}
-<div class="row">
- <h2>{{ _('Preferences') }}</h2>
-
- <form method="post" action="{{ url_for('preferences') }}" id="search_form">
- <fieldset>
- <legend>{{ _('Default categories') }}</legend>
- <p>
- {% include 'categories.html' %}
- </p>
- </fieldset>
- <fieldset>
- <legend>{{ _('Search language') }}</legend>
- <p>
- <select name='language'>
- <option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Automatic') }}</option>
- {% for lang_id,lang_name,country_name in language_codes %}
- <option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>{{ lang_name }} ({{ country_name }}) - {{ lang_id }}</option>
- {% endfor %}
- </select>
- </p>
- </fieldset>
- <fieldset>
- <legend>{{ _('Interface language') }}</legend>
- <p>
- <select name='locale'>
- {% for locale_id,locale_name in locales.items() %}
- <option value="{{ locale_id }}" {% if locale_id == current_locale %}selected="selected"{% endif %}>{{ locale_name }}</option>
- {% endfor %}
- </select>
- </p>
- </fieldset>
- <fieldset>
- <legend>{{ _('Autocomplete') }}</legend>
- <p>
- <select name="autocomplete">
- <option value=""> - </option>
- {% for backend in autocomplete_backends %}
- <option value="{{ backend }}" {% if backend == autocomplete %}selected="selected"{% endif %}>{{ backend }}</option>
- {% endfor %}
- </select>
- </p>
- </fieldset>
- <fieldset>
- <legend>{{ _('Method') }}</legend>
- <p>
- <select name='method'>
- <option value="POST" {% if method == 'POST' %}selected="selected"{% endif %}>POST</option>
- <option value="GET" {% if method == 'GET' %}selected="selected"{% endif %}>GET</option>
- </select>
- </p>
- </fieldset>
- <fieldset>
- <legend>{{ _('Currently used search engines') }}</legend>
-
- <table>
- <tr>
- <th>{{ _('Engine name') }}</th>
- <th>{{ _('Category') }}</th>
- <th>{{ _('Allow') }} / {{ _('Block') }}</th>
- </tr>
- {% for (categ,search_engines) in categs %}
- {% for search_engine in search_engines %}
-
- {% if not search_engine.private %}
- <tr>
- <td>{{ search_engine.name }} ({{ shortcuts[search_engine.name] }})</td>
- <td>{{ _(categ) }}</td>
- <td class="engine_checkbox">
- <input type="checkbox" id="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}" name="engine_{{ search_engine.name }}"{% if search_engine.name in blocked_engines %} checked="checked"{% endif %} />
- <label class="allow" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Allow') }}</label>
- <label class="deny" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Block') }}</label>
- </td>
- </tr>
- {% endif %}
- {% endfor %}
- {% endfor %}
- </table>
- </fieldset>
- <p class="small_font">{{ _('These settings are stored in your cookies, this allows us not to store this data about you.') }}
- <br />
- {{ _("These cookies serve your sole convenience, we don't use these cookies to track you.") }}
- </p>
-
- <input type="submit" value="{{ _('save') }}" />
- <div class="right preferences_back"><a href="{{ url_for('index') }}">{{ _('back') }}</a></div>
- </form>
-</div>
-{% endblock %}
diff --git a/searx/templates/result_templates/default.html b/searx/templates/result_templates/default.html
@@ -1,13 +0,0 @@
-<div class="result {{ result.class }}">
-
- {% if result['favicon'] %}
- <img width="14" height="14" class="favicon" src="static/img/icon_{{result['favicon']}}.ico" />
- {% endif %}
-
- <div>
- <h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
- {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
- <p class="content">{% if result.content %}{{ result.content|safe }}<br />{% endif %}</p>
- <p class="url">{{ result.pretty_url }}</p>
- </div>
-</div>
diff --git a/searx/templates/result_templates/videos.html b/searx/templates/result_templates/videos.html
@@ -1,12 +0,0 @@
-<div class="result">
- {% if result['favicon'] %}
- <img width="14" height="14" class="favicon" src="static/img/icon_{{result['favicon']}}.ico" />
- {% endif %}
-
- <p>
- <h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
- {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
- <a href="{{ result.url }}"><img width="400px" src="{{ result.thumbnail }}" title={{ result.title }} alt=" {{ result.title }}"/></a>
- <p class="url">{{ result.url }}</p>
- </p>
-</div>
diff --git a/searx/templates/results.html b/searx/templates/results.html
@@ -1,79 +0,0 @@
-{% extends "base.html" %}
-{% block title %}{{ q }} - {% endblock %}
-{% block content %}
-<div class="right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
-<div class="small search center">
- {% include 'search.html' %}
-</div>
-<div id="results">
- <div id="sidebar">
-
- <div id="search_url">
- {{ _('Search URL') }}:
- <input type="text" value="{{ base_url }}?q={{ q|urlencode }}&pageno={{ pageno }}{% if selected_categories %}&category_{{ selected_categories|join("&category_") }}{% endif %}" readonly="" />
- </div>
- <div id="apis">
- {{ _('Download results') }}
- {% for output_type in ('csv', 'json', 'rss') %}
- <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
- <div class="left">
- <input type="hidden" name="q" value="{{ q }}" />
- <input type="hidden" name="format" value="{{ output_type }}" />
- {% for category in selected_categories %}
- <input type="hidden" name="category_{{ category }}" value="1"/>
- {% endfor %}
- <input type="hidden" name="pageno" value="{{ pageno }}" />
- <input type="submit" value="{{ output_type }}" />
- </div>
- </form>
- {% endfor %}
- </div>
- </div>
-
- {% if suggestions %}
- <div id="suggestions"><span>{{ _('Suggestions') }}</span>
- {% for suggestion in suggestions %}
- <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
- <input type="hidden" name="q" value="{{ suggestion }}">
- <input type="submit" value="{{ suggestion }}" />
- </form>
- {% endfor %}
- </div>
- {% endif %}
-
- {% for result in results %}
- {% if result['template'] %}
- {% include 'result_templates/'+result['template'] %}
- {% else %}
- {% include 'result_templates/default.html' %}
- {% endif %}
- {% endfor %}
-
- {% if paging %}
- <div id="pagination">
- {% if pageno > 1 %}
- <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
- <div class="left">
- <input type="hidden" name="q" value="{{ q }}" />
- {% for category in selected_categories %}
- <input type="hidden" name="category_{{ category }}" value="1"/>
- {% endfor %}
- <input type="hidden" name="pageno" value="{{ pageno-1 }}" />
- <input type="submit" value="<< {{ _('previous page') }}" />
- </div>
- </form>
- {% endif %}
- <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
- <div class="left">
- {% for category in selected_categories %}
- <input type="hidden" name="category_{{ category }}" value="1"/>
- {% endfor %}
- <input type="hidden" name="q" value="{{ q }}" />
- <input type="hidden" name="pageno" value="{{ pageno+1 }}" />
- <input type="submit" value="{{ _('next page') }} >>" />
- </div>
- </form>
- </div>
- {% endif %}
-</div>
-{% endblock %}
diff --git a/searx/templates/search.html b/searx/templates/search.html
@@ -1,7 +0,0 @@
-<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form">
- <div id="search_wrapper">
- <input type="text" placeholder="{{ _('Search for...') }}" id="q" class="q" name="q" tabindex="1" autocomplete="off" {% if q %}value="{{ q }}"{% endif %}/>
- <input type="submit" value="search" id="search_submit" />
- </div>
- {% include 'categories.html' %}
-</form>
diff --git a/searx/templates/stats.html b/searx/templates/stats.html
@@ -1,22 +0,0 @@
-{% extends "base.html" %}
-{% block head %} {% endblock %}
-{% block content %}
-<h2>{{ _('Engine stats') }}</h2>
-
-{% for stat_name,stat_category in stats %}
-<div class="left">
- <table>
- <tr colspan="3">
- <th>{{ stat_name }}</th>
- </tr>
- {% for engine in stat_category %}
- <tr>
- <td>{{ engine.name }}</td>
- <td>{{ '%.02f'|format(engine.avg) }}</td>
- <td class="percentage"><div style="width: {{ engine.percentage }}%"> </div></td>
- </tr>
- {% endfor %}
- </table>
-</div>
-{% endfor %}
-{% endblock %}
diff --git a/searx/utils.py b/searx/utils.py
@@ -1,10 +1,12 @@
-from HTMLParser import HTMLParser
#import htmlentitydefs
-import csv
from codecs import getincrementalencoder
+from HTMLParser import HTMLParser
+from random import choice
+
import cStringIO
+import csv
+import os
import re
-from random import choice
ua_versions = ('26.0', '27.0', '28.0')
ua_os = ('Windows NT 6.3; WOW64',
@@ -110,3 +112,17 @@ class UnicodeWriter:
def writerows(self, rows):
for row in rows:
self.writerow(row)
+
+
+def get_themes(root):
+ """Returns available themes list."""
+
+ static_path = os.path.join(root, 'static')
+ static_names = set(os.listdir(static_path))
+ templates_path = os.path.join(root, 'templates')
+ templates_names = set(os.listdir(templates_path))
+
+ themes = []
+ for name in static_names.intersection(templates_names):
+ themes += [name]
+ return static_path, templates_path, themes
diff --git a/searx/webapp.py b/searx/webapp.py
@@ -38,16 +38,23 @@ from searx.engines import (
search as do_search, categories, engines, get_engines_stats,
engine_shortcuts
)
-from searx.utils import UnicodeWriter, highlight_content, html_to_text
+from searx.utils import (
+ UnicodeWriter, highlight_content, html_to_text, get_themes
+)
from searx.languages import language_codes
from searx.search import Search
from searx.autocomplete import backends as autocomplete_backends
+static_path, templates_path, themes = get_themes(settings['themes_path'] if \
+ settings.get('themes_path', None) else searx_dir)
+default_theme = settings['default_theme'] if \
+ settings.get('default_theme', None) else 'default'
+
app = Flask(
__name__,
- static_folder=os.path.join(searx_dir, 'static'),
- template_folder=os.path.join(searx_dir, 'templates')
+ static_folder=static_path,
+ template_folder=templates_path
)
app.secret_key = settings['server']['secret_key']
@@ -90,7 +97,30 @@ def get_base_url():
return hostname
-def render(template_name, **kwargs):
+def get_current_theme_name(override=None):
+ """Returns theme name.
+
+ Checks in this order:
+ 1. override
+ 2. cookies
+ 3. settings"""
+
+ if override and override in themes:
+ return override
+ theme_name = request.cookies.get('theme', default_theme)
+ if theme_name not in themes:
+ theme_name = default_theme
+ return theme_name
+
+
+def url_for_theme(endpoint, override_theme=None, **values):
+ if endpoint == 'static' and values.get('filename', None):
+ theme_name = get_current_theme_name(override=override_theme)
+ values['filename'] = "{}/{}".format(theme_name, values['filename'])
+ return url_for(endpoint, **values)
+
+
+def render(template_name, override_theme=None, **kwargs):
blocked_engines = request.cookies.get('blocked_engines', '').split(',')
autocomplete = request.cookies.get('autocomplete')
@@ -125,7 +155,13 @@ def render(template_name, **kwargs):
kwargs['method'] = request.cookies.get('method', 'POST')
- return render_template(template_name, **kwargs)
+ # override url_for function in templates
+ kwargs['url_for'] = url_for_theme
+
+ kwargs['theme'] = get_current_theme_name(override=override_theme)
+
+ return render_template(
+ '{}/{}'.format(kwargs['theme'], template_name), **kwargs)
@app.route('/search', methods=['GET', 'POST'])
@@ -232,7 +268,8 @@ def index():
paging=search.paging,
pageno=search.pageno,
base_url=get_base_url(),
- suggestions=search.suggestions
+ suggestions=search.suggestions,
+ theme=get_current_theme_name()
)
@@ -290,7 +327,7 @@ def preferences():
if request.method == 'GET':
blocked_engines = request.cookies.get('blocked_engines', '').split(',')
- else:
+ else: # on save
selected_categories = []
locale = None
autocomplete = ''
@@ -315,6 +352,8 @@ def preferences():
engine_name = pd_name.replace('engine_', '', 1)
if engine_name in engines:
blocked_engines.append(engine_name)
+ elif pd_name == 'theme':
+ theme = pd if pd in themes else default_theme
resp = make_response(redirect(url_for('index')))
@@ -352,6 +391,9 @@ def preferences():
resp.set_cookie('method', method, max_age=cookie_max_age)
+ resp.set_cookie(
+ 'theme', theme, max_age=cookie_max_age)
+
return resp
return render('preferences.html',
locales=settings['locales'],
@@ -361,7 +403,9 @@ def preferences():
categs=categories.items(),
blocked_engines=blocked_engines,
autocomplete_backends=autocomplete_backends,
- shortcuts={y: x for x, y in engine_shortcuts.items()})
+ shortcuts={y: x for x, y in engine_shortcuts.items()},
+ themes=themes,
+ theme=get_current_theme_name())
@app.route('/stats', methods=['GET'])
@@ -404,7 +448,10 @@ def opensearch():
@app.route('/favicon.ico')
def favicon():
- return send_from_directory(os.path.join(app.root_path, 'static/img'),
+ return send_from_directory(os.path.join(app.root_path,
+ 'static',
+ get_current_theme_name(),
+ 'img'),
'favicon.png',
mimetype='image/vnd.microsoft.icon')