diff --git a/docs/en/guide/command-execute.md b/docs/en/guide/command-execute.md index 79e0e24..c2463e6 100644 --- a/docs/en/guide/command-execute.md +++ b/docs/en/guide/command-execute.md @@ -419,6 +419,16 @@ Usage: instance.command.executeTableBorderType(payload: TableBorder) ``` +## executeTableTdBorderType + +Feature: Table td border type + +Usage: + +```javascript +instance.command.executeTableTdBorderType(payload: TableBorder) +``` + ## executeTableTdBackgroundColor Feature: Table cell background color diff --git a/docs/en/guide/i18n.md b/docs/en/guide/i18n.md index 17f4c2d..bd5bbbc 100644 --- a/docs/en/guide/i18n.md +++ b/docs/en/guide/i18n.md @@ -63,6 +63,8 @@ interface ILang { borderAll: string borderEmpty: string borderExternal: string + borderTd: string + borderTdBottom: string } } datePicker: { diff --git a/docs/en/guide/schema.md b/docs/en/guide/schema.md index 29e1bc6..4420254 100644 --- a/docs/en/guide/schema.md +++ b/docs/en/guide/schema.md @@ -54,6 +54,7 @@ interface IElement { rowspan: number; verticalAlign?: VerticalAlign; backgroundColor?: string; + borderType?: TdBorder; value: IElement[]; }[]; }[]; diff --git a/docs/guide/command-execute.md b/docs/guide/command-execute.md index 4ca07f5..533c341 100644 --- a/docs/guide/command-execute.md +++ b/docs/guide/command-execute.md @@ -419,6 +419,16 @@ instance.command.executeTableTdVerticalAlign(payload: VerticalAlign) instance.command.executeTableBorderType(payload: TableBorder) ``` +## executeTableTdBorderType + +功能:表格单元格边框类型 + +用法: + +```javascript +instance.command.executeTableTdBorderType(payload: TdBorder) +``` + ## executeTableTdBackgroundColor 功能:表格单元格背景色 diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md index 0857ead..76654b4 100644 --- a/docs/guide/i18n.md +++ b/docs/guide/i18n.md @@ -63,6 +63,8 @@ interface ILang { borderAll: string borderEmpty: string borderExternal: string + borderTd: string + borderTdBottom: string } } datePicker: { diff --git a/docs/guide/schema.md b/docs/guide/schema.md index 5de455a..59a41b0 100644 --- a/docs/guide/schema.md +++ b/docs/guide/schema.md @@ -54,6 +54,7 @@ interface IElement { rowspan: number; verticalAlign?: VerticalAlign; backgroundColor?: string; + borderType?: TdBorder; value: IElement[]; }[]; }[]; diff --git a/src/editor/assets/css/contextmenu/contextmenu.css b/src/editor/assets/css/contextmenu/contextmenu.css index dc6a7af..c6ae576 100644 --- a/src/editor/assets/css/contextmenu/contextmenu.css +++ b/src/editor/assets/css/contextmenu/contextmenu.css @@ -157,4 +157,12 @@ .ce-contextmenu-border-external { background-image: url(../../../assets/images/table-border-external.svg); +} + +.ce-contextmenu-border-td { + background-image: url(../../../assets/images/table-border-td.svg); +} + +.ce-contextmenu-border-td-bottom { + background-image: url(../../../assets/images/table-border-td-bottom.svg); } \ No newline at end of file diff --git a/src/editor/assets/images/table-border-td-bottom.svg b/src/editor/assets/images/table-border-td-bottom.svg new file mode 100644 index 0000000..952b9e2 --- /dev/null +++ b/src/editor/assets/images/table-border-td-bottom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/editor/assets/images/table-border-td.svg b/src/editor/assets/images/table-border-td.svg new file mode 100644 index 0000000..219d5f6 --- /dev/null +++ b/src/editor/assets/images/table-border-td.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/editor/core/command/Command.ts b/src/editor/core/command/Command.ts index 2f81632..32c1d13 100644 --- a/src/editor/core/command/Command.ts +++ b/src/editor/core/command/Command.ts @@ -43,6 +43,7 @@ export class Command { public executeCancelMergeTableCell: CommandAdapt['cancelMergeTableCell'] public executeTableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign'] public executeTableBorderType: CommandAdapt['tableBorderType'] + public executeTableTdBorderType: CommandAdapt['tableTdBorderType'] public executeTableTdBackgroundColor: CommandAdapt['tableTdBackgroundColor'] public executeTableSelectAll: CommandAdapt['tableSelectAll'] public executeImage: CommandAdapt['image'] @@ -143,6 +144,7 @@ export class Command { this.executeCancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt) this.executeTableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt) this.executeTableBorderType = adapt.tableBorderType.bind(adapt) + this.executeTableTdBorderType = adapt.tableTdBorderType.bind(adapt) this.executeTableTdBackgroundColor = adapt.tableTdBackgroundColor.bind(adapt) this.executeTableSelectAll = adapt.tableSelectAll.bind(adapt) diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index f39b643..b6db916 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -13,7 +13,7 @@ import { ElementType } from '../../dataset/enum/Element' import { ElementStyleKey } from '../../dataset/enum/ElementStyle' import { ListStyle, ListType } from '../../dataset/enum/List' import { RowFlex } from '../../dataset/enum/Row' -import { TableBorder } from '../../dataset/enum/table/Table' +import { TableBorder, TdBorder } from '../../dataset/enum/table/Table' import { TitleLevel } from '../../dataset/enum/Title' import { VerticalAlign } from '../../dataset/enum/VerticalAlign' import { ICatalog } from '../../interface/Catalog' @@ -1227,6 +1227,27 @@ export class CommandAdapt { }) } + public tableTdBorderType(payload: TdBorder) { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return + const rowCol = this.draw.getTableParticle().getRangeRowCol() + if (!rowCol) return + const tdList = rowCol.flat() + // 存在则设置边框类型,否则取消设置 + const isSetBorderType = tdList.some(td => td.borderType !== payload) + tdList.forEach(td => { + if (isSetBorderType) { + td.borderType = payload + } else { + delete td.borderType + } + }) + const { endIndex } = this.range.getRange() + this.draw.render({ + curIndex: endIndex + }) + } + public tableTdBackgroundColor(payload: string) { const isReadonly = this.draw.isReadonly() if (isReadonly) return diff --git a/src/editor/core/contextmenu/menus/tableMenus.ts b/src/editor/core/contextmenu/menus/tableMenus.ts index ca51bc6..6e33697 100644 --- a/src/editor/core/contextmenu/menus/tableMenus.ts +++ b/src/editor/core/contextmenu/menus/tableMenus.ts @@ -1,5 +1,5 @@ import { VerticalAlign } from '../../../dataset/enum/VerticalAlign' -import { TableBorder } from '../../../dataset/enum/table/Table' +import { TableBorder, TdBorder } from '../../../dataset/enum/table/Table' import { IRegisterContextMenu } from '../../../interface/contextmenu/ContextMenu' import { Command } from '../../command/Command' @@ -37,6 +37,21 @@ export const tableMenus: IRegisterContextMenu[] = [ callback: (command: Command) => { command.executeTableBorderType(TableBorder.EXTERNAL) } + }, + { + i18nPath: 'contextmenu.table.borderTd', + icon: 'border-td', + when: () => true, + childMenus: [ + { + i18nPath: 'contextmenu.table.borderTdBottom', + icon: 'border-td-bottom', + when: () => true, + callback: (command: Command) => { + command.executeTableTdBorderType(TdBorder.BOTTOM) + } + } + ] } ] }, diff --git a/src/editor/core/draw/particle/table/TableParticle.ts b/src/editor/core/draw/particle/table/TableParticle.ts index 017ff03..f1ae929 100644 --- a/src/editor/core/draw/particle/table/TableParticle.ts +++ b/src/editor/core/draw/particle/table/TableParticle.ts @@ -1,4 +1,5 @@ import { ElementType, IElement, TableBorder } from '../../../..' +import { TdBorder } from '../../../../dataset/enum/table/Table' import { IEditorOption } from '../../../../interface/Editor' import { ITd } from '../../../../interface/table/Td' import { ITr } from '../../../../interface/table/Tr' @@ -122,40 +123,55 @@ export class TableParticle { startY: number ) { const { colgroup, trList, borderType } = element - if (!colgroup || !trList || borderType === TableBorder.EMPTY) return + if (!colgroup || !trList) return const { scale } = this.options const tableWidth = element.width! * scale const tableHeight = element.height! * scale + // 无边框 + const isEmptyBorderType = borderType === TableBorder.EMPTY + // 仅外边框 const isExternalBorderType = borderType === TableBorder.EXTERNAL ctx.save() // 渲染边框 - this._drawOuterBorder({ - ctx, - startX, - startY, - width: tableWidth, - height: tableHeight, - isDrawFullBorder: isExternalBorderType - }) - if (!isExternalBorderType) { - // 渲染表格 - for (let t = 0; t < trList.length; t++) { - const tr = trList[t] - for (let d = 0; d < tr.tdList.length; d++) { - const td = tr.tdList[d] - const width = td.width! * scale - const height = td.height! * scale - const x = Math.round(td.x! * scale + startX + width) - const y = Math.round(td.y! * scale + startY) - ctx.translate(0.5, 0.5) - // 绘制线条 - ctx.beginPath() + if (!isEmptyBorderType) { + this._drawOuterBorder({ + ctx, + startX, + startY, + width: tableWidth, + height: tableHeight, + isDrawFullBorder: isExternalBorderType + }) + } + // 渲染单元格 + for (let t = 0; t < trList.length; t++) { + const tr = trList[t] + for (let d = 0; d < tr.tdList.length; d++) { + const td = tr.tdList[d] + // 没有设置单元格边框 && 没有设置表格边框则忽略 + if (!td.borderType && (isEmptyBorderType || isExternalBorderType)) { + continue + } + const width = td.width! * scale + const height = td.height! * scale + const x = Math.round(td.x! * scale + startX + width) + const y = Math.round(td.y! * scale + startY) + ctx.translate(0.5, 0.5) + // 绘制线条 + ctx.beginPath() + if (td.borderType === TdBorder.BOTTOM) { + ctx.moveTo(x, y + height) + ctx.lineTo(x - width, y + height) + ctx.stroke() + } + if (!isEmptyBorderType && !isExternalBorderType) { + ctx.moveTo(x, y + height) ctx.moveTo(x, y) ctx.lineTo(x, y + height) ctx.lineTo(x - width, y + height) ctx.stroke() - ctx.translate(-0.5, -0.5) } + ctx.translate(-0.5, -0.5) } } ctx.restore() diff --git a/src/editor/core/i18n/lang/en.json b/src/editor/core/i18n/lang/en.json index e8e22c4..00f96a9 100644 --- a/src/editor/core/i18n/lang/en.json +++ b/src/editor/core/i18n/lang/en.json @@ -43,7 +43,9 @@ "border": "Table border", "borderAll": "All", "borderEmpty": "Empty", - "borderExternal": "External" + "borderExternal": "External", + "borderTd": "Table cell border", + "borderTdBottom": "Bottom" } }, "datePicker": { diff --git a/src/editor/core/i18n/lang/zh-CN.json b/src/editor/core/i18n/lang/zh-CN.json index de44f3f..49e22ac 100644 --- a/src/editor/core/i18n/lang/zh-CN.json +++ b/src/editor/core/i18n/lang/zh-CN.json @@ -43,7 +43,9 @@ "border": "表格边框", "borderAll": "所有框线", "borderEmpty": "无框线", - "borderExternal": "外侧框线" + "borderExternal": "外侧框线", + "borderTd": "单元格边框", + "borderTdBottom": "下边框" } }, "datePicker": { diff --git a/src/editor/dataset/constant/Element.ts b/src/editor/dataset/constant/Element.ts index 947f14a..891a085 100644 --- a/src/editor/dataset/constant/Element.ts +++ b/src/editor/dataset/constant/Element.ts @@ -1,5 +1,6 @@ import { ElementType } from '../enum/Element' import { IElement } from '../../interface/Element' +import { ITd } from '../../interface/table/Td' export const EDITOR_ELEMENT_STYLE_ATTR: Array = [ 'bold', @@ -61,6 +62,12 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array = [ 'groupIds' ] +export const TABLE_TD_ZIP_ATTR: Array = [ + 'verticalAlign', + 'backgroundColor', + 'borderType' +] + export const TABLE_CONTEXT_ATTR: Array = [ 'tdId', 'trId', diff --git a/src/editor/dataset/enum/table/Table.ts b/src/editor/dataset/enum/table/Table.ts index 927075c..6482dc3 100644 --- a/src/editor/dataset/enum/table/Table.ts +++ b/src/editor/dataset/enum/table/Table.ts @@ -3,3 +3,7 @@ export enum TableBorder { EMPTY = 'empty', EXTERNAL = 'external' } + +export enum TdBorder { + BOTTOM = 'bottom' +} diff --git a/src/editor/index.ts b/src/editor/index.ts index bb90342..0e89946 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -44,7 +44,7 @@ import { defaultCursorOption } from './dataset/constant/Cursor' import { IPageNumber } from './interface/PageNumber' import { defaultPageNumberOption } from './dataset/constant/PageNumber' import { VerticalAlign } from './dataset/enum/VerticalAlign' -import { TableBorder } from './dataset/enum/table/Table' +import { TableBorder, TdBorder } from './dataset/enum/table/Table' import { IFooter } from './interface/Footer' import { defaultFooterOption } from './dataset/constant/Footer' import { MaxHeightRatio, NumberType } from './dataset/enum/Common' @@ -259,6 +259,7 @@ export { BlockType, PaperDirection, TableBorder, + TdBorder, MaxHeightRatio, NumberType, TitleLevel, diff --git a/src/editor/interface/table/Td.ts b/src/editor/interface/table/Td.ts index c35e41b..12ddb5b 100644 --- a/src/editor/interface/table/Td.ts +++ b/src/editor/interface/table/Td.ts @@ -1,4 +1,5 @@ import { VerticalAlign } from '../../dataset/enum/VerticalAlign' +import { TdBorder } from '../../dataset/enum/table/Table' import { IElement, IElementPosition } from '../Element' import { IRow } from '../Row' @@ -20,6 +21,7 @@ export interface ITd { positionList?: IElementPosition[] verticalAlign?: VerticalAlign backgroundColor?: string + borderType?: TdBorder mainHeight?: number // 内容 + 内边距高度 realHeight?: number // 真实高度(包含跨列) realMinHeight?: number // 真实最小高度(包含跨列) diff --git a/src/editor/utils/element.ts b/src/editor/utils/element.ts index f3738b5..78682cb 100644 --- a/src/editor/utils/element.ts +++ b/src/editor/utils/element.ts @@ -14,6 +14,7 @@ import { EDITOR_ELEMENT_ZIP_ATTR, INLINE_NODE_NAME, TABLE_CONTEXT_ATTR, + TABLE_TD_ZIP_ATTR, TEXTLIKE_ELEMENT_TYPE } from '../dataset/constant/Element' import { @@ -483,12 +484,13 @@ export function zipElementList(payload: IElement[]): IElement[] { rowspan: td.rowspan, value: zipElementList(td.value) } - if (td.verticalAlign) { - zipTd.verticalAlign = td.verticalAlign - } - if (td.backgroundColor) { - zipTd.backgroundColor = td.backgroundColor - } + // 压缩单元格属性 + TABLE_TD_ZIP_ATTR.forEach(attr => { + const value = td[attr] as never + if (value !== undefined) { + zipTd[attr] = value + } + }) tr.tdList[d] = zipTd } }