useArticleToggleMore.ts 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { onMounted, ref } from 'vue'
  3. import { waitForAnimationFrame } from '#shared/utils/helpers.ts'
  4. export const useArticleToggleMore = () => {
  5. const MIN_HEIGHT = 60
  6. const MAX_HEIGHT = 320
  7. let heightActual = 0
  8. let heightHidden = 0
  9. const bubbleElement = ref<HTMLDivElement>()
  10. const hasShowMore = ref(true)
  11. const shownMore = ref(false)
  12. const getSignatureMarker = (element: HTMLElement): HTMLElement | null => {
  13. const marker = element.querySelector('.js-signatureMarker') as HTMLElement
  14. if (marker) return marker
  15. return element.querySelector('div [data-signature=true]')
  16. }
  17. const setHeight = async () => {
  18. if (!bubbleElement.value) return
  19. const styles = bubbleElement.value.style
  20. styles.height = ''
  21. await waitForAnimationFrame()
  22. // it's possible it was remounted somehow
  23. if (!bubbleElement.value) return
  24. const height = bubbleElement.value.clientHeight
  25. heightActual = height
  26. const signatureMarker = getSignatureMarker(bubbleElement.value)
  27. const offsetTop = signatureMarker?.offsetTop || 0
  28. if (offsetTop > 0 && offsetTop < MAX_HEIGHT) {
  29. heightHidden = offsetTop < MIN_HEIGHT ? MIN_HEIGHT : offsetTop
  30. hasShowMore.value = true
  31. } else if (height > MAX_HEIGHT) {
  32. heightHidden = MAX_HEIGHT
  33. hasShowMore.value = true
  34. } else {
  35. hasShowMore.value = false
  36. heightHidden = 0
  37. }
  38. if (heightHidden) {
  39. styles.height = `${heightHidden}px`
  40. }
  41. }
  42. onMounted(async () => {
  43. if (!bubbleElement.value) return
  44. await setHeight()
  45. })
  46. const toggleShowMore = () => {
  47. if (!bubbleElement.value) return
  48. shownMore.value = !shownMore.value
  49. const styles = bubbleElement.value.style
  50. styles.transition = 'height 0.3s ease-in-out'
  51. styles.height = shownMore.value
  52. ? `${heightActual + 10}px`
  53. : `${heightHidden}px`
  54. const ontransitionend = () => {
  55. styles.transition = ''
  56. bubbleElement.value?.removeEventListener('transitionend', ontransitionend)
  57. }
  58. bubbleElement.value?.addEventListener('transitionend', ontransitionend)
  59. }
  60. return {
  61. toggleShowMore,
  62. hasShowMore,
  63. shownMore,
  64. bubbleElement,
  65. }
  66. }