source: themeengineplugin/tags/themeengine-2.3.0/themeengine/web_ui.py

Last change on this file was 18428, checked in by Cinc-th, 2 years ago

ThemeEnginePlugin: allow to use a list of CSS files.

File size: 7.0 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2006-2010 Noah Kantrowitz <noah@coderanger.net>
4# Copyright (c) 2013      Olemis Lang <olemis+trac@gmail.com>
5# Copyright (c) 2021      Cinc
6#
7# All rights reserved.
8#
9# This software is licensed as described in the file COPYING, which
10# you should have received as part of this distribution.
11#
12
13import os.path
14import sys
15
16from pkg_resources import resource_filename
17
18from trac.core import *
19from trac.core import ComponentMeta
20from trac.config import BoolOption
21from trac.util.text import exception_to_unicode
22from trac.web.chrome import add_script, add_stylesheet, add_warning, Chrome, \
23                            ITemplateProvider
24from trac.web.api import IRequestFilter
25
26from themeengine.api import ThemeEngineSystem, ThemeNotFound
27from themeengine.translation import I18N_DOC_OPTIONS
28
29
30PY3 = sys.version_info.major == 3
31
32
33class ThemeEngineModule(Component):
34    """A module to provide the theme content."""
35
36    custom_css = BoolOption('theme', 'enable_css', default='false',
37                            doc='Enable or disable custom CSS from theme.',
38                            **I18N_DOC_OPTIONS)
39
40    implements(ITemplateProvider, IRequestFilter)
41
42    def __init__(self):
43        self.system = ThemeEngineSystem(self.env)
44
45    # ITemplateProvider methods
46    def get_htdocs_dirs(self):
47        try:
48            theme = self.system.theme
49            if theme and 'htdocs' in theme:
50                theme_htdocs = theme['htdocs']
51                if not os.path.isabs(theme_htdocs):
52                    theme_htdocs = resource_filename(theme['module'], theme_htdocs)
53                yield 'theme', theme_htdocs
54        except ThemeNotFound:
55            pass
56
57    def get_templates_dirs(self):
58        try:
59            theme = self.system.theme
60            if theme:
61                if 'template' in theme:
62                    theme_templates = os.path.dirname(theme['template'])
63                    if not os.path.isabs(theme_templates):
64                        theme_templates = resource_filename(theme['module'],
65                                                            theme_templates)
66                    yield theme_templates
67                if 'jinja_template' in theme:
68                    theme_templates = os.path.dirname(theme['jinja_template'])
69                    if not os.path.isabs(theme_templates):
70                        theme_templates = resource_filename(theme['module'],
71                                                            theme_templates)
72                    yield theme_templates
73
74        except ThemeNotFound:
75            pass
76
77    # IRequestFilter methods
78    def pre_process_request(self, req, handler):
79        return handler
80
81    def post_process_request(self, req, template, data, content_type):
82        if (template, data) != (None, None) or \
83                sys.exc_info() != (None, None, None):
84            try:
85                theme = self.system.theme
86            except ThemeNotFound as e:
87                add_warning(req, "Unknown theme %s configured. Please check "
88                        "your trac.ini. You may need to enable "
89                        "the theme\'s plugin." % e.theme_name)
90            else:
91                if theme and 'css' in theme:
92                    css = theme['css']
93                    if isinstance(css, tuple) or isinstance(css, list):
94                        for css_file in css:
95                            add_stylesheet(req, 'theme/' + css_file)
96                    else:
97                        add_stylesheet(req, 'theme/' + theme['css'])
98                if hasattr(Chrome, 'jenv'):
99                    # Trac 1.4 supports Genshi and Jinja2 templates. content_type is 'None' in Trac 1.4
100                    # when a Genshi template is being rendered.
101                    # Trac 1.6 only supports Jinja2.
102                    if content_type != None or (template, data) == (None, None):
103                        # If an exception occurs, for example permission error, the content_type is always 'None'.
104                        # So we need to handle exception pages here.
105                        if theme and 'jinja_template' in theme:
106                            req.chrome['theme'] = os.path.basename(theme['jinja_template'])
107                    else:
108                        # Legacy Genshi template rendering.
109                        if theme and 'template' in theme:
110                            req.chrome['theme'] = os.path.basename(theme['template'])
111                else:
112                    if theme and 'template' in theme:
113                        req.chrome['theme'] = os.path.basename(theme['template'])
114                if theme and 'scripts' in theme:
115                    for script_def in theme['scripts']:
116                        if (isinstance(script_def, tuple) and
117                                1 <= len(script_def) <= 4):
118                            temp = [item for item in script_def]
119                            if not temp[0].startswith('theme'):
120                                temp[0] = 'theme/' + temp[0].lstrip('/')
121                            add_script(req, *temp)
122                        else:
123                            self.log.warning('Bad script def %s for theme %s. Is definition a tuple?',
124                                             script_def, theme['name'])
125                if theme and theme.get('disable_trac_css'):
126                    links = req.chrome.get('links')
127                    if links and 'stylesheet' in links:
128                        for i, link in enumerate(links['stylesheet']):
129                            if link.get('href', '') \
130                                    .endswith('common/css/trac.css'):
131                                del links['stylesheet'][i]
132                                break
133                if theme:
134                    req.chrome['theme_info'] = theme
135                    # Template overrides (since 2.2.0)
136                    overrides = self._get_template_overrides(theme)
137                    template, modifier = overrides.get(template,
138                                                       (template, None))
139                    if modifier is not None:
140                        modifier(req, template, data, content_type)
141            if self.custom_css:
142                add_stylesheet(req, 'site/theme.css')
143
144        return template, data, content_type
145
146    # Protected methods
147    def _get_template_overrides(self, theme):
148        overrides = theme.get('template_overrides')
149        if overrides is None:
150            try:
151                overrides = theme['provider'].get_template_overrides(
152                                                    theme['name'])
153            except Exception as e:
154                overrides = {}
155                self.log.warning('Theme %s template overrides : %s',
156                                 theme['name'],
157                                 exception_to_unicode(e))
158            else:
159                overrides = dict([old, (new, callback)]
160                                 for old, new, callback in overrides)
161            theme['template_overrides'] = overrides
162        return overrides
Note: See TracBrowser for help on using the repository browser.