Mercurial > libervia-backend
changeset 3478:b65175eb7769
tools (common/template): new `fallback` settings:
`fallback` can be used to change fallback behaviour. By default, fallback is done on
`default` theme, this can be set to an other theme with a string, or to a list of
fallback. The list can also be empty is no fallback is desired (notably usefull for "main"
themes, on which other themes may fallback).
This setting replaces `css_default_fallback`.
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 19 Mar 2021 14:01:52 +0100 |
parents | 9498f32ba6f7 |
children | be6d91572633 |
files | sat/tools/common/template.py |
diffstat | 1 files changed, 61 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/sat/tools/common/template.py Fri Mar 19 14:01:51 2021 +0100 +++ b/sat/tools/common/template.py Fri Mar 19 14:01:52 2021 +0100 @@ -82,7 +82,7 @@ """A template loader which handle site, theme and absolute paths""" # TODO: list_templates should be implemented - def __init__(self, sites_paths, trusted=False): + def __init__(self, sites_paths, sites_themes, trusted=False): """ @param trusted(bool): if True, absolue template paths will be allowed be careful when using this option and sure that you can trust the template, @@ -93,6 +93,7 @@ raise exceptions.InternalError("Invalid sites_paths") super(jinja2.BaseLoader, self).__init__() self.sites_paths = sites_paths + self.sites_themes = sites_themes self.trusted = trusted @staticmethod @@ -163,21 +164,29 @@ def getSitesAndThemes( site: str, theme: str, - default_fallback: bool=True + settings: Optional[dict] = None, ) -> List[Tuple[str, str]]: """Get sites and themes to check for template/file - Will add default theme and default site in search list when suitable + Will add default theme and default site in search list when suitable. Settings' + `fallback` can be used to modify behaviour: themes in this list will then be used + instead of default (it can also be empty list or None, in which case no fallback + is used). + @param site: site requested @param theme: theme requested @return: site and theme couples to check """ + if settings is None: + settings = {} sites_and_themes = [[site, theme]] - if theme != C.TEMPLATE_THEME_DEFAULT and default_fallback: - sites_and_themes.append([site, C.TEMPLATE_THEME_DEFAULT]) - if site and default_fallback: - # the site is not the default one, so we add default at the end - sites_and_themes.append(['', C.TEMPLATE_THEME_DEFAULT]) + fallback = settings.get("fallback", [C.TEMPLATE_THEME_DEFAULT]) + for fb_theme in fallback: + if theme != fb_theme: + sites_and_themes.append([site, fb_theme]) + if site: + for fb_theme in fallback: + sites_and_themes.append(["", fb_theme]) return sites_and_themes def _get_template_f(self, site, theme, path_elts): @@ -194,13 +203,20 @@ if site is None: raise exceptions.InternalError( "_get_template_f must not be used with absolute path") - for site, theme in self.getSitesAndThemes(site, theme): + settings = self.sites_themes[site][theme]['settings'] + for site_to_check, theme_to_check in self.getSitesAndThemes( + site, theme, settings): try: - base_path = self.sites_paths[site] + base_path = self.sites_paths[site_to_check] except KeyError: - log.warning(_("Unregistered site requested: {site}").format( - site=site)) - filepath = os.path.join(base_path, C.TEMPLATE_TPL_DIR, theme, *path_elts) + log.warning(_("Unregistered site requested: {site_to_check}").format( + site_to_check=site_to_check)) + filepath = os.path.join( + base_path, + C.TEMPLATE_TPL_DIR, + theme_to_check, + *path_elts + ) f = utils.open_if_exists(filepath, 'r') if f is not None: return f, filepath @@ -398,11 +414,21 @@ settings = json.load(f) except Exception as e: log.warning(_( - "Can't load theme settings at {path}").format( - path=theme_settings)) + "Can't load theme settings at {path}: {e}").format( + path=theme_settings, e=e)) else: log.debug( f"found settings for theme {p.name!r} at {theme_settings}") + fallback = settings.get("fallback") + if fallback is None: + settings["fallback"] = [] + elif isinstance(fallback, str): + settings["fallback"] = [fallback] + elif not isinstance(fallback, list): + raise ValueError( + 'incorrect type for "fallback" in settings ' + f'({type(fallback)}) at {theme_settings}: {fallback}' + ) theme_data['settings'] = settings browser_path = p / BROWSER_DIR if browser_path.is_dir(): @@ -419,7 +445,11 @@ continue self.env = Environment( - loader=TemplateLoader(sites_paths=self.sites_paths, trusted=trusted), + loader=TemplateLoader( + sites_paths=self.sites_paths, + sites_themes=self.sites_themes, + trusted=trusted + ), autoescape=jinja2.select_autoescape(["html", "xhtml", "xml"]), trim_blocks=True, lstrip_blocks=True, @@ -550,7 +580,7 @@ self._locale_str = locale_str def getThemeAndRoot(self, template): - """retrieve theme and root dir of a given tempalte + """retrieve theme and root dir of a given template @param template(unicode): template to parse @return (tuple[unicode, unicode]): theme and absolute path to theme's root dir @@ -577,7 +607,7 @@ self, template_data: TemplateData, filename: str, - default_fallback: bool=True + settings: Optional[dict]=None ) -> Optional[TemplateData]: """Retrieve path of a static file if it exists with current theme or default @@ -589,8 +619,7 @@ checked at "/some/path/<filename>" @param template_data: data of current template @param filename: name of the file to retrieve - @param default_fallback: if True, default theme will be checked if the file is - not found in current theme, then default site with default theme will be used. + @param settings: theme settings, can be used to modify behaviour @return: built template data instance where .path is the relative path to the file, from theme root dir. None if not found. @@ -610,7 +639,7 @@ sites_and_themes = TemplateLoader.getSitesAndThemes(template_data.site, template_data.theme, - default_fallback) + settings) for site, theme in sites_and_themes: site_root_dir = self.sites_paths[site] relative_path = os.path.join(C.TEMPLATE_STATIC_DIR, filename) @@ -627,7 +656,7 @@ css_files: list, css_files_noscript: list, name_root: str, - default_fallback: bool + settings: dict ) -> None: """Append found css to css_files and css_files_noscript @@ -637,12 +666,12 @@ with "_noscript" suffix """ name = name_root + ".css" - css_path = self.getStaticPath(template_data, name, default_fallback) + css_path = self.getStaticPath(template_data, name, settings) if css_path is not None: css_files.append(self.getFrontURL(css_path)) noscript_name = name_root + "_noscript.css" noscript_path = self.getStaticPath( - template_data, noscript_name, default_fallback) + template_data, noscript_name, settings) if noscript_path is not None: css_files_noscript.append(self.getFrontURL(noscript_path)) @@ -667,9 +696,9 @@ else default/static/blog_articles.css (if it exists too) and for each found files, if same file with _noscript suffix exists, it is put in noscript list (for instance (some_theme/static/styles_noscript.css)). - The behaviour may be changed with theme settings: if "css_default_fallback" is - False, only CSS from the theme is returned if it exists, default CSS is never - used. + The behaviour may be changed with theme settings: if "fallback" is set, specified + themes will be checked instead of default. The theme will be checked in given + order, and "fallback" may be None or empty list to not check anything. @param template_data(TemplateData): data of the current template @return (tuple[list[unicode], list[unicode]]): a tuple with: - front URLs of CSS files to use @@ -683,24 +712,22 @@ site = template_data.site if site is None: # absolute path - default_fallback = True + settings = {} else: - default_fallback = ( - self.sites_themes[site][template_data.theme]['settings'] - ).get('css_default_fallback', True) + settings = self.sites_themes[site][template_data.theme]['settings'] - css_path = self.getStaticPath(template_data, 'fonts.css', default_fallback) + css_path = self.getStaticPath(template_data, 'fonts.css', settings) if css_path is not None: css_files.append(self.getFrontURL(css_path)) for name_root in ('styles', 'styles_extra', 'highlight'): self._appendCSSPaths( - template_data, css_files, css_files_noscript, name_root, default_fallback) + template_data, css_files, css_files_noscript, name_root, settings) for idx in range(len(path_elems)): name_root = "_".join(path_elems[:idx+1]) self._appendCSSPaths( - template_data, css_files, css_files_noscript, name_root, default_fallback) + template_data, css_files, css_files_noscript, name_root, settings) return css_files, css_files_noscript