InsertionPoint.js
Summary
Tools for editing operations.
Version: 0.8
$Id: overview-summary-InsertionPoint.js.html,v 1.7 2006/08/23 23:30:17 jameso Exp $
Author: James A. Overton
mozile.require("mozile.dom");
mozile.require("mozile.edit");
mozile.provide("mozile.edit.InsertionPoint");
mozile.edit.InsertionPoint = function(node, offset) {
this._node = node;
this._offset = offset;
}
mozile.edit.InsertionPoint.prototype._matchLeadingWS = /^(\s*)/;
mozile.edit.InsertionPoint.prototype._matchTrailingWS = /(\s*)$/;
mozile.edit.InsertionPoint.prototype._matchNonWS = /\S/;
mozile.edit.InsertionPoint.prototype.getNode = function() { return this._node; }
mozile.edit.InsertionPoint.prototype.getOffset = function() {
if(this._offset < 0) this._offset = 0;
return this._offset;
}
mozile.edit.InsertionPoint.prototype.toString = function() {
return "Insertion Point: "+ mozile.xpath.getXPath(this._node) +" "+ this._offset;
}
mozile.edit.InsertionPoint.prototype.select = function() {
try {
var selection = mozile.dom.selection.get();
selection.collapse(this.getNode(), this.getOffset());
} catch(e) {
mozile.debug.debug("mozile.edit.InsertionPoint.prototype.select", "Bad collapse for IP "+ mozile.xpath.getXPath(this.getNode()) +" "+ this.getOffset() +"\n"+ mozile.dumpError(e));
}
}
mozile.edit.InsertionPoint.prototype.extend = function() {
try {
var selection = mozile.dom.selection.get();
selection.extend(this.getNode(), this.getOffset());
} catch(e) {
mozile.debug.debug("mozile.edit.InsertionPoint.prototype.extend", "Bad extend for IP "+ mozile.xpath.getXPath(this.getNode()) +" "+ this.getOffset() +"\n"+ mozile.dumpError(e));
}
}
mozile.edit.InsertionPoint.prototype.next = function() {
this.seek(mozile.edit.NEXT);
}
mozile.edit.InsertionPoint.prototype.previous = function() {
this.seek(mozile.edit.PREVIOUS);
}
mozile.edit.InsertionPoint.prototype.seek = function(direction) {
var node = this.getNode();
var offset = this.getOffset();
if(!node || typeof(offset) == "undefined") return false;
if(node.nodeType != mozile.dom.TEXT_NODE ||
(direction == mozile.edit.PREVIOUS && offset == 0) ||
(direction == mozile.edit.NEXT && offset == node.data.length) ||
(direction == mozile.edit.NEXT && mozile.edit.isEmptyToken(node)) ) {
return this.seekNode(direction);
}
else offset = offset + direction;
if(!node || typeof(offset) == "undefined") return false;
if(mozile.edit.isEmptyToken(node)) {
this._offset = 0;
return true;
}
var content = node.data;
var substring, result, altSpaceIndex;
if(direction == mozile.edit.NEXT) {
substring = content.substring(this.getOffset());
result = substring.match(this._matchLeadingWS);
if(mozile.alternateSpace)
altSpaceIndex = substring.indexOf(mozile.alternateSpace);
}
else {
substring = content.substring(0, this.getOffset());
result = substring.match(this._matchTrailingWS);
if(mozile.alternateSpace) {
altSpaceIndex = substring.length;
altSpaceIndex -= substring.lastIndexOf(mozile.alternateSpace) + 1;
}
}
var wsLength = result[0].length;
if(Number(altSpaceIndex) != NaN && altSpaceIndex > -1 &&
altSpaceIndex < wsLength) {
wsLength = altSpaceIndex;
}
var moveBy = 0;
if(wsLength < 2) moveBy = direction;
else if(mozile.dom.getStyle(node.parentNode, "white-space").toLowerCase() == "pre") moveBy = direction;
else if(wsLength < substring.length) moveBy = wsLength * direction;
else if(wsLength == substring.length) {
return this.seekNode(direction);
}
else throw Error("Unhandled case in InsertionPoint.seek()");
this._node = node;
this._offset = this.getOffset() + moveBy;
return true;
}
mozile.edit.InsertionPoint.prototype.seekNode = function(direction, extraStep) {
if(extraStep !== false) extraStep = true;
var node = this.getNode();
if(!node) return false;
var startNode = node;
var container = mozile.edit.getContainer(node);
if(!container) container = document.documentElement;
var treeWalker = document.createTreeWalker(container, mozile.dom.NodeFilter.SHOW_ALL, null, false);
if(node.nodeType == mozile.dom.TEXT_NODE) {
treeWalker.currentNode = node;
if(direction == mozile.edit.NEXT) node = treeWalker.nextNode();
else {
var tempNode = node;
node = treeWalker.previousNode();
while(node && node.firstChild == tempNode) {
tempNode = node;
node = treeWalker.previousNode();
}
}
}
else {
node = node.childNodes[this.getOffset()];
if(node) {
startNode = node;
treeWalker.currentNode = node;
}
else if(this.getOffset() > 0 &&
this.getOffset() == this.getNode().childNodes.length &&
this.getNode().childNodes[this.getOffset() - 1]) {
node = this.getNode().childNodes[this.getOffset() - 1];
startNode = node;
treeWalker.currentNode = node;
}
else {
node = this.getNode();
startNode = node;
treeWalker.currentNode = node;
if(direction == mozile.edit.NEXT) node = treeWalker.nextNode();
else {
var tempNode = node;
node = treeWalker.previousNode();
while(node && node.firstChild == tempNode) {
tempNode = node;
node = treeWalker.previousNode();
}
}
}
}
if(!node) {
mozile.debug.debug("mozile.edit.InsertionPoint.prototype.seekNode", "Lost node.");
return false;
}
var IP;
var offset = null;
var lastNode = node;
var skippedOne = false;
while(node) {
IP = mozile.edit.getInsertionPoint(node, direction);
if(IP) {
this._node = IP.getNode();
this._offset = IP.getOffset();
if( extraStep &&
(mozile.edit.getParentBlock(node) == mozile.edit.getParentBlock(startNode) && mozile.edit.isNodeEditable(lastNode)) ||
(lastNode.nodeType == mozile.dom.COMMENT_NODE && node == IP.getNode()) )
this._offset = this._offset + direction;
if(mozile.edit.isEmptyToken(IP.getNode())) this._offset = 0;
return true;
}
else if(node.nodeType == mozile.dom.ELEMENT_NODE &&
mozile.edit.isNodeEditable(node.parentNode) ) {
var nextNode = node;
while(nextNode) {
if(direction == mozile.edit.NEXT) nextNode = nextNode.nextSibling;
else nextNode = nextNode.previousSibling;
if(nextNode && nextNode.nodeType == mozile.dom.COMMENT_NODE) continue;
else break;
}
IP = mozile.edit.getInsertionPoint(nextNode, direction);
if(!IP) {
var newNode = node;
if(direction == mozile.edit.PREVIOUS) {
if(nextNode.parentNode == this._node && !skippedOne) {
skippedOne = true;
lastNode = node;
node = nextNode;
treeWalker.currentNode = node;
continue;
}
newNode = nextNode;
}
this._node = newNode.parentNode;
this._offset = mozile.dom.getIndex(newNode) + 1;
return true;
}
}
lastNode = node;
if(direction == mozile.edit.NEXT) node = treeWalker.nextNode();
else node = treeWalker.previousNode();
}
return false;
}
mozile.dom.Selection.prototype.getInsertionPoint = function() {
if(!this.focusNode || this.focusOffset == null) return null;
else return new mozile.edit.InsertionPoint(this.focusNode, this.focusOffset);
}
if(mozile.dom.InternetExplorerSelection) {
mozile.dom.InternetExplorerSelection.prototype.getInsertionPoint = mozile.dom.Selection.prototype.getInsertionPoint;
}
mozile.edit.getInsertionPoint = function(node, direction, force) {
if(!node) return false;
var offset, IP;
if(mozile.edit.isNodeEditable(node) || force) {
if(node.nodeType == mozile.dom.TEXT_NODE) {
if(direction == mozile.edit.NEXT) offset = 0;
else offset = node.data.length;
return new mozile.edit.InsertionPoint(node, offset);
}
if(direction == mozile.edit.NEXT) IP = mozile.edit.getInsertionPoint(node.firstChild, direction);
else IP = mozile.edit.getInsertionPoint(node.lastChild, direction);
if(IP) return IP;
if(direction == mozile.edit.NEXT) offset = 0;
else offset = node.childNodes.length;
return new mozile.edit.InsertionPoint(node, offset);
}
return null;
}
Documentation generated by
JSDoc on Wed Aug 23 18:45:51 2006