Ustaw kursor na określoną pozycję w CKEditor

Czy istnieje sposób na ustawienie pozycji kursora na znany indeks wewnątrz Ckeditora?

Chcę to zrobić, ponieważ gdy zmieniam html wewnątrz edytora, resetuje kursor na początek wstawionego elementu, co jest problemem, ponieważ zmieniam zawartość w locie jako typ użytkownika.

Jeśli wiem, że chcę ustawić kursor z powrotem na znaną pozycję postaci, powiedzmy 100, wewnątrz edytora, czy jest to możliwe?

(zadałem podobne pytanie ale myślę, że był zbyt skomplikowany problem z przykładowym kodem.)

Author: Community, 2013-05-30

2 answers

Podstawowym sposobem ustawienia wyboru jest utworzenie A zakres , ustawienie jego pozycji i wybranie to.

Uwaga: jeśli nie znasz interfejsu API zakresu (lub przynajmniej idei, która stoi za zakresami), nie będziesz mógł użyć selekcji. Oto całkiem dobre wprowadzenie- Dom Range spec (tak, jest to spec, ale jest dobry). CKEditor ' s Range API jest bardzo podobne, ale trochę większe.

Dla przykład:

// Having this HTML in editor:
// <p id="someId1">foo <em id="someId2">bar</em>.</p>

var range = editor.createRange();
range.setStart( editor.document.getById( 'someId1' ), 0 ); // <p>^foo
range.setEnd( editor.document.getById( 'someId2' ).getFirst(), 1 ); // <em>b^ar</em>

editor.getSelection().selectRanges( [ range ] );

// Will select:
// <p id="someId1">[foo <em id="someId2">b]ar</em>.</p>

Lub inny przypadek:

// Having this HTML in editor:
// <p>foo bar.</p>
var range = editor.createRange();
range.moveToElementEditablePosition( editor.editable(), true ); // bar.^</p>

editor.getSelection().selectRanges( [ range ] );

// Will select:
// <p>foo bar.^</p>

Przywracanie wyboru po zmianie DOM

Ale bardzo często nie chcesz wybierać nowego zakresu, ale przywrócić stary wybór lub zakres. Pierwszą rzeczą, którą musisz wiedzieć, jest to, że niemożliwe jest prawidłowe przywrócenie wyboru, jeśli dokonałeś niekontrolowanej zmiany DOM. Musisz być w stanie śledzić kontenery i przesunięcia początku i końca selekcji.

Range zachowuje odniesienia do swoich kontenery start i end (we właściwościach startContainer i endContainer). Niestety, odniesienia te mogą zostać naruszone przez: {]}

  • nadpisanie innerHTML,
  • przenoszenie węzłów DOM,
  • usuwanie węzłów DOM.

To samo może się zdarzyć w przypadku offsetów ( właściwościstartOffset i endOffset) - Jeśli usuniesz jeden z węzłów potomnych kontenera start/end, te offsety mogą wymagać aktualizacji.

Więc w niektórych sytuacjach instancja range nie jest pomocna, gdy chcemy zapamiętać zaznaczenie pozycji. Wyjaśnię trzy podstawowe sposoby radzenia sobie z tym problemem.

Po pierwsze, to jest nasz plan:]}
  1. otrzymujemy aktualną pozycję wyboru.
  2. przechowujemy go (jakoś).
  3. dokonujemy zmian DOM.
  4. przywracamy zaznaczenie.

Uwaga: od teraz używam "ranges" w liczbie mnogiej, ponieważ Firefox obsługuje wiele selekcji zakresu - jedna selekcja może zawierać więcej niż jeden zakres (spróbuj np. użyć klawisza CTRL podczas tworzenia wybór).

Rozwiązanie 1 - przez zakres

var ranges = editor.getSelection().getRanges();

// Make DOM changes.

editor.getSelection().selectRanges( ranges );
To najprostsze rozwiązanie. Będzie to działać tylko wtedy, gdy wprowadzone przez nas zmiany DOM nie mają przestarzałych zakresów lub wiemy, jak je zaktualizować.

Rozwiązanie 2-przez natrętne zakładki

var bookmarks = editor.getSelection().createBookmarks();

// Make DOM changes.

editor.getSelection().selectBookmarks( bookmarks );

Zakładki utworzone przez createBookmarks metoda Wstaw niewidoczne elementy {[11] } ze specjalnymi atrybutami (w tym data-cke-bookmark) w punktach początkowych i końcowych zaznaczenia.

Jeśli można uniknąć niekontrolowanego innerHTML zmienia i zamiast dodawać/usuwać/przenosić niektóre węzły, pamiętaj tylko, że musisz zachować te <span> elementy i ta metoda będzie działać idealnie. Można również przenosić elementy zakładek, jeśli modyfikacje powinny również zmienić zaznaczenie.

Domyślnie zakładki przechowują odniesienia do swoich elementów <span>, ale można również tworzyć zakładki serializowalne przechodząc true DO METODY createBookmarks. Tego rodzaju zakładki zachowają odniesienia do węzłów według identyfikatorów, dzięki czemu można zastąp całość innerHTML.

Uwaga: ta metoda jest również dostępna w API zakresu .

Jest to najpopularniejsza metoda, ponieważ masz pełną kontrolę nad wyborem i możesz zmienić DOM, chociaż musisz zadbać o zakładki' spans.

Rozwiązanie 3 - przez nieinwazyjną zakładkę

var bookmarks = editor.getSelection().createBookmarks2();

// Make DOM changes.

editor.getSelection().selectBookmarks( bookmarks );

Uwaga: w tym rozwiązaniu używamy createBookmarks2 metoda.

Tutaj również tworzymy tablicę obiektów zakładek, ale robimy nie wstawia żadnych elementów do DOM. Te zakładki przechowują swoje pozycje według adresów. adres jest tablicą indeksów przodków w ich rodzicach.

To rozwiązanie jest bardzo podobne do rozwiązania 1, ale można nadpisać całe innerHTML, ponieważ (najprawdopodobniej;>) nie zmieni adresów węzłów zakładek. Chociaż w takim przypadku należy przekazać true do createBookmarks2, aby uzyskać znormalizowane adresy, ponieważ sąsiednie węzły tekstowe zostaną połączone, a puste usunięte podczas ustawiania innerHTML.

Podsumowując...

... Praca z DOM i selekcja nie jest trywialna. Musisz wiedzieć, co robisz, musisz znać DOM i musisz wybrać odpowiednie rozwiązanie dla swojego problemu. Najczęściej będzie to drugi, ale zależy to od przypadku.

 47
Author: Reinmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-31 14:21:50

ODPOWIEDŹ Reinmara doprowadziła mnie do tego rozwiązania

var selection = ed.getSelection();
var bookmarks = selection.createBookmarks(true);

//delete text from editor

var range = selection.getRanges()[0];
range.moveToBookmark(bookmarks[0]);
range.select();

Uwaga: funkcja moveToBookmark nie jest udokumentowana w api, ale była niezwykle przydatna i była jedynym rozwiązaniem, które działało dla mnie. Na pewno nie jestem ekspertem od ckeditor i zajęło mi kilka dni, aby znaleźć działające rozwiązanie. Więc moveToBookmark może przestarzała funkcja, której nie jestem pewien.

 7
Author: codeAline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-05 10:22:12