2014-06-19 20 views
5

Sto lavorando a una semplice schermata di testo/emulatore di terminale (simile al plug-in di terminale JQuery, ma senza elementi RPC e con funzionalità di finestra). Ogni riga dello schermo è una riga della tabella (una stringa HTML) e un comando di stampa può inserire testo con alcuni attributi (ad esempio colore di primo piano e sfondo). Ogni testo stampato è racchiuso da un arco con gli attributi di stile, per esempio:Ottieni gli attributi del tag di inclusione nella stringa HTML

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

Questo funziona bene. Ora voglio aggiungere una funzione che mi dà tutti gli attributi di un personaggio in una data posizione dello schermo, nella riga sopra il carattere in posizione 0 (A) ha il colore # 000000. Quindi devo contare i caratteri che non appartengono al tag span e ottengono gli ultimi stili precedenti. La mia prima soluzione piuttosto soggetta a errori è:

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

Esiste una soluzione più semplice, senza contare i personaggi (forse JQuery o un regex)?

Questo è simile a Get parent element of a selected text ma non ho bisogno di una selezione, solo un indice di carattere.

risposta

0

Avrei lasciato il compito di analizzare l'HTML al browser e usare solo l'albero DOM risultante. Ecco alcuni pseudo-codice si potrebbe usare in base l'idea di utilizzare l'albero del 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); 
} 

Questo è solo un abbozzo molto approssimativa però. Soprattutto dovrai stare attento ai bianchi: sono spogliati molto intensamente dai browser. Quindi, fare affidamento direttamente sulla lunghezza del testo potrebbe non funzionare nel tuo caso. Potresti anche voler gestire il caso in cui un tag span non contiene informazioni sul colore di primo piano o di sfondo.

1

Un modo possibile per gestire la creazione di una struttura dati che consente di indicizzare ogni riga e ottenere il carattere e gli stili associati possono essere eseguiti utilizzando il seguente frammento per ogni riga. Ciò presuppone la marcatura si sta generando per il codice HTML mostrato sopra è abbastanza stabile così (si potrebbe spiegare variazioni nella regex se necessario):

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

questo darebbe un array per ogni riga simile il seguente:

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

modo che permettesse di indice in ogni riga alla posizione del carattere intero e ottenere il carattere in quella posizione insieme con gli stili associati come un oggetto.

Problemi correlati