1// Original JavaScript code by Chirp Internet: www.chirp.com.au 2// Please acknowledge use of this code by including this header. 3 4function Hilitor2(id, tag) 5{ 6 7 // private variables 8 var targetNode = document.getElementById(id) || document.body; 9 var hiliteTag = tag || "MARK"; 10 var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$"); 11 var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"]; 12 var wordColor = []; 13 var colorIdx = 0; 14 var matchRegExp = ""; 15 var openLeft = false; 16 var openRight = false; 17 var matches = []; 18 19 // characters to strip from start and end of the input string 20 var endRegExp = new RegExp('^[^\\w]+|[^\\w]+$', "g"); 21 22 // characters used to break up the input string into words 23 var breakRegExp = new RegExp('[^\\w\'-]+', "g"); 24 // var breakRegExp = new RegExp('\b\w+\b', "g"); 25 26 27 this.setEndRegExp = function(regex) 28 { 29 endRegExp = regex; 30 return true; 31 }; 32 33 this.setBreakRegExp = function(regex) 34 { 35 breakRegExp = regex; 36 return true; 37 }; 38 39 this.setMatchType = function(type) 40 { 41 switch(type) 42 { 43 case "open": 44 this.openLeft = this.openRight = true; 45 break; 46 47 case "closed": 48 this.openLeft = this.openRight = false; 49 break; 50 51 case "right": 52 this.openLeft = true; 53 this.openRight = false; 54 break; 55 56 case "left": 57 default: 58 this.openLeft = false; 59 this.openRight = true; 60 61 } 62 return true; 63 }; 64 65 // break user input into words and convert to RegExp 66 this.setRegex = function(input) 67 { 68 input = input.replace(/\\u[0-9A-F]{4}/g, ""); // remove missed unicode 69 input = input.replace(endRegExp, ""); 70 input = input.replace(breakRegExp, "|"); 71 input = input.replace(/^\||\|$/g, ""); 72 input = addAccents(input); 73 if(input) { 74 var re = "(" + input + ")"; 75 if(!this.openLeft) { 76 re = "(?:^|[\\b\\s])" + re; 77 } 78 if(!this.openRight) { 79 re = re + "(?:[\\b\\s]|$)"; 80 } 81 matchRegExp = new RegExp(re, "i"); 82 return matchRegExp; 83 } 84 return false; 85 }; 86 87 this.getRegex = function() 88 { 89 var retval = matchRegExp.toString(); 90 retval = retval.replace(/(^\/|\(\?:[^\)]+\)|\/i$)/g, ""); 91 return retval; 92 }; 93 94 // recursively apply word highlighting 95 this.hiliteWords = function(node) 96 { 97 if(node === undefined || !node) return; 98 if(!matchRegExp) return; 99 if(skipTags.test(node.nodeName)) return; 100 101 if(node.hasChildNodes()) { 102 for(var i=0; i < node.childNodes.length; i++) 103 this.hiliteWords(node.childNodes[i]); 104 } 105 if(node.nodeType == 3) { // NODE_TEXT 106 if((nv = node.nodeValue) && (regs = matchRegExp.exec(nv))) { 107 if(!wordColor[regs[1].toLowerCase()]) { 108 wordColor[regs[1].toLowerCase()] = colors[colorIdx++ % colors.length]; 109 } 110 111 var match = document.createElement(hiliteTag); 112 match.appendChild(document.createTextNode(regs[1])); 113 match.style.backgroundColor = wordColor[regs[1].toLowerCase()]; 114 match.style.color = "#000"; 115 116 var after; 117 if(regs[0].match(/^\s/)) { // in case of leading whitespace 118 after = node.splitText(regs.index + 1); 119 } else { 120 after = node.splitText(regs.index); 121 } 122 after.nodeValue = after.nodeValue.substring(regs[1].length); 123 node.parentNode.insertBefore(match, after); 124 } 125 }; 126 }; 127 128 // remove highlighting 129 this.remove = function() 130 { 131 var arr = document.getElementsByTagName(hiliteTag); 132 while(arr.length && (el = arr[0])) { 133 var parent = el.parentNode; 134 parent.replaceChild(el.firstChild, el); 135 parent.normalize(); 136 } 137 return true; 138 }; 139 140 // start highlighting at target node 141 this.apply = function(input) 142 { 143 this.remove(); 144 if(input === undefined || !(input = input.replace(/(^\s+|\s+$)/g, ""))) { 145 return; 146 } 147 input = escapeUnicode(input); 148 input = removeUnicode(input); 149 if(this.setRegex(input)) { 150 this.hiliteWords(targetNode); 151 } 152 153 // build array of matches 154 matches = targetNode.getElementsByTagName(hiliteTag); 155 156 // return number of matches 157 return matches.length; 158 }; 159 160 // scroll to the nth match 161 this.gotoMatch = function(idx) 162 { 163 if(matches[idx]) { 164 matches[idx].scrollIntoView({ 165 behavior: "smooth", 166 block: "center", 167 }); 168 for(var i=0; i < matches.length; i++) { 169 matches[i].style.outline = (idx == i) ? "2px solid red" : ""; 170 } 171 return true; 172 } 173 return false;
174 }; 175 176 // convert escaped UNICODE to ASCII 177 function removeUnicode(input) 178 { 179 var retval = input; 180 retval = retval.replace(/\\u(00E[024]|010[23]|00C2)/ig, "a"); 181 retval = retval.replace(/\\u00E7/ig, "c"); 182 retval = retval.replace(/\\u00E[89AB]/ig, "e"); 183 retval = retval.replace(/\\u(00E[EF]|00CE)/ig, "i"); 184 retval = retval.replace(/\\u00F[46]/ig, "o"); 185 retval = retval.replace(/\\u00F[9BC]/ig, "u"); 186 retval = retval.replace(/\\u00FF/ig, "y"); 187 retval = retval.replace(/\\u(00DF|021[89])/ig, "s"); 188 retval = retval.replace(/\\u(0163i|021[AB])/ig, "t"); 189 return retval; 190 } 191 192 // convert ASCII to wildcard 193 function addAccents(input) 194 { 195 var retval = input; 196 retval = retval.replace(/([ao])e/ig, "$1"); 197 retval = retval.replace(/ss/ig, "s"); 198 retval = retval.replace(/e/ig, "[eèéêë]"); 199 retval = retval.replace(/c/ig, "[cç]"); 200 retval = retval.replace(/i/ig, "[iîïÃ]"); 201 retval = retval.replace(/u/ig, "[uùûüú]"); 202 retval = retval.replace(/y/ig, "[yÿ]"); 203 retval = retval.replace(/s/ig, "(ss|[sÃÈ])"); 204 retval = retval.replace(/t/ig, "([tÅ£È])"); 205 retval = retval.replace(/a/ig, "([aà âäÄá]|ae)"); 206 retval = retval.replace(/o/ig, "([oôöó]|oe)"); 207 retval = retval.replace(/n/ig, "[nñ]"); 208 return retval; 209 } 210 211 // added by Yanosh Kunsh to include utf-8 string comparison 212 function dec2hex4(textString) 213 { 214 var hexequiv = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"); 215 return hexequiv[(textString >> 12) & 0xF] + hexequiv[(textString >> 8) & 0xF] + hexequiv[(textString >> 4) & 0xF] + hexequiv[textString & 0xF]; 216 } 217 218 // escape UNICODE characters in string 219 function escapeUnicode(str) 220 { 221 // convertCharStr2jEsc 222 // Converts a string of characters to JavaScript escapes 223 // str: sequence of Unicode characters 224 var highsurrogate = 0; 225 var suppCP; 226 var pad; 227 var n = 0; 228 var outputString = ""; 229 for(var i=0; i < str.length; i++) { 230 var cc = str.charCodeAt(i); 231 if(cc < 0 || cc > 0xFFFF) { 232 outputString += '!Error in convertCharStr2UTF16: unexpected charCodeAt result, cc=' + cc + '!'; 233 } 234 if(highsurrogate != 0) { // this is a supp char, and cc contains the low surrogate 235 if(0xDC00 <= cc && cc <= 0xDFFF) { 236 suppCP = 0x10000 + ((highsurrogate - 0xD800) << 10) + (cc - 0xDC00); 237 suppCP -= 0x10000; 238 outputString += '\\u' + dec2hex4(0xD800 | (suppCP >> 10)) + '\\u' + dec2hex4(0xDC00 | (suppCP & 0x3FF)); 239 highsurrogate = 0; 240 continue; 241 } else { 242 outputString += 'Error in convertCharStr2UTF16: low surrogate expected, cc=' + cc + '!'; 243 highsurrogate = 0; 244 } 245 } 246 if(0xD800 <= cc && cc <= 0xDBFF) { // start of supplementary character 247 highsurrogate = cc; 248 } else { // this is a BMP character 249 switch(cc) 250 { 251 case 0: 252 outputString += '\\0'; 253 break; 254 case 8: 255 outputString += '\\b'; 256 break; 257 case 9: 258 outputString += '\\t'; 259 break; 260 case 10: 261 outputString += '\\n'; 262 break; 263 case 13: 264 outputString += '\\r'; 265 break; 266 case 11: 267 outputString += '\\v'; 268 break; 269 case 12: 270 outputString += '\\f'; 271 break; 272 case 34: 273 outputString += '\\\"'; 274 break; 275 case 92: 276 outputString += '\\\\'; 277 break; 278 default: 279 if(cc > 0x1f && cc < 0x7F) { 280 outputString += String.fromCharCode(cc); 281 } else { 282 pad = cc.toString(16).toUpperCase(); 283 while(pad.length < 4) { 284 pad = '0' + pad; 285 } 286 outputString += '\\u' + pad; 287 } 288 } 289 } 290 } 291 return outputString; 292 } 293 294}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.