From 412f7064a367ce9b073b189f46e7d4b7eb12557e Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Wed, 13 May 2015 20:37:29 -0700 Subject: [PATCH] Allow backspace at the beginning of a todo --- dist/flowy.js | 51 ++++++++++++++++++++++++++++++++------ dist/flowy.unwrapped.js | 51 ++++++++++++++++++++++++++++++++------ dist/main.html | 15 ----------- src/library/cursorToEnd.js | 25 +++++++++++++++++++ src/views/todo.js | 26 +++++++++++++------ 5 files changed, 129 insertions(+), 39 deletions(-) delete mode 100644 dist/main.html diff --git a/dist/flowy.js b/dist/flowy.js index 4881eb9..bf81f86 100644 --- a/dist/flowy.js +++ b/dist/flowy.js @@ -20,6 +20,31 @@ function setEndOfContenteditable(contentEditableElement) } } +function getCaretPosition(editableDiv) { + var caretPos = 0, + sel, range; + if (window.getSelection) { + sel = window.getSelection(); + if (sel.rangeCount) { + range = sel.getRangeAt(0); + if (range.commonAncestorContainer.parentNode == editableDiv) { + caretPos = range.endOffset; + } + } + } else if (document.selection && document.selection.createRange) { + range = document.selection.createRange(); + if (range.parentElement() == editableDiv) { + var tempEl = document.createElement("span"); + editableDiv.insertBefore(tempEl, editableDiv.firstChild); + var tempRange = range.duplicate(); + tempRange.moveToElementText(tempEl); + tempRange.setEndPoint("EndToEnd", range); + caretPos = tempRange.text.length; + } + } + return caretPos; +} + /** * @depend ../library/cursorToEnd.js */ @@ -57,25 +82,35 @@ var TodoView = Backbone.View.extend({ this.$el.find("> .text").blur(); return this; }, + isFocusAtBeginning: function() { + return getCaretPosition(this.$el.find("> .text")[0]) === 0; + }, decodeText: function(encodedText) { return $("
").html(encodedText).text(); }, backspace: function(e) { - // TODO: Handle backspace at beginning of non-empty line if (e.keyCode !== 8 /* backspace */ && e.keyCode !== 46 /* delete */) { return; } + if (this.model.hasChildren()) { + return; + } + var previousNode = this.model.previousNode(this.model.collection); + if (!previousNode) { + return; + } if (this.model.get("text") === "") { // Or focus is at the beginning - if (this.model.hasChildren()) { - return; - } - var previousNode = this.model.previousNode(this.model.collection); - if (!previousNode) { - return; - } e.preventDefault(); this.model.remove(this.model.collection); previousNode.getView().startEditingText({"atEnd":true}); + } else if (this.isFocusAtBeginning()) { + e.preventDefault(); + var text = this.model.get("text"); + this.model.remove(this.model.collection); + // TODO: Keep focus between the two halves + // var focusReminderElement = this.$("") + previousNode.setText(previousNode.get("text")/* + focusReminderElement*/ + text); + previousNode.getView().startEditingText(/*{"atMarker": focusReminderElement}*/); } }, textChange: function(e) { diff --git a/dist/flowy.unwrapped.js b/dist/flowy.unwrapped.js index 98ddff2..ff2a6ac 100644 --- a/dist/flowy.unwrapped.js +++ b/dist/flowy.unwrapped.js @@ -19,6 +19,31 @@ function setEndOfContenteditable(contentEditableElement) } } +function getCaretPosition(editableDiv) { + var caretPos = 0, + sel, range; + if (window.getSelection) { + sel = window.getSelection(); + if (sel.rangeCount) { + range = sel.getRangeAt(0); + if (range.commonAncestorContainer.parentNode == editableDiv) { + caretPos = range.endOffset; + } + } + } else if (document.selection && document.selection.createRange) { + range = document.selection.createRange(); + if (range.parentElement() == editableDiv) { + var tempEl = document.createElement("span"); + editableDiv.insertBefore(tempEl, editableDiv.firstChild); + var tempRange = range.duplicate(); + tempRange.moveToElementText(tempEl); + tempRange.setEndPoint("EndToEnd", range); + caretPos = tempRange.text.length; + } + } + return caretPos; +} + /** * @depend ../library/cursorToEnd.js */ @@ -56,25 +81,35 @@ var TodoView = Backbone.View.extend({ this.$el.find("> .text").blur(); return this; }, + isFocusAtBeginning: function() { + return getCaretPosition(this.$el.find("> .text")[0]) === 0; + }, decodeText: function(encodedText) { return $("
").html(encodedText).text(); }, backspace: function(e) { - // TODO: Handle backspace at beginning of non-empty line if (e.keyCode !== 8 /* backspace */ && e.keyCode !== 46 /* delete */) { return; } + if (this.model.hasChildren()) { + return; + } + var previousNode = this.model.previousNode(this.model.collection); + if (!previousNode) { + return; + } if (this.model.get("text") === "") { // Or focus is at the beginning - if (this.model.hasChildren()) { - return; - } - var previousNode = this.model.previousNode(this.model.collection); - if (!previousNode) { - return; - } e.preventDefault(); this.model.remove(this.model.collection); previousNode.getView().startEditingText({"atEnd":true}); + } else if (this.isFocusAtBeginning()) { + e.preventDefault(); + var text = this.model.get("text"); + this.model.remove(this.model.collection); + // TODO: Keep focus between the two halves + // var focusReminderElement = this.$("") + previousNode.setText(previousNode.get("text")/* + focusReminderElement*/ + text); + previousNode.getView().startEditingText(/*{"atMarker": focusReminderElement}*/); } }, textChange: function(e) { diff --git a/dist/main.html b/dist/main.html deleted file mode 100644 index ea60868..0000000 --- a/dist/main.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - -
- A todo list: -
- -
-
- - diff --git a/src/library/cursorToEnd.js b/src/library/cursorToEnd.js index 555dc60..cddf800 100644 --- a/src/library/cursorToEnd.js +++ b/src/library/cursorToEnd.js @@ -18,3 +18,28 @@ function setEndOfContenteditable(contentEditableElement) range.select();//Select the range (make it the visible selection } } + +function getCaretPosition(editableDiv) { + var caretPos = 0, + sel, range; + if (window.getSelection) { + sel = window.getSelection(); + if (sel.rangeCount) { + range = sel.getRangeAt(0); + if (range.commonAncestorContainer.parentNode == editableDiv) { + caretPos = range.endOffset; + } + } + } else if (document.selection && document.selection.createRange) { + range = document.selection.createRange(); + if (range.parentElement() == editableDiv) { + var tempEl = document.createElement("span"); + editableDiv.insertBefore(tempEl, editableDiv.firstChild); + var tempRange = range.duplicate(); + tempRange.moveToElementText(tempEl); + tempRange.setEndPoint("EndToEnd", range); + caretPos = tempRange.text.length; + } + } + return caretPos; +} diff --git a/src/views/todo.js b/src/views/todo.js index 119d7f6..e2ff583 100644 --- a/src/views/todo.js +++ b/src/views/todo.js @@ -35,25 +35,35 @@ var TodoView = Backbone.View.extend({ this.$el.find("> .text").blur(); return this; }, + isFocusAtBeginning: function() { + return getCaretPosition(this.$el.find("> .text")[0]) === 0; + }, decodeText: function(encodedText) { return $("
").html(encodedText).text(); }, backspace: function(e) { - // TODO: Handle backspace at beginning of non-empty line if (e.keyCode !== 8 /* backspace */ && e.keyCode !== 46 /* delete */) { return; } + if (this.model.hasChildren()) { + return; + } + var previousNode = this.model.previousNode(this.model.collection); + if (!previousNode) { + return; + } if (this.model.get("text") === "") { // Or focus is at the beginning - if (this.model.hasChildren()) { - return; - } - var previousNode = this.model.previousNode(this.model.collection); - if (!previousNode) { - return; - } e.preventDefault(); this.model.remove(this.model.collection); previousNode.getView().startEditingText({"atEnd":true}); + } else if (this.isFocusAtBeginning()) { + e.preventDefault(); + var text = this.model.get("text"); + this.model.remove(this.model.collection); + // TODO: Keep focus between the two halves + // var focusReminderElement = this.$("") + previousNode.setText(previousNode.get("text")/* + focusReminderElement*/ + text); + previousNode.getView().startEditingText(/*{"atMarker": focusReminderElement}*/); } }, textChange: function(e) { -- 2.47.3