8
0

tableselection.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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.only( 'table selection', () => {
  14. let editor, model, tableSelection, modelRoot;
  15. beforeEach( async () => {
  16. editor = await VirtualTestEditor.create( {
  17. plugins: [ TableEditing, TableSelection, Paragraph ]
  18. } );
  19. model = editor.model;
  20. modelRoot = model.document.getRoot();
  21. tableSelection = editor.plugins.get( TableSelection );
  22. setModelData( model, modelTable( [
  23. [ '11[]', '12', '13' ],
  24. [ '21', '22', '23' ],
  25. [ '31', '32', '33' ]
  26. ] ) );
  27. } );
  28. afterEach( async () => {
  29. await editor.destroy();
  30. } );
  31. describe( 'TableSelection', () => {
  32. describe( 'isSelectingAndSomethingElse()', () => {
  33. it( 'should be false if selection is not started', () => {
  34. expect( tableSelection.isSelectingAndSomethingElse ).to.be.false;
  35. } );
  36. it( 'should be true if selection is selecting two different cells', () => {
  37. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  38. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  39. expect( tableSelection.isSelectingAndSomethingElse ).to.be.true;
  40. } );
  41. it( 'should be false if selection start/end is selecting the same table cell', () => {
  42. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  43. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  44. expect( tableSelection.isSelectingAndSomethingElse ).to.be.false;
  45. } );
  46. it( 'should be false if selection has no end cell', () => {
  47. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  48. expect( tableSelection.isSelectingAndSomethingElse ).to.be.false;
  49. } );
  50. it( 'should be false if selection has ended', () => {
  51. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  52. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  53. tableSelection.stopSelection();
  54. expect( tableSelection.isSelectingAndSomethingElse ).to.be.false;
  55. } );
  56. } );
  57. describe( 'startSelectingFrom()', () => {
  58. it( 'should not change model selection', () => {
  59. const spy = sinon.spy();
  60. model.document.selection.on( 'change', spy );
  61. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  62. sinon.assert.notCalled( spy );
  63. } );
  64. } );
  65. describe( 'setSelectingTo()', () => {
  66. it( 'should not change model selection if selection is not started', () => {
  67. const spy = sinon.spy();
  68. model.document.selection.on( 'change', spy );
  69. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  70. sinon.assert.notCalled( spy );
  71. } );
  72. it( 'should change model selection if valid selection will be set', () => {
  73. const spy = sinon.spy();
  74. model.document.selection.on( 'change', spy );
  75. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  76. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  77. sinon.assert.calledOnce( spy );
  78. } );
  79. it( 'should not change model selection if passed table cell is from other table then start cell', () => {
  80. setModelData( model,
  81. modelTable( [
  82. [ '11[]', '12', '13' ],
  83. [ '21', '22', '23' ],
  84. [ '31', '32', '33' ]
  85. ] ) +
  86. modelTable( [
  87. [ 'a', 'b' ],
  88. [ 'c', 'd' ]
  89. ] )
  90. );
  91. const spy = sinon.spy();
  92. model.document.selection.on( 'change', spy );
  93. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  94. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 1, 0, 1 ] ) );
  95. sinon.assert.notCalled( spy );
  96. } );
  97. it( 'should select two table cells', () => {
  98. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  99. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  100. assertSelectedCells( [
  101. [ 1, 1, 0 ],
  102. [ 0, 0, 0 ],
  103. [ 0, 0, 0 ]
  104. ] );
  105. } );
  106. it( 'should select four table cells for diagonal selection', () => {
  107. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  108. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
  109. assertSelectedCells( [
  110. [ 1, 1, 0 ],
  111. [ 1, 1, 0 ],
  112. [ 0, 0, 0 ]
  113. ] );
  114. } );
  115. it( 'should select row table cells', () => {
  116. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  117. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 2 ] ) );
  118. assertSelectedCells( [
  119. [ 1, 1, 1 ],
  120. [ 0, 0, 0 ],
  121. [ 0, 0, 0 ]
  122. ] );
  123. } );
  124. it( 'should select column table cells', () => {
  125. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  126. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 2, 1 ] ) );
  127. assertSelectedCells( [
  128. [ 0, 1, 0 ],
  129. [ 0, 1, 0 ],
  130. [ 0, 1, 0 ]
  131. ] );
  132. } );
  133. it( 'should create proper selection on consecutive changes', () => {
  134. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
  135. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 2, 1 ] ) );
  136. assertSelectedCells( [
  137. [ 0, 0, 0 ],
  138. [ 0, 1, 0 ],
  139. [ 0, 1, 0 ]
  140. ] );
  141. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  142. assertSelectedCells( [
  143. [ 0, 1, 0 ],
  144. [ 0, 1, 0 ],
  145. [ 0, 0, 0 ]
  146. ] );
  147. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 2, 2 ] ) );
  148. assertSelectedCells( [
  149. [ 0, 0, 0 ],
  150. [ 0, 1, 1 ],
  151. [ 0, 1, 1 ]
  152. ] );
  153. } );
  154. } );
  155. describe( 'stopSelection()', () => {
  156. it( 'should not clear currently selected cells if not cell was passed', () => {
  157. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  158. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  159. tableSelection.stopSelection();
  160. assertSelectedCells( [
  161. [ 1, 1, 0 ],
  162. [ 0, 0, 0 ],
  163. [ 0, 0, 0 ]
  164. ] );
  165. } );
  166. it( 'should change model selection if cell was passed', () => {
  167. const spy = sinon.spy();
  168. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  169. model.document.selection.on( 'change', spy );
  170. tableSelection.stopSelection( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  171. sinon.assert.calledOnce( spy );
  172. } );
  173. it( 'should extend selection to passed table cell', () => {
  174. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  175. tableSelection.stopSelection( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  176. assertSelectedCells( [
  177. [ 1, 1, 0 ],
  178. [ 0, 0, 0 ],
  179. [ 0, 0, 0 ]
  180. ] );
  181. } );
  182. } );
  183. describe( 'clearSelection()', () => {
  184. it( 'should not change model selection', () => {
  185. const spy = sinon.spy();
  186. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  187. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  188. model.document.selection.on( 'change', spy );
  189. tableSelection.clearSelection();
  190. sinon.assert.notCalled( spy );
  191. } );
  192. it( 'should stop selecting mode', () => {
  193. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  194. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  195. tableSelection.clearSelection();
  196. expect( tableSelection.isSelectingAndSomethingElse ).to.be.false;
  197. } );
  198. it( 'should not reset model selections', () => {
  199. tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  200. tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  201. tableSelection.clearSelection();
  202. assertSelectedCells( [
  203. [ 1, 1, 0 ],
  204. [ 0, 0, 0 ],
  205. [ 0, 0, 0 ]
  206. ] );
  207. } );
  208. } );
  209. describe( '* getSelectedTableCells()', () => {} );
  210. } );
  211. describe( 'mouse selection', () => {
  212. let view, domEvtDataStub;
  213. beforeEach( () => {
  214. view = editor.editing.view;
  215. domEvtDataStub = {
  216. domEvent: {
  217. buttons: 1
  218. },
  219. target: undefined,
  220. preventDefault: sinon.spy(),
  221. stopPropagation: sinon.spy()
  222. };
  223. } );
  224. it( 'should not start table selection when mouse move is inside one table cell', () => {
  225. setModelData( model, modelTable( [
  226. [ '[]00', '01' ],
  227. [ '10', '11' ]
  228. ] ) );
  229. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  230. view.document.fire( 'mousedown', domEvtDataStub );
  231. assertEqualMarkup( getModelData( model ), modelTable( [
  232. [ '[]00', '01' ],
  233. [ '10', '11' ]
  234. ] ) );
  235. view.document.fire( 'mousemove', domEvtDataStub );
  236. assertEqualMarkup( getModelData( model ), modelTable( [
  237. [ '[]00', '01' ],
  238. [ '10', '11' ]
  239. ] ) );
  240. } );
  241. it( 'should start table selection when mouse move expands over two cells', () => {
  242. setModelData( model, modelTable( [
  243. [ '[]00', '01' ],
  244. [ '10', '11' ]
  245. ] ) );
  246. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  247. view.document.fire( 'mousedown', domEvtDataStub );
  248. assertEqualMarkup( getModelData( model ), modelTable( [
  249. [ '[]00', '01' ],
  250. [ '10', '11' ]
  251. ] ) );
  252. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  253. view.document.fire( 'mousemove', domEvtDataStub );
  254. assertEqualMarkup( getModelData( model ), modelTable( [
  255. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  256. [ '10', '11' ]
  257. ] ) );
  258. assertEqualMarkup( getViewData( view ), viewTable( [
  259. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  260. [ '10', '11' ]
  261. ], { asWidget: true } ) );
  262. } );
  263. it( 'should select rectangular table cells when mouse moved to diagonal cell (up -> down)', () => {
  264. setModelData( model, modelTable( [
  265. [ '[]00', '01' ],
  266. [ '10', '11' ]
  267. ] ) );
  268. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  269. view.document.fire( 'mousedown', domEvtDataStub );
  270. assertEqualMarkup( getModelData( model ), modelTable( [
  271. [ '[]00', '01' ],
  272. [ '10', '11' ]
  273. ] ) );
  274. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  275. view.document.fire( 'mousemove', domEvtDataStub );
  276. assertEqualMarkup( getModelData( model ), modelTable( [
  277. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  278. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true } ]
  279. ] ) );
  280. assertEqualMarkup( getViewData( view ), viewTable( [
  281. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  282. [ { contents: '10', class: 'selected', isSelected: true }, { contents: '11', class: 'selected', isSelected: true } ]
  283. ], { asWidget: true } ) );
  284. } );
  285. it( 'should select rectangular table cells when mouse moved to diagonal cell (down -> up)', () => {
  286. setModelData( model, modelTable( [
  287. [ '00', '01' ],
  288. [ '10', '[]11' ]
  289. ] ) );
  290. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  291. view.document.fire( 'mousedown', domEvtDataStub );
  292. assertEqualMarkup( getModelData( model ), modelTable( [
  293. [ '00', '01' ],
  294. [ '10', '[]11' ]
  295. ] ) );
  296. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  297. view.document.fire( 'mousemove', domEvtDataStub );
  298. assertEqualMarkup( getModelData( model ), modelTable( [
  299. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  300. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true } ]
  301. ] ) );
  302. assertEqualMarkup( getViewData( view ), viewTable( [
  303. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  304. [ { contents: '10', class: 'selected', isSelected: true }, { contents: '11', class: 'selected', isSelected: true } ]
  305. ], { asWidget: true } ) );
  306. } );
  307. it( 'should update view selection after changing selection rect', () => {
  308. setModelData( model, modelTable( [
  309. [ '[]00', '01', '02' ],
  310. [ '10', '11', '12' ],
  311. [ '20', '21', '22' ]
  312. ] ) );
  313. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  314. view.document.fire( 'mousedown', domEvtDataStub );
  315. selectTableCell( domEvtDataStub, view, 0, 0, 2, 2 );
  316. view.document.fire( 'mousemove', domEvtDataStub );
  317. assertEqualMarkup( getModelData( model ), modelTable( [
  318. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true }, { contents: '02', isSelected: true } ],
  319. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true }, { contents: '12', isSelected: true } ],
  320. [ { contents: '20', isSelected: true }, { contents: '21', isSelected: true }, { contents: '22', isSelected: true } ]
  321. ] ) );
  322. assertEqualMarkup( getViewData( view ), viewTable( [
  323. [
  324. { contents: '00', class: 'selected', isSelected: true },
  325. { contents: '01', class: 'selected', isSelected: true },
  326. { contents: '02', class: 'selected', isSelected: true }
  327. ],
  328. [
  329. { contents: '10', class: 'selected', isSelected: true },
  330. { contents: '11', class: 'selected', isSelected: true },
  331. { contents: '12', class: 'selected', isSelected: true }
  332. ],
  333. [
  334. { contents: '20', class: 'selected', isSelected: true },
  335. { contents: '21', class: 'selected', isSelected: true },
  336. { contents: '22', class: 'selected', isSelected: true }
  337. ]
  338. ], { asWidget: true } ) );
  339. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  340. view.document.fire( 'mousemove', domEvtDataStub );
  341. assertEqualMarkup( getModelData( model ), modelTable( [
  342. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true }, '02' ],
  343. [ { contents: '10', isSelected: true }, { contents: '11', isSelected: true }, '12' ],
  344. [ '20', '21', '22' ]
  345. ] ) );
  346. assertEqualMarkup( getViewData( view ), viewTable( [
  347. [
  348. { contents: '00', class: 'selected', isSelected: true },
  349. { contents: '01', class: 'selected', isSelected: true },
  350. '02'
  351. ],
  352. [
  353. { contents: '10', class: 'selected', isSelected: true },
  354. { contents: '11', class: 'selected', isSelected: true },
  355. '12'
  356. ],
  357. [
  358. '20',
  359. '21',
  360. '22'
  361. ]
  362. ], { asWidget: true } ) );
  363. } );
  364. it( 'should stop selecting after "mouseup" event', () => {
  365. setModelData( model, modelTable( [
  366. [ '[]00', '01' ],
  367. [ '10', '11' ]
  368. ] ) );
  369. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  370. view.document.fire( 'mousedown', domEvtDataStub );
  371. assertEqualMarkup( getModelData( model ), modelTable( [
  372. [ '[]00', '01' ],
  373. [ '10', '11' ]
  374. ] ) );
  375. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  376. view.document.fire( 'mousemove', domEvtDataStub );
  377. view.document.fire( 'mouseup', domEvtDataStub );
  378. assertEqualMarkup( getModelData( model ), modelTable( [
  379. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  380. [ '10', '11' ]
  381. ] ) );
  382. assertEqualMarkup( getViewData( view ), viewTable( [
  383. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  384. [ '10', '11' ]
  385. ], { asWidget: true } ) );
  386. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  387. view.document.fire( 'mousemove', domEvtDataStub );
  388. assertEqualMarkup( getModelData( model ), modelTable( [
  389. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  390. [ '10', '11' ]
  391. ] ) );
  392. } );
  393. it( 'should stop selection mode on "mouseleve" event', () => {
  394. setModelData( model, modelTable( [
  395. [ '[]00', '01' ],
  396. [ '10', '11' ]
  397. ] ) );
  398. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  399. view.document.fire( 'mousedown', domEvtDataStub );
  400. assertEqualMarkup( getModelData( model ), modelTable( [
  401. [ '[]00', '01' ],
  402. [ '10', '11' ]
  403. ] ) );
  404. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  405. view.document.fire( 'mousemove', domEvtDataStub );
  406. view.document.fire( 'mouseleave', domEvtDataStub );
  407. assertEqualMarkup( getModelData( model ), modelTable( [
  408. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  409. [ '10', '11' ]
  410. ] ) );
  411. assertEqualMarkup( getViewData( view ), viewTable( [
  412. [ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
  413. [ '10', '11' ]
  414. ], { asWidget: true } ) );
  415. selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
  416. view.document.fire( 'mousemove', domEvtDataStub );
  417. assertEqualMarkup( getModelData( model ), modelTable( [
  418. [ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
  419. [ '10', '11' ]
  420. ] ) );
  421. } );
  422. it( 'should clear view table selection after mouse click outside table', () => {
  423. setModelData( model, modelTable( [
  424. [ '[]00', '01' ],
  425. [ '10', '11' ]
  426. ] ) + '<paragraph>foo</paragraph>' );
  427. selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
  428. view.document.fire( 'mousedown', domEvtDataStub );
  429. assertEqualMarkup( getModelData( model ), modelTable( [
  430. [ '[]00', '01' ],
  431. [ '10', '11' ]
  432. ] ) + '<paragraph>foo</paragraph>' );
  433. selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
  434. view.document.fire( 'mousemove', domEvtDataStub );
  435. domEvtDataStub.target = view.document.getRoot().getChild( 1 );
  436. view.document.fire( 'mousemove', domEvtDataStub );
  437. view.document.fire( 'mousedown', domEvtDataStub );
  438. view.document.fire( 'mouseup', domEvtDataStub );
  439. // The click in the DOM would trigger selection change and it will set the selection:
  440. model.change( writer => {
  441. writer.setSelection( writer.createRange( writer.createPositionAt( model.document.getRoot().getChild( 1 ), 0 ) ) );
  442. } );
  443. assertEqualMarkup( getViewData( view ), viewTable( [
  444. [ '00', '01' ],
  445. [ '10', '11' ]
  446. ], { asWidget: true } ) + '<p>{}foo</p>' );
  447. } );
  448. } );
  449. // Helper method for asserting selected table cells.
  450. //
  451. // To check if a table has expected cells selected pass two dimensional array of truthy and falsy values:
  452. //
  453. // assertSelectedCells( [
  454. // [ 0, 1 ],
  455. // [ 0, 1 ]
  456. // ] );
  457. //
  458. // The above call will check if table has second column selected (assuming no spans).
  459. //
  460. // **Note**: This function operates on child indexes - not rows/columns.
  461. function assertSelectedCells( tableMap ) {
  462. const tableIndex = 0;
  463. for ( let rowIndex = 0; rowIndex < tableMap.length; rowIndex++ ) {
  464. const row = tableMap[ rowIndex ];
  465. for ( let cellIndex = 0; cellIndex < row.length; cellIndex++ ) {
  466. const expectSelected = row[ cellIndex ];
  467. if ( expectSelected ) {
  468. assertNodeIsSelected( [ tableIndex, rowIndex, cellIndex ] );
  469. } else {
  470. assertNodeIsNotSelected( [ tableIndex, rowIndex, cellIndex ] );
  471. }
  472. }
  473. }
  474. }
  475. function assertNodeIsSelected( path ) {
  476. const node = modelRoot.getNodeByPath( path );
  477. const selectionRanges = Array.from( model.document.selection.getRanges() );
  478. expect( selectionRanges.some( range => range.containsItem( node ) ), `Expected node [${ path }] to be selected` ).to.be.true;
  479. }
  480. function assertNodeIsNotSelected( path ) {
  481. const node = modelRoot.getNodeByPath( path );
  482. const selectionRanges = Array.from( model.document.selection.getRanges() );
  483. expect( selectionRanges.every( range => !range.containsItem( node ) ), `Expected node [${ path }] to be not selected` ).to.be.true;
  484. }
  485. } );
  486. function selectTableCell( domEvtDataStub, view, tableIndex, sectionIndex, rowInSectionIndex, tableCellIndex ) {
  487. domEvtDataStub.target = view.document.getRoot()
  488. .getChild( tableIndex )
  489. .getChild( 1 ) // Table is second in widget
  490. .getChild( sectionIndex )
  491. .getChild( rowInSectionIndex )
  492. .getChild( tableCellIndex );
  493. }