forked from GerHobbelt/hilitor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhilitor-utf8.js
198 lines (184 loc) · 5.77 KB
/
hilitor-utf8.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Original JavaScript code by Chirp Internet: www.chirp.com.au
// Modified by Yanosh Kunsh to include utf-8 string comparison
// Please acknowledge use of this code by including this header.
function Hilitor(id, tag)
{
var targetNode = document.getElementById(id) || document.body;
var hiliteTag = tag || "EM";
var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$");
var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"];
var wordColor = [];
var colorIdx = 0;
var matchRegex = "";
var openLeft = false;
var openRight = false;
this.setMatchType = function(type)
{
switch(type)
{
case "left":
this.openLeft = false;
this.openRight = true;
break;
case "right":
this.openLeft = true;
this.openRight = false;
break;
case "open":
this.openLeft = this.openRight = true;
break;
default:
this.openLeft = this.openRight = false;
}
};
this.setRegex = function(input)
{
input = input.replace(/[^\w0-9\\u ]+/, "").replace(/[ ]+/g, "|");
var re = "(" + input + ")";
if(!this.openLeft) re = "\\b" + re;
if(!this.openRight) re = re + "\\b";
matchRegex = new RegExp(re, "i");
};
this.getRegex = function()
{
var retval = matchRegex.toString();
retval = retval.replace(/(^\/(\\b)?|\(|\)|(\\b)?\/i$)/g, "");
retval = retval.replace(/\|/g, " ");
return retval;
};
// recursively apply word highlighting
this.hiliteWords = function(node)
{
if(node == undefined || !node) return;
if(!matchRegex) return;
if(skipTags.test(node.nodeName)) return;
if(node.hasChildNodes()) {
for(var i=0; i < node.childNodes.length; i++)
this.hiliteWords(node.childNodes[i]);
}
if(node.nodeType == 3) { // NODE_TEXT
if((nv = node.nodeValue) && (regs = matchRegex.exec(nv))) {
if(!wordColor[regs[0].toLowerCase()]) {
wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length];
}
var match = document.createElement(hiliteTag);
match.appendChild(document.createTextNode(regs[0]));
match.style.backgroundColor = wordColor[regs[0].toLowerCase()];
match.style.fontStyle = "inherit";
match.style.color = "#000";
var after = node.splitText(regs.index);
after.nodeValue = after.nodeValue.substring(regs[0].length);
node.parentNode.insertBefore(match, after);
}
};
};
// remove highlighting
this.remove = function()
{
var arr = document.getElementsByTagName(hiliteTag);
while(arr.length && (el = arr[0])) {
var parent = el.parentNode;
parent.replaceChild(el.firstChild, el);
parent.normalize();
}
};
// start highlighting at target node
this.apply = function(input)
{
this.remove();
if(input === undefined || !input) return;
input = convertCharStr2jEsc(input);
this.setRegex(input);
this.hiliteWords(targetNode);
};
// added by Yanosh Kunsh to include utf-8 string comparison
function dec2hex4(textString)
{
var hexequiv = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F");
return hexequiv[(textString >> 12) & 0xF] + hexequiv[(textString >> 8) & 0xF] + hexequiv[(textString >> 4) & 0xF] + hexequiv[textString & 0xF];
}
function convertCharStr2jEsc(str, cstyle)
{
// Converts a string of characters to JavaScript escapes
// str: sequence of Unicode characters
var highsurrogate = 0;
var suppCP;
var pad;
var n = 0;
var outputString = '';
for(var i=0; i < str.length; i++) {
var cc = str.charCodeAt(i);
if(cc < 0 || cc > 0xFFFF) {
outputString += '!Error in convertCharStr2UTF16: unexpected charCodeAt result, cc=' + cc + '!';
}
if(highsurrogate != 0) { // this is a supp char, and cc contains the low surrogate
if(0xDC00 <= cc && cc <= 0xDFFF) {
suppCP = 0x10000 + ((highsurrogate - 0xD800) << 10) + (cc - 0xDC00);
if(cstyle) {
pad = suppCP.toString(16);
while(pad.length < 8) {
pad = '0' + pad;
}
outputString += '\\U' + pad;
} else {
suppCP -= 0x10000;
outputString += '\\u' + dec2hex4(0xD800 | (suppCP >> 10)) + '\\u' + dec2hex4(0xDC00 | (suppCP & 0x3FF));
}
highsurrogate = 0;
continue;
} else {
outputString += 'Error in convertCharStr2UTF16: low surrogate expected, cc=' + cc + '!';
highsurrogate = 0;
}
}
if(0xD800 <= cc && cc <= 0xDBFF) { // start of supplementary character
highsurrogate = cc;
} else { // this is a BMP character
switch(cc)
{
case 0:
outputString += '\\0';
break;
case 8:
outputString += '\\b';
break;
case 9:
outputString += '\\t';
break;
case 10:
outputString += '\\n';
break;
case 13:
outputString += '\\r';
break;
case 11:
outputString += '\\v';
break;
case 12:
outputString += '\\f';
break;
case 34:
outputString += '\\\"';
break;
case 39:
outputString += '\\\'';
break;
case 92:
outputString += '\\\\';
break;
default:
if(cc > 0x1f && cc < 0x7F) {
outputString += String.fromCharCode(cc);
} else {
pad = cc.toString(16).toUpperCase();
while(pad.length < 4) {
pad = '0' + pad;
}
outputString += '\\u' + pad;
}
}
}
}
return outputString;
}
}