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