File: /home/mmickelson/martyknows.com/wp-content/themes/p2/js/caret.js
/**
* caret.js -- A lightweight, cross-browser library for manipulating carets.
*
* Author: Daryl Koopersmith
*/
(function() {
var Caret, rWordEnd = /\S+$/, rWordStart = /^\S+/;
Caret = window.Caret = function( element ) {
// Factory/Constructor
if ( ! ( this instanceof Caret ) )
return new Caret( element );
this.element = element;
this.refresh();
};
/**
* Many methods exist along these lines; the pitfalls surround IE.
* This method accounts for the following:
* - IE sometimes counts an additional \r for each newline.
* This can inflate the perceived caret position.
* - Certain methods ignore whitespace immediately before the cursor.
* - If the value is altered and the caret is at the end of the
* textarea, it will deselect when retreived.
*/
Caret.prototype.refresh = function() {
var range, bookmark, original, marker, parent, result, start, end,
element = this.element;
// Check if W3C properties exist.
if ( typeof element.selectionStart !== 'undefined' && typeof element.selectionEnd !== 'undefined' ) {
return this._set( element.selectionStart, element.selectionEnd );
}
// If selection API doesn't exist either, bail.
if ( ! document.selection ) {
return this._set( 0 );
}
element.focus();
range = document.selection.createRange();
bookmark = range.getBookmark();
original = element.value;
marker = String.fromCharCode(28);
parent = range.parentElement();
// Check if we're inside a textarea or text input.
if ( parent == null || ! ( parent.type == 'textarea' || parent.type == 'text' ) ) {
return this._set( 0 );
}
// Add markers for start and end positions.
// Otherwise trailing whitespace will be stripped.
range.text = marker + range.text + marker;
// \r's are counted for each newline... remove them.
contents = element.value.replace( /\r/g, '' );
// Find the caret positions
start = contents.indexOf( marker );
// Remove the first marker. Otherwise the end index will be wrong.
end = contents.replace( marker, "" ).indexOf( marker );
this._set( start, end );
// Restore the value and selection
element.value = original;
// In textareas, if the caret is the final character, the bookmark
// will shift the selected element to the body.
//
// This is a more efficient version of:
// if ( document.selection.createRange().parentElement() != element )
//
if ( original.length == position.start && parent.type == 'textarea' ) {
this.set( element, element.value.length );
} else {
range.moveToBookmark( bookmark );
range.select();
}
};
/**
* Internal.
*
* Sets this.start and this.end.
* Does nothing else!
*
* @param start The starting index.
* @param end Optional. The ending index. Defaults to start.
*/
Caret.prototype._set = function( start, end ) {
this.start = start;
this.end = ( typeof end === 'undefined' ) ? start : end;
};
/**
* Sets the caret position.
*
* @param start The starting index.
* @param end Optional. The ending index. Defaults to start.
*/
Caret.prototype.set = function( start, end ) {
var range;
end = ( typeof end === 'undefined' ) ? start : end;
this._set( start, end );
// W3C
if ( this.element.setSelectionRange ) {
this.element.setSelectionRange( start, end );
// IE
} else if ( this.element.createTextRange ) {
range = this.element.createTextRange();
if ( start === end )
range.collapse( true );
range.moveEnd( 'character', end );
range.moveStart( 'character', start );
range.select();
}
};
Caret.prototype.before = function() {
return this.element.value.substring( 0, this.start );
};
Caret.prototype.after = function() {
return this.element.value.substring( this.end, this.element.value.length );
};
Caret.prototype.selected = function() {
return this.element.value.substring( this.start, this.end );
};
/**
* Inserts a value at the cursor.
*/
Caret.prototype.insert = function( value ) {
// W3C
if ( typeof this.element.selectionStart !== 'undefined' ) {
this.element.value = this.before() + value + this.after();
// IE
} else if ( document.selection ) {
this.element.focus();
document.selection.createRange().text = value;
}
};
/**
* Replaces the current word before the cursor with a value.
*
* @param value The value to insert.
* @param options Optional.
* before - Default true.
* boolean - Whether to replace the word before the cursor.
* RegExp - The RegExp to use before the cursor.
* after - Default false.
* boolean - Whether to replace the word after the cursor.
* RegExp - The RegExp to use after the cursor.
*/
Caret.prototype.replace = function( value, options ) {
var rbefore, rafter, before = this.before(), after = this.after();
options = options || {};
rbefore = options.before;
rafter = ( options.after === true ) ? rWordStart : options.after;
if ( typeof rbefore === 'undefined' || rbefore === true )
rbefore = rWordEnd;
if ( rbefore )
before = before.replace( rbefore, '' );
if ( rafter )
after = after.replace( rafter, '' );
this.element.value = before + value + after;
this.set( before.length + value.length );
};
})();