2014-06-19 8 views
5

Pracuję nad prostym emulatorem ekranu/terminalu (podobnym do wtyczki JQuery, ale bez funkcji RPC i funkcji okna). Każda linia ekranu jest rzędem tabeli (ciąg HTML), a polecenie drukowania może wstawiać tekst z niektórymi atrybutami (np. Kolor pierwszego planu i kolor tła). Każdy drukowany tekst jest otoczone przęsła z atrybutami stylu, na przykład:Uzyskaj atrybuty załączającego znacznika w ciągu HTML

<span style="color:#000000;background-color:#111111">A</span><span style="color:#222222;background-color:#333333>BC</span> 

To działa prawidłowo. Teraz chcę dodać funkcję, która daje mi wszystkie atrybuty postaci na danej pozycji ekranu, w powyższym wierszu znak w pozycji 0 (A) ma kolor # 000000. Więc muszę policzyć znaki, które nie należą do znacznika zakresu i uzyskać ostatnie poprzednie style. Moje pierwsze rozwiązanie jest dość podatny na błędy:

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; 
} 

Czy istnieje prostsze rozwiązanie bez liczenia znaków (może JQuery lub regex)? To jest podobne do Get parent element of a selected text , ale nie potrzebuję selekcji, tylko indeks postaci.

Odpowiedz

0

Zostawię zadanie parsowania HTML do przeglądarki i po prostu używam wynikowego drzewa DOM. Oto niektóre pseudo-kod można użyć w oparciu o pomysł wykorzystania drzewa DOM:

function getAttr(lineNumber, position) { 
    var lineDom = getDOMContainerForLineNumber(lineNumber); 
    var current = 0; // the current character position 

    function getAttrRec(elems, foreground, background) { 
    for(elem in elems) { 
     if(elem is <span>) { 
     var res = getAttrRec(elem.children, elem.foregroundColor, elem.backgroundColor); 
     if(res != null) 
      return res; 
     } else if(elem is TEXT) { 
     current += elem.textLength; 
     if(current >= position) 
      return {foreground: foreground, background: background}; 
     } 
    } 
    return null; 
    } 

    return getAttrRec(lineDom.children, black, black); 
} 

To jest po prostu bardzo szorstki szkic chociaż. Zwłaszcza będziesz musiał uważać na białe spacje - są one dość mocno rozebrane przez przeglądarki. Zatem bezpośrednie poleganie na długości tekstu może nie działać w twoim przypadku. Możesz również zająć się przypadkiem, w którym znacznik zakresu nie zawiera informacji o planie lub kolorze tła.

1

Możliwy sposób obsługi tworzenia struktury danych, która umożliwia indeksowanie każdej linii i uzyskanie znaku, a także skojarzone style, można wykonać za pomocą następującego fragmentu dla każdej linii. To zakłada, że ​​jesteś generowania znaczników HTML dla przedstawionego powyżej jest dość stabilny, jak również (można wyjaśnić różnicami w regex w razie potrzeby):

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); 

To daje tablicę dla każdego wiersza, który wygląda jak następujące:

[ 
    { char: 'A', 
    styles: { 'background-color': '#111111', 'color': '#000000' } 
    }, 
    { char: 'B', 
    styles: { 'background-color': '#333333', 'color': '#222222' } 
    }, 
    { char: 'C', 
    styles: { 'background-color': '#333333', 'color': '#222222' } 
    } 
] 

To pozwoli Ci indeks do każdej linii przy całkowitej pozycji znaku i uzyskać znak w tym miejscu wraz z powiązanymi stylów jak przedmiot.