diff --git a/docs/index.js b/docs/index.js index 40d08a8..a0270cb 100644 --- a/docs/index.js +++ b/docs/index.js @@ -1,3 +1,4 @@ +/* eslint-disable no-undef */ const Quill = window.Quill; const TableUp = window.TableUp.default; @@ -133,10 +134,16 @@ const quill = [ quill2, ]; window.quill = quill; -// eslint-disable-next-line no-undef -const output = [output1, output2]; -// eslint-disable-next-line no-undef -for (const [i, btn] of [btn1, btn2].entries()) { + +const output = [ + output1, + output2, +]; + +for (const [i, btn] of [ + btn1, + btn2, +].entries()) { btn.addEventListener('click', () => { const content = quill[i].getContents(); console.log(content); diff --git a/src/__tests__/table-insert-remove-merge.test.ts b/src/__tests__/table-insert-remove-merge.test.ts index da79508..41e033a 100644 --- a/src/__tests__/table-insert-remove-merge.test.ts +++ b/src/__tests__/table-insert-remove-merge.test.ts @@ -1074,7 +1074,7 @@ describe('insert row into table', () => { }); describe('unusual delete', () => { - it('delete head to inside', async () => { + it('delete head from outside table to inside', async () => { const quill = createQuillWithTableModule(`


`); const tableModule = quill.getModule('tableUp') as TableUp; tableModule.insertTable(5, 5); @@ -1101,7 +1101,7 @@ describe('unusual delete', () => { ); }); - it('delete tail to outside', async () => { + it('delete tail from inside table to outside', async () => { const quill = createQuillWithTableModule(`


`); const tableModule = quill.getModule('tableUp') as TableUp; tableModule.insertTable(5, 5); @@ -1168,7 +1168,7 @@ describe('unusual delete', () => { ); }); - it('delete inside', async () => { + it('delete table inside cell', async () => { const quill = createQuillWithTableModule(`


