~sirn/fanboi2

ref: 5b482cfc1bfb0bb1e89715cb57c7bac864391768 fanboi2/assets/app/javascripts/views/popover_view.ts -rw-r--r-- 2.8 KiB
5b482cfcKridsada Thanabulpong 0.30.0 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import {VNode, h} from 'virtual-dom';


export class PopoverView {
    popoverChildNodes: VNode[];

    constructor(childNode: VNode, title?: string, dismissFn?: (() => void)) {
        this.popoverChildNodes = PopoverView.renderChild(
            childNode,
            title,
            dismissFn,
        );
    }

    render(targetElement: Element, args: any = {}): VNode {
        let pos = PopoverView.computePosition(targetElement);

        return h('div', PopoverView.getViewClassName(args), [
            h('div', {
                className: 'js-popover-inner',
                style: {
                    position: 'absolute',
                    top: `${pos.posX}px`,
                    left: `${pos.posY}px`,
                }
            }, this.popoverChildNodes)
        ]);
    }

    private static renderChild(
        childNode: VNode,
        title?: string,
        dismissFn?: (() => void)
    ): VNode[] {
        let popoverChildNodes: VNode[] = [];

        if (title) {
            let titleChildNodes = [
                h('span', {
                    className: 'js-popover-inner-title-label'
                }, [title])
            ];

            if (dismissFn) {
                titleChildNodes.push(h('a', {
                    className: 'js-popover-inner-title-dismiss',
                    href: '#',
                    onclick: (e: Event): void => {
                        e.preventDefault();
                        if (dismissFn) {
                            dismissFn();
                        }
                    },
                }, ['Close']));
            }

            popoverChildNodes.push(h('div', {
                className: 'js-popover-inner-title',
            }, titleChildNodes));
        }

        popoverChildNodes.push(childNode);
        return popoverChildNodes;
    }

    private static computePosition(targetElement: Element): {
        posX: number,
        posY: number
    } {
        let bodyRect = document.body.getBoundingClientRect();
        let elemRect = targetElement.getBoundingClientRect();
        let yRefRect = elemRect;

        // Indent relative to container rather than element if there is
        // container in element ancestor.
        let containerElement = targetElement.closest('.container');
        if (containerElement) {
            yRefRect = containerElement.getBoundingClientRect();
        }

        return {
            posX: (elemRect.bottom + 5) - bodyRect.top,
            posY: yRefRect.left - bodyRect.left,
        }
    }

    private static getViewClassName(args: any): any {
        const className = 'js-popover';

        if (args.className) {
            let classNames = args.className.split(' ');
            classNames.push(className);
            args.className = classNames.join(' ');
        } else {
            args.className = className;
        }

        return args;
    }
}