2017-05-07 30 views
15

Mam numer contenteditable div i muszę znać słowo na obecnym stanowisku. Próbowałem this solution, ale problem polega na tym, że nie rozpoznaje znaków specjalnych, takich jak @ i ~. Więc jeśli słowo zaczyna się od ~, jak ~fool, otrzymuję fool, natomiast oczekiwałem ~fool. Tak więc próbowałem zmodyfikować rozwiązanie, biorąc pod uwagę, że jeśli po przesunięciu zaznaczenia z powrotem, napotkany znak nie jest spacją, będę poruszał się do tyłu, dopóki nie napotkam spacji. To by oznaczało początek selekcji. Podobnie też posuwałbym się naprzód, dopóki nie znajdę miejsca, a to oznaczałoby koniec selekcji. Wtedy wybór dałby mi słowo. Aby uzyskać pozycję opiekuna, użyłem this solution. Po połączeniu, mój kod wygląda następująco:Zdobądź słowo zaczynające się od znaków specjalnych pod opieką w contenteditable div

function getCaretPosition(editableDiv) { 
    var caretPos = 0, 
    sel, range; 
    if (window.getSelection) { 
    sel = window.getSelection(); 
    if (sel.rangeCount) { 
     range = sel.getRangeAt(0); 
     if (range.commonAncestorContainer.parentNode == editableDiv) { 
     caretPos = range.endOffset; 
     } 
    } 
    } else if (document.selection && document.selection.createRange) { 
    range = document.selection.createRange(); 
    if (range.parentElement() == editableDiv) { 
     var tempEl = document.createElement("span"); 
     editableDiv.insertBefore(tempEl, editableDiv.firstChild); 
     var tempRange = range.duplicate(); 
     tempRange.moveToElementText(tempEl); 
     tempRange.setEndPoint("EndToEnd", range); 
     caretPos = tempRange.text.length; 
    } 
    } 
    return caretPos; 
} 

function getCurrentWord() { 
    var sel, word = ""; 
    if (window.getSelection && (sel = window.getSelection()).modify) { 
     var selectedRange = sel.getRangeAt(0); 
     sel.collapseToStart(); 
     sel.modify("move", "backward", "word"); 

     while (sel.toString() != " " && getCaretPosition($("#editor").get(0)) != 0) { 
      sel.modify("move", "backward", "character"); 
      (sel = window.getSelection()).modify; 
     } 
     sel.modify("move", "forward", "character");  
     sel.modify("extend", "forward", "word"); 
     word = sel.toString(); 

     // Restore selection 
     sel.removeAllRanges(); 
     sel.addRange(selectedRange); 
    } else if ((sel = document.selection) && sel.type != "Control") { 
     var range = sel.createRange(); 
     range.collapse(true); 
     range.expand("word"); 
     word = range.text; 
    } 
    return word; 
} 

$(function() { 

    $(document).on('keyup keydown paste cut mouseup',"#editor", function() { 
     var word = getCurrentWord(); 
     console.log(word); 
    }); 
}); 

To jednak nie działa. To nie jest problem. 1. Problem 2 to, nawet jeśli na obrazie jest obraz, a użytkownik kliknie na obrazku, program obsługi nadal zwraca ostatnie słowo przed obrazem, natomiast oczekuję pustego ciągu. Czy ktoś może mi pomóc rozwiązać te dwa problemy?

+0

Nienawidzę się, że facet, ale to brzmi jak między 2 odpowiedzi masz wszystko, czego potrzebujesz, aby ułożyła roztworu roboczego do swoich potrzeb. Nie musisz zaznaczać żadnej z odpowiedzi, po prostu myśl, że masz wystarczające rozwiązania, aby uzyskać coś działającego dla siebie: P –

+0

Próbuję też sam, nie siedzę leniwie za działającym rozwiązaniem od kogoś innego. – SexyBeast

+0

Przepraszam, nie zamierzałem sugerować, że jesteś leniwy. Chodzi tylko o to, że pomiędzy tymi dwiema odpowiedziami myślę, że odpowiedź czai się. –

Odpowiedz

