User:V111P/js/valSel.js
Appearance
< User:V111P | js
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:V111P/js/valSel. |
/* valSel.js
* ver. 2013-10
*
* A cross-browser textarea and text input value and selection manipulation
* library plug-in for jQuery
* Home: http://en.wikipedia.org/wiki/User:V111P/js/valSel
*
* This script contains code from Rangy Text Inputs (Version from 5 November 2010),
* Copyright 2010, Tim Down, licensed under the MIT license.
* http://code.google.com/p/rangyinputs/
*
* You can use the code not from Rangy Text Inputs under the CC0 license
*/
(function($) {
var UNDEF = "undefined";
var getSelection, setSelection, collapseSelection;
var inited; // whether init() has already been called or not
var rReG = /\r/g;
// Trio of isHost* functions taken from Peter Michaux's article:
// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
function isHostMethod(object, property) {
var t = typeof object[property];
return t === "function" || (!!(t == "object" && object[property])) || t == "unknown";
}
function isHostProperty(object, property) {
return typeof(object[property]) != UNDEF;
}
function isHostObject(object, property) {
return !!(typeof(object[property]) == "object" && object[property]);
}
function fail(reason) {
if (window.console && window.console.error) {
window.console.error("valSel.js: Unsupported browser: " + reason);
}
}
function adjustOffsets(el, start, end) {
var len = el.value.replace(rReG, '').length;
start = (start > 0 ? start : 0);
start = (start < len ? start : len);
if (typeof end == UNDEF)
end = start;
else {
end = (end > 0 ? end : 0);
end = (end < len ? end : len);
}
if (end < start) {
var t = start;
start = end;
end = t;
}
return { start: start, end: end };
}
function makeSelection(normalizedValue, start, end) {
return {
start: start,
end: end,
length: end - start,
text: normalizedValue.slice(start, end)
};
}
function getBody() {
return isHostObject(document, "body") ? document.body : document.getElementsByTagName("body")[0];
}
function init() {
if (inited)
return;
var testTextArea = document.createElement("textarea");
getBody().appendChild(testTextArea);
if (isHostProperty(testTextArea, "selectionStart") && isHostProperty(testTextArea, "selectionEnd")) {
getSelection = function(el) {
var start = el.selectionStart, end = el.selectionEnd;
return makeSelection(el.value.replace(rReG, ''), start, end);
};
setSelection = function(el, startOffset, endOffset) {
var offsets = adjustOffsets(el, startOffset, endOffset);
el.selectionStart = offsets.start;
el.selectionEnd = offsets.end;
};
collapseSelection = function(el, toStart) {
if (toStart) {
el.selectionEnd = el.selectionStart;
} else {
el.selectionStart = el.selectionEnd;
}
};
} else if (isHostMethod(testTextArea, "createTextRange") && isHostObject(document, "selection")
&& isHostMethod(document.selection, "createRange")) {
getSelection = function(el) {
var start = 0, end = 0, range, normalizedValue = '', textInputRange, len, endRange;
el.focus();
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(rReG, "");
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
}
}
}
return makeSelection(normalizedValue, start, end);
};
// Moving across a line break only counts as moving one character in a TextRange,
// whereas a line break in the textarea value is two characters.
// This function corrects for that by converting a text offset into a range character offset
// by subtracting one character for every line break in the textarea prior to the offset
var offsetToRangeCharacterMove = function(el, offset) {
return offset;// - (el.value.slice(0, offset).split("\r\n").length - 1);
};
setSelection = function(el, startOffset, endOffset) {
var offsets = adjustOffsets(el, startOffset, endOffset);
var range = el.createTextRange();
var startCharMove = offsetToRangeCharacterMove(el, offsets.start);
range.collapse(true);
if (offsets.start == offsets.end) {
range.move("character", startCharMove);
} else {
range.moveEnd("character", offsetToRangeCharacterMove(el, offsets.end));
range.moveStart("character", startCharMove);
}
range.select();
};
collapseSelection = function(el, toStart) {
var range = document.selection.createRange();
range.collapse(toStart);
range.select();
};
} else {
getBody().removeChild(testTextArea);
fail("No means of finding text input caret position");
return;
}
// Clean up
getBody().removeChild(testTextArea);
inited = true;
} // init
// the functions always automatically return this
// if they don't otherwise return a result
function jQuerify(func) {
return function() {
var el = this.jquery ? this[0] : this;
var nodeName = el.nodeName.toLowerCase();
if (el.nodeType == 1 && (nodeName == "textarea"
|| (nodeName == "input" && el.type == "text"))) {
if (!inited) init(); // because $(init) won't work after an error from another script
var args = [el].concat(Array.prototype.slice.call(arguments));
var result = func.apply(this, args);
if (typeof result != 'undefined') {
return result;
}
}
return this;
};
}
/* Rangy Text Inputs code ends */
function getValue(el) {
return el.value.replace(rReG, ''); // remove \r
}
function setValue(el, val) {
var scrollPosObj = scrollPos(el);
el.value = val;
scrollPos(el, scrollPosObj);
}
function scrollPos(el, scrollPosObj) {
if (scrollPosObj) {
el.scrollTop = scrollPosObj.top;
el.scrollLeft = scrollPosObj.left;
}
else {
return {
top: el.scrollTop,
left: el.scrollLeft
};
}
}
var valParts = function (el, arg1, selText, textAfter) {
var parts;
var setValParts = function (el, parts) {
setValue(el, parts.join(''));
var beforeLen = parts[0].length;
setSelection(el, beforeLen, beforeLen + parts[1].length);
}
if (typeof arg1 == 'object') {
parts = arg1;
}
else if (typeof arg1 == 'function') {
}
else if (typeof arg1 == 'string') {
parts = [arg1, selText, textAfter];
}
if (parts) {
setValParts(el, parts);
return;
}
else {
var s = getSelection(el);
var text = getValue(el);
parts = [text.slice(0, s.start), s.text, text.slice(s.end)];
if (typeof arg1 == 'function') {
var parts = arg1(parts[0], parts[1], parts[2], text.length);
if (parts)
setValParts(el, parts);
return;
}
return parts;
}
} // valParts
var sel = function (el, arg1, arg2) {
var sel;
var setSel = function (sel) {
if (typeof sel.start == 'number') {
if (typeof sel.end != 'number')
sel.end = sel.start;
if (typeof sel.text == 'string')
setValue(sel.text);
setSelection(el, sel.start, sel.end);
}
else if (typeof sel.text == 'string') {
valParts(el, function (pre, currSel, post) {
var replacementSel = sel.text;
if (collapse < 0) {
post = replacementSel + post;
replacementSel = '';
}
else if (collapse > 0) {
post += replacementSel;
replacementSel = '';
}
return [pre, replacementSel, post];
});
}
}
if (typeof arg1 == 'undefined') {
return getSelection(el);
}
switch (typeof arg1) {
case 'function':
var selObj = getSelection(el);
sel = arg1(selObj.text, selObj.start, selObj.end, selObj.length);
if (typeof sel == 'string')
sel = {text: sel};
if (typeof sel == 'object')
setSel(sel);
break;
case 'string':
var collapse = (typeof arg2 == 'number' ? arg2 : 0);
setSel({text: arg1, collapse: arg2});
break;
case 'number':
var start = arg1, end = arg2;
setSelection(el, start, end);
break;
}
} // sel
var aroundSel = function (el) {
var a = arguments;
var before = a[1];
var after, include, collapse;
var excludedBefore = '', excludedAfter = '';
if (typeof before != 'string')
return this; // error - do nothing
if (typeof a[2] != 'string') {
// aroundSel(string surround, [bool include, [int collapse]])
after = before;
include = a[2];
collapse = a[3];
}
else if (typeof a[3] != 'string') {
// aroundSel(string before, string after, [bool include, [int collapse]])
after = a[2];
include = a[3];
collapse = a[4];
}
else {
// aroundSel(string before, string prepend, string append, string after, [int collapse])
excludedBefore = before;
before = a[2];
after = a[3];
excludedAfter = a[4];
collapse = a[5];
include = true;
}
include = (typeof include == 'boolean' ? include : true);
if (collapse === true)
collapse = 1;
else if (typeof collapse != 'number')
collapse = 0;
valParts(el, function (pre, sel, post) {
if (include)
sel = before + sel + after;
else {
pre = pre + before;
post = after + post;
}
if (collapse < 0) {
post = sel + post;
sel = '';
}
else if (collapse > 0) {
pre += sel;
sel = '';
}
return [pre, sel, post];
});
} // aroundSel
$.fn.extend({
valParts: jQuerify(valParts),
sel: jQuerify(sel),
aroundSel: jQuerify(aroundSel),
collapseSel: jQuerify(collapseSelection)
});
$(init);
})(jQuery);