#javascript #html #dom #textselection
Вопрос:
В терминале jQuery я хочу добавить API, который будет возвращать индексы выбора.
Пример HTML у меня есть:
<div class="cmd" style="width: 100%; --cursor-line:1; top: 0px;">
<div class="cmd-wrapper" style="">
<span class="cmd-prompt" style="visibility: visible; margin-left: 0px;">
<span data-text=">amp;nbsp;">
<span style="width: 2ch;">amp;>amp;nbsp;</span>
</span>
</span>
<div role="presentation" aria-hidden="true" class="cmd-end-line">
<span data-text="H">
<span>H</span>
</span>
<span data-text="e">
<span>e</span>
</span>
<span data-text="l">
<span>l</span>
</span>
<span data-text="l">
<span>l</span>
</span>
<span data-text="o">
<span>o</span>
</span>
<span data-text="amp;nbsp;">
<span>amp;nbsp;</span>
</span>
<span data-text="W">
<span>W</span>
</span>
<span data-text="o">
<span>o</span>
</span>
<span data-text="r">
<span>r</span>
</span>
<span data-text="l">
<span>l</span>
</span>
<span data-text="d">
<span>d</span>
</span>
<span data-text="amp;nbsp;">
<span>amp;nbsp;</span>
</span>
</div>
<div class="cmd-cursor-line" role="presentation" aria-hidden="true">
<span>
<span data-text="x">
<span>x</span>
</span>
<span data-text="x">
<span>x</span>
</span>
<span data-text="x">
<span>x</span>
</span>
<span data-text="x">
<span>x</span>
</span>
<span data-text="x">
<span>x</span>
</span>
</span>
<span class="cmd-cursor" style="">
<span data-text="" class="end">
<span>amp;nbsp;<span></span></span>
</span>
</span>
<span></span>
</div>
</div>
<textarea autocapitalize="off" spellcheck="false" tabindex="1" class="cmd-clipboard" data-cmd-prompt=">amp;nbsp;" style=""></textarea>
</div>
Это копия-вставка DOM после ввода «Hello Worldnxxxxx», отформатированная и красиво напечатанная с использованием https://jsonformatter.org/html-pretty-print
Мой вопрос в том, что я должен сделать, чтобы получить индексы отбора?
Например, у меня есть такая команда:
> He|lo wor|d
Я должен получить [2, 8]
, и если выбор находится за пределами диапазона: пример
>|>> Hello| world
где >>>
подсказка, которую я должен получить [0, 5]
, меня не волнует негатив. Я также должен справляться, когда весь выбор находится снаружи
|>>>| Hello World
он должен возвращать [0, 0]
значение или значение null.
Как бы реализовать что-то подобное? Примечание: меня волнует только API window.getSelection, это 100% поддержка, не нужно быть глупым и поддерживать IE8.
Комментарии:
1. Я не понимаю: разве window.getSelection (с его начальным и конечным api) не является ответом?
2. @ControlAltDel, Где у вас есть начальный и конечный API в выборе, я не вижу его в MDN developer.mozilla.org/en-US/docs/Web/API/Selection
Ответ №1:
Вы хотите что-то вроде
var range = window.getSelection().getRangeAt(0);
var start = range.startOffset;
var end = range.endOffset;
Обратите внимание, что этот код предполагает, что range.startContainer === range.endContainer (что он часто делает). Если вы хотите получить текст / длину текста между начальным и конечным контейнерами, вам нужно рекурсивно пересечь DOM между ними. Существует также проблема, когда длина текста в DOM не совпадает с длиной текста в HTML (браузеры иногда добавляют пробелы и другие элементы HTML).
Вы были бы правы, если бы догадались, что я много работал в Javascript с выделениями. ИМО, это своего рода кошмар. Тим Даун написал очень популярный пакет под названием Rangy
, который я ему очень рекомендую. Вы должны проверить его и посмотреть, соответствует ли он требованиям того, что вы делаете.
Ответ №2:
Я сам решил эту проблему:
var selection = window.getSelection();
var start = $(selection.anchorNode);
var end = $(selection.focusNode);
var before = start.closest('.cmd [role="presentation"]').prevUntil('.cmd-prompt');
var count = 0;
if (before.length > 1) {
count = before.find('[data-text]').length;
}
var s = start.closest('.cmd [role="presentation"] [data-text]');
var e = end.closest('.cmd [role="presentation"] [data-text]');
if ((s.length || e.length)) {
start = count s.index();
end = count e.index() 1;
console.log({start, end});
}