[FIX] website: make navbar content invisible when block invisible

Steps to reproduce:
 1. Go to the website
 2. Add website languages
 3. Drag Table Of Content
 4. Select snippet block
 5. Go to customize the block
 6. Select visibility conditionally - set visible/hide for languages.

Before the commit, selecting block visibility conditionally makes only
the block is invisible but not the navbar content is invisible due to the
absence of the `data-visibility-id` attribute.

In this commit, handling conditional visibility of the navbar when the
the snippet block is invisible.
Also, This commit adds a check for missing visibility IDs in anchor
links. The code checks if both the visibility ID values exist or if they
are both missing. If either condition is met, the function returns
without creating the `<a>` tag.

task-3373943

closes odoo/odoo#137081

X-original-commit: 182d3f20d8d3ae8149280ac3084423ba11e0975d
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
This commit is contained in:
utag-odoo
2023-09-29 11:59:06 +00:00
parent 9e2f0edba5
commit cdbd8d038d
@@ -19,6 +19,8 @@ options.registry.TableOfContent = options.Class.extend({
const config = {attributes: false, childList: true, subtree: true, characterData: true};
this.observer = new MutationObserver(() => this._generateNav());
this.observer.observe(targetNode, config);
// The mutation observer doesn't observe the attributes change, it would
// be too much. Adding content_changed "listener" instead.
this.$target.on('content_changed', () => this._generateNav());
return this._super(...arguments);
},
@@ -89,11 +91,20 @@ options.registry.TableOfContent = options.Class.extend({
return;
}
this.options.wysiwyg && this.options.wysiwyg.odooEditor.unbreakableStepUnactive();
const navEl = this.$target[0].querySelector('.s_table_of_content_navbar');
const headingsEls = this.$target.find(this.targetedElements).toArray()
.filter(el => !el.closest('.o_snippet_desktop_invisible'));
const areHeadingsEqual = this.oldHeadingsEls.length === headingsEls.length
&& this.oldHeadingsEls.every((el, i) => el.isEqualNode(headingsEls[i]));
if (areHeadingsEqual) {
const areVisibilityIdsEqual = headingsEls.every((headingEl) => {
const visibilityId = headingEl.closest('section').getAttribute('data-visibility-id');
const matchingLinkEl = navEl.querySelector(`a[href="#${headingEl.getAttribute('id')}"]`);
const matchingLinkVisibilityId = matchingLinkEl ? matchingLinkEl.getAttribute('data-visibility-id') : null;
// Check if visibilityId matches matchingLinkVisibilityId or both
// are null/undefined
return visibilityId === matchingLinkVisibilityId;
});
if (areHeadingsEqual && areVisibilityIdsEqual) {
// If the content of the navbar before the change of the DOM is
// equal to the content of the navbar after the change of the DOM,
// then there is no need to regenerate the navbar.
@@ -106,15 +117,15 @@ options.registry.TableOfContent = options.Class.extend({
}
// We dispose the scrollSpy because the navbar will be updated.
this._disposeScrollSpy();
const $nav = this.$target.find('.s_table_of_content_navbar');
$nav.empty();
navEl.innerHTML = '';
headingsEls.forEach((el) => {
const $el = $(el);
const id = uniqueId("table_of_content_heading_" + new Date().getTime() + "_");
$('<a>').attr('href', "#" + id)
const visibilityId = $el.closest('section').attr('data-visibility-id');
$('<a>').attr({ 'href': "#" + id, 'data-visibility-id': visibilityId })
.addClass('table_of_content_link list-group-item list-group-item-action py-2 border-0 rounded-0')
.text($el.text())
.appendTo($nav);
.appendTo(navEl);
$el.attr('id', id);
$el[0].dataset.anchor = 'true';
});