Я делаю веб-приложение для проверки регулярных выражений. У меня есть вход, где я ввожу регулярное выражение и contenteditable pre элемент, где я вводю текст, где совпадения найдены и выделены.

Пример: при условии, что регулярное выражение равно ab, если пользователь вводит abcab в элементе pre, и регулярное выражение, и текст отправляются в API, реализованный мною, который возвращает

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>

И эта строка установлена как innerHTML элемента pre

Эта операция выполняется каждый раз, когда пользователь редактирует содержимое элемента pre (точнее, событие keyup). У меня есть проблема (и я надеюсь, что вы сможете решить), что каждый раз, когда устанавливается innterHTML, каретка помещается в начале, и я хочу, чтобы она была размещена сразу после последнего ввода символов пользователем. Любые предложения о том, как узнать, где находится каретка и как ее разместить в желаемой позиции? Благодарю.

ОБНОВЛЕНИЕ . Для лучшего понимания ... Наглядный пример: Regexp - это ab, и в элементе contenteditable мы имеем:

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>

Затем я набираю a c между первым a и первым b, так что теперь мы имеем:

    acbc<span style='background-color: lightgreen'>ab</span>

В этот момент каретка вернулась к началу contenteditable элемента, и она должна быть размещена сразу после ввода c. Это то, чего я хочу достичь, надеюсь, теперь это более понятно.

< Сильный > UPDATE2

function refreshInnerHtml() {
  document.getElementById('textInput').innerHTML = "<span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>";
}
      <pre contenteditable onkeyup="refreshInnerHtml()" id="textInput" style="border: 1px solid black;" ></pre>
1
user8469305 30 Авг 2017 в 23:02

3 ответа

Лучший ответ

С некоторой помощью этих функций отсюда ->

Добавить элемент до / после выделения текста

Я создал кое-что, что я считаю твоим после Я в основном помещаю некоторые временные теги в HTML, где находится текущий курсор. Затем я отображаю новый HTML, затем заменяю теги span диапазоном с атрибутом data-cpos. Используя это, я затем снова выбираю курсор.

var insertHtmlBeforeSelection, insertHtmlAfterSelection;

(function() {
    function createInserter(isBefore) {
        return function(html) {
            var sel, range, node;
            if (window.getSelection) {
                // IE9 and non-IE
                sel = window.getSelection();
                if (sel.getRangeAt && sel.rangeCount) {
                    range = window.getSelection().getRangeAt(0);
                    
                    range.collapse(isBefore);
        
                    // Range.createContextualFragment() would be useful here but is
                    // non-standard and not supported in all browsers (IE9, for one)
                    var el = document.createElement("div");
                    el.innerHTML = html;
                    var frag = document.createDocumentFragment(), node, lastNode;
                    while ( (node = el.firstChild) ) {
                        lastNode = frag.appendChild(node);
                    }
                    range.insertNode(frag);
                }
            } else if (document.selection && document.selection.createRange) {
                // IE < 9
                range = document.selection.createRange();
                range.collapse(isBefore);
                range.pasteHTML(html);
            }
        }
    }
    
    insertHtmlBeforeSelection = createInserter(true);
    insertHtmlAfterSelection = createInserter(false);
})();




function refreshInnerHtml() {
  var
    tag_start = '⇷',  //lets use some unicode chars unlikely to ever use..
    tag_end = '⇸',
    sel = document.getSelection(),
    input = document.getElementById('textInput');
   
  //remove old data-cpos
  [].forEach.call(
    input.querySelectorAll('[data-cpos]'),
    function(e) { e.remove() });
  
  //insert the tags at current cursor position
  insertHtmlBeforeSelection(tag_start);
  insertHtmlAfterSelection(tag_end);
  
  //now do our replace
  let html = input.innerText.replace(/(ab)/g, '<span style="background-color: lightgreen">$1</span>');
  input.innerHTML = html.replace(tag_start,'<span data-cpos>').replace(tag_end,'</span>');
  
  //now put cursor back 
  var e = input.querySelector('[data-cpos]');
  if (e) {
    var range = document.createRange();
    range.setStart(e, 0);
    range.setEnd(e, 0);
    sel.removeAllRanges();
    sel.addRange(range);  
  }
}

refreshInnerHtml();
Type some text below, with the letters 'ab' somewhere within it. <br>

<pre contenteditable onkeyup="refreshInnerHtml()" id="textInput" style="border: 1px solid black;" >It's about time.. above and beyond</pre>
0
Keith 31 Авг 2017 в 01:20
<html>
	<head>
	<script>	
		function test(inp){
			document.getElementById(inp).value = document.getElementById(inp).value; 
		}

	</script>
	</head>
	<body> 
		<input id="search" type="text" value="mycurrtext" size="30" 
       onfocus="test(this.id);" onclick="test(this.id);" name="search"/>
	</body> 
</html>

Я быстро сделал это, и он помещает курсор в конец строки в поле ввода. Онклик - это когда пользователь вручную нажимает на ввод, а онфокус - когда пользователь вкладывает вкладку.

<input id="search" type="text" value="mycurrtext" size="30" 
   onfocus="test(this.id);" onclick="test(this.id);" name="search"/>

function test(inp){
        document.getElementById(inp).value = document.getElementById(inp).value;  
    }
0
schylake 30 Авг 2017 в 20:25

Чтобы упростить выбор, я добавил еще один тег span, в котором ничего нет, и присвоил ему атрибут data-end, чтобы его было легко выбирать.

Затем я просто создаю диапазон из этого и использую window.getSelection addRange, чтобы применить его.

Обновление: изменено для размещения каретки после первого ab

var e = document.querySelector('[data-end]');
var range = document.createRange();
range.setStart(e, 0);
range.setEnd(e, 0);

document.querySelector('[contenteditable]').focus();
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
<div contenteditable="true">
  <span style='background-color: lightgreen'>ab</span><span data-end></span>c<span style='background-color: lightgreen'>ab</span>
</div>
0
Keith 30 Авг 2017 в 21:45