I am working on a simple text screen / terminal emulator (similar to the JQuery terminal plugin, but without RPC stuff and with window functionality). Each line of the screen is a table row (a HTML string) and a print command can insert text with some attributes (e.g. foreground and background color). Each printed text is enclosed by a span with style attributes, for example:
<span style="color:#000000;background-color:#111111">A</span><span style="color:#222222;background-color:#333333>BC</span>
This works fine. Now I want to add a function which gives me all attributes of a character at a given screen position, in the above line the character at position 0 (A) has the color #000000. So I have to count characters which don't belong to the span tag and get the last preceding styles. My first rather error prone solution is:
function getAttr(line, position) {
var result = {foreground:'', background:''},
ch = '', i, j = -1, tag = false;
// Count characters
for (i = 0; i < line.length && j < position; i++) {
ch = line.charAt(i);
if (ch == '<') {
tag = true;
}
if (ch == '>') {
tag = false;
}
else if (!tag) {
j++;
}
}
i--;
// Find styles
while (i > 0 && line.charAt(i) != '<') {
if (line.substr(i, 6) == 'color:') {
result.foreground = line.substr(i + 6, 7);
}
if (line.substr(i, 17) == 'background-color:') {
result.background = line.substr(i + 17, 7);
}
i--;
}
return result;
}
Is there a simpler solution without counting characters (maybe JQuery or a regex)?
This is similar to Get parent element of a selected text but I don't need a selection, just a character index.
A possible way to handle building a data structure that allows you to index each line and get at the character and it's associated styles could be done using the following snippet for each line. This assumes the markup you're generating for the HTML shown above is fairly stable as well (you could account for variations in the regex if needed):
var tagre = /\<span style="([^"]+)"\>([A-Za-z]+)\<\/span\>/ig,
s = '<span style="color:#000000;background-color:#111111">A</span><span style="color:#222222;background-color:#333333">BC</span>';
var matches,
positions = [];
while (matches = tagre.exec(s)) {
var len = matches[2].length,
chars = matches[2],
styles = {};
matches[1].split(';').forEach(function(o) {
var _s = o.split(':'),
key = _s[0],
val = _s[1];
styles[key] = val;
});
for (var i=0; i < len; i++) {
var char = chars[i];
positions.push({ 'char': char, 'styles': styles });
}
}
console.log("positions=%o", positions);
This would give you an array for each line that looks like the following:
[
{ char: 'A',
styles: { 'background-color': '#111111', 'color': '#000000' }
},
{ char: 'B',
styles: { 'background-color': '#333333', 'color': '#222222' }
},
{ char: 'C',
styles: { 'background-color': '#333333', 'color': '#222222' }
}
]
That would let you index into each line by integer character position and get the character at that position along with the associated styles as an object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With