redocommand.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import ModelTestEditor from 'ckeditor5-core/tests/_utils/modeltesteditor';
  6. import Range from 'ckeditor5-engine/src/model/range';
  7. import Position from 'ckeditor5-engine/src/model/position';
  8. import UndoCommand from 'ckeditor5-undo/src/undocommand';
  9. import RedoCommand from 'ckeditor5-undo/src/redocommand';
  10. import { itemAt, getText } from 'ckeditor5-engine/tests/model/_utils/utils';
  11. describe( 'RedoCommand', () => {
  12. let editor, doc, root, redo, undo;
  13. beforeEach( () => {
  14. editor = new ModelTestEditor();
  15. redo = new RedoCommand( editor );
  16. doc = editor.document;
  17. root = doc.getRoot();
  18. } );
  19. afterEach( () => {
  20. redo.destroy();
  21. } );
  22. describe( 'RedoCommand', () => {
  23. describe( '_execute', () => {
  24. const p = pos => new Position( root, [].concat( pos ) );
  25. const r = ( a, b ) => new Range( p( a ), p( b ) );
  26. let batch0, batch1, batch2;
  27. let batches = new Set();
  28. beforeEach( () => {
  29. undo = new UndoCommand( editor );
  30. // Simple integration with undo.
  31. undo.on( 'revert', ( evt, undoneBatch, undoingBatch ) => {
  32. if ( !batches.has( undoingBatch ) ) {
  33. redo.addBatch( undoingBatch );
  34. batches.add( undoingBatch );
  35. }
  36. } );
  37. /*
  38. [root]
  39. - {}
  40. */
  41. editor.document.selection.setRanges( [ r( 0, 0 ) ] );
  42. batch0 = doc.batch();
  43. undo.addBatch( batch0 );
  44. batch0.insert( p( 0 ), 'foobar' );
  45. /*
  46. [root]
  47. - f
  48. - o
  49. - o
  50. - b
  51. - a
  52. - r{}
  53. */
  54. // Let's make things spicy and this time, make a backward selection.
  55. editor.document.selection.setRanges( [ r( 2, 4 ) ], true );
  56. batch1 = doc.batch();
  57. undo.addBatch( batch1 );
  58. batch1.setAttribute( r( 2, 4 ), 'key', 'value' );
  59. /*
  60. [root]
  61. - f
  62. - o
  63. - {o (key: value)
  64. - b} (key: value)
  65. - a
  66. - r
  67. */
  68. editor.document.selection.setRanges( [ r( 1, 3 ) ] );
  69. batch2 = doc.batch();
  70. undo.addBatch( batch2 );
  71. batch2.move( r( 1, 3 ), p( 6 ) );
  72. /*
  73. [root]
  74. - f
  75. - b (key: value)
  76. - a
  77. - r
  78. - {o
  79. - o} (key: value)
  80. */
  81. } );
  82. it( 'should redo batch undone by undo command', () => {
  83. undo._execute( batch2 );
  84. redo._execute();
  85. // Should be back at original state:
  86. /*
  87. [root]
  88. - f
  89. - b (key: value)
  90. - a
  91. - r
  92. - {o
  93. - o} (key: value)
  94. */
  95. expect( getText( root ) ).to.equal( 'fbaroo' );
  96. expect( itemAt( root, 1 ).getAttribute( 'key' ) ).to.equal( 'value' );
  97. expect( itemAt( root, 5 ).getAttribute( 'key' ) ).to.equal( 'value' );
  98. expect( editor.document.selection.getRanges().next().value.isEqual( r( 4, 6 ) ) ).to.be.true;
  99. expect( editor.document.selection.isBackward ).to.be.false;
  100. } );
  101. it( 'should redo series of batches undone by undo command', () => {
  102. undo._execute();
  103. undo._execute();
  104. undo._execute();
  105. redo._execute();
  106. // Should be like after applying `batch0`:
  107. /*
  108. [root]
  109. - f
  110. - o
  111. - o
  112. - b
  113. - a
  114. - r{}
  115. */
  116. expect( getText( root ) ).to.equal( 'foobar' );
  117. expect( Array.from( root.getChildren() ).find( node => node.hasAttribute( 'key' ) ) ).to.be.undefined;
  118. expect( editor.document.selection.getRanges().next().value.isEqual( r( 6, 6 ) ) ).to.be.true;
  119. expect( editor.document.selection.isBackward ).to.be.false;
  120. redo._execute();
  121. // Should be like after applying `batch1`:
  122. /*
  123. [root]
  124. - f
  125. - o
  126. - {o (key: value)
  127. - b} (key: value)
  128. - a
  129. - r
  130. */
  131. expect( getText( root ) ).to.equal( 'foobar' );
  132. expect( itemAt( root, 2 ).getAttribute( 'key' ) ).to.equal( 'value' );
  133. expect( itemAt( root, 3 ).getAttribute( 'key' ) ).to.equal( 'value' );
  134. expect( editor.document.selection.getRanges().next().value.isEqual( r( 2, 4 ) ) ).to.be.true;
  135. expect( editor.document.selection.isBackward ).to.be.true;
  136. redo._execute();
  137. // Should be like after applying `batch2`:
  138. /*
  139. [root]
  140. - f
  141. - b (key: value)
  142. - a
  143. - r
  144. - {o
  145. - o} (key: value)
  146. */
  147. expect( getText( root ) ).to.equal( 'fbaroo' );
  148. expect( itemAt( root, 1 ).getAttribute( 'key' ) ).to.equal( 'value' );
  149. expect( itemAt( root, 5 ).getAttribute( 'key' ) ).to.equal( 'value' );
  150. expect( editor.document.selection.getRanges().next().value.isEqual( r( 4, 6 ) ) ).to.be.true;
  151. expect( editor.document.selection.isBackward ).to.be.false;
  152. } );
  153. it( 'should redo batch selectively undone by undo command', () => {
  154. undo._execute( batch0 );
  155. redo._execute();
  156. // Should be back to original state:
  157. /*
  158. [root]
  159. - f
  160. - b (key: value)
  161. - a
  162. - r
  163. - o
  164. - o{} (key: value)
  165. */
  166. expect( getText( root ) ).to.equal( 'fbaroo' );
  167. expect( itemAt( root, 1 ).getAttribute( 'key' ) ).to.equal( 'value' );
  168. expect( itemAt( root, 5 ).getAttribute( 'key' ) ).to.equal( 'value' );
  169. expect( editor.document.selection.getRanges().next().value.isEqual( r( 6, 6 ) ) ).to.be.true;
  170. expect( editor.document.selection.isBackward ).to.be.false;
  171. } );
  172. it( 'should redo batch selectively undone by undo command #2', () => {
  173. undo._execute( batch1 );
  174. undo._execute( batch2 );
  175. redo._execute();
  176. redo._execute();
  177. // Should be back to original state:
  178. /*
  179. [root]
  180. - f
  181. - {b} (key: value)
  182. - a
  183. - r
  184. - o
  185. - o (key: value)
  186. */
  187. expect( getText( root ) ).to.equal( 'fbaroo' );
  188. expect( itemAt( root, 1 ).getAttribute( 'key' ) ).to.equal( 'value' );
  189. expect( itemAt( root, 5 ).getAttribute( 'key' ) ).to.equal( 'value' );
  190. expect( editor.document.selection.getRanges().next().value.isEqual( r( 1, 2 ) ) ).to.be.true;
  191. expect( editor.document.selection.isBackward ).to.be.true;
  192. } );
  193. it( 'should transform redo batch by changes written in history that happened after undo but before redo #2', () => {
  194. // Now it is "fBaroO".
  195. // Undo moving "oo" to the end of string. Now it is "foOBar". Capitals mean set attribute.
  196. undo._execute();
  197. // Remove "ar".
  198. doc.batch().remove( r( 4, 6 ) );
  199. // Undo setting attribute on "ob". Now it is "foob".
  200. undo._execute();
  201. // Append "xx" at the beginning. Now it is "xxfoob".
  202. doc.batch().insert( p( 0 ), 'xx' );
  203. // Redo setting attribute on "ob". Now it is "xxfoOB".
  204. redo._execute();
  205. expect( getText( root ) ).to.equal( 'xxfoob' );
  206. expect( itemAt( root, 4 ).getAttribute( 'key' ) ).to.equal( 'value' );
  207. expect( itemAt( root, 5 ).getAttribute( 'key' ) ).to.equal( 'value' );
  208. expect( editor.document.selection.getFirstRange().isEqual( r( 4, 6 ) ) ).to.be.true;
  209. expect( editor.document.selection.isBackward ).to.be.true;
  210. // Redo moving "oo". Now it is "xxfBoO". Selection is expected to be on just moved "oO".
  211. redo._execute();
  212. expect( getText( root ) ).to.equal( 'xxfboo' );
  213. expect( itemAt( root, 3 ).getAttribute( 'key' ) ).to.equal( 'value' );
  214. expect( itemAt( root, 5 ).getAttribute( 'key' ) ).to.equal( 'value' );
  215. expect( editor.document.selection.getFirstRange().isEqual( r( 4, 6 ) ) ).to.be.true;
  216. expect( editor.document.selection.isBackward ).to.be.false;
  217. } );
  218. } );
  219. } );
  220. } );