InternetExplorerSelection.js

Summary

Adapts Internet Explorer's Selection object to an interface like Mozilla's.

History: The original code was written by Jorgen Horstink (http://jorgenhorstink.nl/2006/03/11/w3c-range-in-internet-explorer/). It was extensively modified by David Kingma. This version has been adapted for use with Mozile by James A. Overton. Key changes include wrapping the objects in the Mozile namespace, so as to minimize the impact on other scripts in the same page.

Version: 0.8 $Id: overview-summary-InternetExplorerSelection.js.html,v 1.12 2008/02/20 18:47:09 jameso Exp $

Author: James A. Overton


Class Summary
mozile.dom.InternetExplorerSelection  

/* ***** BEGIN LICENSE BLOCK *****
 * Licensed under Version: MPL 1.1/GPL 2.0/LGPL 2.1
 * Full Terms at http://mozile.mozdev.org/0.8/LICENSE
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Jorgen Horstink and David Kingma's code.
 *
 * The Initial Developers of the Original Code are Jorgen Horstink and David Kingma.
 * Portions created by the Initial Developer are Copyright (C) 2005-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *	James A. Overton <james@overton.ca>
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * @fileoverview Adapts Internet Explorer's Selection object to an interface like Mozilla's.
 * <p>History: The original code was written by Jorgen Horstink (http://jorgenhorstink.nl/2006/03/11/w3c-range-in-internet-explorer/).
 * It was extensively modified by David Kingma.
 * This version has been adapted for use with Mozile by James A. Overton.
 * Key changes include wrapping the objects in the Mozile namespace, so as to minimize the impact on other scripts in the same page.
 *
 * @link http://mozile.mozdev.org 
 * @author James A. Overton <james@overton.ca>
 * @version 0.8
 * $Id: overview-summary-InternetExplorerSelection.js.html,v 1.12 2008/02/20 18:47:09 jameso Exp $
 */

mozile.require("mozile.dom");
mozile.require("mozile.xpath");
mozile.require("mozile.dom.InternetExplorerRange");
mozile.provide("mozile.dom.InternetExplorerSelection");


/**
 * Selection object, based on the mozilla implementation.
 * See http://www.xulplanet.com/references/objref/Selection.html
 * @constructor
 */
mozile.dom.InternetExplorerSelection = function() {
	/**
	 * A reference to IE's native selection object.
	 * @private
	 * @type Selection
	 */
	this._selection = mozile.document.selection;

	/**
	 * The node in wich the selection begins.
	 * @type Node
	 */
	this.anchorNode = null; 

	/**
	 * The number of characters that the selection's anchor is offset within the ancherNode.
	 * @type Integer
	 */
	this.anchorOffset = null; 

	/**
	 * The node in which the selection ends.
	 * @type Node
	 */
	this.focusNode = null; 

	/**
	 * The number of characters that the selection's focus is offset within the focusNode.
	 * @type Integer
	 */
	this.focusOffset = null;

	/**
	 * A boolean indicating whether the selection's start and end points are at the same position.
	 * @type Boolean
	 */
	this.isCollapsed = null;

	/**
	 * The number of ranges in the selection.
	 * @type Integer
	 */
	this.rangeCount = 0;

	/**
	 * The direction of the selection. Can be Left-to-Right or Right-to-Left, using coded integers.
	 * @private
	 * @type Integer
	 */
	this._direction = this._LTR;
	
	// Initialize the properties.
	this._init();
}

/**
 * Code indicating the selection direction. Left-to-right.
 * @private
 * @type Integer
 */
mozile.dom.InternetExplorerSelection.prototype._LTR = 1;

/**
 * Code indicating the selection direction. Right-to-left.
 * @private
 * @type Integer
 */
mozile.dom.InternetExplorerSelection.prototype._RTL = -1;

/**
 * Returns a range object representing one of the ranges currently selected.
 * @private
 * @param {Range} range Optional. A range object to use rather than using the getRangeAt(0).
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype._init = function(range) {
	this._selection = mozile.document.selection;

	if(!range) range = this.getRangeAt(0);
	
	if(!this._direction) this._direction = this._LTR;
	
	if(range && range.startContainer) {
		if(this._direction == this._LTR) {
			this.anchorNode = range.startContainer; 
			this.anchorOffset = range.startOffset; 
			this.focusNode = range.endContainer;
			this.focusOffset = range.endOffset;
		}
		else {
			this.anchorNode = range.endContainer; 
			this.anchorOffset = range.endOffset; 
			this.focusNode = range.startContainer;
			this.focusOffset = range.startOffset;
		}
		this.isCollapsed = range.collapsed;
	}
	else {
		this.anchorNode = null; 
		this.anchorOffset = null; 
		this.focusNode = null;
		this.focusOffset = null;
		this.isCollapsed = true;
	}
	//this.currentRange = range;
	this.rangeCount = 1; //this._selection.createRangeCollection().length;
}

/**
 * Returns a range object representing one of the ranges currently selected
 * @param {Integer} index The index of the desired range.
 * @type Range
 */
mozile.dom.InternetExplorerSelection.prototype.getRangeAt = function (index) {
	// NOTE: Replaced createRangeCollection().item(index) with createRange()
	// to avoid a bug when mozile.document is a different document.

	/*
	range = new mozile.dom.InternetExplorerRange(this._selection.createRange());
	range._init();
	return range;
	*/

	// Attempted optimization:
	var textRange = this._selection.createRange().duplicate();
	var range;
	// Trying to cache range, but it's too slow.
	if(this._lastTextRange && this._lastTextRange.isEqual(textRange)) {
		range = this._lastRange;
	}
	else {
		range = new mozile.dom.InternetExplorerRange(textRange);
		range._init();
		this._lastTextRange = textRange.duplicate();
		this._lastRange = range;
		this._direction = this._LTR;
	}

	return range.cloneRange();
}

/**
 * Collapses the current selection to a single point. 
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.collapse = function (parentNode, offset) {
	var range = new mozile.dom.InternetExplorerRange(
		parentNode.ownerDocument.body.createTextRange());
	range.setStart(parentNode, offset);
	range.setEnd(parentNode, offset);
	range.collapse(false);
	this._direction = this._LTR;
	//alert("Collapsed 1 "+ mozile.util.dumpValues(range.store()));
	// Store the values first, then select the TextRange.
	this._init(range); 
	//alert("Collapsed 2 "+ mozile.util.dumpValues(this.store()));
	this._lastTextRange = range._range.duplicate();
	this._lastRange = range;
	range._range.select();
	//alert("Collapsed 3 "+ mozile.util.dumpValues(this.store()));
}

/**
 * Moves the focus of the selection to a specified point.
 * Somewhat tricky because the direction of the extension has to be accounted for.
 * @param {Node} parentNode The new focusNode.
 * @param {Integer} offset The new focusOffset.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.extend = function (parentNode, offset) {
	var range = this.getRangeAt(0);
	var direction;

	// Compare offsets in the same node.
	if(parentNode == range.startContainer && 
		range.startOffset <= offset) {
		direction = this._LTR;
	}
	else if(parentNode == range.endContainer && 
		range.endOffset >= offset){
		direction = this._RTL;
	}

	// Compare offsets in the same container.
	// Suppose the startContainer/endContainer is a text node.
	else if(parentNode == range.startContainer.parentNode &&
	  range.startContainer.nodeType == mozile.dom.TEXT_NODE &&
	  mozile.dom.getIndex(range.startContainer) <= offset) {
	  direction = this._LTR;
	}
	else if(parentNode == range.endContainer.parentNode &&
	  range.endContainer.nodeType == mozile.dom.TEXT_NODE &&
	  mozile.dom.getIndex(range.endContainer) >= offset) {
	  direction = this._RTL;
	}

	// Use a TreeWalker to the parentNode relative to the anchorNode.
	else {
		var ancestor = mozile.dom.getCommonAncestor(parentNode, range.commonAncestorContainer)
		var treeWalker = document.createTreeWalker(ancestor, mozile.dom.NodeFilter.SHOW_ALL, null, false);
		treeWalker.currentNode = this.anchorNode;
		while(treeWalker.previousNode()) {
			if(treeWalker.currentNode == parentNode) {
				direction = this._RTL;
				break;
			}
		}
		if(!direction) direction = this._LTR;
	}
	
	// Extend the selection.
	if(direction == this._LTR) range.setEnd(parentNode, offset);
	else if(direction == this._RTL) range.setStart(parentNode, offset);
	else return;
	
	//alert("Extend "+ this._direction +"\nFocus "+ this.focusOffset +"\n"+  mozile.util.dumpValues(range.store()));
	this._direction = direction;
	this._init(range);
	this._lastTextRange = range._range.duplicate();
	this._lastRange = range;
	range._range.select();
}

/**
 * Moves the focus of the selection to the same point as the anchor.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.collapseToStart = function () {
	var range = this.getRangeAt(0);
	range.collapse(true);
	this._init(range);
	range._range.select();
}

/**
 * Moves the anchor of the selection to the same point as the focus. The focus does not move.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.collapseToEnd = function () {
	var range = this.getRangeAt(0);
	range.collapse();
	this._init(range);
	range._range.select();
}

/**
 * Adds all the children of the specified node to the selection.
 * @param {Node} parentNode
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.selectAllChildren = function (parentNode) {
	var range = this.getRangeAt(0);
	range.selectNodeContents(parentNode);
	this._init(range);
	range._range.select();
}

/**
 * A range object that will be added to the selection.
 * @param {Range} range The range to add.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.addRange = function (range) {
	this._direction = this._LTR;
	this._init(range);
	range._range.select();
}

/**
 * Removes a range from the selection.
 * @param {Range} range The range to remove.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.removeRange = function (range) {
	range.collapse();
	this._init(range);
}

/**
 * Removes all ranges from the selection.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.removeAllRanges = function () {
	this._selection.empty();
	this._init();
}

/**
 * Deletes the selection's content from the document.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.deleteFromDocument = function () {
	this._selection.clear();
	this._init();
}

/**
 * NOT IMPLEMENTED. Changes the selection direction from Left-to-Right to Right-to-Left.
 * @param {Boolean} langRTL True indicates Right-to-Left, false indicates Left-to-Right.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.selectionLanguageChange = function () {}

/**
 * Returns a string currently being represented by the selection object, i.e. the 
 * currently selected text, no markup
 * @type String
 */
mozile.dom.InternetExplorerSelection.prototype.toString = function () {
	var range = this.getRangeAt(0);
	return range.toString();
}

/**
 * NOT IMPLEMENTED. Indicates if a certain node is part of the selection.
 * @param {Node} aNode
 * @param {Boolean} aPartlyContained
 * @type Boolean
 */
mozile.dom.InternetExplorerSelection.prototype.containsNode = function (aNode, aPartlyContained) {
	alert('mozile.dom.InternetExplorerSelection.containsNode() is not implemented yet');
}



/**
 * Store the details about this range in an object which can be used to restore the range.
 * @type Object
 */
mozile.dom.InternetExplorerSelection.prototype.store = mozile.dom.Selection.prototype.store;

/**
 * Takes a stored range object and creates a new range with the same properties.
 * @param {Object} state A state object from Selection.store() or Range.store().
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.restore = mozile.dom.Selection.prototype.restore;

/**
 * Scroll the window to the current selection.
 * @type Void
 */
mozile.dom.InternetExplorerSelection.prototype.scroll = mozile.dom.Selection.prototype.scroll;


/**
 * Restore the give range as the current selection (only allows for a single range).
 * @param {Range} r The range to restore.
 * @type Void
 */
mozile.dom.Selection.restoreSelection = function (r) {
	var range = new mozile.Range();
	try {
		range.setStart(r.startContainer, r.startOffset);
		range.setEnd(r.endContainer, r.endOffset);
	} catch(e) {}

	// Restore the selection.
	var s = new mozile.dom.Selection();
	s.removeAllRanges();
	s.addRange(range);
}






Documentation generated by JSDoc on Wed Feb 20 13:25:28 2008