Treeview.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /**
  2. * --------------------------------------------
  3. * AdminLTE Treeview.js
  4. * License MIT
  5. * --------------------------------------------
  6. */
  7. import $ from 'jquery'
  8. /**
  9. * Constants
  10. * ====================================================
  11. */
  12. const NAME = 'Treeview'
  13. const DATA_KEY = 'lte.treeview'
  14. const EVENT_KEY = `.${DATA_KEY}`
  15. const JQUERY_NO_CONFLICT = $.fn[NAME]
  16. const EVENT_EXPANDED = `expanded${EVENT_KEY}`
  17. const EVENT_COLLAPSED = `collapsed${EVENT_KEY}`
  18. const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`
  19. const SELECTOR_LI = '.nav-item'
  20. const SELECTOR_LINK = '.nav-link'
  21. const SELECTOR_TREEVIEW_MENU = '.nav-treeview'
  22. const SELECTOR_OPEN = '.menu-open'
  23. const SELECTOR_DATA_WIDGET = '[data-widget="treeview"]'
  24. const CLASS_NAME_OPEN = 'menu-open'
  25. const CLASS_NAME_IS_OPENING = 'menu-is-opening'
  26. const CLASS_NAME_SIDEBAR_COLLAPSED = 'sidebar-collapse'
  27. const Default = {
  28. trigger: `${SELECTOR_DATA_WIDGET} ${SELECTOR_LINK}`,
  29. animationSpeed: 300,
  30. accordion: true,
  31. expandSidebar: false,
  32. sidebarButtonSelector: '[data-widget="pushmenu"]'
  33. }
  34. /**
  35. * Class Definition
  36. * ====================================================
  37. */
  38. class Treeview {
  39. constructor(element, config) {
  40. this._config = config
  41. this._element = element
  42. }
  43. // Public
  44. _init() {
  45. $(`${SELECTOR_LI}${SELECTOR_OPEN} ${SELECTOR_TREEVIEW_MENU}${SELECTOR_OPEN}`).css('display', 'block')
  46. this._setupListeners()
  47. }
  48. expand(treeviewMenu, parentLi) {
  49. const expandedEvent = $.Event(EVENT_EXPANDED)
  50. if (this._config.accordion) {
  51. const openMenuLi = parentLi.siblings(SELECTOR_OPEN).first()
  52. const openTreeview = openMenuLi.find(SELECTOR_TREEVIEW_MENU).first()
  53. this.collapse(openTreeview, openMenuLi)
  54. }
  55. parentLi.addClass(CLASS_NAME_IS_OPENING)
  56. treeviewMenu.stop().slideDown(this._config.animationSpeed, () => {
  57. parentLi.addClass(CLASS_NAME_OPEN)
  58. $(this._element).trigger(expandedEvent)
  59. })
  60. if (this._config.expandSidebar) {
  61. this._expandSidebar()
  62. }
  63. }
  64. collapse(treeviewMenu, parentLi) {
  65. const collapsedEvent = $.Event(EVENT_COLLAPSED)
  66. parentLi.removeClass(`${CLASS_NAME_IS_OPENING} ${CLASS_NAME_OPEN}`)
  67. treeviewMenu.stop().slideUp(this._config.animationSpeed, () => {
  68. $(this._element).trigger(collapsedEvent)
  69. treeviewMenu.find(`${SELECTOR_OPEN} > ${SELECTOR_TREEVIEW_MENU}`).slideUp()
  70. treeviewMenu.find(SELECTOR_OPEN).removeClass(`${CLASS_NAME_IS_OPENING} ${CLASS_NAME_OPEN}`)
  71. })
  72. }
  73. toggle(event) {
  74. const $relativeTarget = $(event.currentTarget)
  75. const $parent = $relativeTarget.parent()
  76. let treeviewMenu = $parent.find(`> ${SELECTOR_TREEVIEW_MENU}`)
  77. if (!treeviewMenu.is(SELECTOR_TREEVIEW_MENU)) {
  78. if (!$parent.is(SELECTOR_LI)) {
  79. treeviewMenu = $parent.parent().find(`> ${SELECTOR_TREEVIEW_MENU}`)
  80. }
  81. if (!treeviewMenu.is(SELECTOR_TREEVIEW_MENU)) {
  82. return
  83. }
  84. }
  85. event.preventDefault()
  86. const parentLi = $relativeTarget.parents(SELECTOR_LI).first()
  87. const isOpen = parentLi.hasClass(CLASS_NAME_OPEN)
  88. if (isOpen) {
  89. this.collapse($(treeviewMenu), parentLi)
  90. } else {
  91. this.expand($(treeviewMenu), parentLi)
  92. }
  93. }
  94. // Private
  95. _setupListeners() {
  96. const elementId = this._element.attr('id') !== undefined ? `#${this._element.attr('id')}` : ''
  97. $(document).on('click', `${elementId}${this._config.trigger}`, event => {
  98. this.toggle(event)
  99. })
  100. }
  101. _expandSidebar() {
  102. if ($('body').hasClass(CLASS_NAME_SIDEBAR_COLLAPSED)) {
  103. $(this._config.sidebarButtonSelector).PushMenu('expand')
  104. }
  105. }
  106. // Static
  107. static _jQueryInterface(config) {
  108. return this.each(function () {
  109. let data = $(this).data(DATA_KEY)
  110. const _config = $.extend({}, Default, typeof config === 'object' ? config : $(this).data())
  111. if (!data) {
  112. data = new Treeview($(this), _config)
  113. $(this).data(DATA_KEY, data)
  114. data._init()
  115. } else if (typeof config === 'string') {
  116. if (typeof data[config] === 'undefined') {
  117. throw new TypeError(`No method named "${config}"`)
  118. }
  119. data[config]()
  120. } else if (typeof config === 'undefined') {
  121. data._init()
  122. }
  123. })
  124. }
  125. }
  126. /**
  127. * Data API
  128. * ====================================================
  129. */
  130. $(window).on(EVENT_LOAD_DATA_API, () => {
  131. $(SELECTOR_DATA_WIDGET).each(function () {
  132. Treeview._jQueryInterface.call($(this), 'init')
  133. })
  134. })
  135. /**
  136. * jQuery API
  137. * ====================================================
  138. */
  139. $.fn[NAME] = Treeview._jQueryInterface
  140. $.fn[NAME].Constructor = Treeview
  141. $.fn[NAME].noConflict = function () {
  142. $.fn[NAME] = JQUERY_NO_CONFLICT
  143. return Treeview._jQueryInterface
  144. }
  145. export default Treeview