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

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

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

Loading…
Cancel
Save