2

Oto ładny przykład barebones. Jest div z przykładowym tekstem:

<div contenteditable onclick="getCaretCharacterOffsetWithin(this)">some ~test content</div> 

Oto skrypt. Kiedy klikamy na div, gdziekolwiek znajdzie się kursor, otrzymamy aktualną pozycję i wypluniemy słowo, w którym się znajdujemy. To słowo może zawierać znaki specjalne i jest ograniczone tylko spacją.

function getCaretCharacterOffsetWithin(element) { 
    var caretOffset = 0; 
    var doc = element.ownerDocument || element.document; 
    var win = doc.defaultView || doc.parentWindow; 
    var sel; 
    if (typeof win.getSelection != "undefined") { 
     sel = win.getSelection(); 
     if (sel.rangeCount > 0) { 
      var range = win.getSelection().getRangeAt(0); 
      var preCaretRange = range.cloneRange(); 
      preCaretRange.selectNodeContents(element); 
      preCaretRange.setEnd(range.endContainer, range.endOffset); 
      caretOffset = preCaretRange.toString().length; 
     } 
    } else if ((sel = doc.selection) && sel.type != "Control") { 
     var textRange = sel.createRange(); 
     var preCaretTextRange = doc.body.createTextRange(); 
     preCaretTextRange.moveToElementText(element); 
     preCaretTextRange.setEndPoint("EndToEnd", textRange); 
     caretOffset = preCaretTextRange.text.length; 
    } 
    console.log('caretOffset', caretOffset); 
    word = getWordAtPosition(caretOffset, element); 
    console.log('word', word); 
    return caretOffset; 
} 

function getWordAtPosition(position, element) { 
    var total_text = element.innerHTML; 
    var current_word = ""; 
    var i = 0; 
    var word_found = false; 
    while(i < total_text.length) { 
    if(total_text[i] != ' ') 
     current_word += total_text[i]; 
    else if(word_found) 
     return current_word; 
    else 
     current_word = ""; 
    if(i == position) 
     word_found = true; 
    i++; 
    } 
    return current_word; 
} 

Herezje przykład to działa:

https://codepen.io/anon/pen/dWdyLV

+1

Hmm. Prawie działa. Z wyjątkiem, w podanym kodzie, jeśli kliknę na końcu słowa, tj. Teraz kursor miga na końcu słowa "~ test", wyświetlane słowo to "treść", które jest następnym słowem oddzielonym przez przestrzeń. A po drugie, jeśli kliknę na początku słowa, aby kursor migał tuż przed pierwszym znakiem wyrazu, dla słowa '~ test', zwróci' ~ test', dla innych słów takich jak 'cześć' nie zaczynając od '~', zwraca ' ' – SexyBeast

+0

Nie wspominając już, jeśli pogrubione zostanie słowo '~ test', zwrócone słowo to' '~ test' zamiast '~ test', i kliknie na kolejne' treść słowa nadal daje '~ test'. – SexyBeast

+0

Pierwsza myśl: czy wybranie '~ test' jest niepożądane? Myślę, że najprostszą rzeczą do zrobienia byłoby napisanie specjalnej listy znaków specjalnych, które chcesz wskazać jako separację słów i stamtąd. –

5

I zmodyfikowano funkcję getCurrentWord() posługiwania się podstawowymi metodami String aby słowo z pozycji karetki. Funkcja przyjmuje element i pozycję i zwraca słowo w tej pozycji.

Poniżej znajduje się zaktualizowana funkcja.

function getCurrentWord(el, position) { 
    // Get content of div 
    var content = el.textContent; 

    // Check if clicked at the end of word 
    position = content[position] === ' ' ? position - 1 : position; 

    // Get the start and end index 
    var startPosition = content.lastIndexOf(' ', position); 
    var endPosition = content.indexOf(' ', position); 

    // Special cases 
    startPosition = startPosition === content.length ? 0 : startPosition; 
    endPosition = endPosition === -1 ? content.length : endPosition; 

    return content.substring(startPosition + 1, endPosition); 
} 

