ControlSidebar.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. * --------------------------------------------
  3. * AdminLTE ControlSidebar.js
  4. * License MIT
  5. * --------------------------------------------
  6. */
  7. import $ from 'jquery'
  8. /**
  9. * Constants
  10. * ====================================================
  11. */
  12. const NAME = 'ControlSidebar'
  13. const DATA_KEY = 'lte.controlsidebar'
  14. const EVENT_KEY = `.${DATA_KEY}`
  15. const JQUERY_NO_CONFLICT = $.fn[NAME]
  16. const EVENT_COLLAPSED = `collapsed${EVENT_KEY}`
  17. const EVENT_EXPANDED = `expanded${EVENT_KEY}`
  18. const SELECTOR_CONTROL_SIDEBAR = '.control-sidebar'
  19. const SELECTOR_CONTROL_SIDEBAR_CONTENT = '.control-sidebar-content'
  20. const SELECTOR_DATA_TOGGLE = '[data-widget="control-sidebar"]'
  21. const SELECTOR_HEADER = '.main-header'
  22. const SELECTOR_FOOTER = '.main-footer'
  23. const CLASS_NAME_CONTROL_SIDEBAR_ANIMATE = 'control-sidebar-animate'
  24. const CLASS_NAME_CONTROL_SIDEBAR_OPEN = 'control-sidebar-open'
  25. const CLASS_NAME_CONTROL_SIDEBAR_SLIDE = 'control-sidebar-slide-open'
  26. const CLASS_NAME_LAYOUT_FIXED = 'layout-fixed'
  27. const CLASS_NAME_NAVBAR_FIXED = 'layout-navbar-fixed'
  28. const CLASS_NAME_NAVBAR_SM_FIXED = 'layout-sm-navbar-fixed'
  29. const CLASS_NAME_NAVBAR_MD_FIXED = 'layout-md-navbar-fixed'
  30. const CLASS_NAME_NAVBAR_LG_FIXED = 'layout-lg-navbar-fixed'
  31. const CLASS_NAME_NAVBAR_XL_FIXED = 'layout-xl-navbar-fixed'
  32. const CLASS_NAME_FOOTER_FIXED = 'layout-footer-fixed'
  33. const CLASS_NAME_FOOTER_SM_FIXED = 'layout-sm-footer-fixed'
  34. const CLASS_NAME_FOOTER_MD_FIXED = 'layout-md-footer-fixed'
  35. const CLASS_NAME_FOOTER_LG_FIXED = 'layout-lg-footer-fixed'
  36. const CLASS_NAME_FOOTER_XL_FIXED = 'layout-xl-footer-fixed'
  37. const Default = {
  38. controlsidebarSlide: true,
  39. scrollbarTheme: 'os-theme-light',
  40. scrollbarAutoHide: 'l'
  41. }
  42. /**
  43. * Class Definition
  44. * ====================================================
  45. */
  46. class ControlSidebar {
  47. constructor(element, config) {
  48. this._element = element
  49. this._config = config
  50. this._init()
  51. }
  52. // Public
  53. collapse() {
  54. const $body = $('body')
  55. const $html = $('html')
  56. // Show the control sidebar
  57. if (this._config.controlsidebarSlide) {
  58. $html.addClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE)
  59. $body.removeClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE).delay(300).queue(function () {
  60. $(SELECTOR_CONTROL_SIDEBAR).hide()
  61. $html.removeClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE)
  62. $(this).dequeue()
  63. })
  64. } else {
  65. $body.removeClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN)
  66. }
  67. $(this._element).trigger($.Event(EVENT_COLLAPSED))
  68. }
  69. show() {
  70. const $body = $('body')
  71. const $html = $('html')
  72. // Collapse the control sidebar
  73. if (this._config.controlsidebarSlide) {
  74. $html.addClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE)
  75. $(SELECTOR_CONTROL_SIDEBAR).show().delay(10).queue(function () {
  76. $body.addClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE).delay(300).queue(function () {
  77. $html.removeClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE)
  78. $(this).dequeue()
  79. })
  80. $(this).dequeue()
  81. })
  82. } else {
  83. $body.addClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN)
  84. }
  85. $(this._element).trigger($.Event(EVENT_EXPANDED))
  86. }
  87. toggle() {
  88. const $body = $('body')
  89. const shouldClose = $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) ||
  90. $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE)
  91. if (shouldClose) {
  92. // Close the control sidebar
  93. this.collapse()
  94. } else {
  95. // Open the control sidebar
  96. this.show()
  97. }
  98. }
  99. // Private
  100. _init() {
  101. this._fixHeight()
  102. this._fixScrollHeight()
  103. $(window).resize(() => {
  104. this._fixHeight()
  105. this._fixScrollHeight()
  106. })
  107. $(window).scroll(() => {
  108. const $body = $('body')
  109. const shouldFixHeight = $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) ||
  110. $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE)
  111. if (shouldFixHeight) {
  112. this._fixScrollHeight()
  113. }
  114. })
  115. }
  116. _fixScrollHeight() {
  117. const $body = $('body')
  118. if (!$body.hasClass(CLASS_NAME_LAYOUT_FIXED)) {
  119. return
  120. }
  121. const heights = {
  122. scroll: $(document).height(),
  123. window: $(window).height(),
  124. header: $(SELECTOR_HEADER).outerHeight(),
  125. footer: $(SELECTOR_FOOTER).outerHeight()
  126. }
  127. const positions = {
  128. bottom: Math.abs((heights.window + $(window).scrollTop()) - heights.scroll),
  129. top: $(window).scrollTop()
  130. }
  131. const navbarFixed = (
  132. $body.hasClass(CLASS_NAME_NAVBAR_FIXED) ||
  133. $body.hasClass(CLASS_NAME_NAVBAR_SM_FIXED) ||
  134. $body.hasClass(CLASS_NAME_NAVBAR_MD_FIXED) ||
  135. $body.hasClass(CLASS_NAME_NAVBAR_LG_FIXED) ||
  136. $body.hasClass(CLASS_NAME_NAVBAR_XL_FIXED)
  137. ) && $(SELECTOR_HEADER).css('position') === 'fixed'
  138. const footerFixed = (
  139. $body.hasClass(CLASS_NAME_FOOTER_FIXED) ||
  140. $body.hasClass(CLASS_NAME_FOOTER_SM_FIXED) ||
  141. $body.hasClass(CLASS_NAME_FOOTER_MD_FIXED) ||
  142. $body.hasClass(CLASS_NAME_FOOTER_LG_FIXED) ||
  143. $body.hasClass(CLASS_NAME_FOOTER_XL_FIXED)
  144. ) && $(SELECTOR_FOOTER).css('position') === 'fixed'
  145. const $controlSidebar = $(SELECTOR_CONTROL_SIDEBAR)
  146. const $controlsidebarContent = $(`${SELECTOR_CONTROL_SIDEBAR}, ${SELECTOR_CONTROL_SIDEBAR} ${SELECTOR_CONTROL_SIDEBAR_CONTENT}`)
  147. if (positions.top === 0 && positions.bottom === 0) {
  148. $controlSidebar.css({
  149. bottom: heights.footer,
  150. top: heights.header
  151. })
  152. $controlsidebarContent.css('height', heights.window - (heights.header + heights.footer))
  153. } else if (positions.bottom <= heights.footer) {
  154. if (footerFixed === false) {
  155. $controlSidebar.css('bottom', heights.footer - positions.bottom)
  156. $controlsidebarContent.css('height', heights.window - (heights.footer - positions.bottom))
  157. } else {
  158. $controlSidebar.css('bottom', heights.footer)
  159. }
  160. } else if (positions.top <= heights.header) {
  161. if (navbarFixed === false) {
  162. $controlSidebar.css('top', heights.header - positions.top)
  163. $controlsidebarContent.css('height', heights.window - (heights.header - positions.top))
  164. } else {
  165. $controlSidebar.css('top', heights.header)
  166. }
  167. } else if (navbarFixed === false) {
  168. $controlSidebar.css('top', 0)
  169. $controlsidebarContent.css('height', heights.window)
  170. } else {
  171. $controlSidebar.css('top', heights.header)
  172. }
  173. }
  174. _fixHeight() {
  175. const $body = $('body')
  176. if (!$body.hasClass(CLASS_NAME_LAYOUT_FIXED)) {
  177. return
  178. }
  179. const heights = {
  180. window: $(window).height(),
  181. header: $(SELECTOR_HEADER).outerHeight(),
  182. footer: $(SELECTOR_FOOTER).outerHeight()
  183. }
  184. let sidebarHeight = heights.window - heights.header
  185. if (
  186. $body.hasClass(CLASS_NAME_FOOTER_FIXED) ||
  187. $body.hasClass(CLASS_NAME_FOOTER_SM_FIXED) ||
  188. $body.hasClass(CLASS_NAME_FOOTER_MD_FIXED) ||
  189. $body.hasClass(CLASS_NAME_FOOTER_LG_FIXED) ||
  190. $body.hasClass(CLASS_NAME_FOOTER_XL_FIXED)
  191. ) {
  192. if ($(SELECTOR_FOOTER).css('position') === 'fixed') {
  193. sidebarHeight = heights.window - heights.header - heights.footer
  194. }
  195. }
  196. const $controlSidebar = $(`${SELECTOR_CONTROL_SIDEBAR} ${SELECTOR_CONTROL_SIDEBAR_CONTENT}`)
  197. $controlSidebar.css('height', sidebarHeight)
  198. if (typeof $.fn.overlayScrollbars !== 'undefined') {
  199. $controlSidebar.overlayScrollbars({
  200. className: this._config.scrollbarTheme,
  201. sizeAutoCapable: true,
  202. scrollbars: {
  203. autoHide: this._config.scrollbarAutoHide,
  204. clickScrolling: true
  205. }
  206. })
  207. }
  208. }
  209. // Static
  210. static _jQueryInterface(operation) {
  211. return this.each(function () {
  212. let data = $(this).data(DATA_KEY)
  213. const _options = $.extend({}, Default, $(this).data())
  214. if (!data) {
  215. data = new ControlSidebar(this, _options)
  216. $(this).data(DATA_KEY, data)
  217. }
  218. if (data[operation] === 'undefined') {
  219. throw new Error(`${operation} is not a function`)
  220. }
  221. data[operation]()
  222. })
  223. }
  224. }
  225. /**
  226. *
  227. * Data Api implementation
  228. * ====================================================
  229. */
  230. $(document).on('click', SELECTOR_DATA_TOGGLE, function (event) {
  231. event.preventDefault()
  232. ControlSidebar._jQueryInterface.call($(this), 'toggle')
  233. })
  234. /**
  235. * jQuery API
  236. * ====================================================
  237. */
  238. $.fn[NAME] = ControlSidebar._jQueryInterface
  239. $.fn[NAME].Constructor = ControlSidebar
  240. $.fn[NAME].noConflict = function () {
  241. $.fn[NAME] = JQUERY_NO_CONFLICT
  242. return ControlSidebar._jQueryInterface
  243. }
  244. export default ControlSidebar