QWeb is the primary templating engine used by Odoo. It is an XML templating engine and used mostly to generate XML, HTML fragments and pages. To create new XML template, please see :doc:`QWeb Templates documentation <https://www.odoo.com/documentation/15.0/developer/reference/frontend/qweb.html>` In **input** you have an XML template giving the corresponding input etree. Each etree input nodes are used to generate a python function. This fonction is called and will give the XML **output**. The ``_compile`` method is responsible to generate the function from the etree, that function is a python generator that yield one output line at a time. This generator is consumed by ``_render``. The generated function is orm cached. In the graphic below you can see theresume of the call of the methods performed in the IrQweb class. Odoo ┗━► _render (returns MarkupSafe) ┗━► _compile (returns function) ◄━━━━━━━━━┓ ┗━► _compile_node (returns code string array) ◄━━━━━━━┓ ┃ ┃ (add technical directives: t-inner-content, t-tag) ┃ ┃ ┣━► _directives_eval_order (defined directive order) ┃ ┃ ┃ ┃ ┃ ┣━► _compile_directives (recursive) ◄━━━━┓ ┃ ┃ ┃ ┣━► _compile_directive ┃ ┃ ┃ ┃ ┃ ┗━► t-if ━━► _compile_directive_if ━┫ ┃ ┃ ┃ ┃ ┗━► t-foreach ━━► _compile_directive_foreach ━┫ ┃ ┃ ┃ ┃ ┗━► t-* ━━► ... ━┛ ┃ ┃ ┃ ┃ ┗━► t-inner-content ━━► _compile_directive_inner_content ◄━━━━┓ ━┛ ┃ ┃ ┃ ┗━► t-tag ━━► _compile_directive_tag ━┫ ┃ ┃ ┃ ┗━► t-call ━━► _compile_directive_call ━┫ ━━━┛ ┃ ┃ ┗━► t-out ━━► _compile_directive_out ◄━┓ ━┫ ┃ ┃ ┗━► t-field ━━► _compile_directive_field ━┛ ┃ ┃ ┃ ┃ ┗━━┻━► _compile_static_node ━┛ Part-of: odoo/odoo#81024
92 lines
3.5 KiB
Python
92 lines
3.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import re
|
|
from collections import OrderedDict
|
|
|
|
from odoo import models
|
|
from odoo.http import request
|
|
from odoo.addons.base.models.assetsbundle import AssetsBundle
|
|
from odoo.addons.http_routing.models.ir_http import url_for
|
|
from odoo.osv import expression
|
|
from odoo.addons.website.models import ir_http
|
|
from odoo.tools import html_escape as escape
|
|
|
|
re_background_image = re.compile(r"(background-image\s*:\s*url\(\s*['\"]?\s*)([^)'\"]+)")
|
|
|
|
|
|
class AssetsBundleMultiWebsite(AssetsBundle):
|
|
def _get_asset_url_values(self, id, unique, extra, name, sep, extension):
|
|
website_id = self.env.context.get('website_id')
|
|
website_id_path = website_id and ('%s/' % website_id) or ''
|
|
extra = website_id_path + extra
|
|
res = super(AssetsBundleMultiWebsite, self)._get_asset_url_values(id, unique, extra, name, sep, extension)
|
|
return res
|
|
|
|
def _get_assets_domain_for_already_processed_css(self, assets):
|
|
res = super(AssetsBundleMultiWebsite, self)._get_assets_domain_for_already_processed_css(assets)
|
|
current_website = self.env['website'].get_current_website(fallback=False)
|
|
res = expression.AND([res, current_website.website_domain()])
|
|
return res
|
|
|
|
def get_debug_asset_url(self, extra='', name='%', extension='%'):
|
|
website_id = self.env.context.get('website_id')
|
|
website_id_path = website_id and ('%s/' % website_id) or ''
|
|
extra = website_id_path + extra
|
|
return super(AssetsBundleMultiWebsite, self).get_debug_asset_url(extra, name, extension)
|
|
|
|
class IrQWeb(models.AbstractModel):
|
|
""" IrQWeb object for rendering stuff in the website context """
|
|
|
|
_inherit = 'ir.qweb'
|
|
|
|
URL_ATTRS = {
|
|
'form': 'action',
|
|
'a': 'href',
|
|
'link': 'href',
|
|
'script': 'src',
|
|
'img': 'src',
|
|
}
|
|
|
|
def _get_asset_bundle(self, xmlid, files, env=None, css=True, js=True):
|
|
return AssetsBundleMultiWebsite(xmlid, files, env=env)
|
|
|
|
def _post_processing_att(self, tagName, atts, options):
|
|
if atts.get('data-no-post-process'):
|
|
return atts
|
|
|
|
atts = super(IrQWeb, self)._post_processing_att(tagName, atts, options)
|
|
|
|
if tagName == 'img' and 'loading' not in atts:
|
|
atts['loading'] = 'lazy' # default is auto
|
|
|
|
if options.get('inherit_branding') or options.get('rendering_bundle') or \
|
|
options.get('edit_translations') or options.get('debug') or (request and request.session.debug):
|
|
return atts
|
|
|
|
website = ir_http.get_request_website()
|
|
if not website and options.get('website_id'):
|
|
website = self.env['website'].browse(options['website_id'])
|
|
|
|
if not website:
|
|
return atts
|
|
|
|
name = self.URL_ATTRS.get(tagName)
|
|
if request and name and name in atts:
|
|
atts[name] = url_for(atts[name])
|
|
|
|
if not website.cdn_activated:
|
|
return atts
|
|
|
|
data_name = f'data-{name}'
|
|
if name and (name in atts or data_name in atts):
|
|
atts = OrderedDict(atts)
|
|
if name in atts:
|
|
atts[name] = website.get_cdn_url(atts[name])
|
|
if data_name in atts:
|
|
atts[data_name] = website.get_cdn_url(atts[data_name])
|
|
if isinstance(atts.get('style'), str) and 'background-image' in atts['style']:
|
|
atts = OrderedDict(atts)
|
|
atts['style'] = re_background_image.sub(lambda m: '%s%s' % (m.group(1), website.get_cdn_url(m.group(2))), atts['style'])
|
|
|
|
return atts
|