utils.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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 TableSelection from '../src/tableselection';
  8. import TableEditing from '../src/tableediting';
  9. import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  10. import { modelTable } from './_utils/utils';
  11. import {
  12. getSelectedTableCells,
  13. getTableCellsContainingSelection,
  14. getSelectionAffectedTableCells
  15. } from '../src/utils';
  16. describe( 'table utils', () => {
  17. let editor, model, tableSelection, modelRoot;
  18. beforeEach( async () => {
  19. editor = await VirtualTestEditor.create( {
  20. plugins: [ TableEditing, TableSelection, Paragraph ]
  21. } );
  22. model = editor.model;
  23. modelRoot = model.document.getRoot();
  24. tableSelection = editor.plugins.get( TableSelection );
  25. setModelData( model, modelTable( [
  26. [ '11[]', '12', '13' ],
  27. [ '21', '22', '23' ],
  28. [ '31', '32', '33' ]
  29. ] ) );
  30. } );
  31. afterEach( async () => {
  32. await editor.destroy();
  33. } );
  34. describe( 'getSelectedTableCells()', () => {
  35. let selection;
  36. beforeEach( () => {
  37. selection = model.document.selection;
  38. } );
  39. it( 'should return an empty array when a collapsed selection is anchored in a cell', () => {
  40. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  41. model.change( writer => {
  42. writer.setSelection( writer.createRange( writer.createPositionAt( firstCell, 0 ) ) );
  43. } );
  44. expect( getSelectedTableCells( selection ) ).to.be.empty;
  45. } );
  46. it( 'should return an empty array when a non-collapsed selection is anchored in a cell', () => {
  47. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  48. model.change( writer => {
  49. writer.setSelection( writer.createRangeIn( firstCell ) );
  50. } );
  51. expect( getSelectedTableCells( selection ) ).to.be.empty;
  52. } );
  53. it( 'should return an empty array when a non-cell node is selected', () => {
  54. const paragraph = modelRoot.getNodeByPath( [ 0, 0, 0, 0 ] );
  55. expect( paragraph.is( 'paragraph' ) ).to.be.true;
  56. model.change( writer => {
  57. writer.setSelection( writer.createRangeOn( paragraph ) );
  58. } );
  59. expect( getSelectedTableCells( selection ) ).to.be.empty;
  60. } );
  61. it( 'should return an empty array when an entire table is selected', () => {
  62. const table = modelRoot.getNodeByPath( [ 0 ] );
  63. model.change( writer => {
  64. writer.setSelection( writer.createRangeOn( table ) );
  65. } );
  66. expect( getSelectedTableCells( selection ) ).to.be.empty;
  67. } );
  68. it( 'should return two table cells', () => {
  69. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  70. const lastCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] );
  71. tableSelection._setCellSelection( firstCell, lastCell );
  72. expect( Array.from( getSelectedTableCells( selection ) ) ).to.have.ordered.members( [
  73. firstCell, lastCell
  74. ] );
  75. } );
  76. it( 'should return four table cells for diagonal selection', () => {
  77. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  78. const lastCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  79. tableSelection._setCellSelection( firstCell, lastCell );
  80. expect( Array.from( getSelectedTableCells( selection ) ) ).to.have.ordered.members( [
  81. firstCell,
  82. modelRoot.getNodeByPath( [ 0, 0, 1 ] ),
  83. modelRoot.getNodeByPath( [ 0, 1, 0 ] ),
  84. lastCell
  85. ] );
  86. } );
  87. it( 'should return row table cells', () => {
  88. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  89. const lastCell = modelRoot.getNodeByPath( [ 0, 0, 2 ] );
  90. tableSelection._setCellSelection( firstCell, lastCell );
  91. expect( Array.from( getSelectedTableCells( selection ) ) ).to.have.ordered.members( [
  92. firstCell,
  93. modelRoot.getNodeByPath( [ 0, 0, 1 ] ),
  94. lastCell
  95. ] );
  96. } );
  97. it( 'should return column table cells', () => {
  98. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] );
  99. const lastCell = modelRoot.getNodeByPath( [ 0, 2, 1 ] );
  100. tableSelection._setCellSelection( firstCell, lastCell );
  101. expect( Array.from( getSelectedTableCells( selection ) ) ).to.have.ordered.members( [
  102. firstCell,
  103. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  104. lastCell
  105. ] );
  106. } );
  107. } );
  108. describe( 'getTableCellsContainingSelection()', () => {
  109. let selection;
  110. beforeEach( () => {
  111. selection = model.document.selection;
  112. } );
  113. it( 'should return an array with a cell when a selection is anchored in it', () => {
  114. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  115. model.change( writer => {
  116. writer.setSelection( writer.createRange( writer.createPositionAt( firstCell, 0 ) ) );
  117. } );
  118. expect( getTableCellsContainingSelection( selection ) ).to.have.ordered.members( [ firstCell ] );
  119. } );
  120. it( 'should return an array with a cell when a selection range is anchored in its descendant', () => {
  121. const cell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  122. const paragraph = modelRoot.getNodeByPath( [ 0, 0, 0, 0 ] );
  123. model.change( writer => {
  124. writer.setSelection( writer.createRange(
  125. writer.createPositionAt( paragraph, 0 ),
  126. writer.createPositionAt( paragraph, 1 ),
  127. ) );
  128. } );
  129. expect( getTableCellsContainingSelection( selection ) ).to.have.ordered.members( [
  130. cell
  131. ] );
  132. } );
  133. it( 'should return an array with cells when multiple collapsed selection ranges are anchored in them', () => {
  134. const cellA = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  135. const cellB = modelRoot.getNodeByPath( [ 0, 1, 0 ] );
  136. model.change( writer => {
  137. writer.setSelection( [
  138. writer.createRange( writer.createPositionAt( cellA, 0 ) ),
  139. writer.createRange( writer.createPositionAt( cellB, 0 ) )
  140. ] );
  141. } );
  142. expect( getTableCellsContainingSelection( selection ) ).to.have.ordered.members( [
  143. cellA,
  144. cellB
  145. ] );
  146. } );
  147. it( 'should return an array with cells when multiple non–collapsed selection ranges are anchored in them', () => {
  148. const cellA = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  149. const cellB = modelRoot.getNodeByPath( [ 0, 1, 0 ] );
  150. model.change( writer => {
  151. writer.setSelection( [
  152. writer.createRangeIn( cellA ),
  153. writer.createRangeIn( cellB )
  154. ] );
  155. } );
  156. expect( getTableCellsContainingSelection( selection ) ).to.have.ordered.members( [
  157. cellA,
  158. cellB
  159. ] );
  160. } );
  161. it( 'should return an empty array when an entire cell is selected', () => {
  162. const cell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  163. model.change( writer => {
  164. writer.setSelection( writer.createRangeOn( cell ) );
  165. } );
  166. expect( getTableCellsContainingSelection( selection ) ).to.be.empty;
  167. } );
  168. it( 'should return an empty array when an entire table is selected', () => {
  169. const table = modelRoot.getNodeByPath( [ 0 ] );
  170. model.change( writer => {
  171. writer.setSelection( writer.createRangeOn( table ) );
  172. } );
  173. expect( getTableCellsContainingSelection( selection ) ).to.be.empty;
  174. } );
  175. it( 'should return an empty array when unrelated elements host selection ranges', () => {
  176. setModelData( model, '<paragraph>foo</paragraph>' );
  177. const paragraph = modelRoot.getNodeByPath( [ 0 ] );
  178. model.change( writer => {
  179. writer.setSelection( writer.createRange( writer.createPositionAt( paragraph, 1 ) ) );
  180. } );
  181. expect( getTableCellsContainingSelection( selection ) ).to.be.empty;
  182. } );
  183. } );
  184. describe( 'getSelectionAffectedTableCells()', () => {
  185. let selection;
  186. beforeEach( () => {
  187. selection = model.document.selection;
  188. } );
  189. it( 'should return completely selected cells (if there are any)', () => {
  190. const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  191. const lastCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] );
  192. tableSelection._setCellSelection( firstCell, lastCell );
  193. expect( Array.from( getSelectionAffectedTableCells( selection ) ) ).to.have.ordered.members( [
  194. firstCell, lastCell
  195. ] );
  196. } );
  197. it( 'should return cells when selection ranges are starting in them', () => {
  198. const cellA = modelRoot.getNodeByPath( [ 0, 0, 0 ] );
  199. const cellB = modelRoot.getNodeByPath( [ 0, 1, 0 ] );
  200. model.change( writer => {
  201. writer.setSelection( [
  202. writer.createRange( writer.createPositionAt( cellA, 0 ) ),
  203. writer.createRange( writer.createPositionAt( cellB, 0 ) )
  204. ] );
  205. } );
  206. expect( getSelectionAffectedTableCells( selection ) ).to.have.ordered.members( [
  207. cellA,
  208. cellB
  209. ] );
  210. } );
  211. it( 'should return an empty array if no cells are selected and no selection ranges start in any cell', () => {
  212. const table = modelRoot.getNodeByPath( [ 0 ] );
  213. model.change( writer => {
  214. writer.setSelection( writer.createRangeOn( table ) );
  215. } );
  216. expect( getSelectionAffectedTableCells( selection ) ).to.be.empty;
  217. setModelData( model, '<paragraph>foo</paragraph>' );
  218. const paragraph = modelRoot.getNodeByPath( [ 0 ] );
  219. model.change( writer => {
  220. writer.setSelection( writer.createRange( writer.createPositionAt( paragraph, 1 ) ) );
  221. } );
  222. expect( getSelectionAffectedTableCells( selection ) ).to.be.empty;
  223. } );
  224. } );
  225. } );