`); const tableModule = quill.getModule('tableUp') as TableUp; tableModule.insertTable(5, 5); diff --git a/src/__tests__/utils.ts b/src/__tests__/utils.ts index 06c7a58..d15802b 100644 --- a/src/__tests__/utils.ts +++ b/src/__tests__/utils.ts @@ -25,7 +25,7 @@ export const sortAttributes = (element: HTMLElement) => { } }); }; -export const createQuillWithTableModule = (html: string, options = true, moduleOptions = {}, register = {}) => { +export const createQuillWithTableModule = (html: string, options = {}, moduleOptions = {}, register = {}) => { Quill.register({ 'modules/tableUp': TableUp, ...register, @@ -34,7 +34,10 @@ export const createQuillWithTableModule = (html: string, options = true, moduleO container.innerHTML = normalizeHTML(html); const quill = new Quill(container, { modules: { - tableUp: options, + tableUp: { + full: true, + ...options, + }, history: { delay: 0, }, diff --git a/src/formats/container-format.ts b/src/formats/container-format.ts index 8f58855..9ac65a5 100644 --- a/src/formats/container-format.ts +++ b/src/formats/container-format.ts @@ -1,5 +1,4 @@ import type { Parchment as TypeParchment } from 'quill'; -import type TypeBlock from 'quill/blots/block'; import Quill from 'quill'; import { blotName } from '../utils'; @@ -9,6 +8,7 @@ const Block = Quill.import('blots/block') as TypeParchment.BlotConstructor; const BlockEmbed = Quill.import('blots/block/embed') as TypeParchment.BlotConstructor; export class ContainerFormat extends Container { + static tagName: string; static blotName: string = blotName.container; static scope = Parchment.Scope.BLOCK_BLOT; @@ -16,23 +16,12 @@ export class ContainerFormat extends Container { static requiredContainer: TypeParchment.BlotConstructor; static defaultChild?: TypeParchment.BlotConstructor; - clearDeltaCache() { - const blocks = this.descendants(Block, 0); - for (const child of blocks) { - (child as TypeBlock).cache = {}; - } - } - - insertBefore(blot: TypeParchment.Blot, ref?: TypeParchment.Blot | null) { - // when block line remove will merge format. but in TableCellInner will get TableCellInner format - // that will insert a new TableCellInner line. not a Block line - // detail to see Quill module -> Keyboard -> handleBackspace - if (blot.statics.blotName === this.statics.blotName && (blot as TypeParchment.ParentBlot).children.length > 0) { - super.insertBefore((blot as TypeParchment.ParentBlot).children.head!, ref); - } - else { - super.insertBefore(blot, ref); + static create(_value?: unknown) { + const node = document.createElement(this.tagName); + if (this.className) { + node.classList.add(this.className); } + return node; } insertAt(index: number, value: string, def?: any): void { diff --git a/src/formats/table-body-format.ts b/src/formats/table-body-format.ts index d098d82..2a69ae0 100644 --- a/src/formats/table-body-format.ts +++ b/src/formats/table-body-format.ts @@ -16,14 +16,6 @@ export class TableBodyFormat extends ContainerFormat { return this.domNode.dataset.tableId!; } - checkMerge(): boolean { - const next = this.next; - return ( - next !== null - && next.statics.blotName === this.statics.blotName - ); - } - // insert row at index insertRow(targetIndex: number) { const tableBlot = findParentBlot(this, blotName.tableMain); @@ -79,6 +71,15 @@ export class TableBodyFormat extends ContainerFormat { this.insertBefore(tableRow, rows[targetIndex] || null); } + checkMerge(): boolean { + const next = this.next as TableBodyFormat; + return ( + next !== null + && next.statics.blotName === this.statics.blotName + && next.tableId === this.tableId + ); + } + optimize(context: Record) { const parent = this.parent; if (parent !== null && parent.statics.blotName !== blotName.tableMain) { diff --git a/src/formats/table-cell-format.ts b/src/formats/table-cell-format.ts index 73bfbc4..9f7cf1f 100644 --- a/src/formats/table-cell-format.ts +++ b/src/formats/table-cell-format.ts @@ -86,13 +86,15 @@ export class TableCellFormat extends ContainerFormat { } checkMerge(): boolean { - const { colId, rowId } = this.domNode.dataset; - const next = this.next; + const { colId, rowId, colspan, rowspan } = this; + const next = this.next as TableCellFormat; return ( next !== null && next.statics.blotName === this.statics.blotName - && (next.domNode as HTMLElement).dataset.rowId === rowId - && (next.domNode as HTMLElement).dataset.colId === colId + && next.rowId === rowId + && next.colId === colId + && next.colspan === colspan + && next.rowspan === rowspan ); } diff --git a/src/formats/table-cell-inner-format.ts b/src/formats/table-cell-inner-format.ts index f8f35da..9fa2ae7 100644 --- a/src/formats/table-cell-inner-format.ts +++ b/src/formats/table-cell-inner-format.ts @@ -1,4 +1,5 @@ import type { Parchment as TypeParchment } from 'quill'; +import type TypeBlock from 'quill/blots/block'; import type { TableCellValue } from '../utils'; import type { TableCellFormat } from './table-cell-format'; import Quill from 'quill'; @@ -40,7 +41,10 @@ export class TableCellInnerFormat extends ContainerFormat { else { this.domNode.removeAttribute(attrName); } - this.clearDeltaCache(); + const blocks = this.descendants(Block, 0); + for (const child of blocks) { + (child as TypeBlock).cache = {}; + } } get tableId() { @@ -131,6 +135,19 @@ export class TableCellInnerFormat extends ContainerFormat { }; } + checkMerge(): boolean { + const { colId, rowId, colspan, rowspan } = this; + const next = this.next as TableCellInnerFormat; + return ( + next !== null + && next.statics.blotName === this.statics.blotName + && next.rowId === rowId + && next.colId === colId + && next.colspan === colspan + && next.rowspan === rowspan + ); + } + optimize() { const parent = this.parent; const { tableId, colId, rowId, rowspan, colspan, backgroundColor, height } = this; @@ -146,9 +163,8 @@ export class TableCellInnerFormat extends ContainerFormat { // that delta will create dom like:
... . that means TableCellInner will be an empty cell without 'block' // in this case, a 'block' should to inserted to makesure that the cell will not be remove if (this.children.length === 0) { - const block = this.scroll.create('block') as TypeParchment.BlockBlot; - block.appendChild(this.scroll.create('break')); - this.appendChild(block); + const child = this.scroll.create(this.statics.defaultChild.blotName); + this.appendChild(child); } } @@ -221,8 +237,11 @@ export class TableCellInnerFormat extends ContainerFormat { const index = selfCell.next.offset(selfRow); selfRow.split(index); } - const newCell = cellInnerBlot.wrap(blotName.tableCell, cellInnerBlotValue); - return selfRow.parent.insertBefore(newCell.wrap(blotName.tableRow, cellInnerBlotValue), selfRow.next); + const row = this.scroll.create(blotName.tableRow, cellInnerBlotValue) as TypeParchment.Parent; + const cell = this.scroll.create(blotName.tableCell, cellInnerBlotValue) as TypeParchment.Parent; + cell.appendChild(cellInnerBlot); + row.appendChild(cell); + return selfRow.parent.insertBefore(row, selfRow.next); } return selfRow.insertBefore( cellInnerBlot.wrap(blotName.tableCell, cellInnerBlotValue), diff --git a/src/formats/table-col-format.ts b/src/formats/table-col-format.ts index 5c148e7..e409e96 100644 --- a/src/formats/table-col-format.ts +++ b/src/formats/table-col-format.ts @@ -65,13 +65,13 @@ export class TableColFormat extends BlockEmbed { } checkMerge(): boolean { - const next = this.next; + const next = this.next as TableColFormat; const { tableId, colId } = this; return ( next !== null && next.statics.blotName === this.statics.blotName - && (next.domNode as HTMLElement).dataset.tableId === tableId - && (next.domNode as HTMLElement).dataset.colId === colId + && next.tableId === tableId + && next.colId === colId ); } diff --git a/src/formats/table-colgroup-format.ts b/src/formats/table-colgroup-format.ts index 1b126bf..16dd738 100644 --- a/src/formats/table-colgroup-format.ts +++ b/src/formats/table-colgroup-format.ts @@ -78,7 +78,12 @@ export class TableColgroupFormat extends ContainerFormat { } checkMerge(): boolean { - const reuslt = super.checkMerge(); + const next = this.next as TableColgroupFormat; + const reuslt = ( + next !== null + && next.statics.blotName === this.statics.blotName + && next.tableId === this.tableId + ); const tableMain = this.parent; if (reuslt && (tableMain instanceof TableMainFormat) && !tableMain.full) { tableMain.colWidthFillTable(); diff --git a/src/formats/table-main-format.ts b/src/formats/table-main-format.ts index ea1091a..648fe25 100644 --- a/src/formats/table-main-format.ts +++ b/src/formats/table-main-format.ts @@ -62,7 +62,6 @@ export class TableMainFormat extends ContainerFormat { return ( next !== null && next.statics.blotName === this.statics.blotName - && next.domNode.tagName === this.domNode.tagName && next.domNode.dataset.tableId === this.tableId ); } diff --git a/src/formats/table-row-format.ts b/src/formats/table-row-format.ts index 6529122..615396e 100644 --- a/src/formats/table-row-format.ts +++ b/src/formats/table-row-format.ts @@ -20,15 +20,6 @@ export class TableRowFormat extends ContainerFormat { declare children: TypeParchment.LinkedList; - checkMerge(): boolean { - const next = this.next; - return ( - next !== null - && next.statics.blotName === this.statics.blotName - && next.domNode.dataset.rowId === this.rowId - ); - } - get rowId() { return this.domNode.dataset.rowId!; } @@ -135,6 +126,15 @@ export class TableRowFormat extends ContainerFormat { } } + checkMerge(): boolean { + const next = this.next as TableRowFormat; + return ( + next !== null + && next.statics.blotName === this.statics.blotName + && next.rowId === this.rowId + ); + } + optimize(context: Record) { const parent = this.parent; const { tableId } = this; diff --git a/src/formats/table-wrapper-format.ts b/src/formats/table-wrapper-format.ts index dc0127b..a8c0689 100644 --- a/src/formats/table-wrapper-format.ts +++ b/src/formats/table-wrapper-format.ts @@ -1,4 +1,3 @@ -import type { Parchment as TypeParchment } from 'quill'; import { blotName } from '../utils'; import { ContainerFormat } from './container-format'; import { TableBodyFormat } from './table-body-format'; @@ -36,41 +35,21 @@ export class TableWrapperFormat extends ContainerFormat { return this.domNode.dataset.tableId!; } - insertBefore(blot: TypeParchment.Blot, ref?: TypeParchment.Blot | null) { - if (blot.statics.blotName === this.statics.blotName) { - super.insertBefore((blot as TypeParchment.ParentBlot).children.head!, ref); - } - else if (this.statics.allowedChildren.some((child: TypeParchment.BlotConstructor) => child.blotName === blot.statics.blotName)) { - super.insertBefore(blot, ref); - } - else { - // TODO: is this necessary? - if (ref) { - this.prev ? this.prev.insertBefore(blot, null) : this.parent.insertBefore(blot, this); - } - else { - this.next ? this.next.insertBefore(blot, ref) : this.parent.appendChild(blot); - } - } - } - checkMerge(): boolean { - const next = this.next; + const next = this.next as TableWrapperFormat; return ( next !== null && next.statics.blotName === this.statics.blotName - && next.domNode.tagName === this.domNode.tagName - && next.domNode.dataset.tableId === this.tableId + && next.tableId === this.tableId ); } deleteAt(index: number, length: number) { super.deleteAt(index, length); - setTimeout(() => { - const tableBodys = (this.descendants(TableBodyFormat)); - const tableColgroups = (this.descendants(TableColgroupFormat)); - if (tableBodys.length === 0 || tableColgroups.length === 0) - this.remove(); - }, 0); + const tableBodys = (this.descendants(TableBodyFormat)); + const tableColgroups = (this.descendants(TableColgroupFormat)); + if (tableBodys.length === 0 || tableColgroups.length === 0) { + this.remove(); + } } } diff --git a/src/index.ts b/src/index.ts index 92b13a8..8edae3e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -301,7 +301,7 @@ export class TableUp { return Object.assign({ customBtn: true, texts: this.resolveTexts(options.texts || {}), - full: true, + full: false, resizerSetOuter: false, icon: icons.table, } as TableUpOptions, options); @@ -546,40 +546,47 @@ export class TableUp { const paddingRight = Number.parseInt(rootStyle.paddingRight); const width = Number.parseInt(rootStyle.width) - paddingLeft - paddingRight; - let delta = new Delta().retain(range.index).insert('\n'); const tableId = randomId(); const colIds = new Array(columns).fill(0).map(() => randomId()); // insert delta data to create table const colWidth = !this.options.full ? `${Math.max(Math.floor(width / columns), tableUpSize.colMinWidthPx)}px` : `${Math.max((1 / columns) * 100, tableUpSize.colMinWidthPre)}%`; - delta = new Array(columns).fill('\n').reduce((memo, text, i) => { - memo.insert(text, { - [blotName.tableCol]: { - width: colWidth, - tableId, - colId: colIds[i], - full: this.options.full, + const delta: Record[] = [ + { retain: range.index }, + { insert: '\n' }, + ]; + + for (let i = 0; i < columns; i++) { + delta.push({ + insert: { + [blotName.tableCol]: { + width: colWidth, + tableId, + colId: colIds[i], + full: this.options.full, + }, }, }); - return memo; - }, delta); - delta = new Array(rows).fill(0).reduce((memo) => { + } + for (let j = 0; j < rows; j++) { const rowId = randomId(); - return new Array(columns).fill('\n').reduce((memo, text, i) => { - memo.insert(text, { - [blotName.tableCellInner]: { - tableId, - rowId, - colId: colIds[i], - rowspan: 1, - colspan: 1, + for (let i = 0; i < columns; i++) { + delta.push({ + insert: '\n', + attributes: { + [blotName.tableCellInner]: { + tableId, + rowId, + colId: colIds[i], + rowspan: 1, + colspan: 1, + }, }, }); - return memo; - }, memo); - }, delta); + } + } - this.quill.updateContents(delta, Quill.sources.USER); + this.quill.updateContents(new Delta(delta), Quill.sources.USER); this.quill.setSelection(range.index + columns + columns * rows + 1, Quill.sources.SILENT); this.quill.focus(); }