Merge pull request #70 from matejc/theming_support
add multi theming support
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						@ -44,13 +44,13 @@ minimal: bin/buildout minimal.cfg setup.py
 | 
				
			|||||||
	bin/buildout -c minimal.cfg $(options)
 | 
						bin/buildout -c minimal.cfg $(options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
styles:
 | 
					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:
 | 
					locales:
 | 
				
			||||||
	@pybabel compile -d searx/translations
 | 
						@pybabel compile -d searx/translations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	@rm -rf .installed.cfg .mr.developer.cfg bin parts develop-eggs \
 | 
						@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
 | 
					.PHONY: all tests robot flake8 coverage production minimal styles locales clean
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,8 @@ server:
 | 
				
			|||||||
    debug : True
 | 
					    debug : True
 | 
				
			||||||
    request_timeout : 2.0 # seconds
 | 
					    request_timeout : 2.0 # seconds
 | 
				
			||||||
    base_url : False
 | 
					    base_url : False
 | 
				
			||||||
 | 
					    themes_path : ""
 | 
				
			||||||
 | 
					    default_theme : default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
engines:
 | 
					engines:
 | 
				
			||||||
  - name : wikipedia
 | 
					  - name : wikipedia
 | 
				
			||||||
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB  | 
| 
		 Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB  | 
| 
		 Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB  | 
| 
		 Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 837 B After Width: | Height: | Size: 837 B  | 
| 
		 Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB  | 
| 
		 Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB  | 
| 
		 Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB  | 
@ -1,6 +1,6 @@
 | 
				
			|||||||
{% extends 'base.html' %}
 | 
					{% extends 'default/base.html' %}
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
{% include 'github_ribbon.html' %}
 | 
					{% include 'default/github_ribbon.html' %}
 | 
				
			||||||
<div class="row">
 | 
					<div class="row">
 | 
				
			||||||
    <h1>About <a href="{{ url_for('index') }}">searx</a></h1>
 | 
					    <h1>About <a href="{{ url_for('index') }}">searx</a></h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					{% extends "default/base.html" %}
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
<div class="center">
 | 
					<div class="center">
 | 
				
			||||||
    <div class="title"><h1>searx</h1></div>
 | 
					    <div class="title"><h1>searx</h1></div>
 | 
				
			||||||
    {% include 'search.html' %}
 | 
					    {% include 'default/search.html' %}
 | 
				
			||||||
    <p class="top_margin">
 | 
					    <p class="top_margin">
 | 
				
			||||||
        <a href="{{ url_for('about') }}" class="hmarg">{{ _('about') }}</a>
 | 
					        <a href="{{ url_for('about') }}" class="hmarg">{{ _('about') }}</a>
 | 
				
			||||||
        <a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
 | 
					        <a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					{% extends "default/base.html" %}
 | 
				
			||||||
{% block head %} {% endblock %}
 | 
					{% block head %} {% endblock %}
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
<div class="row">
 | 
					<div class="row">
 | 
				
			||||||
@ -8,7 +8,7 @@
 | 
				
			|||||||
    <fieldset>
 | 
					    <fieldset>
 | 
				
			||||||
        <legend>{{ _('Default categories') }}</legend>
 | 
					        <legend>{{ _('Default categories') }}</legend>
 | 
				
			||||||
        <p>
 | 
					        <p>
 | 
				
			||||||
        {% include 'categories.html' %}
 | 
					        {% include 'default/categories.html' %}
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
    </fieldset>
 | 
					    </fieldset>
 | 
				
			||||||
    <fieldset>
 | 
					    <fieldset>
 | 
				
			||||||
@ -52,6 +52,16 @@
 | 
				
			|||||||
        </select>
 | 
					        </select>
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
    </fieldset>
 | 
					    </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>
 | 
					    <fieldset>
 | 
				
			||||||
    <legend>{{ _('Currently used search engines') }}</legend>
 | 
					    <legend>{{ _('Currently used search engines') }}</legend>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
<div class="result {{ result.class }}">
 | 
					<div class="result {{ result.class }}">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {% if result['favicon'] %}
 | 
					  {% if result['favicon'] %}
 | 
				
			||||||
    <img width="14" height="14" class="favicon" src="static/img/icon_{{result['favicon']}}.ico" />
 | 
					    <img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" />
 | 
				
			||||||
  {% endif %}
 | 
					  {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div>
 | 
					  <div>
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
<div class="result">
 | 
					<div class="result">
 | 
				
			||||||
  {% if result['favicon'] %}
 | 
					  {% if result['favicon'] %}
 | 
				
			||||||
    <img width="14" height="14" class="favicon" src="static/img/icon_{{result['favicon']}}.ico" />
 | 
					    <img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" />
 | 
				
			||||||
  {% endif %}
 | 
					  {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <p>
 | 
					    <p>
 | 
				
			||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					{% extends "default/base.html" %}
 | 
				
			||||||
{% block title %}{{ q }} - {% endblock %}
 | 
					{% block title %}{{ q }} - {% endblock %}
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
<div class="right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
 | 
					<div class="right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
 | 
				
			||||||
<div class="small search center">
 | 
					<div class="small search center">
 | 
				
			||||||
    {% include 'search.html' %}
 | 
					    {% include 'default/search.html' %}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
<div id="results">
 | 
					<div id="results">
 | 
				
			||||||
    <div id="sidebar">
 | 
					    <div id="sidebar">
 | 
				
			||||||
@ -43,9 +43,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    {% for result in results %}
 | 
					    {% for result in results %}
 | 
				
			||||||
        {% if result['template'] %}
 | 
					        {% if result['template'] %}
 | 
				
			||||||
            {% include 'result_templates/'+result['template'] %}
 | 
					            {% include 'default/result_templates/'+result['template'] %}
 | 
				
			||||||
        {% else %}
 | 
					        {% else %}
 | 
				
			||||||
            {% include 'result_templates/default.html' %}
 | 
					            {% include 'default/result_templates/default.html' %}
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
    {% endfor %}
 | 
					    {% endfor %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3,5 +3,5 @@
 | 
				
			|||||||
    <input type="text" placeholder="{{ _('Search for...') }}" id="q" class="q" name="q" tabindex="1" autocomplete="off" {% if q %}value="{{ q }}"{% endif %}/>
 | 
					    <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" />
 | 
					    <input type="submit" value="search" id="search_submit" />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  {% include 'categories.html' %}
 | 
					  {% include 'default/categories.html' %}
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					{% extends "default/base.html" %}
 | 
				
			||||||
{% block head %} {% endblock %}
 | 
					{% block head %} {% endblock %}
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
<h2>{{ _('Engine stats') }}</h2>
 | 
					<h2>{{ _('Engine stats') }}</h2>
 | 
				
			||||||
@ -1,11 +1,13 @@
 | 
				
			|||||||
from HTMLParser import HTMLParser
 | 
					 | 
				
			||||||
#import htmlentitydefs
 | 
					#import htmlentitydefs
 | 
				
			||||||
import csv
 | 
					 | 
				
			||||||
from codecs import getincrementalencoder
 | 
					from codecs import getincrementalencoder
 | 
				
			||||||
import cStringIO
 | 
					from HTMLParser import HTMLParser
 | 
				
			||||||
import re
 | 
					 | 
				
			||||||
from random import choice
 | 
					from random import choice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cStringIO
 | 
				
			||||||
 | 
					import csv
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ua_versions = ('26.0', '27.0', '28.0')
 | 
					ua_versions = ('26.0', '27.0', '28.0')
 | 
				
			||||||
ua_os = ('Windows NT 6.3; WOW64',
 | 
					ua_os = ('Windows NT 6.3; WOW64',
 | 
				
			||||||
         'X11; Linux x86_64',
 | 
					         'X11; Linux x86_64',
 | 
				
			||||||
@ -110,3 +112,17 @@ class UnicodeWriter:
 | 
				
			|||||||
    def writerows(self, rows):
 | 
					    def writerows(self, rows):
 | 
				
			||||||
        for row in rows:
 | 
					        for row in rows:
 | 
				
			||||||
            self.writerow(row)
 | 
					            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
 | 
				
			||||||
 | 
				
			|||||||
@ -38,16 +38,23 @@ from searx.engines import (
 | 
				
			|||||||
    search as do_search, categories, engines, get_engines_stats,
 | 
					    search as do_search, categories, engines, get_engines_stats,
 | 
				
			||||||
    engine_shortcuts
 | 
					    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.languages import language_codes
 | 
				
			||||||
from searx.search import Search
 | 
					from searx.search import Search
 | 
				
			||||||
from searx.autocomplete import backends as autocomplete_backends
 | 
					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(
 | 
					app = Flask(
 | 
				
			||||||
    __name__,
 | 
					    __name__,
 | 
				
			||||||
    static_folder=os.path.join(searx_dir, 'static'),
 | 
					    static_folder=static_path,
 | 
				
			||||||
    template_folder=os.path.join(searx_dir, 'templates')
 | 
					    template_folder=templates_path
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app.secret_key = settings['server']['secret_key']
 | 
					app.secret_key = settings['server']['secret_key']
 | 
				
			||||||
@ -90,7 +97,30 @@ def get_base_url():
 | 
				
			|||||||
    return hostname
 | 
					    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(',')
 | 
					    blocked_engines = request.cookies.get('blocked_engines', '').split(',')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    autocomplete = request.cookies.get('autocomplete')
 | 
					    autocomplete = request.cookies.get('autocomplete')
 | 
				
			||||||
@ -125,7 +155,13 @@ def render(template_name, **kwargs):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    kwargs['method'] = request.cookies.get('method', 'POST')
 | 
					    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'])
 | 
					@app.route('/search', methods=['GET', 'POST'])
 | 
				
			||||||
@ -232,7 +268,8 @@ def index():
 | 
				
			|||||||
        paging=search.paging,
 | 
					        paging=search.paging,
 | 
				
			||||||
        pageno=search.pageno,
 | 
					        pageno=search.pageno,
 | 
				
			||||||
        base_url=get_base_url(),
 | 
					        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':
 | 
					    if request.method == 'GET':
 | 
				
			||||||
        blocked_engines = request.cookies.get('blocked_engines', '').split(',')
 | 
					        blocked_engines = request.cookies.get('blocked_engines', '').split(',')
 | 
				
			||||||
    else:
 | 
					    else:  # on save
 | 
				
			||||||
        selected_categories = []
 | 
					        selected_categories = []
 | 
				
			||||||
        locale = None
 | 
					        locale = None
 | 
				
			||||||
        autocomplete = ''
 | 
					        autocomplete = ''
 | 
				
			||||||
@ -315,6 +352,8 @@ def preferences():
 | 
				
			|||||||
                engine_name = pd_name.replace('engine_', '', 1)
 | 
					                engine_name = pd_name.replace('engine_', '', 1)
 | 
				
			||||||
                if engine_name in engines:
 | 
					                if engine_name in engines:
 | 
				
			||||||
                    blocked_engines.append(engine_name)
 | 
					                    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')))
 | 
					        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('method', method, max_age=cookie_max_age)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resp.set_cookie(
 | 
				
			||||||
 | 
					            'theme', theme, max_age=cookie_max_age)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return resp
 | 
					        return resp
 | 
				
			||||||
    return render('preferences.html',
 | 
					    return render('preferences.html',
 | 
				
			||||||
                  locales=settings['locales'],
 | 
					                  locales=settings['locales'],
 | 
				
			||||||
@ -361,7 +403,9 @@ def preferences():
 | 
				
			|||||||
                  categs=categories.items(),
 | 
					                  categs=categories.items(),
 | 
				
			||||||
                  blocked_engines=blocked_engines,
 | 
					                  blocked_engines=blocked_engines,
 | 
				
			||||||
                  autocomplete_backends=autocomplete_backends,
 | 
					                  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'])
 | 
					@app.route('/stats', methods=['GET'])
 | 
				
			||||||
@ -404,7 +448,10 @@ def opensearch():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@app.route('/favicon.ico')
 | 
					@app.route('/favicon.ico')
 | 
				
			||||||
def favicon():
 | 
					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',
 | 
					                               'favicon.png',
 | 
				
			||||||
                               mimetype='image/vnd.microsoft.icon')
 | 
					                               mimetype='image/vnd.microsoft.icon')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||