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