1/*  DokuWiki MoaiEditor Matches.js file
2    Author  : MoaiTools <info@moaitools.org>
3    License : GPL 3 (http://www.gnu.org/licenses/gpl.html) */
4
5MoaiEditor.Matches = class {
6
7    constructor(outer) {
8
9        // Handles
10
11        // Settings
12        this.settings = {show:{scrollpoints:false}};
13
14        // Variables
15        this.matches = [];          // array of {type, id, handle, startline, endline, syntax, scroll:{top,bottom}}
16        this.newMatches = [];       // newly discovered matches after a preview update (equal to 'this.matches' if partial preview is off)
17        this.startline = 0;         // First starting line to be parsed after the preview response has been received
18
19        // Objects
20        this.matcher = new MoaiEditor.Matcher(this);
21    }
22    // ┌───────────────────────────────────┐
23    // │ Public                            │
24    // └───────────────────────────────────┘
25
26    add (type, handle, startline, endline, syntax=null) {
27        const match = {
28            type      : type,
29            handle    : handle,
30            id        : handle.id,
31            startline : this.startline + startline,
32            endline   : this.startline + endline,
33            syntax    : syntax,
34            scroll    : null,
35        };
36        this.matches.push(match);           // Global list of matches
37        this.newMatches.push(match);        // Only new matches
38    }
39
40    update(top, bottom) {
41        this.start = Date.now();
42
43        // Get current editor
44        const editor = moaiEditor.editor.current;
45
46        // Get the starting and ending line
47        var startline = 0;
48        if (top !== null)
49            startline = top.endline + 1;
50        this.startline = startline;
51        var endline = editor.watcher.lines.length-1;
52        if (bottom !== null)
53            endline = bottom.startline-1;
54
55        // Remove matches in the changed area
56        this.removeMatches(startline, endline, true);
57
58        // Run matcher
59        this.newMatches = [];
60        this.matcher.onAjax (top, bottom, startline, endline);
61
62        // Sort matches by start line
63        this.matches.sort((a, b) => (a.startline > b.startline) ? 1 : -1);
64
65        // Let the editor process the newly found matches
66        var start = Date.now();
67        editor.onAjax(this.newMatches);
68
69        // Calc scroll points of new matches
70        for (let match of this.newMatches) {
71            const top = editor.getLineRect(match.startline).top;
72            const bottom = editor.getLineRect(match.endline).bottom;
73            match.scroll = {top:top, bottom:bottom};
74        }
75        // Show scrollpoints (for debug)
76        this.showScrollPoints('onAjax');
77
78        const elapsed = Date.now() - start;
79        this.measureFrameTime("�� MATCHES.ONAJAX (FRAME TIME)");
80    }
81
82    onTextChanged(change) {
83
84        // Get current editor
85        const editor = moaiEditor.editor.current;
86
87        // Remove matches in the changed area
88        var keep = [];
89        const start = change.num.keepfirst;
90        const end = change.index.keeplast-1;
91        this.removeMatches(start, end);
92
93        // Shift the line-numbers and scroll-points of the matches (below the changed zone)
94        var shift = null;
95        for (let match of this.matches)
96            if (match.startline >= change.index.keeplast) {
97                // Shift line numbers
98                match.startline += change.shift;
99                match.endline += change.shift;
100                // Shift the scroll positions
101                if (match.scroll !== null) {
102                    if (shift === null)
103                        shift = editor.getLineRect(match.startline).top - match.scroll.top;
104                    match.scroll.top += shift;
105                    match.scroll.bottom += shift;
106                }
107            }
108        // Show scrollpoints (for debug)
109        this.showScrollPoints('onTextChanged');
110    }
111
112    removeMatches(startline, endline, editor=false) {
113        var keep = [];
114        for (let match of this.matches)
115            if (!this.collides(match, startline, endline))
116                keep.push(match);
117            else if (editor)
118                moaiEditor.editor.current.removeMatches(match.startline, match.endline);
119        this.matches = keep;
120    }
121
122    collides(match, start, end) {
123        if (match.startline >= start  &&  match.startline <= end)
124            return true;
125        if (match.endline >= start  &&  match.endline <= end)
126            return true;
127        if (start >= match.startline &&  start <= match.endline)
128            return true;
129        if (end >= match.startline &&  end <= match.endline)
130            return true;
131        return false;
132    }
133
134    find(handle) {
135        for (let match of this.matches)
136            if (match.handle == handle)
137                return match;
138        return null;
139    }
140
141    recalcScrollPoints(range=null) {
142        /* @range can be:
143         *   null       : to recalculate all scroll points (called when the editor size or font changes)
144         *   {from, to} : to recalculate scroll points in a range of lines (called when CodeMirror viewport changes)
145         */
146        this.start = Date.now();
147        const editor  = moaiEditor.editor.current;
148        for (let match of this.matches) {
149            if ( range !== null  &&  !this.collides(match, range.from, range.to) )
150                continue;
151            const top = editor.getLineRect(match.startline).top;
152            const bottom = editor.getLineRect(match.endline).bottom;
153            match.scroll = {top:top, bottom:bottom};
154        }
155    }
156
157    showScrollPoints(caller) {
158        if (!this.settings.show.scrollpoints)
159            return;
160        const container = document.querySelector("#moaied__scrollpoints_overlay");
161        container.style.display = 'block';
162        container.innerHTML = '';
163        const editor  = moaiEditor.editor.current;
164        for (let match of this.matches) {
165            const top = editor.getLineRect(match.startline).top;
166            const bottom = editor.getLineRect(match.endline).bottom;
167            var element = moaiEditor.createHTML('<div class="moaied-scrollpoint"></div>');
168            element.style.top =  match.scroll.top+'px';
169            element.style.height = (match.scroll.bottom - match.scroll.top)+'px';
170            container.appendChild(element);
171        }
172    }
173
174    measureFrameTime (text) {
175        requestAnimationFrame(() => {
176            const elapsed = Date.now()-this.start;
177        });
178    }
179}; // End Class
180
181
182
183
184
185
186