tableclipboard-paste.js 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /* globals document console */
  6. import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
  7. import BlockQuoteEditing from '@ckeditor/ckeditor5-block-quote/src/blockquoteediting';
  8. import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
  9. import HorizontalLineEditing from '@ckeditor/ckeditor5-horizontal-line/src/horizontallineediting';
  10. import ImageCaptionEditing from '@ckeditor/ckeditor5-image/src/imagecaption/imagecaptionediting';
  11. import ImageEditing from '@ckeditor/ckeditor5-image/src/image/imageediting';
  12. import ListEditing from '@ckeditor/ckeditor5-list/src/listediting';
  13. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  14. import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
  15. import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  16. import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
  17. import { assertSelectedCells, modelTable, viewTable } from './_utils/utils';
  18. import TableEditing from '../src/tableediting';
  19. import TableCellPropertiesEditing from '../src/tablecellproperties/tablecellpropertiesediting';
  20. import TableWalker from '../src/tablewalker';
  21. import TableClipboard from '../src/tableclipboard';
  22. describe( 'table clipboard', () => {
  23. let editor, model, modelRoot, tableSelection, viewDocument, element;
  24. testUtils.createSinonSandbox();
  25. beforeEach( () => {
  26. element = document.createElement( 'div' );
  27. document.body.appendChild( element );
  28. } );
  29. afterEach( async () => {
  30. await editor.destroy();
  31. element.remove();
  32. } );
  33. describe( 'Clipboard integration - paste (selection scenarios)', () => {
  34. beforeEach( async () => {
  35. await createEditor();
  36. setModelData( model, modelTable( [
  37. [ '00[]', '01', '02', '03' ],
  38. [ '10', '11', '12', '13' ],
  39. [ '20', '21', '22', '23' ],
  40. [ '30', '31', '32', '33' ]
  41. ] ) );
  42. } );
  43. it( 'should be disabled in a readonly mode', () => {
  44. editor.isReadOnly = true;
  45. tableSelection.setCellSelection(
  46. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  47. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  48. );
  49. const data = pasteTable( [
  50. [ 'aa', 'ab' ],
  51. [ 'ba', 'bb' ]
  52. ] );
  53. editor.isReadOnly = false;
  54. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  55. [ '00', '01', '02', '03' ],
  56. [ '10', '11', '12', '13' ],
  57. [ '20', '21', '22', '23' ],
  58. [ '30', '31', '32', '33' ]
  59. ] ) );
  60. sinon.assert.calledOnce( data.preventDefault );
  61. } );
  62. it( 'should allow normal paste if no table cells are selected', () => {
  63. const data = {
  64. dataTransfer: createDataTransfer(),
  65. preventDefault: sinon.spy(),
  66. stopPropagation: sinon.spy()
  67. };
  68. data.dataTransfer.setData( 'text/html', '<p>foo</p>' );
  69. viewDocument.fire( 'paste', data );
  70. editor.isReadOnly = false;
  71. assertEqualMarkup( getModelData( model ), modelTable( [
  72. [ '00foo[]', '01', '02', '03' ],
  73. [ '10', '11', '12', '13' ],
  74. [ '20', '21', '22', '23' ],
  75. [ '30', '31', '32', '33' ]
  76. ] ) );
  77. } );
  78. it( 'should not alter model.insertContent if selectable is different from document selection', () => {
  79. model.change( writer => {
  80. writer.setSelection( modelRoot.getNodeByPath( [ 0, 0, 0 ] ), 0 );
  81. const selectedTableCells = model.createSelection( [
  82. model.createRangeOn( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) ),
  83. model.createRangeOn( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) ),
  84. model.createRangeOn( modelRoot.getNodeByPath( [ 0, 1, 0 ] ) ),
  85. model.createRangeOn( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) )
  86. ] );
  87. const tableToInsert = editor.plugins.get( 'TableUtils' ).createTable( writer, 2, 2 );
  88. for ( const { cell } of new TableWalker( tableToInsert ) ) {
  89. writer.insertText( 'foo', cell.getChild( 0 ), 0 );
  90. }
  91. model.insertContent( tableToInsert, selectedTableCells );
  92. } );
  93. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  94. [ '', '', '02', '03' ],
  95. [ '', '', '12', '13' ],
  96. [ '20', '21', '22', '23' ],
  97. [ '30', '31', '32', '33' ]
  98. ] ) );
  99. } );
  100. it( 'should not alter model.insertContent if no table cells are selected', () => {
  101. model.change( writer => {
  102. writer.insertElement( 'paragraph', modelRoot.getChild( 0 ), 'before' );
  103. writer.setSelection( modelRoot.getChild( 0 ), 'before' );
  104. } );
  105. const data = {
  106. dataTransfer: createDataTransfer(),
  107. preventDefault: sinon.spy(),
  108. stopPropagation: sinon.spy()
  109. };
  110. data.dataTransfer.setData( 'text/html', '<p>foo</p>' );
  111. viewDocument.fire( 'paste', data );
  112. editor.isReadOnly = false;
  113. assertEqualMarkup( getModelData( model ), '<paragraph>foo[]</paragraph>' + modelTable( [
  114. [ '00', '01', '02', '03' ],
  115. [ '10', '11', '12', '13' ],
  116. [ '20', '21', '22', '23' ],
  117. [ '30', '31', '32', '33' ]
  118. ] ) );
  119. } );
  120. it( 'should not alter model.insertContent if no table pasted', () => {
  121. tableSelection.setCellSelection(
  122. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  123. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  124. );
  125. const data = {
  126. dataTransfer: createDataTransfer(),
  127. preventDefault: sinon.spy(),
  128. stopPropagation: sinon.spy()
  129. };
  130. data.dataTransfer.setData( 'text/html', '<p>foo</p>' );
  131. viewDocument.fire( 'paste', data );
  132. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  133. [ 'foo', '', '02', '03' ],
  134. [ '', '', '12', '13' ],
  135. [ '20', '21', '22', '23' ],
  136. [ '30', '31', '32', '33' ]
  137. ] ) );
  138. } );
  139. it( 'should not alter model.insertContent if mixed content is pasted (table + paragraph)', () => {
  140. tableSelection.setCellSelection(
  141. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  142. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  143. );
  144. const table = viewTable( [
  145. [ 'aa', 'ab' ],
  146. [ 'ba', 'bb' ] ] );
  147. const data = {
  148. dataTransfer: createDataTransfer(),
  149. preventDefault: sinon.spy(),
  150. stopPropagation: sinon.spy()
  151. };
  152. data.dataTransfer.setData( 'text/html', `${ table }<p>foo</p>` );
  153. viewDocument.fire( 'paste', data );
  154. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  155. [ 'foo', '', '02', '03' ],
  156. [ '', '', '12', '13' ],
  157. [ '20', '21', '22', '23' ],
  158. [ '30', '31', '32', '33' ]
  159. ] ) );
  160. } );
  161. it( 'should not alter model.insertContent if mixed content is pasted (paragraph + table)', () => {
  162. tableSelection.setCellSelection(
  163. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  164. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  165. );
  166. const table = viewTable( [
  167. [ 'aa', 'ab' ],
  168. [ 'ba', 'bb' ] ] );
  169. const data = {
  170. dataTransfer: createDataTransfer(),
  171. preventDefault: sinon.spy(),
  172. stopPropagation: sinon.spy()
  173. };
  174. data.dataTransfer.setData( 'text/html', `<p>foo</p>${ table }` );
  175. viewDocument.fire( 'paste', data );
  176. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  177. [ 'foo', '', '02', '03' ],
  178. [ '', '', '12', '13' ],
  179. [ '20', '21', '22', '23' ],
  180. [ '30', '31', '32', '33' ]
  181. ] ) );
  182. } );
  183. it( 'should not alter model.insertContent if mixed content is pasted (table + table)', () => {
  184. tableSelection.setCellSelection(
  185. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  186. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  187. );
  188. const table = viewTable( [
  189. [ 'aa', 'ab' ],
  190. [ 'ba', 'bb' ] ] );
  191. const data = {
  192. dataTransfer: createDataTransfer(),
  193. preventDefault: sinon.spy(),
  194. stopPropagation: sinon.spy()
  195. };
  196. data.dataTransfer.setData( 'text/html', `${ table }${ table }` );
  197. viewDocument.fire( 'paste', data );
  198. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  199. [ '', '', '02', '03' ],
  200. [ '', '', '12', '13' ],
  201. [ '20', '21', '22', '23' ],
  202. [ '30', '31', '32', '33' ]
  203. ] ) );
  204. } );
  205. it( 'should alter model.insertContent if selectable is a document selection', () => {
  206. tableSelection.setCellSelection(
  207. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  208. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  209. );
  210. model.change( writer => {
  211. const tableToInsert = editor.plugins.get( 'TableUtils' ).createTable( writer, 2, 2 );
  212. for ( const { cell } of new TableWalker( tableToInsert ) ) {
  213. writer.insertText( 'foo', cell.getChild( 0 ), 0 );
  214. }
  215. model.insertContent( tableToInsert, editor.model.document.selection );
  216. } );
  217. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  218. [ 'foo', 'foo', '02', '03' ],
  219. [ 'foo', 'foo', '12', '13' ],
  220. [ '20', '21', '22', '23' ],
  221. [ '30', '31', '32', '33' ]
  222. ] ) );
  223. } );
  224. it( 'should block non-rectangular selection', () => {
  225. setModelData( model, modelTable( [
  226. [ { contents: '00', colspan: 3 } ],
  227. [ '10', '11', '12' ],
  228. [ '20', '21', '22' ]
  229. ] ) );
  230. tableSelection.setCellSelection(
  231. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  232. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  233. );
  234. // Catches the temporary console log in the CK_DEBUG mode.
  235. sinon.stub( console, 'log' );
  236. pasteTable( [
  237. [ 'aa', 'ab' ],
  238. [ 'ba', 'bb' ]
  239. ] );
  240. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  241. [ { contents: '00', colspan: 3 } ],
  242. [ '10', '11', '12' ],
  243. [ '20', '21', '22' ]
  244. ] ) );
  245. } );
  246. describe( 'single cell selected', () => {
  247. beforeEach( () => {
  248. setModelData( model, modelTable( [
  249. [ '00[]', '01', '02' ],
  250. [ '10', '11', '12' ],
  251. [ '20', '21', '22' ]
  252. ] ) );
  253. } );
  254. it( 'with selection on the first cell', () => {
  255. tableSelection.setCellSelection(
  256. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  257. modelRoot.getNodeByPath( [ 0, 0, 0 ] )
  258. );
  259. pasteTable( [
  260. [ 'aa', 'ab' ],
  261. [ 'ba', 'bb' ]
  262. ] );
  263. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  264. [ 'aa', 'ab', '02' ],
  265. [ 'ba', 'bb', '12' ],
  266. [ '20', '21', '22' ]
  267. ] ) );
  268. } );
  269. it( 'with selection in the first cell', () => {
  270. pasteTable( [
  271. [ 'aa', 'ab' ],
  272. [ 'ba', 'bb' ]
  273. ] );
  274. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  275. [ 'aa', 'ab', '02' ],
  276. [ 'ba', 'bb', '12' ],
  277. [ '20', '21', '22' ]
  278. ] ) );
  279. } );
  280. it( 'with selection on the middle cell of the first row', () => {
  281. tableSelection.setCellSelection(
  282. modelRoot.getNodeByPath( [ 0, 0, 1 ] ),
  283. modelRoot.getNodeByPath( [ 0, 0, 1 ] )
  284. );
  285. pasteTable( [
  286. [ 'aa', 'ab' ],
  287. [ 'ba', 'bb' ]
  288. ] );
  289. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  290. [ '00', 'aa', 'ab' ],
  291. [ '10', 'ba', 'bb' ],
  292. [ '20', '21', '22' ]
  293. ] ) );
  294. } );
  295. it( 'with selection on the last cell of the first row', () => {
  296. tableSelection.setCellSelection(
  297. modelRoot.getNodeByPath( [ 0, 0, 2 ] ),
  298. modelRoot.getNodeByPath( [ 0, 0, 2 ] )
  299. );
  300. pasteTable( [
  301. [ 'aa', 'ab' ],
  302. [ 'ba', 'bb' ]
  303. ] );
  304. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  305. [ '00', '01', 'aa', 'ab' ],
  306. [ '10', '11', 'ba', 'bb' ],
  307. [ '20', '21', '22', '' ]
  308. ] ) );
  309. } );
  310. it( 'with selection on the middle cell of the first column', () => {
  311. tableSelection.setCellSelection(
  312. modelRoot.getNodeByPath( [ 0, 1, 0 ] ),
  313. modelRoot.getNodeByPath( [ 0, 1, 0 ] )
  314. );
  315. pasteTable( [
  316. [ 'aa', 'ab' ],
  317. [ 'ba', 'bb' ]
  318. ] );
  319. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  320. [ '00', '01', '02' ],
  321. [ 'aa', 'ab', '12' ],
  322. [ 'ba', 'bb', '22' ]
  323. ] ) );
  324. } );
  325. it( 'with selection on the last cell of the first column', () => {
  326. tableSelection.setCellSelection(
  327. modelRoot.getNodeByPath( [ 0, 2, 0 ] ),
  328. modelRoot.getNodeByPath( [ 0, 2, 0 ] )
  329. );
  330. pasteTable( [
  331. [ 'aa', 'ab' ],
  332. [ 'ba', 'bb' ]
  333. ] );
  334. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  335. [ '00', '01', '02' ],
  336. [ '10', '11', '12' ],
  337. [ 'aa', 'ab', '22' ],
  338. [ 'ba', 'bb', '' ]
  339. ] ) );
  340. } );
  341. it( 'with selection on the last cell of the last column', () => {
  342. tableSelection.setCellSelection(
  343. modelRoot.getNodeByPath( [ 0, 2, 2 ] ),
  344. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  345. );
  346. pasteTable( [
  347. [ 'aa', 'ab' ],
  348. [ 'ba', 'bb' ]
  349. ] );
  350. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  351. [ '00', '01', '02', '' ],
  352. [ '10', '11', '12', '' ],
  353. [ '20', '21', 'aa', 'ab' ],
  354. [ '', '', 'ba', 'bb' ]
  355. ] ) );
  356. } );
  357. } );
  358. describe( 'pasted table is equal to the selected area', () => {
  359. describe( 'no spans', () => {
  360. it( 'handles simple table paste to a simple table fragment - at the beginning of a table', () => {
  361. tableSelection.setCellSelection(
  362. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  363. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  364. );
  365. pasteTable( [
  366. [ 'aa', 'ab' ],
  367. [ 'ba', 'bb' ]
  368. ] );
  369. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  370. [ 'aa', 'ab', '02', '03' ],
  371. [ 'ba', 'bb', '12', '13' ],
  372. [ '20', '21', '22', '23' ],
  373. [ '30', '31', '32', '33' ]
  374. ] ) );
  375. assertSelectedCells( model, [
  376. [ 1, 1, 0, 0 ],
  377. [ 1, 1, 0, 0 ],
  378. [ 0, 0, 0, 0 ],
  379. [ 0, 0, 0, 0 ]
  380. ] );
  381. } );
  382. it( 'handles simple table paste to a simple table fragment - at the end of a table', () => {
  383. tableSelection.setCellSelection(
  384. modelRoot.getNodeByPath( [ 0, 2, 2 ] ),
  385. modelRoot.getNodeByPath( [ 0, 3, 3 ] )
  386. );
  387. pasteTable( [
  388. [ 'aa', 'ab' ],
  389. [ 'ba', 'bb' ]
  390. ] );
  391. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  392. [ '00', '01', '02', '03' ],
  393. [ '10', '11', '12', '13' ],
  394. [ '20', '21', 'aa', 'ab' ],
  395. [ '30', '31', 'ba', 'bb' ]
  396. ] ) );
  397. assertSelectedCells( model, [
  398. [ 0, 0, 0, 0 ],
  399. [ 0, 0, 0, 0 ],
  400. [ 0, 0, 1, 1 ],
  401. [ 0, 0, 1, 1 ]
  402. ] );
  403. } );
  404. it( 'handles simple table paste to a simple table fragment - in the middle of a table', () => {
  405. tableSelection.setCellSelection(
  406. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  407. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  408. );
  409. pasteTable( [
  410. [ 'aa', 'ab' ],
  411. [ 'ba', 'bb' ]
  412. ] );
  413. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  414. [ '00', '01', '02', '03' ],
  415. [ '10', 'aa', 'ab', '13' ],
  416. [ '20', 'ba', 'bb', '23' ],
  417. [ '30', '31', '32', '33' ]
  418. ] ) );
  419. assertSelectedCells( model, [
  420. [ 0, 0, 0, 0 ],
  421. [ 0, 1, 1, 0 ],
  422. [ 0, 1, 1, 0 ],
  423. [ 0, 0, 0, 0 ]
  424. ] );
  425. } );
  426. it( 'handles simple row paste to a simple row fragment - in the middle of a table', () => {
  427. tableSelection.setCellSelection(
  428. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  429. modelRoot.getNodeByPath( [ 0, 1, 2 ] )
  430. );
  431. pasteTable( [
  432. [ 'aa', 'ab' ]
  433. ] );
  434. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  435. [ '00', '01', '02', '03' ],
  436. [ '10', 'aa', 'ab', '13' ],
  437. [ '20', '21', '22', '23' ],
  438. [ '30', '31', '32', '33' ]
  439. ] ) );
  440. assertSelectedCells( model, [
  441. [ 0, 0, 0, 0 ],
  442. [ 0, 1, 1, 0 ],
  443. [ 0, 0, 0, 0 ],
  444. [ 0, 0, 0, 0 ]
  445. ] );
  446. } );
  447. it( 'handles simple column paste to a simple column fragment - in the middle of a table', () => {
  448. tableSelection.setCellSelection(
  449. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  450. modelRoot.getNodeByPath( [ 0, 2, 1 ] )
  451. );
  452. pasteTable( [
  453. [ 'aa' ],
  454. [ 'ba' ]
  455. ] );
  456. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  457. [ '00', '01', '02', '03' ],
  458. [ '10', 'aa', '12', '13' ],
  459. [ '20', 'ba', '22', '23' ],
  460. [ '30', '31', '32', '33' ]
  461. ] ) );
  462. assertSelectedCells( model, [
  463. [ 0, 0, 0, 0 ],
  464. [ 0, 1, 0, 0 ],
  465. [ 0, 1, 0, 0 ],
  466. [ 0, 0, 0, 0 ]
  467. ] );
  468. } );
  469. it( 'handles simple table paste to a simple table fragment - whole table selected', () => {
  470. tableSelection.setCellSelection(
  471. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  472. modelRoot.getNodeByPath( [ 0, 3, 3 ] )
  473. );
  474. pasteTable( [
  475. [ 'aa', 'ab', 'ac', 'ad' ],
  476. [ 'ba', 'bb', 'bc', 'bd' ],
  477. [ 'ca', 'cb', 'cc', 'cd' ],
  478. [ 'da', 'db', 'dc', 'dd' ]
  479. ] );
  480. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  481. [ 'aa', 'ab', 'ac', 'ad' ],
  482. [ 'ba', 'bb', 'bc', 'bd' ],
  483. [ 'ca', 'cb', 'cc', 'cd' ],
  484. [ 'da', 'db', 'dc', 'dd' ]
  485. ] ) );
  486. assertSelectedCells( model, [
  487. [ 1, 1, 1, 1 ],
  488. [ 1, 1, 1, 1 ],
  489. [ 1, 1, 1, 1 ],
  490. [ 1, 1, 1, 1 ]
  491. ] );
  492. } );
  493. } );
  494. describe( 'pasted table has spans', () => {
  495. it( 'handles pasting table that has cell with colspan', () => {
  496. tableSelection.setCellSelection(
  497. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  498. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  499. );
  500. pasteTable( [
  501. [ { colspan: 2, contents: 'aa' } ],
  502. [ 'ba', 'bb' ]
  503. ] );
  504. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  505. [ '00', '01', '02', '03' ],
  506. [ '10', { colspan: 2, contents: 'aa' }, '13' ],
  507. [ '20', 'ba', 'bb', '23' ],
  508. [ '30', '31', '32', '33' ]
  509. ] ) );
  510. /* eslint-disable no-multi-spaces */
  511. assertSelectedCells( model, [
  512. [ 0, 0, 0, 0 ],
  513. [ 0, 1, 0 ],
  514. [ 0, 1, 1, 0 ],
  515. [ 0, 0, 0, 0 ]
  516. ] );
  517. /* eslint-enable no-multi-spaces */
  518. } );
  519. it( 'handles pasting table that has many cells with various colspan', () => {
  520. tableSelection.setCellSelection(
  521. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  522. modelRoot.getNodeByPath( [ 0, 3, 2 ] )
  523. );
  524. pasteTable( [
  525. [ 'aa', { colspan: 2, contents: 'ab' } ],
  526. [ { colspan: 3, contents: 'ba' } ],
  527. [ 'ca', 'cb', 'cc' ],
  528. [ { colspan: 2, contents: 'da' }, 'dc' ]
  529. ] );
  530. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  531. [ 'aa', { colspan: 2, contents: 'ab' }, '03' ],
  532. [ { colspan: 3, contents: 'ba' }, '13' ],
  533. [ 'ca', 'cb', 'cc', '23' ],
  534. [ { colspan: 2, contents: 'da' }, 'dc', '33' ]
  535. ] ) );
  536. /* eslint-disable no-multi-spaces */
  537. assertSelectedCells( model, [
  538. [ 1, 1, 0 ],
  539. [ 1, 0 ],
  540. [ 1, 1, 1, 0 ],
  541. [ 1, 1, 0 ]
  542. ] );
  543. /* eslint-enable no-multi-spaces */
  544. } );
  545. it( 'handles pasting table that has cell with rowspan', () => {
  546. tableSelection.setCellSelection(
  547. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  548. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  549. );
  550. pasteTable( [
  551. [ { rowspan: 2, contents: 'aa' }, 'ab' ],
  552. [ 'bb' ]
  553. ] );
  554. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  555. [ '00', '01', '02', '03' ],
  556. [ '10', { rowspan: 2, contents: 'aa' }, 'ab', '13' ],
  557. [ '20', 'bb', '23' ],
  558. [ '30', '31', '32', '33' ]
  559. ] ) );
  560. /* eslint-disable no-multi-spaces */
  561. assertSelectedCells( model, [
  562. [ 0, 0, 0, 0 ],
  563. [ 0, 1, 1, 0 ],
  564. [ 0, 1, 0 ],
  565. [ 0, 0, 0, 0 ]
  566. ] );
  567. /* eslint-enable no-multi-spaces */
  568. } );
  569. it( 'handles pasting table that has many cells with various rowspan', () => {
  570. tableSelection.setCellSelection(
  571. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  572. modelRoot.getNodeByPath( [ 0, 2, 3 ] )
  573. );
  574. pasteTable( [
  575. [ 'aa', { rowspan: 3, contents: 'ab' }, { rowspan: 2, contents: 'ac' }, 'ad' ],
  576. [ { rowspan: 2, contents: 'ba' }, 'bd' ],
  577. [ 'cc', 'cd' ]
  578. ] );
  579. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  580. [ 'aa', { rowspan: 3, contents: 'ab' }, { rowspan: 2, contents: 'ac' }, 'ad' ],
  581. [ { rowspan: 2, contents: 'ba' }, 'bd' ],
  582. [ 'cc', 'cd' ],
  583. [ '30', '31', '32', '33' ]
  584. ] ) );
  585. /* eslint-disable no-multi-spaces */
  586. assertSelectedCells( model, [
  587. [ 1, 1, 1, 1 ],
  588. [ 1, 1 ],
  589. [ 1, 1 ],
  590. [ 0, 0, 0, 0 ]
  591. ] );
  592. /* eslint-enable no-multi-spaces */
  593. } );
  594. it( 'handles pasting multi-spanned table', () => {
  595. setModelData( model, modelTable( [
  596. [ '00', '01', '02', '03', '04', '05' ],
  597. [ '10', '11', '12', '13', '14', '15' ],
  598. [ '20', '21', '22', '23', '24', '25' ],
  599. [ '30', '31', '32', '33', '34', '35' ],
  600. [ '40', '41', '42', '43', '44', '45' ]
  601. ] ) );
  602. tableSelection.setCellSelection(
  603. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  604. modelRoot.getNodeByPath( [ 0, 3, 4 ] )
  605. );
  606. // +----+----+----+----+----+
  607. // | aa | ac | ad | ae |
  608. // +----+----+----+----+ +
  609. // | ba | bb | |
  610. // +----+ +----+
  611. // | ca | | ce |
  612. // + +----+----+----+----+
  613. // | | db | dc | dd |
  614. // +----+----+----+----+----+
  615. pasteTable( [
  616. [ { contents: 'aa', colspan: 2 }, 'ac', 'ad', { contents: 'ae', rowspan: 2 } ],
  617. [ 'ba', { contents: 'bb', colspan: 3, rowspan: 2 } ],
  618. [ { contents: 'ca', rowspan: 2 }, 'ce' ],
  619. [ 'db', 'dc', { contents: 'dd', colspan: 2 } ]
  620. ] );
  621. // +----+----+----+----+----+----+
  622. // | aa | ac | ad | ae | 05 |
  623. // +----+----+----+----+ +----+
  624. // | ba | bb | | 15 |
  625. // +----+ +----+----+
  626. // | ca | | ce | 25 |
  627. // + +----+----+----+----+----+
  628. // | | db | dc | dd | 35 |
  629. // +----+----+----+----+----+----+
  630. // | 40 | 41 | 42 | 43 | 44 | 45 |
  631. // +----+----+----+----+----+----+
  632. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  633. [ { contents: 'aa', colspan: 2 }, 'ac', 'ad', { contents: 'ae', rowspan: 2 }, '05' ],
  634. [ 'ba', { contents: 'bb', colspan: 3, rowspan: 2 }, '15' ],
  635. [ { contents: 'ca', rowspan: 2 }, 'ce', '25' ],
  636. [ 'db', 'dc', { contents: 'dd', colspan: 2 }, '35' ],
  637. [ '40', '41', '42', '43', '44', '45' ]
  638. ] ) );
  639. /* eslint-disable no-multi-spaces */
  640. assertSelectedCells( model, [
  641. [ 1, 1, 1, 1, 0 ],
  642. [ 1, 1, 0 ],
  643. [ 1, 1, 0 ],
  644. [ 1, 1, 1, 0 ],
  645. [ 0, 0, 0, 0, 0, 0 ]
  646. ] );
  647. /* eslint-enable no-multi-spaces */
  648. } );
  649. } );
  650. describe( 'content table has spans', () => {
  651. it( 'handles pasting simple table over a table with colspans (no colspan exceeds selection)', () => {
  652. setModelData( model, modelTable( [
  653. [ '00[]', '01', '02', '03' ],
  654. [ { colspan: 3, contents: '10' }, '13' ],
  655. [ { colspan: 2, contents: '20' }, '22', '23' ],
  656. [ '30', '31', { colspan: 2, contents: '31' } ]
  657. ] ) );
  658. tableSelection.setCellSelection(
  659. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  660. modelRoot.getNodeByPath( [ 0, 2, 1 ] )
  661. );
  662. pasteTable( [
  663. [ 'aa', 'ab', 'ac' ],
  664. [ 'ba', 'bb', 'bc' ],
  665. [ 'ca', 'cb', 'cc' ]
  666. ] );
  667. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  668. [ 'aa', 'ab', 'ac', '03' ],
  669. [ 'ba', 'bb', 'bc', '13' ],
  670. [ 'ca', 'cb', 'cc', '23' ],
  671. [ '30', '31', { colspan: 2, contents: '31' } ]
  672. ] ) );
  673. /* eslint-disable no-multi-spaces */
  674. assertSelectedCells( model, [
  675. [ 1, 1, 1, 0 ],
  676. [ 1, 1, 1, 0 ],
  677. [ 1, 1, 1, 0 ],
  678. [ 0, 0, 0 ]
  679. ] );
  680. /* eslint-enable no-multi-spaces */
  681. } );
  682. it( 'handles pasting simple table over a table with rowspans (no rowspan exceeds selection)', () => {
  683. setModelData( model, modelTable( [
  684. [ '00', { rowspan: 3, contents: '01' }, { rowspan: 2, contents: '02' }, '03' ],
  685. [ { rowspan: 2, contents: '10' }, '13' ],
  686. [ '22', '23' ],
  687. [ '30', '31', '32', '33' ]
  688. ] ) );
  689. tableSelection.setCellSelection(
  690. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  691. modelRoot.getNodeByPath( [ 0, 2, 0 ] )
  692. );
  693. pasteTable( [
  694. [ 'aa', 'ab', 'ac' ],
  695. [ 'ba', 'bb', 'bc' ],
  696. [ 'ca', 'cb', 'cc' ]
  697. ] );
  698. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  699. [ 'aa', 'ab', 'ac', '03' ],
  700. [ 'ba', 'bb', 'bc', '13' ],
  701. [ 'ca', 'cb', 'cc', '23' ],
  702. [ '30', '31', '32', '33' ]
  703. ] ) );
  704. assertSelectedCells( model, [
  705. [ 1, 1, 1, 0 ],
  706. [ 1, 1, 1, 0 ],
  707. [ 1, 1, 1, 0 ],
  708. [ 0, 0, 0, 0 ]
  709. ] );
  710. } );
  711. it( 'handles pasting simple table over table with multi-spans (no span exceeds selection)', () => {
  712. // +----+----+----+----+----+----+
  713. // | 00 | 02 | 03 | 05 |
  714. // + + + +----+
  715. // | | | | 15 |
  716. // +----+----+----+ +----+
  717. // | 20 | 21 | | 25 |
  718. // + +----+----+----+----+----+
  719. // | | 31 | 32 | 34 | 35 |
  720. // +----+----+----+----+----+----+
  721. // | 40 | 41 | 42 | 43 | 44 | 45 |
  722. // +----+----+----+----+----+----+
  723. setModelData( model, modelTable( [
  724. [
  725. { contents: '00', colspan: 2, rowspan: 2 },
  726. { contents: '02', rowspan: 2 },
  727. { contents: '03', colspan: 2, rowspan: 3 },
  728. '05'
  729. ],
  730. [ '15' ],
  731. [ { contents: '20', rowspan: 2 }, { contents: '21', colspan: 2 }, '25' ],
  732. [ '31', { contents: '32', colspan: 2 }, '34', '35' ],
  733. [ '40', '41', '42', '43', '44', '45' ]
  734. ] ) );
  735. tableSelection.setCellSelection(
  736. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  737. modelRoot.getNodeByPath( [ 0, 3, 2 ] ) // Cell 34.
  738. );
  739. pasteTable( [
  740. [ 'aa', 'ab', 'ac', 'ad', 'ae' ],
  741. [ 'ba', 'bb', 'bc', 'bd', 'be' ],
  742. [ 'ca', 'cb', 'cc', 'cd', 'ce' ],
  743. [ 'da', 'db', 'dc', 'dd', 'de' ]
  744. ] );
  745. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  746. [ 'aa', 'ab', 'ac', 'ad', 'ae', '05' ],
  747. [ 'ba', 'bb', 'bc', 'bd', 'be', '15' ],
  748. [ 'ca', 'cb', 'cc', 'cd', 'ce', '25' ],
  749. [ 'da', 'db', 'dc', 'dd', 'de', '35' ],
  750. [ '40', '41', '42', '43', '44', '45' ]
  751. ] ) );
  752. assertSelectedCells( model, [
  753. [ 1, 1, 1, 1, 1, 0 ],
  754. [ 1, 1, 1, 1, 1, 0 ],
  755. [ 1, 1, 1, 1, 1, 0 ],
  756. [ 1, 1, 1, 1, 1, 0 ],
  757. [ 0, 0, 0, 0, 0, 0 ]
  758. ] );
  759. } );
  760. it( 'handles pasting simple table over a table with rowspan (rowspan before selection)', () => {
  761. // +----+----+----+----+----+
  762. // | 00 | 01 | 02 | 03 | 04 |
  763. // +----+----+----+----+----+
  764. // | 10 | 11 | 12 | 13 | 14 |
  765. // +----+ +----+----+----+
  766. // | 20 | | 22 | 23 | 24 |
  767. // +----+ +----+----+----+
  768. // | 30 | | 32 | 33 | 34 |
  769. // +----+----+----+----+----+
  770. // | 40 | 41 | 42 | 43 | 44 |
  771. // +----+----+----+----+----+
  772. setModelData( model, modelTable( [
  773. [ '00', '01', '02', '03', '04' ],
  774. [ '10', { contents: '11', rowspan: 3 }, '12', '13', '14' ],
  775. [ '20', '22', '23', '24' ],
  776. [ '30', '32', '33', '34' ],
  777. [ '40', '41', '42', '43', '44' ]
  778. ] ) );
  779. tableSelection.setCellSelection(
  780. modelRoot.getNodeByPath( [ 0, 1, 2 ] ),
  781. modelRoot.getNodeByPath( [ 0, 3, 2 ] ) // Cell 33.
  782. );
  783. pasteTable( [
  784. [ 'aa', 'ab' ],
  785. [ 'ba', 'bb' ],
  786. [ 'ca', 'cb' ]
  787. ] );
  788. // +----+----+----+----+----+
  789. // | 00 | 01 | 02 | 03 | 04 |
  790. // +----+----+----+----+----+
  791. // | 10 | 11 | aa | ab | 14 |
  792. // +----+ +----+----+----+
  793. // | 20 | | ba | bb | 24 |
  794. // +----+ +----+----+----+
  795. // | 30 | | ca | cb | 34 |
  796. // +----+----+----+----+----+
  797. // | 40 | 41 | 42 | 43 | 44 |
  798. // +----+----+----+----+----+
  799. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  800. [ '00', '01', '02', '03', '04' ],
  801. [ '10', { contents: '11', rowspan: 3 }, 'aa', 'ab', '14' ],
  802. [ '20', 'ba', 'bb', '24' ],
  803. [ '30', 'ca', 'cb', '34' ],
  804. [ '40', '41', '42', '43', '44' ]
  805. ] ) );
  806. /* eslint-disable no-multi-spaces */
  807. assertSelectedCells( model, [
  808. [ 0, 0, 0, 0, 0 ],
  809. [ 0, 0, 1, 1, 0 ],
  810. [ 0, 1, 1, 0 ],
  811. [ 0, 1, 1, 0 ],
  812. [ 0, 0, 0, 0, 0 ]
  813. ] );
  814. /* eslint-enable no-multi-spaces */
  815. } );
  816. it( 'handles pasting simple table over a table with rowspans (rowspan before selection)', () => {
  817. // +----+----+----+----+----+----+
  818. // | 00 | 01 | 02 | 03 | 04 | 05 |
  819. // +----+----+----+----+----+----+
  820. // | 10 | 12 | 13 | 14 | 15 |
  821. // +----+----+----+----+----+----+
  822. // | 20 | 23 | 24 | 25 |
  823. // +----+----+----+----+----+----+
  824. // | 30 | 31 | 32 | 33 | 34 | 35 |
  825. // +----+----+----+----+----+----+
  826. setModelData( model, modelTable( [
  827. [ '00', '01', '02', '03', '04', '05' ],
  828. [ { contents: '10', colspan: 2 }, '12', '13', '14', '15' ],
  829. [ { contents: '20', colspan: 3 }, '23', '24', '25' ],
  830. [ '30', '31', '32', '33', '34', '35' ]
  831. ] ) );
  832. tableSelection.setCellSelection(
  833. modelRoot.getNodeByPath( [ 0, 1, 2 ] ), // Cell 13.
  834. modelRoot.getNodeByPath( [ 0, 2, 2 ] ) // Cell 24.
  835. );
  836. pasteTable( [
  837. [ 'aa', 'ab' ],
  838. [ 'ba', 'bb' ]
  839. ] );
  840. // +----+----+----+----+----+----+
  841. // | 00 | 01 | 02 | 03 | 04 | 05 |
  842. // +----+----+----+----+----+----+
  843. // | 10 | 12 | aa | ab | 15 |
  844. // +----+----+----+----+----+----+
  845. // | 20 | ba | bb | 25 |
  846. // +----+----+----+----+----+----+
  847. // | 30 | 31 | 32 | 33 | 34 | 35 |
  848. // +----+----+----+----+----+----+
  849. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  850. [ '00', '01', '02', '03', '04', '05' ],
  851. [ { contents: '10', colspan: 2 }, '12', 'aa', 'ab', '15' ],
  852. [ { contents: '20', colspan: 3 }, 'ba', 'bb', '25' ],
  853. [ '30', '31', '32', '33', '34', '35' ]
  854. ] ) );
  855. /* eslint-disable no-multi-spaces */
  856. assertSelectedCells( model, [
  857. [ 0, 0, 0, 0, 0, 0 ],
  858. [ 0, 0, 1, 1, 0 ],
  859. [ 0, 1, 1, 0 ],
  860. [ 0, 0, 0, 0, 0, 0 ]
  861. ] );
  862. /* eslint-enable no-multi-spaces */
  863. } );
  864. // TODO: Skipped case - should allow pasting but no tools to compare areas (like in MergeCellsCommand).
  865. it.skip( 'handles pasting table that has cell with colspan (last row in selection is spanned)', () => {
  866. // +----+----+----+----+
  867. // | 00 | 01 | 02 | 03 |
  868. // +----+----+----+----+
  869. // | 10 | 11 | 13 |
  870. // + + +----+
  871. // | | | 23 |
  872. // +----+----+----+----+
  873. // | 30 | 31 | 32 | 33 |
  874. // +----+----+----+----+
  875. setModelData( model, modelTable( [
  876. [ '00', '01', '02', '03' ],
  877. [ { contents: '10', rowspan: 2 }, { contents: '11', colspan: 2, rowspan: 2 }, '13' ],
  878. [ '23' ],
  879. [ '30', '31', '32', '33' ]
  880. ] ) );
  881. tableSelection.setCellSelection(
  882. modelRoot.getNodeByPath( [ 0, 0, 2 ] ),
  883. modelRoot.getNodeByPath( [ 0, 1, 0 ] )
  884. );
  885. pasteTable( [
  886. [ 'aa', 'ab', 'ac' ],
  887. [ 'ba', 'bb', 'bc' ],
  888. [ 'ca', 'cb', 'cc' ]
  889. ] );
  890. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  891. [ 'aa', 'ab', 'ac', '03' ],
  892. [ 'ba', 'bb', 'bc', '13' ],
  893. [ 'ca', 'cb', 'cc', '23' ],
  894. [ '30', '31', '32', '33' ]
  895. ] ) );
  896. assertSelectedCells( model, [
  897. [ 1, 1, 1, 0 ],
  898. [ 1, 1, 1, 0 ],
  899. [ 1, 1, 1, 0 ],
  900. [ 0, 0, 0, 0 ]
  901. ] );
  902. } );
  903. } );
  904. describe( 'content and paste tables have spans', () => {
  905. it( 'handles pasting colspanned table over table with colspans (no colspan exceeds selection)', () => {
  906. setModelData( model, modelTable( [
  907. [ '00[]', '01', '02', '03' ],
  908. [ { colspan: 3, contents: '10' }, '13' ],
  909. [ { colspan: 2, contents: '20' }, '22', '23' ],
  910. [ '30', '31', { colspan: 2, contents: '31' } ]
  911. ] ) );
  912. tableSelection.setCellSelection(
  913. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  914. modelRoot.getNodeByPath( [ 0, 2, 1 ] )
  915. );
  916. pasteTable( [
  917. [ 'aa', { colspan: 2, contents: 'ab' } ],
  918. [ { colspan: 3, contents: 'ba' } ],
  919. [ 'ca', 'cb', 'cc' ]
  920. ] );
  921. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  922. [ 'aa', { colspan: 2, contents: 'ab' }, '03' ],
  923. [ { colspan: 3, contents: 'ba' }, '13' ],
  924. [ 'ca', 'cb', 'cc', '23' ],
  925. [ '30', '31', { colspan: 2, contents: '31' } ]
  926. ] ) );
  927. /* eslint-disable no-multi-spaces */
  928. assertSelectedCells( model, [
  929. [ 1, 1, 0 ],
  930. [ 1, 0 ],
  931. [ 1, 1, 1, 0 ],
  932. [ 0, 0, 0 ]
  933. ] );
  934. /* eslint-enable no-multi-spaces */
  935. } );
  936. it( 'handles pasting rowspanned table over table with rowspans (no rowspan exceeds selection)', () => {
  937. setModelData( model, modelTable( [
  938. [ { rowspan: 3, contents: '00' }, { rowspan: 2, contents: '01' }, '02', '03' ],
  939. [ { rowspan: 2, contents: '12' }, '13' ],
  940. [ '21', '23' ],
  941. [ '30', '31', '32', '33' ]
  942. ] ) );
  943. tableSelection.setCellSelection(
  944. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  945. modelRoot.getNodeByPath( [ 0, 2, 1 ] )
  946. );
  947. pasteTable( [
  948. [ 'aa', { rowspan: 3, contents: 'ab' }, { rowspan: 2, contents: 'ac' }, 'ad' ],
  949. [ { rowspan: 2, contents: 'ba' }, 'bd' ],
  950. [ 'cc', 'cd' ]
  951. ] );
  952. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  953. [ 'aa', { rowspan: 3, contents: 'ab' }, { rowspan: 2, contents: 'ac' }, 'ad' ],
  954. [ { rowspan: 2, contents: 'ba' }, 'bd' ],
  955. [ 'cc', 'cd' ],
  956. [ '30', '31', '32', '33' ]
  957. ] ) );
  958. /* eslint-disable no-multi-spaces */
  959. assertSelectedCells( model, [
  960. [ 1, 1, 1, 1 ],
  961. [ 1, 1 ],
  962. [ 1, 1 ],
  963. [ 0, 0, 0, 0 ]
  964. ] );
  965. /* eslint-enable no-multi-spaces */
  966. } );
  967. it( 'handles pasting multi-spanned table over table with multi-spans (no span exceeds selection)', () => {
  968. // +----+----+----+----+----+----+
  969. // | 00 | 02 | 03 | 05 |
  970. // + + + +----+
  971. // | | | | 15 |
  972. // +----+----+----+ +----+
  973. // | 20 | 21 | | 25 |
  974. // + +----+----+----+----+----+
  975. // | | 31 | 32 | 34 | 35 |
  976. // +----+----+----+----+----+----+
  977. // | 40 | 41 | 42 | 43 | 44 | 45 |
  978. // +----+----+----+----+----+----+
  979. setModelData( model, modelTable( [
  980. [
  981. { contents: '00', colspan: 2, rowspan: 2 },
  982. { contents: '02', rowspan: 2 },
  983. { contents: '03', colspan: 2, rowspan: 3 },
  984. '05'
  985. ],
  986. [ '15' ],
  987. [ { contents: '20', rowspan: 2 }, { contents: '21', colspan: 2 }, '25' ],
  988. [ '31', { contents: '32', colspan: 2 }, '34', '35' ],
  989. [ '40', '41', '42', '43', '44', '45' ]
  990. ] ) );
  991. tableSelection.setCellSelection(
  992. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  993. modelRoot.getNodeByPath( [ 0, 3, 2 ] )
  994. );
  995. // +----+----+----+----+----+
  996. // | aa | ac | ad | ae |
  997. // +----+----+----+----+ +
  998. // | ba | bb | |
  999. // +----+ +----+
  1000. // | ca | | ce |
  1001. // + +----+----+----+----+
  1002. // | | db | dc | dd |
  1003. // +----+----+----+----+----+
  1004. pasteTable( [
  1005. [ { contents: 'aa', colspan: 2 }, 'ac', 'ad', { contents: 'ae', rowspan: 2 } ],
  1006. [ 'ba', { contents: 'bb', colspan: 3, rowspan: 2 } ],
  1007. [ { contents: 'ca', rowspan: 2 }, 'ce' ],
  1008. [ 'db', 'dc', { contents: 'dd', colspan: 2 } ]
  1009. ] );
  1010. // +----+----+----+----+----+----+
  1011. // | aa | ac | ad | ae | 05 |
  1012. // +----+----+----+----+ +----+
  1013. // | ba | bb | | 15 |
  1014. // +----+ +----+----+
  1015. // | ca | | ce | 25 |
  1016. // + +----+----+----+----+----+
  1017. // | | db | dc | dd | 35 |
  1018. // +----+----+----+----+----+----+
  1019. // | 40 | 41 | 42 | 43 | 44 | 45 |
  1020. // +----+----+----+----+----+----+
  1021. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1022. [ { contents: 'aa', colspan: 2 }, 'ac', 'ad', { contents: 'ae', rowspan: 2 }, '05' ],
  1023. [ 'ba', { contents: 'bb', colspan: 3, rowspan: 2 }, '15' ],
  1024. [ { contents: 'ca', rowspan: 2 }, 'ce', '25' ],
  1025. [ 'db', 'dc', { contents: 'dd', colspan: 2 }, '35' ],
  1026. [ '40', '41', '42', '43', '44', '45' ]
  1027. ] ) );
  1028. /* eslint-disable no-multi-spaces */
  1029. assertSelectedCells( model, [
  1030. [ 1, 1, 1, 1, 0 ],
  1031. [ 1, 1, 0 ],
  1032. [ 1, 1, 0 ],
  1033. [ 1, 1, 1, 0 ],
  1034. [ 0, 0, 0, 0, 0, 0 ]
  1035. ] );
  1036. /* eslint-enable no-multi-spaces */
  1037. } );
  1038. // TODO: Skipped case - should allow pasting but no tools to compare areas (like in MergeCellsCommand).
  1039. it.skip( 'handles pasting table that has cell with colspan (last row in selection is spanned)', () => {
  1040. // +----+----+----+----+
  1041. // | 00 | 01 | 02 | 03 |
  1042. // +----+----+----+----+
  1043. // | 10 | 11 | 13 |
  1044. // + + +----+
  1045. // | | | 23 |
  1046. // +----+----+----+----+
  1047. // | 30 | 31 | 32 | 33 |
  1048. // +----+----+----+----+
  1049. setModelData( model, modelTable( [
  1050. [ '00', '01', '02', '03' ],
  1051. [ { contents: '10', rowspan: 2 }, { contents: '11', colspan: 2, rowspan: 2 }, '13' ],
  1052. [ '23' ],
  1053. [ '30', '31', '32', '33' ]
  1054. ] ) );
  1055. tableSelection.setCellSelection(
  1056. modelRoot.getNodeByPath( [ 0, 0, 2 ] ),
  1057. modelRoot.getNodeByPath( [ 0, 1, 0 ] )
  1058. );
  1059. // +----+----+----+
  1060. // | aa | ab | ac |
  1061. // +----+----+----+
  1062. // | ba | bc |
  1063. // + +----+
  1064. // | | cc |
  1065. // +----+----+----+
  1066. pasteTable( [
  1067. [ 'aa', 'ab', 'ac' ],
  1068. [ { contents: 'ba', colspan: 2, rowspan: 2 }, 'bc' ],
  1069. [ 'cc' ]
  1070. ] );
  1071. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1072. [ '00', '01', '02', '03' ],
  1073. [ '10', { colspan: 2, contents: 'aa' }, '13' ],
  1074. [ '20', 'ba', 'bb', '23' ],
  1075. [ '30', '31', '32', '33' ]
  1076. ] ) );
  1077. /* eslint-disable no-multi-spaces */
  1078. assertSelectedCells( model, [
  1079. [ 0, 0, 0, 0 ],
  1080. [ 0, 1, 0 ],
  1081. [ 0, 1, 1, 0 ],
  1082. [ 0, 0, 0, 0 ]
  1083. ] );
  1084. /* eslint-enable no-multi-spaces */
  1085. } );
  1086. } );
  1087. } );
  1088. describe( 'pasted table is bigger than the selected area', () => {
  1089. describe( 'no spans', () => {
  1090. it( 'handles simple table paste to a simple table fragment - at the beginning of a table', () => {
  1091. tableSelection.setCellSelection(
  1092. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1093. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  1094. );
  1095. pasteTable( [
  1096. [ 'aa', 'ab', 'ac' ],
  1097. [ 'ba', 'bb', 'bc' ],
  1098. [ 'ca', 'cb', 'cc' ]
  1099. ] );
  1100. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1101. [ 'aa', 'ab', '02', '03' ],
  1102. [ 'ba', 'bb', '12', '13' ],
  1103. [ '20', '21', '22', '23' ],
  1104. [ '30', '31', '32', '33' ]
  1105. ] ) );
  1106. assertSelectedCells( model, [
  1107. [ 1, 1, 0, 0 ],
  1108. [ 1, 1, 0, 0 ],
  1109. [ 0, 0, 0, 0 ],
  1110. [ 0, 0, 0, 0 ]
  1111. ] );
  1112. } );
  1113. it( 'handles simple table paste to a simple table fragment - at the end of a table', () => {
  1114. tableSelection.setCellSelection(
  1115. modelRoot.getNodeByPath( [ 0, 2, 2 ] ),
  1116. modelRoot.getNodeByPath( [ 0, 3, 3 ] )
  1117. );
  1118. pasteTable( [
  1119. [ 'aa', 'ab', 'ac' ],
  1120. [ 'ba', 'bb', 'bc' ],
  1121. [ 'ca', 'cb', 'cc' ]
  1122. ] );
  1123. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1124. [ '00', '01', '02', '03' ],
  1125. [ '10', '11', '12', '13' ],
  1126. [ '20', '21', 'aa', 'ab' ],
  1127. [ '30', '31', 'ba', 'bb' ]
  1128. ] ) );
  1129. assertSelectedCells( model, [
  1130. [ 0, 0, 0, 0 ],
  1131. [ 0, 0, 0, 0 ],
  1132. [ 0, 0, 1, 1 ],
  1133. [ 0, 0, 1, 1 ]
  1134. ] );
  1135. } );
  1136. it( 'handles simple table paste to a simple table fragment - in the middle of a table', () => {
  1137. tableSelection.setCellSelection(
  1138. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1139. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  1140. );
  1141. pasteTable( [
  1142. [ 'aa', 'ab', 'ac' ],
  1143. [ 'ba', 'bb', 'bc' ],
  1144. [ 'ca', 'cb', 'cc' ]
  1145. ] );
  1146. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1147. [ '00', '01', '02', '03' ],
  1148. [ '10', 'aa', 'ab', '13' ],
  1149. [ '20', 'ba', 'bb', '23' ],
  1150. [ '30', '31', '32', '33' ]
  1151. ] ) );
  1152. assertSelectedCells( model, [
  1153. [ 0, 0, 0, 0 ],
  1154. [ 0, 1, 1, 0 ],
  1155. [ 0, 1, 1, 0 ],
  1156. [ 0, 0, 0, 0 ]
  1157. ] );
  1158. } );
  1159. it( 'handles paste to a simple row fragment - in the middle of a table', () => {
  1160. tableSelection.setCellSelection(
  1161. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1162. modelRoot.getNodeByPath( [ 0, 1, 2 ] )
  1163. );
  1164. pasteTable( [
  1165. [ 'aa', 'ab', 'ac' ],
  1166. [ 'ba', 'bb', 'bc' ],
  1167. [ 'ca', 'cb', 'cc' ]
  1168. ] );
  1169. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1170. [ '00', '01', '02', '03' ],
  1171. [ '10', 'aa', 'ab', '13' ],
  1172. [ '20', '21', '22', '23' ],
  1173. [ '30', '31', '32', '33' ]
  1174. ] ) );
  1175. assertSelectedCells( model, [
  1176. [ 0, 0, 0, 0 ],
  1177. [ 0, 1, 1, 0 ],
  1178. [ 0, 0, 0, 0 ],
  1179. [ 0, 0, 0, 0 ]
  1180. ] );
  1181. } );
  1182. it( 'handles paste to a simple column fragment - in the middle of a table', () => {
  1183. tableSelection.setCellSelection(
  1184. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1185. modelRoot.getNodeByPath( [ 0, 2, 1 ] )
  1186. );
  1187. pasteTable( [
  1188. [ 'aa', 'ab', 'ac' ],
  1189. [ 'ba', 'bb', 'bc' ],
  1190. [ 'ca', 'cb', 'cc' ]
  1191. ] );
  1192. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1193. [ '00', '01', '02', '03' ],
  1194. [ '10', 'aa', '12', '13' ],
  1195. [ '20', 'ba', '22', '23' ],
  1196. [ '30', '31', '32', '33' ]
  1197. ] ) );
  1198. assertSelectedCells( model, [
  1199. [ 0, 0, 0, 0 ],
  1200. [ 0, 1, 0, 0 ],
  1201. [ 0, 1, 0, 0 ],
  1202. [ 0, 0, 0, 0 ]
  1203. ] );
  1204. } );
  1205. it( 'handles simple table paste to a simple table fragment - whole table selected', () => {
  1206. tableSelection.setCellSelection(
  1207. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1208. modelRoot.getNodeByPath( [ 0, 3, 3 ] )
  1209. );
  1210. pasteTable( [
  1211. [ 'aa', 'ab', 'ac', 'ad', 'ae' ],
  1212. [ 'ba', 'bb', 'bc', 'bd', 'be' ],
  1213. [ 'ca', 'cb', 'cc', 'cd', 'ce' ],
  1214. [ 'da', 'db', 'dc', 'dd', 'de' ],
  1215. [ 'ea', 'eb', 'ec', 'ed', 'ee' ]
  1216. ] );
  1217. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1218. [ 'aa', 'ab', 'ac', 'ad' ],
  1219. [ 'ba', 'bb', 'bc', 'bd' ],
  1220. [ 'ca', 'cb', 'cc', 'cd' ],
  1221. [ 'da', 'db', 'dc', 'dd' ]
  1222. ] ) );
  1223. assertSelectedCells( model, [
  1224. [ 1, 1, 1, 1 ],
  1225. [ 1, 1, 1, 1 ],
  1226. [ 1, 1, 1, 1 ],
  1227. [ 1, 1, 1, 1 ]
  1228. ] );
  1229. } );
  1230. } );
  1231. describe( 'pasted table has spans', () => {
  1232. it( 'handles pasting table that has cell with colspan', () => {
  1233. tableSelection.setCellSelection(
  1234. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1235. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  1236. );
  1237. pasteTable( [
  1238. [ { colspan: 3, contents: 'aa' } ],
  1239. [ 'ba', 'bb', 'bc' ]
  1240. ] );
  1241. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1242. [ '00', '01', '02', '03' ],
  1243. [ '10', { colspan: 2, contents: 'aa' }, '13' ],
  1244. [ '20', 'ba', 'bb', '23' ],
  1245. [ '30', '31', '32', '33' ]
  1246. ] ) );
  1247. /* eslint-disable no-multi-spaces */
  1248. assertSelectedCells( model, [
  1249. [ 0, 0, 0, 0 ],
  1250. [ 0, 1, 0 ],
  1251. [ 0, 1, 1, 0 ],
  1252. [ 0, 0, 0, 0 ]
  1253. ] );
  1254. /* eslint-enable no-multi-spaces */
  1255. } );
  1256. it( 'handles pasting table that has many cells with various colspan', () => {
  1257. tableSelection.setCellSelection(
  1258. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1259. modelRoot.getNodeByPath( [ 0, 3, 2 ] )
  1260. );
  1261. pasteTable( [
  1262. [ 'aa', { colspan: 3, contents: 'ab' } ],
  1263. [ { colspan: 4, contents: 'ba' } ],
  1264. [ 'ca', 'cb', 'cc', 'cd' ],
  1265. [ { colspan: 2, contents: 'da' }, 'dc', 'dd' ]
  1266. ] );
  1267. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1268. [ 'aa', { colspan: 2, contents: 'ab' }, '03' ],
  1269. [ { colspan: 3, contents: 'ba' }, '13' ],
  1270. [ 'ca', 'cb', 'cc', '23' ],
  1271. [ { colspan: 2, contents: 'da' }, 'dc', '33' ]
  1272. ] ) );
  1273. /* eslint-disable no-multi-spaces */
  1274. assertSelectedCells( model, [
  1275. [ 1, 1, 0 ],
  1276. [ 1, 0 ],
  1277. [ 1, 1, 1, 0 ],
  1278. [ 1, 1, 0 ]
  1279. ] );
  1280. /* eslint-enable no-multi-spaces */
  1281. } );
  1282. it( 'handles pasting table that has cell with rowspan', () => {
  1283. tableSelection.setCellSelection(
  1284. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1285. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  1286. );
  1287. pasteTable( [
  1288. [ { rowspan: 3, contents: 'aa' }, 'ab' ],
  1289. [ 'bb' ],
  1290. [ 'cb' ]
  1291. ] );
  1292. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1293. [ '00', '01', '02', '03' ],
  1294. [ '10', { rowspan: 2, contents: 'aa' }, 'ab', '13' ],
  1295. [ '20', 'bb', '23' ],
  1296. [ '30', '31', '32', '33' ]
  1297. ] ) );
  1298. /* eslint-disable no-multi-spaces */
  1299. assertSelectedCells( model, [
  1300. [ 0, 0, 0, 0 ],
  1301. [ 0, 1, 1, 0 ],
  1302. [ 0, 1, 0 ],
  1303. [ 0, 0, 0, 0 ]
  1304. ] );
  1305. /* eslint-enable no-multi-spaces */
  1306. } );
  1307. it( 'handles pasting table that has many cells with various rowspan', () => {
  1308. tableSelection.setCellSelection(
  1309. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1310. modelRoot.getNodeByPath( [ 0, 2, 3 ] )
  1311. );
  1312. pasteTable( [
  1313. [ 'aa', { rowspan: 3, contents: 'ab' }, { rowspan: 2, contents: 'ac' }, 'ad', 'ae' ],
  1314. [ { rowspan: 3, contents: 'ba' }, 'bd', 'be' ],
  1315. [ 'cc', 'cd', 'ce' ],
  1316. [ 'da', 'db', 'dc', 'dd' ]
  1317. ] );
  1318. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1319. [ 'aa', { rowspan: 3, contents: 'ab' }, { rowspan: 2, contents: 'ac' }, 'ad' ],
  1320. [ { rowspan: 2, contents: 'ba' }, 'bd' ],
  1321. [ 'cc', 'cd' ],
  1322. [ '30', '31', '32', '33' ]
  1323. ] ) );
  1324. /* eslint-disable no-multi-spaces */
  1325. assertSelectedCells( model, [
  1326. [ 1, 1, 1, 1 ],
  1327. [ 1, 1 ],
  1328. [ 1, 1 ],
  1329. [ 0, 0, 0, 0 ]
  1330. ] );
  1331. /* eslint-enable no-multi-spaces */
  1332. } );
  1333. it( 'handles pasting multi-spanned table', () => {
  1334. setModelData( model, modelTable( [
  1335. [ '00', '01', '02', '03', '04', '05' ],
  1336. [ '10', '11', '12', '13', '14', '15' ],
  1337. [ '20', '21', '22', '23', '24', '25' ],
  1338. [ '30', '31', '32', '33', '34', '35' ],
  1339. [ '40', '41', '42', '43', '44', '45' ]
  1340. ] ) );
  1341. tableSelection.setCellSelection(
  1342. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1343. modelRoot.getNodeByPath( [ 0, 3, 3 ] )
  1344. );
  1345. // +----+----+----+----+----+
  1346. // | aa | ac | ad | ae |
  1347. // +----+----+----+----+ +
  1348. // | ba | bb | |
  1349. // +----+ +----+
  1350. // | ca | | ce |
  1351. // + +----+----+----+----+
  1352. // | | db | dc | dd |
  1353. // +----+----+----+----+----+
  1354. pasteTable( [
  1355. [ { contents: 'aa', colspan: 2 }, 'ac', 'ad', { contents: 'ae', rowspan: 2 } ],
  1356. [ 'ba', { contents: 'bb', colspan: 3, rowspan: 2 } ],
  1357. [ { contents: 'ca', rowspan: 2 }, 'ce' ],
  1358. [ 'db', 'dc', { contents: 'dd', colspan: 2 } ]
  1359. ] );
  1360. // +----+----+----+----+----+----+
  1361. // | 00 | 01 | 02 | 03 | 04 | 05 |
  1362. // +----+----+----+----+----+----+
  1363. // | 10 | aa | ac | 14 | 15 |
  1364. // +----+----+----+----+----+----+
  1365. // | 20 | ba | bb | 24 | 25 |
  1366. // +----+----+ +----+----+
  1367. // | 30 | ca | | 34 | 35 |
  1368. // +----+----+----+----+----+----+
  1369. // | 40 | 41 | 42 | 43 | 44 | 45 |
  1370. // +----+----+----+----+----+----+
  1371. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1372. [ '00', '01', '02', '03', '04', '05' ],
  1373. [ '10', { contents: 'aa', colspan: 2 }, 'ac', '14', '15' ],
  1374. [ '20', 'ba', { contents: 'bb', colspan: 2, rowspan: 2 }, '24', '25' ],
  1375. [ '30', 'ca', '34', '35' ],
  1376. [ '40', '41', '42', '43', '44', '45' ]
  1377. ] ) );
  1378. /* eslint-disable no-multi-spaces */
  1379. assertSelectedCells( model, [
  1380. [ 0, 0, 0, 0, 0, 0 ],
  1381. [ 0, 1, 1, 0, 0 ],
  1382. [ 0, 1, 1, 0, 0 ],
  1383. [ 0, 1, 0, 0 ],
  1384. [ 0, 0, 0, 0, 0, 0 ]
  1385. ] );
  1386. /* eslint-enable no-multi-spaces */
  1387. } );
  1388. } );
  1389. } );
  1390. describe( 'pasted table is smaller than the selected area', () => {
  1391. it( 'blocks this case', () => {
  1392. tableSelection.setCellSelection(
  1393. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1394. modelRoot.getNodeByPath( [ 0, 3, 3 ] )
  1395. );
  1396. // Catches the temporary console log in the CK_DEBUG mode.
  1397. sinon.stub( console, 'log' );
  1398. pasteTable( [
  1399. [ 'aa', 'ab' ],
  1400. [ 'ba', 'bb' ]
  1401. ] );
  1402. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1403. [ '00', '01', '02', '03' ],
  1404. [ '10', '11', '12', '13' ],
  1405. [ '20', '21', '22', '23' ],
  1406. [ '30', '31', '32', '33' ]
  1407. ] ) );
  1408. assertSelectedCells( model, [
  1409. [ 1, 1, 1, 1 ],
  1410. [ 1, 1, 1, 1 ],
  1411. [ 1, 1, 1, 1 ],
  1412. [ 1, 1, 1, 1 ]
  1413. ] );
  1414. } );
  1415. } );
  1416. } );
  1417. describe( 'Clipboard integration - paste (content scenarios)', () => {
  1418. it( 'handles multiple paragraphs in table cell', async () => {
  1419. await createEditor();
  1420. setModelData( model, modelTable( [
  1421. [ '00', '01', '02' ],
  1422. [ '01', '11', '12' ],
  1423. [ '02', '21', '22' ]
  1424. ] ) );
  1425. tableSelection.setCellSelection(
  1426. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1427. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  1428. );
  1429. pasteTable( [
  1430. [ '<p>a</p><p>a</p><p>a</p>', 'ab' ],
  1431. [ 'ba', 'bb' ]
  1432. ] );
  1433. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1434. [ '<paragraph>a</paragraph><paragraph>a</paragraph><paragraph>a</paragraph>', 'ab', '02' ],
  1435. [ 'ba', 'bb', '12' ],
  1436. [ '02', '21', '22' ]
  1437. ] ) );
  1438. } );
  1439. it( 'handles image in table cell', async () => {
  1440. await createEditor( [ ImageEditing, ImageCaptionEditing ] );
  1441. setModelData( model, modelTable( [
  1442. [ '00', '01', '02' ],
  1443. [ '01', '11', '12' ],
  1444. [ '02', '21', '22' ]
  1445. ] ) );
  1446. tableSelection.setCellSelection(
  1447. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1448. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  1449. );
  1450. pasteTable( [
  1451. [ '<img src="/assets/sample.jpg">', 'ab' ],
  1452. [ 'ba', 'bb' ]
  1453. ] );
  1454. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1455. [ '<image src="/assets/sample.jpg"><caption></caption></image>', 'ab', '02' ],
  1456. [ 'ba', 'bb', '12' ],
  1457. [ '02', '21', '22' ]
  1458. ] ) );
  1459. } );
  1460. it( 'handles mixed nested content in table cell', async () => {
  1461. await createEditor( [ ImageEditing, ImageCaptionEditing, BlockQuoteEditing, HorizontalLineEditing, ListEditing ] );
  1462. setModelData( model, modelTable( [
  1463. [ '00', '01', '02' ],
  1464. [ '01', '11', '12' ],
  1465. [ '02', '21', '22' ]
  1466. ] ) );
  1467. tableSelection.setCellSelection(
  1468. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1469. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  1470. );
  1471. const img = '<img src="/assets/sample.jpg">';
  1472. const list = '<ul><li>foo</li><li>bar</li></ul>';
  1473. const blockquote = `<blockquote><p>baz</p>${ list }</blockquote>`;
  1474. pasteTable( [
  1475. [ `${ img }${ list }${ blockquote }`, 'ab' ],
  1476. [ 'ba', 'bb' ]
  1477. ] );
  1478. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1479. [
  1480. '<image src="/assets/sample.jpg"><caption></caption></image>' +
  1481. '<listItem listIndent="0" listType="bulleted">foo</listItem>' +
  1482. '<listItem listIndent="0" listType="bulleted">bar</listItem>' +
  1483. '<blockQuote>' +
  1484. '<paragraph>baz</paragraph>' +
  1485. '<listItem listIndent="0" listType="bulleted">foo</listItem>' +
  1486. '<listItem listIndent="0" listType="bulleted">bar</listItem>' +
  1487. '</blockQuote>',
  1488. 'ab',
  1489. '02' ],
  1490. [ 'ba', 'bb', '12' ],
  1491. [ '02', '21', '22' ]
  1492. ] ) );
  1493. } );
  1494. it( 'handles table cell properties', async () => {
  1495. await createEditor( [ TableCellPropertiesEditing ] );
  1496. setModelData( model, modelTable( [
  1497. [ '00', '01', '02' ],
  1498. [ '01', '11', '12' ],
  1499. [ '02', '21', '22' ]
  1500. ] ) );
  1501. tableSelection.setCellSelection(
  1502. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1503. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  1504. );
  1505. pasteTable( [
  1506. [ { contents: 'aa', style: 'border:1px solid #f00;background:#ba7;width:1337px' }, 'ab' ],
  1507. [ 'ba', 'bb' ]
  1508. ] );
  1509. const tableCell = model.document.getRoot().getNodeByPath( [ 0, 0, 0 ] );
  1510. expect( tableCell.getAttribute( 'borderColor' ) ).to.deep.equal( {
  1511. top: '#f00',
  1512. right: '#f00',
  1513. bottom: '#f00',
  1514. left: '#f00'
  1515. } );
  1516. expect( tableCell.getAttribute( 'borderStyle' ) ).to.deep.equal( {
  1517. top: 'solid',
  1518. right: 'solid',
  1519. bottom: 'solid',
  1520. left: 'solid'
  1521. } );
  1522. expect( tableCell.getAttribute( 'borderWidth' ) ).to.deep.equal( {
  1523. top: '1px',
  1524. right: '1px',
  1525. bottom: '1px',
  1526. left: '1px'
  1527. } );
  1528. expect( tableCell.getAttribute( 'backgroundColor' ) ).to.equal( '#ba7' );
  1529. expect( tableCell.getAttribute( 'width' ) ).to.equal( '1337px' );
  1530. } );
  1531. it( 'discards table properties', async () => {
  1532. await createEditor( [ TableCellPropertiesEditing ] );
  1533. setModelData( model, modelTable( [
  1534. [ '00', '01', '02' ],
  1535. [ '01', '11', '12' ],
  1536. [ '02', '21', '22' ]
  1537. ] ) );
  1538. tableSelection.setCellSelection(
  1539. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  1540. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  1541. );
  1542. const tableStyle = 'border:1px solid #f00;background:#ba7;width:1337px';
  1543. const pastedTable = `<table style="${ tableStyle }"><tr><td>aa</td><td>ab</td></tr><tr><td>ba</td><td>bb</td></tr></table>`;
  1544. const data = {
  1545. dataTransfer: createDataTransfer(),
  1546. preventDefault: sinon.spy(),
  1547. stopPropagation: sinon.spy()
  1548. };
  1549. data.dataTransfer.setData( 'text/html', pastedTable );
  1550. viewDocument.fire( 'paste', data );
  1551. assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
  1552. [ 'aa', 'ab', '02' ],
  1553. [ 'ba', 'bb', '12' ],
  1554. [ '02', '21', '22' ]
  1555. ] ) );
  1556. } );
  1557. } );
  1558. async function createEditor( extraPlugins = [] ) {
  1559. editor = await ClassicTestEditor.create( element, {
  1560. plugins: [ TableEditing, TableClipboard, Paragraph, Clipboard, ...extraPlugins ]
  1561. } );
  1562. model = editor.model;
  1563. modelRoot = model.document.getRoot();
  1564. viewDocument = editor.editing.view.document;
  1565. tableSelection = editor.plugins.get( 'TableSelection' );
  1566. }
  1567. function pasteTable( tableData ) {
  1568. const data = {
  1569. dataTransfer: createDataTransfer(),
  1570. preventDefault: sinon.spy(),
  1571. stopPropagation: sinon.spy()
  1572. };
  1573. data.dataTransfer.setData( 'text/html', viewTable( tableData ) );
  1574. viewDocument.fire( 'paste', data );
  1575. return data;
  1576. }
  1577. function createDataTransfer() {
  1578. const store = new Map();
  1579. return {
  1580. setData( type, data ) {
  1581. store.set( type, data );
  1582. },
  1583. getData( type ) {
  1584. return store.get( type );
  1585. }
  1586. };
  1587. }
  1588. } );