Implement text replacement feature in textarea elements

This commit is contained in:
Aljaž Grilc 2024-03-19 14:03:57 +01:00
parent dbecc61ec3
commit 385e38c06d

View File

@ -18,6 +18,7 @@ class BesService {
this.scrollPanel = scrollPanel this.scrollPanel = scrollPanel
this.statusIcon = statusIcon this.statusIcon = statusIcon
this.offsetTop = null this.offsetTop = null
this.textAreaService = null
this.originalSpellcheck = hostElement.spellcheck this.originalSpellcheck = hostElement.spellcheck
this.abortController = new AbortController() this.abortController = new AbortController()
hostElement.spellcheck = false hostElement.spellcheck = false
@ -37,12 +38,13 @@ class BesService {
* @param {Element} hostElement DOM element to register grammar checking service for * @param {Element} hostElement DOM element to register grammar checking service for
* @returns {BesService} Grammar checking service instance * @returns {BesService} Grammar checking service instance
*/ */
static register(hostElement) { static register(hostElement, textAreaService) {
let service = new BesService(hostElement) let service = new BesService(hostElement)
service.proof(hostElement) service.proof(hostElement)
if (service.statusIcon.classList.contains('bes-status-loading')) { if (service.statusIcon.classList.contains('bes-status-loading')) {
service.updateStatusIcon('bes-status-success') service.updateStatusIcon('bes-status-success')
} }
if (textAreaService) service.textAreaService = textAreaService
return service return service
} }
@ -530,7 +532,7 @@ class BesService {
if (m.rects) { if (m.rects) {
for (let r of m.rects) { for (let r of m.rects) {
if (BesService.isPointInRect(clientX, clientY, r)) { if (BesService.isPointInRect(clientX, clientY, r)) {
popup.changeText(m.match.message) popup.changeMessage(m.match.message)
m.match.replacements.forEach(replacement => { m.match.replacements.forEach(replacement => {
popup.appendReplacements( popup.appendReplacements(
el, el,
@ -556,6 +558,9 @@ class BesService {
this.abortController.abort() this.abortController.abort()
match.range.deleteContents() match.range.deleteContents()
match.range.insertNode(document.createTextNode(replacement)) match.range.insertNode(document.createTextNode(replacement))
if (this.textAreaService) {
this.textAreaService.handleReplacement(this.hostElement)
}
this.clearMistakeMarkup(el) this.clearMistakeMarkup(el)
// In my opinion, this approach provides the most straightforward solution for repositioning mistakes after a change. // In my opinion, this approach provides the most straightforward solution for repositioning mistakes after a change.
// It maintains reasonable performance as it only checks the block element that has been modified, // It maintains reasonable performance as it only checks the block element that has been modified,
@ -677,7 +682,7 @@ class BesTAService {
this.textAreaEl = textAreaEl this.textAreaEl = textAreaEl
this.textAreaEl.spellcheck = false this.textAreaEl.spellcheck = false
this.cloneDiv = this.createCloneDiv(textAreaEl) this.cloneDiv = this.createCloneDiv(textAreaEl)
this.service = BesService.register(this.cloneDiv) this.service = BesService.register(this.cloneDiv, this)
this.textAreaEl.addEventListener('input', () => this.handleInput()) this.textAreaEl.addEventListener('input', () => this.handleInput())
this.textAreaEl.addEventListener('click', e => { this.textAreaEl.addEventListener('click', e => {
//TODO: Consider adding some kind of proofing? //TODO: Consider adding some kind of proofing?
@ -731,6 +736,11 @@ class BesTAService {
this.cloneDiv.dispatchEvent(customEvent) this.cloneDiv.dispatchEvent(customEvent)
} }
// TODO: think of a way to reposition the cursor after the replacement
handleReplacement(el) {
this.textAreaEl.value = el.outerText
}
/** /**
* Registers grammar checking service * Registers grammar checking service
* *
@ -867,7 +877,7 @@ class BesPopupEl extends HTMLElement {
} }
} }
changeText(text) { changeMessage(text) {
this.clear() this.clear()
this.shadowRoot.querySelector('.popup-text').textContent = text this.shadowRoot.querySelector('.popup-text').textContent = text
} }