Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Как вставить тег в нужное место div-a (https://javascript.ru/forum/dom-window/31398-kak-vstavit-teg-v-nuzhnoe-mesto-div.html)

Krjemelik 05.09.2012 22:42

Как вставить тег в нужное место div-a
 
У меня есть <div id="d" contenteditable="true">какой-то текст</div>
И есть кнопка <button onClick="Bold()">Bold</button>
Требуется при нажатии на кнопку (т.е. при вызове функции Bold) вставлять теги <b></b> в то место, этого div-a, где находится курсор
Вот такая сложная задача. :yes:

Rootpassword 05.09.2012 22:58

Определить элемент под курсором несложно, примеров много.
Единственная сложность-ваш див, если содержит текстовую информацию, например
12345678

то для определения, над каким именно символом расположено, каждый символ должен быть отдельным элементом в DOM, т.е. проходитесь и получаете что-то типа
<span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span>

Krjemelik 05.09.2012 23:05

Цитата:

Сообщение от Rootpassword (Сообщение 203235)
то для определения, над каким именно символом расположено, каждый символ должен быть отдельным элементом в DOM, т.е. проходитесь и получаете что-то типа
<span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span>

Эх, ты... :blink: не, не годится. Этот див потом отправляется на сервер. Получается слишком крутое увеличение трафика... Нужно что-то другое.

Rootpassword 05.09.2012 23:12

Перед отправкой структуру дива можно почистить от ненужных вам span-ов.

Krjemelik 05.09.2012 23:13

Хотя, я тут подумал... Может как раз перед отправкой обработать текст и удалить ненужные теги... Ну, что ж, спасибо за решение. Хотя бы так.

Но неужели не существует способа точно определить в каком месте текста в div-e находится курсор?

P.S. Не заметил Вашего предыдущего сообщения :)

Rootpassword 05.09.2012 23:18

Нет, отчего же. Координаты вы можете получить, но и только, эта информация бесполезна. То есть вы не сможете в структуру DOM вставить нужный вам элемент в точку (122,834)

Krjemelik 05.09.2012 23:21

Да, похоже, это единственный способ. Еще раз спасибо.

Aetae 06.09.2012 03:49

Rootpassword, что за бредни?
В нормальных браузерах есть rangeOffset и rangeParent:
<div style="cursor:pointer" onclick = "nextSibling.data += event.rangeParent.data.charAt( event.rangeOffset ) + ', ';">
    <b><i>Такие </i>дела,</b> братюня.
</div>
clicked:

А в осле наверняка есть аналоги.

Если вы чего-то не знаете или не умеете, это совершенно не значит что такого не существует.
Заморочили голову человеку. =(

Krjemelik 06.09.2012 08:58

Aetae, да, для MSIE есть аналог, нашел. Для Хрома и Сафари вроде, тоже есть какие-то костылики. Будем разбираться, спасибо большое. :)

Rootpassword 06.09.2012 11:34

И как, позвольте поинтересоваться, вы будете вставлять новый элемент в произвольное место страницы, если insertBefore хочет ссылку на нод, а пятый текстовый символ нодом не является?

Aetae 06.09.2012 12:13

Цитата:

Сообщение от Rootpassword (Сообщение 203296)
И как, позвольте поинтересоваться, вы будете вставлять новый элемент в произвольное место страницы, если insertBefore хочет ссылку на нод, а пятый текстовый символ нодом не является?

Элементарно, ватсон, если использовать чистый DOM:
<div style="cursor:pointer" onclick = "a(event,this)">
    Такие дела, братюня.
</div>
<script type="text/javascript">
function a(e,t){
	var textnode = e.rangeParent, node = textnode.parentNode, fragment = document.createDocumentFragment();
	
	fragment.appendChild( document.createTextNode( textnode.data.slice(0,e.rangeOffset) ) )
	fragment.appendChild( document.createElement('b') ).appendChild( document.createTextNode( textnode.data.slice(e.rangeOffset,e.rangeOffset+1) ) )
	fragment.appendChild( document.createTextNode( textnode.data.slice(e.rangeOffset+1) ) )

	node.replaceChild(fragment, textnode)
	
	t.nextSibling.data = t.innerHTML;
}
</script>

но на самом деле это всё делается с помощью Selection и Range:
<div contenteditable="true" onmouseup = "a(event,this)">
    Такие дела, братюня.
</div>
<script type="text/javascript">
function a(e,t){
	var range = window.getSelection().getRangeAt(0);
	range.surroundContents(document.createElement('b'));
	
	t.nextSibling.data = t.innerHTML;
}
</script>

Rootpassword 06.09.2012 12:53

Первый вариант работает только в FF. Но идея ясна, я решил, что мигать контент будет из-за замены(replaceChild).
Второй вариант фейлится в ИЕ, в старом FF(баг).
Мой вариант хреновый, но реализуется в 3 строчки на фреймворке типа jQuery и вполне рабочий даже в ИЕ6-7-8, которые некоторые все еще вынуждены поддерживать.

Aetae 08.09.2012 22:14

В осле не работает потому, что в нём совершенно друная реализация selection, и мне лень было писать вариант для него.
Ваш фэйл не в предложенном вами методе(он подходит для случаев с парой слов), а в том что вы отрицали возможность сделать это по-человечески.
Любая более-менее серьёзная работа с текстом идёт через selection.


Часовой пояс GMT +3, время: 02:31.