Fix <textarea>, cleanup...
This commit is contained in:
parent
00cb5aecd4
commit
0855c13384
303
service.js
303
service.js
@ -41,7 +41,7 @@ class BesService {
|
||||
this.enabledCategories = []
|
||||
this.disabledCategories = []
|
||||
this.results = [] // Results of grammar-checking, one per each block/paragraph of text
|
||||
this.highlightedRects = []
|
||||
this.highlightElements = []
|
||||
this.createCorrectionPanel()
|
||||
|
||||
// Disable browser built-in spell-checker to prevent collision with our grammar markup.
|
||||
@ -58,7 +58,7 @@ class BesService {
|
||||
this.hostElement.setAttribute('data-gramm', 'false')
|
||||
this.hostElement.setAttribute('data-gramm_editor', 'false')
|
||||
this.hostElement.setAttribute('data-enable-grammarly', 'false')
|
||||
this.textFont = window.getComputedStyle(this.textElement).fontFamily
|
||||
this.textFont = window.getComputedStyle(this.hostElement).fontFamily
|
||||
|
||||
this.onScroll = this.onScroll.bind(this)
|
||||
this.hostElement.addEventListener('scroll', this.onScroll)
|
||||
@ -334,8 +334,8 @@ class BesService {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.lineWidth = 2 * dpr // Use 2 for clearer visibility
|
||||
this.ctx.strokeStyle = ruleId.startsWith('MORFOLOGIK_RULE')
|
||||
? '#ff7300'
|
||||
: '#007bff'
|
||||
? 'rgba(255, 115, 0, 0.5)'
|
||||
: 'rgba(0, 123, 255, 0.5)'
|
||||
for (let rect of range.getClientRects()) {
|
||||
const x = (rect.left - scrollPanelRect.left) * dpr
|
||||
const y = (rect.top - scrollPanelRect.top) * dpr
|
||||
@ -455,7 +455,9 @@ class BesService {
|
||||
* @param {PointerEvent} source Click event source
|
||||
*/
|
||||
popupCorrectionPanel(el, match, source) {
|
||||
this.dismissPopup()
|
||||
const popup = document.querySelector('bes-popup-el')
|
||||
// TODO: popup.setContent(elements, matches, this, this.isContentEditable())
|
||||
popup.changeMessage(match.match.message)
|
||||
popup.appendReplacements(el, match, this, this.isContentEditable())
|
||||
this.highlightMistake(match)
|
||||
@ -469,27 +471,32 @@ class BesService {
|
||||
*/
|
||||
highlightMistake(match) {
|
||||
// TODO: Če sta 2 napaki v istem rectu, se prikaže samo zgornja/zadnja (oz. tista, ki jo uporabnik klikne). To pa pomeni, da se lahko podčrtana barva razlikuje od "highlight" barve.
|
||||
const highlightColor = match.match.rule.id.startsWith('MORFOLOGIK_RULE')
|
||||
? '#ff7300'
|
||||
: '#007bff'
|
||||
|
||||
match.highlights.forEach(highlight => {
|
||||
const rect = highlight
|
||||
const highlightElement = document.createElement('div')
|
||||
highlightElement.classList.add('highlight-rect')
|
||||
highlightElement.style.position = 'absolute'
|
||||
highlightElement.style.left = `${rect.x}px`
|
||||
highlightElement.style.top = `${rect.y}px`
|
||||
highlightElement.style.width = `${rect.width}px`
|
||||
highlightElement.style.height = `${rect.height}px`
|
||||
highlightElement.style.backgroundColor = highlightColor
|
||||
highlightElement.style.opacity = '0.5'
|
||||
highlightElement.style.cursor = 'text'
|
||||
document.body.appendChild(highlightElement)
|
||||
this.highlightedRects.push(highlightElement)
|
||||
match.highlights.forEach(rect => {
|
||||
const el = document.createElement('div')
|
||||
el.classList.add('bes-highlight-rect')
|
||||
el.classList.add(
|
||||
match.match.rule.id.startsWith('MORFOLOGIK_RULE')
|
||||
? 'bes-highlight-spelling-rect'
|
||||
: 'bes-highlight-grammar-rect'
|
||||
)
|
||||
el.style.left = `${rect.x}px`
|
||||
el.style.top = `${rect.y}px`
|
||||
el.style.width = `${rect.width}px`
|
||||
el.style.height = `${rect.height}px`
|
||||
document.body.appendChild(el)
|
||||
this.highlightElements.push(el)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears highlight and hides popup
|
||||
*/
|
||||
dismissPopup() {
|
||||
BesPopup.hide()
|
||||
this.highlightElements.forEach(el => el.remove())
|
||||
this.highlightElements = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if host element content is editable.
|
||||
*
|
||||
@ -764,34 +771,10 @@ class BesTreeService extends BesService {
|
||||
* @param {Element} el DOM element for removal
|
||||
*/
|
||||
clearProofing(el) {
|
||||
this.clearMarkup(el)
|
||||
this.results = this.results.filter(
|
||||
result => !BesTreeService.isSameParagraph(result.element, el)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears given block element grammar mistake markup.
|
||||
*
|
||||
* @param {Element} el DOM element we want to clean markup for
|
||||
*/
|
||||
clearMarkup(el) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.results
|
||||
.filter(result => BesTreeService.isSameParagraph(result.element, el))
|
||||
.forEach(result => {
|
||||
let sourceRect = result.element.getBoundingClientRect()
|
||||
let targetRect = this.canvasPanel.getBoundingClientRect()
|
||||
let newX = sourceRect.left - targetRect.left
|
||||
let newY = sourceRect.top - targetRect.top
|
||||
this.ctx.clearRect(
|
||||
newX * dpr,
|
||||
newY * dpr,
|
||||
sourceRect.width * dpr,
|
||||
sourceRect.height * dpr
|
||||
)
|
||||
delete result.matches
|
||||
})
|
||||
this.repositionAllMarkup()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -930,16 +913,15 @@ class BesTreeService extends BesService {
|
||||
|
||||
for (let result of this.results) {
|
||||
for (let m of result.matches) {
|
||||
for (let h of m.highlights) {
|
||||
if (BesService.isPointInRect(source.clientX, source.clientY, h)) {
|
||||
for (let rect of m.highlights) {
|
||||
if (BesService.isPointInRect(source.clientX, source.clientY, rect)) {
|
||||
this.popupCorrectionPanel(el, m, source)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BesPopup.hide()
|
||||
this.highlightedRects.forEach(h => h.remove())
|
||||
this.dismissPopup()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1024,8 +1006,7 @@ class BesDOMService extends BesTreeService {
|
||||
onInput() {
|
||||
// Now that the text is done changing, we can correctly calculate markup position.
|
||||
this.repositionAllMarkup()
|
||||
BesPopup.hide()
|
||||
this.highlightedRects.forEach(h => h.remove())
|
||||
this.dismissPopup()
|
||||
// Defer grammar-checking to reduce stress on grammar-checking server.
|
||||
this.scheduleProofing(1000)
|
||||
}
|
||||
@ -1536,30 +1517,10 @@ class BesPlainTextService extends BesService {
|
||||
* @param {Range} range Paragraph range
|
||||
*/
|
||||
clearProofing(range) {
|
||||
this.clearMarkup(range)
|
||||
this.results = this.results.filter(
|
||||
result => !BesPlainTextService.isSameParagraph(result.range, range)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears given paragraph grammar mistake markup.
|
||||
*
|
||||
* @param {Range} range Paragraph range
|
||||
*/
|
||||
clearMarkup(range) {
|
||||
this.results
|
||||
.filter(result =>
|
||||
BesPlainTextService.isSameParagraph(result.range, range)
|
||||
)
|
||||
.forEach(result =>
|
||||
result.matches.forEach(match => {
|
||||
if (match.highlights) {
|
||||
match.highlights.forEach(h => h.remove())
|
||||
delete match.highlights
|
||||
}
|
||||
})
|
||||
)
|
||||
this.repositionAllMarkup()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1605,16 +1566,15 @@ class BesPlainTextService extends BesService {
|
||||
|
||||
for (let result of this.results) {
|
||||
for (let m of result.matches) {
|
||||
for (let h of m.highlights) {
|
||||
if (BesService.isPointInRect(source.clientX, source.clientY, h)) {
|
||||
for (let rect of m.highlights) {
|
||||
if (BesService.isPointInRect(source.clientX, source.clientY, rect)) {
|
||||
this.popupCorrectionPanel(result.range, m, source)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BesPopup.hide()
|
||||
this.highlightedRects.forEach(h => h.remove())
|
||||
this.dismissPopup()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1729,8 +1689,7 @@ class BesDOMPlainTextService extends BesPlainTextService {
|
||||
|
||||
// Now that the text is done changing, we can correctly calculate markup position.
|
||||
this.repositionAllMarkup()
|
||||
BesPopup.hide()
|
||||
this.highlightedRects.forEach(h => h.remove())
|
||||
this.dismissPopup()
|
||||
// Defer grammar-checking to reduce stress on grammar-checking server.
|
||||
this.scheduleProofing(1000)
|
||||
}
|
||||
@ -1862,28 +1821,21 @@ class BesTAService extends BesPlainTextService {
|
||||
const styles = window.getComputedStyle(hostElement)
|
||||
|
||||
textElement.style.zIndex = hostElement.style.zIndex - 1
|
||||
textElement.style.fontSize = styles.fontSize
|
||||
textElement.style.fontFamily = styles.fontFamily
|
||||
textElement.style.font = styles.font
|
||||
textElement.style.lineHeight = styles.lineHeight
|
||||
textElement.style.whiteSpace = styles.whiteSpace
|
||||
textElement.style.whiteSpaceCollapse = styles.whiteSpaceCollapse
|
||||
textElement.style.hyphens = styles.hyphens
|
||||
textElement.style.boxSizing = styles.boxSizing
|
||||
textElement.style.scrollBehavior = styles.scrollBehavior
|
||||
textElement.style.overflow = 'hidden'
|
||||
textElement.style.border = styles.border
|
||||
textElement.style.borderRadius = styles.borderRadius
|
||||
textElement.style.paddingLeft = styles.paddingLeft
|
||||
textElement.style.paddingTop = styles.paddingTop
|
||||
textElement.style.paddingRight = styles.paddingRight
|
||||
textElement.style.paddingBottom = styles.paddingBottom
|
||||
textElement.style.height = styles.height
|
||||
textElement.style.minHeight = styles.minHeight
|
||||
textElement.style.maxHeight = styles.maxHeight
|
||||
textElement.style.overflow = styles.overflow
|
||||
textElement.style.overflowWrap = styles.overflowWrap
|
||||
textElement.style.top = `${rect.top + scrollTop}px`
|
||||
textElement.style.padding = styles.padding
|
||||
textElement.style.left = `${rect.left + scrollLeft}px`
|
||||
textElement.style.top = `${rect.top + scrollTop}px`
|
||||
textElement.style.width = styles.width
|
||||
textElement.style.minWidth = styles.minWidth
|
||||
textElement.style.maxWidth = styles.maxWidth
|
||||
textElement.style.height = styles.height
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2137,7 +2089,7 @@ class BesPopup extends HTMLElement {
|
||||
<div class="bes-popup-container">
|
||||
<div class="bes-toolbar">
|
||||
<div class="bes-popup-title">Besana</div>
|
||||
<button class="bes-close-btn" onclick="BesPopup.hide()">X</button>
|
||||
<button class="bes-close-btn" onclick="BesPopup.dismiss()">X</button>
|
||||
</div>
|
||||
<div class="bes-text-div">
|
||||
<span class="popup-text">
|
||||
@ -2210,7 +2162,7 @@ class BesPopup extends HTMLElement {
|
||||
replacementBtn.addEventListener('click', () => {
|
||||
if (allowReplacements) {
|
||||
service.replaceText(el, match, replacement.value)
|
||||
BesPopup.hide()
|
||||
service.dismissPopup()
|
||||
}
|
||||
})
|
||||
replacementDiv.appendChild(replacementBtn)
|
||||
@ -2274,167 +2226,24 @@ class BesPopup extends HTMLElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses all the popups.
|
||||
* Hides all the popups.
|
||||
*/
|
||||
static hide() {
|
||||
document.querySelectorAll('bes-popup-el').forEach(popup => {
|
||||
popup.classList.remove('show')
|
||||
})
|
||||
document.querySelectorAll('.bes-mistake-highlight-selected').forEach(el => {
|
||||
el.classList.remove('bes-mistake-highlight-selected')
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses all the popups.
|
||||
*/
|
||||
static dismiss() {
|
||||
besServices.forEach(service => service.dismissPopup())
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('bes-popup-el', BesPopup)
|
||||
|
||||
// /*************************************************************************
|
||||
// *
|
||||
// * Status pop-up
|
||||
// *
|
||||
// *************************************************************************/
|
||||
// class BesStatusPopup extends HTMLElement {
|
||||
// constructor() {
|
||||
// super()
|
||||
// this.attachShadow({ mode: 'open' })
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Called each time the element is added to the document
|
||||
// */
|
||||
// connectedCallback() {
|
||||
// this.shadowRoot.innerHTML = `
|
||||
// <style>
|
||||
// :host {
|
||||
// display: none;
|
||||
// }
|
||||
// :host(.show){
|
||||
// z-index: 10;
|
||||
// }
|
||||
// .popup-text {
|
||||
// max-width: 160px;
|
||||
// color: #333;
|
||||
// text-align: center;
|
||||
// padding: 8px 0;
|
||||
// z-index: 1;
|
||||
// }
|
||||
// .bes-popup-container {
|
||||
// visibility: hidden;
|
||||
// max-width: 300px;
|
||||
// background-color: #f1f3f9;
|
||||
// box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
|
||||
// border-radius: 5px;
|
||||
// padding: 8px;
|
||||
// z-index: 1;
|
||||
// }
|
||||
// .bes-toolbar {
|
||||
// display: flex;
|
||||
// justify-content: end;
|
||||
// padding: 5px 2px;
|
||||
// }
|
||||
// .bes-toolbar button {
|
||||
// margin-right: 2px;
|
||||
// }
|
||||
// .bes-popup-title {
|
||||
// flex-grow: 1;
|
||||
// }
|
||||
// .bes-text-div{
|
||||
// background-color: #eee;
|
||||
// padding: 10px;
|
||||
// border-radius: 5px;
|
||||
// }
|
||||
// .bes-service-btn{
|
||||
// background-color: none;
|
||||
// width: 30px;
|
||||
// height: 30px;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// }
|
||||
// .bes-turn-off{
|
||||
// width: 20px;
|
||||
// height: 20px;
|
||||
// }
|
||||
// :host(.show) .bes-popup-container {
|
||||
// visibility: visible;
|
||||
// animation: fadeIn 1s;
|
||||
// }
|
||||
// @keyframes fadeIn {
|
||||
// from {opacity: 0;}
|
||||
// to {opacity:1 ;}
|
||||
// }
|
||||
// </style>
|
||||
// <div class="bes-popup-container">
|
||||
// <div class="bes-toolbar">
|
||||
// <div class="bes-popup-title">Besana</div>
|
||||
// <button class="bes-close-btn" onclick="BesStatusPopup.hide()">X</button>
|
||||
// </div>
|
||||
// <div class="bes-text-div">
|
||||
// <span class="popup-text">
|
||||
// Če želite izključiti preverjanje pravopisa, kliknite na gumb.
|
||||
// </span>
|
||||
// <button class="bes-service-btn">
|
||||
// <img class="bes-turn-off" src="/images/turn-off-svgrepo-com.svg" alt="Izključi preverjanje pravopisa">
|
||||
// </button>
|
||||
// </div>
|
||||
// </div>
|
||||
// `
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Shows popup window.
|
||||
// *
|
||||
// * @param {Number} x X location hint
|
||||
// * @param {Number} y Y location hint
|
||||
// * @param {BesService} service Grammar checking service
|
||||
// */
|
||||
// show(x, y, service) {
|
||||
// this.style.position = 'fixed'
|
||||
// this.style.display = 'block'
|
||||
|
||||
// // Element needs some initial placement for the browser to provide this.offsetWidth and this.offsetHeight measurements.
|
||||
// // The fade-in effect on the popup window should prevent flicker.
|
||||
// this.style.left = `0px`
|
||||
// this.style.top = `0px`
|
||||
// this.classList.add('show')
|
||||
|
||||
// if (x + this.offsetWidth <= window.innerWidth) {
|
||||
// this.style.left = `${x}px`
|
||||
// } else if (this.offsetWidth <= x) {
|
||||
// this.style.left = `${x - this.offsetWidth}px`
|
||||
// } else {
|
||||
// this.style.left = `${x - this.offsetWidth / 2}px`
|
||||
// }
|
||||
|
||||
// if (y + 20 + this.offsetHeight <= window.innerHeight) {
|
||||
// this.style.top = `${y + 20}px`
|
||||
// } else if (this.offsetHeight <= y) {
|
||||
// this.style.top = `${y - this.offsetHeight}px`
|
||||
// } else {
|
||||
// this.style.top = `${y - this.offsetHeight / 2}px`
|
||||
// }
|
||||
|
||||
// if (service) {
|
||||
// const disableButton = this.shadowRoot.querySelector('.bes-service-btn')
|
||||
// disableButton.onclick = () => {
|
||||
// service.unregister()
|
||||
// BesStatusPopup.hide()
|
||||
// }
|
||||
// }
|
||||
// this.classList.add('show')
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Dismisses all the popups.
|
||||
// */
|
||||
// static hide() {
|
||||
// const popup = document.querySelector('bes-popup-status.show')
|
||||
// popup?.classList?.remove('show')
|
||||
// }
|
||||
// }
|
||||
|
||||
// customElements.define('bes-popup-status', BesStatusPopup)
|
||||
|
||||
// Auto-register all elements with bes-service class.
|
||||
window.addEventListener('load', () => {
|
||||
document
|
||||
|
26
styles.css
26
styles.css
@ -8,32 +8,26 @@
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* TODO: Cleanup */
|
||||
.bes-grammar-mistake {
|
||||
border-bottom: 2px solid #007bff;
|
||||
.bes-highlight-rect {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
opacity: 0.3;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.bes-highlight-spelling-rect {
|
||||
background: rgb(255, 115, 0);
|
||||
}
|
||||
|
||||
.bes-highlight-grammar-rect {
|
||||
background: rgb(0, 123, 255);
|
||||
}
|
||||
|
||||
.bes-canvas {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* TODO: Cleanup */
|
||||
.bes-spelling-mistake.bes-mistake-highlight-selected {
|
||||
background: #cc7024;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* TODO: Cleanup */
|
||||
.bes-grammar-mistake.bes-mistake-highlight-selected {
|
||||
background: #3691f3;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Styles required to ensure full functionality and optimal user experience. */
|
||||
.bes-correction-panel-parent {
|
||||
position: relative;
|
||||
|
Loading…
x
Reference in New Issue
Block a user