[IMP] odoo_theme: show the "On this page" section in mobile
When the page gets too small for the "On this page" section (local tree
of content) to fit on the page, the section is now moved above the menu
(global tree of content) rather than being hidden.
task-2800970
closes odoo/documentation#2200
X-original-commit: c0040fa532
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
Co-authored-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
parent
1d01977ba5
commit
33c2ee98c8
@ -62,12 +62,20 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</noscript>
|
</noscript>
|
||||||
{# Shown when the JS has properly set all the classes on the TOC elements #}
|
{# Shown when the JS has properly set all the classes on the TOC elements #}
|
||||||
<nav id="o_main_toctree" class="o_side_nav border-end" hidden>
|
<nav id="o_menu" class="o_side_nav border-end">
|
||||||
{%- include "layout_templates/menu.html" %}
|
{%- if 'hide-page-toc' not in meta %}
|
||||||
|
{# Shown when the JS has properly set all the classes on the TOC elements #}
|
||||||
|
<aside id="o_page_toc_in_nav" class="o_page_toc o_in_nav_toc border-bottom pb-3 mb-4" hidden>
|
||||||
|
{%- include "layout_templates/page_toc.html" %}
|
||||||
|
</aside>
|
||||||
|
{%- endif %}
|
||||||
|
<div id="o_main_toctree" class="o_main_toc" hidden>
|
||||||
|
{%- include "layout_templates/menu.html" %}
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<header class="o_main_header border-bottom navbar navbar-light navbar-expand-lg">
|
<header class="o_main_header border-bottom navbar navbar-light navbar-expand-lg">
|
||||||
{%- include "layout_templates/header.html" %}
|
{%- include "layout_templates/header.html" %}
|
||||||
<button class="navbar-toggler p-0 border-0" type="button" data-bs-toggle="collapse" data-bs-target="#o_main_toctree" aria-label="Toggle navigation">
|
<button class="navbar-toggler p-0 border-0" type="button" data-bs-toggle="collapse" data-bs-target="#o_menu" aria-label="Toggle navigation">
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
(function ($) {
|
(function ($) {
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
this.navigationMenu = document.getElementById('o_main_toctree');
|
const navigationMenu = document.getElementById('o_main_toctree');
|
||||||
|
|
||||||
// Allow to automatically collapse and expand TOC entries
|
// Allow to automatically collapse and expand TOC entries
|
||||||
_prepareAccordion(this.navigationMenu);
|
_prepareAccordion(navigationMenu);
|
||||||
|
|
||||||
// Allow to respectively highlight and expand the TOC entries and their related TOC
|
// Allow to respectively highlight and expand the TOC entries and their related TOC
|
||||||
// entry list whose page is displayed.
|
// entry list whose page is displayed.
|
||||||
_flagActiveTocEntriesAndLists();
|
_flagActiveTocEntriesAndLists(navigationMenu);
|
||||||
|
|
||||||
// Show hidden menu when the css classes have been properly specified
|
// Show hidden menu when the css classes have been properly specified
|
||||||
this.navigationMenu.removeAttribute('hidden');
|
navigationMenu.removeAttribute('hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,13 +23,15 @@
|
|||||||
* the `show` (Bootstrap) class.
|
* the `show` (Bootstrap) class.
|
||||||
* Also, the deepest TOC entries of their respective branch receive the
|
* Also, the deepest TOC entries of their respective branch receive the
|
||||||
* `o_deepest_active_toc_entry` class, and their child TOC entry lists receive the `show` class.
|
* `o_deepest_active_toc_entry` class, and their child TOC entry lists receive the `show` class.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} navigationMenu - The navigation menu.
|
||||||
*/
|
*/
|
||||||
const _flagActiveTocEntriesAndLists = () => {
|
const _flagActiveTocEntriesAndLists = navigationMenu => {
|
||||||
const regexLayer = /\btoctree-l(?<layer>\d+)\b/;
|
const regexLayer = /\btoctree-l(?<layer>\d+)\b/;
|
||||||
let lastLayer = undefined;
|
let lastLayer = undefined;
|
||||||
let lastTocEntry = undefined;
|
let lastTocEntry = undefined;
|
||||||
const deepestTocEntries = [];
|
const deepestTocEntries = [];
|
||||||
this.navigationMenu.querySelectorAll('.current').forEach(element => {
|
navigationMenu.querySelectorAll('.current').forEach(element => {
|
||||||
if (element.tagName === 'UL') {
|
if (element.tagName === 'UL') {
|
||||||
element.classList.add('show'); // Expand all related <ul>
|
element.classList.add('show'); // Expand all related <ul>
|
||||||
} else if (element.tagName === 'LI') {
|
} else if (element.tagName === 'LI') {
|
||||||
|
@ -3,43 +3,48 @@
|
|||||||
|
|
||||||
// Customize the page TOC
|
// Customize the page TOC
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
this.pageToc = document.getElementById('o_page_toc'); // The tree of content of the page
|
// Loop on all tree of content of the page. There may be from 0 to 2 depending on the page.
|
||||||
if (this.pageToc) { // The local toctree is not included for toctree pages (see layout.html)
|
document.querySelectorAll('.o_page_toc').forEach(pageToc => {
|
||||||
this.headingRefs = this.pageToc.querySelectorAll('a'); // The references to all headings
|
const headingRefs = pageToc.querySelectorAll('a'); // The references to all headings.
|
||||||
|
|
||||||
// If the page TOC has less than 2 headings, in addition to the title, hide it entirely
|
// If the page TOC has less than 2 headings, in addition to the title, hide it entirely.
|
||||||
if (this.headingRefs.length <= 2) {
|
if (headingRefs.length <= 2) {
|
||||||
_hidePageToc();
|
_hidePageToc(pageToc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow to automatically collapse and expand TOC entries
|
// Allow to automatically collapse and expand TOC entries
|
||||||
_prepareAccordion(this.pageToc);
|
_prepareAccordion(pageToc);
|
||||||
|
|
||||||
// Allow to respectively highlight and expand the TOC entries and their related TOC
|
// Allow to respectively highlight and expand the TOC entries and their related TOC
|
||||||
// entry list whose section is focused.
|
// entry list whose section is focused.
|
||||||
_flagActiveTocEntriesAndLists();
|
_flagActiveTocEntriesAndLists(pageToc, headingRefs);
|
||||||
|
|
||||||
// Allow to hide the TOC entry referring the title (<h1> heading)
|
// Allow to hide the TOC entry referring the title (<h1> heading)
|
||||||
_flagFirstHeadingRef();
|
_flagFirstHeadingRef(headingRefs);
|
||||||
|
|
||||||
// Show hidden menu when the css classes have been properly specified
|
// Show hidden menu when the css classes have been properly specified
|
||||||
this.pageToc.removeAttribute('hidden');
|
pageToc.removeAttribute('hidden');
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entirely hide the local tree of contents.
|
* Entirely hide the local tree of contents.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} pageToc - The tree of content of the page.
|
||||||
*/
|
*/
|
||||||
const _hidePageToc = () => this.pageToc.style.display = 'none';
|
const _hidePageToc = pageToc => pageToc.style.display = 'none';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the relevant classes on the TOC entries (and lists) whose section is focused.
|
* Add the relevant classes on the TOC entries (and lists) whose section is focused.
|
||||||
*
|
*
|
||||||
* TOC entries whose section is focused (<li> elements) receive the `o_active_toc_entry` class
|
* TOC entries whose section is focused (<li> elements) receive the `o_active_toc_entry` class
|
||||||
* and their related TOC entry list (<ul> elements) receive the `show` (Bootstrap) class.
|
* and their related TOC entry list (<ul> elements) receive the `show` (Bootstrap) class.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} pageToc - The tree of content of the page.
|
||||||
|
* @param {NodeList} headingRefs - The references to all headings.
|
||||||
*/
|
*/
|
||||||
const _flagActiveTocEntriesAndLists = () => {
|
const _flagActiveTocEntriesAndLists = (pageToc, headingRefs) => {
|
||||||
|
|
||||||
const _updateFlags = () => {
|
const _updateFlags = () => {
|
||||||
const activeHeadingRef = clickedHeadingRef || _findActiveHeadingRef();
|
const activeHeadingRef = clickedHeadingRef || _findActiveHeadingRef();
|
||||||
@ -56,8 +61,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const _findActiveHeadingRef = () => {
|
const _findActiveHeadingRef = () => {
|
||||||
let activeHeadingRef = this.headingRefs[0];
|
let activeHeadingRef = headingRefs[0];
|
||||||
this.headingRefs.forEach(headingRef => {
|
headingRefs.forEach(headingRef => {
|
||||||
const href = headingRef.getAttribute('href');
|
const href = headingRef.getAttribute('href');
|
||||||
if (href !== '#') {
|
if (href !== '#') {
|
||||||
const sectionId = href.replace('#', '');
|
const sectionId = href.replace('#', '');
|
||||||
@ -78,17 +83,17 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const _unflagAll = () => {
|
const _unflagAll = () => {
|
||||||
this.pageToc.querySelectorAll('li,ul').forEach(element => {
|
pageToc.querySelectorAll('li,ul').forEach(element => {
|
||||||
element.classList.remove('o_active_toc_entry', 'show');
|
element.classList.remove('o_active_toc_entry', 'show');
|
||||||
});
|
});
|
||||||
this.pageToc.querySelectorAll('i').forEach(element => {
|
pageToc.querySelectorAll('i').forEach(element => {
|
||||||
element.setAttribute('aria-expanded', false);
|
element.setAttribute('aria-expanded', false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const _flagActiveHierarchy = (headingRef) => {
|
const _flagActiveHierarchy = (headingRef) => {
|
||||||
let tocEntry = headingRef.parentElement;
|
let tocEntry = headingRef.parentElement;
|
||||||
while (tocEntry !== this.pageToc) {
|
while (tocEntry !== pageToc) {
|
||||||
if (tocEntry.tagName === 'LI') {
|
if (tocEntry.tagName === 'LI') {
|
||||||
// Highlight all <li> in the active hierarchy
|
// Highlight all <li> in the active hierarchy
|
||||||
tocEntry.classList.add('o_active_toc_entry');
|
tocEntry.classList.add('o_active_toc_entry');
|
||||||
@ -104,7 +109,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
let clickedHeadingRef = undefined;
|
let clickedHeadingRef = undefined;
|
||||||
this.pageToc.addEventListener('click', ev => {
|
pageToc.addEventListener('click', ev => {
|
||||||
clickedHeadingRef = ev.target.closest('a[href^="#"]'); // Highlight the clicked ref
|
clickedHeadingRef = ev.target.closest('a[href^="#"]'); // Highlight the clicked ref
|
||||||
});
|
});
|
||||||
let timeoutId = undefined;
|
let timeoutId = undefined;
|
||||||
@ -122,9 +127,11 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the class `o_page_toc_title` on the first heading reference.
|
* Add the class `o_page_toc_title` on the first heading reference.
|
||||||
|
*
|
||||||
|
* @param {NodeList} headingRefs - The references to all headings.
|
||||||
*/
|
*/
|
||||||
const _flagFirstHeadingRef = () => {
|
const _flagFirstHeadingRef = headingRefs => {
|
||||||
this.headingRefs[0].parentNode.classList.add('o_page_toc_title');
|
headingRefs[0].parentNode.classList.add('o_page_toc_title');
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -227,6 +227,23 @@ header.o_main_header {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.o_main_toc {
|
||||||
|
> ul {
|
||||||
|
li {
|
||||||
|
&.o_active_toc_entry {
|
||||||
|
&:not(.toctree-l1) > .o_toc_entry_wrapper i[class^="i-"]:not(.collapsed), > a , > .o_toc_entry_wrapper a, > .o_toc_entry_wrapper i {
|
||||||
|
color: $o-violet-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
&.current {
|
||||||
|
color: $o-violet-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
.o_deepest_active_toc_entry {
|
.o_deepest_active_toc_entry {
|
||||||
@ -235,20 +252,6 @@ header.o_main_header {
|
|||||||
margin-left: -3px;
|
margin-left: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
|
||||||
&.o_active_toc_entry {
|
|
||||||
&:not(.toctree-l1) > .o_toc_entry_wrapper i[class^="i-"]:not(.collapsed), > a , > .o_toc_entry_wrapper a, > .o_toc_entry_wrapper i {
|
|
||||||
color: $o-violet-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
&.current {
|
|
||||||
color: $o-violet-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .toctree-l1 {
|
> .toctree-l1 {
|
||||||
&[class*="o_menu_"] > .o_toc_entry_wrapper > i:before {
|
&[class*="o_menu_"] > .o_toc_entry_wrapper > i:before {
|
||||||
@include o-inline-icon($i-doc-apps, 0 5px 0 0);
|
@include o-inline-icon($i-doc-apps, 0 5px 0 0);
|
||||||
@ -292,7 +295,7 @@ header.o_main_header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_side_nav, .o_page_toc_nav {
|
.o_main_toc, .o_page_toc_nav {
|
||||||
ul { // all uls in toc
|
ul { // all uls in toc
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding-left: $padding-s;
|
padding-left: $padding-s;
|
||||||
@ -350,19 +353,28 @@ header.o_main_header {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
aside.o_page_toc {
|
aside.o_page_toc {
|
||||||
display: none;
|
color: $body-color;
|
||||||
@include font-size($font-size-secondary);
|
@include font-size($font-size-secondary);
|
||||||
@include media-breakpoint-up(xl) {
|
&:not(.o_in_nav_toc) {
|
||||||
display: block;
|
display: none;
|
||||||
|
@include media-breakpoint-up(xl) {
|
||||||
|
display: block;
|
||||||
|
top: $o-header-height;
|
||||||
|
right: 0;
|
||||||
|
padding: $padding-l $padding-s $padding-l 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
position: -webkit-sticky;
|
position: -webkit-sticky;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: $o-header-height;
|
|
||||||
right: 0;
|
|
||||||
width: $o-on-page-width;
|
width: $o-on-page-width;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
max-height: calc(100vh - #{$o-header-height});
|
max-height: calc(100vh - #{$o-header-height});
|
||||||
padding: $padding-l $padding-s $padding-l 0;
|
}
|
||||||
overflow-y: auto;
|
&.o_in_nav_toc {
|
||||||
|
display: block;
|
||||||
|
@include media-breakpoint-up(xl) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
|
Loading…
Reference in New Issue
Block a user