1/* DokuWiki MoaiEditor Matcher.js file 2 Author : MoaiTools <info@moaitools.org> 3 License : GPL 3 (http://www.gnu.org/licenses/gpl.html) */ 4 5MoaiEditor.Matcher = class { 6 7 constructor(outer) { 8 9 this.matches = outer; 10 11 // Variables 12 this.lines = []; // array of plain text lines 13 this.sections = []; // array of {prevHeaderIdx, nextHeaderIdx, nodes:[ {i, type, handle, [textContent, innerText ]} 14 15 // Objects 16 this.tools = new MoaiEditor.MatchTools(this); 17 this.headers = new MoaiEditor.MatchHeaders(this); 18 this.section = new MoaiEditor.MatchSection(this); 19 } 20 21 onAjax(top, bottom, startline, endline) { 22 23 const start = Date.now(); 24 25 // Get the lines of text to be parsed 26 this.lines = moaiEditor.editor.current.watcher.lines.slice(startline, endline); 27 28 // Parse html 29 this.parseDOM(top, bottom); 30 31 // Parse headers 32 this.headers.parseText(this.lines); 33 this.headers.findAll(); 34 35 // Parse sections 36 for (let section of this.sections) 37 this.section.match(section); 38 39 const elapsed = Date.now() - start; 40 } 41 42 parseDOM(top, bottom) { 43 44 // Reset the arrays 45 this.sections = []; 46 this.headers.nodes = []; 47 48 // Preparations 49 var nodes = []; 50 var prevHeaderIdx = null; 51 var nodeidx = 0; 52 var headeridx = 0; 53 var started = false; 54 if (top === null) 55 started = true; 56 57 // Iterate the preview nodes 58 for (let node of document.querySelectorAll("#moaied__preview_content *")) { 59 60 // Ignore nodes before and after the last preview zone 61 if (top !== null && top.handle == node) 62 started = true; 63 if (!started) 64 continue; 65 if (bottom !== null && bottom.handle == node) 66 break; 67 68 // If we find a header 69 if (['H1','H2','H3','H4','H5'].includes(node.tagName)) { 70 71 // Store the header 72 this.headers.nodes.push({ 73 i : headeridx, 74 type : node.tagName, 75 text : node.textContent, 76 handle : node, 77 matchline : null 78 }); 79 // Create a new section if there is at least one element inside 80 if (nodes.length > 0) { 81 this.sections.push({ 82 prevHeaderIdx : prevHeaderIdx, 83 nextHeaderIdx : headeridx, 84 nodes : nodes 85 }); 86 nodeidx = 0; 87 nodes = []; 88 } 89 // Make header clickable 90 moaiEditor.scroll.makeElementClickable(node); 91 92 // Continue 93 prevHeaderIdx = headeridx; 94 headeridx += 1; 95 continue; 96 } 97 // Else add the node to the current section 98 nodes.push({ 99 i : nodeidx, 100 type : node.tagName, 101 handle : node, 102 }); 103 nodeidx += 1; 104 } 105 // Create the last section if there are elements inside 106 if (nodes.length > 0) 107 this.sections.push({ 108 prevHeaderIdx : prevHeaderIdx, 109 nextHeaderIdx : null, 110 nodes : nodes 111 }); 112 113 // 114 /* 115 */ 116 } 117}; // End Class 118 119// ▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆ 120// ▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆ 121 122MoaiEditor.MatchSection = class { 123 124 constructor(outer) { 125 126 // Arguments 127 this.outer = outer; 128 this.tools = outer.tools; 129 this.paragraphs = new MoaiEditor.MatchParagraphs(this); 130 } 131 132 match (section) { 133 134 // Init variables 135 this.text = ''; // Plaintext of this section 136 this.lines = []; // Text lines of this section {text, [cleantext, matched, media, } 137 this.blocks = []; // Blocks of text of this section {i, text, start, end, [cleantext, matched, media, } 138 this.section = section; // {prevHeaderIdx, nextHeaderIdx, nodes:[]} 139 this.startline = null; // Start line of this section in the main text 140 141 // Get the text for this section (this.text, this.lines, this.blocks) 142 this.getSectionText(); 143 144 145 for (let type of ['P']) 146 if (type == 'P') 147 this.paragraphs.match(); 148 149 } 150 151 getSectionText () { 152 153 // Calc starting and ending lines 154 var prevLine = this.outer.headers.nodes[this.section.prevHeaderIdx]?.matchline; 155 var nextLine = this.outer.headers.nodes[this.section.nextHeaderIdx]?.matchline; 156 if (prevLine === undefined) prevLine = -1; 157 if (nextLine === undefined) nextLine = this.outer.lines.length; 158 const start = prevLine + 1; 159 const end = nextLine - 1; 160 this.startline = start; 161 162 // Iterate the lines 163 var blockStart = 0; 164 var block = {text:'', start:0}; 165 var j = 0; 166 var b = 0; 167 for (let i = start; i <= end; i++) { 168 const line = this.outer.lines[i]; 169 this.lines.push({text:line}); 170 this.text += line + '\n'; 171 // If line is not empty, add line to the block 172 if (line.trim().length > 0) { 173 block.text += line + '\n'; 174 // If line is empty 175 } else { 176 // If the block is not empty, save it and start a new one 177 if (block.text.trim().length > 0) { 178 block.i = b; 179 block.end = j-1; 180 block.text = block.text.trimEnd(); 181 this.blocks.push(block); 182 b += 1 183 } 184 // Restart the block regardless 185 block = {text:'', start:j+1}; 186 } 187 j += 1; 188 } 189 if (block.text.trim().length > 0) { 190 block.i = b; 191 block.end = j-1; 192 block.text = block.text.trimEnd(); 193 this.blocks.push(block); 194 } 195 } 196}; // End Class 197 198// ▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆ 199// ▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆ 200 201 202MoaiEditor.MatchPreformatted = class { 203 204 constructor(outer) { 205 this.outer = outer; 206 this.tools = outer.tools; 207 } 208 209 match () { 210 211 } 212}; // End Class 213