You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

menu.js 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /**
  2. * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
  3. *
  4. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  5. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  6. * @author John Molakvoæ <skjnldsv@protonmail.com>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. import _ from 'underscore'
  25. /** @typedef {import('jquery')} jQuery */
  26. import $ from 'jquery'
  27. import { menuSpeed } from './constants'
  28. export let currentMenu = null
  29. export let currentMenuToggle = null
  30. /**
  31. * For menu toggling
  32. *
  33. * @param {jQuery} $toggle the toggle element
  34. * @param {jQuery} $menuEl the menu container element
  35. * @param {Function | undefined} toggle callback invoked everytime the menu is opened
  36. * @param {boolean} headerMenu is this a top right header menu?
  37. * @return {void}
  38. */
  39. export const registerMenu = function($toggle, $menuEl, toggle, headerMenu) {
  40. $menuEl.addClass('menu')
  41. const isClickableElement = $toggle.prop('tagName') === 'A' || $toggle.prop('tagName') === 'BUTTON'
  42. // On link and button, the enter key trigger a click event
  43. // Only use the click to avoid two fired events
  44. $toggle.on(isClickableElement ? 'click.menu' : 'click.menu keyup.menu', function(event) {
  45. // prevent the link event (append anchor to URL)
  46. event.preventDefault()
  47. // allow enter key as a trigger
  48. if (event.key && event.key !== 'Enter') {
  49. return
  50. }
  51. if ($menuEl.is(currentMenu)) {
  52. hideMenus()
  53. return
  54. } else if (currentMenu) {
  55. // another menu was open?
  56. // close it
  57. hideMenus()
  58. }
  59. if (headerMenu === true) {
  60. $menuEl.parent().addClass('openedMenu')
  61. }
  62. // Set menu to expanded
  63. $toggle.attr('aria-expanded', true)
  64. $menuEl.slideToggle(menuSpeed, toggle)
  65. currentMenu = $menuEl
  66. currentMenuToggle = $toggle
  67. })
  68. }
  69. /**
  70. * Unregister a previously registered menu
  71. *
  72. * @param {jQuery} $toggle the toggle element
  73. * @param {jQuery} $menuEl the menu container element
  74. */
  75. export const unregisterMenu = ($toggle, $menuEl) => {
  76. // close menu if opened
  77. if ($menuEl.is(currentMenu)) {
  78. hideMenus()
  79. }
  80. $toggle.off('click.menu').removeClass('menutoggle')
  81. $menuEl.removeClass('menu')
  82. }
  83. /**
  84. * Hides any open menus
  85. *
  86. * @param {Function} complete callback when the hiding animation is done
  87. */
  88. export const hideMenus = function(complete) {
  89. if (currentMenu) {
  90. const lastMenu = currentMenu
  91. currentMenu.trigger(new $.Event('beforeHide'))
  92. currentMenu.slideUp(menuSpeed, function() {
  93. lastMenu.trigger(new $.Event('afterHide'))
  94. if (complete) {
  95. complete.apply(this, arguments)
  96. }
  97. })
  98. }
  99. // Set menu to closed
  100. $('.menutoggle').attr('aria-expanded', false)
  101. $('.openedMenu').removeClass('openedMenu')
  102. currentMenu = null
  103. currentMenuToggle = null
  104. }
  105. /**
  106. * Shows a given element as menu
  107. *
  108. * @param {object} [$toggle=null] menu toggle
  109. * @param {object} $menuEl menu element
  110. * @param {Function} complete callback when the showing animation is done
  111. */
  112. export const showMenu = ($toggle, $menuEl, complete) => {
  113. if ($menuEl.is(currentMenu)) {
  114. return
  115. }
  116. hideMenus()
  117. currentMenu = $menuEl
  118. currentMenuToggle = $toggle
  119. $menuEl.trigger(new $.Event('beforeShow'))
  120. $menuEl.show()
  121. $menuEl.trigger(new $.Event('afterShow'))
  122. // no animation
  123. if (_.isFunction(complete)) {
  124. complete()
  125. }
  126. }