На самом деле, если подумать - я не могу найти подходящего нативного события для решения этой проблемы.
Дело в том, что ... каретка может быть задана разными способами: щелчком, выбором (который может начинаться или заканчиваться в области, которую вы хотите обнаружить), событиями клавиатуры, перемещающими курсор, или даже внешними сценариями.
Нет события, которое захватило бы их всех.
К сожалению, я считаю, что единственный способ сделать это - выполнить цикл и проверить, соответствует ли текущий выбор (который содержит данные каретки).
Чтобы включить то, что вы хотите, я реализовал новый элемент, используя 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>