Skip to content

Instantly share code, notes, and snippets.

@bbrown
Last active March 2, 2016 21:08
Show Gist options
  • Save bbrown/e1cb68e6becba06f3644 to your computer and use it in GitHub Desktop.
Save bbrown/e1cb68e6becba06f3644 to your computer and use it in GitHub Desktop.
Angular directive to navigate around table cells and edit them
angular.module("app").directive("clickToEdit", function()
{
return {
restrict: "A",
link: function link(scope, element)
{
var LEFT = 37, UP = 38, RIGHT = 39, DOWN = 40, ENTER = 13;
var navKeys = [ LEFT, UP, RIGHT, DOWN, ENTER ];
element.attr("contenteditable", true);
element.on("focus", function(e)
{
var currentRow = [].slice.call(e.target.offsetParent.rows).indexOf(e.target.parentElement);
var currentCell = [].slice.call(e.target.parentElement.cells).indexOf(e.target);
var begin = (e.target.innerText !== undefined) ? e.target.innerHTML.indexOf(e.target.innerText) : 0;
var end = (e.target.innerText !== undefined) ? begin + e.target.innerText.length : e.target.innerHTML.length;
var empty = (begin === end);
// http://stackoverflow.com/a/13641884
var range = document.createRange();
range.selectNodeContents(e.target);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
angular.element(e.target).on("keydown", function(e)
{
if (navKeys.indexOf(e.keyCode) !== -1)
{
var caretOffset = 0;
// http://stackoverflow.com/a/4812022
if (typeof window.getSelection !== "undefined")
{
var range = window.getSelection().getRangeAt(0);
var selected = range.toString().length;
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(e.target);
preCaretRange.setEnd(range.endContainer, range.endOffset);
if (selected)
{
caretOffset = preCaretRange.toString().length - selected;
}
else
{
caretOffset = preCaretRange.toString().length;
}
}
switch(e.keyCode)
{
case UP:
{
var next = e.target.offsetParent.rows[currentRow - 1].cells[currentCell];
if (next)
{
next.focus();
}
break;
}
case DOWN:
{
var next = e.target.offsetParent.rows[currentRow + 1].cells[currentCell];
if (next)
{
next.focus();
}
break;
}
case ENTER:
{
var move = (e.shiftKey) ? -1 : 1;
var next = e.target.offsetParent.rows[currentRow + move].cells[currentCell];
if (next)
{
next.focus();
}
e.preventDefault();
break;
}
case LEFT:
{
if (empty || caretOffset === begin)
{
var next = e.target.offsetParent.rows[currentRow].cells[currentCell - 1];
if (next)
{
next.focus();
}
}
break;
}
case RIGHT:
{
if (empty || caretOffset === end)
{
var next = e.target.offsetParent.rows[currentRow].cells[currentCell + 1];
if (next)
{
next.focus();
}
}
break;
}
}
}
});
});
element.on("blur", function(e)
{
angular.element(e.target).off("keydown");
});
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment