UNPKG

jstps

Version:

A Transaction Processing System to be used for implementing Undo/Redo in a JavaScript applicaiton.

226 lines (207 loc) 8.15 kB
/** * A jsTPS_Transaction represents a single atomic transaction to be managed * by the jsTPS class in a transaction stack. Each transaction can be done * and the undone, which should restore the state of the application employing * this framework. * * @author TheMcKillaGorilla * @version 2.0.4 */ export class jsTPS_Transaction { /** * This method is called by jsTPS when a transaction is executed. */ executeDo() { console.log("executeDo - MISSING IMPLEMENTATION"); } /** * This method is called by jsTPS when a transaction is undone. */ executeUndo() { console.log("executeUndo - MISSING IMPLEMENTATION"); } } /** * Thrown when one tries to undo, or redo a transaction when * none is available for such an operation. */ export const TRANSACTION_STACK_EXCEPTION = "TRANSACTION_STACK_EXCEPTION"; /** * jsTPS serves as a transaction processing system employing a transaction * stack such that one can use this framework to implement undo/redo in * an application. * * @author TheMcKillaGorilla * @version 2.0 */ export class jsTPS { /** * A Transaction Processing System to be used for implementing * undo/redo in a JavaScript application. Note that the transaction * stack will start out empty, with no transactions to do or undo. * @constructor */ constructor() { // THE TRANSACTION STACK, MEANING TRANSACTIONS THAT HAVE BEEN // EXECUTED THAT WE CAN UNDO AND THEN REDO this.transactions = []; // THE TOTAL NUMBER OF VALID TRANSACTIONS IN THE STACK, INCLUDING THOSE // THAT WE MIGHT REDO, BUT NOT INCLUDING TRANSACTIONS THAT ARE LOST WHEN // BRANCHING OCCURS, MEANING WHEN WE HAVE UNDONE TRANSACTIONS AND THEN // ADD A NEW ONE, WHICH ELIMINATES THOSE ABOVE IT IN THE STACK. NOTE THAT // THIS NUMBER ONLY CHANGES WHEN WE ADD A TRANSACTION. this.size = 0; // THE INDEX WHERE A NEW TRANSACTION WOULD BE ADDED ONTO THE STACK // SHOULD processTransaction BE CALLED, WHICH ADDES AND EXECUTES A // TRANSACTION. NOTE THAT FOLLOWING COMBINATIONS OF UNDO AND REDO // THIS INDEX WILL BE ONE MORE THAN THE INDEX OF THE MOST RECENTLY // DONE TRANSACTION. this.topIndex = 0; } /** * Completely resets the transaction stack, assigning it a new, empty array and * resetting the top index and size to reflect an empty stack. */ clearAllTransactions() { // REMOVE ALL THE TRANSACTIONS this.transactions = []; // RESET THE OTHER VARIABLES TOO this.topIndex = 0; this.size = 0; } /** * Executes the transaction in the stack where our index is and advances the index such * that it could then be undone if necessary. Note, this does not change what * transactions are on the stack, just the index counter that keeps track of * what has been done and undone. * * @throws {TRANSACTION_STACK_EXCEPTION} thrown if there is no transaction on the * stack to do. */ doTransaction() { if (this.hasTransactionToDo()) { let transaction = this.transactions[this.topIndex]; transaction.executeDo(); this.topIndex++; } else { throw TRANSACTION_STACK_EXCEPTION; } } /** * Accessor method for the number of transactions that can currently be done. * * @returns {Number} The number of transactions in the stack that can be done. */ getDoSize() { return this.getSize() - this.getUndoSize(); } /** * Accessor method for the total number of transactions in the current stack which * includes those that can be done and undone. * * @returns {Number} The number of transactions in total in the stack. */ getSize() { return this.size; } /** * Accessor method for the number of transactions that can currently be undone. * * @returns {Number} The number of transactions in the stack that can be undone. */ getUndoSize() { return this.topIndex; } /** * Used to check if there is an doable transaction in the stack or not, like * to redo a transaction, which might be useful for an application for enabling * a redo button. * * @returns true if there is a transaction in the stack that can be done, * false othewise. */ hasTransactionToDo() { return (this.getDoSize() > 0); } /** * Used to check if there is an undoable transaction in the stack or not, like * to undo a transaction, which might be useful for an application for enabling * an undo button. * * @returns true if there is a transaction in the stack that can be undone, * false otherwise. */ hasTransactionToUndo() { return (this.getUndoSize() > 0); } /** * Gets a transaction in the stack at a provided index without executing the transaction * or changing the stack. * * @param {Number} index = The index of the transaction in the stack to get, which can * be used to get any transaction, even those that have been undone if they are still * in the stack. * * @returns {jsTPS_Transaction} The transaction to retrieve at index in the stack, if * an invalid index is provided, null is returned. */ peekTransaction(index) { if ((index >= 0) && (index < this.getSize())) { return this.transactions[index]; } return null; } /** * This function takes the transaction argument and both pushes it to the top of the * transaction stack and executes it. After this method executes one can undo it, but * there should be no transaction to redo as this one will have been executed. * @param {jsTPS_Transaction} transaction - The transaction to add to the stack and execute. */ processTransaction(transaction) { // FIRST ADD THE TRANSACTION TO THE STACK this.transactions[this.topIndex] = transaction; // NOW WE NEED TO UPDATE THE SIZE OF THE STACK, WHICH AFTER A TRANSACTION // IS PUSHED ONTO THE TOP, WILL ALWAYS BE TWO MORE THAN topIndex, SINCE // THE TRANSACTION HAS NOT YET BEEN EXECUTED. this.size = this.topIndex + 1; // AND THEN EXECUTE IT, WHICH WILL ALSO MOVE THE TOP INDEX this.doTransaction(); } /** * Builds and returns a textual representation of the transaction processing * system, which summarizes the contents of the transaction stack. * * @returns {String} A textual representation of the transaction stack. */ toString() { let text = "--Number of Transactions: " + this.size + "\n"; text += "--Top Index: " + this.topIndex + "\n"; text += "--Current Transaction Stack:\n"; for (let i = 0; i <= this.topIndex; i++) { let jT = this.transactions[i]; text += "----" + jT.toString() + "\n"; } return text; } /** * Undoes the transaction at the top of the stack and decrements the index such * that it could then be redone if necessary. Note, this does not change what * transactions are on the stack, just the index counter that keeps track of * the top of the stack, and thus which transactions would be executed for do * and undo operations. * * @throws {TRANSACTION_STACK_EXCEPTION} thrown if there is no transaction on the * stack to undo. */ undoTransaction() { if (this.hasTransactionToUndo()) { let transaction = this.transactions[this.topIndex - 1]; transaction.executeUndo(); this.topIndex--; } else { throw TRANSACTION_STACK_EXCEPTION; } } }