+ });
+ if(target) {
+ scrolled = scroll('bottom', target);
+ position = utils.caretPositionFromPoint(caretRect.left, rect.top +1 - scrolled);
+ s.canvas.setCurrentElement(s.canvas.getDocumentElement(position.textNode), {caretTo: position.offset});
+ }
+ }
+ if(target) {
+ scrolled = scroll('bottom', target);
+ var left = caretRect.left;
+ if(left > rect.left + rect.width) {
+ left = rect.left + rect.width;
+ } else if(left < rect.left ) {
+ left = rect.left;
+ }
+ position = utils.caretPositionFromPoint(left, rect.top +1 - scrolled);
+ s.canvas.setCurrentElement(s.canvas.getDocumentElement(position.textNode), {caretTo: position.offset});
+ }
+ }
+ },
+ {
+ applies: function(e, s) {
+ return e.key === KEYS.ARROW_LEFT && s.type === 'caret';
+ },
+ run: function(e, s) {
+ /* globals window */
+ var prev;
+
+ if(s.offset === 0) {
+ e.preventDefault();
+ prev = s.canvas.getPreviousTextElement(s.element);
+ if(prev) {
+ scroll('top', prev.dom[0]);
+ s.canvas.setCurrentElement(s.canvas.getDocumentElement(prev.dom.contents()[0]), {caretTo: 'end'});
+ }
+ }
+ }
+ },
+ {
+ applies: function(e, s) {
+ return e.key === KEYS.ARROW_RIGHT && s.type === 'caret';
+ },
+ run: function(e, s) {
+ /* globals window */
+ var next;
+ if(s.isAtEnd()) {
+ e.preventDefault();
+ next = s.canvas.getNextTextElement(s.element);
+ if(next) {
+ scroll('bottom', next.dom[0]);
+ s.canvas.setCurrentElement(s.canvas.getDocumentElement(next.dom.contents()[0]), {caretTo: 0});
+ }
+ } else {
+ var secondToLast = (s.offset === s.element.wlxmlNode.getText().length -1);
+ if(secondToLast) {
+ // Only Flying Spaghetti Monster knows why this is need for FF (for versions at least 26 to 31)
+ e.preventDefault();
+ s.canvas.setCurrentElement(s.element, {caretTo: 'end'});
+ }
+ }
+ }
+ },
+ {
+ applies: function(e, s) {
+ return s.type === 'caret' &&
+ s.element.wlxmlNode.parent().is({tagName: 'span'}) &&
+ s.element.wlxmlNode.getText().length === 1 &&
+ s.offset === 1 &&
+ (e.key === KEYS.BACKSPACE);
+ },
+ run: function(e, s) {
+ var params = {},
+ prevTextNode = s.element.canvas.getPreviousTextElement(s.element).wlxmlNode;
+ e.preventDefault();
+ s.element.wlxmlNode.parent().detach(params);
+ s.canvas.setCurrentElement(
+ (params.ret && params.ret.mergedTo) || prevTextNode,
+ {caretTo: params.ret ? params.ret.previousLen : (prevTextNode ? prevTextNode.getText().length : 0)});
+ }
+ },
+ {
+ applies: function(e, s) {
+ return s.type === 'caret' && (
+ (s.isAtBeginning() && e.key === KEYS.BACKSPACE) ||
+ (s.isAtEnd() && e.key === KEYS.DELETE)
+ );
+ },
+ run: function(e,s) {
+ var direction, caretTo, cursorAtOperationEdge, goto, element;
+
+ if(e.key === KEYS.BACKSPACE) {
+ direction = 'above';
+ caretTo = 'end';
+ cursorAtOperationEdge = s.isAtBeginning();
+ element = s.element;
+ }
+ else {
+ direction = 'below';
+ caretTo = 'start';
+ cursorAtOperationEdge = s.isAtEnd();
+ element = cursorAtOperationEdge && s.canvas.getNearestTextElement(direction, s.element);
+ }
+
+ if(!cursorAtOperationEdge || !element) {
+ return;
+ }
+
+ e.preventDefault();
+
+ s.canvas.wlxmlDocument.transaction(function() {
+ if(element.wlxmlNode.getIndex() === 0) {
+ goto = element.wlxmlNode.parent().moveUp();