*: auth_password_policy, bus, calendar, event, mass_mailing, stock, survey, web_editor, web_tour, website, website_event, website_forum, website_mass_mailing, website_sale This commit is a first step towards a potential deletion of the assets_common bundle, although that step would need more work, specs and discussions as some layouts kinda only use the assets_common bundle (some take the full assets_common but parts of the assets_backend one for example). The main goal of this commit is to have the assets_frontend bundle directly include the "common" files we need. As a first step, this commit only blindly duplicates them all into assets_frontend (without removing the potentially useless ones). The goal is to have those advantages: - Reaching a frontend page only calls two main JS files (one normal and one lazy-loaded) instead of 4 (two normals and two lazy-loaded). This may help reach a better google page speed (which is becoming more and more strict). - The frontend CSS is built as one: the common SCSS which was using bootstrap variables, or even Odoo-based SCSS added by mistake in common instead of both backend and frontend is now computed with the right bootstrap customizations. E.g. the tempusdominus datetimepickers use bootstrap grays... after this PR, they use the right grays as customized by the user on the website. It was also chosen to not have a common "sub-asset" which is included in assets_frontend. Making assets_frontend completely independent makes sense (as it probably will for other "main" asset bundles): we can focus on adding the files each layout needs without the need of worrying if it impacts unrelated layouts. Sub-assets (when not strictly necessary) is also a source of errors: extending the "main" bundle instead of the right sub-asset it may use (like it was the case with the sub-assets of assets_common: _assets_common_scripts and _assets_common_styles as explained in the previous commit). So this is indeed a small drawback of not factorizing the code for the inclusion of "common" files in bundles but it seems more explicit and easier to maintain that way. Note that adding "common" file is not the most common usecase anyway, apps generally only need files in backend or frontend. The __manifest__ declaration will also likely evolve in more and more uses of wildcards to match entire directories. In the future, adding "common" web-app files in both backend, frontend and other "main" bundles could just be about one line duplicated into each bundle. closes odoo/odoo#100314 Related: odoo/enterprise#31394 Signed-off-by: Romain Derie (rde) <rde@odoo.com>
318 lines
15 KiB
XML
318 lines
15 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
|
|
<!-- Call this template instead of "web.assets_tests" to have the proper conditional check -->
|
|
<template id="conditional_assets_tests" name="Tests Assets Bundle">
|
|
<t t-call-assets="web.assets_tests" t-if="'tests' in debug or test_mode_enabled" defer_load="True" />
|
|
</template>
|
|
|
|
<template id="web.layout" name="Web layout"><!DOCTYPE html>
|
|
<html t-att="html_data or {}">
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
|
<title t-esc="title or 'Odoo'"/>
|
|
<link type="image/x-icon" rel="shortcut icon" t-att-href="x_icon or '/web/static/img/favicon.ico'"/>
|
|
<script id="web.layout.odooscript" type="text/javascript">
|
|
var odoo = {
|
|
csrf_token: "<t t-nocache="The csrf token must always be up to date." t-esc="request.csrf_token(None)"/>",
|
|
debug: "<t t-esc="debug"/>",
|
|
};
|
|
</script>
|
|
<t t-out="head or ''"/>
|
|
</head>
|
|
<body t-att-class="body_classname">
|
|
<t t-out="0"/>
|
|
</body>
|
|
</html>
|
|
</template>
|
|
|
|
<template id="web.frontend_layout" name="Frontend Layout" inherit_id="web.layout" primary="True">
|
|
<xpath expr="//head/meta[last()]" position="after">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
</xpath>
|
|
<xpath expr="//head/link[last()]" position="after">
|
|
<link rel="preload" href="/web/static/src/libs/fontawesome/fonts/fontawesome-webfont.woff2?v=4.7.0" as="font" crossorigin=""/>
|
|
<t t-call-assets="web.assets_frontend" t-js="false"/>
|
|
</xpath>
|
|
<xpath expr="//head/script[@id='web.layout.odooscript']" position="after">
|
|
<script t-nocache="Session information should always be up to date." type="text/javascript">
|
|
odoo.__session_info__ = <t t-out="json.dumps(request.env['ir.http'].get_frontend_session_info())"/>;
|
|
if (!/(^|;\s)tz=/.test(document.cookie)) {
|
|
const userTZ = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
document.cookie = `tz=${userTZ}; path=/`;
|
|
}
|
|
</script>
|
|
<t t-call-assets="web.assets_frontend_minimal" t-css="false" defer_load="True"/>
|
|
<t t-call="web.conditional_assets_tests"/>
|
|
<t t-call-assets="web.assets_frontend_lazy" t-css="false" lazy_load="True"/>
|
|
</xpath>
|
|
<xpath expr="//t[@t-out='0']" position="replace">
|
|
<div id="wrapwrap" t-attf-class="#{pageName or ''}">
|
|
<header t-if="not no_header" id="top" data-anchor="true">
|
|
<img class="img-responsive d-block mx-auto"
|
|
t-attf-src="/web/binary/company_logo"
|
|
alt="Logo"/>
|
|
</header>
|
|
<main>
|
|
<t t-out="0"/>
|
|
</main>
|
|
<footer t-cache="no_footer,no_copyright" t-if="not no_footer" id="bottom" data-anchor="true" t-attf-class="bg-light o_footer">
|
|
<div id="footer"/>
|
|
<div t-if="not no_copyright" class="o_footer_copyright">
|
|
<div class="container py-3">
|
|
<div class="row">
|
|
<div class="col-sm text-center text-sm-start text-muted">
|
|
<span class="o_footer_copyright_name me-2">Copyright &copy; <span t-field="res_company.name" itemprop="name">Company name</span></span>
|
|
</div>
|
|
<div class="col-sm text-center text-sm-end">
|
|
<t t-call="web.brand_promotion"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="brand_promotion_message" name="Brand Promotion Message">
|
|
<t t-set="odoo_logo">
|
|
<a target="_blank"
|
|
t-attf-href="http://www.odoo.com?utm_source=db&utm_medium=#{_utm_medium}"
|
|
class="badge text-bg-light">
|
|
<img alt="Odoo"
|
|
src="/web/static/img/odoo_logo_tiny.png"
|
|
style="height: 1em; vertical-align: baseline;"/>
|
|
</a>
|
|
</t>
|
|
<t t-set="final_message">Powered by %s%s</t>
|
|
<t t-out="final_message % (odoo_logo, _message and ('- ' + _message) or '')"/>
|
|
</template>
|
|
<template id="brand_promotion" name="Brand Promotion">
|
|
<div class="o_brand_promotion">
|
|
<t t-call="web.brand_promotion_message">
|
|
<t t-set="_message"></t>
|
|
<t t-set="_utm_medium" t-valuef="portal"/>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="web.login_layout" name="Login Layout">
|
|
<t t-call="web.frontend_layout">
|
|
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
|
|
<t t-set="body_classname" t-value="'bg-100'"/>
|
|
<t t-set="no_header" t-value="True"/>
|
|
<t t-set="no_footer" t-value="True"/>
|
|
|
|
<div class="container py-5">
|
|
<div t-attf-class="card border-0 mx-auto bg-100 {{login_card_classes}} o_database_list" style="max-width: 300px;">
|
|
<div class="card-body">
|
|
<div t-attf-class="text-center pb-3 border-bottom {{'mb-3' if form_small else 'mb-4'}}">
|
|
<img t-attf-src="/web/binary/company_logo{{ '?dbname='+db if db else '' }}" alt="Logo" style="max-height:120px; max-width: 100%; width:auto"/>
|
|
</div>
|
|
<t t-out="0"/>
|
|
<div class="text-center small mt-4 pt-3 border-top" t-if="not disable_footer">
|
|
<t t-if="not disable_database_manager">
|
|
<a class="border-end pe-2 me-1" href="/web/database/manager">Manage Databases</a>
|
|
</t>
|
|
<a href="https://www.odoo.com?utm_source=db&utm_medium=auth" target="_blank">Powered by <span>Odoo</span></a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="web.login" name="Login">
|
|
<t t-call="web.login_layout">
|
|
<form class="oe_login_form" role="form" t-attf-action="/web/login" method="post" onsubmit="this.action = '/web/login' + location.hash">
|
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
|
|
|
<div class="mb-3" t-if="databases and len(databases) > 1">
|
|
<label for="db" class="col-form-label">Database</label>
|
|
<div t-attf-class="input-group {{'input-group-sm' if form_small else ''}}">
|
|
<input type="text" name="db" t-att-value="request.db" id="db" t-attf-class="form-control #{'form-control-sm' if form_small else ''}" required="required" readonly="readonly"/>
|
|
<a role="button" href="/web/database/selector" class="btn btn-secondary">Select <i class="fa fa-database" role="img" aria-label="Database" title="Database"></i></a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3 field-login">
|
|
<label for="login" class="form-label">Email</label>
|
|
<input type="text" placeholder="Email" name="login" t-att-value="login" id="login" t-attf-class="form-control #{'form-control-sm' if form_small else ''}" required="required" autofocus="autofocus" autocapitalize="off"/>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="password" class="form-label">Password</label>
|
|
<input type="password" placeholder="Password" name="password" id="password" t-attf-class="form-control #{'form-control-sm' if form_small else ''}" required="required" autocomplete="current-password" t-att-autofocus="'autofocus' if login else None" maxlength="4096"/>
|
|
</div>
|
|
|
|
<p class="alert alert-danger" t-if="error" role="alert">
|
|
<t t-esc="error"/>
|
|
</p>
|
|
<p class="alert alert-success" t-if="message" role="status">
|
|
<t t-esc="message"/>
|
|
</p>
|
|
|
|
<div t-attf-class="clearfix oe_login_buttons text-center gap-1 d-grid mb-1 {{'pt-2' if form_small else 'pt-3'}}">
|
|
<button type="submit" class="btn btn-primary">Log in</button>
|
|
<t t-if="debug">
|
|
<button type="submit" name="redirect" value="/web/become" class="btn btn-link btn-sm">Log in as superuser</button>
|
|
</t>
|
|
<div class="o_login_auth"/>
|
|
</div>
|
|
|
|
<input type="hidden" name="redirect" t-att-value="redirect"/>
|
|
</form>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="web.login_successful" name="Login successful">
|
|
<t t-call="web.login_layout">
|
|
<div class="oe_login_form">
|
|
<p>
|
|
You are logged in.
|
|
</p>
|
|
<div t-attf-class="clearfix oe_login_buttons text-center mb-1 pt-3">
|
|
<a class="btn btn-primary btn-block" href="/web/session/logout">Log out</a>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="web.test_helpers">
|
|
<t t-call-assets="web.tests_assets" t-js="False"/>
|
|
<style>
|
|
body {
|
|
position: relative; /* bootstrap-datepicker needs this */
|
|
}
|
|
body:not(.debug) .modal-backdrop, body:not(.debug) .modal, body:not(.debug) .ui-autocomplete {
|
|
opacity: 0 !important;
|
|
}
|
|
#qunit-testrunner-toolbar label {
|
|
font-weight: inherit;
|
|
margin-bottom: inherit;
|
|
}
|
|
#qunit-testrunner-toolbar input[type=text] {
|
|
width: inherit;
|
|
display: inherit;
|
|
}
|
|
</style>
|
|
<t t-call-assets="web.tests_assets" t-css="False"/>
|
|
</template>
|
|
|
|
<template id="web.qunit_suite">
|
|
<t t-call="web.layout">
|
|
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
|
|
<t t-set="title">Web Tests</t>
|
|
<t t-set="head">
|
|
<t t-call-assets="web.assets_common" t-js="false"/>
|
|
<t t-call-assets="web.assets_backend" t-js="false"/>
|
|
<t t-call-assets="web.tests_assets_common" t-css="false"/>
|
|
<t t-call-assets="web.assets_backend" t-css="false"/>
|
|
|
|
<t t-call="web.test_helpers"/>
|
|
|
|
<t t-call-assets="web.qunit_suite_tests" t-js="false"/>
|
|
<t t-call-assets="web.qunit_suite_tests" t-css="false"/>
|
|
</t>
|
|
<div id="qunit"/>
|
|
<div id="qunit-fixture"/>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="web.qunit_mobile_suite">
|
|
<t t-call="web.layout">
|
|
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
|
|
<t t-set="title">Web Mobile Tests</t>
|
|
<t t-set="head">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
|
|
|
|
<t t-call-assets="web.assets_common" t-js="false"/>
|
|
<t t-call-assets="web.assets_backend" t-js="false"/>
|
|
<t t-call-assets="web.tests_assets_common" t-css="false"/>
|
|
<t t-call-assets="web.assets_backend" t-css="false"/>
|
|
|
|
<t t-call="web.test_helpers"/>
|
|
|
|
<t t-call-assets="web.qunit_mobile_suite_tests" t-js="false"/>
|
|
<t t-call-assets="web.qunit_mobile_suite_tests" t-css="false"/>
|
|
</t>
|
|
<div id="qunit"/>
|
|
<div id="qunit-fixture"/>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="web.benchmark_suite">
|
|
<t t-call="web.layout">
|
|
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
|
|
<t t-set="title">Web Benchmarks</t>
|
|
<t t-set="head">
|
|
<script type="text/javascript" src="/web/static/lib/benchmarkjs/lodash.js"></script>
|
|
<script type="text/javascript" src="/web/static/lib/benchmarkjs/benchmark.js"></script>
|
|
|
|
<t t-call-assets="web.assets_common" t-js="false"/>
|
|
<t t-call-assets="web.assets_backend" t-js="false"/>
|
|
<t t-call-assets="web.assets_common" t-css="false"/>
|
|
<t t-call-assets="web.assets_backend" t-css="false"/>
|
|
|
|
<t t-call="web.test_helpers"/>
|
|
|
|
<script type="text/javascript">
|
|
QUnit.config.hidepassed = false;
|
|
</script>
|
|
|
|
<style>
|
|
body:not(.debug) .modal-backdrop, body:not(.debug) .modal, body:not(.debug) .ui-autocomplete {
|
|
opacity: 0 !important;
|
|
}
|
|
#qunit-testrunner-toolbar label {
|
|
font-weight: inherit;
|
|
margin-bottom: inherit;
|
|
}
|
|
#qunit-testrunner-toolbar input[type=text] {
|
|
width: inherit;
|
|
display: inherit;
|
|
}
|
|
</style>
|
|
|
|
<script type="text/javascript" src="/web/static/tests/views/list_benchmarks.js"></script>
|
|
<script type="text/javascript" src="/web/static/tests/views/kanban_benchmarks.js"></script>
|
|
<script type="text/javascript" src="/web/static/tests/views/form_benchmarks.js"></script>
|
|
|
|
</t>
|
|
|
|
<div id="qunit"/>
|
|
<div id="qunit-fixture"/>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="web.webclient_bootstrap">
|
|
<t t-call="web.layout">
|
|
<t t-set="head_web">
|
|
<script type="text/javascript">
|
|
odoo.__session_info__ = <t t-out="json.dumps(session_info)"/>;
|
|
odoo.reloadMenus = () => fetch(`/web/webclient/load_menus/${odoo.__session_info__.cache_hashes.load_menus}`).then(res => res.json());
|
|
odoo.loadMenusPromise = odoo.reloadMenus();
|
|
// Block to avoid leaking variables in the script scope
|
|
{
|
|
const { user_context, cache_hashes } = odoo.__session_info__;
|
|
// Prefetch translations to speedup webclient. This is done in JS because link rel="prefetch"
|
|
// is not yet supported on safari.
|
|
fetch(`/web/webclient/translations/${cache_hashes.translations}?lang=${user_context.lang}`);
|
|
}
|
|
</script>
|
|
<t t-call-assets="web.assets_common" t-js="false"/>
|
|
<t t-call-assets="web.assets_backend" t-js="false"/>
|
|
<t t-call-assets="web.assets_common" t-css="false"/>
|
|
<t t-call-assets="web.assets_backend" t-css="false"/>
|
|
<t t-call-assets="web.assets_backend_prod_only" t-css="false"/>
|
|
<t t-call="web.conditional_assets_tests"/>
|
|
</t>
|
|
<t t-set="head" t-value="head_web + (head or '')"/>
|
|
<t t-set="body_classname" t-value="'o_web_client'"/>
|
|
</t>
|
|
</template>
|
|
|
|
</odoo>
|