1
import githubCode from '../../testcases/generated/github.html'
2
import sourcegraphCode from '../../testcases/generated/sourcegraph.html'
3

4
import { PositionsProps } from '../positions_events'
5

6 1
const createElementFromString = (html: string): HTMLElement => {
7 1
    const elem = document.createElement('div')
8

9 1
    elem.innerHTML = html
10 1
    elem.style.height = 'auto'
11 1
    elem.style.width = 'auto'
12 1
    elem.style.whiteSpace = 'pre'
13 1
    elem.style.cssFloat = 'left'
14 1
    elem.style.display = 'block'
15 1
    elem.style.clear = 'both'
16

17 1
    return elem
18
}
19

20 1
export const getCharacterWidthInContainer = (container: HTMLElement, character: string, idx: number): number => {
21 1
    const span = document.createElement('span')
22 1
    span.innerHTML = character
23 1
    span.dataset.char = idx + ''
24 1
    span.dataset.charCode = character.charCodeAt(0) + ''
25 1
    span.style.visibility = 'hidden'
26 1
    span.style.cssFloat = 'left'
27 1
    span.style.height = '0'
28

29 1
    container.appendChild(span)
30 1
    const width = span.getBoundingClientRect().width
31 1
    container.removeChild(span)
32

33 1
    return width
34
}
35

36
export type BlobProps = Pick<
37
    PositionsProps,
38
    'getCodeElementFromTarget' | 'getCodeElementFromLineNumber' | 'getLineNumberFromCodeElement'
39
> & { insertRow: (text: string) => HTMLElement; element: HTMLElement }
40

41 1
export const wrapCharsInSpans = (line: string) =>
42 1
    Array.from(line)
43 1
        .map((c, j) => `<span data-char="${j}">${c}</span>`)
44
        .join('')
45

46 1
const createGitHubBlob = (): BlobProps => {
47 1
    const blob = document.createElement('div')
48

49 1
    blob.innerHTML = githubCode
50 1
    blob.style.clear = 'both'
51

52 1
    const getCodeElementFromTarget = (target: HTMLElement): HTMLElement | null => {
53 1
        const row = target.closest('tr')
54 1
        if (!row) {
55 1
            return null
56
        }
57

58 1
        const codeCell = row.children.item(1) as HTMLElement
59

60 1
        return codeCell
61
    }
62

63 1
    const getCodeElementFromLineNumber = (b: HTMLElement, line: number): HTMLElement | null => {
64 1
        const numCell = b.querySelector(`[data-line-number="${line + 1}"]`)
65 1
        if (!numCell) {
66 1
            return null
67
        }
68

69 1
        const row = numCell.closest('tr')
70

71 1
        return row!.children.item(1) as HTMLElement | null
72
    }
73

74 1
    const getLineNumberFromCodeElement = (codeCell: HTMLElement): number => {
75 1
        const row = codeCell.closest('tr')
76 1
        if (!row) {
77 1
            return -1
78
        }
79 1
        const numCell = row.children.item(0) as HTMLElement
80

81 1
        return parseInt(numCell.dataset.lineNumber as string, 10) - 1
82
    }
83

84 1
    return {
85
        element: blob,
86
        getCodeElementFromTarget,
87
        getCodeElementFromLineNumber,
88
        getLineNumberFromCodeElement,
89 1
        insertRow: (text: string) => {
90 1
            const lastRow = blob.querySelector('tbody tr:last-of-type')!
91

92 1
            const node = lastRow.cloneNode(true) as HTMLElement
93 1
            const line = parseInt((lastRow.children.item(0) as HTMLElement).dataset.lineNumber as string, 10) + 1
94

95 1
            const lineNode = node.children.item(0)! as HTMLElement
96 1
            lineNode.id = `L${line}`
97 1
            lineNode.dataset.lineNumber = line.toString()
98

99 1
            const codeNode = node.children.item(1)! as HTMLElement
100 1
            codeNode.id = `LC${line}`
101 1
            codeNode.innerHTML = wrapCharsInSpans(text)
102

103 1
            blob.querySelector('tbody')!.appendChild(node)
104

105 1
            return node
106
        },
107
    }
108
}
109

110 1
const createSourcegraphBlob = (): BlobProps => {
111 1
    const blob = document.createElement('div')
112

113 1
    blob.innerHTML = sourcegraphCode
114 1
    blob.style.clear = 'both'
115

116 1
    const getCodeElementFromTarget = (target: HTMLElement): HTMLElement | null => {
117 1
        const row = target.closest('tr')
118 1
        if (!row) {
119 1
            return null
120
        }
121

122 1
        const codeCell = row.children.item(1) as HTMLElement
123

124 1
        return codeCell
125
    }
126

127 1
    const getCodeElementFromLineNumber = (b: HTMLElement, line: number): HTMLElement | null => {
128 1
        const numCell = b.querySelector(`[data-line="${line + 1}"]`)
129 1
        if (!numCell) {
130 1
            return null
131
        }
132

133 1
        const row = numCell.closest('tr')
134

135 1
        return row!.children.item(1) as HTMLElement | null
136
    }
137

138 1
    const getLineNumberFromCodeElement = (codeCell: HTMLElement): number => {
139 1
        const row = codeCell.closest('tr')
140 1
        if (!row) {
141 1
            return -1
142
        }
143

144 1
        const numCell = row.children.item(0) as HTMLElement
145

146
        // data-line - 1 because 0-based in LSP
147
        // https://sourcegraph.com/github.com/Microsoft/vscode-languageserver-node/-/blob/types/src/main.ts#L20:5
148 1
        return parseInt(numCell.dataset.line as string, 10) - 1
149
    }
150

151 1
    return {
152
        element: blob,
153
        getCodeElementFromTarget,
154
        getCodeElementFromLineNumber,
155
        getLineNumberFromCodeElement,
156 1
        insertRow: (text: string) => {
157 1
            const lastRow = blob.querySelector('tbody tr:last-of-type')!
158

159 1
            const node = lastRow.cloneNode(true) as HTMLElement
160 1
            const line = parseInt((lastRow.children.item(0) as HTMLElement).dataset.line as string, 10) + 1
161

162 1
            const lineNode = node.children.item(0)! as HTMLElement
163 1
            lineNode.dataset.line = line.toString()
164

165 1
            const codeNode = node.children.item(1)! as HTMLElement
166 1
            codeNode.innerHTML = wrapCharsInSpans(text)
167

168 1
            blob.querySelector('tbody')!.appendChild(node)
169

170 1
            return node
171
        },
172
    }
173
}
174

175 1
export class DOM {
176 1
    private nodes = new Set<Element>()
177

178 1
    public createBlobs(): BlobProps[] {
179 1
        const blobs: BlobProps[] = [createSourcegraphBlob(), createGitHubBlob()]
180

181 1
        for (const { element } of blobs) {
182 1
            this.insert(element)
183
        }
184

185 1
        return blobs
186
    }
187

188 1
    public createElementFromString(html: string): HTMLElement {
189 1
        const element = createElementFromString(html)
190 1
        this.insert(element)
191 1
        return element as HTMLElement
192
    }
193

194 1
    public cleanup = (): void => {
195 1
        for (const node of this.nodes) {
196 1
            document.body.removeChild(node)
197
        }
198
    }
199

200 1
    private insert(node: Element): void {
201 1
        document.body.appendChild(node)
202

203 1
        this.nodes.add(node)
204
    }
205
}

Read our documentation on viewing source code .

Loading