Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions extensions/odoo_theme/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,20 @@
</nav>
</noscript>
{# 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>
{%- include "layout_templates/menu.html" %}
<nav id="o_menu" class="o_side_nav border-end">
{%- 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>
<header class="o_main_header border-bottom navbar navbar-light navbar-expand-lg">
{%- 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>
Expand Down
14 changes: 8 additions & 6 deletions extensions/odoo_theme/static/js/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
(function ($) {

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
_prepareAccordion(this.navigationMenu);
_prepareAccordion(navigationMenu);

// Allow to respectively highlight and expand the TOC entries and their related TOC
// entry list whose page is displayed.
_flagActiveTocEntriesAndLists();
_flagActiveTocEntriesAndLists(navigationMenu);

// Show hidden menu when the css classes have been properly specified
this.navigationMenu.removeAttribute('hidden');
navigationMenu.removeAttribute('hidden');
});

/**
Expand All @@ -23,13 +23,15 @@
* the `show` (Bootstrap) class.
* 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.
*
* @param {HTMLElement} navigationMenu - The navigation menu.
*/
const _flagActiveTocEntriesAndLists = () => {
const _flagActiveTocEntriesAndLists = navigationMenu => {
const regexLayer = /\btoctree-l(?<layer>\d+)\b/;
let lastLayer = undefined;
let lastTocEntry = undefined;
const deepestTocEntries = [];
this.navigationMenu.querySelectorAll('.current').forEach(element => {
navigationMenu.querySelectorAll('.current').forEach(element => {
if (element.tagName === 'UL') {
element.classList.add('show'); // Expand all related <ul>
} else if (element.tagName === 'LI') {
Expand Down
49 changes: 28 additions & 21 deletions extensions/odoo_theme/static/js/page_toc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,48 @@

// Customize the page TOC
document.addEventListener('DOMContentLoaded', () => {
this.pageToc = document.getElementById('o_page_toc'); // The tree of content of the page
if (this.pageToc) { // The local toctree is not included for toctree pages (see layout.html)
this.headingRefs = this.pageToc.querySelectorAll('a'); // The references to all headings
// Loop on all tree of content of the page. There may be from 0 to 2 depending on the page.
document.querySelectorAll('.o_page_toc').forEach(pageToc => {
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 (this.headingRefs.length <= 2) {
_hidePageToc();
// If the page TOC has less than 2 headings, in addition to the title, hide it entirely.
if (headingRefs.length <= 2) {
_hidePageToc(pageToc);
return;
}

// 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
// entry list whose section is focused.
_flagActiveTocEntriesAndLists();
_flagActiveTocEntriesAndLists(pageToc, headingRefs);

// 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
this.pageToc.removeAttribute('hidden');
}
pageToc.removeAttribute('hidden');
});
});

/**
* 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.
*
* 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.
*
* @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 activeHeadingRef = clickedHeadingRef || _findActiveHeadingRef();
Expand All @@ -56,8 +61,8 @@
};

const _findActiveHeadingRef = () => {
let activeHeadingRef = this.headingRefs[0];
this.headingRefs.forEach(headingRef => {
let activeHeadingRef = headingRefs[0];
headingRefs.forEach(headingRef => {
const href = headingRef.getAttribute('href');
if (href !== '#') {
const sectionId = href.replace('#', '');
Expand All @@ -78,17 +83,17 @@
};

const _unflagAll = () => {
this.pageToc.querySelectorAll('li,ul').forEach(element => {
pageToc.querySelectorAll('li,ul').forEach(element => {
element.classList.remove('o_active_toc_entry', 'show');
});
this.pageToc.querySelectorAll('i').forEach(element => {
pageToc.querySelectorAll('i').forEach(element => {
element.setAttribute('aria-expanded', false);
});
};

const _flagActiveHierarchy = (headingRef) => {
let tocEntry = headingRef.parentElement;
while (tocEntry !== this.pageToc) {
while (tocEntry !== pageToc) {
if (tocEntry.tagName === 'LI') {
// Highlight all <li> in the active hierarchy
tocEntry.classList.add('o_active_toc_entry');
Expand All @@ -104,7 +109,7 @@
};

let clickedHeadingRef = undefined;
this.pageToc.addEventListener('click', ev => {
pageToc.addEventListener('click', ev => {
clickedHeadingRef = ev.target.closest('a[href^="#"]'); // Highlight the clicked ref
});
let timeoutId = undefined;
Expand All @@ -122,9 +127,11 @@

/**
* Add the class `o_page_toc_title` on the first heading reference.
*
* @param {NodeList} headingRefs - The references to all headings.
*/
const _flagFirstHeadingRef = () => {
this.headingRefs[0].parentNode.classList.add('o_page_toc_title');
const _flagFirstHeadingRef = headingRefs => {
headingRefs[0].parentNode.classList.add('o_page_toc_title');
}

})();
58 changes: 35 additions & 23 deletions extensions/odoo_theme/static/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,23 @@ header.o_main_header {
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 {
.o_deepest_active_toc_entry {
Expand All @@ -235,20 +252,6 @@ header.o_main_header {
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 {
&[class*="o_menu_"] > .o_toc_entry_wrapper > i:before {
@include o-inline-icon($i-doc-apps, 0 5px 0 0);
Expand Down Expand Up @@ -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
list-style: none;
padding-left: $padding-s;
Expand Down Expand Up @@ -350,19 +353,28 @@ header.o_main_header {
//------------------------------------------------------------------------------

aside.o_page_toc {
display: none;
color: $body-color;
@include font-size($font-size-secondary);
@include media-breakpoint-up(xl) {
display: block;
&:not(.o_in_nav_toc) {
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: sticky;
top: $o-header-height;
right: 0;
width: $o-on-page-width;
height: 100%;
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 {
Expand Down Expand Up @@ -1064,7 +1076,7 @@ header.o_main_header {
> div[class^="highlight-"]{
border: 0 !important;
}

> *:last-child {
margin-bottom: 0 !important;
}
Expand Down