Files
odoo_source/addons/website/models/ir_qweb.py
T
Gorash 9ce5bc8881 [IMP] IrQweb: merge Qweb engine file qweb.py and ir_qweb.py
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
2022-02-03 08:09:31 +00:00

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