#javascript #contenteditable #assistant
#javascript #удовлетворяемый #помощник #редактируемый контент
Вопрос:
Я создал работающий пример помощника по контенту в редактируемой области html-документа. Таким образом, если пользователь нажимает ctrl и пробел на клавиатуре, появляется контекстное меню. В настоящее время (см. демонстрацию ниже) контекстное меню находится в правой y-позиции (ниже текста). Но это не совпадает с осью x (если текст станет длиннее, поле будет посеяно в начале строки).
Можете ли вы помочь мне решить эту проблему?
Приветствую, мифбу
Пример кода:
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Test</title>
<script type="text/javascript">
var iframe = null, iwindow = null, iDocument = null;
function setUpInput() {
iframe = document.createElement( 'iframe' );
iframe.setAttribute( 'id', 'iframe-test' );
iframe.setAttribute( 'frameborder', 0 );
iframe.setAttribute( 'style', 'width:100%; height:100%;border: solid 1px red;' );
document.getElementById( "input" ).appendChild( iframe );
iwindow = iframe.contentWindow;
idocument = iwindow.document;
idocument.open();
idocument.write("<p></p>");
idocument.close();
idocument.body.setAttribute( 'spellcheck', false );
idocument.body.setAttribute( 'style', 'font-family: Consolas,serif;font-size: 0.8em;' );
idocument.body.contentEditable = true;
iwindow.onkeydown = function(e) {
if (e.ctrlKey amp;amp; e.keyCode == 32) {
createSuggestObject();
return false;
}
if (e.ctrlKey) return false;
};
iwindow.onkeypress = function(e) {if (e.ctrlKey) return false;};
}
function createSuggestObject() {
suggest = new Object();
suggest.box = document.createElement( 'div' );
suggest.box.style.position = 'absolute';
suggest.box.style.width = '120px';
suggest.box.style.overflow = 'auto';
suggest.box.style.border = '1px solid #BEC7E4';
suggest.box.style.display = 'block';
suggest.box.style.marginTop = '16px';
suggest.box.innerHTML = "Example 1";
document.body.appendChild( suggest.box )
var position = iframe.getBoundingClientRect();
var selObj = iwindow.getSelection();
var selRange = selObj.getRangeAt(0);
var p2 = selObj.anchorNode.parentNode.getBoundingClientRect();
suggest.box.style.top = Math.round( window.scrollY position.top p2.top) 'px';
suggest.box.style.left = Math.round( window.scrollX position.left p2.left) 'px';
}
window.onload = function() {
setUpInput();
};
</script>
</head>
<body>
<div id="input"></div>
</body>
</html>
Ответ №1:
Основная проблема с вашим решением заключалась в том, что вы использовали ограничивающий прямоугольник элемента p (который, как вы предполагали, содержал текст, введенный пользователем) в качестве ссылки на то, где разместить предлагаемый объект.
Во-первых, вы не учли ширину ограничивающего прямоугольника в позиции предлагаемого объекта, поэтому ваше поле для предложений оставалось слева независимо от длины текста.
Однако этот подход в конечном итоге потерпит неудачу, потому что, если текст будет содержать более одной строки (где вторая строка будет короче первой), ширина ограничивающего прямоугольника будет равна длине первой строки (более или менее). Следовательно, объект предложения будет расположен неправильно.
Моей первой идеей о том, как исправить ваш код, было добавить к тексту какой-нибудь встроенный элемент (маяк, если хотите), измерить его положение, удалить его из DOM и использовать это вычисленное положение для правильной установки объекта предложения.
Оказалось, что это почти сработало. Почти, потому что, как оказалось, разные браузеры используют разные методы обработки редактируемых окончаний строк. Firefox, например, вставляет <br _moz_dirty=""/>
в конце строки, в то время как Chrome этого не делает. Итак, когда я попытался добавить свой элемент beacon после текста, он был добавлен после этого, <br/>
что снова привело к неправильному положению.
Решение состояло в том, чтобы изменить способ получения текстового узла, с которым мы имеем дело, и вставить маяк прямо перед его следующей публикацией.
Вот рабочий пример http://jsfiddle.net/MmKXS/10 /
Примечание 1: Я удалил добавление пустого <p></p>
элемента в документ iframe, поскольку в Chrome текст, введенный пользователем, не был вставлен в него, что вызвало еще одну проблему с позиционированием объекта предложения.
Примечание 2: На данный момент мое решение работает только для размещения объекта предложения в конце текста, не в позиции курсора, поскольку это потребовало бы разделения текстовых узлов, вставки маяка, проверки его положения и повторного объединения текстовых узлов. В зависимости от варианта использования, который у вас есть для этого кода, это может привести к снижению производительности и / или может потребовать изменения всего подхода к размещению вашего объекта предложения.