mxUndoableEdit.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /**
  2. * Copyright (c) 2006-2015, JGraph Ltd
  3. * Copyright (c) 2006-2015, Gaudenz Alder
  4. */
  5. /**
  6. * Class: mxUndoableEdit
  7. *
  8. * Implements a composite undoable edit. Here is an example for a custom change
  9. * which gets executed via the model:
  10. *
  11. * (code)
  12. * function CustomChange(model, name)
  13. * {
  14. * this.model = model;
  15. * this.name = name;
  16. * this.previous = name;
  17. * };
  18. *
  19. * CustomChange.prototype.execute = function()
  20. * {
  21. * var tmp = this.model.name;
  22. * this.model.name = this.previous;
  23. * this.previous = tmp;
  24. * };
  25. *
  26. * var name = prompt('Enter name');
  27. * graph.model.execute(new CustomChange(graph.model, name));
  28. * (end)
  29. *
  30. * Event: mxEvent.EXECUTED
  31. *
  32. * Fires between START_EDIT and END_EDIT after an atomic change was executed.
  33. * The <code>change</code> property contains the change that was executed.
  34. *
  35. * Event: mxEvent.START_EDIT
  36. *
  37. * Fires before a set of changes will be executed in <undo> or <redo>.
  38. * This event contains no properties.
  39. *
  40. * Event: mxEvent.END_EDIT
  41. *
  42. * Fires after a set of changeswas executed in <undo> or <redo>.
  43. * This event contains no properties.
  44. *
  45. * Constructor: mxUndoableEdit
  46. *
  47. * Constructs a new undoable edit for the given source.
  48. */
  49. function mxUndoableEdit(source, significant)
  50. {
  51. this.source = source;
  52. this.changes = [];
  53. this.significant = (significant != null) ? significant : true;
  54. };
  55. /**
  56. * Variable: source
  57. *
  58. * Specifies the source of the edit.
  59. */
  60. mxUndoableEdit.prototype.source = null;
  61. /**
  62. * Variable: changes
  63. *
  64. * Array that contains the changes that make up this edit. The changes are
  65. * expected to either have an undo and redo function, or an execute
  66. * function. Default is an empty array.
  67. */
  68. mxUndoableEdit.prototype.changes = null;
  69. /**
  70. * Variable: significant
  71. *
  72. * Specifies if the undoable change is significant.
  73. * Default is true.
  74. */
  75. mxUndoableEdit.prototype.significant = null;
  76. /**
  77. * Variable: undone
  78. *
  79. * Specifies if this edit has been undone. Default is false.
  80. */
  81. mxUndoableEdit.prototype.undone = false;
  82. /**
  83. * Variable: redone
  84. *
  85. * Specifies if this edit has been redone. Default is false.
  86. */
  87. mxUndoableEdit.prototype.redone = false;
  88. /**
  89. * Function: isEmpty
  90. *
  91. * Returns true if the this edit contains no changes.
  92. */
  93. mxUndoableEdit.prototype.isEmpty = function()
  94. {
  95. return this.changes.length == 0;
  96. };
  97. /**
  98. * Function: isSignificant
  99. *
  100. * Returns <significant>.
  101. */
  102. mxUndoableEdit.prototype.isSignificant = function()
  103. {
  104. return this.significant;
  105. };
  106. /**
  107. * Function: add
  108. *
  109. * Adds the specified change to this edit. The change is an object that is
  110. * expected to either have an undo and redo, or an execute function.
  111. */
  112. mxUndoableEdit.prototype.add = function(change)
  113. {
  114. this.changes.push(change);
  115. };
  116. /**
  117. * Function: notify
  118. *
  119. * Hook to notify any listeners of the changes after an <undo> or <redo>
  120. * has been carried out. This implementation is empty.
  121. */
  122. mxUndoableEdit.prototype.notify = function() { };
  123. /**
  124. * Function: die
  125. *
  126. * Hook to free resources after the edit has been removed from the command
  127. * history. This implementation is empty.
  128. */
  129. mxUndoableEdit.prototype.die = function() { };
  130. /**
  131. * Function: undo
  132. *
  133. * Undoes all changes in this edit.
  134. */
  135. mxUndoableEdit.prototype.undo = function()
  136. {
  137. if (!this.undone)
  138. {
  139. this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
  140. var count = this.changes.length;
  141. for (var i = count - 1; i >= 0; i--)
  142. {
  143. var change = this.changes[i];
  144. if (change.execute != null)
  145. {
  146. change.execute();
  147. }
  148. else if (change.undo != null)
  149. {
  150. change.undo();
  151. }
  152. // New global executed event
  153. this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
  154. }
  155. this.undone = true;
  156. this.redone = false;
  157. this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
  158. }
  159. this.notify();
  160. };
  161. /**
  162. * Function: redo
  163. *
  164. * Redoes all changes in this edit.
  165. */
  166. mxUndoableEdit.prototype.redo = function()
  167. {
  168. if (!this.redone)
  169. {
  170. this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
  171. var count = this.changes.length;
  172. for (var i = 0; i < count; i++)
  173. {
  174. var change = this.changes[i];
  175. if (change.execute != null)
  176. {
  177. change.execute();
  178. }
  179. else if (change.redo != null)
  180. {
  181. change.redo();
  182. }
  183. // New global executed event
  184. this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
  185. }
  186. this.undone = false;
  187. this.redone = true;
  188. this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
  189. }
  190. this.notify();
  191. };