xref: /plugin/diagrams/script/DiagramsForm.js (revision 3d6886fdda1da3668e853a389b1500cbdfc63619)
1class DiagramsForm extends KeyValueForm {
2
3    /** {DiagramsView} The view of the currently selected node */
4    #view = null;
5
6    constructor(name = 'diagrams-form', fields = []) {
7        if (fields.length === 0) {
8            fields = [
9                {
10                    label: LANG.plugins.diagrams.mediaSource, name: 'src'
11                },
12                {
13                    type: 'select', 'label': LANG.plugins.diagrams.alignment, 'options':
14                        [
15                            {name: 'alignment', value: '', label: ''},
16                            {name: 'alignment', value: 'left', label: LANG.plugins.diagrams.left},
17                            {name: 'alignment', value: 'right', label: LANG.plugins.diagrams.right},
18                            {name: 'alignment', value: 'center', label: LANG.plugins.diagrams.center}
19                        ]
20                }
21            ];
22        }
23
24        super(name, fields);
25
26        this.$form.on('submit', (event) => {
27            event.preventDefault(); // prevent form submission
28            this.updateViewFromForm();
29            this.#view.deselectNode();
30        });
31
32        if (!this.instance) {
33            // media manager button
34            const selectButton = document.createElement('button');
35            selectButton.innerText = LANG.plugins.diagrams.selectSource;
36            selectButton.className = 'diagrams-btn-select';
37            selectButton.addEventListener('click', DiagramsForm.openMediaManager);
38            this.$form.find('fieldset').prepend(selectButton);
39            window.dMediaSelect = this.mediaSelect.bind(this);
40
41            // editor button
42            const editButton = document.createElement('button');
43            editButton.className = 'diagrams-btn-edit';
44            editButton.id = 'diagrams__btn-edit';
45            editButton.innerText = LANG.plugins.diagrams.editButton;
46            this.$form.find('fieldset').prepend(editButton);
47
48            editButton.addEventListener('click', event => {
49                event.preventDefault(); // prevent form submission
50
51                const url = this.#view.node.attrs.url;
52                const mediaid = this.#view.node.attrs.id;
53
54                if(this.#view.node.attrs.type === 'mediafile') {
55                    const diagramsEditor = new DiagramsEditor(this.onSavedMediaFile.bind(this, url));
56                    diagramsEditor.editMediaFile(mediaid);
57                } else {
58                    const diagramsEditor = new DiagramsEditor();
59                    diagramsEditor.editMemory(url, this.onSaveEmbed.bind(this));
60                }
61
62            });
63        }
64
65        return this.instance;
66    }
67
68    /**
69     * Update the form to reflect the new selected nodeView
70     *
71     * @param {DiagramsView} view
72     */
73    updateFormFromView(view) {
74        this.#view = view;
75
76        // update form fields to reflect new node
77
78        this.$form.find('[name="src"]').val(view.node.attrs.id);
79
80        // this.dForm.setWidth(view.node.attrs.width);
81        // this.dForm.setHeight(view.node.attrs.height);
82
83
84        const align = view.node.attrs.align;
85        this.$form.find('[name="alignment"]').prop('selected', '');
86        this.$form.find(`[name="alignment"][value="${align}"]`).prop('selected', 'selected');
87    }
88
89    updateViewFromForm() {
90        const newAttrs = this.getAttributes();
91        console.log('updateViewFromForm', newAttrs);
92        this.#view.dispatchNodeUpdate(newAttrs);
93    }
94
95    getAttributes() {
96        const attrs = {};
97        attrs.id = this.$form.find('[name="src"]').val();
98        attrs.align = this.$form.find('[name="alignment"]:selected').val();
99        attrs.type = this.#view.node.attrs.type;
100
101        // fixme this is only correct for media files
102        if(this.#view.node.attrs.type === 'embed') {
103            attrs.url = this.#view.node.attrs.url; // keep the data uri
104        } else {
105            attrs.url = `${DOKU_BASE}lib/exe/fetch.php?cache=nocache&media=` + attrs.id;
106        }
107        return attrs;
108    }
109
110
111    /**
112     * After svaing a media file reload the src for all images using it
113     *
114     * @see https://stackoverflow.com/a/66312176
115     * @param {string} url
116     * @returns {Promise<void>}
117     */
118    async onSavedMediaFile(url) {
119        await fetch(url, {cache: 'reload', mode: 'no-cors'});
120        document.body.querySelectorAll(`img[src='${url}']`)
121            .forEach(img => img.src = url)
122    }
123
124    /**
125     * Save an embedded diagram back to the editor
126     */
127    onSaveEmbed(svg) {
128        // FIXME how do we update the diagram?
129        const url = 'data:image/svg+xml;base64,' + btoa(svg);
130
131        this.#view.node.attrs.url = url;
132        this.updateViewFromForm();
133
134        return true;
135    }
136
137    setEditButtonUrl(id, url) {
138        const $editButton = jQuery(this.$form.find('#diagrams__btn-edit'));
139        // FIXME show/hide button depending on set url
140        $editButton.attr('data-id', id);
141        $editButton.attr('data-url', url);
142    }
143
144    setSource(id = '') {
145        this.$form.find('[name="src"]').val(id);
146    }
147
148    getSource() {
149        return this.$form.find('[name="src"]').val();
150    }
151
152    setAlignment(align = '') {
153    }
154
155    getAlignment() {
156        return this.$form.find('[name="alignment"]:checked').val();
157    }
158
159    resetForm() {
160        this.setSource();
161        this.setAlignment();
162    }
163
164    static resolveSubmittedLinkData(initialAttrs, $diagramsForm, callback) {
165        return (event) => {
166            event.preventDefault();
167            const newAttrs = { ...initialAttrs };
168            newAttrs.id = $diagramsForm.getSource();
169            // FIXME is this conditional?
170            newAttrs.url = `${DOKU_BASE}lib/exe/fetch.php?cache=nocache&media=` + $diagramsForm.getSource();
171            newAttrs.align = $diagramsForm.getAlignment();
172
173            callback(newAttrs);
174        };
175    }
176
177    static openMediaManager() {
178        window.open(
179            `${DOKU_BASE}lib/exe/mediamanager.php?ns=${encodeURIComponent(JSINFO.namespace)}&onselect=dMediaSelect`,
180            'mediaselect',
181            'width=750,height=500,left=20,top=20,scrollbars=yes,resizable=yes',
182        );
183    }
184
185    mediaSelect(edid, mediaid, opts, align) {
186        this.setSource(mediaid);
187    }
188}
189