1/*  DokuWiki MoaiEditor Cm_scroll.js file
2    Version : 0.5 (May 5, 2026)
3    Author  : MoaiTools <info@moaitools.org>
4    License : GPL 3 (http://www.gnu.org/licenses/gpl.html) */
5
6/*  This class implements the 'scroll.max', 'scroll.top' and 'scroll.smooth'
7    getters and setters required for every editor.
8
9    It also updates the vertical position of currently rendered lines to make
10    sure we work with precise values. We use an interval to throttle this process.
11
12    This is needed because CodeMirror will report inaccurate line positions when
13    they have not been rendered yet. So scrolling close to that part of the document
14    is required before an accurate value can be obtained.
15
16    If not corrected, this aproximation error adds up in large documents, which
17    results in a really bad scroll synchronization in lower parts of the page.
18*/
19MoaiEditor.CodemirrorScroll = class {
20
21    constructor(outer) {
22
23        // Arguments
24        this.outer = outer;
25
26        // Variables
27        this.smoothvalue = false;
28        this.range = null;       // {from, to} or null
29
30        // Interval
31        this.interval = setInterval(this.onInterval.bind(this), 250);
32    }
33    // ────────────────────────────────────
34    get max() {
35        // Return the maximum scroll possible
36        const info = this.outer.editor.getScrollInfo();
37        const height = info.height;                 // size of the scrollable area
38        const visHeight = info.clientHeight;        // size of the visible area (minus scrollbars)
39        return Math.abs(height-visHeight);
40    }
41    get height() {
42        // Return the height of the scrollable area
43        return this.outer.editor.getScrollInfo().height;
44    }
45    // ────────────────────────────────────
46    get top() {
47        return this.outer.editor.getScrollInfo().top;
48    }
49    set top(value) {
50        this.outer.scroller.scrollTop = value;
51        //this.outer.editor.scrollTo(null, value);
52    }
53    // ────────────────────────────────────
54    get smooth() {
55        return this.smoothvalue;
56    }
57    set smooth(boolean) {
58        var value = 'auto';
59        if (boolean)
60            value = 'smooth';
61        this.smoothvalue = boolean;
62        this.outer.scroller.style.scrollBehavior = value;
63    }
64    // ────────────────────────────────────
65    onScroll() {
66        const vp = this.outer.editor.getViewport();
67        if (this.range === null)
68            this.range = {from: vp.from, to: vp.to};
69        this.range.from = Math.min(this.range.from, vp.from);
70        this.range.to   = Math.max(this.range.to, vp.to);
71        this.debugLine();
72    }
73    onInterval() {
74        if (this.range !== null)
75            moaiEditor.matches.recalcScrollPoints(this.range);
76        this.range = null;
77    }
78    // ────────────────────────────────────
79    debugLine() {
80        // Exit if debugline is not enabled
81        const line = document.querySelector("#moai__debug div:nth-child(2)");
82        if (!line) return;
83        // Debug line
84        const info = this.outer.editor.getScrollInfo();
85        const scroll = Math.floor(info.top);
86        const height = info.height;
87        const viewport = info.clientHeight;
88        const text = "scroll:"+scroll+"  h:"+height+"  vp:"+viewport+"  max:"+this.max;
89        line.textContent = text;
90    }
91
92}; // End Class
93
94