Undo

Objective
  • Undo
  1. function Undo(size = 100) {
  2.     if (! Number.isInteger(size))
  3.         throw new TypeError();
  4.  
  5.     if (size < 1)
  6.         throw new RangeError();
  7.  
  8.     this._size = size;
  9.  
  10.     this._undo = [];
  11.     this._redo = null;
  12. }
  13.  
  14. Object.defineProperty(Undo.prototype, 'size', {
  15.     get:    function() {
  16.                 return this._size;
  17.             },
  18.     set:    function(n) {
  19.                 if (! Number.isInteger(n))
  20.                     throw new TypeError();
  21.  
  22.                 if (n < 1)
  23.                     throw new RangeError();
  24.  
  25.                 if (this._size > n)
  26.                     this._undo = this._undo.slice(-n);
  27.  
  28.                 this._redo = null;
  29.  
  30.                 this._size = n;
  31.             }
  32. });
  33.  
  34. Object.defineProperty(Undo.prototype, 'undoLength', {
  35.     get:    function() {
  36.                 return this._undo.length;
  37.             }
  38. });
  39.  
  40. Object.defineProperty(Undo.prototype, 'redoLength', {
  41.     get:    function() {
  42.                 return this._redo === null ? 0 : this._redo.length;
  43.             }
  44. });
  45.  
  46. Undo.prototype.push = function(f, ...args) {
  47.     if (this._undo.length >= this._size)
  48.         this._undo.shift();
  49.  
  50.     this._undo.push(args.length ? [f, args] : f);
  51.  
  52.     this._redo = null;
  53.  
  54.     return this;
  55. }
  56.  
  57. Undo.prototype.pop = function() {
  58.     this._undo.pop();
  59.  
  60.     this._redo = null;
  61.  
  62.     return this;
  63. }
  64.  
  65. Undo.prototype.undo = function() {
  66.     let exp = this._undo.pop();
  67.  
  68.     if (exp === undefined)
  69.         return false;
  70.  
  71.     let redo = this._redo;
  72.  
  73.     if (Array.isArray(exp))
  74.         exp[0](...exp[1]);
  75.     else
  76.         exp();
  77.  
  78.     exp = this._undo.pop();
  79.  
  80.     if (exp === undefined)
  81.         return true;
  82.  
  83.     this._redo = redo;
  84.  
  85.     if (this._redo === null)
  86.         this._redo = [];
  87.     else if (this._redo.length >= this._size)
  88.         this._redo.shift();
  89.  
  90.     this._redo.push(exp);
  91.  
  92.     return true;
  93. }
  94.  
  95. Undo.prototype.redo = function() {
  96.     if (! this._redo)
  97.         return false;
  98.  
  99.     let exp = this._redo.pop();
  100.  
  101.     if (exp === undefined)
  102.         return false;
  103.  
  104.     let redo = this._redo;
  105.  
  106.     if (Array.isArray(exp))
  107.         exp[0](...exp[1]);
  108.     else
  109.         exp();
  110.  
  111.     this._redo = redo;
  112.  
  113.     return true;
  114. }
  115.  
  116. Undo.prototype.clear = function() {
  117.     this._undo = [];
  118.     this._redo = null;
  119.  
  120.     return this;
  121. }
Test
  1. <?php head('javascript', '/objectivejs/Objective.js'); ?>
  2. <?php head('javascript', '/objectivejs/Undo.js'); ?>
  1. <?php head('javascript', '/objectivejs/tests/Calculator.js'); ?>
  1. var undo = new Undo();
  2.  
  3. console.log(undo.size);         // 100
  4.  
  5. undo.size = 20;
  6.  
  7. console.log(undo.size);         // 20
  8.  
  9. console.log(undo.undoLength);   // 0
  10.  
  11. var calc = new Calculator();
  12.  
  13. function fmul(val) {
  14.     undo.push(() => fdiv(val));
  15.     calc.mul(val);
  16. }
  17.  
  18. function fdiv(val) {
  19.     undo.push((v) => fmul(v), val); // context
  20.     calc.div(val);
  21. }
  22.  
  23. calc.value = 3;
  24.  
  25. fmul(calc.value);
  26. fmul(4);
  27.  
  28. console.log(calc.value);        // 36
  29.  
  30. console.log(undo.undoLength);   // 2
  31.  
  32. undo.undo();
  33. undo.undo();
  34.  
  35. console.log(calc.value);        // 3
  36.  
  37. console.log(undo.undoLength);   // 0
  38. console.log(undo.redoLength);   // 2
  39.  
  40. undo.undo();    // one too many
  41.  
  42. undo.redo();
  43. undo.redo();
  44.  
  45. console.log(calc.value);        // 36
  46.  
  47. console.log(undo.undoLength);   // 2
  48. console.log(undo.redoLength);   // 0
  49.  
  50. undo.redo();    // one too many
  51.  
  52. undo.undo();
  53. undo.undo();
  54.  
  55. console.log(calc.value);        // 3

Display the page generated by the file testUndo.phtml and check the trace in the console of the browser:

100
20
0
36
2
3
0
2
36
2
0
3
SEE ALSO

Model, Editor

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].