/** * -------------------------------------------- * AdminLTE ControlSidebar.js * License MIT * -------------------------------------------- */ import $ from 'jquery' /** * Constants * ==================================================== */ const NAME = 'ControlSidebar' const DATA_KEY = 'lte.controlsidebar' const EVENT_KEY = `.${DATA_KEY}` const JQUERY_NO_CONFLICT = $.fn[NAME] const EVENT_COLLAPSED = `collapsed${EVENT_KEY}` const EVENT_COLLAPSED_DONE = `collapsed-done${EVENT_KEY}` const EVENT_EXPANDED = `expanded${EVENT_KEY}` const SELECTOR_CONTROL_SIDEBAR = '.control-sidebar' const SELECTOR_CONTROL_SIDEBAR_CONTENT = '.control-sidebar-content' const SELECTOR_DATA_TOGGLE = '[data-widget="control-sidebar"]' const SELECTOR_HEADER = '.main-header' const SELECTOR_FOOTER = '.main-footer' const CLASS_NAME_CONTROL_SIDEBAR_ANIMATE = 'control-sidebar-animate' const CLASS_NAME_CONTROL_SIDEBAR_OPEN = 'control-sidebar-open' const CLASS_NAME_CONTROL_SIDEBAR_SLIDE = 'control-sidebar-slide-open' const CLASS_NAME_LAYOUT_FIXED = 'layout-fixed' const CLASS_NAME_NAVBAR_FIXED = 'layout-navbar-fixed' const CLASS_NAME_NAVBAR_SM_FIXED = 'layout-sm-navbar-fixed' const CLASS_NAME_NAVBAR_MD_FIXED = 'layout-md-navbar-fixed' const CLASS_NAME_NAVBAR_LG_FIXED = 'layout-lg-navbar-fixed' const CLASS_NAME_NAVBAR_XL_FIXED = 'layout-xl-navbar-fixed' const CLASS_NAME_FOOTER_FIXED = 'layout-footer-fixed' const CLASS_NAME_FOOTER_SM_FIXED = 'layout-sm-footer-fixed' const CLASS_NAME_FOOTER_MD_FIXED = 'layout-md-footer-fixed' const CLASS_NAME_FOOTER_LG_FIXED = 'layout-lg-footer-fixed' const CLASS_NAME_FOOTER_XL_FIXED = 'layout-xl-footer-fixed' const Default = { controlsidebarSlide: true, scrollbarTheme: 'os-theme-light', scrollbarAutoHide: 'l', target: SELECTOR_CONTROL_SIDEBAR, animationSpeed: 300 } /** * Class Definition * ==================================================== */ class ControlSidebar { constructor(element, config) { this._element = element this._config = config } // Public collapse() { const $body = $('body') const $html = $('html') // Show the control sidebar if (this._config.controlsidebarSlide) { $html.addClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) $body.removeClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE).delay(300).queue(function () { $(SELECTOR_CONTROL_SIDEBAR).hide() $html.removeClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) $(this).dequeue() }) } else { $body.removeClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) } $(this._element).trigger($.Event(EVENT_COLLAPSED)) setTimeout(() => { $(this._element).trigger($.Event(EVENT_COLLAPSED_DONE)) }, this._config.animationSpeed) } show(toggle = false) { const $body = $('body') const $html = $('html') if (toggle) { $(SELECTOR_CONTROL_SIDEBAR).hide() } // Collapse the control sidebar if (this._config.controlsidebarSlide) { $html.addClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) $(this._config.target).show().delay(10).queue(function () { $body.addClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE).delay(300).queue(function () { $html.removeClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) $(this).dequeue() }) $(this).dequeue() }) } else { $body.addClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) } this._fixHeight() this._fixScrollHeight() $(this._element).trigger($.Event(EVENT_EXPANDED)) } toggle() { const $body = $('body') const { target } = this._config const notVisible = !$(target).is(':visible') const shouldClose = ($body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE)) const shouldToggle = notVisible && ($body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE)) if (notVisible || shouldToggle) { // Open the control sidebar this.show(notVisible) } else if (shouldClose) { // Close the control sidebar this.collapse() } } // Private _init() { const $body = $('body') const shouldNotHideAll = $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE) if (shouldNotHideAll) { $(SELECTOR_CONTROL_SIDEBAR).not(this._config.target).hide() $(this._config.target).css('display', 'block') } else { $(SELECTOR_CONTROL_SIDEBAR).hide() } this._fixHeight() this._fixScrollHeight() $(window).resize(() => { this._fixHeight() this._fixScrollHeight() }) $(window).scroll(() => { const $body = $('body') const shouldFixHeight = $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE) if (shouldFixHeight) { this._fixScrollHeight() } }) } _isNavbarFixed() { const $body = $('body') return ( $body.hasClass(CLASS_NAME_NAVBAR_FIXED) || $body.hasClass(CLASS_NAME_NAVBAR_SM_FIXED) || $body.hasClass(CLASS_NAME_NAVBAR_MD_FIXED) || $body.hasClass(CLASS_NAME_NAVBAR_LG_FIXED) || $body.hasClass(CLASS_NAME_NAVBAR_XL_FIXED) ) } _isFooterFixed() { const $body = $('body') return ( $body.hasClass(CLASS_NAME_FOOTER_FIXED) || $body.hasClass(CLASS_NAME_FOOTER_SM_FIXED) || $body.hasClass(CLASS_NAME_FOOTER_MD_FIXED) || $body.hasClass(CLASS_NAME_FOOTER_LG_FIXED) || $body.hasClass(CLASS_NAME_FOOTER_XL_FIXED) ) } _fixScrollHeight() { const $body = $('body') const $controlSidebar = $(this._config.target) if (!$body.hasClass(CLASS_NAME_LAYOUT_FIXED)) { return } const heights = { scroll: $(document).height(), window: $(window).height(), header: $(SELECTOR_HEADER).outerHeight(), footer: $(SELECTOR_FOOTER).outerHeight() } const positions = { bottom: Math.abs((heights.window + $(window).scrollTop()) - heights.scroll), top: $(window).scrollTop() } const navbarFixed = this._isNavbarFixed() && $(SELECTOR_HEADER).css('position') === 'fixed' const footerFixed = this._isFooterFixed() && $(SELECTOR_FOOTER).css('position') === 'fixed' const $controlsidebarContent = $(`${this._config.target}, ${this._config.target} ${SELECTOR_CONTROL_SIDEBAR_CONTENT}`) if (positions.top === 0 && positions.bottom === 0) { $controlSidebar.css({ bottom: heights.footer, top: heights.header }) $controlsidebarContent.css('height', heights.window - (heights.header + heights.footer)) } else if (positions.bottom <= heights.footer) { if (footerFixed === false) { const top = heights.header - positions.top $controlSidebar.css('bottom', heights.footer - positions.bottom).css('top', top >= 0 ? top : 0) $controlsidebarContent.css('height', heights.window - (heights.footer - positions.bottom)) } else { $controlSidebar.css('bottom', heights.footer) } } else if (positions.top <= heights.header) { if (navbarFixed === false) { $controlSidebar.css('top', heights.header - positions.top) $controlsidebarContent.css('height', heights.window - (heights.header - positions.top)) } else { $controlSidebar.css('top', heights.header) } } else if (navbarFixed === false) { $controlSidebar.css('top', 0) $controlsidebarContent.css('height', heights.window) } else { $controlSidebar.css('top', heights.header) } if (footerFixed && navbarFixed) { $controlsidebarContent.css('height', '100%') $controlSidebar.css('height', '') } else if (footerFixed || navbarFixed) { $controlsidebarContent.css('height', '100%') $controlsidebarContent.css('height', '') } } _fixHeight() { const $body = $('body') const $controlSidebar = $(`${this._config.target} ${SELECTOR_CONTROL_SIDEBAR_CONTENT}`) if (!$body.hasClass(CLASS_NAME_LAYOUT_FIXED)) { $controlSidebar.attr('style', '') return } const heights = { window: $(window).height(), header: $(SELECTOR_HEADER).outerHeight(), footer: $(SELECTOR_FOOTER).outerHeight() } let sidebarHeight = heights.window - heights.header if (this._isFooterFixed() && $(SELECTOR_FOOTER).css('position') === 'fixed') { sidebarHeight = heights.window - heights.header - heights.footer } $controlSidebar.css('height', sidebarHeight) if (typeof $.fn.overlayScrollbars !== 'undefined') { $controlSidebar.overlayScrollbars({ className: this._config.scrollbarTheme, sizeAutoCapable: true, scrollbars: { autoHide: this._config.scrollbarAutoHide, clickScrolling: true } }) } } // Static static _jQueryInterface(operation) { return this.each(function () { let data = $(this).data(DATA_KEY) const _options = $.extend({}, Default, $(this).data()) if (!data) { data = new ControlSidebar(this, _options) $(this).data(DATA_KEY, data) } if (data[operation] === 'undefined') { throw new Error(`${operation} is not a function`) } data[operation]() }) } } /** * * Data Api implementation * ==================================================== */ $(document).on('click', SELECTOR_DATA_TOGGLE, function (event) { event.preventDefault() ControlSidebar._jQueryInterface.call($(this), 'toggle') }) $(document).ready(() => { ControlSidebar._jQueryInterface.call($(SELECTOR_DATA_TOGGLE), '_init') }) /** * jQuery API * ==================================================== */ $.fn[NAME] = ControlSidebar._jQueryInterface $.fn[NAME].Constructor = ControlSidebar $.fn[NAME].noConflict = function () { $.fn[NAME] = JQUERY_NO_CONFLICT return ControlSidebar._jQueryInterface } export default ControlSidebar