/** * 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.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"); } } }); });