JSFiddle - React, Tailwind, and code Playground

by Daniel Herzog Cruz

HTML

<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<!-- Current stack -->
<div id="stack">
</div>

<!-- Number buttons -->
<div class="numbers">
  <button id="btn-0">0</button>
  <button id="btn-1">1</button>
  <button id="btn-2">2</button>
  <button id="btn-3">3</button>
  <button id="btn-4">4</button>
  <button id="btn-5">5</button>
  <button id="btn-6">6</button>
  <button id="btn-7">7</button>
  <button id="btn-8">8</button>
  <button id="btn-9">9</button>
</div>

<!-- Operator buttons -->
<div class="operators">
  <button id="btn-add">+</button>
  <button id="btn-substract">-</button>
  <button id="btn-multiply">*</button>
  <button id="btn-divide">/</button>
</div>

<!-- Other -->
<div class="other">
  <button id="btn-clear">CL</button>
  <button id="btn-undo">Undo</button>
  <button id="btn-redo">Redo</button>
</div>

CSS

#stack {
  display: block;
  height: 80px;
  width: 265px;
  margin-bottom: 20px;
  border: 1px solid black;
  padding-bottom: 20px;
  
  overflow-y: scroll;
  overflow-x: hidden;
}

#stack span {
  display: block;
}

.numbers,
.operators,
.other {
  display: block;
  margin-bottom: 10px;
}

JavaScript

// Create a global manager with an auto-executable anonymous function.
var Commander = (function(scope) {
  'use strict';

  // Manager object instance.
  var obj = {};

  // -- Private --

  // Command list.
  var _commands = {};
  // Commands list for undo/redo.
  var _list = [];
  // Current command index on `list`.
  var _current = 0;

  var _currentCommand = function() {
    var name = _list[_current];
    return _commands[name];
  };

  // -- Public --

  // Add a new command to the list (name shortcut). `name` must be a string, and `command`
  // must be an object which responds to `execute` and `undo`.
  obj.addCommand = function(name, command) {
    _commands[name] = command;
  };

  // Execute a command by its name.
  obj.execute = function(name) {
    var cmd = _commands[name];

    // Remove the actions after `current` command in the stack. Of course,
    // if we undo 3 times, we can redo 3 times. However, if we undo 3 times,
    // and execute a new action, we can no longer those 3 old commands.
    // This action will not affect the list if the `current` points to the last element.
    _list = _list.slice(0, _current);

    // Execute the command, add it to the top of the stack and increment the current index.
    cmd.execute();
    _list.push(name);
    _current += 1;
  };

  // Check if the the next command can be `undone`
  obj.canUndo = function() {
    return _current > 0;
  };

  // Check if the next command can be `redone`.
  obj.canRedo = function() {
    return _current < _list.length;
  };

  // Undo the previous command executed.
  obj.undo = function() {
    // Stop if there are no elements on the list.
    if (!obj.canUndo()) return false;

    // Move back, and undo the previous command.
    _current -= 1;
    _currentCommand().undo();
    return true;
  };

  // Redo the next command.
  obj.redo = function() {
    // Stop if there are no elements on the list.
    if (!obj.canRedo()) return false;

    // Move forward, and execute the...