/****************************************************
* Created by Subhrajit Bhattacharya [[User:Subh83]] *
* Licensed under GNU-GPL v3.0 *
*****************************************************/
var UserSubh83_utilsDOMdynamics = true;
// ================================================================
/*** DOM traversal/search utils ***/
function FindNodeUpLeftTree(elemin, tagnames) {
// Given an element 'elemin', the function finds the first node with
// tag name in array 'tagnames' that is either a previous sibling,
// or a previous sibling of of any ancestor.
var elem = elemin;
for (var j=0; j<tagnames.length; j++) tagnames[j] = tagnames[j].toLowerCase();
var prevelem;
for (var i=0;i<=10000;i++) {
if (elem.previousSibling)
prevelem = elem.previousSibling;
else if (elem.parentNode)
prevelem = elem.parentNode;
if (!prevelem.tagName) {
elem = prevelem;
continue;
}
if (prevelem) {
var tn = prevelem.tagName.toLowerCase();
for (var j=0; j<tagnames.length; j++)
if (tn==tagnames[j])
return prevelem;
elem = prevelem;
} else
return false;
}
}
function FindNodeUpTree(elemin, tagnames) {
// Given an element 'elemin', the function finds an ancestor with tag from 'tagnames'
var elem = elemin;
for (var j=0; j<tagnames.length; j++) tagnames[j] = tagnames[j].toLowerCase();
var prevelem;
for (var i=0;i<=10000;i++) {
if (elem.parentNode)
prevelem = elem.parentNode;
if (!prevelem.tagName) {
elem = prevelem;
continue;
}
if (prevelem) {
var tn = prevelem.tagName.toLowerCase();
for (var j=0; j<tagnames.length; j++)
if (tn==tagnames[j])
return prevelem;
elem = prevelem;
} else
return false;
}
}
// Wikipedia specific: For finding the edit section corresponding to a paragraph
function GetPrevEditsectionLinkElement(elem) {
// Traverse the DOM tree upwards until a 'h' element is encountered
var hElem = FindNodeUpLeftTree(elem, ['h1','h2','h3','h4','h5','h6']);
// Return the 'a' in it
if (hElem) {
var hElemAs = hElem.getElementsByTagName("a");
if (hElemAs && hElemAs.length>0)
return hElemAs[0];
}
return false;
}
// ================================================================
/*** Poistioning/display utils ***/
function setMenuPosition (e, menudiv) {
// Position 'menudiv' at mouse pointer position.
var posx = e.clientX;
var posy = e.clientY;
var w, h;
if (document.body && document.body.offsetWidth) {
w = document.body.offsetWidth;
h = document.body.offsetHeight;
}
if (document.compatMode=='CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth ) {
w = document.documentElement.offsetWidth;
h = document.documentElement.offsetHeight;
}
if (window.innerWidth && window.innerHeight) {
w = window.innerWidth;
h = window.innerHeight;
}
menudiv.style.position = "fixed";
if (posx < w/2) {
menudiv.style.left = posx+"px";
menudiv.style.pixelLeft = posx+"px";
menudiv.style.right = "auto";
menudiv.style.pixelRight = "auto";
} else {
menudiv.style.right = (w-posx)+"px";
menudiv.style.pixelRight = (w-posx)+"px";
menudiv.style.left = "auto";
menudiv.style.pixelLeft = "auto";
}
if (posy < h/2) {
menudiv.style.top = posy+"px";
menudiv.style.pixelTop = posy+"px";
menudiv.style.bottom = "auto";
menudiv.style.pixelBottom = "auto";
} else {
menudiv.style.bottom = (h-posy)+"px";
menudiv.style.pixelBottom = (h-posy)+"px";
menudiv.style.top = "auto";
menudiv.style.pixelTop = "auto";
}
}
function ToggleElementDisplay(divID) {
var theElem = document.getElementById(divID);
if (theElem) {
if (theElem.style.display=='none') { theElem.style.display='block'; return 1; }
else { theElem.style.display='none'; return 0; }
}
}
// ================================================================
/*** Textarea, textbox selection & editing utils ***/
function selectRangeInTextarea(ctrl, start, end, autoscroll) {
if(ctrl.setSelectionRange) {
ctrl.focus();
ctrl.setSelectionRange(start, end);
}
else if (ctrl.createTextRange) {
var range = ctrl.createTextRange();
range.collapse(true);
range.moveStart('character', start);
range.moveEnd('character', end);
range.select();
}
if (typeof(autoscroll)=='undefined') autoscroll = true;
if(autoscroll)
ctrl.scrollTop = findScrollTopFromPos(ctrl, start, 2);
ctrl.focus();
}
function findScrollTopFromPos(ctrl, pos, topOffset) {
if(typeof(topOffset)=='undefined') topOffset = 0;
var reducingtext = ctrl.value;
reducingtext.replace(/\t/g, " ").replace(/\r\n|\n\r/g, "\n").replace(/\r/g, "\n");
var ColsNo = getTextareaNumberOfColumns(ctrl);
var LineRegexS = "^.{0,"+ColsNo+"}?\\n|^.{0,"+ColsNo+"}\\s|.{0,"+ColsNo+"}";
var LineRegex = new RegExp(LineRegexS);
var LineCount=0, CharCount=0, LinePos=0;
while (CharCount<(ctrl.value.length-ColsNo-1)) {
line = reducingtext.match(LineRegex);
CharCount += line[0].length;
if (CharCount<=pos) LinePos = LineCount;
LineCount++;
reducingtext = reducingtext.substring(line[0].length);
}
return parseInt( ctrl.scrollHeight * Math.min(1,Math.max(0, ((LinePos-topOffset)/LineCount) )) );
}
function getTextareaNumberOfColumns(ctrl) {
var fullWidth = ctrl.clientWidth;
ctrl.style.width = 'auto';
while(ctrl.clientWidth < fullWidth) {
ctrl.cols = ctrl.cols + 1;
}
while (ctrl.clientWidth > fullWidth) {
ctrl.cols = ctrl.cols - 1;
}
return(ctrl.cols);
}
function getSelectionInTextarea(ctrl) {
var sel = new Object();
if(ctrl.selectionStart) {
sel.start = ctrl.selectionStart;
sel.end = ctrl.selectionEnd;
}
else if (document.selection) {
var textRange = document.selection.createRange();
sel.start = textRange.startOffset;
sel.end = textRange.endOffset;
}
if (typeof(sel.start)!='undefined') {
sel.text = ctrl.value.substring(sel.start, sel.end);
return sel;
}
else {
sel.start = 0;
sel.end = 0;
sel.text = 0;
}
return sel;
}
function updateSelectionInTextarea(ctrl, newtext, sel, newSelectionStartOffset, newSelectionLength) {
if (typeof(sel)=='undefined') sel = getSelectionInTextarea(ctrl);
var newcontent = ctrl.value.substring(0, sel.start) + newtext + ctrl.value.substring(sel.end);
ctrl.value = newcontent;
var retsel = new Object();
if(typeof(newSelectionStartOffset)=='undefined') newSelectionStartOffset = 0;
if(typeof(newSelectionLength)=='undefined') newSelectionLength = newtext.length;
retsel.start = sel.start + newSelectionStartOffset;
retsel.end = sel.start + newSelectionStartOffset + newSelectionLength;
retsel.text = newtext.substr(newSelectionStartOffset, newSelectionLength);
return retsel;
}
// ================================================================
/*** Event handling utils ***/
function AppendHandlerToEvent(theevent, newhandler, position, condition, finalEvalS) {
// 'theevent' is a string. 'newhandler' is a function name or a string.
// position is 'post' (default) or 'pre'
// If 'condition' is provided, the function that is evaluated first must
// return the value of the 'condition' for the next function to be evaluated.
// 'finalEvalS' is a string to be evaluated at the end of the combined handler execution.
// This is required for passing signals to browser's native handlers. It can contain
// variables 'retOld' and 'retNew'.
if (typeof(position)=='undefined') position='post';
if (typeof(finalEvalS)=='undefined') finalEvalS="";
eval("var oldhandler = " + theevent);
var evalStartS = theevent + " = function(e) { ";
var oldEvalS = " if (oldhandler) { " +
" if (typeof(oldhandler)=='string') eval('r='+oldhandler); " +
" else r = oldhandler(e); " +
" retOld = r; " +
" } ";
var condStartS = ""; condEndS = "";
if (typeof(condition)!='undefined') { condStartS = " if (r===condition) {"; condEndS = "}"; }
var newEvalS = " if (typeof(newhandler)=='string') eval('r='+newhandler); " +
" else r = newhandler(e); " +
" retNew = r; ";
var evalEndS = finalEvalS + " } ";
if (position == 'post') var evalS = evalStartS + oldEvalS + condStartS + newEvalS + condEndS + evalEndS;
else if (position == 'pre') var evalS = evalStartS + newEvalS + condStartS + oldEvalS + condEndS + evalEndS;
eval(evalS);
}