Files
odoo_source/odoo/tools/rendering_tools.py
T
Nicolas Bayet 4813f42997 [IMP] mail,*: replace jinja with qweb
Jinja as a templating engine was problematic in differents respect:
- introduce external dependency to Odoo (less controll)
- add another templating mechanism in the stack
- specific feature in qweb cannot be reused
- difficulty in rendering easily editable templates
- more knowledge required with no betterment

By replacing jinja with qweb we can now build tools to edit a qweb
that will work with the previously jinja encoded document
(essentially `mail.template` records).

There is a catch however. Some email fields (eg. email_to) used jinja
syntax for rendering dynamic variables (ie. ${object.something} and
${object.something_that_should_not_be_escaped | safe}).

We still want user to use dynamic variables for some char fields (eg.
subject, from, to, ...). We made a new rendering engine called
"inline_template" that will render an expression enclosed by `{{` and
`}}`.

To be able to edit the templates from the backend interface, a
plugin to the Odoo editor has been made for seamlessly edit the
document.

This qweb plugin includes:
- make dynamic variables (eg. `<t t-out="variable"/>`) not editable
  (for preventing the user to shoot himself in the foot)
- group and hide related logical branching (ie. t-if, t-elif, and t-else)
  in order to see only one at once
- a floating select input to switch visibility of a particular logical
  branching

Task-27033

X-original-commit: odoo/odoo@68182baff4
Part-of: odoo/odoo#77377
2021-09-28 23:42:54 +00:00

76 lines
2.1 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import dateutil.relativedelta as relativedelta
import functools
import re
from markupsafe import Markup
from werkzeug import urls
from odoo.tools import safe_eval
INLINE_TEMPLATE_REGEX = re.compile(r"\{\{(.+?)\}\}")
def relativedelta_proxy(*args, **kwargs):
# dateutil.relativedelta is an old-style class and cannot be directly
# instanciated wihtin a jinja2 expression, so a lambda "proxy" is
# is needed, apparently
return relativedelta.relativedelta(*args, **kwargs)
template_env_globals = {
'str': str,
'quote': urls.url_quote,
'urlencode': urls.url_encode,
'datetime': safe_eval.datetime,
'len': len,
'abs': abs,
'min': min,
'max': max,
'sum': sum,
'filter': filter,
'reduce': functools.reduce,
'map': map,
'relativedelta': relativedelta.relativedelta,
'round': round,
'hasattr': hasattr,
}
def parse_inline_template(text):
groups = []
current_literal_index = 0
for match in INLINE_TEMPLATE_REGEX.finditer(text):
literal = text[current_literal_index:match.start()]
expression = match.group(1)
groups.append((literal, expression))
current_literal_index = match.end()
# string past last regex match
literal = text[current_literal_index:]
if literal:
groups.append((literal, ''))
return groups
def convert_inline_template_to_qweb(template):
template_instructions = parse_inline_template(template or '')
preview_markup = []
for string, expression in template_instructions:
if expression:
preview_markup.append(Markup('{}<t t-out="{}"/>').format(string, expression))
else:
preview_markup.append(string)
return Markup('').join(preview_markup)
def render_inline_template(template_instructions, variables):
results = []
for string, expression in template_instructions:
results.append(string)
if expression:
result = safe_eval.safe_eval(expression, variables)
if result:
results.append(str(result))
return ''.join(results)