Событие пожара, когда каретка вводится в элемент span - PullRequest
0 голосов
/ 29 июня 2018

У меня есть редактируемый div с содержимым со следующим диапазоном:

<div contenteditable="true">some <span>spanned</span> text</div>

И я хотел бы знать, есть ли какие-либо прослушиватели событий, которые я могу прикрепить к самому элементу span, который можно использовать для обнаружения перемещения каретки внутри элемента span.

Я не ищу ответа, если к div подключены слушатели, которые выполняют проверку каждый раз, когда в div появляется активность, например решение этого ответа:

Запуск события, когда каретка попадает в определенный тег div / span / a, а также, когда каретка покидает тег

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

На самом деле, если подумать - я не могу найти подходящего нативного события для решения этой проблемы.

Дело в том, что ... каретка может быть задана разными способами: щелчком, выбором (который может начинаться или заканчиваться в области, которую вы хотите обнаружить), событиями клавиатуры, перемещающими курсор, или даже внешними сценариями.

Нет события, которое захватило бы их всех.

К сожалению, я считаю, что единственный способ сделать это - выполнить цикл и проверить, соответствует ли текущий выбор (который содержит данные каретки).

Чтобы включить то, что вы хотите, я реализовал новый элемент, используя CustomElements , Реализация в основном о том, чтобы позволить вам использовать любой синтаксис, который вы хотите - будь то: myElement.dispatchEvent('caretin') или просто используя синтаксис html-тега <caret-detector oncaretin="myFunction(event,'myArg')"></caret-detector>.

Я не утверждаю, что это лучшая идея, ни лучшая реализация текущей идеи, но я думаю, что она охватывает все случаи с использованием одного цикла и нативного подхода js / html.

//Create Appropriate Events And initialize them
var CaretInEvent = document.createEvent('Event'),
		CaretOutEvent = document.createEvent('Event');
CaretInEvent.initEvent('caretin',true,true);
CaretOutEvent.initEvent('caretout',true,true);

//Next section will provide the caret handling functionallity
const CaretDetectorTagName = "caret-detector";
class CaretDetector extends HTMLElement {
      //these will be used in order to support switching element in focus
	static get lastDetected(){
		return CaretDetector._lastDetected;
	}
	static set lastDetected(element){
		CaretDetector._lastDetected = element;
	}
    //the interval
	static detectorStart(){
		setInterval(function(){
			let focusNode = document.getSelection().focusNode;
			if(focusNode){
				focusNode = focusNode.parentNode.closest(CaretDetectorTagName) || focusNode.parentNode;
				if(CaretDetector.lastDetected && focusNode !== CaretDetector.lastDetected && CaretDetector.lastDetected.inStatus === true && CaretDetector.lastDetected.triggerCaretOut){
					CaretDetector.lastDetected.dispatchEvent(CaretOutEvent);
				}
				if(focusNode.triggerCaretIn && focusNode.inStatus !== true){
					focusNode.dispatchEvent(CaretInEvent);
					CaretDetector.lastDetected = focusNode;
				}
			}
		},100);
	}
	//start with listening to the mentioned events
	constructor(){
		super();
		this._instatus = false;
		this.addEventListener('caretin', (...args)=>{
			this._instatus = true;
			this.triggerCaretIn(...args);
		});
		this.addEventListener('caretout', (...args)=>{
			this._instatus = false;
			this.triggerCaretOut(...args);
		});
	}
			
	get inStatus(){
		return this._instatus;
	}
			
	triggerCaretIn(event){
		let desiredFn = this.getAttribute('oncaretin'),
		wrapperFunction = new Function('event',`${desiredFn};`);
		wrapperFunction(event);	
	}
			
	triggerCaretOut(event){
		let desiredFn = this.getAttribute('oncaretout'),
		wrapperFunction = new Function('event',`${desiredFn};`);
		wrapperFunction(event);	
	}
}
    
//actually connect the tag-name with the above class
customElements.define(CaretDetectorTagName, CaretDetector);

//the functions you want to execute when caret is in or out
function inFn(event){
	console.log(event.srcElement.id + ": in");
}

function outFn(event){
	console.log(event.srcElement.id + ": out");
}
		
window.onload = CaretDetector.detectorStart;
<div contenteditable="true">
	012345
	<caret-detector id="object1" oncaretin="inFn(event)" oncaretout="outFn(event)">STRING OF OBJECT 1</caret-detector>
	<caret-detector id="object2" oncaretin="inFn(event)" oncaretout="outFn(event)">STRING OF OBJECT 2</caret-detector>
</div>
0 голосов
/ 29 июня 2018

Вы можете использовать MutationObserver . И проверьте characterData изменения в обратном вызове наблюдателя.

Вот пример:

var MutationObserver = 
		window.MutationObserver || 
		window.WebKitMutationObserver || 
		window.MozMutationObserver;

var config = { childList: true, characterData: true, characterDataOldValue:true, subtree: true };

var target = document
.querySelector('div[contenteditable]')
.getElementsByTagName('span')
.item(0);

var observer = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		if (mutation.type === 'characterData') {
			console.clear();
			console.log('old value:', mutation.oldValue);
			console.log('new value:', mutation.target.textContent);
		}
	});
});

observer.observe(target, config);
<div contenteditable="true">some <span>spanned</span> text</div>

Чтобы проверить, что каретка только что вошла в span, простой слушатель click должен выполнить эту работу.

var target = document
.querySelector('div[contenteditable]')
.getElementsByTagName('span')
.item(0)
.addEventListener('click', function(evt) {
	console.log('caret entered:', evt.target)
})
<div contenteditable="true">some <span>spanned</span> text</div>
...