]> git.za3k.com Git - flowy.git/commitdiff
Add undo/redo system in code
authorZachary Vance <vanceza@gmail.com>
Thu, 4 Jun 2015 00:25:21 +0000 (17:25 -0700)
committerZachary Vance <vanceza@gmail.com>
Thu, 4 Jun 2015 00:25:21 +0000 (17:25 -0700)
dist/flowy.js
dist/flowy.unwrapped.js
src/actions.js [new file with mode: 0644]
src/flowy.js
src/views/app.js
src/views/todo.js

index 32af476635a5698a9d678e763708b8e1f7185734..cd291a4081d8c2f21458b24777bb91c1cf1c4a96 100644 (file)
@@ -408,6 +408,7 @@ var TodoView = Backbone.View.extend({
     "input > .text": "textChange",
     "blur > .text": "render", // Because the model shouldn't update the view during active editing, add a re-render at the end
     "keydown > .text": "keydown",
+    // "Shortcut(ID, TEXT, DEFAULT KEYBINDING) SELECTOR": "ACTION"
     'Shortcut("combinePrevious", "Combine an item with the previous item", "backspace") > .text': "combinePrevious",
     'Shortcut("combineNext", "Combine an item with the next item", "del") > .text': "combineNext",
     'Shortcut("next", "Next", "down") > .text': 'focusNext',
@@ -1050,12 +1051,38 @@ var testTodos = [
 ];
 
 
+BaseAction = function() {};
+BaseAction.prototype= {
+    apply: function() {},
+    rewind: function() {},
+    reapply: function() { return this.apply.apply(this, arguments); },
+};
+
+Actions = {};
+
+Actions.AppendWords = function(array, word) {
+    this.array = array;
+    this.word = word;
+};
+Actions.AppendWords.prototype = _.extend(new BaseAction(), {
+    apply: function() {
+        this.array.push(this.word);
+    },
+    rewind: function() {
+        var a = this.array.pop();
+        if (a !== this.word) {
+            throw "Rewind faiiiiiled :(";
+        }
+    },
+});
+
 /**
  * @depend ../views/todo.js
  * @depend ../models/flowyDoc.js
  * @depend ../models/todo.js
  * @depend ../library/viewShortcuts.js
  * @depend ../views/testTodos.js
+ * @depend ../actions.js
  */
 
 var todos = new FlowyDocModel({
@@ -1091,6 +1118,8 @@ var AppView = Backbone.View.extend({
         });
         Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right'] });
         this.views = {}; // A list of views for each element in the collection
+        this.history = [];
+        this.history.redo = [];
         this.list.fetch();
         this.render();
     },
@@ -1110,6 +1139,23 @@ var AppView = Backbone.View.extend({
            this.renderTodo(todo, { rerender: true }); // Don't remove existing view since it's still valid.
         }
     },
+    act: function(action) {
+        action.apply();
+        this.history.push(action);
+        this.history.redo = [];
+    },
+    undo: function() {
+        var action = this.history.pop();
+        if (!action) throw "Rewind called with empty history stack";
+        action.rewind();
+        this.history.redo.push(action);
+    },
+    redo: function() {
+        var action = this.history.redo.pop();
+        if (!action) throw "Replay called with empty redo stack";
+        action.reapply();
+        this.history.push(action);
+    },
     toggleShortcuts: function() {
         this.$(".shortcuts").toggle();
         return false;
@@ -1164,17 +1210,19 @@ var AppView = Backbone.View.extend({
     },
 });
 
-// DEBUGGING
-window.Backbone = Backbone;
-window.Shortcut = Shortcut;
-window.AppView = AppView;
-
 /**
  * @depend views/app.js
  */
 
 $(function() {
     var flowyView = new AppView();
+    window.Flowy = flowyView;
+
+    // DEBUGGING
+    window.Backbone = Backbone;
+    window.Shortcut = Shortcut;
+    window.Actions = Actions;
 });
 
+
 });
index 7e9d91332c55fcc28c65ab1dae6bc319b67e3f04..a5f4ddb3261959df99e961fa2f4eaa8d07e9aece 100644 (file)
@@ -407,6 +407,7 @@ var TodoView = Backbone.View.extend({
     "input > .text": "textChange",
     "blur > .text": "render", // Because the model shouldn't update the view during active editing, add a re-render at the end
     "keydown > .text": "keydown",
+    // "Shortcut(ID, TEXT, DEFAULT KEYBINDING) SELECTOR": "ACTION"
     'Shortcut("combinePrevious", "Combine an item with the previous item", "backspace") > .text': "combinePrevious",
     'Shortcut("combineNext", "Combine an item with the next item", "del") > .text': "combineNext",
     'Shortcut("next", "Next", "down") > .text': 'focusNext',
@@ -1049,12 +1050,38 @@ var testTodos = [
 ];
 
 
+BaseAction = function() {};
+BaseAction.prototype= {
+    apply: function() {},
+    rewind: function() {},
+    reapply: function() { return this.apply.apply(this, arguments); },
+};
+
+Actions = {};
+
+Actions.AppendWords = function(array, word) {
+    this.array = array;
+    this.word = word;
+};
+Actions.AppendWords.prototype = _.extend(new BaseAction(), {
+    apply: function() {
+        this.array.push(this.word);
+    },
+    rewind: function() {
+        var a = this.array.pop();
+        if (a !== this.word) {
+            throw "Rewind faiiiiiled :(";
+        }
+    },
+});
+
 /**
  * @depend ../views/todo.js
  * @depend ../models/flowyDoc.js
  * @depend ../models/todo.js
  * @depend ../library/viewShortcuts.js
  * @depend ../views/testTodos.js
+ * @depend ../actions.js
  */
 
 var todos = new FlowyDocModel({
@@ -1090,6 +1117,8 @@ var AppView = Backbone.View.extend({
         });
         Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right'] });
         this.views = {}; // A list of views for each element in the collection
+        this.history = [];
+        this.history.redo = [];
         this.list.fetch();
         this.render();
     },
@@ -1109,6 +1138,23 @@ var AppView = Backbone.View.extend({
            this.renderTodo(todo, { rerender: true }); // Don't remove existing view since it's still valid.
         }
     },
+    act: function(action) {
+        action.apply();
+        this.history.push(action);
+        this.history.redo = [];
+    },
+    undo: function() {
+        var action = this.history.pop();
+        if (!action) throw "Rewind called with empty history stack";
+        action.rewind();
+        this.history.redo.push(action);
+    },
+    redo: function() {
+        var action = this.history.redo.pop();
+        if (!action) throw "Replay called with empty redo stack";
+        action.reapply();
+        this.history.push(action);
+    },
     toggleShortcuts: function() {
         this.$(".shortcuts").toggle();
         return false;
@@ -1163,15 +1209,17 @@ var AppView = Backbone.View.extend({
     },
 });
 
-// DEBUGGING
-window.Backbone = Backbone;
-window.Shortcut = Shortcut;
-window.AppView = AppView;
-
 /**
  * @depend views/app.js
  */
 
 $(function() {
     var flowyView = new AppView();
+    window.Flowy = flowyView;
+
+    // DEBUGGING
+    window.Backbone = Backbone;
+    window.Shortcut = Shortcut;
+    window.Actions = Actions;
 });
+
diff --git a/src/actions.js b/src/actions.js
new file mode 100644 (file)
index 0000000..15543bf
--- /dev/null
@@ -0,0 +1,24 @@
+BaseAction = function() {};
+BaseAction.prototype= {
+    apply: function() {},
+    rewind: function() {},
+    reapply: function() { return this.apply.apply(this, arguments); },
+};
+
+Actions = {};
+
+Actions.AppendWords = function(array, word) {
+    this.array = array;
+    this.word = word;
+};
+Actions.AppendWords.prototype = _.extend(new BaseAction(), {
+    apply: function() {
+        this.array.push(this.word);
+    },
+    rewind: function() {
+        var a = this.array.pop();
+        if (a !== this.word) {
+            throw "Rewind faiiiiiled :(";
+        }
+    },
+});
index 8aacf1192df94b73ca8ecfb729272e0e6ec771f7..ecba84a076adf27ecfc2ba4973fc306f9bcff965 100644 (file)
@@ -4,4 +4,11 @@
 
 $(function() {
     var flowyView = new AppView();
+    window.Flowy = flowyView;
+
+    // DEBUGGING
+    window.Backbone = Backbone;
+    window.Shortcut = Shortcut;
+    window.Actions = Actions;
 });
+
index ebbd4a2a9e7cbf09d5817bd58c7d0d07e794e6e0..e6a2c0759b4de9ada81f8828a8b316b18948fdca 100644 (file)
@@ -4,6 +4,7 @@
  * @depend ../models/todo.js
  * @depend ../library/viewShortcuts.js
  * @depend ../views/testTodos.js
+ * @depend ../actions.js
  */
 
 var todos = new FlowyDocModel({
@@ -39,6 +40,8 @@ var AppView = Backbone.View.extend({
         });
         Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right'] });
         this.views = {}; // A list of views for each element in the collection
+        this.history = [];
+        this.history.redo = [];
         this.list.fetch();
         this.render();
     },
@@ -58,6 +61,23 @@ var AppView = Backbone.View.extend({
            this.renderTodo(todo, { rerender: true }); // Don't remove existing view since it's still valid.
         }
     },
+    act: function(action) {
+        action.apply();
+        this.history.push(action);
+        this.history.redo = [];
+    },
+    undo: function() {
+        var action = this.history.pop();
+        if (!action) throw "Rewind called with empty history stack";
+        action.rewind();
+        this.history.redo.push(action);
+    },
+    redo: function() {
+        var action = this.history.redo.pop();
+        if (!action) throw "Replay called with empty redo stack";
+        action.reapply();
+        this.history.push(action);
+    },
     toggleShortcuts: function() {
         this.$(".shortcuts").toggle();
         return false;
@@ -111,8 +131,3 @@ var AppView = Backbone.View.extend({
         this.list.each(this.addOne, this);
     },
 });
-
-// DEBUGGING
-window.Backbone = Backbone;
-window.Shortcut = Shortcut;
-window.AppView = AppView;
index f0806d5cf5ac318d2c50d6fbdc570bb7b6ba1f7d..25619e19d8bb064af2336ce98a8094f1b36696a1 100644 (file)
@@ -11,6 +11,7 @@ var TodoView = Backbone.View.extend({
     "input > .text": "textChange",
     "blur > .text": "render", // Because the model shouldn't update the view during active editing, add a re-render at the end
     "keydown > .text": "keydown",
+    // "Shortcut(ID, TEXT, DEFAULT KEYBINDING) SELECTOR": "ACTION"
     'Shortcut("combinePrevious", "Combine an item with the previous item", "backspace") > .text': "combinePrevious",
     'Shortcut("combineNext", "Combine an item with the next item", "del") > .text': "combineNext",
     'Shortcut("next", "Next", "down") > .text': 'focusNext',