vdc-editor 0.1.197 → 0.1.198

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { c as Z, a as Y, C as be, P as Ce, b as ve, D as ye, d as Ee, _ as Se, e as we, f as Te, S as oe, o as Ie, g as Re, h as Oe, i as Ne, j as We, k as Me, l as He, m as Ae, n as $e } from "./index-CT6L-cic.mjs";
1
+ import { c as Z, a as Y, C as be, P as Ce, b as ve, D as ye, d as Ee, _ as Se, e as we, f as Te, S as oe, o as Ie, g as Re, h as Oe, i as Ne, j as We, k as Me, l as He, m as Ae, n as $e } from "./index-DgdZsemB.mjs";
2
2
  import { defineComponent as P, createElementBlock as v, openBlock as m, createVNode as E, createElementVNode as h, unref as s, ref as L, onMounted as ee, nextTick as le, createCommentVNode as ie, normalizeClass as z, withModifiers as te, toDisplayString as G, normalizeStyle as ae, Fragment as K, renderList as q, createTextVNode as V, createBlock as B, createStaticVNode as Le, withCtx as $, reactive as ce, computed as se, watch as ue, normalizeProps as De, guardReactiveProps as Pe, renderSlot as Be, onUnmounted as re, resolveDynamicComponent as ze } from "vue";
3
3
  import { useWindowSize as je, useEventListener as Ge } from "@vueuse/core";
