app/frontend/shared/entities/ticket-article/composables/getArticleSelection.ts
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
// import { textToHtml } from '#shared/utils/helpers.ts'
import { getCurrentSelectionData } from '#shared/utils/selection.ts'
const closest = (node: Node, selector: string) => {
while (node.parentNode) {
if ('matches' in node && (node as Element).matches(selector)) return node
node = node.parentNode
}
return null
}
const isInsideSelectionBoundary = (node: Element, articleId: number) => {
// node can be textNode, it doesn't have "closest" method
return !!closest(node, `#article-${articleId} .Content`)
}
const containsNode = (selection: Selection, node: Element) => {
return !!selection.containsNode(node, false)
}
export const getArticleSelection = (articleId: number) => {
const selection = window.getSelection()
if (!selection || selection.rangeCount <= 0) return undefined
const range = selection.getRangeAt(0)
const articleContent = document.querySelector(
`#article-${articleId} .Content`,
) as HTMLDivElement | null
if (!articleContent) return undefined
const startInsideArticle = isInsideSelectionBoundary(
range.startContainer as Element,
articleId,
)
const endInsideArticle = isInsideSelectionBoundary(
range.endContainer as Element,
articleId,
)
const contains = containsNode(selection, articleContent)
const canQuote = startInsideArticle || endInsideArticle || contains
if (!canQuote) return undefined
// Fixes Issue #3539 - When replying quote article content only
if (!startInsideArticle && endInsideArticle) {
range.setStart(articleContent, 0)
} else if (startInsideArticle && !endInsideArticle) {
range.setEnd(articleContent, articleContent.childNodes.length)
} else if (contains) {
range.setStart(articleContent, 0)
range.setEnd(articleContent, articleContent.childNodes.length)
}
return getCurrentSelectionData()
}