history.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import Delta from 'quill-delta';
  2. import Quill from '../../../core';
  3. import { getLastChangeIndex } from '../../../modules/history';
  4. const { registry } = Quill.getNamespace();
  5. describe('History', function() {
  6. describe('getLastChangeIndex', function() {
  7. it('delete', function() {
  8. const delta = new Delta().retain(4).delete(2);
  9. expect(getLastChangeIndex(registry, delta)).toEqual(4);
  10. });
  11. it('delete with inserts', function() {
  12. const delta = new Delta()
  13. .retain(4)
  14. .insert('test')
  15. .delete(2);
  16. expect(getLastChangeIndex(registry, delta)).toEqual(8);
  17. });
  18. it('insert text', function() {
  19. const delta = new Delta().retain(4).insert('testing');
  20. expect(getLastChangeIndex(registry, delta)).toEqual(11);
  21. });
  22. it('insert embed', function() {
  23. const delta = new Delta().retain(4).insert({ image: true });
  24. expect(getLastChangeIndex(registry, delta)).toEqual(5);
  25. });
  26. it('insert with deletes', function() {
  27. const delta = new Delta()
  28. .retain(4)
  29. .delete(3)
  30. .insert('!');
  31. expect(getLastChangeIndex(registry, delta)).toEqual(5);
  32. });
  33. it('format', function() {
  34. const delta = new Delta().retain(4).retain(3, { bold: true });
  35. expect(getLastChangeIndex(registry, delta)).toEqual(7);
  36. });
  37. it('format newline', function() {
  38. const delta = new Delta().retain(4).retain(1, { align: 'left' });
  39. expect(getLastChangeIndex(registry, delta)).toEqual(4);
  40. });
  41. it('format mixed', function() {
  42. const delta = new Delta()
  43. .retain(4)
  44. .retain(1, { align: 'left', bold: true });
  45. expect(getLastChangeIndex(registry, delta)).toEqual(4);
  46. });
  47. it('insert newline', function() {
  48. const delta = new Delta().retain(4).insert('a\n');
  49. expect(getLastChangeIndex(registry, delta)).toEqual(5);
  50. });
  51. it('mutliple newline inserts', function() {
  52. const delta = new Delta().retain(4).insert('ab\n\n');
  53. expect(getLastChangeIndex(registry, delta)).toEqual(7);
  54. });
  55. });
  56. describe('undo/redo', function() {
  57. beforeEach(function() {
  58. this.initialize(HTMLElement, '<div><p>The lazy fox</p></div>');
  59. this.quill = new Quill(this.container.firstChild, {
  60. modules: {
  61. history: { delay: 400 },
  62. },
  63. });
  64. this.original = this.quill.getContents();
  65. });
  66. it('limits undo stack size', function() {
  67. const quill = new Quill(this.container.firstChild, {
  68. modules: {
  69. history: { delay: 0, maxStack: 2 },
  70. },
  71. });
  72. ['A', 'B', 'C'].forEach(function(text) {
  73. quill.insertText(0, text);
  74. });
  75. expect(quill.history.stack.undo.length).toEqual(2);
  76. });
  77. it('user change', function() {
  78. this.quill.root.firstChild.innerHTML = 'The lazy foxes';
  79. this.quill.update();
  80. const changed = this.quill.getContents();
  81. expect(changed).not.toEqual(this.original);
  82. this.quill.history.undo();
  83. expect(this.quill.getContents()).toEqual(this.original);
  84. this.quill.history.redo();
  85. expect(this.quill.getContents()).toEqual(changed);
  86. });
  87. it('merge changes', function() {
  88. expect(this.quill.history.stack.undo.length).toEqual(0);
  89. this.quill.updateContents(new Delta().retain(12).insert('e'));
  90. expect(this.quill.history.stack.undo.length).toEqual(1);
  91. this.quill.updateContents(new Delta().retain(13).insert('s'));
  92. expect(this.quill.history.stack.undo.length).toEqual(1);
  93. this.quill.history.undo();
  94. expect(this.quill.getContents()).toEqual(this.original);
  95. expect(this.quill.history.stack.undo.length).toEqual(0);
  96. });
  97. it('dont merge changes', function(done) {
  98. expect(this.quill.history.stack.undo.length).toEqual(0);
  99. this.quill.updateContents(new Delta().retain(12).insert('e'));
  100. expect(this.quill.history.stack.undo.length).toEqual(1);
  101. setTimeout(() => {
  102. this.quill.updateContents(new Delta().retain(13).insert('s'));
  103. expect(this.quill.history.stack.undo.length).toEqual(2);
  104. done();
  105. }, this.quill.history.options.delay * 1.25);
  106. });
  107. it('multiple undos', function(done) {
  108. expect(this.quill.history.stack.undo.length).toEqual(0);
  109. this.quill.updateContents(new Delta().retain(12).insert('e'));
  110. const contents = this.quill.getContents();
  111. setTimeout(() => {
  112. this.quill.updateContents(new Delta().retain(13).insert('s'));
  113. this.quill.history.undo();
  114. expect(this.quill.getContents()).toEqual(contents);
  115. this.quill.history.undo();
  116. expect(this.quill.getContents()).toEqual(this.original);
  117. done();
  118. }, this.quill.history.options.delay * 1.25);
  119. });
  120. it('transform api change', function() {
  121. this.quill.history.options.userOnly = true;
  122. this.quill.updateContents(
  123. new Delta().retain(12).insert('es'),
  124. Quill.sources.USER,
  125. );
  126. this.quill.history.lastRecorded = 0;
  127. this.quill.updateContents(
  128. new Delta().retain(14).insert('!'),
  129. Quill.sources.USER,
  130. );
  131. this.quill.history.undo();
  132. this.quill.updateContents(
  133. new Delta().retain(4).delete(5),
  134. Quill.sources.API,
  135. );
  136. expect(this.quill.getContents()).toEqual(
  137. new Delta().insert('The foxes\n'),
  138. );
  139. this.quill.history.undo();
  140. expect(this.quill.getContents()).toEqual(new Delta().insert('The fox\n'));
  141. this.quill.history.redo();
  142. expect(this.quill.getContents()).toEqual(
  143. new Delta().insert('The foxes\n'),
  144. );
  145. this.quill.history.redo();
  146. expect(this.quill.getContents()).toEqual(
  147. new Delta().insert('The foxes!\n'),
  148. );
  149. });
  150. it('transform preserve intention', function() {
  151. const url = 'https://www.google.com/';
  152. this.quill.history.options.userOnly = true;
  153. this.quill.updateContents(
  154. new Delta().insert(url, { link: url }),
  155. Quill.sources.USER,
  156. );
  157. this.quill.history.lastRecorded = 0;
  158. this.quill.updateContents(
  159. new Delta().delete(url.length).insert('Google', { link: url }),
  160. Quill.sources.API,
  161. );
  162. this.quill.history.lastRecorded = 0;
  163. this.quill.updateContents(
  164. new Delta().retain(this.quill.getLength() - 1).insert('!'),
  165. Quill.sources.USER,
  166. );
  167. this.quill.history.lastRecorded = 0;
  168. expect(this.quill.getContents()).toEqual(
  169. new Delta().insert('Google', { link: url }).insert('The lazy fox!\n'),
  170. );
  171. this.quill.history.undo();
  172. expect(this.quill.getContents()).toEqual(
  173. new Delta().insert('Google', { link: url }).insert('The lazy fox\n'),
  174. );
  175. this.quill.history.undo();
  176. expect(this.quill.getContents()).toEqual(
  177. new Delta().insert('Google', { link: url }).insert('The lazy fox\n'),
  178. );
  179. });
  180. it('ignore remote changes', function() {
  181. this.quill.history.options.delay = 0;
  182. this.quill.history.options.userOnly = true;
  183. this.quill.setText('\n');
  184. this.quill.insertText(0, 'a', Quill.sources.USER);
  185. this.quill.insertText(1, 'b', Quill.sources.API);
  186. this.quill.insertText(2, 'c', Quill.sources.USER);
  187. this.quill.insertText(3, 'd', Quill.sources.API);
  188. expect(this.quill.getText()).toEqual('abcd\n');
  189. this.quill.history.undo();
  190. expect(this.quill.getText()).toEqual('abd\n');
  191. this.quill.history.undo();
  192. expect(this.quill.getText()).toEqual('bd\n');
  193. this.quill.history.redo();
  194. expect(this.quill.getText()).toEqual('abd\n');
  195. this.quill.history.redo();
  196. expect(this.quill.getText()).toEqual('abcd\n');
  197. });
  198. it('correctly transform against remote changes', function() {
  199. this.quill.history.options.delay = 0;
  200. this.quill.history.options.userOnly = true;
  201. this.quill.setText('b\n');
  202. this.quill.insertText(1, 'd', Quill.sources.USER);
  203. this.quill.insertText(0, 'a', Quill.sources.USER);
  204. this.quill.insertText(2, 'c', Quill.sources.API);
  205. expect(this.quill.getText()).toEqual('abcd\n');
  206. this.quill.history.undo();
  207. expect(this.quill.getText()).toEqual('bcd\n');
  208. this.quill.history.undo();
  209. expect(this.quill.getText()).toEqual('bc\n');
  210. this.quill.history.redo();
  211. expect(this.quill.getText()).toEqual('bcd\n');
  212. this.quill.history.redo();
  213. expect(this.quill.getText()).toEqual('abcd\n');
  214. });
  215. it('correctly transform against remote changes breaking up an insert', function() {
  216. this.quill.history.options.delay = 0;
  217. this.quill.history.options.userOnly = true;
  218. this.quill.setText('\n');
  219. this.quill.insertText(0, 'ABC', Quill.sources.USER);
  220. this.quill.insertText(3, '4', Quill.sources.API);
  221. this.quill.insertText(2, '3', Quill.sources.API);
  222. this.quill.insertText(1, '2', Quill.sources.API);
  223. this.quill.insertText(0, '1', Quill.sources.API);
  224. expect(this.quill.getText()).toEqual('1A2B3C4\n');
  225. this.quill.history.undo();
  226. expect(this.quill.getText()).toEqual('1234\n');
  227. this.quill.history.redo();
  228. expect(this.quill.getText()).toEqual('1A2B3C4\n');
  229. this.quill.history.undo();
  230. expect(this.quill.getText()).toEqual('1234\n');
  231. this.quill.history.redo();
  232. expect(this.quill.getText()).toEqual('1A2B3C4\n');
  233. });
  234. });
  235. });