|
3 | 3 | </template> |
4 | 4 |
|
5 | 5 | <script lang="ts"> |
6 | | -import { highlight } from 'highlight.js' |
7 | 6 | import { defineComponent, ref, onMounted, watch } from 'vue' |
8 | | -import { MODIFIED_START_TAG, MODIFIED_CLOSE_TAG } from './utils' |
9 | | -
|
10 | | -import type { Ref } from 'vue' |
11 | | -
|
12 | | -/** |
13 | | - * Set hightlight code |
14 | | - * This function must calling at client only (use DOM) |
15 | | - */ |
16 | | -const setHighlightCode = ({ highlightCode, language, code }: { highlightCode: Ref; language: string; code: string }) => { |
17 | | - const hasModifiedTags = code.match(new RegExp(`(${MODIFIED_START_TAG}|${MODIFIED_CLOSE_TAG})`, 'g')) |
18 | | -
|
19 | | - if (!hasModifiedTags) { |
20 | | - highlightCode.value = highlight(language, code).value |
21 | | - return |
22 | | - } |
23 | | -
|
24 | | - /** |
25 | | - * Explore highlight DOM extracted from pure code and compare the text with the original code code to generate the highlight code |
26 | | - */ |
27 | | - let originalCode = code // original code with modified tags |
28 | | - const pureCode = code.replace(new RegExp(`(${MODIFIED_START_TAG}|${MODIFIED_CLOSE_TAG})`, 'g'), '') // Without modified tags |
29 | | - let pureElement = document.createElement('div') |
30 | | - pureElement.innerHTML = highlight(language, pureCode).value // Highlight DOM without modified tags |
31 | | -
|
32 | | - const diffElements = (node: HTMLElement) => { |
33 | | - node.childNodes.forEach(child => { |
34 | | - if (child.nodeType === 1) { |
35 | | - diffElements(child as HTMLElement) |
36 | | - } |
37 | | -
|
38 | | - // Compare text nodes and check changed text |
39 | | - if (child.nodeType === 3) { |
40 | | - if (!child.textContent) return |
41 | | -
|
42 | | - let oldContent = child.textContent |
43 | | - let newContent = '' |
44 | | -
|
45 | | - while (oldContent.length) { |
46 | | - if (originalCode.startsWith(MODIFIED_START_TAG)) { // Add modified start tag |
47 | | - originalCode = originalCode.slice(MODIFIED_START_TAG.length) |
48 | | - newContent = newContent + MODIFIED_START_TAG |
49 | | - continue |
50 | | - } |
51 | | - if (originalCode.startsWith(MODIFIED_CLOSE_TAG)) { // Add modified close tag |
52 | | - originalCode = originalCode.slice(MODIFIED_CLOSE_TAG.length) |
53 | | - newContent = newContent + MODIFIED_CLOSE_TAG |
54 | | - continue |
55 | | - } |
56 | | -
|
57 | | - // Add words before modified tag |
58 | | - const hasModifiedTag = originalCode.match(new RegExp(`(${MODIFIED_START_TAG}|${MODIFIED_CLOSE_TAG})`)) |
59 | | - const originalCodeDiffLength = hasModifiedTag && hasModifiedTag.index ? hasModifiedTag.index : originalCode.length |
60 | | - const nextDiffsLength = Math.min(originalCodeDiffLength, oldContent.length) |
61 | | -
|
62 | | - newContent = newContent + originalCode.substring(0, nextDiffsLength) |
63 | | - originalCode = originalCode.slice(nextDiffsLength) |
64 | | - oldContent = oldContent.slice(nextDiffsLength) |
65 | | - } |
66 | | -
|
67 | | - child.textContent = newContent // put as entity code because change textContent |
68 | | - } |
69 | | - }) |
70 | | - } |
71 | | - diffElements(pureElement) |
72 | | -
|
73 | | - const startEntity = MODIFIED_START_TAG.replace('<', '<').replace('>', '>') |
74 | | - const closeEntity = MODIFIED_CLOSE_TAG.replace('<', '<').replace('>', '>') |
75 | | -
|
76 | | - highlightCode.value = pureElement.innerHTML |
77 | | - .replace(new RegExp(startEntity, 'g'), '<span class="modified">') |
78 | | - .replace(new RegExp(closeEntity, 'g'), '</span>') |
79 | | -
|
80 | | - // @ts-ignore |
81 | | - pureElement = null |
82 | | -} |
| 7 | +import { setHighlightCode } from './utils' |
83 | 8 |
|
84 | 9 | export default defineComponent({ |
85 | 10 | props: { |
|
0 commit comments