kukaew
@kukaew

Как жертве JQuery получить всех «детей» (элемент.childNodes[все дети]), неужели поочередным перебором?

Функция заменяет символы по ходу набора.
Как выбрать всех детей, чтоб замена работала и внутри детей?
Мой велосипед нормально поедет? Круглы ли его колёса? Где их можно округлить?
Спасибо.

jsfiddle.net/kukaew/xzhjvjjy

Напиши "--", чтоб получить "—":

<div id="edit" contenteditable="true" style="border: solid 1px #666; padding: 10px 20px">

Jimmy and Zack, the police explained, were last seen diving into a field of buttered quahogs.  

<p>Jimmy and <i>Zack, <b>the</b> police explained</i>, were <u>last seen <b>div i</b>nto a</u> field ofbuttered quahogs.</p>

</div>

$('#edit').off('keyup blur').on('keyup blur', function() {
	addsmile();
});

function addsmile() {
	var root = document.getElementById('edit').childNodes[0];
	var content = root.data;

	console.log(root);
	console.log(content);

	var arrIN = ['--','<<','>>','->','<-'];
	var arrOUT = ['—','«','»','→','←'];
	for (var i = 0; i < arrIN.length; i++) {
		var text = arrIN[i];
		if (~content.indexOf(text)) {
			var rng = document.createRange();
			rng.setStart(root, content.indexOf(text));
			rng.setEnd(root, content.indexOf(text) + text.length);
			window.getSelection().removeAllRanges();
			window.getSelection().addRange(rng);
			document.execCommand('insertText', false, arrOUT[i]);
		}
	}
}
  • Вопрос задан
  • 294 просмотра
Решения вопроса 1
sergiks
@sergiks Куратор тега JavaScript
♬♬
Выбрать дочерние узлы первого уровня можно через contents(). Но понадобится рекурсия. Когда очередной узел текстовый, в нём можно менять содержание, но если он элемент, то надо внутрь него лезть тем же contents()

RegExp'ы с глобальной заменой лучше простого replace на случай вставки Copy-Paste текста с большим количеством двойных дефисов, например. Поэтому же событие input, а не клавиатурные.

Кроме того жо.. сложность выскочила с позицией курсора: при замене содержимого он сползает в начало узла. Ок, можно получить Selection и запомнить Range до всех замен и потом восстановить. Но тут кроется вторая засада: при замене меняется длина текста: два дефиса на одно тире. Поэтому нужно ещё и ловить изменение длины текста при замене в узле, в котором находится курсор.

Вроде, получилось. Fiddle. Код:
var curNode
	  , startOffset
	  , arrIN = ['--','<<','>>','->','<-']
	  , arrOUT = ['—','«','»','→','←']
	;
	arrIN = arrIN.map(function(s){ return new RegExp(s,'g')});

	$('#edit').on('input', onInput);
	
	function onInput() {
		var selObj = window.getSelection()
		  , range  = selObj.getRangeAt(0)
		;
		curNode = range.startContainer;
		startOffset = range.startOffset;
		$(this).contents().each(walk);
		range.setStart(curNode, startOffset);
	}

	function walk(i, node){
		var len
		  , diff
		;
		if( node.nodeType === Node.TEXT_NODE) {
			len = node.textContent.length;
			node.textContent = replacer(node.textContent);
			diff = len - node.textContent.length;
			if( node === curNode && diff) {
				startOffset -= diff;
			}
		} else if( node.nodeType === Node.ELEMENT_NODE) {
			$(node).contents().each(walk);
		}
	}

	function replacer(s) {
		var i;
		for( i = 0; i < arrIN.length; i++) s = s.replace( arrIN[i], arrOUT[i]);
		return s;
	}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы