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.5KB

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