jquery-textrange
Version:
A jQuery plugin for getting, setting and replacing the selected text in input fields and textareas.
258 lines (214 loc) • 6.42 kB
JavaScript
/**
* jquery-textrange
*
* A jQuery plugin for getting, setting and replacing the selected text in input fields and textareas.
* See the [README](https://github.com/dwieeb/jquery-textrange/blob/1.x/README.md) for usage and examples.
*
* (c) 2012-2017 Daniel Imhoff <dwieeb@gmail.com> - dwieeb.com
*/
(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof exports === 'object') {
factory(require('jquery'));
} else {
factory(jQuery);
}
})(function($) {
var browserType,
textrange = {
/**
* $().textrange() or $().textrange('get')
*
* Retrieves an object containing the start and end location of the text range, the length of the range and the
* substring of the range.
*
* @param (optional) property
* @return An object of properties including position, start, end, length, and text or a specific property.
*/
get: function(property) {
return _textrange[browserType].get.apply(this, [property]);
},
/**
* $().textrange('set')
*
* Sets the selected text of an object by specifying the start and length of the selection.
*
* The start and length parameters are identical to PHP's substr() function with the following changes:
* - excluding start will select all the text in the field.
* - passing 0 for length will set the cursor at start. See $().textrange('setcursor')
*
* @param (optional) start
* @param (optional) length
*
* @see https://secure.php.net/manual/en/function.substr.php
*/
set: function(start, length) {
var s = parseInt(start),
l = parseInt(length),
e;
if (typeof start === 'undefined') {
s = 0;
} else if (start < 0) {
s = this[0].value.length + s;
}
if (typeof length !== 'undefined') {
if (length >= 0) {
e = s + l;
} else {
e = this[0].value.length + l;
}
}
_textrange[browserType].set.apply(this, [s, e]);
return this;
},
/**
* $().textrange('setcursor')
*
* Sets the cursor at a position of the text field.
*
* @param position
*/
setcursor: function(position) {
return this.textrange('set', position, 0);
},
/**
* $().textrange('replace')
* Replaces the selected text in the input field or textarea with text.
*
* @param text The text to replace the selection with.
*/
replace: function(text) {
_textrange[browserType].replace.apply(this, [String(text)]);
return this;
},
/**
* Alias for $().textrange('replace')
*/
insert: function(text) {
return this.textrange('replace', text);
}
},
_textrange = {
xul: {
get: function(property) {
var props = {
position: this[0].selectionStart,
start: this[0].selectionStart,
end: this[0].selectionEnd,
length: this[0].selectionEnd - this[0].selectionStart,
text: this.val().substring(this[0].selectionStart, this[0].selectionEnd)
};
return typeof property === 'undefined' ? props : props[property];
},
set: function(start, end) {
if (typeof end === 'undefined') {
end = this[0].value.length;
}
this[0].selectionStart = start;
this[0].selectionEnd = end;
},
replace: function(text) {
var start = this[0].selectionStart;
var end = this[0].selectionEnd;
var val = this.val();
this.val(val.substring(0, start) + text + val.substring(end, val.length));
this[0].selectionStart = start;
this[0].selectionEnd = start + text.length;
}
},
msie: {
get: function(property) {
var range = document.selection.createRange();
if (typeof range === 'undefined') {
var props = {
position: 0,
start: 0,
end: this.val().length,
length: this.val().length,
text: this.val()
};
return typeof property === 'undefined' ? props : props[property];
}
var start = 0;
var end = 0;
var length = this[0].value.length;
var lfValue = this[0].value.replace(/\r\n/g, '\n');
var rangeText = this[0].createTextRange();
var rangeTextEnd = this[0].createTextRange();
rangeText.moveToBookmark(range.getBookmark());
rangeTextEnd.collapse(false);
if (rangeText.compareEndPoints('StartToEnd', rangeTextEnd) === -1) {
start = -rangeText.moveStart('character', -length);
start += lfValue.slice(0, start).split('\n').length - 1;
if (rangeText.compareEndPoints('EndToEnd', rangeTextEnd) === -1) {
end = -rangeText.moveEnd('character', -length);
end += lfValue.slice(0, end).split('\n').length - 1;
} else {
end = length;
}
} else {
start = length;
end = length;
}
var props = {
position: start,
start: start,
end: end,
length: length,
text: range.text
};
return typeof property === 'undefined' ? props : props[property];
},
set: function(start, end) {
var range = this[0].createTextRange();
if (typeof range === 'undefined') {
return;
}
if (typeof end === 'undefined') {
end = this[0].value.length;
}
var ieStart = start - (this[0].value.slice(0, start).split("\r\n").length - 1);
var ieEnd = end - (this[0].value.slice(0, end).split("\r\n").length - 1);
range.collapse(true);
range.moveEnd('character', ieEnd);
range.moveStart('character', ieStart);
range.select();
},
replace: function(text) {
document.selection.createRange().text = text;
}
}
};
$.fn.extend({
textrange: function(arg) {
var method = 'get';
var options = {};
if (typeof this[0] === 'undefined') {
return this;
}
if (typeof arg === 'string') {
method = arg;
} else if (typeof arg === 'object') {
method = arg.method || method;
options = arg;
}
if (typeof browserType === 'undefined') {
browserType = 'selectionStart' in this[0] ? 'xul' : document.selection ? 'msie' : 'unknown';
}
// I don't know how to support this browser. :c
if (browserType === 'unknown') {
return this;
}
// Focus on the element before operating upon it.
if (!options.nofocus && document.activeElement !== this[0]) {
this[0].focus();
}
if (typeof textrange[method] === 'function') {
return textrange[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else {
$.error("Method " + method + " does not exist in jQuery.textrange");
}
}
});
});