From 88c9fbd153a440b2f770cab32cc29c45baf9e0f3 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Sun, 18 Feb 2024 15:33:07 +0200 Subject: [PATCH] ref --- client/src/helpers/record/misc/sticky-bar.js | 149 +++++++++++++++++++ client/src/views/record/detail.js | 103 ++----------- 2 files changed, 158 insertions(+), 94 deletions(-) create mode 100644 client/src/helpers/record/misc/sticky-bar.js diff --git a/client/src/helpers/record/misc/sticky-bar.js b/client/src/helpers/record/misc/sticky-bar.js new file mode 100644 index 0000000000..fab6320b1e --- /dev/null +++ b/client/src/helpers/record/misc/sticky-bar.js @@ -0,0 +1,149 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM – Open Source CRM application. + * Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko + * Website: https://www.espocrm.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +import $ from 'jquery'; + +/** + * @internal + */ +class StickyBarHelper { + + + /** + * @param {import('views/record/detail').default} view + * @param {boolean} stickButtonsFormBottomSelector + * @param {boolean} stickButtonsContainerAllTheWay + * @param {number} numId + */ + constructor(view, stickButtonsFormBottomSelector, stickButtonsContainerAllTheWay, numId) { + this.view = view; + this.stickButtonsFormBottomSelector = stickButtonsFormBottomSelector; + this.stickButtonsContainerAllTheWay = stickButtonsContainerAllTheWay; + this.numId = numId; + + this.themeManager = view.getThemeManager(); + this.$el = view.$el; + } + + init() { + const $containers = this.$el.find('.detail-button-container'); + const $container = this.$el.find('.detail-button-container.record-buttons'); + + if (!$container.length) { + return; + } + + const navbarHeight = this.themeManager.getParam('navbarHeight'); + const screenWidthXs = this.themeManager.getParam('screenWidthXs'); + + const isSmallScreen = $(window.document).width() < screenWidthXs; + + const getOffsetTop = (/** JQuery */$element) => { + let element = /** @type {HTMLElement} */$element.get(0); + + let value = 0; + + while (element) { + value += !isNaN(element.offsetTop) ? element.offsetTop : 0; + + element = element.offsetParent; + } + + if (isSmallScreen) { + return value; + } + + return value - navbarHeight; + }; + + let stickTop = getOffsetTop($container); + const blockHeight = $container.outerHeight(); + + stickTop -= 5; // padding; + + const $block = $('
') + .css('height', blockHeight + 'px') + .html(' ') + .hide() + .insertAfter($container); + + let $middle = this.view.getMiddleView().$el; + const $window = $(window); + const $navbarRight = $('#navbar .navbar-right'); + + if (this.stickButtonsFormBottomSelector) { + const $bottom = this.$el.find(this.stickButtonsFormBottomSelector); + + if ($bottom.length) { + $middle = $bottom; + } + } + + $window.off('scroll.detail-' + this.numId); + + $window.on('scroll.detail-' + this.numId, () => { + const edge = $middle.position().top + $middle.outerHeight(false) - blockHeight; + const scrollTop = $window.scrollTop(); + + if (scrollTop >= edge && !this.stickButtonsContainerAllTheWay) { + $containers.hide(); + $navbarRight.removeClass('has-sticked-bar'); + $block.show(); + + return; + } + + if (isSmallScreen && $('#navbar .navbar-body').hasClass('in')) { + return; + } + + if (scrollTop > stickTop) { + if (!$containers.hasClass('stick-sub')) { + $containers.addClass('stick-sub'); + $block.show(); + } + + $navbarRight.addClass('has-sticked-bar'); + + $containers.show(); + + return; + } + + if ($containers.hasClass('stick-sub')) { + $containers.removeClass('stick-sub'); + $navbarRight.removeClass('has-sticked-bar'); + $block.hide(); + } + + $containers.show(); + }); + } +} + +export default StickyBarHelper; diff --git a/client/src/views/record/detail.js b/client/src/views/record/detail.js index d124b63f52..58119a81c6 100644 --- a/client/src/views/record/detail.js +++ b/client/src/views/record/detail.js @@ -31,6 +31,7 @@ import BaseRecordView from 'views/record/base'; import ViewRecordHelper from 'view-record-helper'; import ActionItemSetup from 'helpers/action-item-setup'; +import StickyBarHelper from 'helpers/record/misc/sticky-bar'; /** * A detail record view. @@ -1419,102 +1420,16 @@ class DetailRecordView extends BaseRecordView { } } - /** - * @private - */ + /** @private */ initStickableButtonsContainer() { - const $containers = this.$el.find('.detail-button-container'); - const $container = this.$el.find('.detail-button-container.record-buttons'); + const helper = new StickyBarHelper( + this, + this.stickButtonsFormBottomSelector, + this.stickButtonsContainerAllTheWay, + this.numId + ); - if (!$container.length) { - return; - } - - const navbarHeight = this.getThemeManager().getParam('navbarHeight'); - const screenWidthXs = this.getThemeManager().getParam('screenWidthXs'); - - const isSmallScreen = $(window.document).width() < screenWidthXs; - - const getOffsetTop = (/** JQuery */$element) => { - let element = /** @type {HTMLElement} */$element.get(0); - - let value = 0; - - while (element) { - value += !isNaN(element.offsetTop) ? element.offsetTop : 0; - - element = element.offsetParent; - } - - if (isSmallScreen) { - return value; - } - - return value - navbarHeight; - }; - - let stickTop = getOffsetTop($container); - const blockHeight = $container.outerHeight(); - - stickTop -= 5; // padding; - - const $block = $('
') - .css('height', blockHeight + 'px') - .html(' ') - .hide() - .insertAfter($container); - - let $middle = this.getMiddleView().$el; - const $window = $(window); - const $navbarRight = $('#navbar .navbar-right'); - - if (this.stickButtonsFormBottomSelector) { - const $bottom = this.$el.find(this.stickButtonsFormBottomSelector); - - if ($bottom.length) { - $middle = $bottom; - } - } - - $window.off('scroll.detail-' + this.numId); - - $window.on('scroll.detail-' + this.numId, () => { - const edge = $middle.position().top + $middle.outerHeight(false) - blockHeight; - const scrollTop = $window.scrollTop(); - - if (scrollTop >= edge && !this.stickButtonsContainerAllTheWay) { - $containers.hide(); - $navbarRight.removeClass('has-sticked-bar'); - $block.show(); - - return; - } - - if (isSmallScreen && $('#navbar .navbar-body').hasClass('in')) { - return; - } - - if (scrollTop > stickTop) { - if (!$containers.hasClass('stick-sub')) { - $containers.addClass('stick-sub'); - $block.show(); - } - - $navbarRight.addClass('has-sticked-bar'); - - $containers.show(); - - return; - } - - if ($containers.hasClass('stick-sub')) { - $containers.removeClass('stick-sub'); - $navbarRight.removeClass('has-sticked-bar'); - $block.hide(); - } - - $containers.show(); - }); + helper.init(); } fetch() {