undomanager.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. Simple Javascript undo and redo.
  3. https://github.com/ArthurClemens/Javascript-Undo-Manager
  4. */
  5. ;(function() {
  6. 'use strict';
  7. function removeFromTo(array, from, to) {
  8. array.splice(from,
  9. !to ||
  10. 1 + to - from + (!(to < 0 ^ from >= 0) && (to < 0 || -1) * array.length));
  11. return array.length;
  12. }
  13. var UndoManager = function() {
  14. var commands = [],
  15. index = -1,
  16. limit = 0,
  17. isExecuting = false,
  18. callback,
  19. // functions
  20. execute;
  21. execute = function(command, action) {
  22. if (!command || typeof command[action] !== "function") {
  23. return this;
  24. }
  25. isExecuting = true;
  26. command[action]();
  27. isExecuting = false;
  28. return this;
  29. };
  30. return {
  31. /*
  32. Add a command to the queue.
  33. */
  34. add: function (command) {
  35. if (isExecuting) {
  36. return this;
  37. }
  38. // if we are here after having called undo,
  39. // invalidate items higher on the stack
  40. commands.splice(index + 1, commands.length - index);
  41. commands.push(command);
  42. // if limit is set, remove items from the start
  43. if (limit && commands.length > limit) {
  44. removeFromTo(commands, 0, -(limit+1));
  45. }
  46. // set the current index to the end
  47. index = commands.length - 1;
  48. if (callback) {
  49. callback();
  50. }
  51. return this;
  52. },
  53. /*
  54. Pass a function to be called on undo and redo actions.
  55. */
  56. setCallback: function (callbackFunc) {
  57. callback = callbackFunc;
  58. },
  59. /*
  60. Perform undo: call the undo function at the current index and decrease the index by 1.
  61. */
  62. undo: function () {
  63. var command = commands[index];
  64. if (!command) {
  65. return this;
  66. }
  67. execute(command, "undo");
  68. index -= 1;
  69. if (callback) {
  70. callback();
  71. }
  72. return this;
  73. },
  74. /*
  75. Perform redo: call the redo function at the next index and increase the index by 1.
  76. */
  77. redo: function () {
  78. var command = commands[index + 1];
  79. if (!command) {
  80. return this;
  81. }
  82. execute(command, "redo");
  83. index += 1;
  84. if (callback) {
  85. callback();
  86. }
  87. return this;
  88. },
  89. /*
  90. Clears the memory, losing all stored states. Reset the index.
  91. */
  92. clear: function () {
  93. var prev_size = commands.length;
  94. commands = [];
  95. index = -1;
  96. if (callback && (prev_size > 0)) {
  97. callback();
  98. }
  99. },
  100. hasUndo: function () {
  101. return index !== -1;
  102. },
  103. hasRedo: function () {
  104. return index < (commands.length - 1);
  105. },
  106. getCommands: function () {
  107. return commands;
  108. },
  109. getIndex: function() {
  110. return index;
  111. },
  112. setLimit: function (l) {
  113. limit = l;
  114. }
  115. };
  116. };
  117. if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
  118. // AMD. Register as an anonymous module.
  119. define(function() {
  120. return UndoManager;
  121. });
  122. } else if (typeof module !== 'undefined' && module.exports) {
  123. module.exports = UndoManager;
  124. } else {
  125. window.UndoManager = UndoManager;
  126. }
  127. }());