8
0

tableselection.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  6. import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
  7. import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  8. import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
  9. import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
  10. import TableEditing from '../src/tableediting';
  11. import TableSelection from '../src/tableselection';
  12. import { modelTable, viewTable } from './_utils/utils';
  13. describe( 'table selection', () => {
  14. let editor, model;
  15. beforeEach( () => {
  16. return VirtualTestEditor
  17. .create( {
  18. plugins: [ TableEditing, TableSelection, Paragraph ]
  19. } )
  20. .then( newEditor => {
  21. editor = newEditor;
  22. model = editor.model;
  23. } );
  24. } );
  25. afterEach( () => {
  26. editor.destroy();
  27. } );
  28. describe( 'behavior', () => {
  29. let view, domEvtDataStub;
  30. beforeEach( () => {
  31. view = editor.editing.view;
  32. domEvtDataStub = {
  33. domEvent: {
  34. buttons: 1
  35. },
  36. target: undefined,
  37. preventDefault: sinon.spy(),
  38. stopPropagation: sinon.spy()
  39. };
  40. } );
  41. it( 'should not start table selection when mouse move is inside one table cell', () => {
  42. setModelData( model, modelTable( [
  43. [ '[]00', '01' ],
  44. [ '10', '11' ]
  45. ] ) );
  46. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  47. view.document.fire( 'mousedown', domEvtDataStub );
  48. assertEqualMarkup( getModelData( model ), modelTable( [
  49. [ '[]00', '01' ],
  50. [ '10', '11' ]
  51. ] ) );
  52. view.document.fire( 'mousemove', domEvtDataStub );
  53. assertEqualMarkup( getModelData( model ), modelTable( [
  54. [ '[]00', '01' ],
  55. [ '10', '11' ]
  56. ] ) );
  57. } );
  58. it( 'should start table selection when mouse move expands over two cells', () => {
  59. setModelData( model, modelTable( [
  60. [ '[]00', '01' ],
  61. [ '10', '11' ]
  62. ] ) );
  63. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  64. view.document.fire( 'mousedown', domEvtDataStub );
  65. assertEqualMarkup( getModelData( model ), modelTable( [
  66. [ '[]00', '01' ],
  67. [ '10', '11' ]
  68. ] ) );
  69. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  70. view.document.fire( 'mousemove', domEvtDataStub );
  71. assertEqualMarkup( getModelData( model ), modelTable( [
  72. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  73. [ '10', '11' ]
  74. ] ) );
  75. assertEqualMarkup( getViewData( view ), viewTable( [
  76. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  77. [ '10', '11' ]
  78. ], { asWidget: true } ) );
  79. } );
  80. it( 'should select rectangular table cells when mouse moved to diagonal cell (up -> down)', () => {
  81. setModelData( model, modelTable( [
  82. [ '[]00', '01' ],
  83. [ '10', '11' ]
  84. ] ) );
  85. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  86. view.document.fire( 'mousedown', domEvtDataStub );
  87. assertEqualMarkup( getModelData( model ), modelTable( [
  88. [ '[]00', '01' ],
  89. [ '10', '11' ]
  90. ] ) );
  91. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  92. view.document.fire( 'mousemove', domEvtDataStub );
  93. assertEqualMarkup( getModelData( model ), modelTable( [
  94. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  95. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true } ]
  96. ] ) );
  97. assertEqualMarkup( getViewData( view ), viewTable( [
  98. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  99. [ { contents: '10', class: 'selected', isSelected: true }, { contents: '11', class: 'selected', isSelected: true } ]
  100. ], { asWidget: true } ) );
  101. } );
  102. it( 'should select rectangular table cells when mouse moved to diagonal cell (down -> up)', () => {
  103. setModelData( model, modelTable( [
  104. [ '00', '01' ],
  105. [ '10', '[]11' ]
  106. ] ) );
  107. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  108. view.document.fire( 'mousedown', domEvtDataStub );
  109. assertEqualMarkup( getModelData( model ), modelTable( [
  110. [ '00', '01' ],
  111. [ '10', '[]11' ]
  112. ] ) );
  113. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  114. view.document.fire( 'mousemove', domEvtDataStub );
  115. assertEqualMarkup( getModelData( model ), modelTable( [
  116. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  117. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true } ]
  118. ] ) );
  119. assertEqualMarkup( getViewData( view ), viewTable( [
  120. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  121. [ { contents: '10', class: 'selected', isSelected: true }, { contents: '11', class: 'selected', isSelected: true } ]
  122. ], { asWidget: true } ) );
  123. } );
  124. it( 'should update view selection after changing selection rect', () => {
  125. setModelData( model, modelTable( [
  126. [ '[]00', '01', '02' ],
  127. [ '10', '11', '12' ],
  128. [ '20', '21', '22' ]
  129. ] ) );
  130. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  131. view.document.fire( 'mousedown', domEvtDataStub );
  132. selectTableCell( domEvtDataStub, view, 0, 0, 2, 2 );
  133. view.document.fire( 'mousemove', domEvtDataStub );
  134. assertEqualMarkup( getModelData( model ), modelTable( [
  135. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true }, { contents: '02', isSelected: true } ],
  136. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true }, { contents: '12', isSelected: true } ],
  137. [ { contents: '20', isSelected: true }, { contents: '21', isSelected: true }, { contents: '22', isSelected: true } ]
  138. ] ) );
  139. assertEqualMarkup( getViewData( view ), viewTable( [
  140. [
  141. { contents: '00', class: 'selected', isSelected: true },
  142. { contents: '01', class: 'selected', isSelected: true },
  143. { contents: '02', class: 'selected', isSelected: true }
  144. ],
  145. [
  146. { contents: '10', class: 'selected', isSelected: true },
  147. { contents: '11', class: 'selected', isSelected: true },
  148. { contents: '12', class: 'selected', isSelected: true }
  149. ],
  150. [
  151. { contents: '20', class: 'selected', isSelected: true },
  152. { contents: '21', class: 'selected', isSelected: true },
  153. { contents: '22', class: 'selected', isSelected: true }
  154. ]
  155. ], { asWidget: true } ) );
  156. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  157. view.document.fire( 'mousemove', domEvtDataStub );
  158. assertEqualMarkup( getModelData( model ), modelTable( [
  159. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true }, '02' ],
  160. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true }, '12' ],
  161. [ '20', '21', '22' ]
  162. ] ) );
  163. assertEqualMarkup( getViewData( view ), viewTable( [
  164. [
  165. { contents: '00', class: 'selected', isSelected: true },
  166. { contents: '01', class: 'selected', isSelected: true },
  167. '02'
  168. ],
  169. [
  170. { contents: '10', class: 'selected', isSelected: true },
  171. { contents: '11', class: 'selected', isSelected: true },
  172. '12'
  173. ],
  174. [
  175. '20',
  176. '21',
  177. '22'
  178. ]
  179. ], { asWidget: true } ) );
  180. } );
  181. it( 'should stop selecting after "mouseup" event', () => {
  182. setModelData( model, modelTable( [
  183. [ '[]00', '01' ],
  184. [ '10', '11' ]
  185. ] ) );
  186. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  187. view.document.fire( 'mousedown', domEvtDataStub );
  188. assertEqualMarkup( getModelData( model ), modelTable( [
  189. [ '[]00', '01' ],
  190. [ '10', '11' ]
  191. ] ) );
  192. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  193. view.document.fire( 'mousemove', domEvtDataStub );
  194. view.document.fire( 'mouseup', domEvtDataStub );
  195. assertEqualMarkup( getModelData( model ), modelTable( [
  196. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  197. [ '10', '11' ]
  198. ] ) );
  199. assertEqualMarkup( getViewData( view ), viewTable( [
  200. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  201. [ '10', '11' ]
  202. ], { asWidget: true } ) );
  203. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  204. view.document.fire( 'mousemove', domEvtDataStub );
  205. assertEqualMarkup( getModelData( model ), modelTable( [
  206. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  207. [ '10', '11' ]
  208. ] ) );
  209. } );
  210. it( 'should stop selection mode on "mouseleve" event', () => {
  211. setModelData( model, modelTable( [
  212. [ '[]00', '01' ],
  213. [ '10', '11' ]
  214. ] ) );
  215. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  216. view.document.fire( 'mousedown', domEvtDataStub );
  217. assertEqualMarkup( getModelData( model ), modelTable( [
  218. [ '[]00', '01' ],
  219. [ '10', '11' ]
  220. ] ) );
  221. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  222. view.document.fire( 'mousemove', domEvtDataStub );
  223. view.document.fire( 'mouseleave', domEvtDataStub );
  224. assertEqualMarkup( getModelData( model ), modelTable( [
  225. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  226. [ '10', '11' ]
  227. ] ) );
  228. assertEqualMarkup( getViewData( view ), viewTable( [
  229. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  230. [ '10', '11' ]
  231. ], { asWidget: true } ) );
  232. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  233. view.document.fire( 'mousemove', domEvtDataStub );
  234. assertEqualMarkup( getModelData( model ), modelTable( [
  235. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  236. [ '10', '11' ]
  237. ] ) );
  238. } );
  239. it( 'should clear view table selection after mouse click outside table', () => {
  240. setModelData( model, modelTable( [
  241. [ '[]00', '01' ],
  242. [ '10', '11' ]
  243. ] ) + '<paragraph>foo</paragraph>' );
  244. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  245. view.document.fire( 'mousedown', domEvtDataStub );
  246. assertEqualMarkup( getModelData( model ), modelTable( [
  247. [ '[]00', '01' ],
  248. [ '10', '11' ]
  249. ] ) + '<paragraph>foo</paragraph>' );
  250. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  251. view.document.fire( 'mousemove', domEvtDataStub );
  252. domEvtDataStub.target = view.document.getRoot().getChild( 1 );
  253. view.document.fire( 'mousemove', domEvtDataStub );
  254. view.document.fire( 'mousedown', domEvtDataStub );
  255. view.document.fire( 'mouseup', domEvtDataStub );
  256. // The click in the DOM would trigger selection change and it will set the selection:
  257. model.change( writer => {
  258. writer.setSelection( writer.createRange( writer.createPositionAt( model.document.getRoot().getChild( 1 ), 0 ) ) );
  259. } );
  260. assertEqualMarkup( getViewData( view ), viewTable( [
  261. [ '00', '01' ],
  262. [ '10', '11' ]
  263. ], { asWidget: true } ) + '<p>{}foo</p>' );
  264. } );
  265. } );
  266. } );
  267. function selectTableCell( domEvtDataStub, view, tableIndex, sectionIndex, rowInSectionIndex, tableCellIndex ) {
  268. domEvtDataStub.target = view.document.getRoot()
  269. .getChild( tableIndex )
  270. .getChild( 1 ) // Table is second in widget
  271. .getChild( sectionIndex )
  272. .getChild( rowInSectionIndex )
  273. .getChild( tableCellIndex );
  274. }