tableselection-integration.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 */
  6. import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
  7. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  8. import Delete from '@ckeditor/ckeditor5-typing/src/delete';
  9. import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
  10. import HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline';
  11. import TableEditing from '../src/tableediting';
  12. import TableSelection from '../src/tableselection';
  13. import TableClipboard from '../src/tableclipboard';
  14. import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  15. import { modelTable } from './_utils/utils';
  16. import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
  17. import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';
  18. import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
  19. import Input from '@ckeditor/ckeditor5-typing/src/input';
  20. import ViewText from '@ckeditor/ckeditor5-engine/src/view/text';
  21. describe( 'TableSelection - integration', () => {
  22. let editor, model, tableSelection, modelRoot, element, viewDocument;
  23. afterEach( async () => {
  24. element.remove();
  25. await editor.destroy();
  26. } );
  27. describe( 'on delete', () => {
  28. beforeEach( async () => {
  29. await setupEditor( [ Delete ] );
  30. } );
  31. it( 'should clear contents of the selected table cells and put selection in last cell on backward delete', () => {
  32. tableSelection._setCellSelection(
  33. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  34. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  35. );
  36. const domEventData = new DomEventData( viewDocument, {
  37. preventDefault: sinon.spy()
  38. }, {
  39. direction: 'backward',
  40. unit: 'character',
  41. sequence: 1
  42. } );
  43. viewDocument.fire( 'delete', domEventData );
  44. assertEqualMarkup( getModelData( model ), modelTable( [
  45. [ '', '', '13' ],
  46. [ '', '[]', '23' ],
  47. [ '31', '32', '33' ]
  48. ] ) );
  49. } );
  50. it( 'should clear contents of the selected table cells and put selection in last cell on forward delete', () => {
  51. tableSelection._setCellSelection(
  52. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  53. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  54. );
  55. const domEventData = new DomEventData( viewDocument, {
  56. preventDefault: sinon.spy()
  57. }, {
  58. direction: 'forward',
  59. unit: 'character',
  60. sequence: 1
  61. } );
  62. viewDocument.fire( 'delete', domEventData );
  63. assertEqualMarkup( getModelData( model ), modelTable( [
  64. [ '[]', '', '13' ],
  65. [ '', '', '23' ],
  66. [ '31', '32', '33' ]
  67. ] ) );
  68. } );
  69. it( 'should not interfere with default key handler if no table selection', () => {
  70. setModelData( model, modelTable( [
  71. [ '11[]', '12', '13' ],
  72. [ '21', '22', '23' ],
  73. [ '31', '32', '33' ]
  74. ] ) );
  75. const domEventData = new DomEventData( viewDocument, {
  76. preventDefault: sinon.spy()
  77. }, {
  78. direction: 'backward',
  79. unit: 'character',
  80. sequence: 1
  81. } );
  82. viewDocument.fire( 'delete', domEventData );
  83. assertEqualMarkup( getModelData( model ), modelTable( [
  84. [ '1[]', '12', '13' ],
  85. [ '21', '22', '23' ],
  86. [ '31', '32', '33' ]
  87. ] ) );
  88. } );
  89. } );
  90. describe( 'on user input', () => {
  91. beforeEach( async () => {
  92. await setupEditor( [ Input ] );
  93. } );
  94. it( 'should clear contents of the selected table cells and put selection in last cell on user input', () => {
  95. tableSelection._setCellSelection(
  96. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  97. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  98. );
  99. viewDocument.fire( 'keydown', { keyCode: getCode( 'x' ) } );
  100. // Mutate at the place where the document selection was put; it's more realistic
  101. // than mutating at some arbitrary position.
  102. const placeOfMutation = viewDocument.selection.getFirstRange().start.parent;
  103. viewDocument.fire( 'mutations', [
  104. {
  105. type: 'children',
  106. oldChildren: [],
  107. newChildren: [ new ViewText( viewDocument, 'x' ) ],
  108. node: placeOfMutation
  109. }
  110. ] );
  111. assertEqualMarkup( getModelData( model ), modelTable( [
  112. [ '', '', '13' ],
  113. [ '', 'x[]', '23' ],
  114. [ '31', '32', '33' ]
  115. ] ) );
  116. } );
  117. it( 'should not interfere with default key handler if no table selection', () => {
  118. viewDocument.fire( 'keydown', { keyCode: getCode( 'x' ) } );
  119. // Mutate at the place where the document selection was put; it's more realistic
  120. // than mutating at some arbitrary position.
  121. const placeOfMutation = viewDocument.selection.getFirstRange().start.parent;
  122. viewDocument.fire( 'mutations', [
  123. {
  124. type: 'children',
  125. oldChildren: [],
  126. newChildren: [ new ViewText( viewDocument, 'x' ) ],
  127. node: placeOfMutation
  128. }
  129. ] );
  130. assertEqualMarkup( getModelData( model ), modelTable( [
  131. [ 'x[]11', '12', '13' ],
  132. [ '21', '22', '23' ],
  133. [ '31', '32', '33' ]
  134. ] ) );
  135. } );
  136. } );
  137. describe( 'with other features', () => {
  138. beforeEach( async () => {
  139. await setupEditor( [ Clipboard, HorizontalLine ] );
  140. } );
  141. it( 'allows pasting over multi-cell selection', () => {
  142. tableSelection._setCellSelection(
  143. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  144. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  145. );
  146. const dataTransferMock = {
  147. getData: sinon.stub().withArgs( 'text/plain' ).returns( 'foo' )
  148. };
  149. editor.editing.view.document.fire( 'clipboardInput', {
  150. dataTransfer: dataTransferMock,
  151. stop: sinon.spy()
  152. } );
  153. assertEqualMarkup( getModelData( model ), modelTable( [
  154. [ 'foo[]', '', '13' ],
  155. [ '', '', '23' ],
  156. [ '31', '32', '33' ]
  157. ] ) );
  158. } );
  159. it( 'allows inserting a horizontal line over a multi-range selection', () => {
  160. tableSelection._setCellSelection(
  161. modelRoot.getNodeByPath( [ 0, 0, 0 ] ),
  162. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  163. );
  164. editor.execute( 'horizontalLine' );
  165. assertEqualMarkup(
  166. getModelData( model ),
  167. '<table>' +
  168. '<tableRow>' +
  169. '<tableCell><horizontalLine></horizontalLine><paragraph>[]</paragraph></tableCell>' +
  170. '<tableCell><paragraph></paragraph></tableCell>' +
  171. '<tableCell><paragraph>13</paragraph></tableCell>' +
  172. '</tableRow>' +
  173. '<tableRow>' +
  174. '<tableCell><paragraph></paragraph></tableCell>' +
  175. '<tableCell><paragraph></paragraph></tableCell>' +
  176. '<tableCell><paragraph>23</paragraph></tableCell>' +
  177. '</tableRow>' +
  178. '<tableRow>' +
  179. '<tableCell><paragraph>31</paragraph></tableCell>' +
  180. '<tableCell><paragraph>32</paragraph></tableCell>' +
  181. '<tableCell><paragraph>33</paragraph></tableCell>' +
  182. '</tableRow>' +
  183. '</table>'
  184. );
  185. } );
  186. } );
  187. async function setupEditor( plugins ) {
  188. element = document.createElement( 'div' );
  189. document.body.appendChild( element );
  190. editor = await ClassicTestEditor.create( element, {
  191. plugins: [ TableEditing, TableSelection, TableClipboard, Paragraph, ...plugins ]
  192. } );
  193. model = editor.model;
  194. modelRoot = model.document.getRoot();
  195. viewDocument = editor.editing.view.document;
  196. tableSelection = editor.plugins.get( TableSelection );
  197. setModelData( model, modelTable( [
  198. [ '[]11', '12', '13' ],
  199. [ '21', '22', '23' ],
  200. [ '31', '32', '33' ]
  201. ] ) );
  202. }
  203. } );