diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/website/static/src/snippets/s_table_of_content | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/website/static/src/snippets/s_table_of_content')
3 files changed, 264 insertions, 0 deletions
diff --git a/addons/website/static/src/snippets/s_table_of_content/000.js b/addons/website/static/src/snippets/s_table_of_content/000.js new file mode 100644 index 00000000..fcae4ed7 --- /dev/null +++ b/addons/website/static/src/snippets/s_table_of_content/000.js @@ -0,0 +1,77 @@ +odoo.define('website.s_table_of_content', function (require) { +'use strict'; + +const publicWidget = require('web.public.widget'); +const {extraMenuUpdateCallbacks} = require('website.content.menu'); + +const TableOfContent = publicWidget.Widget.extend({ + selector: 'section .s_table_of_content_navbar_sticky', + disabledInEditableMode: false, + + /** + * @override + */ + async start() { + await this._super(...arguments); + this._updateTableOfContentNavbarPosition(); + extraMenuUpdateCallbacks.push(this._updateTableOfContentNavbarPosition.bind(this)); + }, + /** + * @override + */ + destroy() { + this.$target.css('top', ''); + this.$target.find('.s_table_of_content_navbar').css('top', ''); + this._super(...arguments); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + */ + _updateTableOfContentNavbarPosition() { + let position = 0; + const $fixedElements = $('.o_top_fixed_element'); + _.each($fixedElements, el => position += $(el).outerHeight()); + const isHorizontalNavbar = this.$target.hasClass('s_table_of_content_horizontal_navbar'); + this.$target.css('top', isHorizontalNavbar ? position : ''); + this.$target.find('.s_table_of_content_navbar').css('top', isHorizontalNavbar ? '' : position + 20); + const $mainNavBar = $('#oe_main_menu_navbar'); + position += $mainNavBar.length ? $mainNavBar.outerHeight() : 0; + position += isHorizontalNavbar ? this.$target.outerHeight() : 0; + $().getScrollingElement().scrollspy({target: '.s_table_of_content_navbar', method: 'offset', offset: position + 100, alwaysKeepFirstActive: true}); + }, +}); + +publicWidget.registry.anchorSlide.include({ + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Overridden to add the height of the horizontal sticky navbar at the scroll value + * when the link is from the table of content navbar + * + * @override + * @private + */ + _computeExtraOffset() { + let extraOffset = this._super(...arguments); + if (this.$el.hasClass('table_of_content_link')) { + const tableOfContentNavbarEl = this.$el.closest('.s_table_of_content_navbar_sticky.s_table_of_content_horizontal_navbar'); + if (tableOfContentNavbarEl.length > 0) { + extraOffset += $(tableOfContentNavbarEl).outerHeight(); + } + } + return extraOffset; + }, +}); + +publicWidget.registry.snippetTableOfContent = TableOfContent; + +return TableOfContent; +}); diff --git a/addons/website/static/src/snippets/s_table_of_content/000.scss b/addons/website/static/src/snippets/s_table_of_content/000.scss new file mode 100644 index 00000000..670e1365 --- /dev/null +++ b/addons/website/static/src/snippets/s_table_of_content/000.scss @@ -0,0 +1,65 @@ +.s_table_of_content:not([data-vcss]) { + .s_table_of_content_navbar_wrap { + &.s_table_of_content_navbar_sticky { + &.s_table_of_content_horizontal_navbar, &.s_table_of_content_vertical_navbar .s_table_of_content_navbar { + @include o-position-sticky($top: 0px); + } + } + &:not(.s_table_of_content_navbar_sticky) { + &, .s_table_of_content_navbar { + top: 0px !important; + } + } + &.s_table_of_content_vertical_navbar .s_table_of_content_navbar { + > a.list-group-item-action { + background: none; + color: inherit; + opacity: 0.7; + font-weight: $font-weight-normal + 100; + padding-left: 3px; + transition: padding 0.1s; + + &:before { + @include o-position-absolute(10px, auto, 10px, 0); + width: 2px; + content: ""; + } + &:hover { + opacity: 1; + } + &:focus { + background: none; + } + &.active { + background: none; + padding-left: 8px; + opacity: 1; + + &:before { + background-color: theme-color('primary'); + } + } + } + } + &.s_table_of_content_horizontal_navbar { + z-index: 1; + padding-top: $navbar-padding-y; + padding-bottom: $navbar-padding-y; + margin-bottom: $spacer * 2; + + .s_table_of_content_navbar { + display: inline; + + > a { + &.list-group-item-action { + width: auto; + } + &.list-group-item { + display: inline-block; + margin-bottom: 2px; + } + } + } + } + } +} diff --git a/addons/website/static/src/snippets/s_table_of_content/options.js b/addons/website/static/src/snippets/s_table_of_content/options.js new file mode 100644 index 00000000..3feb0c74 --- /dev/null +++ b/addons/website/static/src/snippets/s_table_of_content/options.js @@ -0,0 +1,122 @@ +odoo.define('website.s_table_of_content_options', function (require) { +'use strict'; + +const options = require('web_editor.snippets.options'); + +options.registry.TableOfContent = options.Class.extend({ + /** + * @override + */ + start: function () { + this.targetedElements = 'h1, h2'; + const $headings = this.$target.find(this.targetedElements); + if ($headings.length > 0) { + this._generateNav(); + } + // Generate the navbar if the content changes + const targetNode = this.$target.find('.s_table_of_content_main')[0]; + const config = {attributes: false, childList: true, subtree: true, characterData: true}; + this.observer = new MutationObserver(() => this._generateNav()); + this.observer.observe(targetNode, config); + return this._super(...arguments); + }, + /** + * @override + */ + onClone: function () { + this._generateNav(); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + */ + _generateNav: function (ev) { + const $nav = this.$target.find('.s_table_of_content_navbar'); + const $headings = this.$target.find(this.targetedElements); + $nav.empty(); + _.each($headings, el => { + const $el = $(el); + const id = 'table_of_content_heading_' + _.now() + '_' + _.uniqueId(); + $('<a>').attr('href', "#" + id) + .addClass('table_of_content_link list-group-item list-group-item-action py-2 border-0 rounded-0') + .text($el.text()) + .appendTo($nav); + $el.attr('id', id); + $el[0].dataset.anchor = 'true'; + }); + $nav.find('a:first').addClass('active'); + }, +}); + +options.registry.TableOfContentNavbar = options.Class.extend({ + + //-------------------------------------------------------------------------- + // Options + //-------------------------------------------------------------------------- + + /** + * Change the navbar position. + * + * @see this.selectClass for parameters + */ + navbarPosition: function (previewMode, widgetValue, params) { + const $navbar = this.$target; + const $mainContent = this.$target.parent().find('.s_table_of_content_main'); + if (widgetValue === 'top' || widgetValue === 'left') { + $navbar.prev().before($navbar); + } + if (widgetValue === 'left' || widgetValue === 'right') { + $navbar.removeClass('s_table_of_content_horizontal_navbar col-lg-12').addClass('s_table_of_content_vertical_navbar col-lg-3'); + $mainContent.removeClass('col-lg-12').addClass('col-lg-9'); + $navbar.find('.s_table_of_content_navbar').removeClass('list-group-horizontal-md'); + } + if (widgetValue === 'right') { + $navbar.next().after($navbar); + } + if (widgetValue === 'top') { + $navbar.removeClass('s_table_of_content_vertical_navbar col-lg-3').addClass('s_table_of_content_horizontal_navbar col-lg-12'); + $navbar.find('.s_table_of_content_navbar').addClass('list-group-horizontal-md'); + $mainContent.removeClass('col-lg-9').addClass('col-lg-12'); + } + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _computeWidgetState: function (methodName, params) { + switch (methodName) { + case 'navbarPosition': { + const $navbar = this.$target; + if ($navbar.hasClass('s_table_of_content_horizontal_navbar')) { + return 'top'; + } else { + const $mainContent = $navbar.parent().find('.s_table_of_content_main'); + return $navbar.prev().is($mainContent) === true ? 'right' : 'left'; + } + } + } + return this._super(...arguments); + }, +}); + +options.registry.TableOfContentMainColumns = options.Class.extend({ + forceNoDeleteButton: true, + + /** + * @override + */ + start: function () { + const leftPanelEl = this.$overlay.data('$optionsSection')[0]; + leftPanelEl.querySelector('.oe_snippet_clone').classList.add('d-none'); // TODO improve the way to do that + return this._super.apply(this, arguments); + }, +}); +}); |
