index.es.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { isPlainObject } from 'is-plain-object';
  2. import { Operation, Editor, Path } from 'slate';
  3. var History = {
  4. /**
  5. * Check if a value is a `History` object.
  6. */
  7. isHistory(value) {
  8. return isPlainObject(value) && Array.isArray(value.redos) && Array.isArray(value.undos) && (value.redos.length === 0 || Operation.isOperationList(value.redos[0])) && (value.undos.length === 0 || Operation.isOperationList(value.undos[0]));
  9. }
  10. };
  11. /**
  12. * Weakmaps for attaching state to the editor.
  13. */
  14. var HISTORY = new WeakMap();
  15. var SAVING = new WeakMap();
  16. var MERGING = new WeakMap();
  17. var HistoryEditor = {
  18. /**
  19. * Check if a value is a `HistoryEditor` object.
  20. */
  21. isHistoryEditor(value) {
  22. return History.isHistory(value.history) && Editor.isEditor(value);
  23. },
  24. /**
  25. * Get the merge flag's current value.
  26. */
  27. isMerging(editor) {
  28. return MERGING.get(editor);
  29. },
  30. /**
  31. * Get the saving flag's current value.
  32. */
  33. isSaving(editor) {
  34. return SAVING.get(editor);
  35. },
  36. /**
  37. * Redo to the previous saved state.
  38. */
  39. redo(editor) {
  40. editor.redo();
  41. },
  42. /**
  43. * Undo to the previous saved state.
  44. */
  45. undo(editor) {
  46. editor.undo();
  47. },
  48. /**
  49. * Apply a series of changes inside a synchronous `fn`, without merging any of
  50. * the new operations into previous save point in the history.
  51. */
  52. withoutMerging(editor, fn) {
  53. var prev = HistoryEditor.isMerging(editor);
  54. MERGING.set(editor, false);
  55. fn();
  56. MERGING.set(editor, prev);
  57. },
  58. /**
  59. * Apply a series of changes inside a synchronous `fn`, without saving any of
  60. * their operations into the history.
  61. */
  62. withoutSaving(editor, fn) {
  63. var prev = HistoryEditor.isSaving(editor);
  64. SAVING.set(editor, false);
  65. fn();
  66. SAVING.set(editor, prev);
  67. }
  68. };
  69. /**
  70. * The `withHistory` plugin keeps track of the operation history of a Slate
  71. * editor as operations are applied to it, using undo and redo stacks.
  72. *
  73. * If you are using TypeScript, you must extend Slate's CustomTypes to use
  74. * this plugin.
  75. *
  76. * See https://docs.slatejs.org/concepts/11-typescript to learn how.
  77. */
  78. var withHistory = editor => {
  79. var e = editor;
  80. var {
  81. apply
  82. } = e;
  83. e.history = {
  84. undos: [],
  85. redos: []
  86. };
  87. e.redo = () => {
  88. var {
  89. history
  90. } = e;
  91. var {
  92. redos
  93. } = history;
  94. if (redos.length > 0) {
  95. var batch = redos[redos.length - 1];
  96. HistoryEditor.withoutSaving(e, () => {
  97. Editor.withoutNormalizing(e, () => {
  98. for (var op of batch) {
  99. e.apply(op);
  100. }
  101. });
  102. });
  103. history.redos.pop();
  104. history.undos.push(batch);
  105. }
  106. };
  107. e.undo = () => {
  108. var {
  109. history
  110. } = e;
  111. var {
  112. undos
  113. } = history;
  114. if (undos.length > 0) {
  115. var batch = undos[undos.length - 1];
  116. HistoryEditor.withoutSaving(e, () => {
  117. Editor.withoutNormalizing(e, () => {
  118. var inverseOps = batch.map(Operation.inverse).reverse();
  119. for (var op of inverseOps) {
  120. e.apply(op);
  121. }
  122. });
  123. });
  124. history.redos.push(batch);
  125. history.undos.pop();
  126. }
  127. };
  128. e.apply = op => {
  129. var {
  130. operations,
  131. history
  132. } = e;
  133. var {
  134. undos
  135. } = history;
  136. var lastBatch = undos[undos.length - 1];
  137. var lastOp = lastBatch && lastBatch[lastBatch.length - 1];
  138. var overwrite = shouldOverwrite(op, lastOp);
  139. var save = HistoryEditor.isSaving(e);
  140. var merge = HistoryEditor.isMerging(e);
  141. if (save == null) {
  142. save = shouldSave(op);
  143. }
  144. if (save) {
  145. if (merge == null) {
  146. if (lastBatch == null) {
  147. merge = false;
  148. } else if (operations.length !== 0) {
  149. merge = true;
  150. } else {
  151. merge = shouldMerge(op, lastOp) || overwrite;
  152. }
  153. }
  154. if (lastBatch && merge) {
  155. if (overwrite) {
  156. lastBatch.pop();
  157. }
  158. lastBatch.push(op);
  159. } else {
  160. var batch = [op];
  161. undos.push(batch);
  162. }
  163. while (undos.length > 100) {
  164. undos.shift();
  165. }
  166. if (shouldClear(op)) {
  167. history.redos = [];
  168. }
  169. }
  170. apply(op);
  171. };
  172. return e;
  173. };
  174. /**
  175. * Check whether to merge an operation into the previous operation.
  176. */
  177. var shouldMerge = (op, prev) => {
  178. if (op.type === 'set_selection') {
  179. return true;
  180. }
  181. if (prev && op.type === 'insert_text' && prev.type === 'insert_text' && op.offset === prev.offset + prev.text.length && Path.equals(op.path, prev.path)) {
  182. return true;
  183. }
  184. if (prev && op.type === 'remove_text' && prev.type === 'remove_text' && op.offset + op.text.length === prev.offset && Path.equals(op.path, prev.path)) {
  185. return true;
  186. }
  187. return false;
  188. };
  189. /**
  190. * Check whether an operation needs to be saved to the history.
  191. */
  192. var shouldSave = (op, prev) => {
  193. if (op.type === 'set_selection' && (op.properties == null || op.newProperties == null)) {
  194. return false;
  195. }
  196. return true;
  197. };
  198. /**
  199. * Check whether an operation should overwrite the previous one.
  200. */
  201. var shouldOverwrite = (op, prev) => {
  202. if (prev && op.type === 'set_selection' && prev.type === 'set_selection') {
  203. return true;
  204. }
  205. return false;
  206. };
  207. /**
  208. * Check whether an operation should clear the redos stack.
  209. */
  210. var shouldClear = op => {
  211. if (op.type === 'set_selection') {
  212. return false;
  213. }
  214. return true;
  215. };
  216. export { HISTORY, History, HistoryEditor, MERGING, SAVING, withHistory };
  217. //# sourceMappingURL=index.es.js.map