2017-03-11 59 views
7

Próbuję odbudować obiekt Range() w przeglądarce klientów za pomocą websockets.Przebudowywanie zakresu z węzłem, startOffset i endOffset

https://jsfiddle.net/k36goyec/

pierwsze jestem coraz obiekt klasy w mojej przeglądarce i Node że zakres zaczyna się:

var range = window.getSelection().getRangeAt(0); 
var node = range.startContainer 

jestem przechodzącej trzy parametry ponad WebSocket do funkcji Zakres budowniczy na klientach przeglądarka.

var text  = node.parentNode.textContent; 
var startOffset = range.startOffset 
var endOffset = range.endOffset 

dane te są przekazywane do mojej funkcji buildRange:

/** 
* 
*/ 
buildRange: function(text, startOffset, endOffset){ 
    var node = this.getNodeByText(text); // get the Node by its contents 

    var range = document.createRange(); 
    range.setStart(node, startOffset); 
    range.setEnd(node, endOffset); 

    span = document.createElement('span'); 
    span.style.backgroundColor = this.color; 
    $(span).addClass('hl'); 
    range.surroundContents(span); 
}, 

Jak widać poniżej, jestem coraz węzeł w przeglądarce klientów poprzez zapętlenie przez wszystkie elementy na stronie i porównanie jej zawartość z tekstem:

/** 
* 
*/ 
getNodeByText: function(text){ 
    var all = document.getElementsByTagName("*"); 
    for (var i = 0; i < all.length; i++) { 
     if (all[i].textContent === text) { 
      return all[i]; 
     } 

    } 
}, 

Używam setStart() i setEnd(), aby ustawić zakres mojego wyboru na węźle.

Problemy!

range.startOffset/endOffset Spec mówi co następuje:

If the startNode is a Node of type Text, Comment, or CDATASection, then startOffset is the number of characters from the start of startNode. For other Node types, startOffset is the number of child nodes between the start of the startNode.

Kiedy wybrać zakres tekstu pojawia się następujący błąd:

IndexSizeError: Index or size is negative or greater than the allowed amount 

To dlatego, że jestem przekazując przesunięcie jak 0, 10 (wybrano 10 znaków), ale węzeł jest węzłem elementu, a nie węzłem tekstowym.

po prostu nie może wydawać się niezawodnie uzyskać węzeł tekstowy, mogę tylko sam węzeł elementu ...

Q:

Jak można wiarygodnie odbudować szeregu z węzłem i przesunięcia?

+0

Używasz metody getElementsByTagName, która zwróci elementy. Proponuję przejrzenie https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes i https://developer.mozilla.org/en/docs/Web/API/ Węzeł/nodeType i – Orangesandlemons

Odpowiedz

2

Inni zauważyli już, że bezpośrednim problemem, przed którym stoisz, jest to, że kiedy zapiszesz dane zakresu, otrzymasz przesunięcie w węźle tekstowym, ale przy próbie odtworzenia zakresu użyjesz przesunięcia jako indeksu w element i ulega awarii. Jeśli to rozwiążesz, naprawisz swój natychmiastowy problem.

Twoje ogólne podejście jest jednak kruche.

Rozważmy dokument z tym:

<p>Farmer John has a thousand <b>goats</b></p> 
<p>and his <b>goats</b> ate all his oats.</p> 

pewne problemy, z góry na głowie:

  1. przypadku wybrania 2. „kozy”, Twój algorytm będzie odtworzyć zakres na pierwszych "kozłach", ponieważ szuka tylko elementu, który ma ten sam tekst co oryginalny zakres.

  2. Jeśli wybierzesz zakres które zaczynają się od „a” w 2. linii i kończy z „zjadł”, przesunięcia, które otrzymuje się od zakresu pochodzenia są indeksowania w dwóch różnych węzłów tekstowych: jednego węzła tekstowego zawiera tekst and his i drugi węzeł tekstowy, który zawiera tekst. ate all his oats. Twój algorytm zakłada, że ​​istnieje tylko jedna notatka do odzyskania w miejscu docelowym. Może być ich więcej niż jeden.

    Ten sam problem występuje, jeśli zaznaczenie rozpoczyna się od jednego z pogrubionych słów i kończy na zewnątrz.

Aby mieć coś solidnego, należy przeprowadzić szeregowanie zakresu w miejscu pochodzenia, które rejestruje wystarczającą ilość informacji, aby zapewnić dokładną deserializację w miejscu docelowym.

Istnieje wiele sposobów na zrobienie tego. Jednym ze sposobów może być zapewnienie, że ta sama struktura DOM jest obecna w punkcie początkowym i docelowym, i użycie serialization module biblioteki Rangy do przeprowadzenia serializacji i deserializacji. Jeśli możesz zapewnić tę samą strukturę DOM na obu końcach, to jest to, czego bym użył.

Jeśli nie możesz zapewnić tej samej struktury DOM na obu końcach, musisz wykonać własne. Musisz zidentyfikować punkty odniesienia, które są takie same na obu końcach i zidentyfikować węzeł początkowy/przesunięcie i węzeł końcowy/przesunięcie zakresu w odniesieniu do punktów odniesienia.

1

Rozwiązanie tego problemu:

I just can't seem to reliably get the text node, I can only get the element node itself...

Aby uzyskać rzeczywisty węzeł tekstowy, można użyć właściwości .childnodes elementu. Jeśli masz więcej niż jeden, możesz przetestować nodeType, aby określić, które węzły tekstowe. Aby dowiedzieć się, co jest w dowolnym węźle tekstowym, sprawdź właściwość nodeValue.