Funkcja najpierw pobiera zawartość elementu. Następnie sprawdza, czy użytkownik kliknął na końcu słowa, jeśli tak, odejmij jedną od pozycji, aby indexOf i lastIndexOf działały poprawnie w przestrzeni.

Dla pozycji początkowej i końcowej istnieją dwa specjalne przypadki, które należy obsłużyć. Najpierw kliknij ostatni element. W tym celu startPosition będzie -1, ponieważ po ostatnim słowie może nie być spacji.

Po drugie, po kliknięciu pierwszego słowa, endPosition będzie -1, ponieważ nie może być miejsca przed pierwszym słowem.

Te dwa warunki będą działać, nawet jeśli przed pierwszym znakiem jest spacja i spacja po ostatnim znaku.

indexOf i lastIndexOf służą do znajdowania spacji przed i po słowie, a użycie tych indeksów spowoduje, że słowo substring zostanie podane na tej pozycji.

Oto live demo do przetestowania.

$(function() { 
 
    function getCaretPosition(editableDiv) { 
 
    var caretPos = 0, 
 
     sel, range; 
 
    if (window.getSelection) { 
 
     sel = window.getSelection(); 
 
     if (sel.rangeCount) { 
 
     range = sel.getRangeAt(0); 
 
     if (range.commonAncestorContainer.parentNode == editableDiv) { 
 
      caretPos = range.endOffset; 
 
     } 
 
     } 
 
    } else if (document.selection && document.selection.createRange) { 
 
     range = document.selection.createRange(); 
 
     if (range.parentElement() == editableDiv) { 
 
     var tempEl = document.createElement("span"); 
 
     editableDiv.insertBefore(tempEl, editableDiv.firstChild); 
 
     var tempRange = range.duplicate(); 
 
     tempRange.moveToElementText(tempEl); 
 
     tempRange.setEndPoint("EndToEnd", range); 
 
     caretPos = tempRange.text.length; 
 
     } 
 
    } 
 
    return caretPos; 
 
    } 
 

 
    function getCurrentWord(el, position) { 
 
    var word = ''; 
 

 
    // Get content of div 
 
    var content = el.textContent; 
 

 
    // Check if clicked at the end of word 
 
    position = content[position] === ' ' ? position - 1 : position; 
 

 
    // Get the start and end index 
 
    var startPosition = content.lastIndexOf(' ', position); 
 
    startPosition = startPosition === content.length ? 0 : startPosition; 
 
    var endPosition = content.indexOf(' ', position); 
 
    endPosition = endPosition === -1 ? content.length : endPosition; 
 

 
    return content.substring(startPosition + 1, endPosition); 
 
    } 
 

 

 
    $('#editor').on('keyup keydown paste cut mouseup', function() { 
 
    var caretPosition = getCaretPosition(this); 
 
    var word = getCurrentWord(this, caretPosition); 
 
    console.log(word); 
 
    }); 
 
});
div { 
 
    font-size: 18px; 
 
    line-height: 1.5em; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="editor" contenteditable> 
 

 

 

 
    Lorem !p$um dolor $!t @met, con$ectetur @d!p!$!c!ng el!t, $ed do e!u$mod tempor !nc!d!dunt ut [email protected] et dolore [email protected]@ @[email protected] Ut en!m @d m!n!m [email protected], qu!$ no$trud [email protected]!on [email protected] [email protected]or!$ n!$! ut @l!qu!p ex [email protected] commodo [email protected] Du!$ @ute !rure dolor 
 
    !n reprehender!t !n [email protected] vel!t e$$e c!llum dolore eu [email protected] [email protected] [email protected][email protected] 
 
</div>

+1

Nadal mnóstwo błędów. Na przykład, w przykładowej zawartości, którą dałeś w skrzypcach, jeśli klikniesz na trzecie słowo - dolor, i zrobisz "CTRL-B", aby uczynić go pogrubionym, a następnie ponownie kliknij, zacznie dawać złe słowa. Jeśli dwukrotnie wybierzesz słowo, aby je wybrać, zamiast rejestrowanego słowa, będą rejestrowane nieprawidłowe słowa. – SexyBeast