1/*  DokuWiki MoaiEditor Layout_desktop.js file
2    Version : 0.5a (May 6, 2026)
3    Author  : MoaiTools <info@moaitools.org>
4    License : GPL 3 (http://www.gnu.org/licenses/gpl.html) */
5
6/*  Desktop layout class
7    ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
8    This class handles the desktop layout.
9
10    Layout
11    ‾‾‾‾‾‾
12    body                            --
13      #moaied__wrapper              -- Semitransparent overlay
14        #moaied__tplsidebar         -- Container for editor (and optionally the template sidebar as well)
15        #moaied__editor             -- Container for the editor itself
16
17       ┌─ #moaied__wrapper           ┌─ #moaied__editor
18       │                             │
19    ┌──┴──┏━━━━━━┓┏━━━━━━━━━━━━━━━━━━┴━━━━━━┓─────┐
20    │/ / /┃      ┃┃                         ┃/ / /│
21    │/ / /┃      ┃┃                         ┃/ / /│
22    │/ / /┃      ┃┃                         ┃/ / /│
23    │/ / /┃      ┃┃                         ┃/ / /│
24    │/ / /┃      ┃┃                         ┃/ / /│
25    │/ / /┃      ┃┃                         ┃/ / /│
26    │/ / /┃      ┃┃                         ┃/ / /│
27    │/ / /┃      ┃┃                         ┃/ / /│
28    │/ / /┃      ┃┃                         ┃/ / /│
29    │/ / /┃      ┃┃                         ┃/ / /│
30    └─────┗━━━┬━━┛┗━━━━━━━━━━━━━━━━━━━━━━━━━┛─────┘
3132              └─ #moaied__tplsidebar (the template's sidebar)
33*/
34MoaiEditor.LayoutDesktop = class {
35
36    constructor(layout) {
37
38        // Arguments
39        this.layout = layout;
40
41        // Settings
42        this.settings = {
43            default: { show_edit_summary:false, show_optional_buttons:false}
44        };
45        // Variables
46        this.show_edit_summary = this.settings.default.show_edit_summary;
47        this.show_optional_buttons = this.settings.default.show_optional_buttons;
48
49    }
50    // ────────────────────────────────────
51    deactivate () {
52        // Remove the right sidebar from the panes container
53        this.sidebar.remove();
54        // Unhide all buttons
55        const buttons = document.querySelectorAll(".moaied-button");
56        for (let button of buttons)
57            button.classList.remove('moaied-display-none');
58        // Remove editor padding
59        this.layout.editor.style.paddingLeft = '';
60        this.layout.editor.style.paddingRight = '';
61        // Unhide edit summary
62        this.show_edit_summary = true;
63        this.setEditSummaryVisibility();
64    }
65    // ────────────────────────────────────
66    activate () {
67
68        // Handles
69        const editor = this.layout.editor;
70        const elements = this.layout.elements;
71
72        // Editor layout
73        this.row1         = moaiEditor.createHTML('<div id="moaied__row1"></div>');             // Page location, MoaiEditor buttons
74        this.row2         = moaiEditor.createHTML('<div id="moaied__row2"></div>');             // Toolbar buttons, edit-summary input fields
75        this.paneswrapper = moaiEditor.createHTML('<div id="moaied__panes_wrapper"></div>');    // This div allows us to scroll the panes horizontally in single pane view
76        this.footer       = moaiEditor.createHTML('<div id="moaied__footer"></div>');           // Footer row
77        editor.appendChild(this.row1);
78        editor.appendChild(this.layout.msgarea);
79        editor.appendChild(this.row2);
80        editor.appendChild(this.paneswrapper);
81        editor.appendChild(this.footer);
82        editor.appendChild(this.layout.indicatorScrolling);
83        this.paneswrapper.appendChild(this.layout.panes);
84
85        // Setup Dokuwiki page-tools (currently we are not showing it but someone might want it back in the future)
86        //this.setupPageTools();
87
88        // ──────────────── Row 1 ────────────────────
89
90        // Left, center and right
91        this.topleft = moaiEditor.createHTML('<div id="moaied__topleft"></div>');           // Back button and document id
92        this.toc = moaiEditor.toc.container;                                                // Table of contents
93        this.toc.classList.remove('phone');
94        this.buttons = moaiEditor.createHTML('<div id="moaied__buttons"></div>');           // Editor buttons
95        this.row1.appendChild(this.topleft);
96        this.row1.appendChild(this.toc);
97        this.row1.appendChild(this.buttons);
98
99        // Back button
100        this.topleft.appendChild(moaiEditor.buttons.back.handle);
101
102        // Page id
103        this.topleft.appendChild(this.layout.pageid);
104
105        // Editor buttons
106        var names = [
107            'preview',
108            'livepreview',
109            'partialpreview',
110            'autoscroll',
111            'sep',
112            'divider_moveleft',
113            'divider_moveright',
114            'panes',
115            'sep',
116            'settings',
117            'fullwidth',
118            'enabled',
119            'sep',
120            'save',
121            'cancel',
122        ];
123        this.layout.addButtons (this.buttons, names);
124
125        // ──────────────── Row 2 ────────────────────
126
127        // Left and right
128        this.row2left = moaiEditor.createHTML('<div id="moaied__row2_left" class="moaied-second-to-shrink"></div>');
129        this.row2right = moaiEditor.createHTML('<div id="moaied__row2_right" class="moaied-first-to-shrink"></div>');
130        this.row2.appendChild(this.row2left);
131        this.row2.appendChild(this.row2right);
132
133        // Default Dokuwiki toolbar
134        this.toolbar = elements.toolbar;
135        this.row2left.appendChild(this.toolbar);
136
137
138        // Edit summary
139        this.row2right.appendChild(this.layout.summary);
140
141        // ──────────────── Side ────────────────────
142
143        // Sidebar buttons
144        this.btn_options = this.layout.createSidebarButton ('options', 'More options', this.toggleButtonsVisibility.bind(this) );
145        this.btn_scrollhrz = this.layout.createSidebarButton ('arrowhrz', 'Toggle preview', this.toggleHorizontalScroll.bind(this) );
146        this.btn_editsummary = this.layout.createSidebarButton ('summary', 'Edit summary', this.toggleEditSummaryVisibility.bind(this) );
147
148        // Sidebar
149        this.sidebar = moaiEditor.createHTML('<div id="moaied__sidebar"></div>');    // Sidebar with buttons (on the right)
150        this.row2.appendChild(this.sidebar);
151        this.sidebar.appendChild(this.btn_options);
152        this.sidebar.appendChild(this.btn_scrollhrz);
153        this.sidebar.appendChild(this.btn_editsummary);
154        this.sidebar.appendChild(this.layout.btn_editor);
155        this.sidebar.appendChild(this.layout.btn_linewrap);
156        this.sidebar.appendChild(this.layout.btn_fullscreen);
157        this.sidebar.appendChild(this.layout.btn_scrolltop);
158        this.sidebar.appendChild(this.layout.btn_scrollbottom);
159
160        // Bottom right container (for logo, codemirror menu, etc)
161        this.footer.appendChild(this.layout.bottomRight);
162
163        // ──────────────── Footer ────────────────────
164
165        // Footer
166        this.footerLeft = moaiEditor.createHTML('<div id="moaied__footer_left"></div>');
167        this.docinfo = moaiEditor.createHTML('<div id="moaied__docinfo">&nbsp;</div>');
168        this.footer.appendChild(this.footerLeft);
169        this.footer.appendChild(this.docinfo);
170
171        // Docinfo (will not exist when creating a document)
172        const data = JSINFO.plugin_moaieditor.docinfo;
173        if (data !== null) {
174            const path = '<span>'+data.labelPath+':&nbsp;&nbsp;'+data.path+'</span>';
175            const mod  = '<span>'+data.labelMod+'&nbsp;&nbsp;'+data.time+'&nbsp;&nbsp;'+data.by+'</span>';
176            this.docinfo.innerHTML = path + '&nbsp;&nbsp;·&nbsp;&nbsp;' + mod;
177        }
178        // ────────────────── Hints ─────────────────────
179
180        this.hint_scrollhrz_btn = new MoaiEditor.Hint('arrow-right', 'Click me', this.btn_scrollhrz, 40, 2);
181        this.hint_scrollhrz_bar = new MoaiEditor.Hint('arrow-corner-left-down', 'Drag the scroll bar', this.footer, 200, 52);
182
183        // ────────────── Other things ──────────────────
184
185        this.updatePanesLayout();               // Update the panes layout (side-by-side, top-bottom, single-pane)
186        this.setButtonsVisibility();            // Hide or show the optional buttons at the top
187        this.setEditSummaryVisibility();        // Hide or show the edit summary input fields
188        moaiEditor.buttons.updateDivider();     // Update the panel divider position
189    }
190    // ────────────────────────────────────
191    onClickPanesBtn() {
192        const mode = moaiEditor.buttons.panes.mode;
193        // Show or hide hints
194        this.hint_scrollhrz_btn.disable();
195        this.hint_scrollhrz_bar.disable();
196        if (mode == 'single') {
197            this.hint_scrollhrz_btn.start();
198            this.hint_scrollhrz_bar.start();
199        }
200        // Update the layout
201        this.updatePanesLayout();
202    }
203    // ────────────────────────────────────
204    updatePanesLayout() {
205
206        // Handles
207        const mode = moaiEditor.buttons.panes.mode;
208        const wrapper = document.body.querySelector('#moaied__panes_wrapper');
209        const panes = document.body.querySelector('#moaied__panes');
210        const btn_moveleft = moaiEditor.buttons.divider_moveleft;
211        const btn_moveright = moaiEditor.buttons.divider_moveright;
212
213        // Set single or dual pane layout
214        if (wrapper) {
215            wrapper.classList.remove('moaied-single-pane');
216            if (mode == 'single')
217                wrapper.classList.add('moaied-single-pane');
218        }
219        // In dual pane layout, adjust the orientation of the panes (side-by-side, top-bottom) by controlling 'flex-direction'
220        if (panes) {
221            panes.classList.remove('column');
222            if (mode == 'column')
223                panes.classList.add('column');
224        }
225        // Update the icons of the divider adjustment buttons (to show the correct layout)
226        if (mode != 'single') {
227            btn_moveleft.mode = mode;
228            btn_moveright.mode = mode;
229        }
230        // In single pane layout
231        btn_moveleft.handle.classList.remove('moaied-display-none-secondary');
232        btn_moveright.handle.classList.remove('moaied-display-none-secondary');
233        this.btn_scrollhrz.classList.add('moaied-display-none');
234        if (mode == 'single') {
235            // Hide the divider adjustment buttons (as they are not needed)
236            btn_moveleft.handle.classList.add('moaied-display-none-secondary');
237            btn_moveright.handle.classList.add('moaied-display-none-secondary');
238            // Show the horizontal scroll toggle button (to toggle between editor and preview panes)
239            this.btn_scrollhrz.classList.remove('moaied-display-none');
240        }
241        // Set the maximum width depending on user settings and full-width button
242        const userSettings = JSINFO.plugin_moaieditor;
243        var maxwidth;
244        if (mode == 'row')
245            maxwidth = userSettings.editor_width_side_by_side;
246        if (mode == 'column')
247            maxwidth = userSettings.editor_width_top_bottom;
248        if (mode == 'single')
249            maxwidth = userSettings.editor_width_single_pane;
250        if (moaiEditor.buttons.fullwidth.mode == 'on')
251            maxwidth = 'none';
252        this.layout.editor.style.maxWidth = maxwidth;
253        //console.warn(JSINFO.plugin_moaieditor);
254    }
255    // ────────────────────────────────────
256    toggleHorizontalScroll() {
257        // Toggle between editor and preview pane in single pane layout mode (horizontal scroll)
258        const scroll = this.paneswrapper.scrollLeft;
259        const maxScroll = moaiEditor.scroll.tools.getMaxScrollX (this.paneswrapper);
260        const threshold = maxScroll / 2;
261        if (scroll > threshold)
262            this.paneswrapper.scrollLeft = 0;
263        else
264            this.paneswrapper.scrollLeft = maxScroll+10;
265    }
266    // ────────────────────────────────────
267    toggleButtonsVisibility() {
268        // Show or hide additional buttons at the top of the editor (blue and green buttons)
269        this.show_optional_buttons = !this.show_optional_buttons;
270        this.setButtonsVisibility();
271    }
272    setButtonsVisibility() {
273        // Hide or show the optional buttons at the top of the editor
274        const show = this.show_optional_buttons;
275        var element;
276        var names = [
277            'livepreview',
278            'partialpreview',
279            'autoscroll',
280            'settings',
281            /*'enabled',
282            3*/
283        ];
284        for (let name of names) {
285            if (typeof name === 'string')
286                element = moaiEditor.buttons[name].handle;
287             else
288                element = document.getElementById('moaied__sep_'+name);
289            if (show)
290                element.classList.remove('moaied-display-none');
291            else
292                element.classList.add('moaied-display-none');
293        }
294    }
295    // ────────────────────────────────────
296    toggleEditSummaryVisibility() {
297        // Show or hide the edit-summary input fields (because many users don't use this feature)
298        this.show_edit_summary = !this.show_edit_summary;
299        this.setEditSummaryVisibility();
300    }
301    setEditSummaryVisibility() {
302        const summary = this.layout.summary;
303        if (this.show_edit_summary)
304            summary.classList.remove('moaied-display-none');
305        else
306            summary.classList.add('moaied-display-none');
307    }
308    // ────────────────────────────────────
309    onWindowResize() {
310        this.adjustPaddings();
311    }
312    // ────────────────────────────────────
313    adjustPaddings() {
314        //
315        var w = window.innerWidth;
316        var h = window.innerHeight;
317        // Horizontal padding
318        var left = 10;
319        var right = 40;
320        if (w > 1200) {
321            let extra = (w-1200)/40;
322            left += extra;
323            right += extra*.65;
324        }
325        this.layout.editor.style.paddingLeft = left + 'px';
326        this.layout.editor.style.paddingRight = right + 'px';
327
328    }
329}; // End Class
330
331
332