]> git.za3k.com Git - flowy.git/commitdiff
Undo/redo typing and moving
authorZachary Vance <vanceza@gmail.com>
Thu, 4 Jun 2015 01:12:41 +0000 (18:12 -0700)
committerZachary Vance <vanceza@gmail.com>
Thu, 4 Jun 2015 01:12:41 +0000 (18:12 -0700)
dist/flowy.js
dist/flowy.unwrapped.js
src/actions.js
src/library/viewShortcuts.js
src/models/todo.js
src/views/app.js

index cd291a4081d8c2f21458b24777bb91c1cf1c4a96..aa43858a8158f9002c1ac5dcfde1381e9aa2e0a1 100644 (file)
@@ -362,6 +362,7 @@ var Shortcut = (function(document, _) {
         var el = this.el;
         if (objectType === "global") {
             Shortcut.globalObject = el;
+            Shortcut.globalObject.options = { view: this };
             this._shortcutObject = Shortcut.globalObject;
         } else {
             this._shortcutObject = Shortcut.addObject(el, objectType, { view: this });
@@ -719,8 +720,11 @@ var TodoModel = Backbone.Model.extend({
     toggleCollapsed: function() {
         this.save({collapsed: !this.get("collapsed")});
     },
+    _setText: function(text) {
+        return this.save({text: text});
+    },
     setText: function(text) {
-        this.save({text: text});
+        return Actions.App.act(new Actions.ChangeText(this, text));
     },
     hasChildren: function() {
         return this.get("bullets").length > 0;
@@ -809,16 +813,23 @@ var TodoModel = Backbone.Model.extend({
         this.set("bullets", bullets);
         return this;
     },
+    getLocation: function() {
+        return {
+            parent: this.getParent(),
+            index: this.getParent().findChild(this.id),
+        };
+    },
     moveTo: function(newLocation) {
         if (this.isRoot()) {
             console.log("Cannot move root");
             return this;
         }
-        var existingLocation = {
-            parent: this.getParent(),
-            index: this.getParent().findChild(this.id),
-        };
+        var existingLocation = this.getLocation();
         newLocation = _.defaults({}, newLocation, existingLocation);
+        return Actions.App.act(new Actions.MoveBullet(this, newLocation));
+    },
+    _moveTo: function(newLocation) {
+        var existingLocation = this.getLocation();
         var newChildren;
         if (newLocation.parent === existingLocation.parent && newLocation.index === existingLocation.index) {
             // No-op
@@ -1060,19 +1071,31 @@ BaseAction.prototype= {
 
 Actions = {};
 
-Actions.AppendWords = function(array, word) {
-    this.array = array;
-    this.word = word;
+Actions.MoveBullet = function(bullet, newLocation) {
+    this.bullet = bullet;
+    this.oldLocation = bullet.getLocation();
+    this.newLocation = newLocation;
 };
-Actions.AppendWords.prototype = _.extend(new BaseAction(), {
+Actions.MoveBullet.prototype = _.extend(new BaseAction(), {
     apply: function() {
-        this.array.push(this.word);
+        return this.bullet._moveTo(this.newLocation);
     },
     rewind: function() {
-        var a = this.array.pop();
-        if (a !== this.word) {
-            throw "Rewind faiiiiiled :(";
-        }
+        return this.bullet._moveTo(this.oldLocation);
+    },
+});
+
+Actions.ChangeText = function(bullet, newText) {
+    this.bullet = bullet;
+    this.oldText = bullet.get("text");
+    this.newText = newText;
+};
+Actions.ChangeText.prototype = _.extend(new BaseAction(), {
+    apply: function() {
+        return this.bullet._setText(this.newText);
+    },
+    rewind: function() {
+        return this.bullet._setText(this.oldText);
     },
 });
 
@@ -1094,9 +1117,11 @@ var AppView = Backbone.View.extend({
     el: $("#todo-app"),
     shortcutObject: "global",
     events: {
-        'Shortcut("toggleShortcuts", "Keyboard Shortcuts", "ctrl+shift+/") > .text': 'toggleShortcuts',
-        'Shortcut("toggleShowCompleted", "Show/hide completed", "ctrl+o") > .text': 'toggleShowCompleted',
-        'Shortcut("search", "Not Done - Search", "esc") > .text': 'search',
+        'Shortcut("toggleShortcuts", "Keyboard Shortcuts", "ctrl+shift+/") body': 'toggleShortcuts',
+        'Shortcut("toggleShowCompleted", "Show/hide completed", "ctrl+o") body': 'toggleShowCompleted',
+        'Shortcut("search", "Not Done - Search", "esc") body': 'search',
+        'Shortcut("undo", "Undo", "ctrl+z") body': 'undo',
+        'Shortcut("redo", "Redo", "ctrl+shift+z,ctrl+y") body': 'redo',
     },
     initialize: function(options) {
         options = _.defaults({}, options, appDefaults);
@@ -1116,10 +1141,10 @@ var AppView = Backbone.View.extend({
                 e.save();
             });
         });
-        Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right'] });
+        Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right', 'undo', 'redo'] });
         this.views = {}; // A list of views for each element in the collection
-        this.history = [];
-        this.history.redo = [];
+        Actions.App = this;
+        this.undoRedoHistory = {undo: [], redo:[]}; // Linear zipper
         this.list.fetch();
         this.render();
     },
@@ -1140,21 +1165,29 @@ var AppView = Backbone.View.extend({
         }
     },
     act: function(action) {
-        action.apply();
-        this.history.push(action);
-        this.history.redo = [];
+        var retVal = action.apply();
+        this.undoRedoHistory.undo.push(action);
+        this.undoRedoHistory.redo = [];
+        return retVal;
     },
     undo: function() {
-        var action = this.history.pop();
-        if (!action) throw "Rewind called with empty history stack";
-        action.rewind();
-        this.history.redo.push(action);
+        var action = this.undoRedoHistory.undo.pop();
+        if (!action) {
+            console.log("Rewind called with empty history stack");
+            return;
+        }
+        var retVal = action.rewind();
+        this.undoRedoHistory.redo.push(action);
+        return retVal;
     },
     redo: function() {
-        var action = this.history.redo.pop();
-        if (!action) throw "Replay called with empty redo stack";
+        var action = this.undoRedoHistory.redo.pop();
+        if (!action) {
+            console.log("Replay called with empty redo stack");
+            return;
+        }
         action.reapply();
-        this.history.push(action);
+        this.undoRedoHistory.undo.push(action);
     },
     toggleShortcuts: function() {
         this.$(".shortcuts").toggle();
index a5f4ddb3261959df99e961fa2f4eaa8d07e9aece..4765349888dc80196c38807acfe5fb8dcbfd6482 100644 (file)
@@ -361,6 +361,7 @@ var Shortcut = (function(document, _) {
         var el = this.el;
         if (objectType === "global") {
             Shortcut.globalObject = el;
+            Shortcut.globalObject.options = { view: this };
             this._shortcutObject = Shortcut.globalObject;
         } else {
             this._shortcutObject = Shortcut.addObject(el, objectType, { view: this });
@@ -718,8 +719,11 @@ var TodoModel = Backbone.Model.extend({
     toggleCollapsed: function() {
         this.save({collapsed: !this.get("collapsed")});
     },
+    _setText: function(text) {
+        return this.save({text: text});
+    },
     setText: function(text) {
-        this.save({text: text});
+        return Actions.App.act(new Actions.ChangeText(this, text));
     },
     hasChildren: function() {
         return this.get("bullets").length > 0;
@@ -808,16 +812,23 @@ var TodoModel = Backbone.Model.extend({
         this.set("bullets", bullets);
         return this;
     },
+    getLocation: function() {
+        return {
+            parent: this.getParent(),
+            index: this.getParent().findChild(this.id),
+        };
+    },
     moveTo: function(newLocation) {
         if (this.isRoot()) {
             console.log("Cannot move root");
             return this;
         }
-        var existingLocation = {
-            parent: this.getParent(),
-            index: this.getParent().findChild(this.id),
-        };
+        var existingLocation = this.getLocation();
         newLocation = _.defaults({}, newLocation, existingLocation);
+        return Actions.App.act(new Actions.MoveBullet(this, newLocation));
+    },
+    _moveTo: function(newLocation) {
+        var existingLocation = this.getLocation();
         var newChildren;
         if (newLocation.parent === existingLocation.parent && newLocation.index === existingLocation.index) {
             // No-op
@@ -1059,19 +1070,31 @@ BaseAction.prototype= {
 
 Actions = {};
 
-Actions.AppendWords = function(array, word) {
-    this.array = array;
-    this.word = word;
+Actions.MoveBullet = function(bullet, newLocation) {
+    this.bullet = bullet;
+    this.oldLocation = bullet.getLocation();
+    this.newLocation = newLocation;
 };
-Actions.AppendWords.prototype = _.extend(new BaseAction(), {
+Actions.MoveBullet.prototype = _.extend(new BaseAction(), {
     apply: function() {
-        this.array.push(this.word);
+        return this.bullet._moveTo(this.newLocation);
     },
     rewind: function() {
-        var a = this.array.pop();
-        if (a !== this.word) {
-            throw "Rewind faiiiiiled :(";
-        }
+        return this.bullet._moveTo(this.oldLocation);
+    },
+});
+
+Actions.ChangeText = function(bullet, newText) {
+    this.bullet = bullet;
+    this.oldText = bullet.get("text");
+    this.newText = newText;
+};
+Actions.ChangeText.prototype = _.extend(new BaseAction(), {
+    apply: function() {
+        return this.bullet._setText(this.newText);
+    },
+    rewind: function() {
+        return this.bullet._setText(this.oldText);
     },
 });
 
@@ -1093,9 +1116,11 @@ var AppView = Backbone.View.extend({
     el: $("#todo-app"),
     shortcutObject: "global",
     events: {
-        'Shortcut("toggleShortcuts", "Keyboard Shortcuts", "ctrl+shift+/") > .text': 'toggleShortcuts',
-        'Shortcut("toggleShowCompleted", "Show/hide completed", "ctrl+o") > .text': 'toggleShowCompleted',
-        'Shortcut("search", "Not Done - Search", "esc") > .text': 'search',
+        'Shortcut("toggleShortcuts", "Keyboard Shortcuts", "ctrl+shift+/") body': 'toggleShortcuts',
+        'Shortcut("toggleShowCompleted", "Show/hide completed", "ctrl+o") body': 'toggleShowCompleted',
+        'Shortcut("search", "Not Done - Search", "esc") body': 'search',
+        'Shortcut("undo", "Undo", "ctrl+z") body': 'undo',
+        'Shortcut("redo", "Redo", "ctrl+shift+z,ctrl+y") body': 'redo',
     },
     initialize: function(options) {
         options = _.defaults({}, options, appDefaults);
@@ -1115,10 +1140,10 @@ var AppView = Backbone.View.extend({
                 e.save();
             });
         });
-        Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right'] });
+        Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right', 'undo', 'redo'] });
         this.views = {}; // A list of views for each element in the collection
-        this.history = [];
-        this.history.redo = [];
+        Actions.App = this;
+        this.undoRedoHistory = {undo: [], redo:[]}; // Linear zipper
         this.list.fetch();
         this.render();
     },
@@ -1139,21 +1164,29 @@ var AppView = Backbone.View.extend({
         }
     },
     act: function(action) {
-        action.apply();
-        this.history.push(action);
-        this.history.redo = [];
+        var retVal = action.apply();
+        this.undoRedoHistory.undo.push(action);
+        this.undoRedoHistory.redo = [];
+        return retVal;
     },
     undo: function() {
-        var action = this.history.pop();
-        if (!action) throw "Rewind called with empty history stack";
-        action.rewind();
-        this.history.redo.push(action);
+        var action = this.undoRedoHistory.undo.pop();
+        if (!action) {
+            console.log("Rewind called with empty history stack");
+            return;
+        }
+        var retVal = action.rewind();
+        this.undoRedoHistory.redo.push(action);
+        return retVal;
     },
     redo: function() {
-        var action = this.history.redo.pop();
-        if (!action) throw "Replay called with empty redo stack";
+        var action = this.undoRedoHistory.redo.pop();
+        if (!action) {
+            console.log("Replay called with empty redo stack");
+            return;
+        }
         action.reapply();
-        this.history.push(action);
+        this.undoRedoHistory.undo.push(action);
     },
     toggleShortcuts: function() {
         this.$(".shortcuts").toggle();
index 15543bf636111503ca378262cf9a13aa5392bf74..973f48430ad31c9ccc77cc42510448a4691bf5c3 100644 (file)
@@ -7,18 +7,30 @@ BaseAction.prototype= {
 
 Actions = {};
 
-Actions.AppendWords = function(array, word) {
-    this.array = array;
-    this.word = word;
+Actions.MoveBullet = function(bullet, newLocation) {
+    this.bullet = bullet;
+    this.oldLocation = bullet.getLocation();
+    this.newLocation = newLocation;
 };
-Actions.AppendWords.prototype = _.extend(new BaseAction(), {
+Actions.MoveBullet.prototype = _.extend(new BaseAction(), {
     apply: function() {
-        this.array.push(this.word);
+        return this.bullet._moveTo(this.newLocation);
     },
     rewind: function() {
-        var a = this.array.pop();
-        if (a !== this.word) {
-            throw "Rewind faiiiiiled :(";
-        }
+        return this.bullet._moveTo(this.oldLocation);
+    },
+});
+
+Actions.ChangeText = function(bullet, newText) {
+    this.bullet = bullet;
+    this.oldText = bullet.get("text");
+    this.newText = newText;
+};
+Actions.ChangeText.prototype = _.extend(new BaseAction(), {
+    apply: function() {
+        return this.bullet._setText(this.newText);
+    },
+    rewind: function() {
+        return this.bullet._setText(this.oldText);
     },
 });
index 1ac718044099a07d7df133efb879c1b4183dfb18..e4868a43fd4c07ef310c4c545af8ac3512701621 100644 (file)
@@ -32,6 +32,7 @@
         var el = this.el;
         if (objectType === "global") {
             Shortcut.globalObject = el;
+            Shortcut.globalObject.options = { view: this };
             this._shortcutObject = Shortcut.globalObject;
         } else {
             this._shortcutObject = Shortcut.addObject(el, objectType, { view: this });
index 11f9206cbf5ca465bf13f2f88bf5317f5db560ca..79e9c743e8410ad4eadbf12cc1499487b9e431a0 100644 (file)
@@ -14,8 +14,11 @@ var TodoModel = Backbone.Model.extend({
     toggleCollapsed: function() {
         this.save({collapsed: !this.get("collapsed")});
     },
+    _setText: function(text) {
+        return this.save({text: text});
+    },
     setText: function(text) {
-        this.save({text: text});
+        return Actions.App.act(new Actions.ChangeText(this, text));
     },
     hasChildren: function() {
         return this.get("bullets").length > 0;
@@ -104,16 +107,23 @@ var TodoModel = Backbone.Model.extend({
         this.set("bullets", bullets);
         return this;
     },
+    getLocation: function() {
+        return {
+            parent: this.getParent(),
+            index: this.getParent().findChild(this.id),
+        };
+    },
     moveTo: function(newLocation) {
         if (this.isRoot()) {
             console.log("Cannot move root");
             return this;
         }
-        var existingLocation = {
-            parent: this.getParent(),
-            index: this.getParent().findChild(this.id),
-        };
+        var existingLocation = this.getLocation();
         newLocation = _.defaults({}, newLocation, existingLocation);
+        return Actions.App.act(new Actions.MoveBullet(this, newLocation));
+    },
+    _moveTo: function(newLocation) {
+        var existingLocation = this.getLocation();
         var newChildren;
         if (newLocation.parent === existingLocation.parent && newLocation.index === existingLocation.index) {
             // No-op
index e6a2c0759b4de9ada81f8828a8b316b18948fdca..27d054a3e71f03bb148c1cf02d58c01c2b762810 100644 (file)
@@ -16,9 +16,11 @@ var AppView = Backbone.View.extend({
     el: $("#todo-app"),
     shortcutObject: "global",
     events: {
-        'Shortcut("toggleShortcuts", "Keyboard Shortcuts", "ctrl+shift+/") > .text': 'toggleShortcuts',
-        'Shortcut("toggleShowCompleted", "Show/hide completed", "ctrl+o") > .text': 'toggleShowCompleted',
-        'Shortcut("search", "Not Done - Search", "esc") > .text': 'search',
+        'Shortcut("toggleShortcuts", "Keyboard Shortcuts", "ctrl+shift+/") body': 'toggleShortcuts',
+        'Shortcut("toggleShowCompleted", "Show/hide completed", "ctrl+o") body': 'toggleShowCompleted',
+        'Shortcut("search", "Not Done - Search", "esc") body': 'search',
+        'Shortcut("undo", "Undo", "ctrl+z") body': 'undo',
+        'Shortcut("redo", "Redo", "ctrl+shift+z,ctrl+y") body': 'redo',
     },
     initialize: function(options) {
         options = _.defaults({}, options, appDefaults);
@@ -38,10 +40,10 @@ var AppView = Backbone.View.extend({
                 e.save();
             });
         });
-        Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right'] });
+        Shortcut.bindShortcutsDisplay(this.$("#shortcuts-wrapper")[0], {allowRebind: true, noDisplay: ['combineNext', 'combinePrevious', 'next', 'previous', 'left', 'right', 'undo', 'redo'] });
         this.views = {}; // A list of views for each element in the collection
-        this.history = [];
-        this.history.redo = [];
+        Actions.App = this;
+        this.undoRedoHistory = {undo: [], redo:[]}; // Linear zipper
         this.list.fetch();
         this.render();
     },
@@ -62,21 +64,29 @@ var AppView = Backbone.View.extend({
         }
     },
     act: function(action) {
-        action.apply();
-        this.history.push(action);
-        this.history.redo = [];
+        var retVal = action.apply();
+        this.undoRedoHistory.undo.push(action);
+        this.undoRedoHistory.redo = [];
+        return retVal;
     },
     undo: function() {
-        var action = this.history.pop();
-        if (!action) throw "Rewind called with empty history stack";
-        action.rewind();
-        this.history.redo.push(action);
+        var action = this.undoRedoHistory.undo.pop();
+        if (!action) {
+            console.log("Rewind called with empty history stack");
+            return;
+        }
+        var retVal = action.rewind();
+        this.undoRedoHistory.redo.push(action);
+        return retVal;
     },
     redo: function() {
-        var action = this.history.redo.pop();
-        if (!action) throw "Replay called with empty redo stack";
+        var action = this.undoRedoHistory.redo.pop();
+        if (!action) {
+            console.log("Replay called with empty redo stack");
+            return;
+        }
         action.reapply();
-        this.history.push(action);
+        this.undoRedoHistory.undo.push(action);
     },
     toggleShortcuts: function() {
         this.$(".shortcuts").toggle();