feat: double click the selected text through the segmenter #510

pr675
Hufe921 2 years ago
parent 7e5a1ac04c
commit 3f8399de62

@ -1,38 +1,63 @@
import { ZERO } from '../../../dataset/constant/Common'
import { TEXTLIKE_ELEMENT_TYPE } from '../../../dataset/constant/Element'
import { NUMBER_LIKE_REG } from '../../../dataset/constant/Regular'
import { ControlComponent } from '../../../dataset/enum/Control'
import { IRange } from '../../../interface/Range'
import { CanvasEvent } from '../CanvasEvent'
function dblclick(host: CanvasEvent, evt: MouseEvent) {
// 通过分词器获取单词所在选区
function getWordRangeBySegmenter(host: CanvasEvent): IRange | null {
if (!Intl.Segmenter) return null
const draw = host.getDraw()
const LETTER_REG = draw.getLetterReg()
const position = draw.getPosition()
const positionContext = position.getPositionByXY({
x: evt.offsetX,
y: evt.offsetY
})
// 图片预览
if (positionContext.isImage && positionContext.isDirectHit) {
draw.getPreviewer().render()
return
}
// 切换区域
if (draw.getIsPagingMode()) {
if (!~positionContext.index && positionContext.zone) {
draw.getZone().setZone(positionContext.zone)
draw.clearSideEffect()
position.setPositionContext({
isTable: false
})
return
const cursorPosition = draw.getPosition().getCursorPosition()
if (!cursorPosition) return null
const rangeManager = draw.getRange()
const paragraphInfo = rangeManager.getRangeParagraphInfo()
if (!paragraphInfo) return null
// 组装段落文本
const paragraphText =
paragraphInfo?.elementList
?.map(e =>
!e.type ||
(TEXTLIKE_ELEMENT_TYPE.includes(e.type) &&
e.controlComponent !== ControlComponent.CHECKBOX)
? e.value
: ZERO
)
.join('') || ''
if (!paragraphText) return null
// 光标所在位置
const cursorStartIndex = cursorPosition.index
// 段落首字符相对文档起始位置
const offset = paragraphInfo.startIndex
const segmenter = new Intl.Segmenter(undefined, { granularity: 'word' })
const segments = segmenter.segment(paragraphText)
// 新的光标位置
let startIndex = -1
let endIndex = -1
for (const { segment, index, isWordLike } of segments) {
const realSegmentStartIndex = index + offset
if (
isWordLike &&
cursorStartIndex >= realSegmentStartIndex &&
cursorStartIndex < realSegmentStartIndex + segment.length
) {
startIndex = realSegmentStartIndex - 1
endIndex = startIndex + segment.length
break
}
}
// 复选框双击时是切换选择状态,禁用扩选
if (positionContext.isCheckbox && positionContext.isDirectHit) return
// 自动扩选文字
const cursorPosition = position.getCursorPosition()
if (!cursorPosition) return
return ~startIndex && ~endIndex ? { startIndex, endIndex } : null
}
// 通过光标位置获取单词所在选区
function getWordRangeByCursor(host: CanvasEvent): IRange | null {
const draw = host.getDraw()
const cursorPosition = draw.getPosition().getCursorPosition()
if (!cursorPosition) return null
const { value, index } = cursorPosition
// 判断是否是数字或英文
const LETTER_REG = draw.getLetterReg()
let upCount = 0
let downCount = 0
const isNumber = NUMBER_LIKE_REG.test(value)
@ -67,11 +92,46 @@ function dblclick(host: CanvasEvent, evt: MouseEvent) {
}
}
}
// 设置选中区域
// 新的光标位置
const startIndex = index - upCount - 1
if (startIndex < 0) return
if (startIndex < 0) return null
return {
startIndex,
endIndex: index + downCount
}
}
function dblclick(host: CanvasEvent, evt: MouseEvent) {
const draw = host.getDraw()
const position = draw.getPosition()
const positionContext = position.getPositionByXY({
x: evt.offsetX,
y: evt.offsetY
})
// 图片预览
if (positionContext.isImage && positionContext.isDirectHit) {
draw.getPreviewer().render()
return
}
// 切换区域
if (draw.getIsPagingMode()) {
if (!~positionContext.index && positionContext.zone) {
draw.getZone().setZone(positionContext.zone)
draw.clearSideEffect()
position.setPositionContext({
isTable: false
})
return
}
}
// 复选框双击时是切换选择状态,禁用扩选
if (positionContext.isCheckbox && positionContext.isDirectHit) return
// 自动扩选文字-分词处理,优先使用分词器否则降级使用光标所在位置
const rangeManager = draw.getRange()
rangeManager.setRange(startIndex, index + downCount)
const segmenterRange =
getWordRangeBySegmenter(host) || getWordRangeByCursor(host)
if (!segmenterRange) return
rangeManager.setRange(segmenterRange.startIndex, segmenterRange.endIndex)
// 刷新文档
draw.render({
isSubmitHistory: false,

@ -8,7 +8,12 @@ import { IEditorOption } from '../../interface/Editor'
import { IElement } from '../../interface/Element'
import { EventBusMap } from '../../interface/EventBus'
import { IRangeStyle } from '../../interface/Listener'
import { IRange, RangeRowArray, RangeRowMap } from '../../interface/Range'
import {
IRange,
IRangeParagraphInfo,
RangeRowArray,
RangeRowMap
} from '../../interface/Range'
import { getAnchorElement } from '../../utils/element'
import { Draw } from '../draw/Draw'
import { EventBus } from '../event/eventbus/EventBus'
@ -208,10 +213,12 @@ export class RangeManager {
return rangeRow
}
// 获取选区段落元素列表
public getRangeParagraphElementList(): IElement[] | null {
// 获取选区段落信息
public getRangeParagraphInfo(): IRangeParagraphInfo | null {
const { startIndex, endIndex } = this.range
if (!~startIndex && !~endIndex) return null
/// 起始元素位置
let startPositionIndex = -1
// 需要改变的元素列表
const rangeElementList: IElement[] = []
// 选区行信息
@ -224,10 +231,22 @@ export class RangeManager {
const rowArray = rangeRow.get(position.pageNo)
if (!rowArray) continue
if (rowArray.includes(position.rowNo)) {
if (!~startPositionIndex) {
startPositionIndex = position.index
}
rangeElementList.push(elementList[p])
}
}
return rangeElementList
if (!rangeElementList.length) return null
return {
elementList: rangeElementList,
startIndex: startPositionIndex
}
}
// 获取选区段落元素列表
public getRangeParagraphElementList(): IElement[] | null {
return this.getRangeParagraphInfo()?.elementList || null
}
public getIsSelectAll() {

@ -29,3 +29,8 @@ export type RangeContext = {
zone: EditorZone
isTable: boolean
}
export interface IRangeParagraphInfo {
elementList: IElement[]
startIndex: number
}

Loading…
Cancel
Save