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
76 lines
2.1 KiB
Python
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)
|