Skip to content

Commit 94582fc

Browse files
authored
✨ enhance MarkManager and attribute of html (#136)
* ✨ enhance MarkManager to handle raw text extraction and improve approx_source management * ✨ add language attribute to article HTML and enable hyphenation in article styles * ✨ enhance MarkManager to extract raw text from approximate sources and improve error handling * ✨ enhance handleHTMLImgs to set padding and height styles for images * ✨ refactor handleHTMLImgs to apply multiple styles using a loop for better readability
1 parent 566baa0 commit 94582fc

File tree

6 files changed

+72
-6
lines changed

6 files changed

+72
-6
lines changed

apps/slax-reader-dweb/layers/core/components/Article/BookmarkArticle.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<BookmarkTags :bookmarkId="bookmarkId || 0" :tags="detail.tags" :readonly="!allowTagged" />
2020
</div>
2121
<div class="article-detail" ref="articleDetail" :class="{ [articleStyle]: true }">
22-
<div class="html-text" v-html="articleHTML"></div>
22+
<div class="html-text" lang="en" v-html="articleHTML"></div>
2323
</div>
2424
<div class="end">
2525
<div class="line"></div>
@@ -245,6 +245,10 @@ const handleHTMLImgs = (imgs: HTMLImageElement[]) => {
245245
img.setAttribute('style', `width: ${img.naturalWidth}px !important;`)
246246
return
247247
}
248+
249+
;[`padding: 0 !important`, `height: auto !important;`].forEach(style => {
250+
img.setAttribute('style', style)
251+
})
248252
}
249253
250254
img.onclick = () => {
@@ -680,7 +684,7 @@ defineExpose({
680684
}
681685
682686
.article-detail {
683-
--style: mt-24px;
687+
--style: mt-24px hyphens-auto;
684688
@include article.reset;
685689
686690
&.default {

apps/slax-reader-dweb/layers/core/components/Article/Selection/manager.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { HighlightRange, type HighlightRangeInfo } from '@commons/utils/range'
2+
import { getRangeTextWithNewlines } from '@commons/utils/string'
23

34
import type { QuoteData } from '../../Chat/type'
45
import { Base } from './base'
@@ -225,7 +226,7 @@ export class MarkManager extends Base {
225226
const texts: string[] = []
226227

227228
if (approx) {
228-
texts.push(approx.exact)
229+
texts.push(approx.raw_text ?? approx.exact)
229230
} else if (source && source.length > 0) {
230231
let lastNode: Node | null = null
231232
for (const markItem of source) {
@@ -498,6 +499,7 @@ export class MarkManager extends Base {
498499
}
499500

500501
private generateMarkItemInfos(markList: MarkInfo[], commentMap: Map<number, MarkCommentInfo>): MarkItemInfo[] {
502+
const rangeSvc = new HighlightRange(this.document, this.config.monitorDom!)
501503
const infoItems: MarkItemInfo[] = []
502504
for (const mark of markList) {
503505
const userId = mark.user_id
@@ -509,6 +511,16 @@ export class MarkManager extends Base {
509511
let markInfoItem = infoItems.find(infoItem => this.checkMarkSourceIsSame(infoItem.source, markSources))
510512

511513
if (!markInfoItem) {
514+
try {
515+
if (mark.approx_source) {
516+
const newRange = rangeSvc.getRange(mark.approx_source)
517+
const rawText = newRange ? getRangeTextWithNewlines(newRange) : undefined
518+
mark.approx_source.raw_text = rawText
519+
}
520+
} catch (error) {
521+
console.error('create raw text failed', error, mark.approx_source?.exact)
522+
}
523+
512524
markInfoItem = { id: getUUID(), source: markSources, comments: [], stroke: [], approx: mark.approx_source }
513525
infoItems.push(markInfoItem)
514526
}

apps/slax-reader-extensions/src/components/Selection/manager.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getElementFullSelector } from '@commons/utils/dom'
22
import { HighlightRange, type HighlightRangeInfo } from '@commons/utils/range'
3+
import { getRangeTextWithNewlines } from '@commons/utils/string'
34

45
import type { QuoteData } from '../Chat/type'
56
import Toast, { ToastType } from '../Toast'
@@ -226,7 +227,7 @@ export class MarkManager extends Base {
226227
const texts: string[] = []
227228

228229
if (approx) {
229-
texts.push(approx.exact)
230+
texts.push(approx.raw_text ?? approx.exact)
230231
} else if (source && source.length > 0) {
231232
let lastNode: Node | null = null
232233
for (const markItem of source) {
@@ -510,6 +511,7 @@ export class MarkManager extends Base {
510511

511512
private async saveMarkSelectContent(value: MarkPathItem[], type: MarkType, approx: MarkPathApprox, comment?: string, replyToId?: number) {
512513
const bookmarkId = await this.config.bookmarkIdQuery()
514+
const { raw_text: _, ...approxSource } = approx
513515
try {
514516
const res = await request.post<{ mark_id: number; root_id: number }>({
515517
url: RESTMethodPath.ADD_MARK,
@@ -520,7 +522,7 @@ export class MarkManager extends Base {
520522
source: value,
521523
parent_id: replyToId,
522524
select_content: this._selectContent.value,
523-
approx_source: approx
525+
approx_source: approxSource
524526
}
525527
})
526528
return res || null
@@ -578,6 +580,7 @@ export class MarkManager extends Base {
578580
}
579581

580582
private generateMarkItemInfos(markList: MarkInfo[], commentMap: Map<number, MarkCommentInfo>): MarkItemInfo[] {
583+
const rangeSvc = new HighlightRange(this.document, this.config.monitorDom!)
581584
const infoItems: MarkItemInfo[] = []
582585
for (const mark of markList) {
583586
const userId = mark.user_id
@@ -589,6 +592,16 @@ export class MarkManager extends Base {
589592
let markInfoItem = infoItems.find(infoItem => this.checkMarkSourceIsSame(infoItem.source, markSources))
590593

591594
if (!markInfoItem) {
595+
try {
596+
if (mark.approx_source) {
597+
const newRange = rangeSvc.getRange(mark.approx_source)
598+
const rawText = newRange ? getRangeTextWithNewlines(newRange) : undefined
599+
mark.approx_source.raw_text = rawText
600+
}
601+
} catch (error) {
602+
console.error('create raw text failed', error, mark.approx_source?.exact)
603+
}
604+
592605
markInfoItem = { id: getUUID(), source: markSources, comments: [], stroke: [], approx: mark.approx_source }
593606
infoItems.push(markInfoItem)
594607
}

commons/types/src/interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export type MarkPathApprox = {
5555
suffix: string
5656
position_start: number
5757
position_end: number
58+
raw_text?: string
5859
}
5960

6061
export interface ShareInfo {

commons/utils/src/range.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import search from 'approx-string-match'
2+
import { getRangeTextWithNewlines } from './string'
23

34
export interface HighlightRangeInfo {
45
// postion selector
@@ -9,6 +10,7 @@ export interface HighlightRangeInfo {
910
exact: string
1011
prefix: string
1112
suffix: string
13+
raw_text?: string
1214
}
1315

1416
export class HighlightRange {
@@ -221,7 +223,8 @@ export class HighlightRange {
221223
prefix,
222224
suffix,
223225
position_start: startOffset,
224-
position_end: endOffset
226+
position_end: endOffset,
227+
raw_text: getRangeTextWithNewlines(range)
225228
}
226229
}
227230

commons/utils/src/string.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,36 @@ export const urlHttpString = (url: string) => {
4545

4646
return 'https://' + url
4747
}
48+
49+
/**
50+
* 根据range返回对应文本
51+
*/
52+
export const getRangeTextWithNewlines = (range: Range): string => {
53+
const selection = window.getSelection()
54+
if (!selection) {
55+
console.warn('无法获取 window.getSelection()')
56+
57+
const temp = document.createElement('div')
58+
temp.appendChild(range.cloneContents())
59+
return temp.innerText
60+
}
61+
62+
const originalRanges: Range[] = []
63+
for (let i = 0; i < selection.rangeCount; i++) {
64+
originalRanges.push(selection.getRangeAt(i))
65+
}
66+
67+
try {
68+
selection.removeAllRanges()
69+
selection.addRange(range)
70+
71+
const text = selection.toString()
72+
73+
return text
74+
} finally {
75+
selection.removeAllRanges()
76+
for (const originalRange of originalRanges) {
77+
selection.addRange(originalRange)
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)