1
import isEqual from 'lodash/isEqual'
2

3
import { fromEvent, Observable } from 'rxjs'
4

5
import { distinctUntilChanged, filter, map } from 'rxjs/operators'
6

7
import { Position } from '@sourcegraph/extension-api-types'
8

9
import { Characters, Token } from './characters'
10
import { propertyIsDefined } from './utils/types'
11

12
export type SupportedMouseEvents = 'mousemove' | 'click'
13

14 1
const mouseEventTypes: SupportedMouseEvents[] = ['mousemove', 'click']
15

16
export interface PositionEvent extends Position {
17
    /** The token the event occured at. */
18
    token: Token | null
19
    /** The original event. */
20
    event: MouseEvent
21
    /* The type of event. */
22
    eventType: SupportedMouseEvents
23
}
24

25 1
const fromMouseEvent = (element: HTMLElement, eventType: SupportedMouseEvents) =>
26 1
    fromEvent<MouseEvent>(element, eventType)
27

28
export interface PositionsProps {
29
    /**
30
     * Gets the element containing
31
     *
32
     * @param
33
     */
34
    getCodeElementFromTarget: (target: HTMLElement) => HTMLElement | null
35
    getCodeElementFromLineNumber: (blob: HTMLElement, line: number) => HTMLElement | null
36
    getLineNumberFromCodeElement: (target: HTMLElement) => number
37
}
38

39
export function findPositionsFromEvents(
40 1
    props: PositionsProps
41
): (source: Observable<HTMLElement>) => Observable<PositionEvent> {
42 1
    return elements =>
43 1
        new Observable(observer => {
44 1
            const addEventListener = (element: HTMLElement, eventType: SupportedMouseEvents, characters: Characters) =>
45 1
                observer.add(
46
                    fromMouseEvent(element, eventType)
47
                        .pipe(
48 1
                            map(event => ({
49
                                event,
50
                                elem: props.getCodeElementFromTarget(event.target as HTMLElement),
51
                            })),
52
                            filter(propertyIsDefined('elem')),
53 1
                            map(({ event, elem }) => {
54 1
                                const { token, character } = characters.getToken(elem, event)
55

56 1
                                return {
57
                                    event,
58
                                    line: props.getLineNumberFromCodeElement(elem),
59
                                    character,
60
                                    token,
61
                                }
62
                            }),
63 1
                            distinctUntilChanged((a, b) => a.line === b.line && isEqual(a.token, b.token))
64
                        )
65
                        .subscribe(({ event, token, line, character }) =>
66 1
                            observer.next({
67
                                line,
68
                                character,
69
                                token,
70
                                event,
71
                                eventType,
72
                            })
73
                        )
74
                )
75

76 1
            elements.subscribe(element => {
77 1
                const firstCell = props.getCodeElementFromLineNumber(element, 0)
78 1
                if (!firstCell) {
79 1
                    observer.error(new Error('Cannot create annotator for element with no rows'))
80 1
                    return
81
                }
82

83 1
                const characters = new Characters(firstCell)
84

85 1
                for (const eventType of mouseEventTypes) {
86 1
                    addEventListener(element, eventType, characters)
87
                }
88
            })
89
        })
90
}

Read our documentation on viewing source code .

Loading