4
4
  const U = {
@@ -684,4 +684,4 @@ const vt = /* @__PURE__ */ Se(kt, [["render", Ct]]), yt = { class: "text-xs py-4
684
684
  export {
685
685
  Mt as default
686
686
  };
687
- //# sourceMappingURL=BulkSpellChecker-Er4di3gp.mjs.map
687
+ //# sourceMappingURL=BulkSpellChecker-IKxccUeP.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BulkSpellChecker-Er4di3gp.mjs","sources":["../src/constants/bulkSpellChecker.ts","../node_modules/lucide-vue-next/dist/esm/icons/arrow-left-right.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-alert.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-check.js","../src/components/BulkSpellCheckerHelpText.vue","../src/utils/bulkSpellchecker.ts","../src/components/BulkSpellCheckerWrongWordList.vue","../src/components/ui/SpinnerIcon.vue","../src/components/BulkSpellCheckerLoading.vue","../src/components/BulkSpellCheckerContent.vue","../src/hooks/useBulkSpellCheckerStore.ts","../src/components/ui/dialog/DialogTrigger.vue","../src/components/BulkSpellChecker.vue"],"sourcesContent":["export const ERROR_TYPE = {\n SPACING: 1,\n SPELLING: 2,\n}\n\nexport const SPELL_CHECK_CODE = {\n NOTHING_TO_CHANGE: 'NOTHING_TO_CHANGE',\n} as const\n\nexport const SPELL_CHECK_STATUS = {\n LOADING: 'loading',\n HAS_ERROR: 'hasError',\n NO_ERROR: 'noError',\n FAIL: 'fail',\n} as const\n\nexport type SpellCheckStatus = (typeof SPELL_CHECK_STATUS)[keyof typeof SPELL_CHECK_STATUS]\n\nexport const EDITOR_NAME = {\n EDITOR_COMMENT: 'editorComment',\n EDITOR_CONTENT: 'editorContent',\n} as const\n\nexport type EditorName = (typeof EDITOR_NAME)[keyof typeof EDITOR_NAME]\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ArrowLeftRight = createLucideIcon(\"ArrowLeftRightIcon\", [\n [\"path\", { d: \"M8 3 4 7l4 4\", key: \"9rb6wj\" }],\n [\"path\", { d: \"M4 7h16\", key: \"6tx8e3\" }],\n [\"path\", { d: \"m16 21 4-4-4-4\", key: \"siv7j2\" }],\n [\"path\", { d: \"M20 17H4\", key: \"h6l3hr\" }]\n]);\n\nexport { ArrowLeftRight as default };\n//# sourceMappingURL=arrow-left-right.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleAlert = createLucideIcon(\"CircleAlertIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n]);\n\nexport { CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheck = createLucideIcon(\"CircleCheckIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n]);\n\nexport { CircleCheck as default };\n//# sourceMappingURL=circle-check.js.map\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\nimport { ChevronDown } from 'lucide-vue-next'\n\ninterface Props {\n text: string\n}\nconst props = defineProps<Props>()\n\nconst expanded = ref(false)\nconst showButton = ref(false)\nconst helpRef = ref<HTMLElement | null>(null)\n\nfunction toggle() {\n expanded.value = !expanded.value\n}\n\nonMounted(async () => {\n await nextTick()\n if (helpRef.value && helpRef.value.scrollHeight > 32) {\n showButton.value = true\n }\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div\n ref=\"helpRef\"\n class=\"text-gray-700 dark:text-gray-400 transition-all\"\n :class=\"expanded ? 'max-h-none' : 'max-h-[32px] overflow-hidden'\"\n v-html=\"text\"\n ></div>\n\n <div\n v-if=\"showButton\"\n class=\"\"\n :class=\"\n cn(\n 'w-32 flex items-end justify-end bg-gradient-to-l from-white via-white to-transparent dark:from-ed-background dark:via-ed-background',\n expanded ? 'ml-auto opacity-60' : 'absolute bottom-0 right-0'\n )\n \"\n >\n <button class=\"flex items-center gap-1\" @click.stop=\"toggle\">\n <span class=\"border-b border-gray-500\">{{ expanded ? '접기' : '자세히' }}</span>\n <ChevronDown class=\"w-4 h-4 transition-transform\" :class=\"expanded ? 'rotate-180' : ''\" />\n </button>\n </div>\n </div>\n</template>\n","import { ERROR_TYPE } from '@/constants'\nimport { WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport { Plugin, PluginKey } from 'prosemirror-state'\nimport { Decoration, DecorationSet } from 'prosemirror-view'\n\nconst HIGHLIGHT_KEY = new PluginKey('bulk-spellcheck-highlight')\n\nfunction createHighlightPlugin(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n return new Plugin({\n key: HIGHLIGHT_KEY,\n props: {\n decorations(state) {\n const decos: Decoration[] = []\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bulk-highlight text-blue-500 border-b-2 border-blue-500',\n [ERROR_TYPE.SPELLING]: 'bulk-highlight text-red-500 border-b-2 border-red-500',\n }\n\n errors.forEach(item => {\n const from = findDocPosFromOffset(editor, item.startIndex, blockSeparator)\n const to = findDocPosFromOffset(editor, item.endIndex - 1, blockSeparator) + 1\n\n const errorType = item.errorHelpDtos?.[0]?.errorType\n const className = errorColorMap[errorType ?? -1] || 'bulk-highlight text-green-500 border-b-2 border-green-500' // type integrated\n\n const safeFrom = Math.max(0, Math.min(from, state.doc.content.size))\n const safeTo = Math.max(0, Math.min(to, state.doc.content.size))\n if (safeFrom < safeTo) {\n decos.push(Decoration.inline(safeFrom, safeTo, { class: className }))\n }\n })\n\n return DecorationSet.create(state.doc, decos)\n },\n },\n })\n}\n\nexport function applyHighlights(editor: Editor, errors: WrongWordItem[]) {\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n\n if (!errors.length) return\n\n const plugin = createHighlightPlugin(editor, errors)\n editor.registerPlugin(plugin)\n}\n\nexport function clearHighlights(editor: Editor) {\n if (!editor) return\n\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n}\n\nexport function buildPlainIndexToDocPosMap(editor: Editor, blockSeparator = '\\n') {\n const map: (number | null)[] = []\n let plainIndex = 0\n let firstBlock = true\n\n editor.state.doc.descendants((node, pos) => {\n if (node.isText && node.text) {\n for (let i = 0; i < node.text.length; i++) {\n map[plainIndex++] = pos + i\n }\n }\n\n const nodeName = node.type && (node.type as any).name\n const isHardBreak = nodeName === 'hardBreak' || nodeName === 'hard_break' || nodeName === 'br'\n if (isHardBreak && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos\n }\n }\n\n if (node.isBlock) {\n if (!firstBlock && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos \n }\n }\n firstBlock = false\n }\n\n return true\n })\n\n return map\n}\n\nexport function findDocPosFromOffset(editor: Editor,offset: number, blockSeparator = '\\n') {\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n if (offset < 0) offset = 0\n if (offset >= map.length) {\n return editor.state.doc.content.size\n }\n const mapped = map[offset]\n if (mapped == null) {\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n return mapped as number\n}\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME, EditorName, ERROR_TYPE } from '@/constants'\nimport { ArrowLeftRight } from 'lucide-vue-next'\nimport { Editor } from '@tiptap/core'\nimport { EditorsState, WrongWordItem } from '@/type'\nimport { applyHighlights, findDocPosFromOffset } from '@/utils/bulkSpellchecker'\n\ninterface Props {\n editorsState: EditorsState\n}\nconst props = defineProps<Props>()\n\nfunction getErrorColor(errorType?: number) {\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bg-blue-500',\n [ERROR_TYPE.SPELLING]: 'bg-red-500',\n }\n return errorColorMap[errorType ?? -1] || 'bg-green-500' // integrated\n}\n\nfunction getNoSuggestionText(editor: Editor) {\n return editor?.extensionStorage?.spellchecker?.spellchecker?.uiStrings?.uiStrings || 'No suggestions found'\n}\n\nfunction resetHightlightSection(key: EditorName) {\n if (key === EDITOR_NAME.EDITOR_COMMENT) {\n props.editorsState[EDITOR_NAME.EDITOR_CONTENT].editor?.commands.setTextSelection(0)\n return\n }\n\n if (key === EDITOR_NAME.EDITOR_CONTENT) {\n props.editorsState[EDITOR_NAME.EDITOR_COMMENT].editor?.commands.setTextSelection(0)\n return\n }\n}\n\nfunction scrollToError(key: EditorName, editor: Editor, item: WrongWordItem) {\n if (!editor) return\n\n resetHightlightSection(key)\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n editor.chain().setTextSelection({ from, to }).focus().run()\n\n const mid = Math.max(0, Math.floor((from + to) / 2))\n const domAtPos = editor.view.domAtPos(mid)\n const maybeNode = domAtPos.node as unknown\n\n let el: HTMLElement | null = null\n\n if (maybeNode instanceof Element) {\n el = maybeNode as HTMLElement\n } else if (maybeNode instanceof Text) {\n el = maybeNode.parentElement\n } else {\n el = (maybeNode as any)?.parentElement ?? (editor.view.dom as HTMLElement)\n }\n\n if (el?.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth', block: 'center' })\n }\n}\n\nfunction replaceWithCorrectWord(editor: Editor, errors: WrongWordItem[], item: WrongWordItem, replacement: string) {\n if (!editor) return\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n const tr = editor.state.tr.insertText(replacement, from, to)\n editor.view.dispatch(tr)\n editor.view.focus()\n\n const delta = replacement.length - (item.wrongWord?.length ?? 0)\n const origStart = item.startIndex\n const origEnd = item.endIndex\n\n for (let i = errors.length - 1; i >= 0; i--) {\n const err = errors[i]\n\n if (err.startIndex >= origStart && err.startIndex < origEnd) {\n errors.splice(i, 1)\n continue\n }\n\n if (err.startIndex > origStart) {\n err.startIndex += delta\n err.endIndex += delta\n }\n }\n\n const idx = errors.indexOf(item)\n if (idx !== -1) errors.splice(idx, 1)\n\n applyHighlights(editor, errors)\n}\n\nconst contentEl = ref<HTMLElement | null>(null)\nconst standardMaxHeight = 450\nconst maxHeight = ref(standardMaxHeight)\nconst { height: windowHeight } = useWindowSize()\n\nfunction computeMaxHeight() {\n const el = contentEl.value\n if (!el) return\n\n const gap = 80\n const rect = el.getBoundingClientRect()\n const availableViewportHeight = windowHeight.value - rect.top - gap\n\n maxHeight.value = standardMaxHeight > availableViewportHeight ? availableViewportHeight : standardMaxHeight\n}\n\nonMounted(() => {\n computeMaxHeight()\n useEventListener(window, 'resize', computeMaxHeight)\n})\n</script>\n\n<template>\n <div ref=\"contentEl\" :style=\"{ maxHeight: `${maxHeight}px` }\" class=\"pr-1 overflow-y-auto\">\n <template v-for=\"(editorData, key) in editorsState\" :key=\"key\">\n <div\n v-for=\"(item, idx) in editorData.wrongWords\"\n :key=\"idx\"\n class=\"border-b border-gray-100 dark:border-ed-muted pb-5 mb-5 cursor-pointer\"\n @click=\"scrollToError(key, editorsState[key].editor as Editor, item)\"\n >\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">입력 내용</span>\n <div class=\"flex items-center gap-2\">\n <span class=\"w-1.5 h-1.5 rounded-full\" :class=\"getErrorColor(item.errorHelpDtos[0]?.errorType)\"></span>\n <span class=\"break-all whitespace-normal\">{{ item.wrongWord }}</span>\n </div>\n </div>\n\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">대치어</span>\n <div v-if=\"item.correctWord.length\" class=\"flex-1 space-y-1\">\n <div\n v-for=\"(sub, sidx) in item.correctWord\"\n :key=\"sidx\"\n class=\"font-semibold px-3 py-1.5 rounded bg-gray-100 dark:bg-ed-muted flex items-center justify-between\"\n >\n <div class=\"text-sm\">\n {{ sub }}\n </div>\n <button\n class=\"flex items-center gap-1 text-blue-500\"\n @click.stop=\"replaceWithCorrectWord(editorData.editor as Editor, editorData.wrongWords, item, sub)\"\n >\n <ArrowLeftRight class=\"w-4 h-4\" /> <span>바꾸기</span>\n </button>\n </div>\n </div>\n <div v-else>\n {{ getNoSuggestionText(editorData.editor as Editor) }}\n </div>\n </div>\n\n <div class=\"flex\">\n <span class=\"w-16 font-medium\">도움말</span>\n <div class=\"flex-1\">\n <BulkSpellCheckerHelpText :text=\"item.errorHelpDtos[0]?.errorMessage\" />\n </div>\n </div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\n\ninterface Props {\n fillWhite?: boolean\n class?: string\n}\nconst props = withDefaults(defineProps<Props>(), {\n fillWhite: false,\n class: '',\n})\n</script>\n\n<template>\n <svg :class=\"cn('animate-spin h-5 w-5 mr-0.5', props.class)\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle\n v-if=\"fillWhite\"\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n fill=\"#ffffff\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <circle v-else class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path\n class=\"opacity-100\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</template>\n\n<style scoped></style>\n","<template>\n <div class=\"min-h-[188px] flex flex-col items-center justify-center gap-y-2 text-sm\">\n <SpinnerIcon fill-white class=\"h-10 w-10 text-blue-500\" />\n <div>맞춤법 검사 중입니다</div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { cn } from '@/utils'\nimport { EditorsState } from '@/type'\n\ninterface Props {\n editorsState: EditorsState,\n spellCheckStatus: SpellCheckStatus\n allWrongWordsMissSuggestions: boolean\n}\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'close-modal'): void\n (e: 'run-spellcheck'): void\n (e: 'replace-all-editor-errors'): void\n}>()\n</script>\n\n<template>\n <div class=\"text-xs py-4 px-6\">\n <BulkSpellCheckerLoading v-if=\"spellCheckStatus === SPELL_CHECK_STATUS.LOADING\" />\n <BulkSpellCheckerWrongWordList v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.HAS_ERROR\" :editorsState=\"editorsState\" />\n <BulkSpellCheckerNotWrongWord v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.NO_ERROR\" />\n <BulkSpellCheckerFail v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.FAIL\" />\n\n <div class=\"flex items-center justify-between mt-3\">\n <ul class=\"flex items-cente gap-x-4\">\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-red-500\"></span>맞춤법</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-blue-500\"></span>띄어쓰기</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-green-500\"></span>통합교정</li>\n </ul>\n\n <div class=\"flex gap-x-1\">\n <Button\n variant=\"outline\"\n :class=\"\n cn(\n 'border-blue-500 text-blue-500 text-xs px-3 py-2 h-auto hover:bg-white/80 hover:opacity-80 hover:text-blue-500 dark:text-dark-blue-100 dark:hover:bg-dark-blue-400 dark:hover:text-dark-blue-50 dark:hover:border-dark-blue-100',\n spellCheckStatus === SPELL_CHECK_STATUS.LOADING &&\n 'text-gray-300 bg-gray-100 border-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:border-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('run-spellcheck')\"\n >다시 검사하기</Button\n >\n\n <Button\n :class=\"\n cn(\n 'border-blue-500 text-white text-xs px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80',\n (spellCheckStatus !== SPELL_CHECK_STATUS.HAS_ERROR || allWrongWordsMissSuggestions) &&\n 'text-gray-300 bg-gray-100 hover:bg-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('replace-all-editor-errors')\"\n >모두 바꾸기</Button\n >\n </div>\n </div>\n </div>\n</template>\n","import { EDITOR_NAME, EditorName, SPELL_CHECK_CODE, SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { EditorsState, SpellCheckResponse, WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport axios from 'axios'\nimport { applyHighlights, clearHighlights, buildPlainIndexToDocPosMap } from '@/utils/bulkSpellchecker'\nimport { SPELLCHECKER_META_LIST } from '@/extensions/SpellChecker/spellchecker-extension'\n\nexport const useBulkSpellCheckerStore = () => {\n const editorsState: EditorsState = reactive({\n [EDITOR_NAME.EDITOR_COMMENT]: {\n editor: null,\n wrongWords: [],\n },\n [EDITOR_NAME.EDITOR_CONTENT]: {\n editor: null,\n wrongWords: [],\n },\n })\n\n function setEditor(editorKey: EditorName, editorInstance: Editor | null) {\n editorsState[editorKey].editor = editorInstance\n }\n\n const spellCheckStatus = ref<SpellCheckStatus>(SPELL_CHECK_STATUS.NO_ERROR)\n\n function resetAllEditorWrongWords() {\n Object.values(editorsState).forEach(editorState => {\n editorState.wrongWords = []\n })\n }\n\n function evaluateStatus(hasFail: boolean, hasError: boolean) {\n if (hasFail) return SPELL_CHECK_STATUS.FAIL\n if (hasError) return SPELL_CHECK_STATUS.HAS_ERROR\n return SPELL_CHECK_STATUS.NO_ERROR\n }\n\n async function handleRunSpellCheck() {\n spellCheckStatus.value = SPELL_CHECK_STATUS.LOADING\n\n let hasError = false\n let hasFail = false\n\n for (const [editorKey, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n\n const apiUrl = editor?.extensionManager.extensions.find(ext => ext.name === 'spellchecker')?.options.proofreader\n .api\n const content = editor.getText({ blockSeparator: '\\n' })\n if (!apiUrl || !content) continue\n\n try {\n const { data: response } = await axios.post<SpellCheckResponse>(apiUrl, {\n value: content,\n })\n\n if (!response.success && response.code !== SPELL_CHECK_CODE.NOTHING_TO_CHANGE) {\n hasFail = true\n editorsState[editorKey].wrongWords = []\n continue\n }\n\n if (response.data?.wrongWordResponseDto) {\n hasError = true\n editorsState[editorKey].wrongWords = response.data.wrongWordResponseDto\n continue\n }\n\n editorsState[editorKey].wrongWords = []\n } catch (error) {\n console.error('handleRunSpellCheck error: ', error)\n hasFail = true\n }\n }\n\n spellCheckStatus.value = evaluateStatus(hasFail, hasError)\n }\n\n const countTotalWrongWords = computed(() => {\n return Object.values(editorsState).reduce((sum, { wrongWords }) => {\n return sum + wrongWords.length\n }, 0)\n })\n\n watch(countTotalWrongWords, newVal => {\n if (newVal === 0) {\n spellCheckStatus.value = evaluateStatus(false, false)\n }\n })\n\n const allWrongWordsMissSuggestions = computed(() => {\n const allWrongWords = Object.values(editorsState).flatMap(es => es.wrongWords)\n if (allWrongWords.length === 0) return false\n return allWrongWords.every(w => !Array.isArray(w.correctWord) || w.correctWord.length === 0)\n })\n\n function applyAllEditorHighlightErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n applyHighlights(editor as Editor, wrongWords)\n }\n }\n\n function clearAllEditorHighlightErrors() {\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n clearHighlights(editor as Editor)\n }\n }\n\n async function reRunSpellCheckAndHighlight() {\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n }\n\n let isEnableCurrent = true\n function disableSpellCheckRealTime(isEnableSpellCheckRealTime: boolean) {\n isEnableCurrent = isEnableSpellCheckRealTime\n if (!isEnableSpellCheckRealTime) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(false)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, false))\n }\n }\n\n function resetEnableSpellCheckRealTime() {\n if (!isEnableCurrent) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(true)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, true))\n }\n }\n\n function replaceAllErrors(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n if (!editor) return\n if (!errors.length) return\n\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n\n function getMappedPos(offset: number) {\n if (offset < 0) offset = 0\n if (offset >= map.length) return editor.state.doc.content.size\n if (map[offset] != null) return map[offset] as number\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n\n const replacements = errors.map(item => {\n const from = getMappedPos(item.startIndex)\n const to = getMappedPos(Math.max(0, item.endIndex - 1)) + 1\n const replacement = item.correctWord?.[0] ?? item.wrongWord\n return { item, from, to, replacement }\n })\n\n const validRepls = replacements.filter(r => typeof r.from === 'number' && typeof r.to === 'number' && r.from < r.to)\n\n if (!validRepls.length) return\n\n validRepls.sort((a, b) => b.from - a.from)\n\n const tr = editor.state.tr\n let lastAppliedFrom = Number.POSITIVE_INFINITY\n const appliedItems = new Set<WrongWordItem>()\n\n for (const r of validRepls) {\n if (r.to > lastAppliedFrom) {\n continue\n }\n\n tr.insertText(r.replacement, r.from, r.to)\n\n appliedItems.add(r.item)\n lastAppliedFrom = r.from\n }\n\n if (appliedItems.size > 0) {\n editor.view.dispatch(tr)\n editor.view.focus()\n }\n\n if (appliedItems.size > 0) {\n errors = errors.filter(e => ![...appliedItems].some(a => a === e))\n }\n\n applyHighlights(editor, errors)\n }\n\n function replaceAllEditorErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n replaceAllErrors(editor as Editor, wrongWords)\n }\n }\n\n return {\n editorsState,\n spellCheckStatus,\n countTotalWrongWords,\n allWrongWordsMissSuggestions,\n setEditor,\n resetAllEditorWrongWords,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n handleRunSpellCheck,\n replaceAllEditorErrors,\n }\n}\n","<script setup lang=\"ts\">\nimport { DialogTrigger, type DialogTriggerProps } from 'radix-vue'\n\nconst props = defineProps<DialogTriggerProps>()\n</script>\n\n<template>\n <DialogTrigger v-bind=\"props\">\n <slot />\n </DialogTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME } from '@/constants'\nimport { useBulkSpellCheckerStore } from '@/hooks/useBulkSpellCheckerStore'\nimport { Editor } from '@tiptap/core'\nimport { DialogTrigger } from './ui/dialog'\n\ninterface Props {\n editor: Editor\n editorComment?: Editor\n isEnableSpellCheckRealTime: boolean\n}\nconst props = defineProps<Props>()\n\nconst {\n editorsState,\n countTotalWrongWords,\n spellCheckStatus,\n allWrongWordsMissSuggestions,\n setEditor,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n handleRunSpellCheck,\n resetAllEditorWrongWords,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n replaceAllEditorErrors,\n} = useBulkSpellCheckerStore()\n\nconst isOpenModal = ref(false)\n\nconst dragOffset = reactive({ x: 0, y: 0 })\nconst dragging = ref(false)\nconst offset = { x: 0, y: 0 }\n\nconst onMouseDown = (e: MouseEvent) => {\n dragging.value = true\n offset.x = e.clientX - dragOffset.x\n offset.y = e.clientY - dragOffset.y\n document.addEventListener('mousemove', onMouseMove)\n document.addEventListener('mouseup', onMouseUp)\n}\n\nconst onMouseMove = (e: MouseEvent) => {\n if (!dragging.value) return\n dragOffset.x = e.clientX - offset.x\n dragOffset.y = e.clientY - offset.y\n}\n\nconst onMouseUp = () => {\n dragging.value = false\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n}\n\nonUnmounted(() => {\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n})\n\nconst triggerRef = ref<InstanceType<typeof DialogTrigger> | null>(null)\nconst position = ref({ top: 0, right: 0 })\n\nconst updatePosition = () => {\n if (triggerRef.value) {\n const rect = triggerRef.value.$el.getBoundingClientRect()\n\n position.value = {\n top: rect.bottom + window.scrollY + 5,\n right: window.innerWidth - rect.right - window.scrollX,\n }\n\n dragOffset.x = 0\n dragOffset.y = 0\n }\n}\n\nonMounted(async () => {\n if (props.editorComment) {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, props.editorComment)\n }\n setEditor(EDITOR_NAME.EDITOR_CONTENT, props.editor)\n})\n\nonUnmounted(() => {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, null)\n setEditor(EDITOR_NAME.EDITOR_CONTENT, null)\n})\n\nwatch(isOpenModal, async val => {\n if (val) {\n await nextTick()\n updatePosition()\n disableSpellCheckRealTime(props.isEnableSpellCheckRealTime)\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n } else {\n resetAllEditorWrongWords()\n resetEnableSpellCheckRealTime()\n clearAllEditorHighlightErrors()\n }\n})\n\nconst bulkSpellCheckerBtnConfig = props.editor?.extensionManager.extensions.find(e => e.name === 'spellchecker')\n ?.options.bulkSpellCheckerButton\n</script>\n\n<template>\n <Dialog :open=\"isOpenModal\">\n <DialogTrigger as-child ref=\"triggerRef\" @click=\"isOpenModal = !isOpenModal\">\n <button\n v-if=\"!bulkSpellCheckerBtnConfig\"\n class=\"border-blue-500 text-white text-xs text-nowrap px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80 flex items-center rounded\"\n >\n <Icon name=\"checkUnderline\" />맞춤법 일괄 교정\n </button>\n\n <component\n v-else\n :is=\"bulkSpellCheckerBtnConfig.component\"\n :buttonName=\"bulkSpellCheckerBtnConfig.props.buttonName\"\n :icon=\"bulkSpellCheckerBtnConfig.props.icon\"\n :type=\"bulkSpellCheckerBtnConfig.props.type\"\n :disabled=\"bulkSpellCheckerBtnConfig.props.disabled\"\n :iconPosition=\"bulkSpellCheckerBtnConfig.props.iconPosition\"\n :buttonSize=\"bulkSpellCheckerBtnConfig.props.buttonSize\"\n :iconClass=\"bulkSpellCheckerBtnConfig.props.iconClass\"\n />\n </DialogTrigger>\n\n <DialogContent is-overlay-transparent class=\"p-0 gap-0 !animate-none !transition-none dark:border-ed-muted\" as-child>\n <div\n class=\"z-[70]\"\n :style=\"{\n transform: `translate(${dragOffset.x}px, ${dragOffset.y}px)`,\n top: `${position.top}px`,\n right: `${position.right}px`,\n left: 'auto',\n }\"\n >\n <DialogHeader\n class=\"bg-ed-blue-light py-3.5 px-6 rounded-t-[5px] cursor-move text-blue-500 dark:text-dark-blue-100 flex-row items-center justify-between\"\n @mousedown.prevent=\"onMouseDown\"\n >\n <DialogTitle class=\"text-base space-x-2\">\n <span>맞춤법/문법 오류</span>\n <Badge class=\"text-sm bg-blue-500 hover:bg-blue-500 dark:bg-dark-blue-100 px-2\">{{ countTotalWrongWords }}개</Badge></DialogTitle\n >\n\n <DialogClose @click=\"isOpenModal = false\" class=\"text-xs flex items-center gap-x-1\">\n <Icon name=\"Close\" class=\"w-4 h-4\" />{{ $t('editor.close') }}\n </DialogClose>\n </DialogHeader>\n\n <DialogDescription></DialogDescription>\n\n <BulkSpellCheckerContent\n :editorsState=\"editorsState\"\n :spellCheckStatus=\"spellCheckStatus\"\n :allWrongWordsMissSuggestions=\"allWrongWordsMissSuggestions\"\n @close-modal=\"isOpenModal = false\"\n @run-spellcheck=\"reRunSpellCheckAndHighlight\"\n @replace-all-editor-errors=\"(replaceAllEditorErrors(), (isOpenModal = false))\"\n />\n </div>\n </DialogContent>\n </Dialog>\n</template>\n\n<style scoped></style>\n"],"names":["ERROR_TYPE","SPELL_CHECK_CODE","SPELL_CHECK_STATUS","EDITOR_NAME","ArrowLeftRight","createLucideIcon","CircleAlert","CircleCheck","expanded","ref","showButton","helpRef","toggle","onMounted","nextTick","HIGHLIGHT_KEY","PluginKey","createHighlightPlugin","editor","errors","blockSeparator","Plugin","state","decos","errorColorMap","item","from","findDocPosFromOffset","to","errorType","_b","_a","className","safeFrom","safeTo","Decoration","DecorationSet","applyHighlights","plugin","clearHighlights","buildPlainIndexToDocPosMap","map","plainIndex","firstBlock","node","pos","i","nodeName","k","offset","mapped","standardMaxHeight","props","__props","getErrorColor","getNoSuggestionText","_d","_c","resetHightlightSection","key","scrollToError","mid","maybeNode","el","replaceWithCorrectWord","replacement","tr","delta","origStart","origEnd","err","idx","contentEl","maxHeight","windowHeight","useWindowSize","computeMaxHeight","gap","rect","availableViewportHeight","useEventListener","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_component_SpinnerIcon","emit","__emit","useBulkSpellCheckerStore","editorsState","reactive","setEditor","editorKey","editorInstance","spellCheckStatus","resetAllEditorWrongWords","editorState","evaluateStatus","hasFail","hasError","handleRunSpellCheck","apiUrl","ext","content","response","axios","error","countTotalWrongWords","computed","sum","wrongWords","watch","newVal","allWrongWordsMissSuggestions","allWrongWords","es","w","applyAllEditorHighlightErrors","_","clearAllEditorHighlightErrors","reRunSpellCheckAndHighlight","isEnableCurrent","disableSpellCheckRealTime","isEnableSpellCheckRealTime","SPELLCHECKER_META_LIST","resetEnableSpellCheckRealTime","replaceAllErrors","getMappedPos","validRepls","r","a","b","lastAppliedFrom","appliedItems","e","replaceAllEditorErrors","isOpenModal","dragOffset","dragging","onMouseDown","onMouseMove","onMouseUp","onUnmounted","triggerRef","position","updatePosition","val","bulkSpellCheckerBtnConfig"],"mappings":"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","x_google_ignoreList":[1,2,3]}
1
+ {"version":3,"file":"BulkSpellChecker-IKxccUeP.mjs","sources":["../src/constants/bulkSpellChecker.ts","../node_modules/lucide-vue-next/dist/esm/icons/arrow-left-right.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-alert.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-check.js","../src/components/BulkSpellCheckerHelpText.vue","../src/utils/bulkSpellchecker.ts","../src/components/BulkSpellCheckerWrongWordList.vue","../src/components/ui/SpinnerIcon.vue","../src/components/BulkSpellCheckerLoading.vue","../src/components/BulkSpellCheckerContent.vue","../src/hooks/useBulkSpellCheckerStore.ts","../src/components/ui/dialog/DialogTrigger.vue","../src/components/BulkSpellChecker.vue"],"sourcesContent":["export const ERROR_TYPE = {\n SPACING: 1,\n SPELLING: 2,\n}\n\nexport const SPELL_CHECK_CODE = {\n NOTHING_TO_CHANGE: 'NOTHING_TO_CHANGE',\n} as const\n\nexport const SPELL_CHECK_STATUS = {\n LOADING: 'loading',\n HAS_ERROR: 'hasError',\n NO_ERROR: 'noError',\n FAIL: 'fail',\n} as const\n\nexport type SpellCheckStatus = (typeof SPELL_CHECK_STATUS)[keyof typeof SPELL_CHECK_STATUS]\n\nexport const EDITOR_NAME = {\n EDITOR_COMMENT: 'editorComment',\n EDITOR_CONTENT: 'editorContent',\n} as const\n\nexport type EditorName = (typeof EDITOR_NAME)[keyof typeof EDITOR_NAME]\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ArrowLeftRight = createLucideIcon(\"ArrowLeftRightIcon\", [\n [\"path\", { d: \"M8 3 4 7l4 4\", key: \"9rb6wj\" }],\n [\"path\", { d: \"M4 7h16\", key: \"6tx8e3\" }],\n [\"path\", { d: \"m16 21 4-4-4-4\", key: \"siv7j2\" }],\n [\"path\", { d: \"M20 17H4\", key: \"h6l3hr\" }]\n]);\n\nexport { ArrowLeftRight as default };\n//# sourceMappingURL=arrow-left-right.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleAlert = createLucideIcon(\"CircleAlertIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n]);\n\nexport { CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheck = createLucideIcon(\"CircleCheckIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n]);\n\nexport { CircleCheck as default };\n//# sourceMappingURL=circle-check.js.map\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\nimport { ChevronDown } from 'lucide-vue-next'\n\ninterface Props {\n text: string\n}\nconst props = defineProps<Props>()\n\nconst expanded = ref(false)\nconst showButton = ref(false)\nconst helpRef = ref<HTMLElement | null>(null)\n\nfunction toggle() {\n expanded.value = !expanded.value\n}\n\nonMounted(async () => {\n await nextTick()\n if (helpRef.value && helpRef.value.scrollHeight > 32) {\n showButton.value = true\n }\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div\n ref=\"helpRef\"\n class=\"text-gray-700 dark:text-gray-400 transition-all\"\n :class=\"expanded ? 'max-h-none' : 'max-h-[32px] overflow-hidden'\"\n v-html=\"text\"\n ></div>\n\n <div\n v-if=\"showButton\"\n class=\"\"\n :class=\"\n cn(\n 'w-32 flex items-end justify-end bg-gradient-to-l from-white via-white to-transparent dark:from-ed-background dark:via-ed-background',\n expanded ? 'ml-auto opacity-60' : 'absolute bottom-0 right-0'\n )\n \"\n >\n <button class=\"flex items-center gap-1\" @click.stop=\"toggle\">\n <span class=\"border-b border-gray-500\">{{ expanded ? '접기' : '자세히' }}</span>\n <ChevronDown class=\"w-4 h-4 transition-transform\" :class=\"expanded ? 'rotate-180' : ''\" />\n </button>\n </div>\n </div>\n</template>\n","import { ERROR_TYPE } from '@/constants'\nimport { WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport { Plugin, PluginKey } from 'prosemirror-state'\nimport { Decoration, DecorationSet } from 'prosemirror-view'\n\nconst HIGHLIGHT_KEY = new PluginKey('bulk-spellcheck-highlight')\n\nfunction createHighlightPlugin(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n return new Plugin({\n key: HIGHLIGHT_KEY,\n props: {\n decorations(state) {\n const decos: Decoration[] = []\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bulk-highlight text-blue-500 border-b-2 border-blue-500',\n [ERROR_TYPE.SPELLING]: 'bulk-highlight text-red-500 border-b-2 border-red-500',\n }\n\n errors.forEach(item => {\n const from = findDocPosFromOffset(editor, item.startIndex, blockSeparator)\n const to = findDocPosFromOffset(editor, item.endIndex - 1, blockSeparator) + 1\n\n const errorType = item.errorHelpDtos?.[0]?.errorType\n const className = errorColorMap[errorType ?? -1] || 'bulk-highlight text-green-500 border-b-2 border-green-500' // type integrated\n\n const safeFrom = Math.max(0, Math.min(from, state.doc.content.size))\n const safeTo = Math.max(0, Math.min(to, state.doc.content.size))\n if (safeFrom < safeTo) {\n decos.push(Decoration.inline(safeFrom, safeTo, { class: className }))\n }\n })\n\n return DecorationSet.create(state.doc, decos)\n },\n },\n })\n}\n\nexport function applyHighlights(editor: Editor, errors: WrongWordItem[]) {\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n\n if (!errors.length) return\n\n const plugin = createHighlightPlugin(editor, errors)\n editor.registerPlugin(plugin)\n}\n\nexport function clearHighlights(editor: Editor) {\n if (!editor) return\n\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n}\n\nexport function buildPlainIndexToDocPosMap(editor: Editor, blockSeparator = '\\n') {\n const map: (number | null)[] = []\n let plainIndex = 0\n let firstBlock = true\n\n editor.state.doc.descendants((node, pos) => {\n if (node.isText && node.text) {\n for (let i = 0; i < node.text.length; i++) {\n map[plainIndex++] = pos + i\n }\n }\n\n const nodeName = node.type && (node.type as any).name\n const isHardBreak = nodeName === 'hardBreak' || nodeName === 'hard_break' || nodeName === 'br'\n if (isHardBreak && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos\n }\n }\n\n if (node.isBlock) {\n if (!firstBlock && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos \n }\n }\n firstBlock = false\n }\n\n return true\n })\n\n return map\n}\n\nexport function findDocPosFromOffset(editor: Editor,offset: number, blockSeparator = '\\n') {\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n if (offset < 0) offset = 0\n if (offset >= map.length) {\n return editor.state.doc.content.size\n }\n const mapped = map[offset]\n if (mapped == null) {\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n return mapped as number\n}\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME, EditorName, ERROR_TYPE } from '@/constants'\nimport { ArrowLeftRight } from 'lucide-vue-next'\nimport { Editor } from '@tiptap/core'\nimport { EditorsState, WrongWordItem } from '@/type'\nimport { applyHighlights, findDocPosFromOffset } from '@/utils/bulkSpellchecker'\n\ninterface Props {\n editorsState: EditorsState\n}\nconst props = defineProps<Props>()\n\nfunction getErrorColor(errorType?: number) {\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bg-blue-500',\n [ERROR_TYPE.SPELLING]: 'bg-red-500',\n }\n return errorColorMap[errorType ?? -1] || 'bg-green-500' // integrated\n}\n\nfunction getNoSuggestionText(editor: Editor) {\n return editor?.extensionStorage?.spellchecker?.spellchecker?.uiStrings?.uiStrings || 'No suggestions found'\n}\n\nfunction resetHightlightSection(key: EditorName) {\n if (key === EDITOR_NAME.EDITOR_COMMENT) {\n props.editorsState[EDITOR_NAME.EDITOR_CONTENT].editor?.commands.setTextSelection(0)\n return\n }\n\n if (key === EDITOR_NAME.EDITOR_CONTENT) {\n props.editorsState[EDITOR_NAME.EDITOR_COMMENT].editor?.commands.setTextSelection(0)\n return\n }\n}\n\nfunction scrollToError(key: EditorName, editor: Editor, item: WrongWordItem) {\n if (!editor) return\n\n resetHightlightSection(key)\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n editor.chain().setTextSelection({ from, to }).focus().run()\n\n const mid = Math.max(0, Math.floor((from + to) / 2))\n const domAtPos = editor.view.domAtPos(mid)\n const maybeNode = domAtPos.node as unknown\n\n let el: HTMLElement | null = null\n\n if (maybeNode instanceof Element) {\n el = maybeNode as HTMLElement\n } else if (maybeNode instanceof Text) {\n el = maybeNode.parentElement\n } else {\n el = (maybeNode as any)?.parentElement ?? (editor.view.dom as HTMLElement)\n }\n\n if (el?.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth', block: 'center' })\n }\n}\n\nfunction replaceWithCorrectWord(editor: Editor, errors: WrongWordItem[], item: WrongWordItem, replacement: string) {\n if (!editor) return\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n const tr = editor.state.tr.insertText(replacement, from, to)\n editor.view.dispatch(tr)\n editor.view.focus()\n\n const delta = replacement.length - (item.wrongWord?.length ?? 0)\n const origStart = item.startIndex\n const origEnd = item.endIndex\n\n for (let i = errors.length - 1; i >= 0; i--) {\n const err = errors[i]\n\n if (err.startIndex >= origStart && err.startIndex < origEnd) {\n errors.splice(i, 1)\n continue\n }\n\n if (err.startIndex > origStart) {\n err.startIndex += delta\n err.endIndex += delta\n }\n }\n\n const idx = errors.indexOf(item)\n if (idx !== -1) errors.splice(idx, 1)\n\n applyHighlights(editor, errors)\n}\n\nconst contentEl = ref<HTMLElement | null>(null)\nconst standardMaxHeight = 450\nconst maxHeight = ref(standardMaxHeight)\nconst { height: windowHeight } = useWindowSize()\n\nfunction computeMaxHeight() {\n const el = contentEl.value\n if (!el) return\n\n const gap = 80\n const rect = el.getBoundingClientRect()\n const availableViewportHeight = windowHeight.value - rect.top - gap\n\n maxHeight.value = standardMaxHeight > availableViewportHeight ? availableViewportHeight : standardMaxHeight\n}\n\nonMounted(() => {\n computeMaxHeight()\n useEventListener(window, 'resize', computeMaxHeight)\n})\n</script>\n\n<template>\n <div ref=\"contentEl\" :style=\"{ maxHeight: `${maxHeight}px` }\" class=\"pr-1 overflow-y-auto\">\n <template v-for=\"(editorData, key) in editorsState\" :key=\"key\">\n <div\n v-for=\"(item, idx) in editorData.wrongWords\"\n :key=\"idx\"\n class=\"border-b border-gray-100 dark:border-ed-muted pb-5 mb-5 cursor-pointer\"\n @click=\"scrollToError(key, editorsState[key].editor as Editor, item)\"\n >\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">입력 내용</span>\n <div class=\"flex items-center gap-2\">\n <span class=\"w-1.5 h-1.5 rounded-full\" :class=\"getErrorColor(item.errorHelpDtos[0]?.errorType)\"></span>\n <span class=\"break-all whitespace-normal\">{{ item.wrongWord }}</span>\n </div>\n </div>\n\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">대치어</span>\n <div v-if=\"item.correctWord.length\" class=\"flex-1 space-y-1\">\n <div\n v-for=\"(sub, sidx) in item.correctWord\"\n :key=\"sidx\"\n class=\"font-semibold px-3 py-1.5 rounded bg-gray-100 dark:bg-ed-muted flex items-center justify-between\"\n >\n <div class=\"text-sm\">\n {{ sub }}\n </div>\n <button\n class=\"flex items-center gap-1 text-blue-500\"\n @click.stop=\"replaceWithCorrectWord(editorData.editor as Editor, editorData.wrongWords, item, sub)\"\n >\n <ArrowLeftRight class=\"w-4 h-4\" /> <span>바꾸기</span>\n </button>\n </div>\n </div>\n <div v-else>\n {{ getNoSuggestionText(editorData.editor as Editor) }}\n </div>\n </div>\n\n <div class=\"flex\">\n <span class=\"w-16 font-medium\">도움말</span>\n <div class=\"flex-1\">\n <BulkSpellCheckerHelpText :text=\"item.errorHelpDtos[0]?.errorMessage\" />\n </div>\n </div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\n\ninterface Props {\n fillWhite?: boolean\n class?: string\n}\nconst props = withDefaults(defineProps<Props>(), {\n fillWhite: false,\n class: '',\n})\n</script>\n\n<template>\n <svg :class=\"cn('animate-spin h-5 w-5 mr-0.5', props.class)\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle\n v-if=\"fillWhite\"\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n fill=\"#ffffff\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <circle v-else class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path\n class=\"opacity-100\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</template>\n\n<style scoped></style>\n","<template>\n <div class=\"min-h-[188px] flex flex-col items-center justify-center gap-y-2 text-sm\">\n <SpinnerIcon fill-white class=\"h-10 w-10 text-blue-500\" />\n <div>맞춤법 검사 중입니다</div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { cn } from '@/utils'\nimport { EditorsState } from '@/type'\n\ninterface Props {\n editorsState: EditorsState,\n spellCheckStatus: SpellCheckStatus\n allWrongWordsMissSuggestions: boolean\n}\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'close-modal'): void\n (e: 'run-spellcheck'): void\n (e: 'replace-all-editor-errors'): void\n}>()\n</script>\n\n<template>\n <div class=\"text-xs py-4 px-6\">\n <BulkSpellCheckerLoading v-if=\"spellCheckStatus === SPELL_CHECK_STATUS.LOADING\" />\n <BulkSpellCheckerWrongWordList v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.HAS_ERROR\" :editorsState=\"editorsState\" />\n <BulkSpellCheckerNotWrongWord v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.NO_ERROR\" />\n <BulkSpellCheckerFail v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.FAIL\" />\n\n <div class=\"flex items-center justify-between mt-3\">\n <ul class=\"flex items-cente gap-x-4\">\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-red-500\"></span>맞춤법</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-blue-500\"></span>띄어쓰기</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-green-500\"></span>통합교정</li>\n </ul>\n\n <div class=\"flex gap-x-1\">\n <Button\n variant=\"outline\"\n :class=\"\n cn(\n 'border-blue-500 text-blue-500 text-xs px-3 py-2 h-auto hover:bg-white/80 hover:opacity-80 hover:text-blue-500 dark:text-dark-blue-100 dark:hover:bg-dark-blue-400 dark:hover:text-dark-blue-50 dark:hover:border-dark-blue-100',\n spellCheckStatus === SPELL_CHECK_STATUS.LOADING &&\n 'text-gray-300 bg-gray-100 border-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:border-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('run-spellcheck')\"\n >다시 검사하기</Button\n >\n\n <Button\n :class=\"\n cn(\n 'border-blue-500 text-white text-xs px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80',\n (spellCheckStatus !== SPELL_CHECK_STATUS.HAS_ERROR || allWrongWordsMissSuggestions) &&\n 'text-gray-300 bg-gray-100 hover:bg-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('replace-all-editor-errors')\"\n >모두 바꾸기</Button\n >\n </div>\n </div>\n </div>\n</template>\n","import { EDITOR_NAME, EditorName, SPELL_CHECK_CODE, SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { EditorsState, SpellCheckResponse, WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport axios from 'axios'\nimport { applyHighlights, clearHighlights, buildPlainIndexToDocPosMap } from '@/utils/bulkSpellchecker'\nimport { SPELLCHECKER_META_LIST } from '@/extensions/SpellChecker/spellchecker-extension'\n\nexport const useBulkSpellCheckerStore = () => {\n const editorsState: EditorsState = reactive({\n [EDITOR_NAME.EDITOR_COMMENT]: {\n editor: null,\n wrongWords: [],\n },\n [EDITOR_NAME.EDITOR_CONTENT]: {\n editor: null,\n wrongWords: [],\n },\n })\n\n function setEditor(editorKey: EditorName, editorInstance: Editor | null) {\n editorsState[editorKey].editor = editorInstance\n }\n\n const spellCheckStatus = ref<SpellCheckStatus>(SPELL_CHECK_STATUS.NO_ERROR)\n\n function resetAllEditorWrongWords() {\n Object.values(editorsState).forEach(editorState => {\n editorState.wrongWords = []\n })\n }\n\n function evaluateStatus(hasFail: boolean, hasError: boolean) {\n if (hasFail) return SPELL_CHECK_STATUS.FAIL\n if (hasError) return SPELL_CHECK_STATUS.HAS_ERROR\n return SPELL_CHECK_STATUS.NO_ERROR\n }\n\n async function handleRunSpellCheck() {\n spellCheckStatus.value = SPELL_CHECK_STATUS.LOADING\n\n let hasError = false\n let hasFail = false\n\n for (const [editorKey, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n\n const apiUrl = editor?.extensionManager.extensions.find(ext => ext.name === 'spellchecker')?.options.proofreader\n .api\n const content = editor.getText({ blockSeparator: '\\n' })\n if (!apiUrl || !content) continue\n\n try {\n const { data: response } = await axios.post<SpellCheckResponse>(apiUrl, {\n value: content,\n })\n\n if (!response.success && response.code !== SPELL_CHECK_CODE.NOTHING_TO_CHANGE) {\n hasFail = true\n editorsState[editorKey].wrongWords = []\n continue\n }\n\n if (response.data?.wrongWordResponseDto) {\n hasError = true\n editorsState[editorKey].wrongWords = response.data.wrongWordResponseDto\n continue\n }\n\n editorsState[editorKey].wrongWords = []\n } catch (error) {\n console.error('handleRunSpellCheck error: ', error)\n hasFail = true\n }\n }\n\n spellCheckStatus.value = evaluateStatus(hasFail, hasError)\n }\n\n const countTotalWrongWords = computed(() => {\n return Object.values(editorsState).reduce((sum, { wrongWords }) => {\n return sum + wrongWords.length\n }, 0)\n })\n\n watch(countTotalWrongWords, newVal => {\n if (newVal === 0) {\n spellCheckStatus.value = evaluateStatus(false, false)\n }\n })\n\n const allWrongWordsMissSuggestions = computed(() => {\n const allWrongWords = Object.values(editorsState).flatMap(es => es.wrongWords)\n if (allWrongWords.length === 0) return false\n return allWrongWords.every(w => !Array.isArray(w.correctWord) || w.correctWord.length === 0)\n })\n\n function applyAllEditorHighlightErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n applyHighlights(editor as Editor, wrongWords)\n }\n }\n\n function clearAllEditorHighlightErrors() {\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n clearHighlights(editor as Editor)\n }\n }\n\n async function reRunSpellCheckAndHighlight() {\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n }\n\n let isEnableCurrent = true\n function disableSpellCheckRealTime(isEnableSpellCheckRealTime: boolean) {\n isEnableCurrent = isEnableSpellCheckRealTime\n if (!isEnableSpellCheckRealTime) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(false)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, false))\n }\n }\n\n function resetEnableSpellCheckRealTime() {\n if (!isEnableCurrent) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(true)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, true))\n }\n }\n\n function replaceAllErrors(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n if (!editor) return\n if (!errors.length) return\n\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n\n function getMappedPos(offset: number) {\n if (offset < 0) offset = 0\n if (offset >= map.length) return editor.state.doc.content.size\n if (map[offset] != null) return map[offset] as number\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n\n const replacements = errors.map(item => {\n const from = getMappedPos(item.startIndex)\n const to = getMappedPos(Math.max(0, item.endIndex - 1)) + 1\n const replacement = item.correctWord?.[0] ?? item.wrongWord\n return { item, from, to, replacement }\n })\n\n const validRepls = replacements.filter(r => typeof r.from === 'number' && typeof r.to === 'number' && r.from < r.to)\n\n if (!validRepls.length) return\n\n validRepls.sort((a, b) => b.from - a.from)\n\n const tr = editor.state.tr\n let lastAppliedFrom = Number.POSITIVE_INFINITY\n const appliedItems = new Set<WrongWordItem>()\n\n for (const r of validRepls) {\n if (r.to > lastAppliedFrom) {\n continue\n }\n\n tr.insertText(r.replacement, r.from, r.to)\n\n appliedItems.add(r.item)\n lastAppliedFrom = r.from\n }\n\n if (appliedItems.size > 0) {\n editor.view.dispatch(tr)\n editor.view.focus()\n }\n\n if (appliedItems.size > 0) {\n errors = errors.filter(e => ![...appliedItems].some(a => a === e))\n }\n\n applyHighlights(editor, errors)\n }\n\n function replaceAllEditorErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n replaceAllErrors(editor as Editor, wrongWords)\n }\n }\n\n return {\n editorsState,\n spellCheckStatus,\n countTotalWrongWords,\n allWrongWordsMissSuggestions,\n setEditor,\n resetAllEditorWrongWords,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n handleRunSpellCheck,\n replaceAllEditorErrors,\n }\n}\n","<script setup lang=\"ts\">\nimport { DialogTrigger, type DialogTriggerProps } from 'radix-vue'\n\nconst props = defineProps<DialogTriggerProps>()\n</script>\n\n<template>\n <DialogTrigger v-bind=\"props\">\n <slot />\n </DialogTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME } from '@/constants'\nimport { useBulkSpellCheckerStore } from '@/hooks/useBulkSpellCheckerStore'\nimport { Editor } from '@tiptap/core'\nimport { DialogTrigger } from './ui/dialog'\n\ninterface Props {\n editor: Editor\n editorComment?: Editor\n isEnableSpellCheckRealTime: boolean\n}\nconst props = defineProps<Props>()\n\nconst {\n editorsState,\n countTotalWrongWords,\n spellCheckStatus,\n allWrongWordsMissSuggestions,\n setEditor,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n handleRunSpellCheck,\n resetAllEditorWrongWords,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n replaceAllEditorErrors,\n} = useBulkSpellCheckerStore()\n\nconst isOpenModal = ref(false)\n\nconst dragOffset = reactive({ x: 0, y: 0 })\nconst dragging = ref(false)\nconst offset = { x: 0, y: 0 }\n\nconst onMouseDown = (e: MouseEvent) => {\n dragging.value = true\n offset.x = e.clientX - dragOffset.x\n offset.y = e.clientY - dragOffset.y\n document.addEventListener('mousemove', onMouseMove)\n document.addEventListener('mouseup', onMouseUp)\n}\n\nconst onMouseMove = (e: MouseEvent) => {\n if (!dragging.value) return\n dragOffset.x = e.clientX - offset.x\n dragOffset.y = e.clientY - offset.y\n}\n\nconst onMouseUp = () => {\n dragging.value = false\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n}\n\nonUnmounted(() => {\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n})\n\nconst triggerRef = ref<InstanceType<typeof DialogTrigger> | null>(null)\nconst position = ref({ top: 0, right: 0 })\n\nconst updatePosition = () => {\n if (triggerRef.value) {\n const rect = triggerRef.value.$el.getBoundingClientRect()\n\n position.value = {\n top: rect.bottom + window.scrollY + 5,\n right: window.innerWidth - rect.right - window.scrollX,\n }\n\n dragOffset.x = 0\n dragOffset.y = 0\n }\n}\n\nonMounted(async () => {\n if (props.editorComment) {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, props.editorComment)\n }\n setEditor(EDITOR_NAME.EDITOR_CONTENT, props.editor)\n})\n\nonUnmounted(() => {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, null)\n setEditor(EDITOR_NAME.EDITOR_CONTENT, null)\n})\n\nwatch(isOpenModal, async val => {\n if (val) {\n await nextTick()\n updatePosition()\n disableSpellCheckRealTime(props.isEnableSpellCheckRealTime)\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n } else {\n resetAllEditorWrongWords()\n resetEnableSpellCheckRealTime()\n clearAllEditorHighlightErrors()\n }\n})\n\nconst bulkSpellCheckerBtnConfig = props.editor?.extensionManager.extensions.find(e => e.name === 'spellchecker')\n ?.options.bulkSpellCheckerButton\n</script>\n\n<template>\n <Dialog :open=\"isOpenModal\">\n <DialogTrigger as-child ref=\"triggerRef\" @click=\"isOpenModal = !isOpenModal\">\n <button\n v-if=\"!bulkSpellCheckerBtnConfig\"\n class=\"border-blue-500 text-white text-xs text-nowrap px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80 flex items-center rounded\"\n >\n <Icon name=\"checkUnderline\" />맞춤법 일괄 교정\n </button>\n\n <component\n v-else\n :is=\"bulkSpellCheckerBtnConfig.component\"\n :buttonName=\"bulkSpellCheckerBtnConfig.props.buttonName\"\n :icon=\"bulkSpellCheckerBtnConfig.props.icon\"\n :type=\"bulkSpellCheckerBtnConfig.props.type\"\n :disabled=\"bulkSpellCheckerBtnConfig.props.disabled\"\n :iconPosition=\"bulkSpellCheckerBtnConfig.props.iconPosition\"\n :buttonSize=\"bulkSpellCheckerBtnConfig.props.buttonSize\"\n :iconClass=\"bulkSpellCheckerBtnConfig.props.iconClass\"\n />\n </DialogTrigger>\n\n <DialogContent is-overlay-transparent class=\"p-0 gap-0 !animate-none !transition-none dark:border-ed-muted\" as-child>\n <div\n class=\"z-[70]\"\n :style=\"{\n transform: `translate(${dragOffset.x}px, ${dragOffset.y}px)`,\n top: `${position.top}px`,\n right: `${position.right}px`,\n left: 'auto',\n }\"\n >\n <DialogHeader\n class=\"bg-ed-blue-light py-3.5 px-6 rounded-t-[5px] cursor-move text-blue-500 dark:text-dark-blue-100 flex-row items-center justify-between\"\n @mousedown.prevent=\"onMouseDown\"\n >\n <DialogTitle class=\"text-base space-x-2\">\n <span>맞춤법/문법 오류</span>\n <Badge class=\"text-sm bg-blue-500 hover:bg-blue-500 dark:bg-dark-blue-100 px-2\">{{ countTotalWrongWords }}개</Badge></DialogTitle\n >\n\n <DialogClose @click=\"isOpenModal = false\" class=\"text-xs flex items-center gap-x-1\">\n <Icon name=\"Close\" class=\"w-4 h-4\" />{{ $t('editor.close') }}\n </DialogClose>\n </DialogHeader>\n\n <DialogDescription></DialogDescription>\n\n <BulkSpellCheckerContent\n :editorsState=\"editorsState\"\n :spellCheckStatus=\"spellCheckStatus\"\n :allWrongWordsMissSuggestions=\"allWrongWordsMissSuggestions\"\n @close-modal=\"isOpenModal = false\"\n @run-spellcheck=\"reRunSpellCheckAndHighlight\"\n @replace-all-editor-errors=\"(replaceAllEditorErrors(), (isOpenModal = false))\"\n />\n </div>\n </DialogContent>\n </Dialog>\n</template>\n\n<style scoped></style>\n"],"names":["ERROR_TYPE","SPELL_CHECK_CODE","SPELL_CHECK_STATUS","EDITOR_NAME","ArrowLeftRight","createLucideIcon","CircleAlert","CircleCheck","expanded","ref","showButton","helpRef","toggle","onMounted","nextTick","HIGHLIGHT_KEY","PluginKey","createHighlightPlugin","editor","errors","blockSeparator","Plugin","state","decos","errorColorMap","item","from","findDocPosFromOffset","to","errorType","_b","_a","className","safeFrom","safeTo","Decoration","DecorationSet","applyHighlights","plugin","clearHighlights","buildPlainIndexToDocPosMap","map","plainIndex","firstBlock","node","pos","i","nodeName","k","offset","mapped","standardMaxHeight","props","__props","getErrorColor","getNoSuggestionText","_d","_c","resetHightlightSection","key","scrollToError","mid","maybeNode","el","replaceWithCorrectWord","replacement","tr","delta","origStart","origEnd","err","idx","contentEl","maxHeight","windowHeight","useWindowSize","computeMaxHeight","gap","rect","availableViewportHeight","useEventListener","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_component_SpinnerIcon","emit","__emit","useBulkSpellCheckerStore","editorsState","reactive","setEditor","editorKey","editorInstance","spellCheckStatus","resetAllEditorWrongWords","editorState","evaluateStatus","hasFail","hasError","handleRunSpellCheck","apiUrl","ext","content","response","axios","error","countTotalWrongWords","computed","sum","wrongWords","watch","newVal","allWrongWordsMissSuggestions","allWrongWords","es","w","applyAllEditorHighlightErrors","_","clearAllEditorHighlightErrors","reRunSpellCheckAndHighlight","isEnableCurrent","disableSpellCheckRealTime","isEnableSpellCheckRealTime","SPELLCHECKER_META_LIST","resetEnableSpellCheckRealTime","replaceAllErrors","getMappedPos","validRepls","r","a","b","lastAppliedFrom","appliedItems","e","replaceAllEditorErrors","isOpenModal","dragOffset","dragging","onMouseDown","onMouseMove","onMouseUp","onUnmounted","triggerRef","position","updatePosition","val","bulkSpellCheckerBtnConfig"],"mappings":"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","x_google_ignoreList":[1,2,3]}
@@ -31679,7 +31679,7 @@ const XK = { class: "flex gap-2 items-center overflow-x-auto overflow-y-hidden [
31679
31679
  mode: {}
31680
31680
  },
31681
31681
  setup(t) {
31682
- const e = sR(() => import("./BulkSpellChecker-Er4di3gp.mjs")), { t: n } = Jt(), o = t, r = Gt("isEditable", H(!0)), i = ["fontSize", "fontFamily", "superText", "spellchecker", "fontSizeIncreaseDecrease"], s = Y(() => {
31682
+ const e = sR(() => import("./BulkSpellChecker-IKxccUeP.mjs")), { t: n } = Jt(), o = t, r = Gt("isEditable", H(!0)), i = ["fontSize", "fontFamily", "superText", "spellchecker", "fontSizeIncreaseDecrease"], s = Y(() => {
31683
31683
  const f = [...o.editor.extensionManager.extensions].sort((m, b) => m.name === "superText" ? 1 : b.name === "superText" ? -1 : 0);
31684
31684
  let h = [];
31685
31685
  for (const m of f) {
@@ -52762,64 +52762,64 @@ const vse = { class: "flex items-center h-[32px] hover:bg-ed-muted rounded-md" }
52762
52762
  }
52763
52763
  return !0;
52764
52764
  }), I && t && t.view.dispatch($), k !== -1 && (n.value[k].text = T, n.value[k].textOriginal = T);
52765
- }, l = () => {
52765
+ }, l = H(/* @__PURE__ */ new Map()), u = () => {
52766
52766
  if (!(t != null && t.view.dom)) return [];
52767
52767
  const T = [], k = t == null ? void 0 : t.view.dom.querySelectorAll("[node-id]"), A = /* @__PURE__ */ new Map();
52768
- return k.forEach((B) => {
52768
+ return l.value.clear(), k.forEach((B) => {
52769
52769
  const $ = B.getBoundingClientRect().top;
52770
- A.set($, B);
52770
+ A.set($, B), l.value.set(B.getAttribute("node-id") || "unknown", 0);
52771
52771
  }), T.push(...A.values()), T;
52772
- }, u = (T) => {
52772
+ }, d = (T) => {
52773
52773
  const k = T.closest(`#${o}`);
52774
52774
  if (!k) return;
52775
52775
  const A = k.getBoundingClientRect().top, B = k == null ? void 0 : k.scrollTop;
52776
52776
  return T.getBoundingClientRect().top - (A - B);
52777
- }, d = (T, k) => {
52777
+ }, f = (T, k) => {
52778
52778
  const A = n.value.findIndex((B) => B.id === T);
52779
52779
  A > -1 && (n.value[A].status = k);
52780
- }, f = (T) => T.replace(/<p><\/p>/g, "<p>&nbsp;</p>"), h = H(/* @__PURE__ */ new Map()), m = () => {
52780
+ }, h = (T) => T.replace(/<p><\/p>/g, "<p>&nbsp;</p>"), m = () => {
52781
52781
  if (!n.value || n.value.length === 0) {
52782
- i.value = 0, h.value.clear();
52782
+ i.value = 0, l.value.clear();
52783
52783
  return;
52784
52784
  }
52785
52785
  if (!r.value || r.value.length === 0)
52786
52786
  return;
52787
- const T = r.value, k = new Set(n.value.map(($) => $.id));
52788
- for (const $ of h.value.keys())
52789
- k.has($) || h.value.delete($);
52790
- const A = T.map(($) => ({
52787
+ const T = r.value, k = new Set(n.value.map(($) => $.id)), A = T.map(($) => ({
52791
52788
  isHidden: $.classList.contains("hidden"),
52792
52789
  isTruncated: $.classList.contains("super-text-truncate")
52793
52790
  }));
52794
52791
  T.forEach(($) => {
52795
52792
  $.classList.remove("hidden"), $.classList.remove("super-text-truncate");
52796
- }), T.forEach(($) => {
52793
+ });
52794
+ for (const $ of l.value.keys())
52795
+ k.has($) || l.value.delete($);
52796
+ T.forEach(($) => {
52797
52797
  const I = $.getAttribute("book-mark-id");
52798
52798
  if (!I) return;
52799
- const j = $.offsetTop + $.offsetHeight, J = h.value.get(I) || 0;
52800
- h.value.set(I, Math.max(j, J));
52799
+ const j = $.offsetTop + $.offsetHeight, J = l.value.get(I) || 0;
52800
+ l.value.set(I, Math.max(j, J));
52801
52801
  }), T.forEach(($, I) => {
52802
52802
  A[I].isHidden && $.classList.add("hidden"), A[I].isTruncated && $.classList.add("super-text-truncate");
52803
52803
  });
52804
52804
  let B = 0;
52805
- for (const $ of h.value.values())
52805
+ for (const $ of l.value.values())
52806
52806
  $ > B && (B = $);
52807
52807
  i.value = B;
52808
52808
  }, b = async () => {
52809
52809
  await Rt();
52810
- const k = l().map((A) => {
52810
+ const k = u().map((A) => {
52811
52811
  const B = A.getAttribute("node-id"), $ = A.getAttribute("book-mark-content"), I = A.getAttribute("page-id"), j = A.getAttribute("page-number"), J = A.getBoundingClientRect(), oe = A.getAttribute("line-id"), be = A.getAttribute("element-id");
52812
52812
  return {
52813
52813
  position: J,
52814
- text: f($),
52814
+ text: h($),
52815
52815
  id: B,
52816
52816
  pageId: I,
52817
52817
  pageNumber: j,
52818
- visiblePosition: u(A),
52818
+ visiblePosition: d(A),
52819
52819
  status: 0,
52820
52820
  lineId: oe,
52821
52821
  elementId: be,
52822
- textOriginal: f($)
52822
+ textOriginal: h($)
52823
52823
  };
52824
52824
  });
52825
52825
  n.value = k;
@@ -52829,7 +52829,11 @@ const vse = { class: "flex items-center h-[32px] hover:bg-ed-muted rounded-md" }
52829
52829
  };
52830
52830
  async function x() {
52831
52831
  const T = r.value;
52832
- !T || T.length === 0 || (T.sort((k, A) => {
52832
+ if (!T || T.length === 0) {
52833
+ m();
52834
+ return;
52835
+ }
52836
+ T.sort((k, A) => {
52833
52837
  const B = Number(k.getAttribute("index")), $ = Number(A.getAttribute("index"));
52834
52838
  return B - $;
52835
52839
  }), T.forEach((k) => k.classList.remove("super-text-truncate")), T.forEach((k, A) => {
@@ -52838,7 +52842,7 @@ const vse = { class: "flex items-center h-[32px] hover:bg-ed-muted rounded-md" }
52838
52842
  const I = $.getBoundingClientRect();
52839
52843
  y(B, I) && k.classList.add("super-text-truncate");
52840
52844
  });
52841
- }), m());
52845
+ }), m();
52842
52846
  }
52843
52847
  const w = async (T) => {
52844
52848
  await Rt();
@@ -52854,7 +52858,7 @@ const vse = { class: "flex items-center h-[32px] hover:bg-ed-muted rounded-md" }
52854
52858
  A.querySelector(".super-text-lines").innerHTML = n.value[B].textOriginal, r.value.forEach((I) => I.classList.remove("hidden")), x();
52855
52859
  return;
52856
52860
  }
52857
- A.querySelector(".super-text-lines").innerHTML = f(T.text), A.classList.remove("super-text-truncate");
52861
+ A.querySelector(".super-text-lines").innerHTML = h(T.text), A.classList.remove("super-text-truncate");
52858
52862
  const $ = A.getBoundingClientRect();
52859
52863
  r.value.forEach((I, j) => {
52860
52864
  if (j !== B) {
@@ -52868,7 +52872,7 @@ const vse = { class: "flex items-center h-[32px] hover:bg-ed-muted rounded-md" }
52868
52872
  w(T.payload);
52869
52873
  break;
52870
52874
  case "status":
52871
- d(T.payload.id, T.payload.status);
52875
+ f(T.payload.id, T.payload.status);
52872
52876
  break;
52873
52877
  case "render":
52874
52878
  b();
@@ -56802,4 +56806,4 @@ export {
56802
56806
  Sae as y,
56803
56807
  yae as z
56804
56808
  };
56805
- //# sourceMappingURL=index-CT6L-cic.mjs.map
56809
+ //# sourceMappingURL=index-DgdZsemB.mjs.map