/** * Copyright (c) 2011 * OJC Technologies * all rights reserved * @author: Jake Smith */ var atEndOfLine = false; var hasCursor = false; var cursorTag = "span"; var cursorId = "littlecursorelement"; function dropCursorAt(targetNode, offsetIndex) { var noFront, noPost; noFront = (offsetIndex == 0) ? true : false; noPost = (offsetIndex == targetNode.nodeValue.length) ? true : false; if (noFront && noPost) { addCursorOnly(targetNode); } else if (noFront) { addCursorWithNoPrefix(targetNode); } else if (noPost) { addCursorWithNoSuffix(targetNode, offsetIndex); } else { insertCursor(targetNode, offsetIndex); } hasCursor = true; } function addCursorOnly(node) { var cursor, character; character = node.nodeValue; if (character.length != 1) { if (character == "") { character = "_"; } else { throw new Error("wanting to add only a cursor when it shouldn't"); } } cursor = makeCursor(character); node.parentNode.replaceChild(cursor, node); atEndOfLine = true; } function addCursorWithNoPrefix(node) { var parent, cursor, text, suffix, character, postString; parent = node.parentNode; text = node.nodeValue; character = text.substring(0, 1); postString = text.substring(1); cursor = makeCursor(character); suffix = document.createTextNode(postString); parent.replaceChild(cursor, node); insertAfter(cursor, suffix); } function addCursorWithNoSuffix(node, index) { var parent, cursor, text, prefix, character, foreString; parent = node.parentNode; text = node.nodeValue; foreString = text.substring(0, index); prefix = document.createTextNode(foreString); character = text.substring(index); if(character == "") { character = "_"; } cursor = makeCursor(character); parent.replaceChild(prefix, node); insertAfter(prefix, cursor); atEndOfLine = true; } function insertCursor(node, index) { var parent, cursor, text, prefix, suffix, character, foreString, postString; parent = node.parentNode; text = node.nodeValue; foreString = text.substring(0, index); prefix = document.createTextNode(foreString); character = text.substring(index, index + 1); cursor = makeCursor(character); postString = text.substring(index+1); suffix = document.createTextNode(postString); parent.replaceChild(prefix, node); insertAfter(prefix, cursor); insertAfter(cursor, suffix); } function makeCursor(character) { var cursor = document.createElement(cursorTag); cursor.setAttribute("id", cursorId); cursor.appendChild(document.createTextNode(character)); return cursor; } function removeStandingCursor() { if (!hasCursor) { return; } var cursor, parent; cursor = document.getElementById(cursorId); parent = cursor.parentNode; if(cursor.childNodes[0] != null) { if (atEndOfLine) { parent.removeChild(cursor); atEndOfLine = false; } else { parent.replaceChild(cursor.childNodes[0], cursor); } } else { parent.removeChild(cursor); } parent.normalize(); hasCursor = false; } function bumpCursorLeft() { var parent, cursor, prevSib, tempNode; cursor = document.getElementById(cursorId); parent = cursor.parentNode; prevSib = cursor.previousSibling; if (prevSib == null || prevSib.nodeType != Node.TEXT_NODE) { return; } else { if (atEndOfLine) { parent.removeChild(cursor); dropCursorAt(prevSib, prevSib.nodeValue.length - 1); atEndOfLine = false; } else { tempNode = document.createTextNode(cursor.childNodes[0].nodeValue); parent.replaceChild(tempNode, cursor); dropCursorAt(prevSib, prevSib.nodeValue.length - 1); parent.normalize(); } } } function bumpCursorRight() { var parent, cursor, nextSib, tempNode; cursor = document.getElementById(cursorId); parent = cursor.parentNode; nextSib = cursor.nextSibling; if (nextSib == null || nextSib.nodeType != Node.TEXT_NODE) { if (atEndOfLine) { return; } else { tempNode = document.createTextNode(cursor.childNodes[0].nodeValue); parent.replaceChild(tempNode, cursor); dropCursorAt(tempNode, tempNode.nodeValue.length); parent.normalize(); atEndOfLine = true; } } else { tempNode = document.createTextNode(cursor.childNodes[0].nodeValue); parent.replaceChild(tempNode, cursor); dropCursorAt(nextSib, 0); parent.normalize(); } } // This function inserts newNode after referenceNode function insertAfter(referenceNode, newNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); }