Compare commits
4 Commits
a507f24326
...
c27f9628f4
Author | SHA1 | Date | |
---|---|---|---|
c27f9628f4 | |||
ef0d35ccee | |||
2b54735175 | |||
9c2151f182 |
@ -91,8 +91,8 @@ Kategorije pravopisnih pravil so:
|
||||
|
||||
Privzeto servis uporablja podčrtovanje pravopisnih napak (nastavitev `'underline'`). Videz lahko spreminjamo.
|
||||
|
||||
<img src="samples/markup_underline.png" alt="underline" width="448"/>
|
||||
<img src="samples/markup_lector.png" alt="lector" width="448"/>
|
||||
<img src="samples/images/markup_underline.png" alt="underline" width="448"/>
|
||||
<img src="samples/images/markup_lector.png" alt="lector" width="448"/>
|
||||
|
||||
Levo `'underline'`, desno `'lector'`.
|
||||
|
||||
|
BIN
samples/images/markup_lector.png
Normal file
BIN
samples/images/markup_lector.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 201 KiB |
BIN
samples/images/markup_underline.png
Normal file
BIN
samples/images/markup_underline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 179 KiB |
Binary file not shown.
Before Width: | Height: | Size: 174 KiB |
Binary file not shown.
Before Width: | Height: | Size: 151 KiB |
99
service.js
99
service.js
@ -371,13 +371,19 @@ class BesService {
|
||||
if (match.highlights.length === 0) return
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.lineWidth = 2 * dpr // Use 2 for clearer visibility
|
||||
let amplitude = 0
|
||||
const ruleId = match.match.rule.id
|
||||
this.ctx.strokeStyle = ruleId.startsWith('MORFOLOGIK_RULE')
|
||||
? 'rgba(0, 123, 255, 0.8)'
|
||||
: 'rgba(255, 115, 0, 0.8)'
|
||||
this.ctx.fillStyle = ruleId.startsWith('MORFOLOGIK_RULE')
|
||||
? 'rgba(0, 123, 255, 0.8)'
|
||||
: 'rgba(255, 115, 0, 0.8)'
|
||||
if (ruleId.startsWith('MORFOLOGIK_RULE')) {
|
||||
const styles = window.getComputedStyle(this.highlightSpelling)
|
||||
this.ctx.strokeStyle = styles.color
|
||||
this.ctx.fillStyle = styles.color
|
||||
amplitude = -1
|
||||
} else {
|
||||
const styles = window.getComputedStyle(this.highlightGrammar)
|
||||
this.ctx.strokeStyle = styles.color
|
||||
this.ctx.fillStyle = styles.color
|
||||
amplitude = 1
|
||||
}
|
||||
let markerY1, markerY2
|
||||
switch (this.markupStyle) {
|
||||
case 'lector':
|
||||
@ -681,7 +687,7 @@ class BesService {
|
||||
const x2 = rect.right
|
||||
const y = rect.bottom
|
||||
const scale = (rect.bottom - rect.top) / 18
|
||||
this.drawAttentionRequired(x1, x2, y, scale)
|
||||
this.drawAttentionRequired(x1, x2, y, amplitude, scale)
|
||||
}
|
||||
|
||||
markerY1 = Math.min(...match.highlights.map(rect => rect.top))
|
||||
@ -865,17 +871,18 @@ class BesService {
|
||||
* @param {Number} x1 Sign left [px]
|
||||
* @param {Number} x2 Sign right [px]
|
||||
* @param {Number} y Sign baseline [px]
|
||||
* @param {Number} amplitude Sign amplitude [px]
|
||||
* @param {Number} scale Sign scale
|
||||
*/
|
||||
drawAttentionRequired(x1, x2, y, scale) {
|
||||
drawAttentionRequired(x1, x2, y, amplitude, scale) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.beginPath()
|
||||
this.ctx.moveTo(x1 * dpr, (y - scale) * dpr)
|
||||
this.ctx.moveTo(x1 * dpr, (y - amplitude * scale) * dpr)
|
||||
for (let x = x1; ; ) {
|
||||
if (x >= x2) break
|
||||
this.ctx.lineTo((x += 2 * scale) * dpr, (y + scale) * dpr)
|
||||
this.ctx.lineTo((x += 2 * scale) * dpr, (y + amplitude * scale) * dpr)
|
||||
if (x >= x2) break
|
||||
this.ctx.lineTo((x += 2 * scale) * dpr, (y - scale) * dpr)
|
||||
this.ctx.lineTo((x += 2 * scale) * dpr, (y - amplitude * scale) * dpr)
|
||||
}
|
||||
this.ctx.stroke()
|
||||
}
|
||||
@ -886,10 +893,11 @@ class BesService {
|
||||
* @param {Number} scale Sign scale
|
||||
* @param {Number} dpr Device pixel ratio
|
||||
*/
|
||||
setCtxFont(scale, dpr)
|
||||
{
|
||||
setCtxFont(scale, dpr) {
|
||||
const styles = window.getComputedStyle(this.canvasPanel)
|
||||
this.ctx.font = `${styles.fontStyle} ${styles.fontWeight} ${14 * scale * dpr}px ${styles.fontFamily}`
|
||||
this.ctx.font = `${styles.fontStyle} ${styles.fontWeight} ${
|
||||
14 * scale * dpr
|
||||
}px ${styles.fontFamily}`
|
||||
}
|
||||
|
||||
/**
|
||||
@ -944,10 +952,16 @@ class BesService {
|
||||
* @param {Number} x X coordinate
|
||||
* @param {Number} y Y coordinate
|
||||
* @param {DOMRect} rect Rectangle
|
||||
* @param {Number} tolerance Extra margin around the rectangle treated as "inside"
|
||||
* @returns
|
||||
*/
|
||||
static isPointInRect(x, y, rect) {
|
||||
return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom
|
||||
static isPointInRect(x, y, rect, tolerance) {
|
||||
return (
|
||||
rect.left - tolerance <= x &&
|
||||
x < rect.right + tolerance &&
|
||||
rect.top - tolerance <= y &&
|
||||
y < rect.bottom + tolerance
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -965,7 +979,16 @@ class BesService {
|
||||
this.ctx = this.canvasPanel.getContext('2d')
|
||||
this.ctx.scale(1, 1)
|
||||
|
||||
this.highlightSpelling = document.createElement('div')
|
||||
this.highlightSpelling.classList.add('bes-highlight-placeholder')
|
||||
this.highlightSpelling.classList.add('bes-highlight-spelling')
|
||||
this.highlightGrammar = document.createElement('div')
|
||||
this.highlightGrammar.classList.add('bes-highlight-placeholder')
|
||||
this.highlightGrammar.classList.add('bes-highlight-grammar')
|
||||
|
||||
this.correctionPanel.appendChild(this.scrollPanel)
|
||||
this.correctionPanel.appendChild(this.highlightSpelling)
|
||||
this.correctionPanel.appendChild(this.highlightGrammar)
|
||||
this.scrollPanel.appendChild(this.canvasPanel)
|
||||
this.textElement.parentElement.insertBefore(
|
||||
this.correctionPanel,
|
||||
@ -1033,14 +1056,14 @@ class BesService {
|
||||
/**
|
||||
* Prepares and displays popup.
|
||||
*
|
||||
* @param {*} elMatch Array containing block element/paragraph containing grammar checking rule match and a match
|
||||
* @param {*} hits Array containing block element/paragraph containing grammar checking rule match and a match
|
||||
* @param {PointerEvent} source Click event source
|
||||
*/
|
||||
preparePopup(elMatch, source) {
|
||||
preparePopup(hits, source) {
|
||||
this.dismissPopup()
|
||||
const popup = document.querySelector('bes-popup-el')
|
||||
BesPopup.clearReplacements()
|
||||
elMatch.forEach(({ el, match }) => {
|
||||
hits.forEach(({ el, match }) => {
|
||||
popup.setContent(el, match, this, this.isContentEditable())
|
||||
this.highlightMistake(match)
|
||||
})
|
||||
@ -1059,8 +1082,8 @@ class BesService {
|
||||
el.classList.add('bes-highlight-rect')
|
||||
el.classList.add(
|
||||
match.match.rule.id.startsWith('MORFOLOGIK_RULE')
|
||||
? 'bes-highlight-spelling-rect'
|
||||
: 'bes-highlight-grammar-rect'
|
||||
? 'bes-highlight-spelling'
|
||||
: 'bes-highlight-grammar'
|
||||
)
|
||||
el.style.left = `${rect.x + canvasPanelRect.x + window.scrollX}px`
|
||||
el.style.top = `${rect.y + canvasPanelRect.y + window.scrollY}px`
|
||||
@ -1100,7 +1123,9 @@ class BesService {
|
||||
redrawAllMistakeMarkup() {
|
||||
this.ctx.clearRect(0, 0, this.canvasPanel.width, this.canvasPanel.height)
|
||||
this.results.forEach(result => {
|
||||
result.matches.forEach(match => this.drawMistakeMarkup(match))
|
||||
// Most important matches are first, we want to draw them last => iterate in reverse.
|
||||
for (let i = result.matches.length; i-- > 0; )
|
||||
this.drawMistakeMarkup(result.matches[i])
|
||||
})
|
||||
}
|
||||
|
||||
@ -1256,9 +1281,11 @@ class BesTreeService extends BesService {
|
||||
),
|
||||
match: match
|
||||
}
|
||||
this.drawMistakeMarkup(m)
|
||||
matches.push(m)
|
||||
})
|
||||
// Most important matches are first, we want to draw them last => iterate in reverse.
|
||||
for (let i = matches.length; i-- > 0; )
|
||||
this.drawMistakeMarkup(matches[i])
|
||||
this.markProofed(node, matches)
|
||||
this.onProofingProgress(matches.length)
|
||||
})
|
||||
@ -1514,19 +1541,19 @@ class BesTreeService extends BesService {
|
||||
const canvasPanelRect = this.canvasPanel.getBoundingClientRect()
|
||||
let x = source.clientX - canvasPanelRect.x
|
||||
let y = source.clientY - canvasPanelRect.y
|
||||
const pointsInRect = []
|
||||
const hits = []
|
||||
for (let result of this.results) {
|
||||
for (let m of result.matches) {
|
||||
for (let rect of m.highlights) {
|
||||
if (BesService.isPointInRect(x, y, rect)) {
|
||||
pointsInRect.push({ el, match: m })
|
||||
if (BesService.isPointInRect(x, y, rect, 5)) {
|
||||
hits.push({ el, match: m })
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dismissPopup()
|
||||
if (pointsInRect.length) this.preparePopup(pointsInRect, source)
|
||||
if (hits.length) this.preparePopup(hits, source)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2045,9 +2072,11 @@ class BesPlainTextService extends BesService {
|
||||
),
|
||||
match: match
|
||||
}
|
||||
this.drawMistakeMarkup(m)
|
||||
matches.push(m)
|
||||
})
|
||||
// Most important matches are first, we want to draw them last => iterate in reverse.
|
||||
for (let i = matches.length; i-- > 0; )
|
||||
this.drawMistakeMarkup(matches[i])
|
||||
this.markProofed(paragraphRange, matches)
|
||||
this.onProofingProgress(matches.length)
|
||||
})
|
||||
@ -2182,19 +2211,19 @@ class BesPlainTextService extends BesService {
|
||||
const canvasPanelRect = this.canvasPanel.getBoundingClientRect()
|
||||
let x = source.clientX - canvasPanelRect.x
|
||||
let y = source.clientY - canvasPanelRect.y
|
||||
const pointsInRect = []
|
||||
const hits = []
|
||||
for (let result of this.results) {
|
||||
for (let m of result.matches) {
|
||||
for (let rect of m.highlights) {
|
||||
if (BesService.isPointInRect(x, y, rect)) {
|
||||
pointsInRect.push({ el: result.range, match: m })
|
||||
if (BesService.isPointInRect(x, y, rect, 5)) {
|
||||
hits.push({ el: result.range, match: m })
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dismissPopup()
|
||||
if (pointsInRect.length) this.preparePopup(pointsInRect, source)
|
||||
if (hits.length) this.preparePopup(hits, source)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2467,11 +2496,13 @@ class BesTAService extends BesPlainTextService {
|
||||
parseFloat(styles.paddingRight) -
|
||||
parseFloat(styles.borderRightWidth)
|
||||
}px`
|
||||
textElement.style.height = `${rect.height -
|
||||
textElement.style.height = `${
|
||||
rect.height -
|
||||
parseFloat(styles.borderTopWidth) -
|
||||
parseFloat(styles.paddingTop) -
|
||||
parseFloat(styles.paddingBottom) -
|
||||
parseFloat(styles.borderBottomWidth)}px`
|
||||
parseFloat(styles.borderBottomWidth)
|
||||
}px`
|
||||
}
|
||||
|
||||
/**
|
||||
|
35
styles.css
35
styles.css
@ -1,23 +1,29 @@
|
||||
/* Mistake types styles */
|
||||
.bes-spelling-mistake {
|
||||
border-bottom: 2px solid #ff7300;
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.bes-highlight-rect {
|
||||
position: absolute;
|
||||
opacity: 0.3;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.bes-highlight-spelling-rect {
|
||||
background: rgb(0, 123, 255);
|
||||
.bes-highlight-spelling {
|
||||
color: hsl(211, 100%, 60%);
|
||||
background: hsla(211, 100%, 60%, 0.3);
|
||||
}
|
||||
|
||||
.bes-highlight-grammar-rect {
|
||||
background: rgb(255, 115, 0);
|
||||
.bes-highlight-grammar {
|
||||
color: hsl(27, 100%, 45%);
|
||||
background: hsla(27, 100%, 45%, 0.3);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.bes-highlight-spelling {
|
||||
color: hsl(211, 100%, 55%);
|
||||
background: hsla(211, 100%, 55%, 0.3);
|
||||
}
|
||||
|
||||
.bes-highlight-grammar {
|
||||
color: hsl(27, 100%, 65%);
|
||||
background: hsla(27, 100%, 65%, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles required to ensure full functionality and optimal user experience. */
|
||||
@ -54,3 +60,8 @@
|
||||
background: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.bes-highlight-placeholder {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user