redocommand.js 6.9 KB

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