useBubbleHeader.ts 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { useTimeout } from '@vueuse/core'
  3. import { ref } from 'vue'
  4. export const useBubbleHeader = () => {
  5. const showMetaInformation = ref(false)
  6. const isInteractiveTarget = (target: HTMLElement) => {
  7. if (!target) return false
  8. const interactiveElements = new Set(['A', 'BUTTON'])
  9. // Parent interactive or traversed nodes
  10. const hasInteractiveElements = target.closest(
  11. Array.from(interactiveElements).join(','),
  12. )
  13. return interactiveElements.has(target.tagName) || hasInteractiveElements
  14. }
  15. const hasSelectionRange = (target: HTMLElement) => {
  16. if (!target) return false
  17. const selection = window.getSelection()
  18. if (!selection || selection.type !== 'Range') return false
  19. return true
  20. }
  21. const { start, stop } = useTimeout(200, {
  22. controls: true,
  23. callback: () => {
  24. showMetaInformation.value = !showMetaInformation.value
  25. },
  26. immediate: false,
  27. })
  28. const toggleHeader = async (event: MouseEvent) => {
  29. stop()
  30. if (
  31. event.detail === 2 || // Double-click
  32. isInteractiveTarget(event.target as HTMLElement) ||
  33. hasSelectionRange(event.target as HTMLElement)
  34. )
  35. return
  36. start()
  37. }
  38. return {
  39. showMetaInformation,
  40. toggleHeader,
  41. }
  42. }