aboutsummaryrefslogtreecommitdiff
path: root/static/components/popup-element.ts
blob: 42e8ee7ffe9183435794469b3e050ee870b16208 (plain)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
export { PopupElement }

import { VEvent } from '../vevent'
import { bind_popup_control } from '../dragable'
import { close_popup, event_from_popup } from '../popup'
import { vcal_objects } from '../globals'

import { ComponentVEvent } from './vevent'

import { remove_event } from '../server_connect'

/* <popup-element /> */
class PopupElement extends ComponentVEvent {

    constructor(uid?: string) {
        super(uid);

        /* TODO populate remaining (??) */

        let obj = vcal_objects.get(this.uid);
        if (obj && obj.calendar) {
            this.dataset.calendar = obj.calendar;
        }
    }

    redraw(data: VEvent) {
        if (data.calendar) {
            /* The CSS has hooks on [data-calendar], meaning that this can
               (and will) change stuff */
            this.dataset.calendar = data.calendar;
        }

    }

    connectedCallback() {
        let template = document.getElementById('popup-template') as HTMLTemplateElement
        let body = (template.content.cloneNode(true) as DocumentFragment).firstElementChild!;

        let uid = this.uid;

        /* nav bar */
        let nav = body.getElementsByClassName("popup-control")[0] as HTMLElement;
        bind_popup_control(nav);

        let close_btn = body.querySelector('.popup-control .close-button') as HTMLButtonElement
        close_btn.addEventListener('click', () => close_popup(this));

        let maximize_btn = body.querySelector('.popup-control .maximize-button') as HTMLButtonElement
        maximize_btn.addEventListener('click', () => {
            /* TODO this assumes that popups are direct decendant of their parent,
               which they really ought to be */
            let parent = this.parentElement!;
            let el = this.firstElementChild as HTMLElement
            /* TODO offsetParent.scrollLeft places us "fullscreen" according to the currently
               scrolled viewport. But is this the correct way to do it? How does it work for
               month views */
            this.style.left = `${this.offsetParent!.scrollLeft + 10}px`;
            this.style.top = '10px';
            /* 5ex is width of tab labels */
            el.style.width = `calc(${parent.clientWidth - 20}px - 5ex)`
            el.style.height = `${parent.clientHeight - 20}px`
        });

        let remove_btn = body.querySelector('.popup-control .remove-button') as HTMLButtonElement
        remove_btn.addEventListener('click', () => remove_event(uid));
        /* end nav bar */

        this.replaceChildren(body);
    }

    static get observedAttributes() {
        return ['visible'];
    }

    attributeChangedCallback(name: string, oldValue?: string, newValue?: string) {
        switch (name) {
            case 'visible':
                this.onVisibilityChange()
                break;
        }
    }

    get visible(): boolean {
        return this.hasAttribute('visible');
    }

    set visible(isVisible: boolean) {
        if (isVisible) {
            this.setAttribute('visible', 'visible');
        } else {
            this.removeAttribute('visible');
        }
    }

    private onVisibilityChange() {

        /* TODO better way to find root */
        let root;
        switch (window.VIEW) {
            case 'week':
                root = document.getElementsByClassName("days")[0];
                break;
            case 'month':
            default:
                root = document.body;
                break;
        }

        let element = event_from_popup(this) as HTMLElement;
        /* start <X, Y> sets offset between top left corner
           of event in calendar and popup. 10, 10 soo old
           event is still visible */
        let offsetX = 10, offsetY = 10;
        while (element !== root && element !== null) {
            offsetX += element.offsetLeft;
            offsetY += element.offsetTop;
            element = element.offsetParent as HTMLElement;
        }
        this.style.left = offsetX + "px";
        this.style.top = offsetY + "px";

        /* Reset width and height to initial, to save user if they have resized
        it to something weird */
        let el = this.firstElementChild as HTMLElement;
        el.style.removeProperty('width');
        el.style.removeProperty('height');
    }
}