@@ -27,6 +27,7 @@ import type {
2727 ReadonlyContentModelBlock ,
2828 ReadonlyContentModelBlockGroup ,
2929 ReadonlyContentModelDocument ,
30+ ReadonlyContentModelTable ,
3031 ShallowMutableContentModelParagraph ,
3132} from 'roosterjs-content-model-types' ;
3233
@@ -191,44 +192,64 @@ function mergeTables(
191192 const { table : readonlyTable , colIndex, rowIndex } = tableContext ;
192193 const table = mutateBlock ( readonlyTable ) ;
193194
195+ const newTableColCount = newTable . rows [ 0 ] ?. cells . length || 0 ;
196+ const newTableRowCount = newTable . rows . length ;
197+
198+ const lastTargetColIndex = getTargetColIndex ( table , rowIndex , colIndex , newTableColCount ) ;
199+ const extraColsNeeded = lastTargetColIndex - table . rows [ 0 ] . cells . length ;
200+
201+ if ( extraColsNeeded > 0 ) {
202+ const currentColCount = table . rows [ 0 ] . cells . length ;
203+ for ( let col = 0 ; col < extraColsNeeded ; col ++ ) {
204+ const newColIndex = currentColCount + col ;
205+ for ( let k = 0 ; k < table . rows . length ; k ++ ) {
206+ const leftCell = table . rows [ k ] ?. cells [ newColIndex - 1 ] ;
207+ table . rows [ k ] . cells [ newColIndex ] = createTableCell (
208+ false /*spanLeft*/ ,
209+ false /*spanAbove*/ ,
210+ leftCell ?. isHeader ,
211+ leftCell ?. format
212+ ) ;
213+ }
214+ }
215+ }
216+
217+ const lastTargetRowIndex = getTargetRowIndex ( table , rowIndex , newTableRowCount , colIndex ) ;
218+ const extraRowsNeeded = lastTargetRowIndex - table . rows . length ;
219+
220+ if ( extraRowsNeeded > 0 ) {
221+ const currentRowCount = table . rows . length ;
222+ const colCount = table . rows [ 0 ] ?. cells . length || 0 ;
223+ for ( let row = 0 ; row < extraRowsNeeded ; row ++ ) {
224+ const newRowIndex = currentRowCount + row ;
225+ table . rows [ newRowIndex ] = {
226+ cells : [ ] ,
227+ format : { } ,
228+ height : 0 ,
229+ } ;
230+ for ( let k = 0 ; k < colCount ; k ++ ) {
231+ const aboveCell = table . rows [ newRowIndex - 1 ] ?. cells [ k ] ;
232+ table . rows [ newRowIndex ] . cells [ k ] = createTableCell (
233+ false /*spanLeft*/ ,
234+ false /*spanAbove*/ ,
235+ false /*isHeader*/ ,
236+ aboveCell ?. format
237+ ) ;
238+ }
239+ }
240+ }
241+
194242 for ( let i = 0 ; i < newTable . rows . length ; i ++ ) {
243+ const targetRowIndex = getTargetRowIndex ( table , rowIndex , i , colIndex ) ;
244+
195245 for ( let j = 0 ; j < newTable . rows [ i ] . cells . length ; j ++ ) {
196246 const newCell = newTable . rows [ i ] . cells [ j ] ;
197247
198- if ( i == 0 && colIndex + j >= table . rows [ 0 ] . cells . length ) {
199- for ( let k = 0 ; k < table . rows . length ; k ++ ) {
200- const leftCell = table . rows [ k ] ?. cells [ colIndex + j - 1 ] ;
201- table . rows [ k ] . cells [ colIndex + j ] = createTableCell (
202- false /*spanLeft*/ ,
203- false /*spanAbove*/ ,
204- leftCell ?. isHeader ,
205- leftCell ?. format
206- ) ;
207- }
208- }
209-
210- if ( j == 0 && rowIndex + i >= table . rows . length ) {
211- if ( ! table . rows [ rowIndex + i ] ) {
212- table . rows [ rowIndex + i ] = {
213- cells : [ ] ,
214- format : { } ,
215- height : 0 ,
216- } ;
217- }
248+ const targetColIndex = getTargetColIndex ( table , targetRowIndex , colIndex , j ) ;
218249
219- for ( let k = 0 ; k < table . rows [ rowIndex ] . cells . length ; k ++ ) {
220- const aboveCell = table . rows [ rowIndex + i - 1 ] ?. cells [ k ] ;
221- table . rows [ rowIndex + i ] . cells [ k ] = createTableCell (
222- false /*spanLeft*/ ,
223- false /*spanAbove*/ ,
224- false /*isHeader*/ ,
225- aboveCell ?. format
226- ) ;
227- }
228- }
250+ const oldCell = table . rows [ targetRowIndex ] ?. cells [ targetColIndex ] ;
229251
230- const oldCell = table . rows [ rowIndex + i ] . cells [ colIndex + j ] ;
231- table . rows [ rowIndex + i ] . cells [ colIndex + j ] = newCell ;
252+ table . rows [ targetRowIndex ] . cells [ targetColIndex ] = newCell ;
232253
233254 if ( i == 0 && j == 0 ) {
234255 const newMarker = createSelectionMarker ( marker . format ) ;
@@ -494,6 +515,7 @@ function getFormatWithoutSegmentFormat(
494515 KeysOfSegmentFormat . forEach ( key => delete resultFormat [ key ] ) ;
495516 return resultFormat ;
496517}
518+
497519function getHyperlinkTextColor ( sourceFormat : ContentModelHyperLinkFormat ) {
498520 const result : ContentModelHyperLinkFormat = { } ;
499521 if ( sourceFormat . textColor ) {
@@ -502,3 +524,60 @@ function getHyperlinkTextColor(sourceFormat: ContentModelHyperLinkFormat) {
502524
503525 return result ;
504526}
527+
528+ function getTargetColIndex (
529+ table : ReadonlyContentModelTable ,
530+ rowIndex : number ,
531+ startColIndex : number ,
532+ offset : number
533+ ) : number {
534+ const row = table . rows [ rowIndex ] ;
535+ if ( ! row ) {
536+ return startColIndex + offset ;
537+ }
538+
539+ if ( offset === 0 ) {
540+ return startColIndex ;
541+ }
542+
543+ let targetColIndex = startColIndex ;
544+ let logicalCellsToSkip = offset ;
545+
546+ while ( logicalCellsToSkip > 0 ) {
547+ targetColIndex ++ ;
548+
549+ if ( targetColIndex >= row . cells . length ) {
550+ logicalCellsToSkip -- ;
551+ } else if ( ! row . cells [ targetColIndex ] . spanLeft ) {
552+ logicalCellsToSkip -- ;
553+ }
554+ }
555+
556+ return targetColIndex ;
557+ }
558+
559+ function getTargetRowIndex (
560+ table : ReadonlyContentModelTable ,
561+ startRowIndex : number ,
562+ offset : number ,
563+ colIndex : number
564+ ) : number {
565+ if ( offset === 0 ) {
566+ return startRowIndex ;
567+ }
568+
569+ let targetRowIndex = startRowIndex ;
570+ let logicalRowsToSkip = offset ;
571+
572+ while ( logicalRowsToSkip > 0 ) {
573+ targetRowIndex ++ ;
574+
575+ if ( targetRowIndex >= table . rows . length ) {
576+ logicalRowsToSkip -- ;
577+ } else if ( ! table . rows [ targetRowIndex ] ?. cells [ colIndex ] ?. spanAbove ) {
578+ logicalRowsToSkip -- ;
579+ }
580+ }
581+
582+ return targetRowIndex ;
583+ }
0 commit comments