From b54b66d3d4a9e7366cef02add9b897770bac39c5 Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Tue, 8 Aug 2023 22:30:01 +0800 Subject: [PATCH] feat: apply style to entire table #232 --- docs/en/guide/command-execute.md | 10 ++ docs/guide/command-execute.md | 10 ++ src/editor/core/command/Command.ts | 2 + src/editor/core/command/CommandAdapt.ts | 119 +++++++++++++----------- src/editor/core/range/RangeManager.ts | 50 ++++++++++ 5 files changed, 136 insertions(+), 55 deletions(-) diff --git a/docs/en/guide/command-execute.md b/docs/en/guide/command-execute.md index 3445dd8..9b4829d 100644 --- a/docs/en/guide/command-execute.md +++ b/docs/en/guide/command-execute.md @@ -419,6 +419,16 @@ Usage: instance.command.executeTableTdBackgroundColor(payload: string) ``` +## executeTableSelectAll + +Feature: Select the entire table + +Usage: + +```javascript +instance.command.executeTableSelectAll() +``` + ## executeImage Feature: Insert a picture diff --git a/docs/guide/command-execute.md b/docs/guide/command-execute.md index f19016c..2d9a431 100644 --- a/docs/guide/command-execute.md +++ b/docs/guide/command-execute.md @@ -419,6 +419,16 @@ instance.command.executeTableBorderType(payload: TableBorder) instance.command.executeTableTdBackgroundColor(payload: string) ``` +## executeTableSelectAll + +功能:选中整个表格 + +用法: + +```javascript +instance.command.executeTableSelectAll() +``` + ## executeImage 功能:插入图片 diff --git a/src/editor/core/command/Command.ts b/src/editor/core/command/Command.ts index 8ae9fe1..7cd6c21 100644 --- a/src/editor/core/command/Command.ts +++ b/src/editor/core/command/Command.ts @@ -43,6 +43,7 @@ export class Command { public executeTableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign'] public executeTableBorderType: CommandAdapt['tableBorderType'] public executeTableTdBackgroundColor: CommandAdapt['tableTdBackgroundColor'] + public executeTableSelectAll: CommandAdapt['tableSelectAll'] public executeImage: CommandAdapt['image'] public executeHyperlink: CommandAdapt['hyperlink'] public executeDeleteHyperlink: CommandAdapt['deleteHyperlink'] @@ -133,6 +134,7 @@ export class Command { this.executeTableBorderType = adapt.tableBorderType.bind(adapt) this.executeTableTdBackgroundColor = adapt.tableTdBackgroundColor.bind(adapt) + this.executeTableSelectAll = adapt.tableSelectAll.bind(adapt) this.executeImage = adapt.image.bind(adapt) this.executeHyperlink = adapt.hyperlink.bind(adapt) this.executeDeleteHyperlink = adapt.deleteHyperlink.bind(adapt) diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index 3262d5a..c793ca8 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -195,7 +195,7 @@ export class CommandAdapt { public format() { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { el.font = '' @@ -211,7 +211,7 @@ export class CommandAdapt { public font(payload: string) { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { el.font = payload @@ -224,7 +224,7 @@ export class CommandAdapt { if (payload < minSize || payload > maxSize) return const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getTextLikeSelection() + const selection = this.range.getTextLikeSelectionElementList() if (!selection || !selection.length) return let isExistUpdate = false selection.forEach(el => { @@ -245,7 +245,7 @@ export class CommandAdapt { public sizeAdd() { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getTextLikeSelection() + const selection = this.range.getTextLikeSelectionElementList() if (!selection || !selection.length) return const { defaultSize, maxSize } = this.options let isExistUpdate = false @@ -269,7 +269,7 @@ export class CommandAdapt { public sizeMinus() { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getTextLikeSelection() + const selection = this.range.getTextLikeSelectionElementList() if (!selection || !selection.length) return const { defaultSize, minSize } = this.options let isExistUpdate = false @@ -293,7 +293,7 @@ export class CommandAdapt { public bold() { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return const noBoldIndex = selection.findIndex(s => !s.bold) selection.forEach(el => { @@ -305,7 +305,7 @@ export class CommandAdapt { public italic() { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return const noItalicIndex = selection.findIndex(s => !s.italic) selection.forEach(el => { @@ -317,7 +317,7 @@ export class CommandAdapt { public underline() { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return const noUnderlineIndex = selection.findIndex(s => !s.underline) selection.forEach(el => { @@ -329,7 +329,7 @@ export class CommandAdapt { public strikeout() { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return const noStrikeoutIndex = selection.findIndex(s => !s.strikeout) selection.forEach(el => { @@ -343,7 +343,7 @@ export class CommandAdapt { if (isReadonly) return const activeControl = this.control.getActiveControl() if (activeControl) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return const superscriptIndex = selection.findIndex( s => s.type === ElementType.SUPERSCRIPT @@ -374,7 +374,7 @@ export class CommandAdapt { if (isReadonly) return const activeControl = this.control.getActiveControl() if (activeControl) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return const subscriptIndex = selection.findIndex( s => s.type === ElementType.SUBSCRIPT @@ -403,7 +403,7 @@ export class CommandAdapt { public color(payload: string) { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { el.color = payload @@ -417,7 +417,7 @@ export class CommandAdapt { public highlight(payload: string) { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const selection = this.range.getSelection() + const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { el.highlight = payload @@ -505,20 +505,11 @@ export class CommandAdapt { if (isReadonly) return const { startIndex, endIndex } = this.range.getRange() if (!~startIndex && !~endIndex) return - // 选区行信息 - const rangeRow = this.range.getRangeRow() - if (!rangeRow) return - const positionList = this.position.getPositionList() - const elementList = this.draw.getElementList() - // 当前选区所在行 - for (let p = 0; p < positionList.length; p++) { - const position = positionList[p] - const rowSet = rangeRow.get(position.pageNo) - if (!rowSet) continue - if (rowSet.has(position.rowNo)) { - elementList[p].rowFlex = payload - } - } + const rowElementList = this.range.getRangeRowElementList() + if (!rowElementList) return + rowElementList.forEach(element => { + element.rowFlex = payload + }) // 光标定位 const isSetCursor = startIndex === endIndex const curIndex = isSetCursor ? endIndex : startIndex @@ -530,20 +521,11 @@ export class CommandAdapt { if (isReadonly) return const { startIndex, endIndex } = this.range.getRange() if (!~startIndex && !~endIndex) return - // 选区行信息 - const rangeRow = this.range.getRangeRow() - if (!rangeRow) return - const positionList = this.position.getPositionList() - const elementList = this.draw.getElementList() - // 当前选区所在行 - for (let p = 0; p < positionList.length; p++) { - const position = positionList[p] - const rowSet = rangeRow.get(position.pageNo) - if (!rowSet) continue - if (rowSet.has(position.rowNo)) { - elementList[p].rowMargin = payload - } - } + const rowElementList = this.range.getRangeRowElementList() + if (!rowElementList) return + rowElementList.forEach(element => { + element.rowMargin = payload + }) // 光标定位 const isSetCursor = startIndex === endIndex const curIndex = isSetCursor ? endIndex : startIndex @@ -1187,21 +1169,23 @@ export class CommandAdapt { public tableTdVerticalAlign(payload: VerticalAlign) { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const positionContext = this.position.getPositionContext() - if (!positionContext.isTable) return - const { index, trIndex, tdIndex } = positionContext - const originalElementList = this.draw.getOriginalElementList() - const element = originalElementList[index!] - const curTd = element?.trList?.[trIndex!]?.tdList?.[tdIndex!] - if ( - !curTd || - curTd.verticalAlign === payload || - (!curTd.verticalAlign && payload === VerticalAlign.TOP) - ) { - return + const rowCol = this.draw.getTableParticle().getRangeRowCol() + if (!rowCol) return + for (let r = 0; r < rowCol.length; r++) { + const row = rowCol[r] + for (let c = 0; c < row.length; c++) { + const td = row[c] + if ( + !td || + td.verticalAlign === payload || + (!td.verticalAlign && payload === VerticalAlign.TOP) + ) { + continue + } + // 重设垂直对齐方式 + td.verticalAlign = payload + } } - // 重设垂直对齐方式 - curTd.verticalAlign = payload const { endIndex } = this.range.getRange() this.draw.render({ curIndex: endIndex @@ -1248,6 +1232,31 @@ export class CommandAdapt { }) } + public tableSelectAll() { + const positionContext = this.position.getPositionContext() + const { index, tableId, isTable } = positionContext + if (!isTable || !tableId) return + const { startIndex, endIndex } = this.range.getRange() + const originalElementList = this.draw.getOriginalElementList() + const trList = originalElementList[index!].trList! + // 最后单元格位置 + const endTrIndex = trList.length - 1 + const endTdIndex = trList[endTrIndex].tdList.length - 1 + this.range.replaceRange({ + startIndex, + endIndex, + tableId, + startTdIndex: 0, + endTdIndex, + startTrIndex: 0, + endTrIndex + }) + this.draw.render({ + isCompute: false, + isSubmitHistory: false + }) + } + public hyperlink(payload: IElement) { const isReadonly = this.draw.isReadonly() if (isReadonly) return diff --git a/src/editor/core/range/RangeManager.ts b/src/editor/core/range/RangeManager.ts index 0fc747c..894020f 100644 --- a/src/editor/core/range/RangeManager.ts +++ b/src/editor/core/range/RangeManager.ts @@ -56,6 +56,23 @@ export class RangeManager { return elementList.slice(startIndex + 1, endIndex + 1) } + public getSelectionElementList(): IElement[] | null { + if (this.range.isCrossRowCol) { + const rowCol = this.draw.getTableParticle().getRangeRowCol() + if (!rowCol) return null + const elementList: IElement[] = [] + for (let r = 0; r < rowCol.length; r++) { + const row = rowCol[r] + for (let c = 0; c < row.length; c++) { + const col = row[c] + elementList.push(...col.value) + } + } + return elementList + } + return this.getSelection() + } + public getTextLikeSelection(): IElement[] | null { const selection = this.getSelection() if (!selection) return null @@ -64,6 +81,14 @@ export class RangeManager { ) } + public getTextLikeSelectionElementList(): IElement[] | null { + const selection = this.getSelectionElementList() + if (!selection) return null + return selection.filter( + s => !s.type || TEXTLIKE_ELEMENT_TYPE.includes(s.type) + ) + } + // 获取光标所选位置行信息 public getRangeRow(): RangeRowMap | null { const { startIndex, endIndex } = this.range @@ -84,6 +109,31 @@ export class RangeManager { return rangeRow } + // 获取光标所选位置元素列表 + public getRangeRowElementList(): IElement[] | null { + const { startIndex, endIndex, isCrossRowCol } = this.range + if (!~startIndex && !~endIndex) return null + if (isCrossRowCol) { + return this.getSelectionElementList() + } + // 选区行信息 + const rangeRow = this.getRangeRow() + if (!rangeRow) return null + const positionList = this.position.getPositionList() + const elementList = this.draw.getElementList() + // 当前选区所在行 + const rowElementList: IElement[] = [] + for (let p = 0; p < positionList.length; p++) { + const position = positionList[p] + const rowSet = rangeRow.get(position.pageNo) + if (!rowSet) continue + if (rowSet.has(position.rowNo)) { + rowElementList.push(elementList[p]) + } + } + return rowElementList + } + // 获取选取段落信息 public getRangeParagraph(): RangeRowArray | null { const { startIndex, endIndex } = this.range