How to use clearKeyEvents method in Appium Android Driver

Best JavaScript code snippet using appium-android-driver

Generic.js

Source:Generic.js Github

copy

Full Screen

1var _formName = "form1";2var _currentBusyDiv = "";3var _keyEvents = new Array();4var isdrag=false;5var x = 0,y = 0;6var dobj;7var cobj;8var bobj;9var bx = 0, by = 0;10var cx = 0, cy = 0;11var _popEvents = new Array();12var popupControls = new Array();13var _pagePath;14//XML FIX15var BrowserIE = (window.navigator.userAgent.indexOf("MSIE") > 0); //Must be declared here;16if (document.implementation.hasFeature("XPath", "3.0") && !BrowserIE)17{18    if (typeof XMLDocument == "undefined") { XMLDocument = Document; }19    XMLDocument.prototype.selectNodes = function(cXPathString, xNode)20    {21        if (!xNode) { xNode = this; }22        var oNSResolver = this.createNSResolver(this.documentElement)23        var aItems = this.evaluate(cXPathString, xNode, oNSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)24        var aResult = [];25        for (var i = 0; i < aItems.snapshotLength; i++) { aResult[i] = aItems.snapshotItem(i); }26        return aResult;27    }28    XMLDocument.prototype.selectSingleNode = function(cXPathString, xNode)29    {30        if (!xNode) { xNode = this; }31        var xItems = this.selectNodes(cXPathString, xNode);32        if (xItems.length > 0) { return xItems[0]; }33        else { return null; }34    }35    Element.prototype.selectNodes = function(cXPathString)36    {37        if (this.ownerDocument.selectNodes) { return this.ownerDocument.selectNodes(cXPathString, this); }38        else { throw "For XML Elements Only"; }39    }40    Element.prototype.selectSingleNode = function(cXPathString)41    {42        if (this.ownerDocument.selectSingleNode) { return this.ownerDocument.selectSingleNode(cXPathString, this); }43        else { throw "For XML Elements Only"; }44    }45    Element.prototype.__defineGetter__("text",46              function() { return (this.textContent); });47    Element.prototype.__defineSetter__("text",48              function(txt) { this.textContent = txt; });49}50//multi Nodes for xpath 51//old name executeXpathSelectNodes;52function $mn(xmlDocument, xp)53{54    var ResultNodes = xmlDocument.selectNodes(xp);55    return ResultNodes;56}57//Single Node for xpath58//old name executeXpathSingleNode59function $sn(xmlDocument, xp)60{61    var ResultNode = xmlDocument.selectSingleNode(xp);62    return ResultNode;63}64//END XML FIX 65function ActivateGlobalKeys(DivId)66{67    if (DivId != "document")68    {69        $addEvent($id(DivId),"keydown",ExecuteKeyPressEvent);70    }71    else72    {73        $addEvent(document,"keydown",ExecuteKeyPressEvent);74    }75    ClearKeyEvents(); 76}77function AddKeyEvents(Key,Event,Cntrl,DivId)78{79    var cntrl = false;80    81    if (Cntrl != null)82    {83        cntrl = Cntrl;84    }85    86    if (DivId != null)87    {88        ActivateGlobalKeys(DivId)89    }90    _keyEvents[Key] = Event + "|" + cntrl;91}92function ClearKeyEvents()93{94    _keyEvents = new Array();95}96function Key_size(Keys){97    var size = 0;98    for (var i in Keys) {99        if (_keyEvents[i] != null) 100            size ++;101    }102    return size;103}104function GetKeyPressed(e)105{106    if (!e) 107    {108        if (window.event) 109        {110            //Internet Explorer111            e = window.event;112        } 113        else 114        {115            return;116        }117    }118  119    if (typeof( e.keyCode ) == 'number') 120    {121        //DOM122        e = e.keyCode;123    } 124    else if( typeof( e.which ) == 'number' ) 125    {126        //NS 4 compatible127        e = e.which;128    } 129    else if( typeof( e.charCode ) == 'number'  ) 130    {131        //also NS 6+, Mozilla 0.9+132        e = e.charCode;133    } 134    else 135    {136        //total failure, we have no way of obtaining the key code137        return;138    }139    return e;140}141function CheckCtrlKey(e)142{143    var ctrlKeyPressed = false;144    if (!e) 145    {146        if (window.event) 147        {148            //Internet Explorer149            e = window.event;150        } 151        else 152        {153            return;154        }155    }156  157    try158    {159        ctrlKeyPressed =  e.ctrlKey;160    }161    catch(ex)162    {}163    return ctrlKeyPressed;164}165function ExecuteKeyPressEvent(e) 166{167    var validKey = false;168    if (parseInt(Key_size(_keyEvents)) != 0)169    {170        var keypressed = GetKeyPressed(e);171        var ctrlpressed = CheckCtrlKey(e);172        if (_keyEvents[keypressed]) 173        {174            try175            {176                if (_keyEvents[keypressed].split("|")[1] == "true")177                {178                    if (ctrlpressed)179                    {180                        validKey = true; 181                    }182                }183                else184                {185                    validKey = true;186                }187                if (validKey)188                {189                    eval(_keyEvents[keypressed].split("|")[0]);190                    return false;191                }192            }193            catch(ex)194            {}195        }196    }197}198function ExecuteKeyPressEventPopUp(e)199{200    if (parseInt(Key_size(_popEvents)) != 0)201    {202        var keypressed = GetKeyPressed(e) 203        if (_popEvents[keypressed]) 204        {205            try206            {207                eval(_popEvents[keypressed]);208            }209            catch(ex)210            {}211            return false;212        }213    }214}215//document.getElementByID216function $id(id) 217{218	return document.getElementById(id);219}220function $tn(id)221{222    return document.getElementsByName(id);223}224 225// evaluateXPath226// $xpath227function $xpath(aNode, aExpr) 228{229	var xpe = new XPathEvaluator();230	var nsResolver = xpe.createNSResolver(aNode.ownerDocument == null ? aNode.documentElement : aNode.ownerDocument.documentElement);231	var result = aNode.evaluate(aExpr, aNode, null, 0, null);232	var found = [];233	var res;234	while (res = result.iterateNext())235	{236		found.push(res);237    }238	return found;239}240function $SingleNodeMoz(aNode,sXPath)241{242	var xpe = new XPathEvaluator();243    var oResult = xpe.evaluate(sXPath, aNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);244    //weird.. oResult is always object..245    if(oResult !=null)246    {247        if(oResult.singleNodeValue != null)248        {249            return oResult;250        }251        else252        {253           return null;254        }255    }256    else257    {258        return null;259    }260    /*if (oResult != null) 261    {262		return oResult;263    } 264    else 265    {266		return null;267    }  */   268}269//create Xml document270//createXMLObject is the old name271function $xml(xmlToLoad)272{273	var xmldoc;274    if (document.implementation && document.implementation.createDocument) 275	{276		var oXML = xmlToLoad;277		var parser = new DOMParser();278		var xmldoc = parser.parseFromString(oXML, "text/xml");279	} 280	else if (window.ActiveXObject) 281    {282		xmldoc = new ActiveXObject("Microsoft.XMLDOM");283        if(xmlToLoad != "")284        {285			xmldoc.loadXML(xmlToLoad);286		} 287	}288	return xmldoc;289}290//get Attribute for xml node 291//pass the xml node  <node surname="">292//AttrToGet to get , ex surname293function $xa(xmlNode,AttrToGet)294{295	if(BrowserIE)296    {297		if(xmlNode !=null)298        {299			return xmlNode.getAttribute(AttrToGet);300        }301        else302        {303			return null;304        }305	}306    else307    {308		//return xmlNode.singleNodeValue.attributes[AttrToGet].nodeValue309	    if(xmlNode == null)310	    {311	        return null;312	    }313	    if(xmlNode.toString() == "[object XPathResult]")314	    {315	    316	        if(xmlNode.singleNodeValue.nodeValue == null)317	        {318	            return null;319	        }320	        else321	        {322	            return xmlNode.singleNodeValue.attributes[AttrToGet].nodeValue;323	        }324	    }325	    else326	    {327	        if(xmlNode.attributes[AttrToGet] == null)328	        {329	            return null;330	        }331	        else332	        {333	            return xmlNode.attributes[AttrToGet].nodeValue;334	        }335	    }336	}337}338//get Attribute for xml node 339//pass the xml node  <node surname="">340//AttrToGet to get , ex surname341function $xaparent(xmlNode,AttrToGet)342{343	if(BrowserIE)344    {345		if(xmlNode !=null)346        {347			return xmlNode.parentNode.getAttribute(AttrToGet);348		}349        else350        {351			return null;352		}353	}354    else355    {356		return xmlNode.singleNodeValue.parentNode.attributes[AttrToGet].nodeValue357    }358}359// old name getTextFromXmlNodeSingle360//returns text from single node 361function $xt(XmlNode)362{363    var ret = "";364    if(BrowserIE)365    {366        ret = XmlNode.childNodes[0].nodeValue;367    }368    else369    {370        ret = XmlNode.singleNodeValue.textContent ; //XmlNode[0].childNodes[0].nodeValue;371    }372    return ret;373}  374// old name replace375// replaces text in a string376function $rep(string, text, by) 377{378    // Replaces text with by in string379    var strLength = string.length;380    var txtLength = text.length;381    382    if ((strLength == 0) || (txtLength == 0)) 383        return string;384    var i = string.indexOf(text);385    386    if ((!i) && (text != string.substring(0, txtLength))) 387        return string;388        389    if (i == -1) 390        return string;391    var newstr = string.substring(0, i) + by;392    if (i + txtLength < strLength)393        newstr += $rep(string.substring(i + txtLength, strLength), text, by);394    return newstr;395}396function $togglePopUp(div, frame, viewState, widthType)397{398	var state = false;399    var IfrRef = $id(frame);400    401   if (IfrRef == null) 402   {403        return;404   }405    IfrRef.style.display = "none";  406    407    div.style.zIndex = 1001;408   	409    if (viewState == "") 410    {411	    if (div.style.display == "none") 412	    {413		    state = true;414	    } 415	    else 416	    {417		    state = false;418	    }    419    }420    else421    {422        if (viewState == "none")423        {424		    state = false;        425        }426        else427        {428	        if (div.style.display == "none") 429	        {430		        state = true;431	        } 432	        else 433	        {434		        state = false;435	        }            436        }437    }438   	if(state)439   	{440        div.style.display = "block";441        if (widthType)442        {443            IfrRef.style.width = div.style.width;444    	    IfrRef.style.height = div.style.height;445    	}446    	else447    	{448    	    IfrRef.style.width = div.clientWidth;449    	    IfrRef.style.height = div.clientHeight;450    	}451    	IfrRef.style.top = div.offsetTop;452    	IfrRef.style.left = div.offsetLeft;453    	IfrRef.style.zIndex = div.style.zIndex - 1;454    	IfrRef.style.display = "block";455    }456   	else457   	{458        div.style.display = "none";459    	IfrRef.style.display = "none";460    	IfrRef.style.width = "0px";461    	IfrRef.style.height = "0px";462    	IfrRef.style.top = 0;463    	IfrRef.style.left = 0;464  	}465}466//popupdiv for view467function doViewPopup(headingText, contentText, viewID)468{469//    busyDivTag();470//    var HeadingText = headingText;471//    var ContentText = contentText;472    var viewText = $id(viewID);473    var viewHeight = viewText.childNodes[0].childNodes[0].offsetHeight;474    var viewWidth = viewText.childNodes[0].childNodes[0].offsetWidth;475    476    if  ((viewHeight == 0) && (viewWidth == 0))477    {478		viewText.style.display = "";479		viewHeight = viewText.childNodes[0].childNodes[0].offsetHeight;480		viewWidth = viewText.childNodes[0].childNodes[0].offsetWidth;481		viewText.style.display = "none";482    }483   484     if  (viewWidth < 500)485    {486        var maintbl  = ReplaceID(viewID, "part_","maintbl_");487        ($id(maintbl)).width = "500px"; 488		viewText.style.display = "";489		viewWidth = viewText.childNodes[0].childNodes[0].offsetWidth;490		viewText.style.width = "500px";491		viewText.style.display = "none";492    } 493//            494//    var screenL = window.screen.availWidth - viewWidth;495//    var screenH = window.screen.availHeight - viewHeight;496//    var top = (screenH/3) +  parseInt(returnScrollDimensions(0)); 497//    var left = (screenL/2) + parseInt(returnScrollDimensions(1));498//    var newDiv = false;499//    var st = "top:" + (parseInt(top) - 40) + "px;z-index:9018;position:absolute;left:" + (parseInt(left) - 50) + "px;width:" + (viewWidth) + "px;height:" + (viewHeight) + "px";500//    501//    viewText.style.cssText = st;502//    503//    var divAlert = "";504//    var divExists = $id("containerView");505//    if(divExists == null)506//    {507//		divAlert = document.createElement("DIV");508//		divAlert.id = "containerView";509//		divAlert.className="dragme";510//        divAlert.attachEvent("onmousedown",selectmouse);511//        divAlert.attachEvent("onmouseup",new Function("isdrag=false"));512//		newDiv= true;513//    }514//    else515//    {516//		newDiv = false;517//		divAlert = test;518//    }519//    520//    var stDiv = "top:" + (parseInt(top) - 80) + "px;z-index:9018;position:absolute;left:" + (parseInt(left) - 60) + "px;width:" + (viewWidth+20) + "px;height:" + (viewHeight+20) + "px";521//    var stIframe = "top:" + (parseInt(top) - 70) + "px;z-index:9017;position:absolute;left:" + (parseInt(left) - 50) + "px;width:" + (viewWidth+5) + "px;height:" + (viewHeight+30) + "px;frameborder=0;";522//    523//    divAlert.style.cssText = "position:absolute;display:none;z-index:9019;" + stDiv;524//    divAlert.innerHTML += '<table id="tblContainerView" cellpadding="0" cellspacing="0" border="0"><tr><td><div id="poptl" class="poptl"></div></td><td><div id="poptc" class="poptc"><div style="font-family:Arial;padding-top:5px;color:White;font-weight:bold;">' + HeadingText + '</div></div></td><td><div id="poptr" class="poptr"></div></td></tr><tr><td><div id="popcl" class="popcl"></div></td><td align="center"><div id="popcc" class="popcc">' + ContentText + '</div></td><td><div id="popcr" class="popcr"></div></td></tr><tr><td><div id="popbl" class="popbl"></div></td><td><div id="popbc" class="popbc"></div></td><td><div id="popbr" class="popbr"></div></td></tr></table>';525//   526//    if(newDiv == true)527//    { 528//        document.body.appendChild(divAlert);529//    }530//    531//    //add iframe532//    var ifr = $id("iframepopup");533//    var table = $id("tblContainerView");534//    var stIf = "top:" + (parseInt(top) - 80) + "px;z-index:9017;position:absolute;left:" + (parseInt(left) - 90) + "px;width:" + (viewWidth+20) + "px;height:" + (viewHeight+20) + "px";535//  536//    $DivSetVisible(true,table,ifr,stIframe);537//    ifr.frameBorder="no";538//    ifr.style.backgroundColor = "green";539//    ifr.className="dragmeIfr"540//    var thediv = "";541//    thediv = document.getElementById("containerView");542//    thediv.style.display = "block";543//    544//    document.getElementById("poptc").style.width=viewWidth+'px';545//    document.getElementById("popcc").style.width=viewWidth+'px';546//    document.getElementById("popbc").style.width=viewWidth+'px';547//    document.getElementById("popcl").style.height=viewHeight+'px';548//    document.getElementById("popcc").style.height=viewHeight+'px';549//    document.getElementById("popcr").style.height=viewHeight+'px';550 551    $showPopup(headingText, contentText, viewID, viewHeight, viewWidth, "", "closeSubForm()", "", "", "", "", "", "", "", "", "");552    showSelectSpecific(viewID);553}554function doViewHidePopup()555{556    HideDisableDiv();557    var thediv = document.getElementById("containerView");558    559    if (thediv != null && thediv != "")560    {561        thediv.style.display = "none";562        thediv.parentNode.removeChild(thediv);563    }564    565}566// Removes leading whitespaces567function $LTrim( value ) 568{569	var re = /\s*((\S+\s*)*)/;570	return value.replace(re, "$1");571}572// Removes ending whitespaces573function $RTrim( value ) 574{575	var re = /((\s*\S+)*)\s*/;576	return value.replace(re, "$1");577}578// Removes leading and ending whitespaces579function $Trim( value ) 580{581	return $LTrim($RTrim(value));582}583//popup for alert in Iframe584function doPopupIframe(headingText, contentText, twidth , theight, btnValue1, fn1, btnValue2, fn2, btnValue3, fn3,zIndexSpec,zID, extraPath, helpID, popupImage)585{586//    if (!extraPath)587//   {588//        extraPath = "";589//   } 590//    //jvz : zIndexSpec is overloaded for popups on each other591//    if(zIndexSpec=="undefined")592//    {593//        busyDivTag();594//    }595//    else596//    {597//         busyDivTag(zIndexSpec,zID);598//    }599//    var HeadingText = headingText;600//    var ContentText = contentText;601//    var divAlert = document.createElement("DIV");602//    var inpValue = "";603//    var strValue = "";604//    var screenL = document.documentElement.offsetWidth - twidth ;605//    var screenH = document.documentElement.offsetHeight - theight;606////   if (infoText.length > 0)607////	{608////	    screenH = screenH - 110;609////	}610////	else611////	{612//	    screenH = screenH - 150;613////	} 614//    var top = (screenH/3) +  parseInt(returnScrollDimensions(0)); 615//    var left = (screenL/2) + parseInt(returnScrollDimensions(1));616//    617//    618////    if (btnValue1 != "")619////    {620////        inpValue += '<input type="button" class="button" id="' + btnValue1 + '" value="' + btnValue1 + '" onclick=' + fn1 + '>&nbsp;';621////    }622////    623////    if (btnValue2 != "")624////    {625////        inpValue += '<input type="button" class="button" id="' + btnValue2 + '" value="' + btnValue2 + '" onclick=' + fn2 + '>&nbsp;';626////    }627////    628////    if (btnValue3 != "")629////    {630////        inpValue += '<input type="button" class="button" id="' + btnValue3 + '" value="' + btnValue3 + '" onclick=' + fn3 + '>';631////    }632////    633////    strValue = inpValue;634// 635    var buttonvalues = btnValue1 + "☺" +  fn1 ;636   if (btnValue2.length > 0)637   { 638        buttonvalues += "☺" +  btnValue2 + "☺" +  fn2 ;639   } 640   if (btnValue3.length > 0)641   {642        buttonvalues += "☺" +  btnValue3 + "☺" +  fn3 ;643   }644    645//    var stDiv = "top:" + parseInt(top - 5) + "px;left:" + parseInt(left  -5) + "px;width:" + parseInt(twidth  + 10) + "px;height:" + parseInt(theight + 10) + "px;"646//    647//    divAlert.style.cssText = "position:absolute;display:none;z-index:10020;" + stDiv;648//    //divAlert.innerHTML += '<table id="tblContainer" cellpadding="0" cellspacing="0"><tr><td><div id="poptlA" class="poptl"></div></td><td><div id="poptcA" class="poptc"><div valign="middle" align="left" class="smllabelboldwhite" style="font-family:Arial;padding-top:15px;color:White;font-weight:bold;">' + HeadingText + '</div></div></td><td><div id="poptrA" class="poptr"></div></td></tr><tr><td><div id="popclA" class="popcl"></div></td><td align="center"><div id="popccA" class="popcc"><table cellspacing="0" cellpadding="0" style="font-family:Arial;padding-top:15px;font-size:12px;"><tr><td>' + ContentText + '</td></tr><tr><td align="right">' + strValue + '</td></tr></table></div></td><td><div id="popcrA" class="popcr"></div></td></tr><tr><td><div id="popblA" class="popbl"></div></td><td><div id="popbcA" class="popbc"></div></td><td><div id="popbrA" class="popbr"></div></td></tr></table>';649//   divAlert.innerHTML += generatePopupHTML('tblContainer', HeadingText, '',  ContentText, buttonvalues, theight, twidth, '', '', "","",  extraPath);650//    divAlert.className="dragme";651//    divAlert.onmousedown=selectmouse;652//    divAlert.onmouseup=new Function("isdrag=false");    653//    divAlert.id = "container";654//        655//    document.body.appendChild(divAlert);656//    657//    //add iframe658//    //var ifr = $id("iframepopup");659//    var ifr = document.createElement("IFRAME");660//    ifr.id = "iframepopups"661//    ifr.frameBorder = "0";662//    ifr.className="dragmeIfr";663//    var table = $id("tblContainer");664//    //var st = "width:" + twidth + "px; height:" + theight + "px;";665//    var st = "top:" + parseInt(top) + "px;z-index:10019;position:absolute;left:" + parseInt(left) + "px;width:" + (twidth) + "px;height:" + (theight) + "px";666//    667//    divAlert.parentElement.appendChild(ifr);668//     669//    $DivSetVisible(true,table,ifr,st);670// 671//    var thediv = document.getElementById("container");672//    thediv.style.display = "block";673//        674////    document.getElementById("poptcA").style.width=twidth+'px';675////    document.getElementById("popccA").style.width=twidth+'px';676////    document.getElementById("popbcA").style.width=twidth+'px';677////    document.getElementById("popclA").style.height=theight+'px';678////    document.getElementById("popccA").style.height=theight+'px';679////    document.getElementById("popcrA").style.height=theight+'px';680if (!popupImage)681{682    popupImage = "";683}684if (!helpID)685{686    helpID = "";687}688    $showPopup(headingText, contentText, "", theight, twidth, "", "doHidePopup()", buttonvalues, zIndexSpec, zID, extraPath, "", helpID, "", "",popupImage)689}690//folowing two functions are used to make the popups dragable691function movemouse(e)692{693    var obj = null;694    var i = true;695   var eventclientX = event.clientX;696   var eventclientY = event.clientY; 697    if (isdrag)698    {699    //checks if the window has content ie. which type of popup?700        if(dobj != null)701        {702            dobj.style.left = parseInt(tx) + parseInt(eventclientX) - parseInt(x);703            dobj.style.top  = parseInt(ty) + parseInt(eventclientY) - parseInt(y);704            obj = dobj;705         }706         else if(bobj != null)707        {708            bobj.style.left = parseInt(tx) + parseInt(eventclientX) - parseInt(x);709            bobj.style.top  = parseInt(ty) + parseInt(eventclientY) - parseInt(y);710            obj = bobj;711          }712         713         if (obj != null)714         { 715            while(i==true)716            {717                if(obj.className!="dragmeIfr")718                {719                     if (obj.nextSibling != null)720                    {721                        obj = obj.nextSibling;722                    }723                    else724                    {725                        return false;726                    }727                }728                else729                {730                    i = false;731                }732            }733            if (obj != null)734            {735                obj.style.left = parseInt(tx) + parseInt(eventclientX) - parseInt(x) +12;736                obj.style.top = parseInt(ty) + parseInt(eventclientY) - parseInt(y) +22;737            }738             if (cobj != null)739            { 740                if (isNaN(cx)) cx = 0;741                if (isNaN(cy)) cy = 0;742                         743                cobj.style.left = parseInt(cx) + parseInt(eventclientX) - parseInt(x);744                cobj.style.top = parseInt(cy) + parseInt(eventclientY) - parseInt(y);745               746            }747            return false;748        }749    }750   751}752function selectmouse(e) 753{754    cobj = popupControls[popupControls.length-1];755  var fobj = event.srcElement; 756  var topelement = "BODY";757  var aobj = event.srcElement;758  759  if ((fobj != null) && (aobj != null))760  {761      while (fobj.tagName != topelement && fobj.className!="dragme")762      {763            fobj = fobj.parentElement;764      }765      while(aobj.tagName != topelement && aobj.className!="dragmain")766      {767        aobj=aobj.parentElement;768      } 769      if (fobj.className=="dragme")770      {771        aobj=null;772        bobj=null;773        isdrag = true;774        dobj = fobj;775        tx = parseInt(dobj.style.left+0);776        ty = parseInt(dobj.style.top+0);777        x = event.clientX;778        y = event.clientY;779        if (cobj)780        {781            cx = parseInt(cobj.style.left);782            cy = parseInt(cobj.style.top);783        }784        document.onmousemove=movemouse;785        return false;786      }787      if (aobj.className == "dragmain")788      {789        fobj = null;790        dobj = null;791        bobj = aobj;792        isdrag = true;793        tx = parseInt(bobj.style.left+0);794        ty = parseInt(bobj.style.top+0);795        x = event.clientX;796        y = event.clientY;797        if (cobj)798        {799            cx = parseInt(cobj.style.left);800            cy = parseInt(cobj.style.top);801        }802        document.onmousemove=movemouse;803        return false;  804      }805    }806}807//popup for alert808function doPopup(headingText, contentText, twidth , theight, btnValue1, fn1, btnValue2, fn2, btnValue3, fn3,zIndexSpec,zID, extraPath, helpID, popupImage)809{810//    //jvz : zIndexSpec is overloaded for popups on each other811//    if(zIndexSpec=="undefined")812//    {813//        busyDivTag();814//    }815//    else816//    {817//         busyDivTag(zIndexSpec,zID);818//    }819//    var HeadingText = headingText;820//    var ContentText = contentText;821//    var divAlert ;//= document.createElement("DIV");822//    var inpValue = "";823//    var strValue = "";824//    var screenL = window.screen.availWidth - twidth ;825//    var screenH = window.screen.availHeight - theight;826//   //   if (infoText.length > 0)827////	{828////	    screenH = screenH - 110;829////	}830////	else831////	{832//	    screenH = screenH - 150;833////	}  834//    var top = (screenH/3) +  parseInt(returnScrollDimensions(0)); 835//    var left = (screenL/2) + parseInt(returnScrollDimensions(1));836//    837//    838////    if (btnValue1 != "")839////    {840////        if (fn1.split("|")[1] != null)841////        {842////            _popEvents[fn1.split("|")[1]] = fn1.split("|")[0];843////            fn1 = fn1.split("|")[0];            844////        }845////        inpValue += '<input type="button" class="button" id="' + btnValue1 + '" value="' + btnValue1 + '" onclick=' + fn1 + '>&nbsp;';846////    }847////    848////    if (btnValue2 != "")849////    {850////        if (fn2.split("|")[1] != null)851////        {852////            _popEvents[fn2.split("|")[1]] = fn2.split("|")[0];853////            fn2 = fn2.split("|")[0];            854////        }    855////        inpValue += '<input type="button" class="button" id="' + btnValue2 + '" value="' + btnValue2 + '" onclick=' + fn2 + '>&nbsp;';856////    }857////    858////    if (btnValue3 != "")859////    {860////        if (fn3.split("|")[1] != null)861////        {862////            _popEvents[fn3.split("|")[1]] = fn3.split("|")[0];863////            fn3 = fn3.split("|")[0];            864////        }    865////        inpValue += '<input type="button" class="button" id="' + btnValue3 + '" value="' + btnValue3 + '" onclick=' + fn3 + '>';866////    }867////    868////    strValue = inpValue;869//    870//    var stDiv = "top:" + parseInt(top-5) + "px;left:" + parseInt(left-5) + "px;width:" + parseInt(twidth+10) + "px;height:" + parseInt(theight+10) + "px;"871//    872//   if ($id("container"))873//   {874//        divAlert = ($id("container"));875//   }876//   else877//   {878//       divAlert = document.createElement("DIV"); 879//       divAlert.id = "container";880//       divAlert.className = "dragmain";881//       divAlert.attachEvent("onmousedown",selectmouse);882//       divAlert.attachEvent("onmouseup",new Function("isdrag=false"));883//       divAlert.attachEvent("onkeydown",ExecuteKeyPressEventPopUp);884//       document.body.appendChild(divAlert);885//   } 886//    887//    888    var buttonvalues = btnValue1 + "☺" +  fn1 ;889   if (btnValue2.length > 0)890   { 891        buttonvalues += "☺" +  btnValue2 + "☺" +  fn2 ;892   } 893   if (btnValue3.length > 0)894   {895        buttonvalues += "☺" +  btnValue3 + "☺" +  fn3 ;896   }897//    //divAlert.innerHTML = '<table id="tblContainer" cellpadding="0" cellspacing="0"><tr><td><div id="poptlA" class="poptl" /></td><td><div id="poptcA" class="poptc"><div valign="middle" align="left" class="smllabelboldwhite" style="font-family:Arial;padding-top:15px;color:White;font-weight:bold;">' + HeadingText + '</div></div></td><td><div id="poptrA" class="poptr" /></td></tr><tr><td><div id="popclA" class="popcl" /></td><td align="center"><div id="popccA" class="popcc"><table cellspacing="0" cellpadding="0" style="font-family:Arial;padding-top:2px;font-size:12px;"><tr><td><div style="overflow:auto;"><table cellspacing="0" cellpadding="0"><tr><td>' + ContentText + '</td></tr></table></div></td></tr><tr><td align="right">' + strValue + '</td></tr></table></div></td><td><div id="popcrA" class="popcr" /></td></tr><tr><td><div id="popblA" class="popbl" /></td><td><div id="popbcA" class="popbc" /></td><td><div id="popbrA" class="popbr" /></td></tr></table>';898//   divAlert.innerHTML = generatePopupHTML('tblContainer',HeadingText, '', ContentText, buttonvalues, theight, twidth, '', '');899//   divAlert.style.cssText = "position:absolute;display:none;z-index:10020;" + stDiv;900//            901//    //add iframe902//    //var ifr = $id("iframepopup");903//   var ifr;904//   if ($id("iframepopups"))905//   {906//     ifr = ($id("iframepopups"));907//   } 908//   else909//   {910//     ifr = document.createElement("IFRAME");911//     ifr.id = "iframepopups"912//     ifr.className="dragmeIfr";913//     divAlert.parentElement.appendChild(ifr);914//    }915//    ifr.frameBorder = "0";916//    var table = $id("tblContainer");917//    //var st = "width:" + twidth + "px; height:" + theight + "px;";918//    //var st = "top:" + parseInt(top + 10) + "px;z-index:10019;position:absolute;left:" + parseInt(left + 8) + "px;width:" + parseInt(twidth) + "px;height:" + parseInt(theight) + "px";919//   var st = "top:" + parseInt(top) + "px;z-index:10019;position:absolute;left:" + parseInt(left) + "px;width:" + parseInt(twidth-5) + "px;height:" + parseInt(theight-5) + "px"; 920//     921//    $DivSetVisible(true,table,ifr,st);922// 923//    var thediv = document.getElementById("container");924//    thediv.style.display = "block";925//        //divAlert.style.display = "block";926//        927////    document.getElementById("poptcA").style.width=twidth+'px';928////    document.getElementById("popccA").style.width=twidth+'px';929////    document.getElementById("popbcA").style.width=twidth+'px';930////    document.getElementById("popclA").style.height=theight+'px';931////    document.getElementById("popccA").style.height=theight+'px';932////    document.getElementById("popcrA").style.height=theight+'px';933//    divAlert.focus();934    if (!popupImage)935   {936        popupImage = "";937   } 938   if (!helpID)939   {940        helpID = "";941   }942   943   //if zIndex is specified, and the closefunction is not changed, the relevant busydiv is never hidden944   var closeFunction = "doHidePopup()";945   try946   {947       if (zID.length > 0)948       {949            closeFunction = "doHidePopup('" + zID +  "');"950       }951   }952   catch(error)953   {954   }955   956    $showPopup(headingText, contentText, "", theight, twidth, "", closeFunction, buttonvalues,   zIndexSpec, zID , extraPath,"", helpID, "", "", popupImage)       957}958function doHidePopup(ControlID, doHideSpecify)959{960    if (!ControlID)961   {962        ControlID = "";963   } 964   965   if (ControlID.length > 0)966   { 967        HideDisableDiv("busy_" + ControlID); 968        HideDisableDiv( ControlID); 969   }970   else971   { 972       HideDisableDiv();973   }974    var thediv = document.getElementById("container" + ControlID);975   if (!thediv)976   {977        ControlID = "";978        thediv = document.getElementById("container" + ControlID);979   } 980//    $removeEvent(thediv, "mousedown", selectmouse);981//    $removeEvent(thediv, "mouseup", new Function("isdrag=false"));982//    $removeEvent(thediv, "keydown", ExecuteKeyPressEventPopUp) ;   983    popupControls.pop(); 984   985//      var oldControl = popupControls[popupControls.length-1];986//      if (oldControl)987//      {988//        $addEvent(oldControl, "mousedown", selectmouse);989//        $addEvent(oldControl, "mouseup", new Function("isdrag=false"));990//        $addEvent(oldControl, "keydown", ExecuteKeyPressEventPopUp) ;  991//      992//         if ($id("container"+ oldControl.id))993//          {994//            oldControl = ($id("container"+ oldControl.id));995//            $addEvent(oldControl, "mousedown", selectmouse);996//            $addEvent(oldControl, "mouseup", new Function("isdrag=false"));997//            $addEvent(oldControl, "keydown", ExecuteKeyPressEventPopUp) ;  998//         } 999//     } 1000    1001    var ifr = window.parent.document.getElementById("iframepopups" + ControlID) != null ? window.parent.document.getElementById("iframepopups" + ControlID) : document.getElementById("iframepopups" + ControlID);1002    1003    if (thediv != null && thediv != "")1004    {1005//        var ifr = $id("iframepopup");1006//        ifr.style.display = "none";1007        var ifr = window.document.getElementById("iframepopups" + ControlID);1008        if (ifr)1009        {1010            ifr.style.display = "none";1011            ifr.parentNode.removeChild(ifr);1012        }1013        thediv.style.display = "none";1014        thediv.parentNode.removeChild(thediv);1015    }1016   1017   if (ControlID.length > 0)1018   {1019        if ($id(ControlID))1020        {1021            ($id(ControlID)).style.display = "none";1022        }1023   } 1024//   if ((doHideSpecify != "false") || (doHideSpecify == null))1025  if ((doHideSpecify != "false"))1026   {1027        hidePWait(); 1028    }1029}1030//get Scrolling values for all browsers1031function returnScrollDimensions(which) 1032{1033    //if which = 1 return x, if which = 0 return y1034    var scrOfX = 0, scrOfY = 0;1035    var d = document;1036    if( typeof( window.pageYOffset ) == 'number' ) 1037    {1038        //Netscape compliant1039        scrOfY = window.pageYOffset;1040        scrOfX = window.pageXOffset;1041    } 1042    else if ( document.body  && ( document.body.scrollLeft || document.body.scrollTop ) ) 1043    {1044        //DOM compliant1045        scrOfY = document.body.scrollTop;1046        scrOfX = document.body.scrollLeft;1047    } 1048    else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) 1049    {1050        //IE6 standards compliant mode1051        scrOfY = document.documentElement.scrollTop;1052        scrOfX = document.documentElement.scrollLeft;1053    }1054    if(which) 1055    {1056        return scrOfX;1057    } 1058    else 1059    {1060        return scrOfY;1061    }1062}	1063//do popup control1064function $doControlPopup(headingText, contentText, controlID, closeBtn, closeBtnFn, pathExtra)1065{1066//    if (!pathExtra)1067//   {1068//        pathExtra = "";1069//   } 1070//    _controlID = controlID1071//    var HeadingText = headingText;1072//    var ContentText = contentText;1073//    var newDiv = false;1074//    var headerClose = "";1075//    var headerMain = "";1076//    var controlText = $id(controlID);1077//    controlText.style.display = "block";1078//    1079//    var controlValue = "";1080//    var controlHeight = (parseInt(controlText.style.height.replace("px","")));1081//    var controlWidth = (parseInt(controlText.style.width.replace("px","")));1082//    1083//    if ((controlHeight == "") || isNaN(controlHeight))1084//		controlHeight = controlText.offsetHeight;1085//		1086//    if ((controlWidth == "") || isNaN(controlWidth))1087//		controlWidth = controlText.offsetWidth;	1088//		1089//	var screenL = window.screen.availWidth - controlWidth ;1090//    var screenH = window.screen.availHeight - controlHeight;1091////   if (infoText.length > 0)1092////	{1093////	    screenH = screenH - 110;1094////	}1095////	else1096////	{1097//	    screenH = screenH - 150;1098////	} 1099//    var top = (screenH/3) +  parseInt(returnScrollDimensions(0)); 1100//    var left = (screenL/2) + parseInt(returnScrollDimensions(1));1101//    var divAlert = "";1102//    var divExists = $id("containerControl" + controlID); 1103//   //control style 1104//    //var st = "top:" + (parseInt(top) - parseInt(35)) + "px;" + "position:absolute;left:" + (parseInt(left)+ parseInt(25))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight))+"px;";1105//   //70 as dit infotext bevat1106//   //var st = "top:" + (parseInt(top) + parseInt(70)) + "px;" + "position:absolute;left:" + (parseInt(left)+ parseInt(5))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight+10))+"px;"; 1107//   //40 as daar nie info is nie1108//   var st = "top:" + (parseInt(top) + parseInt(40)) + "px;" + "position:absolute;left:" + (parseInt(left) + parseInt(2))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight ))+"px;"; 1109//    1110//    if (controlText.style.zIndex == "")1111//    {1112//         st += "z-index:9020;";1113//    }1114//    else1115//    {1116//        st += "z-index:" + controlText.style.zIndex + ";";1117//    }1118//    1119//    if(divExists == null)1120//    {1121//		divAlert = document.createElement("DIV");1122//		divAlert.id = "containerControl" + controlID;1123//		divAlert.className = "dragme";1124//		divAlert.attachEvent("onmousedown",selectmouse);1125//        divAlert.attachEvent("onmouseup",new Function("isdrag=false"));1126//		newDiv= true;1127//    }1128//    else1129//    {1130//		return;1131//    }1132//    1133//    controlText.style.cssText = "";1134//    controlText.style.cssText = st;1135//    1136//   //div se style 1137//    var stDiv = "top:" + (parseInt(top) +parseInt(2)) + "px;" + "position:absolute;left:" + (parseInt(left) +  parseInt(2))  + "px;width:"+(parseInt(controlWidth )) + "px;height:"+(parseInt(controlHeight) )+"px;";1138//   //iframe se style 1139//    //var stMain = "top:" + (parseInt(top) - parseInt(60)) + "px;" + "position:absolute;left:" + (parseInt(left)+ parseInt(25))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight)+20)+"px;";1140//   var stMain = "top:" + (parseInt(top) + parseInt(2)) + "px;" + "position:absolute;left:" + (parseInt(left) + parseInt(2))  + "px;width:"+(parseInt(controlWidth - 12)) + "px;height:"+(parseInt(controlHeight) - 4)+"px;"; 1141//    1142//    var currentIndex = controlText.style.zIndex;    1143//    stDiv += "z-index:" + (parseInt(currentIndex)-1) + ";";    1144//    stMain += "z-index:" + (parseInt(currentIndex)-2) + ";";1145//    busyDivTag((parseInt(currentIndex)-3), "busy_" + controlID);1146//    1147//    if (closeBtn != false)1148//    {1149//        headerClose = '<img id="btnClose' + controlID +  '" src="../images/clear.GIF" style="width:15px;height:15px;cursor:hand;">'1150//    }1151//    1152//    //headerMain = '<table cellspacing="0" cellpadding="0" style="table-layout:fixed;"><tr><td valign="middle" align="left" class="smllabelboldwhite"><nobr>' + headingText + '</td><td align="right" style="width:15px;">' + headerClose + '</td></tr></table>';1153//    1154//    divAlert.style.cssText = "";1155//    divAlert.style.cssText = "position:absolute;display:none;" + stDiv;1156//    //divAlert.innerHTML += '<table id="tblContainerControl' + controlID + '" cellpadding="0" cellspacing="0" border="0"><tr><td><div id="poptl' + controlID + '" class="poptl"></div></td><td><div id="poptc' + controlID + '" class="poptc"><div style="font-family:Arial;padding-top:15px;color:White;font-weight:bold; width:100%;">' + headerMain + '</div></div></td><td><div id="poptr' + controlID + '" class="poptr"></div></td></tr><tr><td><div id="popcl' + controlID + '" class="popcl"></div></td><td align="center"><div align="center" id="popcc' + controlID + '" class="popcc">' + controlValue + '</div></td><td><div id="popcr' + controlID + '" class="popcr"></div></td></tr><tr><td><div id="popbl' + controlID + '" class="popbl"></div></td><td><div id="popbc' + controlID + '" class="popbc"></div></td><td><div id="popbr' + controlID + '" class="popbr"></div></td></tr></table>';1157//   var closeName = "btnClose" + controlID ;1158//   divAlert.innerHTML += generatePopupHTML('tblContainerControl' + controlID, headingText, '', controlValue, '', controlHeight + 'px', controlWidth + 'px', closeName, closeBtnFn,'','',pathExtra) 1159//    1160//    if(newDiv == true)1161//    { 1162//        //mozilla 1163//        //controlText.parentElement.appendChild(divAlert);1164//        controlText.parentNode.appendChild(divAlert);1165//    }1166//    1167//    //add iframe1168//    var ifr = document.createElement("IFRAME");1169//    ifr.id = "containerframe" + controlID;1170//    ifr.className = "dragmeIfr";1171//    ifr.style.cssText = "";1172//    ifr.style.cssText = "display: none;position:absolute";1173//    1174//    //Jaco Lubbe - Verander vir die property grid se popup1175//    //document.body.appendChild(ifr);1176//   //mozilla 1177//    //controlText.parentElement.appendChild(ifr);1178//   controlText.parentNode.appendChild(ifr); 1179//    1180//    1181//    var table = $id("tblContainerControl" + controlID);1182//    1183//    $DivSetVisible(true,table,ifr,stMain);1184//    1185//    var thediv = "";1186//    var divID = $id("containerControl" + controlID);1187//    thediv = divID;1188//    thediv.style.display = "block";1189//    1190////    $id("poptc" + controlID).style.width=controlWidth+'px';1191////    $id("popcc" + controlID).style.width=controlWidth+'px';1192////    $id("popbc" + controlID).style.width=controlWidth+'px';1193////    $id("popcl" + controlID).style.height=controlHeight+'px';1194////    $id("popcc" + controlID).style.height=controlHeight+'px';1195////    $id("popcr" + controlID).style.height=controlHeight+'px';1196//    1197//    if (closeBtnFn != "") 1198//		document.getElementById("btnClose" + controlID).attachEvent("onclick", closeBtnFn);1199    //$showPopup(headingText, contentText, controlID, "", "", "", "doHidePopup()", "", "", "", pathExtra, "", "", "", "")1200   $showPopup(headingText, contentText, controlID, "", "", "", "doHidePopup()", "", "", "", pathExtra, "", "", "", "");1201    showSelectSpecific(controlID);	    	1202}1203function $doControlPopupDetail(headingText, contentText, infoText, controlID, buttons, closeBtn, closeBtnFn, pathExtra, helpID, popupImage)1204{1205//    if (!pathExtra)1206//   {1207//        pathExtra = "";1208//   } 1209//    _controlID = controlID1210//    var HeadingText = headingText;1211//    var ContentText = contentText;1212//    var newDiv = false;1213//    var headerClose = "";1214//    var headerMain = "";1215//    var controlText = $id(controlID);1216//    controlText.style.display = "block";1217//    1218//    var controlValue = "";1219//    var controlHeight = (parseInt(controlText.style.height.replace("px","")));1220//    var controlWidth = (parseInt(controlText.style.width.replace("px","")));1221//    1222//    if ((controlHeight == "") || isNaN(controlHeight))1223//		controlHeight = controlText.offsetHeight;1224//		1225//    if ((controlWidth == "") || isNaN(controlWidth))1226//		controlWidth = controlText.offsetWidth;	1227//		1228//	var screenL = window.screen.availWidth - controlWidth ;1229//	var screenH = window.screen.availHeight - controlHeight;1230//	if (infoText.length > 0)1231//	{1232//	    screenH = screenH - 110;1233//	}1234//	else1235//	{1236//	    screenH = screenH - 150;1237//	}1238//    var top = (screenH/3) +  parseInt(returnScrollDimensions(0)); 1239//    var left = (screenL/2) + parseInt(returnScrollDimensions(1));1240//    var divAlert = "";1241//    var divExists = $id("containerControl" + controlID); 1242//   //control style 1243//    //var st = "top:" + (parseInt(top) - parseInt(35)) + "px;" + "position:absolute;left:" + (parseInt(left)+ parseInt(25))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight))+"px;";1244//   //70 as dit infotext bevat1245//   var st = "";1246//   if (infoText.length > 0)1247//   {1248//    st = "top:" + (parseInt(top) + parseInt(70)) + "px;" + "position:absolute;left:" + (parseInt(left)+ parseInt(5))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight+10))+"px;"; 1249//   }1250//   else1251//   {1252//   //40 as daar nie info is nie1253//    st = "top:" + (parseInt(top) + parseInt(40)) + "px;" + "position:absolute;left:" + (parseInt(left) + parseInt(2))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight ))+"px;"; 1254//   }1255//    1256//    if (controlText.style.zIndex == "")1257//    {1258//         st += "z-index:9020;";1259//    }1260//    else1261//    {1262//        st += "z-index:" + controlText.style.zIndex + ";";1263//    }1264//    1265//    if(divExists == null)1266//    {1267//		divAlert = document.createElement("DIV");1268//		divAlert.id = "containerControl" + controlID;1269//		divAlert.className = "dragme";1270//		divAlert.attachEvent("onmousedown",selectmouse);1271//        divAlert.attachEvent("onmouseup",new Function("isdrag=false"));1272//		newDiv= true;1273//    }1274//    else1275//    {1276//		return;1277//    }1278//    1279//    controlText.style.cssText = "";1280//    controlText.style.cssText = st;1281//    1282//   //div se style 1283//    var stDiv = "top:" + (parseInt(top) +parseInt(2)) + "px;" + "position:absolute;left:" + (parseInt(left) +  parseInt(2))  + "px;width:"+(parseInt(controlWidth )) + "px;height:"+(parseInt(controlHeight) )+"px;";1284//   //iframe se style 1285//    //var stMain = "top:" + (parseInt(top) - parseInt(60)) + "px;" + "position:absolute;left:" + (parseInt(left)+ parseInt(25))  + "px;width:"+(parseInt(controlWidth)) + "px;height:"+(parseInt(controlHeight)+20)+"px;";1286//   var stMain = "top:" + (parseInt(top) + parseInt(2)) + "px;" + "position:absolute;left:" + (parseInt(left) + parseInt(2))  + "px;width:"+(parseInt(controlWidth - 12)) + "px;height:"+(parseInt(controlHeight) - 4)+"px;"; 1287//    1288//    var currentIndex = controlText.style.zIndex;    1289//    stDiv += "z-index:" + (parseInt(currentIndex)-1) + ";";    1290//    stMain += "z-index:" + (parseInt(currentIndex)-2) + ";";1291//    busyDivTag((parseInt(currentIndex)-3), "busy_" + controlID);1292//    1293//    if (closeBtn != false)1294//    {1295//        headerClose = '<img id="btnClose' + controlID +  '" src="../images/clear.GIF" style="width:15px;height:15px;cursor:hand;">'1296//    }1297//    1298//    //headerMain = '<table cellspacing="0" cellpadding="0" style="table-layout:fixed;"><tr><td valign="middle" align="left" class="smllabelboldwhite"><nobr>' + headingText + '</td><td align="right" style="width:15px;">' + headerClose + '</td></tr></table>';1299//    1300//    divAlert.style.cssText = "";1301//    divAlert.style.cssText = "position:absolute;display:none;" + stDiv;1302//    //divAlert.innerHTML += '<table id="tblContainerControl' + controlID + '" cellpadding="0" cellspacing="0" border="0"><tr><td><div id="poptl' + controlID + '" class="poptl"></div></td><td><div id="poptc' + controlID + '" class="poptc"><div style="font-family:Arial;padding-top:15px;color:White;font-weight:bold; width:100%;">' + headerMain + '</div></div></td><td><div id="poptr' + controlID + '" class="poptr"></div></td></tr><tr><td><div id="popcl' + controlID + '" class="popcl"></div></td><td align="center"><div align="center" id="popcc' + controlID + '" class="popcc">' + controlValue + '</div></td><td><div id="popcr' + controlID + '" class="popcr"></div></td></tr><tr><td><div id="popbl' + controlID + '" class="popbl"></div></td><td><div id="popbc' + controlID + '" class="popbc"></div></td><td><div id="popbr' + controlID + '" class="popbr"></div></td></tr></table>';1303//   var closeName = "btnClose" + controlID ;1304//   divAlert.innerHTML += generatePopupHTML('tblContainerControl' + controlID, headingText, infoText, controlValue, buttons, controlHeight + 'px', controlWidth + 'px', closeName, closeBtnFn, "","", pathExtra) 1305//    1306//    if(newDiv == true)1307//    { 1308//        //mozilla 1309//        //controlText.parentElement.appendChild(divAlert);1310//        controlText.parentNode.appendChild(divAlert);1311//    }1312//    1313//    //add iframe1314//    var ifr = document.createElement("IFRAME");1315//    ifr.id = "containerframe" + controlID;1316//    ifr.className = "dragmeIfr";1317//    ifr.style.cssText = "";1318//    ifr.style.cssText = "display: none;position:absolute";1319//    1320//    //Jaco Lubbe - Verander vir die property grid se popup1321//    //document.body.appendChild(ifr);1322//   //mozilla 1323//    //controlText.parentElement.appendChild(ifr);1324//   controlText.parentNode.appendChild(ifr); 1325//    1326//    1327//    var table = $id("tblContainerControl" + controlID);1328//    1329//    $DivSetVisible(true,table,ifr,stMain);1330//    1331//    var thediv = "";1332//    var divID = $id("containerControl" + controlID);1333//    thediv = divID;1334//    thediv.style.display = "block";1335//    1336////    $id("poptc" + controlID).style.width=controlWidth+'px';1337////    $id("popcc" + controlID).style.width=controlWidth+'px';1338////    $id("popbc" + controlID).style.width=controlWidth+'px';1339////    $id("popcl" + controlID).style.height=controlHeight+'px';1340////    $id("popcc" + controlID).style.height=controlHeight+'px';1341////    $id("popcr" + controlID).style.height=controlHeight+'px';1342//    1343//    //if (closeBtnFn != "") 1344//	//	document.getElementById("btnClose" + controlID).attachEvent("onclick", closeBtnFn);1345    if (!helpID)1346   {1347        helpID = "";1348   } 1349   if (!popupImage)1350   {1351        popupImage = "";1352   }1353   if (!infoText)1354   {1355        infoText = "";1356   }1357    $showPopup(headingText, contentText, controlID, "", "", "", closeBtnFn, buttons, "", "", pathExtra, infoText, helpID, "", "", popupImage);1358    showSelectSpecific(controlID);	    	1359}1360function $doHideControlPopup(controlID)1361{1362    doHidePopup(controlID);1363//    var thediv = $id("containerControl" + controlID);1364//    var theControlID = $id(controlID);1365    var thediv = window.parent.document.getElementById("containerControl" + controlID) != null ? window.parent.document.getElementById("containerControl" + controlID) : document.getElementById("containerControl" + controlID);1366    var theControlID = window.parent.document.getElementById(controlID) != null ? window.parent.document.getElementById(controlID) : document.getElementById(controlID);1367    1368    if (thediv != null && thediv != "")1369    {1370        theControlID.style.display = "none";1371//        var ifr = $id("containerframe" + controlID);1372        var ifr = window.parent.document.getElementById("containerframe" + controlID) != null ? window.parent.document.getElementById("containerframe" + controlID) : document.getElementById("containerframe" + controlID);1373        ifr.style.display = "none";1374        ifr.parentNode.removeChild(ifr);1375        thediv.style.display = "none";1376        thediv.parentNode.removeChild(thediv);1377    }1378   HideDisableDiv("busy_" + controlID);1379   hidePWait();1380   1381}1382//subforms;1383function $DivSetVisible(state,DivRef,IfrRef,st)1384{1385    if(state)1386    {1387        DivRef.style.display = "block";1388        IfrRef.style.cssText=st;1389        //Jaco Lubbe - Uitgecomment vir Property grid se popup1390        //IfrRef.style.zIndex = DivRef.style.zIndex - 1;1391        IfrRef.border=0;1392        IfrRef.style.display = "block";1393    }1394    else1395    {1396        DivRef.style.display = "none";1397        IfrRef.style.display = "none";1398    }1399}1400 /* replace function */1401function ReplaceID( str, currentvalue, newvalue) 1402{  1403        str += '';1404        var idx = str.indexOf( currentvalue );1405        while ( idx > -1 ) {1406            str = str.replace( currentvalue, newvalue ); 1407            idx = str.indexOf( currentvalue );1408        }1409    return str;1410}1411/* return http://hostname/solutionname and passes in the rest of the path to a page */1412function buildURL(path)1413{1414    1415   path =  location.pathname.substring(0,location.pathname.indexOf('/',1,0)) + "/" + path1416   //changed the buildURL function so the current solution (IIS) name of the project is not hardcoded1417    if (path.substring(0,1) == "/")1418    {1419        return "//" + location.host + path;1420        //return "http://" + location.host + path;1421    }1422    else1423    {   1424        return "//" + location.host + "/" + path;1425        //return "http://" + location.host + "/" + path;1426    }1427}1428    1429//Validation for a valid e-mail address1430function validateEmail(emailAddress)1431{1432  var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(2([0-4]\d|5[0-5])|1?\d{1,2})(\.(2([0-4]\d|5[0-5])|1?\d{1,2})){3} \])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/1433  return re.test(emailAddress);1434}1435//Validation on special chars1436function validateSpecialChars(id, friendlyName, specialChar, allowBlank, extraPath)1437{1438    var validateResult = ""1439    var objValue = "$id('" + id + "').value";1440    var _path = "";1441    1442    if (_pagePath != null)1443    {1444        _path = _pagePath.replace("../","");1445    }1446   1447   if (extraPath != null)1448   {1449        _path  = extraPath;1450   } 1451   1452    1453    if ($Trim(eval(objValue)).length == "")1454    {1455       if((allowBlank == null) || (allowBlank == false))1456        {1457            doPopup(Generic_js_ValidateHeading, Generic_js_ValidateDescription + " '" +  friendlyName + "'.", 400 , 75, Generic_js_ButtonOk, "doHidePopup('valID')|13", "", "", "", "", 11500, "valID", _path,"","error");1458            validateResult = false;1459            return validateResult;1460        }1461        else1462            validateResult = true;1463    }1464    1465    var iChars = "&!@#$%^&*()+=-[]\\\';,./{}|\":<>?_~";1466    iChars = iChars.replace(specialChar,"");1467    for (var i = 0; i < eval(objValue).length; i++) 1468    {1469        if (iChars.indexOf(eval(objValue).charAt(i)) != -1) {1470            doPopup(Generic_js_ValidateSpecialCharHeading, Generic_js_ValidateSpecialCharDescription + " '" + friendlyName + "' " + Generic_js_ValidateSpecialCharDescription1 + "  '" + eval(objValue).charAt(i) + "'.<br>" + Generic_js_ValidateSpecialCharDescription2, 400 , 70, Generic_js_ButtonOk, "doHidePopup('valIDSpec')|13", "", "", "", "", 11500, "valIDSpec", _path, "", "warning");1471            validateResult = false;1472            return validateResult;1473        }1474        else1475        {1476            validateResult = true;1477        }1478    }1479    return validateResult;1480}1481//check a string for special chars and return a 'true' or 'false'1482//set a space delimited exclude list if you need to1483function containsSpecialChars(inputString, excludeChars)1484{1485    var validateResult = false;1486    var specialChars = "&@#$%?!^*()+=-[]\\';,./{}|:<>_~";1487    var chinSpecialChars1 = "≈≠=≤≥≤<>≮≯∷±+-×÷∫∮∝∧∨∑∏∪∩∈∵∴⊥∥∠⌒⊙≌∽√";1488    var chinSpecialChars2 = "┼┽┾┿╀╁╂╃┬┭┮┯┰┰┱┱┲┳├┝┞┟┠┡┢┣┍┎┏┐┑┒┓┒─┄";1489    var chinSpecialChars3 = "§№☆★○●◎◇◆□℃‰€■△▲※→←↑↓〓¤°#&@\︿_ ̄―♂♀";1490    var chinSpecialChars4 = "〖〗【】[]{}《》「」『』々‖…—•ˉ〃";1491    var chinSpecialChars5 = "ㄅㄉˇˋㄓˊˊ˙˙ㄚㄞㄢㄆㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄈㄌㄏㄒㄖㄙㄩㄝㄡㄥ";1492    1493    var ExcludeList = excludeChars.split(" ");1494    //remove excluded chars form list    1495    for (var k = 0; k < ExcludeList.length; k++)1496    {1497        specialChars = specialChars.replace(ExcludeList[k],"");1498        chinSpecialChars1 = chinSpecialChars1.replace(ExcludeList[k],"");1499        chinSpecialChars2 = chinSpecialChars2.replace(ExcludeList[k],"");1500        chinSpecialChars3 = chinSpecialChars3.replace(ExcludeList[k],"");1501        chinSpecialChars4 = chinSpecialChars4.replace(ExcludeList[k],"");1502        chinSpecialChars5 = chinSpecialChars5.replace(ExcludeList[k],"");1503    }1504    1505    for (var i = 0; i < inputString.length; i++) 1506    {1507        if (specialChars.indexOf(inputString.charAt(i)) != -1) 1508        {1509            validateResult = true;1510        }1511        if (chinSpecialChars1.indexOf(inputString.charAt(i)) != -1) 1512        {1513            validateResult = true;1514        }1515        if (chinSpecialChars2.indexOf(inputString.charAt(i)) != -1) 1516        {1517            validateResult = true;1518        }1519        if (chinSpecialChars3.indexOf(inputString.charAt(i)) != -1) 1520        {1521            validateResult = true;1522        }1523        if (chinSpecialChars4.indexOf(inputString.charAt(i)) != -1) 1524        {1525            validateResult = true;1526        }1527        if (chinSpecialChars5.indexOf(inputString.charAt(i)) != -1) 1528        {1529            validateResult = true;1530        }1531    }1532    return validateResult;1533}1534 function addbookmark()1535{1536     if (document.all)1537          window.external.AddFavorite(location,'WorkSpace')1538}1539//Fix texttoplace in for 1st time its created; 1540function createPWait(texttoplace, zIndexValue)1541{1542    var divt = $id("div_SAVING");1543    if(divt == null)1544    {1545        divt = document.createElement("DIV");1546    var left =  (document.documentElement.clientWidth - 64) / 2;1547      if (left <= 0)1548      {1549        left = (document.body.clientWidth - 64) / 2;1550      }1551       var top =  (document.documentElement.clientHeight  - 64) / 2; 1552      if (top <= 0)1553      {1554        top = (document.body.clientHeight - 64) / 2;1555      }1556       // divt.style.cssText = "background:whitesmoke;border:1px solid gray;text-align: center;vertical-align: middle; line-height: normal; letter-spacing: normal;width: 381px; height: 51px; z-index: 1010; left: 390px; position: absolute; top: 209px;";1557      divt.style.cssText = "border:none;width: 32px; height: 32px; z-index: 1010; left:" + left + "px; position: absolute; top: " + top +"px;"; 1558        divt.innerHTML = textDiv(texttoplace); 1559        //divt.style.zIndex=12500;1560        divt.style.zIndex = zIndexValue;1561        divt.id = "div_SAVING";1562        1563        document.body.appendChild(divt);                1564    }1565 1566}1567function textDiv(eventtodisplay)1568{1569   eventtodisplay = (typeof(eventtodisplay) == 'undefined') ? "" : " : " +  eventtodisplay1570   1571   //var d= "<img src='../images/please_wait.gif'>" + "<br />"+ "Please wait  " +  eventtodisplay + "<br />";1572    var d= "<img id='imgBigGreenRot' src='../images/Green_Big_Rotate.gif'>";1573   return d;1574}1575//duplicate1576function showPWait(texttoplace, zIndex)1577{1578    var divt = $id("div_SAVING");1579     var ifr = $id("iframepopup");1580       1581    if(divt != null)1582    {1583       1584//        //divt.style.zIndex=9080;1585//        //Port_togglePopUpMenuDisplay(divt,"hiddenframe",true);1586//        $togglePopUp(divt, "hiddenframe", true);1587//        divt.innerHTML = textDiv(texttoplace);1588//        1589//        divt.style.display = "inline";1590        divt.parentNode.removeChild(divt);1591    }1592    1593    1594    1595    1596    var divtest = $id("div_SAVING");1597   if (zIndex != null)1598   {1599        createPWait(texttoplace, (parseInt(zIndex) + 100));1600        busyDivTag(zIndex);1601   } 1602   else1603   {1604        createPWait(texttoplace, 11500);1605        busyDivTag(11400);1606    }1607   _canload_Portal = false; 1608}1609function showPWaitIframe(texttoplace)1610{1611    var divt = $id("div_SAVING");1612    if(divt != null)1613    {1614        divt.parentNode.removeChild(divt); 1615     }1616        divt = document.createElement("DIV");1617//       var left = (document.documentElement.offsetWidth) /2;1618//       var top = (document.documentElement.offsetHeight) / 3; 1619     var left =  (document.documentElement.clientWidth - 64) / 2;1620      if (left <= 0)1621      {1622        left = (document.body.clientWidth - 64) / 2;1623      }1624       var top =  (document.documentElement.clientHeight  - 64) / 2; 1625      if (top <= 0)1626      {1627        top = (document.body.clientHeight - 64) / 2;1628      }1629       // divt.style.cssText = "background:whitesmoke;border:1px solid gray;text-align: center;vertical-align: middle; line-height: normal; letter-spacing: normal;width: 381px; height: 51px; z-index: 1010; left: 390px; position: absolute; top: 209px;";1630      divt.style.cssText = "border:none;width: 32px; height: 32px; z-index: 1010; left:" + left + "px; position: absolute; top: " + top +"px;"; 1631        divt.innerHTML = textDiv(texttoplace); 1632        divt.style.zIndex=9031;1633        divt.id = "div_SAVING";1634        1635        document.body.appendChild(divt);                1636     busyDivTag();1637   _canload_Portal = false; 1638 1639}1640//duplicate1641function hidePWait()1642{1643    var divt = $id("div_SAVING");1644    if(divt != null)1645    {1646        // Port_togglePopUpMenuDisplay(divt,"hiddenframe","none");1647        $togglePopUp(divt, "hiddenframe","none");1648        divt.style.display = "none";1649    }1650    HideDisableDiv();1651   _canload_Portal = true; 1652}1653function setFormName(customFormName)1654{1655    _formName = customFormName;1656}1657//Jvz : File and image upload div1658function busyDivTagTester(zIndex, ID,Con)1659{1660    var d;1661    var newDiv = false;1662   1663    if((ID != null) && (ID.length > 0))1664    {1665        d  = $id(ID); 1666        if(d==null)1667        {1668		    d= document.createElement("div");1669		    d.id = ID;1670		    _currentBusyDiv = ID;1671		    newDiv=true;1672        }1673    }1674    else1675    {1676        d = $id("divbusywithtop"); 1677        if(d==null)1678        {1679	        d= document.createElement("div");1680	        d.id = "divbusywithtop";1681	        newDiv=true;1682        }1683   }1684   	1685	d.style.backgroundColor = "black";1686	d.style.filter = "Alpha(opacity=50)";1687	d.style.top = "1px";1688	d.style.left="1px";1689	d.style.position="absolute";1690	d.style.width = document.forms[0].offsetWidth;// screen.availWidth;//document.documentElement.clientWidth;//document.body.offsetWidth + "px";//document.documentElement.offsetWidth + "px";1691//	d.style.height = screen.availHeight;//document.documentElement.clientHeight;1692	if (document.forms[0].offsetHeight >100)1693	{1694	    d.style.height = document.forms[0].offsetHeight;//screen.availHeight;//document.documentElement.clientHeight;//document.body.offsetHeight + "px"; //document.documentElement.offsetHeight + "px";1695	}1696	else1697	{1698	    d.style.height = document.documentElement.clientHeight;1699	}1700	if ((zIndex != null) && (zIndex.toString().length > 0 )) //jvz : zIndex.length1701	{1702	    d.style.zIndex = zIndex;1703	}1704	else1705	{1706	    d.style.zIndex="9010";1707	}1708	d.className="alphadiv";1709	d.style.display="inline";1710	1711	//Jvz het dit ingesit. Dis vir die FREAKING SUBFORMS!!!!!!!!!1712	if(typeof(_SubFormChildID) != "undefined")1713	{1714	    hideSelectsButKeepID(_SubFormChildID);1715	}1716	else1717	{1718	    hideSelects();1719	}1720	if(newDiv==true)1721	{1722	    try1723	    {1724	        try1725	        {1726	            var form = $id(Con);1727	            if (form != null)1728	            {1729		            $id(Con).appendChild(d);1730		        }1731		        else1732		        {1733		           $id(_formName).appendChild(d);1734		        }1735		    }1736		    catch(e)1737		    {1738		        $id(_formName).appendChild(d);1739		    } 1740		}1741		catch(e)1742		{1743		    document.forms[0].appendChild(d);1744		}1745	}1746}1747function busyDivTag(zIndex, ID)1748{1749    var d;1750    var newDiv = false;1751   1752    if((ID != null) && (ID.length > 0))1753    {1754        d  = $id(ID); 1755        if(d==null)1756        {1757		    d= document.createElement("div");1758		    d.id = ID;1759		    _currentBusyDiv = ID;1760		    newDiv=true;1761        }1762    }1763    else1764    {1765        d = $id("divbusywithtop"); 1766        if(d==null)1767        {1768	        d= document.createElement("div");1769	        d.id = "divbusywithtop";1770	        newDiv=true;1771        }1772   }1773   	1774	d.style.backgroundColor = "black";1775	d.style.filter = "Alpha(opacity=50)";1776	d.style.top = "1px";1777	d.style.left="1px";1778	d.style.position="absolute";1779	d.style.width = document.forms[0].offsetWidth;// screen.availWidth;//document.documentElement.clientWidth;//document.body.offsetWidth + "px";//document.documentElement.offsetWidth + "px";1780//	d.style.height = screen.availHeight;//document.documentElement.clientHeight;1781//	if (document.forms[0].offsetHeight >100)1782//	{1783//	    d.style.height = document.forms[0].offsetHeight;//screen.availHeight;//document.documentElement.clientHeight;//document.body.offsetHeight + "px"; //document.documentElement.offsetHeight + "px";1784//	}1785//	else1786//	{1787//	    d.style.height = document.documentElement.clientHeight;1788//	}1789    d.style.height  = document.documentElement.offsetHeight; //changed for Q4_2007 (bug 10309)1790	if ((zIndex != null) && (zIndex.toString().length > 0 )) //jvz : zIndex.length1791	{1792	    d.style.zIndex = zIndex;1793	}1794	else1795	{1796	    d.style.zIndex="9010";1797	}1798	d.className="alphadiv";1799	d.style.display="inline";1800	1801	//Jvz het dit ingesit. Dis vir die FREAKING SUBFORMS!!!!!!!!!1802	if(typeof(_SubFormChildID) != "undefined")1803	{1804	    hideSelectsButKeepID(_SubFormChildID);1805	}1806	else1807	{1808	    hideSelects();1809	}1810	if(newDiv==true)1811	{1812	    try1813	    {1814	        try1815	        {1816	            var form = $id("form1");1817	            if (form != null)1818	            {1819		            $id("form1").appendChild(d);1820		        }1821		        else1822		        {1823		           $id(_formName).appendChild(d);1824		        }1825		    }1826		    catch(e)1827		    {1828		        $id(_formName).appendChild(d);1829		    } 1830		}1831		catch(e)1832		{1833		    document.forms[0].appendChild(d);1834		}1835	}1836}1837function hideSelects()1838{1839    //mozilla1840    //var selCount = document.all.tags("select");1841   var selCount = document.getElementsByTagName("select"); 1842    for (var i=0; i<selCount.length; i++)1843    {1844            selCount[i].style.visibility = "hidden";1845    }1846}1847 1848function showSelects()1849{1850    //mozilla1851    //var selCount = document.all.tags("select");1852    var selCount = document.getElementsByTagName("select");1853    for (var i=0; i<selCount.length; i++)1854    {1855       selCount[i].style.visibility = "visible";1856    }1857   if ($id("textStyle"))1858   {1859        //mozilla1860        //selCount = ($id("textStyle")).all.tags("select");1861        selCount = ($id("textStyle")).getElementsByTagName("select");1862        for (var i=0; i<selCount.length; i++)1863        {1864                selCount[i].style.visibility = "hidden";1865        }   1866   } 1867}1868function showSelectSpecific(controlID)1869{1870     if ($id(controlID))1871   {1872        //This is a fix for Mozilla browser.1873        //selCount = ($id(controlID)).all.tags("select");1874        selCount = ($id(controlID)).getElementsByTagName("select");1875        for (var i=0; i<selCount.length; i++)1876        {1877                selCount[i].style.visibility = "visible";1878        }   1879   } 1880} 1881function hideSelectSpecific(controlID)1882{1883     if ($id(controlID))1884   {1885         //This is a fix for Mozilla browser.1886        //selCount = ($id(controlID)).all.tags("select");1887        selCount = ($id(controlID)).getElementsByTagName("select");1888        for (var i=0; i<selCount.length; i++)1889        {1890                selCount[i].style.visibility = "hidden";1891        }   1892   } 1893} 1894 1895function HideDisableDiv(ID)1896{1897    var df;// = $id("divbusywithtop");1898    if ((ID != null) && (ID.length > 0))1899    {1900        df = $id(ID);1901    }1902    else1903    {1904        df = $id("divbusywithtop");1905    }1906    1907    if(df!=null)1908    {1909        df.style.display="none";1910        _currentBusyDiv = "";1911	}1912	showSelects();1913}1914function hideSelectsButKeepID(idtoKeep)1915{1916    //var selCount = _portaldocument.all.tags("select");1917   var selCount = document.getElementsByTagName("select"); 1918    1919    for (var i=0; i<selCount.length; i++)1920    {1921      	var id = selCount[i].getAttribute("id");1922		1923		if(idtoKeep !=null)1924       {1925			if(getParamsNumber(id) != getParamsNumber(idtoKeep))1926			{1927				selCount[i].style.visibility = "hidden";1928			}1929			else1930			{1931				selCount[i].style.visibility = "visible";1932			}1933		}1934		else1935		{1936			selCount[i].style.visibility = "hidden";1937		}1938		1939      	//selCount[i].style.visibility = "hidden";1940    }1941}1942//Shows certain selects but keep the id passed visible;1943function showSelectsButKeepID(idtoKeep)1944{1945    var selCount = document.getElementsByTagName("select");1946    for (var i=0; i<selCount.length; i++)1947    {1948       var id = selCount[i].getAttribute("id");1949            1950       if(idtoKeep !=null)1951       {1952			if(getParamsNumber(id) != getParamsNumber(idtoKeep))1953			{1954				selCount[i].style.visibility = "hidden";1955			}1956			else1957			{1958				selCount[i].style.visibility = "visible";1959			}1960		}1961		else1962		{1963			selCount[i].style.visibility = "visible";1964		}1965    }1966    1967    //selCount = ($id("textStyle")).all.tags("select");1968   selCount = ($id("textStyle")).getElementsByTagName("select"); 1969    1970    for (var i=0; i<selCount.length; i++)1971    {1972            selCount[i].style.visibility = "hidden";1973    }   1974    1975}1976function checkoutsideBottomPopUp(inputObj,height, scrollDivID)1977{1978	//var i = clienty + parseInt(divImageUpload.style.height);1979	if (!scrollDivID)1980	{1981	    scrollDivID = "PageContentScrollDiv";1982	}1983	var i = getTopPos(inputObj) + parseInt(height.replace("px",""));1984	if ($id(scrollDivID))1985	{1986	    var scrolltop = ($id(scrollDivID)).scrollTop;1987	    var contentheight = ($id(scrollDivID)).offsetHeight;1988	    if ((i   - scrolltop) > (contentheight))1989	    {1990	       i = getTopPos(inputObj) ;1991	    }1992	}1993	else1994	{1995	    if( i > document.body.offsetHeight-10)1996	    {1997		    i = getTopPos(inputObj); //works1998	    }1999	    var scrolltop = 0;2000	}2001	2002	return i = i - scrolltop - parseInt(height.replace("px",""));2003}2004function checkoutsideWidth(inputObj,width, scrollDivID)2005{2006	if (!scrollDivID)2007	{2008	    scrollDivID = "PageContentScrollDiv";2009	}2010	2011	var i = getleftPos(inputObj)+ parseInt(width.replace("px",""));2012	2013	var scrolleft = 0;2014	if ($id(scrollDivID))2015	{2016	    scrolleft = ($id(scrollDivID)).scrollLeft;2017	}2018	2019	i = i - scrolleft;2020	if( i > document.body.offsetWidth-10)2021	{2022		i =getleftPos(inputObj) - scrolleft - parseInt(width.replace("px","")); //out2023	}2024	else2025	{2026		i = i - scrolleft - parseInt(width.replace("px",""));2027	}2028	2029	return i;2030}2031//jvz: function for Multivalue popup control;2032function $ShowSelectPopUpControl(headingText, contentText, controlID, closeBtn, closeBtnFn)2033{2034    if(($id(controlID)).style.width == "" || ($id(controlID)).style.width.indexOf("%") >0)2035    {2036        ($id(controlID)).style.width = "100px";2037    }2038      2039    $showPopup(headingText, contentText, controlID, "", "110", "", closeBtnFn, "", "", "", "", "", "", "", "", "");2040//    var containerControl = "containerControlPOP";2041//    var tblContainerControl = "tblContainerControlPOP";2042//    var obj= event.srcElement;2043//    var HeadingText = headingText;2044//    var ContentText = contentText;2045//    var newDiv = false;2046//    var headerClose = "";2047//    var headerMain = "";2048//    var controlText = $id(controlID);2049//    var controlValue = "";//controlText.innerHTML;2050//    //Added 20px 24/nov due to bug in des?2051//    if(controlText.style.height == "" || controlText.style.height == "20px")2052//    {2053//        controlText.style.height = "100px";2054//    }2055//    2056//    if(controlText.style.width == "" || controlText.style.width.indexOf("%") >0)2057//    {2058//       2059//        controlText.style.width = "100px";2060//    }2061//    2062//    var iPos = checkoutsideWidth(obj,controlText.style.width);2063//    var xPosRec = checkoutsideBottomPopUp(obj,controlText.style.height);2064//    if (_SubFormChildID == null)2065//    {2066//        controlText.style.left = iPos;2067//        controlText.style.top = xPosRec;2068//    } 2069//    2070//    var controlHeight = controlText.style.height.replace("px","");2071//    var controlWidth =  controlText.style.width.replace("px","");2072//    var screenL = window.screen.availWidth - controlWidth ;2073//    var screenH = window.screen.availHeight - controlHeight;2074//    var top =controlText.style.top.replace("px","");  //(screenH/3) +  parseInt(returnScrollDimensions(0)); 2075//    var left = controlText.style.left.replace("px",""); //(screenL/2) + parseInt(returnScrollDimensions(1));2076//        2077//    var divAlert = ""; 2078//    var divExists = $id(containerControl); 2079//    var ViewID = "part_" + getParamsNumber(controlID);2080//    var View = $id(ViewID);2081//	var vtop = View.offsetTop;2082//    var vleft = View.offsetLeft;2083//    2084//    var dtop = (parseInt(top) + parseInt(vtop)) - parseInt(10);2085//    var dleft =  (parseInt(left) + parseInt(vleft)) + parseInt(20);2086//    var st = "top:" + dtop  + "px;" + "z-index:9025;position:absolute;left:" + dleft + "px;width:"+(parseInt(controlWidth)+10) + "px;height:"+(parseInt(controlHeight)+ 5)+"px";2087//   2088//    if(divExists == null)2089//    {2090//		divAlert = document.createElement("DIV");2091//		divAlert.id = containerControl; //"containerControl";2092//		newDiv= true;2093//    }2094//    else2095//    {2096//		//return;2097//    }2098//	 2099//     var stTop = (parseInt(top) + parseInt(vtop)) - parseInt(35);2100//     var stLeft = parseInt(left)+ parseInt(vleft) - parseInt(7);2101//     2102//     var stDiv = "top:" + stTop + "px;" + "z-index:9021;position:absolute;left:" +  stLeft  + "px;width:"+(parseInt(controlWidth)+30) + "px;height:"+(parseInt(controlHeight)+10)+"px";2103//    2104//    if (closeBtn != false)2105//    {2106//        headerClose = '<img id="btnClose" src="../images/clear.GIF" style="width:15px;height:15px;cursor:hand;">'2107//    }2108//    2109//    headerMain = '<table cellspacing="0" cellpadding="0" style="table-layout:fixed;width:100%;"><tr><td  style="padding-top:10px" align="left" nowrap>' + headingText + '</td><td align="right">' + headerClose + '</td></tr></table>';2110//    2111//    //divAlert.style.cssText = "position:absolute;display:none;" + stDiv;2112//    divAlert.style.cssText = controlText.style.cssText;2113//    divAlert.style.top = parseInt(divAlert.style.top) - 36;2114//    divAlert.style.left = parseInt(divAlert.style.left) - 10;  2115//    divAlert.style.zIndex = "9995";2116//    divAlert.innerHTML += '<table id="tblContainerControlPOP" cellpadding="0" cellspacing="0" border="0"><tr><td><div id="poptl" class="poptl"></div></td><td><div id="poptcPop" class="poptc"><div style="font-family:Arial;padding-top:5px;color:White;font-weight:bold;">' + headerMain + '</div></div></td><td><div id="poptrPOP" class="poptr"></div></td></tr><tr><td><div id="popclPOP" class="popcl"></div></td><td align="center"><div id="popccPOP" class="popcc">' + ""+ '</div></td><td><div id="popcrPOP" class="popcr"></div></td></tr><tr><td><div id="popblPOP" class="popbl"></div></td><td><div id="popbcPOP" class="popbc"></div></td><td><div id="popbrPOP" class="popbr"></div></td></tr></table>';2117//   2118//    if(newDiv == true)2119//    { 2120//         var cid = getParamsNumber(controlID);2121//         $id("part_" + cid).appendChild(divAlert);2122//        2123//    }2124//    2125//    //add iframe2126//   2127//    var table = $id(tblContainerControl);2128//    2129//    var testi = $id("ifr")2130//    var i = null;2131//    if(testi == null)2132//    {2133//		i = document.createElement("Iframe");2134//    }2135//    else2136//    {2137//		i = $id("ifr");2138//    }2139//    i.id = "ifr";2140//   2141//    if(_SubViewIsOnTop ==true)2142//    {2143//		i.style.cssText = controlText.style.cssText;2144//		i.style.zIndex = "9994"2145//		//i.style.top = stTop - 35;2146//		//i.style.left = stLeft - 7;  2147//		//i.style.cssText = divAlert.style.cssText;2148//        2149//        if(testi == null)2150//        {2151//		    $id("part_" + cid).appendChild(i);2152//        }2153//        else2154//        {2155//		    i.style.display = "block";2156//        }2157//    2158//    }2159//    2160//    2161//   2162//    2163//    var thediv =null;2164//    thediv = document.getElementById(containerControl);2165//    thediv.style.display = "block";2166//    2167//        2168//    document.getElementById("poptcPop").style.width=controlWidth+'px';2169//    document.getElementById("popccPOP").style.width=controlWidth+'px';2170//    document.getElementById("popbcPOP").style.width=controlWidth+'px';2171//    document.getElementById("popclPOP").style.height=controlHeight+'px';2172//    document.getElementById("popccPOP").style.height=controlHeight+'px';2173//    document.getElementById("popcrPOP").style.height=controlHeight+'px';2174//    2175//    document.getElementById("btnClose").attachEvent("onclick", closeBtnFn);2176    2177}2178//jvz multivalue popup;2179function $doHideControlPopupControl(controlID)2180{2181    var thediv = window.parent.document.getElementById("containerControlPOP") != null ? window.parent.document.getElementById("containerControlPOP") : document.getElementById("containerControlPOP");2182    var theControlID = window.parent.document.getElementById(controlID) != null ? window.parent.document.getElementById(controlID) : document.getElementById(controlID);2183    2184    if (thediv != null && thediv != "")2185    {2186        theControlID.style.display = "none";2187        ///var ifr = window.parent.document.getElementById("containerframePOP") != null ? window.parent.document.getElementById("containerframe") : document.getElementById("containerframe");2188        //ifr.style.display = "none";2189         var testi = $id("ifr")2190         if(testi !=null)2191         {2192			testi.style.display = "none";2193         }2194        thediv.style.display = "none";2195        thediv.parentNode.removeChild(thediv);2196    }2197}2198function RemoveAllTableRows(TableName)2199{2200	var thisTable = $id(TableName);2201	2202	if (thisTable != null)2203	{2204		var rows = thisTable.rows.length;2205		2206		for (var i = 0; i < rows; i++)2207		{2208			thisTable.deleteRow(0);2209		}2210	}2211}2212// Use for IFrame , in green div2213// setups everything but doesn't show until being called;2214function $doViewPopupIframe(headingText, contentText, src, viewHeight, viewWidth)2215{2216    showPWait()2217    var HeadingText = headingText;2218    var ContentText = contentText;2219  2220    if (viewHeight == null)2221    {2222        viewHeight = 350; 2223    }2224    2225    if (viewWidth == null)2226    {2227        viewWidth = 318;2228    }2229    2230    var screenL = (window.screen.availWidth/2) - (viewWidth/2);2231    var screenH = window.screen.availHeight - viewHeight;2232    2233    var top = (screenH/3) +  parseInt(returnScrollDimensions(0)); 2234    var left = (screenL) + parseInt(returnScrollDimensions(1));2235    2236    var newDiv = false;2237    var divAlert = "";2238    var divExists = $id("containerView");2239    2240    var IframeEx = false;2241    2242    if(divExists == null)2243    {2244		divAlert = document.createElement("DIV");2245		divAlert.id = "containerView";2246		newDiv= true;2247    }2248    else2249    {2250		newDiv = false;2251		divAlert = divExists;2252    }2253    2254    var IFrameSrc = $id("IFrameSrc");2255    2256    if(IFrameSrc == null)2257    {2258        IFrameSrc = document.createElement("IFRAME");2259        IFrameSrc.id = "IFrameSrc";2260        IFrameSrc.src = src;2261        IframeEx = false;2262        IFrameSrc.frameBorder =0;2263    }2264    else2265    {2266        IframeEx = true;2267    }2268    2269    var stDiv = "top:" + (parseInt(top) - 100) + "px;z-index:9018;position:absolute;left:" + (parseInt(left) - 25) + "px;width:" + (viewWidth+20) + "px;height:" + (viewHeight+10) + "px";2270    var IframeStyle = "top:" + (parseInt(top) - 59) + "px;z-index:9017;position:absolute;left:" + (parseInt(left)-15) + "px;width:" + (viewWidth+10) + "px;height:" + (viewHeight+30) + "px;frameborder=0;";2271    2272    IFrameSrc.style.cssText = IframeStyle;2273    IFrameSrc.style.zIndex = IFrameSrc.style.zIndex +1;2274    IFrameSrc.style.height = IFrameSrc.style.height.replace("px","") -40;2275    IFrameSrc.style.width = IFrameSrc.style.width.replace("px","") -15;2276    IFrameSrc.style.left = parseInt(IFrameSrc.style.left.replace("px","")) + (parseInt(5));2277    IFrameSrc.style.display = "none";2278    2279    divAlert.style.cssText = "position:absolute;display:none;z-index:9019;" + stDiv;2280    //divAlert.innerHTML += '<table id="tblContainerView" cellpadding="0" cellspacing="0" border="0"><tr><td><div id="poptl" class="poptl"></div></td><td><div id="poptc" class="poptc"><div style="font-family:Arial;padding-top:15px;color:White;font-weight:bold;">' + HeadingText + '</div></div></td><td><div id="poptr" class="poptr"></div></td></tr><tr><td><div id="popcl" class="popcl"></div></td><td align="center"><div id="popcc" class="popcc">' + ContentText + '</div></td><td><div id="popcr" class="popcr"></div></td></tr><tr><td><div id="popbl" class="popbl"></div></td><td><div id="popbc" class="popbc"></div></td><td><div id="popbr" class="popbr"></div></td></tr></table>';2281   divAlert.innerHTML = generatePopupHTML("tblContainerView",headingText, "", ContentText,  "", viewHeight, viewWidth, "","", "","");2282   2283    if(newDiv == true)2284    { 2285        document.body.appendChild(divAlert);2286    }2287    if(IframeEx==false)2288    {2289        document.body.appendChild(IFrameSrc);2290    }2291    2292   /* var thediv = "";2293    thediv = document.getElementById("containerView");2294    thediv.style.display = "block";2295   */2296//    document.getElementById("poptc").style.width=viewWidth+'px';2297//    document.getElementById("popcc").style.width=viewWidth+'px';2298//    document.getElementById("popbc").style.width=viewWidth+'px';2299//    document.getElementById("popcl").style.height=viewHeight+'px';2300//    document.getElementById("popcc").style.height=viewHeight+'px';2301//    document.getElementById("popcr").style.height=viewHeight+'px';2302}2303//Helper2304//this is to build the packet removing NAME_203 will return NAME2305function $getParamWithOutNumber(idcomingin)2306{2307    var arrS = idcomingin.split('_');2308   2309    //return arrS[0];2310    if (arrS != null)2311    {    2312        if(arrS.length == 1)2313        {2314            return arrS[0];2315        }2316            2317        if(arrS.length == 2) //LOAD_155 Course_Code (2)2318        {   2319            return arrS[0]; 2320        }2321        else2322        {2323            //bug met _ op die einde. bv 2324            //Send_for_Approval__7232325             var Id = arrS[arrS.length-1];2326             var sub = idcomingin.substring(0,idcomingin.indexOf('_'+Id));2327             return sub; 2328        }2329    } 2330}2331function $doViewPopupShowIframe()2332{2333        var thediv = "";2334        2335        thediv = window.parent.document.getElementById("containerView")2336        thediv.style.display = "block";2337        var theIFrame = window.parent.document.getElementById("IFrameSrc")2338        theIFrame.style.display = "block";2339        window.parent.hidePWait();2340        window.parent.busyDivTag();2341}2342function $doViewPopupCloseIframe()2343{2344    window.parent.HideDisableDiv();2345    var IfClose = window.parent.document.getElementById("tblContainerView");2346    if(IfClose !=null)2347    {2348        IfClose.parentNode.removeChild(IfClose);2349    }2350    2351    var containerView = window.parent.document.getElementById("containerView");2352    if(containerView !=null)2353    {2354        containerView.parentNode.removeChild(containerView);2355    }2356        2357    var Iframe = window.parent.document.getElementById("IFrameSrc");2358    if(Iframe !=null)2359    {2360        Iframe.parentNode.removeChild(Iframe);2361    }2362}2363//Hover Context Menus2364function showSelectedContext(obj)2365{2366    if (obj.className != "divSelected"){2367        obj.className = "selectedItemCat";2368    }2369}2370function hideSelectedContext(obj)2371{2372    obj.className = "divNormal";2373}2374//Hover Tree Items2375function showSelected()2376{2377    var hoverID = event.srcElement;2378    2379    hoverID.className = "selectedItem";2380    //selectedItem2381}2382function hideSelected()2383{2384    var hoverID = event.srcElement;2385    2386    hoverID.className = "smllabel";2387}2388//Resize of Window2389function ResizeEvent()2390{2391    var busyD = $id("divbusywithtop"); 2392    var CheckGlobalDiv = false;2393    if (busyD == null)2394    {2395        CheckGlobalDiv = true;2396    }2397    else2398    {2399        if (busyD.style.display == "none")2400        {2401            CheckGlobalDiv = true;2402        }    2403    }2404   2405    if (CheckGlobalDiv)2406    {2407        if (_currentBusyDiv != null)2408        {   2409            if (_currentBusyDiv != "")2410            {2411                busyD = $id(_currentBusyDiv); 2412            }2413        }   2414    }2415  2416    if (busyD != null)2417    {2418        busyD.style.width = document.forms[0].offsetWidth;2419	    if (document.forms[0].offsetHeight >100)2420	    {2421	        busyD.style.height = document.forms[0].offsetHeight;2422	    }2423	    else2424	    {2425	        busyD.style.height = document.documentElement.clientHeight;2426	    }2427    }2428    //the line below added by sean to recalculate all expressions on the page2429    document.recalc(true);2430}2431 /* mozlla insertAdjacentHTML replacement function - not quite working */2432     function mozilla_insertAdjacentHTML(control, sWhere, sHTML) 2433     {2434       var df;   // : DocumentFragment2435       var r =control.ownerDocument.createRange();2436        2437       switch (String(sWhere).toLowerCase()) 2438       {  // convert to string and unify case2439          case "beforebegin":2440             r.setStartBefore(control);2441             df = r.createContextualFragment(sHTML);2442             control.parentNode.insertBefore(df, control);2443             break;2444             2445          case "afterbegin":2446             r.selectNodeContents(control);2447             r.collapse(control);2448             df = r.createContextualFragment(sHTML);2449             control.insertBefore(df, control.firstChild);2450             break;2451             2452          case "beforeend":2453             r.selectNodeContents(control);2454             r.collapse(false);2455             df = r.createContextualFragment(sHTML);2456             control.appendChild(df);2457             break;2458             2459          case "afterend":2460             r.setStartAfter(control);2461             df = r.createContextualFragment(sHTML);2462             control.parentNode.insertBefore(df, control.nextSibling);2463             break;2464       }   2465    }2466   2467     var mozilla_emptyTags = {2468       "IMG":   true,2469       "BR":    true,2470       "INPUT": true,2471       "META":  true,2472       "LINK":  true,2473       "PARAM": true,2474       "HR":    true2475    }2476    /*mozilla outerHTML replacement function */2477    function mozilla_outerHTML(control)2478    {2479            var attrs = control.attributes;2480            var str = "<" + control.tagName;2481            for (var i = 0; i < attrs.length; i++)2482            str += " " + attrs[i].name + "=\"" + attrs[i].value + "\"";2483            if (mozilla_emptyTags[this.tagName])2484                return str + ">";2485            return  str + ">" + control.innerHTML + "</" + control.tagName + ">";2486    } 2487        2488//var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";2489//function encode64(input) 2490//{2491//    if (input == "") return input;2492//    var output = "";2493//    var chr1, chr2, chr3;2494//    var enc1, enc2, enc3, enc4;2495//    var i = 0;2496//    do 2497//    {2498//        chr1 = input.charCodeAt(i++);2499//        chr2 = input.charCodeAt(i++);2500//        chr3 = input.charCodeAt(i++);2501//        enc1 = chr1 >> 2;2502//        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);2503//        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);2504//        enc4 = chr3 & 63;2505//        if (isNaN(chr2)) 2506//        {2507//            enc3 = enc4 = 64;2508//        } 2509//        else if (isNaN(chr3)) 2510//        {2511//            enc4 = 64;2512//        }2513//        output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);2514//    } while (i < input.length);2515//   2516//    return output;2517//}2518//function decode64(input) 2519//{2520//    if (input == "") return input;2521//    var output = "";2522//    var chr1, chr2, chr3;2523//    var enc1, enc2, enc3, enc4;2524//    var i = 0;2525//    // remove all characters that are not A-Z, a-z, 0-9, +, /, or =2526//    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");2527//    do 2528//    {2529//        enc1 = keyStr.indexOf(input.charAt(i++));2530//        enc2 = keyStr.indexOf(input.charAt(i++));2531//        enc3 = keyStr.indexOf(input.charAt(i++));2532//        enc4 = keyStr.indexOf(input.charAt(i++));2533//        chr1 = (enc1 << 2) | (enc2 >> 4);2534//        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);2535//        chr3 = ((enc3 & 3) << 6) | enc4;2536//        output = output + String.fromCharCode(chr1);2537//        if (enc3 != 64) 2538//        {2539//            output = output + String.fromCharCode(chr2);2540//        }2541//        if (enc4 != 64) 2542//        {2543//            output = output + String.fromCharCode(chr3);2544//        }2545//    } while (i < input.length);2546//    return output;2547//}2548function $createCookie(name,value,days) {2549	if (days) {2550		var date = new Date();2551		date.setTime(date.getTime()+(days*24*60*60*1000));2552		var expires = "; expires="+date.toGMTString();2553	}2554	else var expires = "";2555	document.cookie = name+"="+value+expires+"; path=/";2556}2557function $readCookie(name) {2558	var nameEQ = name + "=";2559	var ca = document.cookie.split(';');2560	for(var i=0;i < ca.length;i++) {2561		var c = ca[i];2562		while (c.charAt(0)==' ') c = c.substring(1,c.length);2563		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);2564	}2565	return null;2566}2567function $eraseCookie(name) {2568	createCookie(name,"",-1);2569}2570function $containsSpecialChars(inputString, excludeChars)2571{2572    var validateResult = -1;2573    var specialChars = "&!@#$%^&*()+=-[]\\\';,./{}|\":<>?_~";2574    var chinSpecialChars1 = "≈≠=≤≥≤<>≮≯∷±+-×÷∫∮∝∧∨∑∏∪∩∈∵∴⊥∥∠⌒⊙≌∽√";2575    var chinSpecialChars2 = "┼┽┾┿╀╁╂╃┬┭┮┯┰┰┱┱┲┳├┝┞┟┠┡┢┣┍┎┏┐┑┒┓┒─┄";2576    var chinSpecialChars3 = "§№☆★○●◎◇◆□℃‰€■△▲※→←↑↓〓¤°#&@\︿_ ̄―♂♀";2577    var chinSpecialChars4 = "〖〗【】[]{}《》「」『』々‖…—•ˉ〃";2578    var chinSpecialChars5 = "ㄅㄉˇˋㄓˊˊ˙˙ㄚㄞㄢㄆㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄈㄌㄏㄒㄖㄙㄩㄝㄡㄥ";2579    var ExcludeList = excludeChars.split(" ");2580    //remove excluded chars form list    2581    for (var k = 0; k < ExcludeList.length; k++)2582    {2583        specialChars = specialChars.replace(ExcludeList[k],"");2584        chinSpecialChars1 = chinSpecialChars1.replace(ExcludeList[k],"");2585        chinSpecialChars2 = chinSpecialChars2.replace(ExcludeList[k],"");2586        chinSpecialChars3 = chinSpecialChars3.replace(ExcludeList[k],"");2587        chinSpecialChars4 = chinSpecialChars4.replace(ExcludeList[k],"");2588        chinSpecialChars5 = chinSpecialChars5.replace(ExcludeList[k],"");2589        2590    }2591    2592    for (var i = 0; i < inputString.length; i++) 2593    {2594        if (specialChars.indexOf(inputString.charAt(i)) != -1) 2595        {2596            validateResult = i;2597        }2598        if (chinSpecialChars1.indexOf(inputString.charAt(i)) != -1) 2599        {2600            validateResult = true;2601        }2602        if (chinSpecialChars2.indexOf(inputString.charAt(i)) != -1) 2603        {2604            validateResult = true;2605        }2606        if (chinSpecialChars3.indexOf(inputString.charAt(i)) != -1) 2607        {2608            validateResult = true;2609        }2610        if (chinSpecialChars4.indexOf(inputString.charAt(i)) != -1) 2611        {2612            validateResult = true;2613        }2614        if (chinSpecialChars5.indexOf(inputString.charAt(i)) != -1) 2615        {2616            validateResult = true;2617        }2618    }2619    return validateResult;2620}2621function convertToGuidString(normalstring)2622{2623    if (normalstring == "0")2624   {2625        normalstring = "00000000-0000-0000-0000-000000000000";2626   } 2627    var newstring = normalstring;2628    var part1 = "";2629    var part2 = "";2630    var part3 = "";2631    var part4 = "";2632    var part5 = "";     2633    if (normalstring.indexOf('-') == -1)2634   {2635        normalstring = ReplaceID(normalstring, 'part_', '');2636        part1 = normalstring.substring(0, 8);2637        part2 = normalstring.substring(8, 12);2638        part3 = normalstring.substring(12, 16);2639        part4 = normalstring.substring(16, 20);2640        part5 = normalstring.substring(20);2641        newstring = part1 + "-" + part2 + "-" + part3 + "-" + part4 + "-" + part5;2642   } 2643   return newstring;2644}2645function convertFromGuidString(guidstring)2646{2647    var newstring = ReplaceID(guidstring, "-", "");2648    newstring = newstring.toUpperCase();2649    return newstring;   2650}2651// Allows the developer to find HTML elements of a specific classname2652function getElementsByClassName(node, classname)2653{2654    var a = [];2655    var re = new RegExp('(^| )'+classname+'( |$)');2656    var els = node.getElementsByTagName("*");2657    for(var i=0,j=els.length; i<j; i++)2658        if(re.test(els[i].className))a.push(els[i]);2659    return a;2660}2661function hasClassName(el, name) {2662    // Return true if the given element currently has the given class2663    // name. 2664    var re = new RegExp('(?:^|\\s)'+name+'(?:\\s|$)');2665  2666    if (el.className.match(re) != -1 && el.className.match(re) != null)2667    {2668        return true;2669    }2670    else2671    {2672        return false;2673    }2674  2675}2676function addClassName(el, name)2677{2678    if (!hasClassName(el, name)) el.className = (el.className+' '+name);2679}2680function removeClassName(el, name) {2681    // Remove the given class name from the element's className property.2682  2683    /*var re = new RegExp('(^|\\s)'+name+'(?:\\s|$)');2684    el.className = el.className.replace(re, '$1');*/2685    2686    var curClasses = el.className.split(" ");2687    var newClasses = [];2688    2689    for (var i = 0; i < curClasses.length; i++)2690    {2691        if (curClasses[i] != "" && curClasses[i] != name) newClasses.push(curClasses[i]);2692    }2693    2694    el.className = newClasses.join(" ");2695      2696}2697function toggleClassName(el, name)2698{2699    if (hasClassName(el, name))2700    {2701        removeClassName(el, name);2702    }2703    else2704    {2705        addClassName(el, name);2706    }2707}2708function getPageOffsetLeft(el) {2709  var x;2710  // Return the x coordinate of an element relative to the page.2711  x = el.offsetLeft;2712  if (el.offsetParent != null)2713    x += getPageOffsetLeft(el.offsetParent);2714  return x;2715}2716function getPageOffsetTop(el) {2717  var y;2718  // Return the x coordinate of an element relative to the page.2719  y = el.offsetTop;2720  if (el.offsetParent != null)2721    y += getPageOffsetTop(el.offsetParent);2722  return y;2723}2724function $showException(objErr,CloseMethod, extraPath)2725{2726    var finalErr = "";2727    var closeMethod = "doHidePopup()";2728    2729    if ((CloseMethod != null) && (typeof(CloseMethod) != "undefined"))2730    {2731        closeMethod = CloseMethod;2732    }2733       2734    2735    finalErr += "<Table cellspacing=2 cellpadding=0 border=0><tr><td colspan=2 align=left class='smllabelbold'>An unexpected error occurred, please review the following information:</td></tr><tr><td colspan=2>&nbsp;</td></tr>";2736    2737    if (objErr.Title != null)2738    {2739        finalErr += "<tr><td valign=top align=left class='smllabelbold'>Title:</td><td align=left class='smllabel'>" + objErr.Title + "</td></tr>";2740    }2741    2742    if (objErr.Type != null)2743    {    2744        finalErr += "<tr><td valign=top align=left class='smllabelbold'>Type:</td><td align=left class='smllabel'>" +  objErr.Type + "</td></tr>";2745    }2746    2747    if (objErr.Description != null)2748    {2749        finalErr += "<tr><td valign=top align=left class='smllabelbold'>Description:</td><td align=left class='smllabel'>" + objErr.Description + "</td></tr>"2750    }2751    2752    if (objErr.StackTrace != null)2753    {2754        finalErr += "<tr><td valign=top align=left class='smllabelbold'>StackTrace:</td><td align=left class='smllabel'>" + objErr.StackTrace + "</td></tr>"2755    }    2756    2757    finalErr += "</table>";2758    if (!extraPath)2759   {2760    extraPath = "";2761   } 2762    doPopupIframe("Error",finalErr,450,200,"OK",closeMethod,"","","","","20000","",extraPath, "", "error");2763}2764function $CustomError()2765{2766    this.Title;2767    this.Type;2768    this.Description;2769    this.StackTrace;2770}2771function $addEvent(obj, evType, fn)2772{2773	//if(evType.indexOf("on"))2774	//{2775	//    evType = ReplaceID(evType,"on","");2776	//}2777	var evTypeRef = '__' + evType;2778	if (obj[evTypeRef])2779	{2780		if (array_search(fn, obj[evTypeRef]) > -1) return;2781	}2782	else2783	{2784		obj[evTypeRef] = [];2785		if (obj['on'+evType]) obj[evTypeRef][0] = obj['on'+evType];2786		obj['on'+evType] = handleEvent;2787	}2788	obj[evTypeRef][obj[evTypeRef].length] = fn;2789}2790/* Adds multiple events to an object that fires the same function */2791function $addEvents(obj, evs, fn)2792{2793    for (var i = evs.length; --i >= 0;)2794	{2795		$addEvent(el, evs[i], func);2796	}2797}2798function $removeEvent(obj, evType, fn)2799{2800    var evTypeRef = '__' + evType;2801    if (obj != null)2802    {2803	    if (obj[evTypeRef])2804	    {2805		    var i = array_search(fn, obj[evTypeRef]);2806		    if (i > -1) delete obj[evTypeRef][i];2807	    }2808	}2809}2810/* Remove multiple events from an object that fires the same function */2811function $removeEvents(obj, evs, fn)2812{2813    for (var i = evs.length; --i >= 0;)2814	{2815		$removeEvent(el, evs[i], func);2816	}2817}2818function handleEvent(e)2819{2820	e = e || window.event;2821	var evTypeRef = '__' + e.type;2822	var retValue = true;2823	for (var i = 0, j = this[evTypeRef].length; i < j; i++)2824	{2825		if (this[evTypeRef][i])2826		{2827			this.__fn = this[evTypeRef][i];2828			retValue = this.__fn(e) && retValue;2829		}2830	}2831	if (this.__fn) try { delete this.__fn; } catch(e) { this.__fn = null; }2832	return retValue;2833}2834function array_search(val, arr)2835{2836	var i = arr.length;2837	while (i--)2838		if (arr[i] && arr[i] === val) break;2839	return i;2840}2841/* SVE: 15/02/2007: shows a mini version of the busydivtag, when only a certain div should be disabled */2842function miniBusyDiv(divTagID)2843{2844//    if (_MustShowPop)2845//   {2846//        return;2847//   } 2848   if ($id('miniBusy_' + divTagID)) 2849   {2850        var controlMiniState = ($id('miniBusy_' + divTagID));2851        controlMiniState.parentNode.removeChild(controlMiniState); 2852   }  2853  2854    var controlwidth = ($id(divTagID)).offsetWidth;2855    var controlheight = ($id(divTagID)).offsetHeight;2856    var controlzindex =   10000;2857    var controltop  = getElementTrueTop($id(divTagID));2858    var controlleft  = getElementTrueLeft($id(divTagID));2859       2860    var controlBusyDiv = document.createElement("div");2861    controlBusyDiv.id = 'miniBusy_' + divTagID; 2862    controlBusyDiv.style.width = controlwidth;2863    controlBusyDiv.style.height = controlheight;2864    controlBusyDiv.style.zIndex =  controlzindex;2865    controlBusyDiv.style.left =  controlleft;2866    controlBusyDiv.style.top =  controltop;  2867    controlBusyDiv.style.position = "absolute";2868    controlBusyDiv.style.background = "white";2869    controlBusyDiv.style.border = "2px solid whitesmoke"; 2870    controlBusyDiv.style.filter = "Alpha(opacity=85)"; 2871    controlBusyDiv.innerHTML = "<table height='100%' width='100%'><tr valign='middle'><td align='center'><img src='../images/Blue_Big_Rotate.gif' /></td></tr></table>"; 2872    ($id(divTagID)).disabled = "disabled"; 2873    document.body.appendChild(controlBusyDiv);  2874}2875function miniBusyDone(divTagID)2876{2877    if ($id(divTagID))2878   { 2879        if ($id('miniBusy_' + divTagID)) 2880       {2881            var controlBusyDiv = ($id('miniBusy_' + divTagID));2882            controlBusyDiv.parentNode.removeChild(controlBusyDiv); 2883       } 2884       ($id(divTagID)).disabled = "";2885   }2886}2887/* end mini busy div */2888function generatePopupHTML(id, heading, info, content, buttons, height, width, closeButtonName, closeFunction, infoHeader, infoContent, pathExtra,  popupImage)2889{2890    if (!pathExtra)2891   {2892        pathExtra = "";2893   } 2894   2895   if (!popupImage)2896   {2897        popupImage = "";2898   }2899    var htmlValue = "";2900   2901    htmlValue += '<table width="100%" height="100%" cellpadding="0" border="0" cellspacing="0" id="' + id + '">'; 2902    htmlValue += '			<tr>';2903	htmlValue += '			<td valign=top align=left >';2904    htmlValue += '		           <table id="body" width="100%" height="100%" border="0" cellpadding="0" cellspacing="0" >'; 2905    htmlValue += '		            	<tr >';2906    htmlValue += '							<td valign=top><IMG SRC="' + pathExtra +  '../images/popup_top_left.gif"></td>';2907    htmlValue += '	    				    <td class="toptab_repeat  " width="100%" >';2908    htmlValue += '								<table cellpadding="0" cellspacing="0" width="100%" >';2909    htmlValue += '									<tr>';2910    htmlValue += '										<td colspan="2"><IMG height="3px" SRC="' + pathExtra +  '../images/spacer.gif"></td>';2911    htmlValue += '									</tr>';2912    htmlValue += '									<tr>';2913    htmlValue += '										<td >';2914    htmlValue += '										    <table width=100%>';2915    htmlValue += '										        <tr>';2916    htmlValue += '										            <td class="white_heading" >&nbsp;' +  heading + '</td>';2917    if  ((closeFunction != null) &&  (closeFunction.length > 0))2918    { 2919        htmlValue += '										             <td align=right>';2920        htmlValue += '                                                         <img src="' + pathExtra +  '../images/close.gif" onclick="' + closeFunction + '" style="cursor:hand;" /></td>';2921   } 2922    htmlValue += '										        </tr>';   2923    htmlValue += '										    </table>';2924    htmlValue += '                                       </td>';2925    htmlValue += '			                        </tr>';2926    htmlValue += '								</table>';2927    htmlValue += '							</td>';2928    htmlValue += '							<td align="right" valign=top><IMG SRC="' + pathExtra +  '../images/popup_top_right.gif"></td>';2929    htmlValue += '						   </tr>';2930    htmlValue += '						<tr>';2931    htmlValue += '							<td colspan="3" height="100%" bgcolor="white">';2932    htmlValue += '								<table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="white">';2933    htmlValue += '									<tr>';2934    htmlValue += '										<td class="tabs_left_plain_repeat" width="3px"><img width="3px" src="' + pathExtra +  '../images/spacer.gif"></td>';2935    htmlValue += '										<td width="100%" height="100%">';2936    htmlValue += '											<table width="100%" height="100%" cellpadding="1" cellspacing="1"  border="0">';2937    htmlValue += '												<tr>';2938    htmlValue += '										            <td style="width: 1px;"></td>';2939    htmlValue += '										        </tr>';2940    if (info.length > 0)2941   { 2942        htmlValue += '												<tr>';2943        if (popupImage.length > 0)2944        {2945            htmlValue += '<td  colspan="2" valign="top" width="100%"><div id="info" style="height:30px; overflow:auto;width:100%;" class="info"> ' + info + '</div>';2946        }2947        else2948        {2949            htmlValue += '<td  valign="top" width="100%"><div id="info" style="height:30px; overflow:auto;width:100%;" class="info"> ' + info + '</div>';2950        }2951        htmlValue += '                                                   </td>';2952        htmlValue += '												</tr>';2953   } 2954    htmlValue += '												<tr valign=top>';2955  if (popupImage.length > 0)2956   {2957         htmlValue += '<td style=\"width:48px;\"><img src="' + pathExtra + '../images/' + popupImage + '48x48.gif" /></td>'; 2958         htmlValue += '													<td   height=' +  (parseInt(height) + 10) ;2959   }2960   else2961   {2962        htmlValue += '													<td colspan="2" style="padding-left:10px;" height="' +  (parseInt(height) + 10) + 'px"';2963   }2964    if (content.length > 0)2965    { 2966        htmlValue +=                                                           ' class=black_bdtxt >' + content;2967    } 2968   else2969   {2970        htmlValue +=                                                         '>';2971   } 2972    htmlValue += '													</td>';2973    htmlValue += '                                               </tr>';2974    htmlValue += '											</table>';2975    htmlValue += '										</td>';2976    htmlValue += '										<td class="tabs_right_plain_repeat" style="border-right: solid 1px #E0E0E0" width=4px><img width=4px src="' + pathExtra +  '../images/spacer.gif"></td>';2977    htmlValue += '									</tr>';2978    htmlValue += '								</table>';2979    htmlValue += '							</td>';2980    htmlValue += '						</tr>';2981   //if buttons should be added into the popup 2982    if (buttons.length > 0)2983   {  2984   2985        //left edge of buttons2986        htmlValue += '					<tr>';2987        htmlValue += '						    <td colspan=3>';2988        htmlValue += '						        <table cellpadding=0 cellspacing=0 border=0 width="100%">';2989        htmlValue += '						            <tr>';2990        2991        if (infoHeader.length > 0)2992        {2993            htmlValue += '						                <td rowspan=2><img src="' + pathExtra +  '../images/help_button.gif" onclick="ShowK2Help(' + infoHeader + ')" /></td>';2994            //onclick=showHelpPopup("help' + id + '")2995        }2996        else2997        {2998           htmlValue += '						                <td rowspan=2><img src="' + pathExtra +  '../images/button_left_two_edges.gif" /></td>';2999        }3000        htmlValue += '						                <td class="button_bar_repeat" width=100%></td>';3001        htmlValue += '							            <td class="button_bar_repeat" valign=top width=4px><img src="' + pathExtra +  '../images/button_left.gif" /></td>';3002        3003        var btnValues = buttons.split("☺");3004        var btnValue = '';3005        var fn = '';3006        var looper = 0;3007        for (var i=0; i<btnValues.length; i++)3008        {3009            if (i % 2 == 0)3010            {3011                //new button & values3012                btnValue = btnValues[i];3013                if (btnValue.length > 0)3014               { 3015                    fn = btnValues[i + 1];3016                    if (fn.split("|")[1] != null)3017                    {3018                        _popEvents[fn.split("|")[1]] = fn.split("|")[0];3019                        fn = fn.split("|")[0];            3020                    }     3021                3022                    htmlValue += '						            <td style="cursor:hand;" class="button_repeat"  id="' + btnValue +'" onclick="' + fn +'" onmouseover=\'popupButtonMouseOver(event, "' +  pathExtra +'")\' onmouseout=\'popupButtonMouseOut(event, "' +  pathExtra +'")\' nowrap>' +  btnValue+ '</td>';3023                    looper += 1; 3024               }3025               3026                if ((i + 2) < btnValues.length)3027                {3028                    htmlValue += '							            <td ><img src="' + pathExtra +  '../images/toolbar_repeat-.gif" /></td>';3029                    looper +=1;3030                }3031                else3032                {3033                    htmlValue += '							            <td rowspan=2 ><img src="' + pathExtra +  '../images/buttonbar_right2.gif" /></td>';3034                    looper +=2;3035                }3036             }3037        }3038    3039        //repeater for looper 3040        htmlValue += '						            </tr>';3041        htmlValue += '						            <tr>';3042        htmlValue += '						                <td class=button_bar_bottom_repeat colspan=' + looper + ' width=100% height=4px ><img src="' + pathExtra +  '../images/spacer.gif" /></td>';3043        htmlValue += '						            </tr>';3044        htmlValue += '						        </table>';3045        htmlValue += '						    </td>';3046        htmlValue += '						</tr>';3047        htmlValue += '					</table>';3048        htmlValue += '				</td>';3049        htmlValue += '			</tr>';3050    }3051   else // just the "normal" closing tags - without place for buttons3052   {3053       htmlValue += '					<tr>';3054        htmlValue += '						    <td colspan=3>';3055        htmlValue += '						        <table cellpadding=0 cellspacing=0 border=0 width="100%">';3056        htmlValue += '						            <tr>';3057        htmlValue += '						                <td rowspan=2><img src="' + pathExtra +  '../images/bottom_left_clear.gif" /></td>';3058        htmlValue += '						                <td width=100% style="background:white;"></td>';3059        htmlValue += '							            <td rowspan=2 ><img src="' + pathExtra +  '../images/buttonbar_right_clear.gif" /></td>';3060        htmlValue += '						            </tr>';3061        htmlValue += '						            <tr>';3062        htmlValue += '						                <td class=button_bar_bottom_repeat width=100%  ><img src="' + pathExtra +  '../images/spacer.gif" /></td>';3063        htmlValue += '						            </tr>';3064        htmlValue += '						        </table>';3065        htmlValue += '						    </td>';3066        htmlValue += '						</tr>';3067        htmlValue += '					</table>';3068        htmlValue += '				</td>';3069        htmlValue += '			</tr>';3070   }  3071    htmlValue += '		</table>';3072   3073//   htmlValue += '<tr><td>';3074//   htmlValue += generateInfoPopupHTML('blablabla','morebla die bla <br>again and again', width, 0);3075//   htmlValue += '</td></tr>';    3076     3077     return htmlValue; 3078}3079function setPopupButtonStatus(id, status)3080{3081    //id = id of control3082   //status = new status (disabled, enabled)3083   //todo:  remove the click events from the buttons (or do the check from the functions?)3084   ($id(id)).setAttribute("status", status); 3085   if (status == "disabled")3086   {3087        ($id(id)).className = "button_repeat_disabled";3088   }3089   else3090   {3091        ($id(id)).className = "button_repeat";3092   }3093}3094function generateInfoPopupHTML(InfoHeader, InfoText, width, height, pathExtra)3095{3096    var htmlValue = '';3097    if ((!width)||(width < 100))3098   {3099        width = 100;3100   }  3101    htmlValue += '<table cellpadding=0 cellspacing=0 border=0 width="' + width +'">';3102    htmlValue += '   <tr>';3103    htmlValue += '       <td width=6px><img src="' + pathExtra +  '../images/help_left_top.gif" /></td>';3104    htmlValue += '       <td class=help_top_repeat></td>';3105    htmlValue += '       <td ><img src="' + pathExtra +  '../images/help_top_right.gif" /></td>';3106    htmlValue += '   </tr>';3107    htmlValue += '   <tr>';3108    htmlValue += '       <td class=help_left_repeat height=100% width=6px></td>';3109    htmlValue += '       <td width=100% class=help_body><b><i>' + InfoHeader + '</i></b><br>';3110    htmlValue += InfoText;3111    htmlValue += '       </td>';3112    htmlValue += '       <td class=help_right_repeat></td>';3113    htmlValue += '   </tr>';3114    htmlValue += '   <tr>';3115    htmlValue += '       <td colspan=3>';3116    htmlValue += '           <table cellpadding=0 cellspacing=0>';3117    htmlValue += '               <tr>';3118    htmlValue += '                   <td colspan=2 align=left width=52px><img src="' + pathExtra +  '../images/help_left_bottom.gif" /></td>';3119    htmlValue += '                   <td class=help_bottom_repeat width=100%></td>';3120    htmlValue += '                   <td valign=top><img src="' + pathExtra +  '../images/help_right_bottom.gif" /></td>';3121    htmlValue += '               </tr>';3122    htmlValue += '          </table>';3123    htmlValue += '       </td>';3124    htmlValue += '     </tr>';3125    htmlValue += '</table>';3126   3127    return htmlValue; 3128}3129function createHelpPopup(ID, InfoHeader, InfoText, width, height, pathExtra)3130{3131    var helpDiv;3132    if ($id(ID))3133   {3134        helpDiv = ($id(ID));3135   }3136   else3137   {3138        helpDiv = document.createElement("DIV");3139        helpDiv.id = ID;3140        document.appendChild(helpDiv);3141   }      3142   helpDiv.innerHTML = generateInfoPopupHTML(InfoHeader, InfoText, width, height, pathExtra);3143   helpDiv.style.display = "none";3144   helpDiv.style.position = "absolute";3145}3146function showHelpPopup(ID, top, left)3147{3148    var helpDiv;3149    if ($id(ID))3150   {3151        helpDiv = ($id(ID));3152        helpDiv.style.display = "";3153        if (!top)3154        {3155            top = event.clientY;3156        }3157        if (!left)3158        {3159            left = event.clientX;3160        }3161        helpDiv.style.top = top;3162        helpDiv.style.left = left;3163   }3164}3165function hideHelpPopup(ID)3166{3167     var helpDiv;3168    if ($id(ID))3169    {3170        helpDiv = ($id(ID));3171        helpDiv.style.display = "none";3172    }3173}3174function $showPopup(HeadingText, ContentText, ControlID, Height, Width, IframeSrc, CloseFunction, ButtonValues, ZIndex, BusyDivID, ExtraPath, InfoText, HelpHeader, HelpContents, Drag, popupImage)3175{3176    //Text in the header of the popup3177    if (!HeadingText)3178   {3179        HeadingText = "";3180   } 3181   //Text to be displayed in the popup, if no control is popped up3182   if (!ContentText)3183   {3184        ContentText = "";3185   } 3186    //control to display in the popup3187   if (!ControlID)3188   {3189        ControlID = "";3190   }3191   //height of the popup3192   if (!Height)3193   {3194        Height = "";3195   } 3196   //width of the popup3197   if (!Width)3198   {3199        Width = "";3200   }3201   //src of the iframe that will be popped up3202   if (!IframeSrc)3203   {3204        IframeSrc = "";3205   }3206   //function to execute on the close button3207   if (!CloseFunction)3208   {3209        CloseFunction = "";3210   }3211   //list of buttons with relevant functions3212   if (!ButtonValues)3213   {3214        ButtonValues = "";3215   }3216   //zindex of popup3217   if (!ZIndex)3218   {3219        ZIndex = "";3220   }3221   //name of busy div to be displayed3222   if (!BusyDivID)3223   {3224        BusyDivID = "";3225   }3226   //extra path which will be appended to src of images of popup3227   if (!ExtraPath)3228   {3229        ExtraPath = "";3230   }3231   //information text of popup (green section)3232   if (!InfoText)3233   {3234        InfoText = "";3235   }3236   //Help ID to be passed to the help file3237   if (!HelpHeader)3238   {3239        HelpHeader = "";3240   }3241   //contents of help (redundant)3242   if (!HelpContents)3243   {3244        HelpContents = "";3245   }3246   //whether the popup should be draggable - not implemented3247   if (!Drag)3248   {3249        Drag = "";3250   }3251   //image to be displayed next to the message in the popup3252   //options: warning, info, error, help3253   if (!popupImage)3254   {3255        popupImage = "";3256   }3257   3258   //declaration of variables3259    var IframeZIndex = 10019;3260    var DivZIndex = 10020; 3261    var currentIndex = 9020; 3262    var divAlert ; 3263    var ControlDiv;3264    var ifr; 3265   3266   //calculation of relevant zIndeces3267    if (ControlID.length > 0)3268   { 3269        if (($id(ControlID)).style.zIndex)3270        {3271            currentIndex = ($id(ControlID)).style.zIndex;    3272        }      3273        else3274        {3275            ($id(ControlID)).style.zIndex = currentIndex;3276        }3277         DivZIndex = parseInt(parseInt(currentIndex) - parseInt(1));3278         IframeZIndex = parseInt(parseInt(currentIndex) - parseInt(2));3279   } 3280    3281   //generate/reference foreground iframe  3282    if ((ControlID.length == 0) && (IframeSrc.length > 0))3283   {3284        var IframeControl = ($id("IFrameSrc"));3285        if(!(IframeControl))3286        {3287            IframeControl = document.createElement("IFRAME");3288            IframeControl.id = "IFrameSrc";3289            IframeControl.frameBorder =0;   3290            document.body.appendChild(IframeControl);3291        }3292        IframeControl.style.width = Width;3293        IframeControl.style.height = (parseInt(Height) + 15);3294        IframeControl.src = IframeSrc;3295        3296        IframeControl.style.zIndex = (parseInt(DivZIndex) + parseInt(2));3297        ControlID = IframeControl.id;3298   }3299    //Busy Div tag & zIndex3300    if (ZIndex == undefined)3301   {3302        ZIndex= "";3303   } 3304    if ((ZIndex=="undefined")||(ZIndex.length == 0))3305    {3306        3307        if (ControlID.length > 0)3308        {3309            busyDivTag((parseInt(DivZIndex)-parseInt(2)), "busy_" + ControlID);3310        } 3311        else3312        {3313            if ((BusyDivID=="undefined")||(BusyDivID.length == 0))3314            {3315                busyDivTag();3316             }3317            else3318            {3319                busyDivTag((parseInt(DivZIndex)-parseInt(2)),  "busy_" + BusyDivID);3320            }  3321        }3322    }3323    else3324    {3325         IframeZIndex = (parseInt(ZIndex) + parseInt(1));3326         DivZIndex = (parseInt(ZIndex) + parseInt(2));3327         busyDivTag(ZIndex,BusyDivID);3328    }3329   3330   //display of control3331   if (!ControlID)3332   {3333        ControlID = "";3334   }3335   else  if ($id(ControlID))3336   { 3337        ControlDiv = $id(ControlID);3338        ControlDiv.style.display = "block"; 3339        if (!Height)3340       {3341            Height =(parseInt(ControlDiv.style.height.replace("px","")));3342       } 3343       3344       if (!Width)3345       {3346            Width =  (parseInt(ControlDiv.style.width.replace("px","")));3347       }3348      3349        if ((Height == "") || isNaN(Height))3350	        Height = ControlDiv.offsetHeight;3351    		3352        if ((Width == "") || isNaN(Width))3353	        Width = ControlDiv.offsetWidth;	3354   }3355   3356   if ((CloseFunction.length == 0)||(CloseFunction == "doHidePopup()"))3357   {3358       //close function of the popup3359       CloseFunction = "doHidePopup('" + ControlID + "')";3360   }3361    var screenL = document.documentElement.offsetWidth - Width ;3362    var screenH = document.documentElement.offsetHeight - Height; 3363    if (InfoText.length > 0)3364    {3365        screenH = screenH - 110;3366    }3367    var xtraPopupHeight=70;3368    var top = ((screenH-xtraPopupHeight)/2) +  parseInt(returnScrollDimensions(0));3369    if (top<0)3370    {3371        top=0;3372    } 3373    var left = (screenL/2) + parseInt(returnScrollDimensions(1));3374    //poisitioning of div    3375    var stDiv = "top:" + parseInt(top-5) + "px;left:" + parseInt(left-5) + "px;width:" + (parseInt(Width)+10) + "px;height:" + (parseInt(Height)+10) + "px;"3376    3377   if ($id("container" + ControlID))3378   {3379        divAlert = ($id("container" + ControlID));3380   }3381   else3382   {3383       divAlert = document.createElement("DIV"); 3384       divAlert.id = "container" + ControlID;3385       divAlert.className = "dragmain";3386     3387      //add control/parentdiv to array of controls which can be moved3388      if ($id(ControlID))3389      {3390        popupControls.push(($id(ControlID)));3391      }3392      else3393      {3394        popupControls.push(divAlert);3395      }3396      3397        if ((ControlID.length == 0)||(IframeSrc.length > 0))3398        {3399            document.body.appendChild(divAlert);3400        }3401        else3402        {3403            ($id(ControlID)).parentNode.appendChild(divAlert);3404        }3405   } 3406    //set the innerhtml of the div3407   divAlert.innerHTML = generatePopupHTML('tblContainer' + ControlID, HeadingText, InfoText, ContentText, ButtonValues, Height, Width, "X", CloseFunction, HelpHeader, HelpContents, ExtraPath, popupImage)3408   divAlert.style.cssText = "position:absolute;display:none;z-index:"+ DivZIndex +";" + stDiv;3409            3410    //add background iframe3411   if ($id("iframepopups" + ControlID))3412   {3413     ifr = ($id("iframepopups"  + ControlID));3414   } 3415   else3416   {3417     ifr = document.createElement("IFRAME");3418     ifr.id = "iframepopups"  + ControlID;3419     divAlert.parentElement.appendChild(ifr);3420    }3421   ifr.className="dragmeIfr"; 3422    ifr.frameBorder = "0";3423    var table = $id("tblContainer" + ControlID);3424    var st = "top:" + parseInt(top) + "px;z-index:" + IframeZIndex+";position:absolute;left:" + parseInt(left) + "px;width:" + (parseInt(Width)-5) + "px;height:" + (parseInt(Height)-5) + "px"; 3425    3426    //toggle the relevant visibility of the div and iframe  3427    $DivSetVisible(true,table,ifr,st);3428     3429     if (ControlDiv)3430     {3431        //Control style 3432        var stcontrol = "";3433        if (InfoText.length > 0)3434        {3435             stcontrol = ";top:" + (parseInt(top) + parseInt(75)) + "px;z-index:" + parseInt(parseInt(DivZIndex) + parseInt(1)) + ";position:absolute;left:" + (parseInt(left))  + "px;";3436        }3437        else3438        { 3439             stcontrol = ";top:" + (parseInt(top) + parseInt(33)) + "px;z-index:" + parseInt(parseInt(DivZIndex) + parseInt(1)) + ";position:absolute;left:" + (parseInt(left))  + "px;";3440        } 3441        ControlDiv.style.cssText += stcontrol;3442   }3443    divAlert.style.display = "block";3444    divAlert.focus(); 3445   3446//     if (HelpHeader.length > 0)3447//     {3448//        createHelpPopup("help" + 'tblContainer' + ControlID, HelpHeader, HelpContents, 0, 200, ExtraPath);3449//     } 3450}3451function getElementTrueLeft(inputObj)3452{3453    var returnValue = inputObj.offsetLeft;3454    3455    while((inputObj = inputObj.offsetParent) != null)3456    {3457        if(inputObj.tagName!='HTML')returnValue += inputObj.offsetLeft;3458    }3459    3460    return returnValue;3461}3462function getElementTrueTop(inputObj)3463{  3464    var returnValue = inputObj.offsetTop;3465    3466    while((inputObj = inputObj.offsetParent) != null)3467    {3468        if(inputObj.tagName!='HTML')returnValue += inputObj.offsetTop;3469    }3470    return returnValue;3471}3472function popupButtonMouseOver(e, pathExtra)3473{3474    var openevent = (e) ? e : window.event;3475    var tg = (e.target) ? e.target : e.srcElement3476    if (tg.getAttribute("status") == "disabled")3477   {3478        return false;3479   } 3480    tg.className = "green_button_repeat3"; 3481    if (tg.previousSibling)3482    {3483        if (tg.previousSibling.childNodes.length > 0)3484       {3485            if ((tg.previousSibling.childNodes[0].tagName.toLowerCase()  == "img") && (tg.previousSibling.childNodes[0].src.toLowerCase().indexOf("left") > 0))3486            {3487                tg.previousSibling.childNodes[0].src =   pathExtra + "../images/green_button_left.gif";3488            }3489       } 3490    }3491    if (tg.nextSibling)3492    {3493        if (tg.nextSibling.childNodes.length > 0)3494       {3495            if ((tg.nextSibling.childNodes[0].tagName.toLowerCase()  == "img") && (tg.nextSibling.childNodes[0].src.toLowerCase().indexOf("right") > 0))3496            {3497                tg.nextSibling.childNodes[0].src =   pathExtra + "../images/buttonbar_green_right.gif";3498            }3499       } 3500    } 3501    3502}3503function popupButtonMouseOut(e, pathExtra)3504{3505    var openevent = (e) ? e : window.event;3506    var tg = (e.target) ? e.target : e.srcElement3507    if (tg.getAttribute("status") == "disabled")3508   {3509        return false;3510   }  3511    tg.className = "button_repeat";3512     if (tg.previousSibling)3513    {3514        if (tg.previousSibling.childNodes.length > 0)3515       {3516            if ((tg.previousSibling.childNodes[0].tagName.toLowerCase()  == "img") && (tg.previousSibling.childNodes[0].src.toLowerCase().indexOf("left") > 0))3517            {3518                tg.previousSibling.childNodes[0].src =   pathExtra + "../images/button_left.gif";3519            }3520       } 3521    }3522    if (tg.nextSibling)3523    {3524        if (tg.nextSibling.childNodes.length > 0)3525       {3526            if ((tg.nextSibling.childNodes[0].tagName.toLowerCase()  == "img") && (tg.nextSibling.childNodes[0].src.toLowerCase().indexOf("right") > 0))3527            {3528                tg.nextSibling.childNodes[0].src =   pathExtra + "../images/buttonbar_right2.gif";3529            }3530       } 3531    }3532}3533//Pass the URL , it will return the filename3534function $getFileName(URL)3535{3536    var tr = URL;3537    var strBack = "";3538    len = tr.length 3539    rs = 0 3540    for (i = len; i > 0; i--) 3541    { 3542            vb = tr.substring(i,i+1) 3543            if (vb == "/" && rs == 0) 3544             { 3545                strBack =  tr.substring(i+1,len);3546                rs = 1 3547             } 3548    }3549    3550    return strBack;3551}3552function $swopImage(URL,to,from)3553{3554    //http://bp1/images/area1.gif3555    //area1.gif3556    var filename = $getFileName(URL);3557    var fileTemp = filename;3558    if(filename == "")3559    {3560        alert('Error in swop Image');3561    } 3562    else3563    {3564        fileTemp = $rep(fileTemp,to,from);3565        fileTemp = $rep(URL,filename,fileTemp);3566    }3567    3568    return fileTemp;3569}3570//////////3571function showSimplePopupDiv(popuptablename, nohide, top, left)3572{3573    //shows the context menu type, showing the popuptable name's innerHTML3574   // need to add your own getTopPos & getLeftPos function in your own JS for  checkoutsideWidth & checkoutsideBottomPopUp to work - specifically done like this to reuse code, but work with calendar3575    var htmlValue = '';3576    htmlValue +=' <table class="context_menu_main"> ';3577    htmlValue +='     <tr> ';3578    htmlValue +='            <td class="context_menu_second"> ';3579    if (!nohide)3580    {3581        htmlValue +='                <table cellpadding="1" cellspacing="0" onmouseleave="closeSimplePopupDiv()">';3582    }3583    else3584    {3585        htmlValue +='                <table cellpadding="1" cellspacing="0">';3586    }3587    htmlValue +=  ($id(popuptablename)).innerHTML;3588    htmlValue +='                </table>' 3589    htmlValue +='            </td> ';3590    htmlValue +='       </tr> ';3591    htmlValue +='    </table> ';3592    3593    var popupDiv =($id("simplePopupDiv"));3594    if (popupDiv) 3595    {3596        popupDiv.innerHTML = htmlValue;3597    }3598    else3599    {3600        popupDiv = document.createElement("div");3601        popupDiv.style.position = "absolute";3602        popupDiv.style.display = "none";3603        popupDiv.style.backgroundColor = "white";3604        popupDiv.id= "simplePopupDiv";3605        popupDiv.innerHTML = htmlValue;3606        document.body.appendChild(popupDiv);3607    }3608    3609    //do the physical popup section3610    var IfrRef = $id("backgroundframe");3611    if (!IfrRef)3612    {3613        IfrRef = document.createElement("iframe");3614        IfrRef.id = "backgroundframe";3615        document.body.appendChild(IfrRef);3616    }3617    3618    popupDiv.style.zIndex=9031;3619    popupDiv.style.display = "block";3620    IfrRef.style.position = 'absolute';3621    IfrRef.style.width = popupDiv.offsetWidth ;3622    IfrRef.style.height = popupDiv.offsetHeight ;3623    IfrRef.style.zIndex = popupDiv.style.zIndex - 1;3624    IfrRef.style.display = "block";3625    IfrRef.style.backgroundColor = "black";3626    3627     var iPos = 0;3628     var xPosRec = 0;3629     3630    if (event)3631    {3632        var obj= event.srcElement;3633    3634        iPos = checkoutsideWidth(obj,IfrRef.style.width, "MenuStructureScrollDiv");3635        xPosRec = checkoutsideBottomPopUp(obj,IfrRef.style.height, "MenuStructureScrollDiv");3636    }3637    else3638    {3639        iPos = left;3640        xPosRec = top;3641    }3642    3643   IfrRef.style.left = parseInt(iPos);3644   IfrRef.style.top = parseInt(xPosRec);3645   3646   popupDiv.style.left = parseInt(iPos);3647   popupDiv.style.top = parseInt(xPosRec);3648}3649function closeSimplePopupDiv()3650{3651    var IfrRef = $id("backgroundframe");3652    var div = ($id("simplePopupDiv"));3653    3654    if (div)3655    {3656        div.style.display = "none";3657    }3658    if (IfrRef)3659    {3660        IfrRef.style.display = "none";3661    }3662    3663     var tg = ($id("imageActionSelected"));3664     if (tg)3665     {3666        tg.src = "../images/black_context_arrow.gif";3667        tg.id = "";3668        tg.className = "normalItem";3669    }3670}3671function ShowK2Help(helpID)3672{3673    if (helpID == 0)3674        helpID = "";3675        3676    if (helpID != "")3677        window.open(buildURL("WorkspaceHelp/WorkspaceHelp.aspx?HelpID=" + helpID, null,"directories=0, location=0, menubar=0, titlebar=0, toolbar=0"));3678    else3679        window.open(buildURL("WorkspaceHelp/WorkspaceHelp.aspx", null,"directories=0, location=0, menubar=0, titlebar=0, toolbar=0"));3680}3681function ValidateDate(FromDate, ToDate, pagePath)3682{3683    if (FromDate > ToDate)3684    {3685        doPopup(Generic_js_DateValidationHeading, Generic_js_StartDateEndDate, 400 , 75, Generic_js_ButtonOk, "doHidePopup('dateCompare')|13", "", "", "", "", 11500, "dateCompare", pagePath,"","error");3686        return true;3687    }3688    else3689    {3690        return false;3691    }3692}3693function generateGuid()3694{3695    var result, i, j;3696    result = '';3697    for(j = 0; j < 32; j++)3698    {3699        if( j == 8 || j == 12|| j == 16|| j == 20)3700        {3701            result = result + '-';3702        }3703        i = Math.floor(Math.random()*16).toString(16).toUpperCase();3704        result = result + i;3705    }3706    return result;...

Full Screen

Full Screen

tools.js

Source:tools.js Github

copy

Full Screen

1/* jshint expr: true */2(function () {3    "use strict";4}());5define = define || function () {6    //7};8define(9    [10        "jquery",11        "jqueryui",12        "howler",13    ],14    function ($) {15        window.log = console.log;16        /*17         *18         *      Extending jQuery!  How cool is this?19         *20         *      A few functions to deal with various input types, their21         *      various change events, and methods for retrieving values22         *23         *24         *25         */26        // gets input type, like "button" or "radio"27        // usage: let type = $("#thisElement").getInputType();28        // NOTE can't use fat-arrow function here, because it screws with "this"29        $.fn.getInputType = function () {30            if (!$(this)) return log("No $(this) for getInputType!"); // NEW TEST sometimes it seems there's no "this"!31            const type = $(this).attr("type");32            const tagName = $(this)[0].tagName;33            return (type || tagName).toLowerCase();34        };35        // gets the input value for various types of input36        // like this: let value = $("#someElement").getInputValue();37        $.fn.getInputValue = function () {38            const type = this.getInputType();39            if (["text", "number", "textarea", "range", "select"].indexOf(type) !== -1) return this.val();40            if (type === "checkbox") return this.is(":checked") ? 1 : 0;41            if (type === "radio") {42                const name = $(this[0]).prop("name");43                return $(`input[name='${name}'']:checked`).val();44            }45            return null;46        };47        // gets the appropriate change event to listen for for various48        // kinds of inputs, e.g., "change", "click", or "input"49        $.fn.getInputChangeEvent = function () {50            const type = this.getInputType();51            const inputTypes = ["checkbox", "text", "textarea", "number", "radio", "select"];52            if (inputTypes.indexOf(type) !== -1) return "change";53            if (type === "button" || type === "submit") return "click";54            if (type === "range") return "input"; // 'input' responds while sliding; 'change' responds only when finished sliding55            return null;56        };57        let tools = {};58        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *59         *60         *61         *62         *      Simple timer - starts, stops, clears, does something every second, etc.63         *64         *65         *66         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */67        function timer(obj = {}) {68            obj = $.extend({69                onEachFrame: function () {70                    // log("Frame!");71                },72                onEachSecond: function () {73                    // log(lastSecond + " seconds");74                },75                onStart: function () {76                    log("Started");77                },78                onStop: function () {79                    // log("Stopped");80                },81                onPause: function () {82                    log("Paused");83                },84                onClear: function () {85                    // log("Cleared!");86                },87            }, obj);88            let t1 = Date.now();89            let timeElapsed = 0;90            let secondsCounter = 0;91            let timerIsRunning = false;92            function eachFrame() {93                t2 = Date.now()94                if (timerIsRunning) timeElapsed += (t2 - t1);95                if (timerIsRunning) secondsCounter += (t2 - t1);96                t1 = t2;97                checkForSecond();98                obj.onEachFrame();99                window.requestAnimationFrame(eachFrame);100            }101            function checkForSecond() {102                if (secondsCounter < 1000) return;103                secondsCounter -= 1000;104                obj.onEachSecond();105            }106            function start() {107                if (timerIsRunning) return;108                timerIsRunning = true;109                t1 = Date.now();110                eachFrame();111                obj.onStart();112            }113            function stop() {114                if (!timerIsRunning) return this;115                timerIsRunning = false;116                t1 = null;117                obj.onStop();118                return this;119            }120            function getTimeElapsed() {121                return timeElapsed;122            }123            function getSecondsElapsed() {124                return Math.floor(getTimeElapsed() / 1000);125            }126            function isRunning() {127                return timerIsRunning;128            }129            function pause() {130                timerIsRunning = false;131                t1 = null;132                obj.onPause();133                return this;134            }135            function reset() {136                stop();137                t1 = null;138                t2 = null;139                lastSecond = null;140                timeElapsed = 0;141                obj.onClear();142                return this;143            }144            return {145                isRunning,146                pause,147                reset,148                start,149                stop,150                getTimeElapsed,151                getSecondsElapsed,152            };153        }154        function Timer(obj = {}) {155            const controller = new TimerController(Ticker, Display, Interval);156            const public = this;157            function TimerController(Ticker, Display, Interval) {158                const ticker = new Ticker();159                const display = new Display();160                display.getMs = () => ticker.getElapsedMs();161            };162            function Ticker() {163                let elapsedMs = 0;164                let isRunning = false;165                let t1 = Date.now();166                let elapsedSeconds = 0;167                setInterval(() => {168                    const t2 = Date.now();169                    if (isRunning) elapsedMs += t2 - t1;170                    if (isRunning) checkForSecond(t2 - t1);171                    t1 = t2;172                }, 20);173                function checkForSecond(ms) {174                    elapsedMs += ms;175                    if (elapsedSeconds < 1000) return;176                    elapsedSeconds -= 1000;177                    this.onElapsedSecond();178                }179                this.getElapsedMs = () => elapsedMs;180                this.onElapsedSecond = () => undefined;181                this.changeRunningState = val => isRunning = val ?? !isRunning;182            }183            function Display() {184                const pad = t => t < 10 ? "0" + t : t;185                this.getMs = () => undefined;186                this.getFormattedTime = () => {187                    const ms = this.getMs();188                    const totalSeconds = Math.floor(ms / 1000);189                    const displaySeconds = totalSeconds % 60;190                    const minutes = Math.floor(totalSeconds / 60);191                    const hundredths = Math.floor(ms / 10) % 100;192                    return {193                        raw: {194                            totalSeconds,195                            displaySeconds,196                            minutes,197                            hundredths198                        },199                        padded: {200                            totalSeconds: pad(totalSeconds),201                            displaySeconds: pad(displaySeconds),202                            minutes: pad(minutes),203                            hundredths: pad(hundredths),204                        },205                    };206                }207            }208            // return {209            //     isRunning,210            //     pause,211            //     reset,212            //     start,213            //     stop,214            //     getTimeElapsed,215            //     getSecondsElapsed,216            // };217        }218        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *219         *220         *221         *222         *      Analyzing arrays to see if they intersect partially, completely, etc.223         *224         *225         *226         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */227        function arrayIntersectHandler(a1, a2) {228            if (arguments.length !== 2 || !Array.isArray(a1) || !Array.isArray(a2)) {229                return log("Didn't the right number of arrays!");230            }231            if (!a1.length || !a2.length) return false;232            const intersection = a1.filter(item => a2.indexOf(item) !== -1);233            const numOverlap = intersection.length;234            const arraysDoIntersect = !!numOverlap;235            const arraysDontOverlap = !arraysDoIntersect;236            const arraysOverlapCompletely = a1.every(item => a2.indexOf(item) !== -1) || a2.every(item => a1.indexOf(item) !== -1);237            return {238                numOverlap,239                arraysDoIntersect,240                arraysDontOverlap,241                arraysOverlapCompletely,242            };243        }244        function arraysDoIntersect(a1, a2) {245            return arrayIntersectHandler(a1, a2).arraysDoIntersect;246        }247        tools.arraysDoIntersect = arraysDoIntersect;248        function arraysOverlapCompletely(a1, a2) {249            return arrayIntersectHandler(a1, a2).arraysOverlapCompletely;250        }251        tools.arraysOverlapCompletely = arraysOverlapCompletely;252        function stringsIntersect(s1, s2, obj = {}) {253            const a1 = s1.split(" " ?? obj.breakOn);254            const a2 = s2.split(" " ?? obj.breakOn);255            return arraysDoIntersect(a1, a2);256        }257        tools.stringsIntersect = stringsIntersect;258        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *259         *260         *261         *262         *      Just a shortcut for the audio voices263         *264         *265         *266         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */267        const getAudioVoices = (function () {268            const baseArray = ["Emma", "Joanna", "Justin", "Matthew"];269            return function (doShuffle = false) {270                return doShuffle ? shuffleArray(baseArray) : baseArray;271            };272        }());273        tools.getAudioVoices = getAudioVoices;274        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *275         *276         *277         *278         *      Picking a random voice for the audio279         *280         *281         *282         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */283        const audioVoice = (function () {284            const voicesArray = getAudioVoices();285            const shuffledArray = getAudioVoices(true);286            let voicePointer = 0;287            return {288                rotateVoice: () => voicePointer++,289                getCurrentVoice: () => shuffledArray[voicePointer % voicesArray.length],290                getAllVoices: (obj = {}) => obj.shuffle ? shuffledArray : voicesArray,291            };292        }());293        tools.rotateVoice = audioVoice.rotateVoice;294        tools.getCurrentVoice = audioVoice.getCurrentVoice;295        tools.getAllVoices = audioVoice.getAllVoices;296        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *297         *298         *299         *      Simply plays a sound. Stops on any keypress.300         *301         *302         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */303        const simplePlayer = (function () {304            let isPlaying = false;305            let playerSettings = {};306            let howl = null;307            function set(obj = {}) {308                $.extend(playerSettings, obj);309                return true;310            }311            function play(file, obj = {}) {312                if (!file) return;313                howl && howl.stop();314                if (isPlaying) return;315                isPlaying = false;316                if (file.toString().indexOf(".mp3") === -1) file += ".mp3";317                const voice = obj.voice || audioVoice.pickRandom();318                howl = new Howl({319                    src: playerSettings.useCustomPath ? [file] : [`/audio/${voice}/${file}`],320                    autoplay: playerSettings.autoplay || true,321                    onplay: function () {322                        $(window).on("keydown", stop);323                        playerSettings.onplay && playerSettings.onplay();324                        obj.onplay && obj.onplay();325                    },326                    onend: function () {327                        $(window).off("keydown", stop);328                        isPlaying = false;329                        playerSettings.onstop && playerSettings.onstop();330                        obj.onstop && obj.onstop();331                    },332                    onstop: function () {333                        $(window).off("keydown", stop);334                        isPlaying = false;335                        playerSettings.onstop && playerSettings.onstop();336                        obj.onstop && obj.onstop();337                    },338                    onloaderror: function (e) {339                        log("Couldn't load " + file);340                    }341                });342            }343            function stop(e) {344                e.preventDefault();345                howl && howl.stop();346            }347            return {348                play,349                stop,350                set,351            };352        }());353        tools.simplePlayer = simplePlayer;354        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *355         *356         *357         *358         *      Loads a JavaScript file dynamically359         *360         *361         *362         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */363        function loadScript(scriptSrc, callback) {364            let scriptTag = document.createElement("script");365            scriptTag.src = scriptSrc;366            document.head.appendChild(scriptTag);367            scriptTag.onload = function () {368                callback && callback();369            };370        }371        tools.loadScript = loadScript;372        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *373         *374         *375         *376         *      Returns the average width of an array of jQuery elements377         *378         *379         *380         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */381        function getAverageWidth(elements = []) {382            let totalWidth = 0;383            elements.forEach($span => {384                $span = forceJQuery($span);385                totalWidth += $span.outerWidth();386            });387            return totalWidth / elements.length;388        }389        tools.getAverageWidth = getAverageWidth;390        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *391         *392         *393         *394         *      Forcing an element to be jQuery395         *396         *397         *398         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */399        function forceJQuery(element) {400            return element instanceof $ ? element : $(element);401        }402        tools.forceJQuery = forceJQuery;403        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *404         *405         *406         *407         *      Couldn't be simpler408         *409         *410         *411         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */412        function isMobile() {413            return typeof window.orientation !== "undefined";414        }415        tools.isMobile = isMobile;416        tools.isNotMobile = () => !isMobile();417        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *418         *419         *420         *421         *      Scrolls an element to the middle of the page (actually, the top of the element)422         *423         *424         *425         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */426        function scrollToMiddle(elem) {427            elem = (elem instanceof $) ? elem[0] : elem; // extracting HTML element from jQuery428            const absoluteElementTop = elem.getBoundingClientRect().top + window.pageYOffset;429            const middle = absoluteElementTop - (window.innerHeight / 2);430            window.scrollTo(0, middle);431        }432        tools.scrollToMiddle = scrollToMiddle;433        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *434         *435         *436         *437         *      Handles the saving an object or array in localStorage (or sessionStorage) as JSON438         *439         *440         *441         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */442        function objectStorage(masterKey, sessionOrLocalStorage = "sessionStorage") {443            if (!masterKey) return log("objectStorage requires a key for the local (or session) storage!");444            const storage = window[sessionOrLocalStorage]; // either "localStorage" or "sessionStorage"445            let json = safeParseJSON(storage[masterKey]);446            return function (p) {447                /*448                    Usage:449                    tools.userInfo()                       --> GETS the WHOLE string, parsed as JSON450                    tools.userInfo("clear")                --> DELETES the object entirely from storage451                    tools.userInfo("username")             --> GETS the "username" value from the object452                    tools.userInfo("username", "James")    --> SETS the "username" to "James"453                    tools.userInfo({ one: 1, two: 2 })     --> SETS multiple values to the object454                    tools.userInfo([1, 2, 3,])             --> SETS the whole ARRAY into storage455                */456                const numArgs = arguments.length;457                if (!numArgs) return Object.keys(json).length ? json : null; // returning null if it's an empty object458                const arg1 = arguments[0];459                const arg2 = arguments[1];460                // saving key + value, like "storeObject('numStudent', 3)"461                if (numArgs === 2) { // key + value, presumably462                    json[arg1] = arg2;463                    storage[masterKey] = JSON.stringify(json);464                    return json;465                }466                if (numArgs === 1) {467                    if (arg1 === "clear") return storage.removeItem(masterKey);468                    if (typeof arg1 === "string") return json[arg1];469                    // overwriting the whole value with array new array470                    if (Array.isArray(p)) {471                        storage[masterKey] = JSON.stringify(p);472                        return p;473                    }474                    // extending the values475                    if (typeof p === "object") {476                        $.extend(json, p);477                        storage[masterKey] = JSON.stringify(json);478                        return json;479                    }480                }481                return false;482            };483        }484        tools.objectStorage = objectStorage;485        // shortcut methods for objectStorage486        tools.objectLocalStorage = function (masterKey) {487            return objectStorage(masterKey, "localStorage");488        };489        tools.objectSessionStorage = function (masterKey) {490            return objectStorage(masterKey, "sessionStorage");491        };492        /*493            Testing whether localStorage works or not, and alerting a warning if not494        */495        function warnPrivateBrowsing() {496            try {497                localStorage.setItem("testItem", "test_value");498                localStorage.removeItem("testItem");499            } catch (e) {500                alert("このサイトはプライベート・ブラウズに対応していません!\n\nプライベート・ブラウズを解除してください!\n\n - by Wood!");501            }502        }503        tools.warnPrivateBrowsing = warnPrivateBrowsing;504        function getArrayIndex(obj) {505            if (!obj || typeof obj !== "object" || !obj.array || !obj.find) return false;506            if (obj.searchFrom && obj.searchFrom !== "start" && obj.searchFrom !== "end") {507                return log("searchFrom property must be 'start' or 'end'");508            }509            if (!obj.find || typeof obj.find !== "function") {510                return log("getArrayIndex requires a 'find' property that is a function!");511            }512            const array = obj.array;513            const searchFrom = obj.searchFrom || "start";514            const meetsSearchCondition = obj.find;515            const onNull = obj.onNull;516            // loops through an array, either forwards or backwards, and517            // returns the index of the searched-for value, else -1518            function searchArrayByDirection(startValue, testCondition, direction) {519                for (let i = startValue; testCondition(i); i += direction) {520                    if (meetsSearchCondition(array[i])) return i;521                }522                onNull && onNull();523                return -1;524            }525            if (searchFrom === "start") {526                return searchArrayByDirection(0, function (i) {527                    return i < array.length;528                }, 1);529            } else {530                return searchArrayByDirection(array.length - 1, function (i) {531                    return i >= 0;532                }, -1);533            }534        }535        tools.getArrayIndex = getArrayIndex;536        const pickColor = (function () {537            const baseColors = {538                light: shuffleArray([539                    "yellow",540                    "orange",541                    "springgreen",542                    "powderblue",543                    "lightcyan",544                    "greenyellow",545                    "aqua",546                ]),547                dark: shuffleArray([548                    "navy",549                    "blue",550                    "purple",551                    "darkred",552                    "darkslateblue",553                    "indigo",554                    "darkcyan",555                    "green",556                    "darkgreen",557                ]),558            };559            baseColors.allColors = [...baseColors.light, ...baseColors.dark];560            let index = 0;561            return function (colorType) {562                if (!(colorType in baseColors)) return log("Requires either 'light', 'dark', or 'allColors'!");563                const numColors = baseColors[colorType].length;564                return () => baseColors[colorType][++index % numColors];565            };566        }());567        tools.pickColor = pickColor("allColors");568        tools.pickDarkColor = pickColor("dark");569        tools.pickLightColor = pickColor("light");570        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *571         *572         *573         *      Takes an array and removes random elements574         *      until it's a specified length575         *576         *577         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */578        function whittleDownArray(array, desiredLength) {579            if (arguments.length === 0 || !Array.isArray(array)) return log("whittleDownArray got some bad parameteres!");580            if (!desiredLength) return array;581            while (array.length > desiredLength) pickOneFrom(array, true); // true means "delete this index"582            return array;583        }584        tools.whittleDownArray = whittleDownArray;585        /*586         *587         *      Removes elements from an object whose keys are not in a given array588         *589         *      Example: whittleDownObject(obj).toKeysIn(array);590         *591         *      NOTE this "returns" nothing, since objects are passed by reference592         *593         *594         */595        function whittleDownObject(object) {596            if (!object || typeof object !== "object" || Object.keys(object).length < 1) {597                return log("whittleDownObject requires an object as the first parameter!");598            }599            return {600                toKeysIn: function toKeysIn(array) {601                    if (!array || !Array.isArray(array) || !array.length) {602                        return log("whittleDownObject requires an array as the second parameter!");603                    }604                    // looping through the object, removing any elements where605                    // the key isn't in the array606                    for (let key in object) if (array.indexOf(key) === -1) delete object[key];607                }608            };609        }610        tools.whittleDownObject = whittleDownObject;611        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *612         *613         *614         *615         *      Links a checkbox with a localStorage key, toggling between "true" and "false"616         *617         *618         *619         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */620        function checkboxStateHandler(obj = {}) {621            obj = $.extend({622                checkbox: null, // REQUIRED623                localStorageKey: null, // REQUIRED624                checkedValue: "true",625                uncheckedValue: "false",626                defaultToChecked: false, // whether to check by default on first use627                onChange: function () {628                    //629                },630                onCheck: function () {631                    //632                },633                onUncheck: function () {634                    //635                },636            }, obj);637            if (!obj.checkbox || !obj.localStorageKey) {638                return log("checkBoxStateHandler requires 'checkbox' and 'localStorageKey' properties!");639            }640            const $checkbox = tools.forceJQuery(obj.checkbox);641            const key = obj.localStorageKey;642            const checkedValue = obj.checkedValue;643            const uncheckedValue = obj.uncheckedValue;644            // checking by default IF it has never been set before AND 'defaultToChecked' is true645            if (!localStorage.hasOwnProperty(key) && obj.defaultToChecked) {646                localStorage.setItem(key, checkedValue);647                setCheckedStateTo(true);648                obj.onChange && obj.onChange();649            }650            $checkbox.on("change", function () {651                localStorage[key] = isChecked() ? checkedValue : uncheckedValue;652                obj.onChange();653                $checkbox.is(":checked") ? obj.onCheck() : obj.onUncheck();654            });655            function setCheckedStateTo(thisValue = false) {656                $checkbox.prop("checked", thisValue);657                return this;658            }659            function isChecked() {660                return $checkbox.is(":checked");661            }662            function disable() {663                $checkbox.prop("disabled", true);664                return this;665            }666            function enable() {667                $checkbox.prop("disabled", false);668                return this;669            }670            $checkbox.prop("checked", localStorage[key] === checkedValue);671            return {672                isChecked,673                disable,674                enable,675            };676        }677        tools.checkboxStateHandler = checkboxStateHandler;678        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *679         *680         *681         *682         *      Links a radio input with a localStorage key, toggling between "true" and "false"683         *684         *685         *686         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */687        function radioStateHandler(obj = {}) {688            obj = $.extend({689                radioName: null, // REQUIRED690                localStorageKey: null, // REQUIRED691                onChange: function () {692                    //693                },694            }, obj);695            const radioName = obj.radioName;696            const $radios = $(`input[type='radio'][name='${radioName}']`);697            const localStorageKey = obj.localStorageKey;698            $radios.on("change", function () {699                localStorage[localStorageKey] = getValue();700                obj.onChange();701            });702            function getValue() {703                return $(`input[type='radio'][name='${radioName}']:checked`).val();704            }705            function setValue(value) {706                $(`input[type='radio'][name='${radioName}'][value='${value}']`).prop("checked", true);707                return this;708            }709            function disable() {710                $radios.prop("disabled", true);711            }712            function enable() {713                $radios.prop("disabled", false);714            }715            setValue(localStorage[localStorageKey]);716            return {717                getValue,718                setValue,719                disable,720                enable,721            };722        }723        tools.radioStateHandler = radioStateHandler;724        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *725         *726         *727         *728         *      Links a select input with a localStorage key, toggling between "true" and "false"729         *730         *731         *732         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */733        function selectStateHandler(obj = {}) {734            obj = $.extend({735                select: null, // REQUIRED, jQuery or not736                localStorageKey: null, // REQUIRED737                options: [],738                onChange: function () {739                    //740                },741            }, obj);742            const $select = forceJQuery(obj.select);743            const localStorageKey = obj.localStorageKey;744            setOptions(obj.options);745            $select.on("change", function () {746                localStorage[localStorageKey] = getValue();747                obj.onChange();748            });749            function setOptions(array) {750                forceArray(array).forEach(function (item) {751                    const value = (typeof item === "object" && item.value) ? item.value : item;752                    const label = (typeof item === "object" && item.label) ? item.label : item;753                    $select.append(`<option value="${value}">${label}</option>`);754                });755                return true;756            }757            function getValue() {758                return $select.val();759            }760            function setValue(value) {761                $select.val(value);762                return this;763            }764            function disable() {765                $select.prop("disabled", true);766            }767            function enable() {768                $select.prop("disabled", false);769            }770            setValue(localStorage[localStorageKey]);771            return {772                getValue,773                setValue,774                disable,775                enable,776                setOptions,777            };778        }779        tools.selectStateHandler = selectStateHandler;780        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *781         *782         *783         *      naturally sorts an array of items, or an array of objects by some key in the objects784         *785         *786         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */787        function naturallySort(array, key) {788            array.sort(function (a, b) {789                let k1 = a,790                    k2 = b;791                if (key) {792                    k1 = k1[key];793                    k2 = k2[key];794                }795                return k1.toString().localeCompare(k2.toString(), undefined, { // WHOOOA I don't understand this796                    numeric: true,797                    sensitivity: "base"798                });799            });800            return true;801        }802        tools.naturallySort = naturallySort;803        /*804         *805         *806         *      Converts an image to a dataURI, via a canvas element (which is not added to the DOM)807         *808         *809         */810        function imageToDataURL(image, obj = {}) {811            const ratio = (function () {812                if (obj.maxWidth && obj.maxHeight) {813                    return Math.min(obj.maxWidth / image.width, obj.maxHeight / image.height);814                } else if (obj.maxWidth) {815                    return obj.maxWidth / image.width;816                } else if (obj.maxHeight) {817                    return obj.maxHeight / image.height;818                }819                return 1;820            }());821            // creating a canvas element, but never adding it to the DOM822            const canvas = document.createElement("canvas");823            canvas.width = image.width * ratio;824            canvas.height = image.height * ratio;825            canvas.getContext("2d").drawImage(image, 0, 0, canvas.width, canvas.height);826            return canvas.toDataURL();827        }828        tools.imageToDataURL = imageToDataURL;829        /*830         *831         *832         *      Converts an image to a dataURI, via a canvas element833         *834         *835         */836        function dataURLToBlob(obj = {}) {837            if (!obj.url) return log("dataURLToBlob got some bad parameters");838            const callback = obj.onFinish;839            let parts,840                contentType,841                raw,842                blob,843                dataURL = obj.url;844            if (dataURL.indexOf(";base64,") === -1) {845                parts = dataURL.split(',');846                contentType = parts[0].split(':')[1];847                raw = parts[1];848                blob = new Blob([raw], { type: contentType });849                obj.onFinish && obj.onFinish(blob);850                return;851            }852            parts = dataURL.split(";base64,");853            contentType = parts[0].split(':')[1];854            raw = window.atob(parts[1]);855            const uInt8Array = new Uint8Array(raw.length);856            for (let i = 0; i < raw.length; ++i) uInt8Array[i] = raw.charCodeAt(i);857            blob = new Blob([uInt8Array], { type: contentType });858            obj.onFinish && obj.onFinish(blob);859        }860        tools.dataURLToBlob = dataURLToBlob;861        /*862         *863         *864         *      Converts a Konva layer (canvas) to a PNG image, so it can be printed865         *866         *867         *868         */869        function konvaLayerToImage(layer) {870            const imageData = layer.getCanvas().toDataURL();871            const canvas = layer.getCanvas()._canvas; // funky872            const $image = $(`<img src='${imageData}'>`).css({873                width: layer.width() + "px", // NOTE have to force width & height, for cases where874                height: layer.height() + "px", // the pixel ration may be weird875            });876            $(canvas).replaceWith($image);877            return true;878        }879        tools.konvaLayerToImage = konvaLayerToImage;880        function objectToArray(thing) {881            /* * * * * * * * * * * * * * * * * * * * * * * *882             *883             *884             *      changes an object to an array, like this:885             *886             *      {dog: 犬} --> ["dog", "犬"]887             *888             *889             * * * * * * * * * * * * * * * * * * * * * * * * */890            if (Array.isArray(thing)) return thing;891            let array = [];892            for (let word in thing) array.push([word, thing[word]]);893            return array;894        }895        tools.objectToArray = objectToArray;896        // adjusting quotes (slanted to straight) and removing any 2+ consecutive spaces897        function removeExtraWhiteSpace(string, obj = {}) {898            string = string.replace(/’|‘/g, "'"); // slanted single quotes (open and close) to straight899            string = string.replace(/“|”/g, '"'); // slanted double quotes (open and close) to straight900            string = string.replace(/\s{2,}/g, " ").trim();901            return string;902        }903        tools.removeExtraWhiteSpace = removeExtraWhiteSpace;904        function straightQuotesToSlanted(string) {905            // string = string.replace(/(\w)'(\w)/g, "$1’$2"); // apostrophe906            // string = string.replace(/ "/g, " ”"); // opening double quote907            // string = string.replace(/(\w)"/g, "$1”"); // closing double quote908            return string;909        }910        tools.straightQuotesToSlanted = straightQuotesToSlanted;911        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *912         *913         *914         *      1.  Splits a string into an array of words,915         *      2.  Trims white space from all elements (words), and916         *      3.  Optionally removes underscores917         *      4.  Optionally shuffles918         *919         *920         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */921        function trimAllElements(array, options = {}) {922            if (typeof array === "string") {923                array = removeExtraWhiteSpace(array);924                array = array.split(" ");925            }926            if (!Array.isArray(array)) return log("trimAll requires an array or a string!");927            // trimming each item (string) and replacing underscores with spaces, optionally928            array = array.map(item => {929                item = item.trim();930                item = removeExtraWhiteSpace(item);931                if (options.removeUnderscores) item = item.replace(/_/gi, " ");932                item = item.replace(/‘|’/g, "'"); // slanted single quotes to straight933                item = item.replace(/“|”/g, "\""); // slanted double quotes to straight934                return item;935            });936            if (options.shuffle) array = shuffleArray(array, options.alwaysMoveFirst);937            return array;938        }939        tools.trimAllElements = trimAllElements;940        // adds an item to an array IF it isn't there already941        function pushUnique(item, array) {942            if (arguments.length !== 2 || !Array.isArray(array)) return log("Bad arguments!");943            array.indexOf(item) === -1 && array.push(item);944            return true;945        }946        tools.pushUnique = pushUnique;947        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *948         *949         *950         *951         *      "turn (to the) left"        --> ["turn left, turn to the left"]952         *      "(an) apple"                --> ["apple", "an apple"]953         *      "[one's, your] left"        --> ["one's left", "your left"] NOTE separated by comma, not slash!954         *955         *956         *957         * * * * * * * * * * * * * * * * * * * * * * * * * * * * */958        function getCandidateAnswers(string, divider = "/") {959            string = removeExtraWhiteSpace(string);960            let candidatesArray = string.split(divider).map(answer => removeExtraWhiteSpace(answer));961            // adding scrubbed versions to the array962            candidatesArray.forEach(answer => {963                answer = scrubString(answer);964                pushUnique(answer, candidatesArray);965                // adding versions WITH optional bits, and without966                const withoutOptional = answer.replace(/\(.*?[^\)]\)/g, "");967                const withOptional = answer.replace(/\(|\)/g, "");968                const withoutDashes = answer.replace(/-/g, " "); // replacing dashes with SPACES969                pushUnique(withoutOptional, candidatesArray);970                pushUnique(withOptional, candidatesArray);971                pushUnique(withoutDashes, candidatesArray);972                // "lose [one's, your, my] way" --> ["lose one's way", "lose your way", "lose my way"]973                if (answer.indexOf("[") !== -1 && answer.indexOf("]") !== -1) {974                    const alternates = answer.split("[")[1].split("]")[0].split(",").map(word => word.trim());975                    alternates.forEach(alternate => {976                        const newString = answer.replace(/\[.[^\]]{0,}\]/, alternate); // any text between square brackets977                        pushUnique(newString, candidatesArray);978                    });979                }980            });981            candidatesArray = candidatesArray.map(item => removeExtraWhiteSpace(item));982            return candidatesArray;983        }984        tools.getCandidateAnswers = getCandidateAnswers;985        function getIdealAnswer(string) {986            return removeParenthetical(getCandidateAnswers(string)[0]).trim();987        }988        tools.getIdealAnswer = getIdealAnswer;989        // limiting to alphanumeric, spaces, (), [], and select punctuation990        function scrubString(text) {991            return text.replace(/[^\w\s\(\)\[\]\/',_-]/gi, "");992        }993        tools.scrubString = scrubString;994        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *995         *996         *997         *      Stripping any text between (parentheses) or [brackets] from a string,998         *      and returning the first letter999         *1000         *1001         * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1002        function getFirstRealLetter(string) {1003            string = string.replace(/\(.[^\)]*\)/g, ""); // removing anything in ( ) - same as "removeParenthetical" below1004            string = string.replace(/\[.[^\]]*\]/g, ""); // removing anything in [ ]1005            string = removeExtraWhiteSpace(string);1006            return string.charAt(0);1007        }1008        tools.getFirstRealLetter = getFirstRealLetter;1009        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *1010         *1011         *1012         *      Removes any text between parentheses, and any spaces after1013         *1014         *      "(the) United States (of America)" --> "United States"1015         *1016         *1017         * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1018        function removeParenthetical(string) {1019            string = string.replace(/\([^\(\)]*\)/gi, ""); // removing anything in parentheses1020            string = string.replace(/\[[^\[\]]*\]/gi, ""); // removing anything in square brackets1021            string = string.replace(/<[^<>]*>/gi, ""); // removing anything in angle brackets1022            return string;1023        }1024        tools.removeParenthetical = removeParenthetical;1025        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *1026         *1027         *1028         *      Takes an array and returns a shuffled version of it1029         *1030         *      ALWAYS returns a differently ordered version1031         *      UNLESS there are only two elements, in which case it1032         *      MAY return an identical version1033         *1034         *1035         * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1036        function shuffleArray(originalArray) {1037            if (!Array.isArray(originalArray)) return log("shuffleArray requires an array!");1038            let arrayCopy = originalArray.concat(); // cloning the array1039            let shuffledArray = [];1040            while (arrayCopy.length > 0) shuffledArray.push(pickOneFrom(arrayCopy, true)); // true => delete that element1041            // ensuring that arrays of length 3+ are changed1042            if (shuffledArray.length >= 3) {1043                while (arraysAreIdentical(shuffledArray, originalArray)) shuffledArray = shuffleArray(originalArray);1044            }1045            return shuffledArray;1046        }1047        tools.shuffle = shuffleArray;1048        // gets the x & y coordinates of mouse click or touch, relative to any offset parent1049        function pointerPosition(event, offsetParent) {1050            const offsetLeft = offsetParent ? offsetParent.offset().left : 0;1051            const offsetTop = offsetParent ? offsetParent.offset().top : 0;1052            let x, y;1053            // calculating position, for either touch or click1054            if (event.type === "touchstart" || event.type === "touchend") {1055                const touch = event.originalEvent.touches[0] || event.originalEvent.changedTouches[0];1056                x = touch.pageX - offsetLeft;1057                y = touch.pageY - offsetTop;1058            } else {1059                x = event.pageX - offsetLeft;1060                y = event.pageY - offsetTop;1061            }1062            return { x, y, };1063        }1064        tools.pointerPosition = pointerPosition;1065        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1066         *1067         *1068         *      Picks a random index (integer) from an array,1069         *1070         *      or else a random int, 0 <= int < some given number1071         *1072         *1073         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1074        function pickIntFrom(arrayOrNumber) {1075            if (!arrayOrNumber || !(Array.isArray(arrayOrNumber) || !isNaN(arrayOrNumber))) {1076                return log("pickIntFrom requires an array or a number as a parameter!");1077            }1078            if (Array.isArray(arrayOrNumber)) {1079                return Math.floor(Math.random() * arrayOrNumber.length);1080            }1081            return Math.floor(Math.random() * arrayOrNumber);1082        }1083        tools.pickIntFrom = pickIntFrom;1084        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1085         *1086         *1087         *1088         *      Returns a random ELEMENT from an array (not just the index integer),1089         *1090         *      and deletes that element, optionally1091         *1092         *1093         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1094        function pickOneFrom(array, deleteChosenItem) {1095            if (!array || !Array.isArray(array) || array.length < 1) {1096                return log("tools.pickOneFrom requires an array!");1097            }1098            const index = pickIntFrom(array);1099            const item = array[index];1100            if (deleteChosenItem) array.splice(index, 1);1101            return item;1102        }1103        tools.pickOneFrom = pickOneFrom;1104        function removeOneFrom(array) {1105            return pickOneFrom(array, true);1106        }1107        tools.removeOneFrom = removeOneFrom;1108        function elementOnScreen($element, callback, obj = null) {1109            if (!$element || !callback) return false;1110            $element = tools.forceJQuery($element);1111            // wiring up the scroll listener, and triggering once1112            $(window).off("scroll", scrollHandler).on("scroll", scrollHandler).trigger("scroll");1113            function scrollHandler() {1114                const elementTop = $element.offset().top;1115                const screenBottom = $(window).scrollTop() + $(window).height();1116                if (elementTop > screenBottom || $element.is(":hidden")) return;1117                $(window).off("scroll", scrollHandler);1118                callback();1119            }1120            function activate() {1121                $(window).off("scroll", scrollHandler).on("scroll", scrollHandler);1122            }1123            return {1124                activate1125            };1126        }1127        tools.elementOnScreen = elementOnScreen;1128        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *1129         *1130         *1131         *      Simply returns whether an element is on screen, vertically1132         *      NOTE doesn't check left and right1133         *1134         *1135         * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1136        function elementIsOnScreen($element) {1137            const elementTop = $element.offset().top;1138            const elementBottom = $element.offset().bottom;1139            const screenTop = $(window).scrollTop();1140            const screenBottom = $(window).scrollTop() + $(window).height();1141            return !(elementTop > screenBottom || elementBottom < screenTop);1142        }1143        tools.elementIsOnScreen = elementIsOnScreen;1144        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1145         *1146         *1147         *      Checks whether arrays contain the same elements, though not necessarily in the1148         *1149         *      same order.  NOTE that this is different than "arraysAreIdentical" below.1150         *1151         *      Does NOT work on nested arrays!1152         *1153         *1154         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1155        function arraysContainSameElements(a1, a2) {1156            if (!Array.isArray(a1) || !Array.isArray(a2) || a1.length !== a2.length) return false;1157            const intersection = a1.filter(element => a2.indexOf(element) !== -1);1158            return intersection.length === a1.length;1159        }1160        tools.arraysContainSameElements = arraysContainSameElements;1161        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1162         *1163         *1164         *      Checks whether arrays are identical - same elements in the same order1165         *1166         *      Also checks for nested arrays (useful?) but DOES NOT WORK with nested objects!1167         *1168         *1169         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1170        function arraysAreIdentical(a1, a2) {1171            if (!Array.isArray(a1) || !Array.isArray(a2) || a1.length !== a2.length) return false;1172            for (let i = 0; i < a1.length; i++) {1173                if (Array.isArray(a1[i])) {1174                    if (!arraysAreIdentical(a1[i], a2[i])) return false;1175                } else if (a1[i] !== a2[i]) {1176                    return false;1177                }1178            }1179            return true;1180        }1181        tools.arraysAreIdentical = arraysAreIdentical;1182        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *1183         *1184         *1185         *      Tries to parse a string into JSON, and1186         *      returns an empty object if it fails1187         *1188         *1189         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1190        function safeParseJSON(string) {1191            try {1192                return JSON.parse(string) || {};1193            } catch (err) {1194                return {};1195            }1196        }1197        tools.safeParseJSON = safeParseJSON;1198        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1199         *1200         *1201         *1202         *      Takes a string with words surrounded by * (astrixes) and replaces those * with1203         *      other strings, such as span tags1204         *1205         *      NOTE that the opening and closing replacement string may be different1206         *1207         *      Usage:1208         *      replaceStars("This is *bold*", "<b>", "</b>");  -->   "This is <b>bold</b>"1209         *1210         *1211         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1212        function replaceStars(string, before, after = null) {1213            if (arguments.length < 2 || arguments.length > 3) return;1214            after = after || before; // if after is null, setting it to same as the "before" element1215            // returning the string unchanged if there are no stars1216            if (string.indexOf("*") === -1) return string;1217            // exiting if stars are not of an even number1218            if (string.match(/\*/g).length % 2 !== 0) {1219                return log("Odd number of stars!");1220            }1221            return string.replace(/\*(.[^\*]{0,})\*/g, before + "$1" + after);1222        }1223        tools.replaceStars = replaceStars;1224        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1225         *1226         *1227         *1228         *      In a text input (or textarea), toggles square brackets around selected text1229         *      (inserts them if not present, removes them if they are)1230         *1231         *      Usage: "Shift + Ctrl + [" (opening square backet)1232         *1233         *1234         *1235         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1236        function toggleBrackets($input, e, p = {}) {1237            const keyCode = p.which || 219; // opening square bracket1238            const openingCharacter = p.openingCharacter || "[";1239            const closingCharacter = p.closingCharacter || "]";1240            const oldVal = $input.val();1241            if (e.which !== keyCode || !e.ctrlKey || !e.shiftKey) return;1242            // auto-selecting the current word, if nothing is selected1243            selectWholeWord($input);1244            const start = $input.prop("selectionStart"); // COOL! getting the start and end of an input's selected area1245            const end = $input.prop("selectionEnd");1246            const alreadySurrounded = oldVal.substring(start - 1, start) === openingCharacter && oldVal.substring(end, end + 1 === closingCharacter);1247            let newVal;1248            if (!alreadySurrounded) {1249                newVal = oldVal.substring(0, start) + openingCharacter + oldVal.substring(start, end) + closingCharacter + oldVal.substring(end, oldVal.length);1250            } else {1251                newVal = oldVal.substring(0, start - 1) + oldVal.substring(start, end) + oldVal.substring(end + 1, oldVal.length);1252            }1253            $input.val(newVal);1254            // re-selecting the selected test, just for good measure1255            const adjustment = alreadySurrounded ? -1 : 1; // moving the selected area by 1, depending1256            $input.prop({ selectionStart: start + adjustment, selectionEnd: end + adjustment }).change();1257        }1258        tools.toggleBrackets = toggleBrackets;1259        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1260         *1261         *1262         *1263         *      In a text input, selects the whole word (if nothing is otherwise selected)1264         *1265         *      or whole words, if words are partially selected1266         *1267         *1268         *1269         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1270        function selectWholeWord($input) {1271            const string = $input.val();1272            let start = $input.prop("selectionStart");1273            let end = $input.prop("selectionEnd");1274            while (string.charAt(start - 1).match(/\w\b/) && start >= 0) start--;1275            while (string.charAt(end).match(/\w\b/) && end < string.length) end++;1276            $input.prop({ selectionStart: start, selectionEnd: end });1277        }1278        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1279         *1280         *1281         *1282         *      In a text input (or textarea), replaces the next space (based on the insertion point)1283         *      with an underscore.1284         *1285         *      Usage: Shift + Ctrl + "u"    (NOTE: can't use "_" 'cause that doubles as "-" minus on Windows - fuck!)1286         *1287         *1288         *1289         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1290        function toggleUnderscores($input, e, p = {}) {1291            const keyCode = p.which || 85; // 85 = "u" for "underscore"1292            if (e.which !== keyCode || !e.ctrlKey || !e.shiftKey) return;1293            e.preventDefault();1294            const string = $input.val();1295            const selectionStart = $input.prop("selectionStart");1296            const selectionEnd = $input.prop("selectionEnd");1297            const p1 = string.substring(0, selectionStart);1298            const p2 = string.substring(selectionEnd, string.length).replace(/\s/, "_"); // only the first space, 'cause no global "g" flag1299            $input.val(p1 + p2).prop({ selectionStart: selectionStart, selectionEnd: selectionStart }).change();1300        }1301        tools.toggleUnderscores = toggleUnderscores;1302        // keeps track of user info (name, grade, etc.) in sessionStorage1303        tools.userInfo = tools.objectLocalStorage("user_info");1304        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1305         *1306         *1307         *      Abstracting away the tediousness of making something fullscreen1308         *1309         *      NOTE some browsers don't use promises, so we can't use: elem.requestFullscreen().then()1310         *1311         *1312         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1313        function requestFullscreen($elem, obj = {}) {1314            const elem = ($elem instanceof $) ? $elem[0] : $elem; // extracting the raw HTML if it's jQuery1315            elem.requestFullscreen = elem.webkitRequestFullscreen || elem.msRequestFullscreen || elem.requestFullscreen;1316            try {1317                elem.requestFullscreen();1318                obj.onFullscreen && obj.onFullscreen();1319                return true;1320            } catch (err) {1321                obj.onError && obj.onError(err);1322                return false;1323            }1324        }1325        tools.requestFullscreen = requestFullscreen;1326        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *1327         *1328         *1329         *      Handles the ".my-template" stuff, detaching and returning1330         *      an element that can be cloned many times1331         *1332         *1333         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1334        function makeTemplate($element, obj = {}) {1335            $element = forceJQuery($element);1336            const classToRemove = obj.klass || "my-template";1337            $element.removeClass(classToRemove);1338            $element.detach();1339            return $element;1340        }1341        tools.makeTemplate = makeTemplate;1342        /*1343         *      UNDER CONSTRUCTION!!1344         *1345         */1346        // function sentenceWithDummyWords(string) {1347        //1348        //     if (!string || typeof string !== "string") {1349        //         console.log("sentenceWithDummyWords needs a string");1350        //         return false;1351        //     }1352        //1353        //     if (string.includes("¥") && string.includes("[")) {1354        //         console.log("Either a ¥ *OR* square brackets, butthead!");1355        //         return false;1356        //     }1357        //1358        //     let divider = string.includes("¥") ? "¥" : "[";1359        //1360        //     let twoArrays = string.split(divider);1361        //1362        //1363        //     return {1364        //         //1365        //     };1366        // }1367        // tools.sentenceWithDummyWords = sentenceWithDummyWords;1368        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1369         *1370         *1371         *      the dateTime of the pageLoad, so we only get chats1372         *        that showed up AFTER the page was loaded1373         *1374         *1375         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1376        const getPageLoadDateTime = (function () {1377            const pageLoadTime = (new Date()).getTime();1378            return function () {1379                return (new Date(pageLoadTime));1380            };1381        }());1382        tools.pageLoadDateTime = getPageLoadDateTime;1383        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1384         *1385         *1386         *      Shortcut for creating a range1387         *      NOTE that the loop returns THROUGH the end value1388         *1389         *1390         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1391        function range(startValue, throughValue) {1392            if (arguments.length !== 2) {1393                return console.log("tools.range takes two arguments, a startValue and a throughValue!");1394            }1395            let array = [];1396            for (let i = startValue; i <= throughValue; i++) array.push(i);1397            return array;1398        }1399        tools.range = range;1400        /*1401         *1402         *      Gets the index of the first element in an array that meets1403         *      some condition, as defined by a testIsTrueFor function1404         *1405         *1406         */1407        function getIndexOfElementInArray(array, testIsTrueFor) {1408            for (let i = 0; i < array.length; i++) {1409                if (testIsTrueFor(array[i])) return i;1410            }1411            return -1;1412        }1413        tools.getIndexOfElementInArray = getIndexOfElementInArray;1414        /*1415         *1416         *      Removes the first element in an array that meets1417         *      some condition, as defined by a testFunction1418         *1419         *1420         */1421        function removeElement(array, testFunction) {1422            const index = getIndexOfElementInArray(array, testFunction);1423            array.splice(index, 1);1424        }1425        tools.removeElement = removeElement;1426        /*1427         *1428         *      Calculates the number of rows and columns for a grid of objects, e.g.1429         *1430         *      4 objects => 2x21431         *      5 objects => 3x21432         *      6 objects => 3x21433         *      7 objects => 3x31434         *      8 objects => 3x31435         *      ...1436         *      15 objects => 5x51437         *1438         *1439         */1440        // function calculateGrid(numItems) {1441        //1442        //     const squareRouteRoundedUp = Math.ceil(Math.sqrt(numItems));1443        //     const numRows = squareRouteRoundedUp;1444        //1445        //     let numColumns = squareRouteRoundedUp;1446        //1447        //     if (numRows * (numColumns - 1) >= numItems) {1448        //         numColumns--;1449        //     }1450        //1451        //     return { numRows, numColumns };1452        // }1453        // tools.calculateGrid = calculateGrid;1454        /*1455         *1456         *      converts MySQL timestamp to a readable format, e.g.1457         *1458         *      2018-04-06 13.15.06 -> Mar 06, 20181459         *1460         */1461        const readableDate = (function () {1462            const months = ["Jan", "Feb", "March", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];1463            return function (timestamp) {1464                const yearMonthDate = timestamp.split(" ")[0].split("-");1465                const year = yearMonthDate[0];1466                const month = months[parseInt(yearMonthDate[1]) - 1];1467                const date = yearMonthDate[2];1468                return month + " " + date + ", " + year;1469            };1470        }());1471        tools.readableDate = readableDate;1472        function promptStringWithTrim(obj = {}) {1473            obj = $.extend({1474                label: "",1475                placeholder: "default",1476                minLength: 21477            }, obj);1478            let inputString = prompt(obj.label, obj.placeholder);1479            if (!inputString || inputString <= obj.minLength) return;1480            inputString = inputString.trim();1481            if (!inputString || inputString <= obj.minLength) return;1482            return inputString;1483        }1484        tools.promptStringWithTrim = promptStringWithTrim;1485        function getSelectOptionWidth($select) {1486            const fontSize = $select.css("font-size");1487            const fontFamily = $select.css("font-family");1488            const fontWeight = $select.css("font-weight");1489            const text = $select.find("option:selected").text();1490            const $span = $("<span></span>").text(text).css({1491                visibility: "hidden",1492                position: "fixed",1493                top: "100%",1494                fontSize: fontSize,1495                fontFamily: fontFamily,1496                fontWeight: fontWeight1497            }).appendTo("html");1498            const width = $span.outerWidth(true);1499            $span.remove();1500            return width;1501        }1502        tools.getSelectOptionWidth = getSelectOptionWidth;1503        /*1504         *1505         *      Returns true if an element has class "this-input-is-momentarily-disabled";1506         *      otherwise, adds that class and then removes it after some number of miliseconds1507         *      (100 by default)1508         *1509         *      Used to temporarily disable an input - e.g., when "blur" and "sumbit"1510         *      events call each other on an input, leading to stack overflow1511         *1512         *1513         */1514        const momentarilyDisable = (function () {1515            const className = "this-input-is-momentarily-disabled";1516            return function ($input, callback, obj = {}) {1517                obj = $.extend({1518                    delay: 100 //ms1519                }, obj);1520                if (!$input.hasClass(className)) {1521                    $input.addClass(className);1522                    setTimeout(function () {1523                        $input.removeClass(className);1524                    }, obj.delay);1525                    callback();1526                }1527            };1528        }());1529        tools.momentarilyDisable = momentarilyDisable;1530        const brackets = (function () {1531            function areBalanced(str) {1532                if (!str) return;1533                let nextExpectedType = "["; // first must be opening bracket1534                return str.split("").every(function (char) {1535                    if (char === "[" || char === "]") {1536                        if (char !== nextExpectedType) return false;1537                        nextExpectedType = (nextExpectedType === "[") ? "]" : "[";1538                    }1539                    return true;1540                });1541            }1542            function sameNumber(str) {1543                if (!str) return;1544                const num = numberOfBrackets(str);1545                if (num[0] === num[1]) return true;1546                return false;1547            }1548            function numberOfBrackets(string) {1549                const numOpeningBrackers = (string.match(/\[/gi) || []).length;1550                const numClosingBrackets = (string.match(/\]/gi) || []).length;1551                return [numOpeningBrackers, numClosingBrackets];1552            }1553            function noBrackets(string) {1554                const num = numberOfBrackets(string);1555                return (num[0] === 0) && (num[1] === 0);1556            }1557            function areBrackets(str) {1558                return !noBrackets(str);1559            }1560            function areBalancedAndSameNumber(str) {1561                return areBalanced(str) && sameNumber(str); // && areBrackets(str);1562            }1563            function notBalanced(s) {1564                return !areBalanced(s);1565            }1566            function notSameNumber(s) {1567                return !sameNumber(s);1568            }1569            function notBalancedAndSame(s) {1570                return !areBalancedAndSameNumber(s);1571            }1572            return {1573                areBalanced,1574                sameNumber,1575                areBalancedAndSameNumber,1576                notBalanced,1577                notSameNumber,1578                notBalancedAndSame,1579                numberOfBrackets,1580                noBrackets,1581            };1582        }());1583        tools.brackets = brackets;1584        /*1585         *      Takes one argument and returns that "array version" of that item1586         *1587         *      This is so we can use Array.forEach, even when1588         *1589         */1590        function forceArray(item = []) {1591            return Array.isArray(item) ? item : [item];1592        }1593        tools.forceArray = forceArray;1594        const currentlyPressedKeys = (function () {1595            /*1596             *1597             *       Keeps track of which keys are currently pressed1598             *1599             *1600             */1601            let keysDown = {};1602            // adding or removing keyCodes from the keysDown object1603            // whenever a key is pressed or released1604            $(window).on("keyup keydown", function (e) {1605                e.type === "keydown" ? keysDown[e.which] = true : delete keysDown[e.which];1606            });1607            function getAll() {1608                return keysDown;1609            }1610            function getArray() {1611                return Object.keys(keysDown);1612            }1613            function isPressed(keyCode) {1614                return forceArray(keyCode).some(function (thisKeycode) {1615                    return keysDown.hasOwnProperty(thisKeycode);1616                });1617            }1618            function allArePressed(keyCodes) {1619                return forceArray(keyCodes).every(function (thisKeycode) {1620                    return keysDown.hasOwnProperty(thisKeycode);1621                });1622            }1623            function numPressed() {1624                return getArray().length;1625            }1626            return {1627                getAll,1628                getArray,1629                isPressed,1630                numPressed,1631                allArePressed,1632            };1633        }());1634        tools.currentlyPressedKeys = currentlyPressedKeys;1635        tools.numKeysPressed = currentlyPressedKeys.numPressed;1636        tools.keyIsPressed = currentlyPressedKeys.isPressed;1637        tools.keysAreAllPressed = currentlyPressedKeys.allArePressed;1638        // returns True if ANY arrow keys are pressed1639        function anyArrowKeysPressed() {1640            return currentlyPressedKeys.isPressed([37, 38, 39, 40]);1641        }1642        tools.anyArrowKeysPressed = anyArrowKeysPressed;1643        // returns True if NO arrow keys are pressed1644        function noArrowKeysPressed() {1645            return !anyArrowKeysPressed();1646        }1647        tools.noArrowKeysPressed = noArrowKeysPressed;1648        // returns an array of all the currently pressed arrow keys1649        function currentlyPressedArrowKeys() {1650            let array = [];1651            [37, 38, 39, 40].forEach(function (thisKey) {1652                currentlyPressedKeys.isPressed(thisKey) && array.push();1653            });1654            return array;1655        }1656        tools.currentlyPressedArrowKeys = currentlyPressedArrowKeys;1657        // matches keydown (and keyup) events with callback functions1658        const keyevent = (function () {1659            let anyKeyUpFunctions = [];1660            let bindings = {1661                keydown: {}, // e.g. {"37": someFunc}1662                keyup: {}1663            };1664            let anyKeyDownFunctions = [];1665            function anyKeyDown(func) {1666                anyKeyDownFunctions.push(func);1667            }1668            function anyKeyUp(func) {1669                anyKeyUpFunctions.push(func);1670            }1671            $(window).on("keydown keyup", function (e) {1672                // first, calling functions that are linked to ANY keydown or keyup1673                const funcs = (e.type === "keydown") ? anyKeyDownFunctions : anyKeyUpFunctions;1674                funcs.forEach(thisFunc => thisFunc(e));1675                e.which = e.which || e.keyCode;1676                if (!e.which) return;1677                const keyCode = e.which.toString(); // 'cause the numbers are object keys, which are string1678                const eventType = e.type; // keydown or keyup1679                // calling the associated function, if any1680                if (bindings[eventType][keyCode]) {1681                    e.preventDefault();1682                    bindings[eventType][keyCode].callback(e);1683                    // deleting the binding after it's used, if the "callOnce" property is true1684                    if (bindings[eventType][keyCode] && bindings[eventType][keyCode].callOnce) {1685                        delete bindings[eventType][keyCode];1686                    }1687                }1688            });1689            function bindKeyEvent(p) {1690                if (!p || typeof p !== "object" ||1691                    !p.keys ||1692                    !p.onOrOff ||1693                    !(p.onOrOff === "on" || p.onOrOff === "off") ||1694                    (isNaN(p.keys) && !Array.isArray(p.keys)) ||1695                    (p.callback && typeof p.callback !== "function") ||1696                    !p.event ||1697                    !(p.event === "keydown" || p.event === "keyup")) {1698                    log("bindKeyEvent got some bad arguments!");1699                    return false;1700                }1701                const e = p.event;1702                const keys = p.keys;1703                forceArray(keys).forEach(function (thisKey) {1704                    thisKey = thisKey.toString(); // 'cause it's a key in an object1705                    if (p.onOrOff === "on") {1706                        bindings[e][thisKey] = {1707                            callback: p.callback,1708                            callOnce: !!p.callOnce1709                        };1710                    } else {1711                        delete bindings[e][thisKey];1712                    }1713                });1714                return keyevent;1715            }1716            function keydown(keys, callback, callOnce) {1717                return bindKeyEvent({1718                    keys: keys,1719                    callback: callback,1720                    callOnce: callOnce,1721                    onOrOff: "on",1722                    event: "keydown"1723                });1724            }1725            function keyup(keys, callback, callOnce) {1726                return bindKeyEvent({1727                    keys: keys,1728                    callback: callback,1729                    callOnce: callOnce,1730                    onOrOff: "on",1731                    event: "keyup"1732                });1733            }1734            function keydownOnce(keys, callback) {1735                return bindKeyEvent({1736                    keys: keys,1737                    callback: callback,1738                    onOrOff: "on",1739                    callOnce: true,1740                    event: "keydown"1741                });1742            }1743            function keyupOnce(keys, callback) {1744                return bindKeyEvent({1745                    keys: keys,1746                    callback: callback,1747                    onOrOff: "on",1748                    callOnce: true,1749                    event: "keyup"1750                });1751            }1752            function keydownOff(keys) {1753                return bindKeyEvent({1754                    keys: keys,1755                    onOrOff: "off",1756                    event: "keydown"1757                });1758            }1759            function keyupOff(keys) {1760                return bindKeyEvent({1761                    keys: keys,1762                    onOrOff: "off",1763                    event: "keyup"1764                });1765            }1766            function hasKeydownEvent(key) {1767                return !!bindings.keydown[key];1768            }1769            function hasKeyupEvent(key) {1770                return !!bindings.keyup[key];1771            }1772            function hasSomeEvent(key) {1773                return !!(hasKeydownEvent(key) || hasKeyupEvent(key));1774            }1775            function clearAll(event) {1776                if (event) {1777                    bindings[event] = {};1778                } else {1779                    bindings.keydown = {};1780                    bindings.keyup = {};1781                }1782            }1783            // returning "on" or "off" functionality1784            return {1785                keydown,1786                keyup,1787                keydownOnce,1788                keydownOff,1789                keyupOff,1790                hasKeydownEvent,1791                hasKeyupEvent,1792                clearAll,1793                hasSomeEvent,1794                anyKeyDown,1795                anyKeyUp,1796            };1797        }());1798        tools.keydown = keyevent.keydown;1799        tools.keydownOnce = keyevent.keydownOnce;1800        tools.keydownOff = keyevent.keydownOff;1801        tools.keyup = keyevent.keyup;1802        tools.keyupOnce = keyevent.keyupOnce;1803        tools.keyupOff = keyevent.keyupOff;1804        tools.hasKeydownEvent = keyevent.hasKeydownEvent;1805        tools.hasKeyupEvent = keyevent.hasKeyupEvent;1806        tools.clearKeyEvents = keyevent.clearAll;1807        tools.hasSomeEvent = keyevent.hasSomeEvent;1808        tools.anyKeyDown = keyevent.anyKeyDown;1809        tools.anyKeyUp = keyevent.anyKeyUp;1810        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1811         *1812         *1813         *1814         *      Listens for any user interaction with the device, and calls a callback1815         *1816         *1817         *1818         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1819        const onUserInteraction = (function () {1820            // NOTE removed "keydown" from the events list, 'cause it's easily spoofed by simply1821            // holding down any key (thanks, Kyota!) and anyway "keyup" is sufficient.1822            // Also erased "mousedown" 'cause it can probably be spoofed too1823            let eventsToListenFor = "scroll mouseup mousemove DOMMouseScroll mousewheel touchmove touchend";1824            // adding keyup listeners ONLY for desktop; this is because other1825            // plugins (e.g. "tiltSimulatesArrowKeys") may simulate keypresses1826            // on mobile, even though there's no actual keyboard1827            if (!tools.isMobile()) { eventsToListenFor += " keyup"; }1828            return function (callback) {1829                if (!callback || typeof callback !== "function") {1830                    log("onUserIntraction requires a callback function!");1831                    return false;1832                }1833                // activating by default1834                activate();1835                function activate() {1836                    $(window).on(eventsToListenFor, callback);1837                }1838                function deactivate() {1839                    $(window).off(eventsToListenFor, callback);1840                }1841                return {1842                    deactivate,1843                    activate,1844                };1845            };1846        }());1847        tools.onUserInteraction = onUserInteraction;1848        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1849         *1850         *1851         *      Returns the first several items from an array, e.g.,1852         *      items [0 ~ 4] of an array of ten items1853         *1854         *1855         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1856        function getFirstFromArray(number, array) {1857            if (!array || !number ||1858                !Array.isArray(array) ||1859                isNaN(number) ||1860                number < 1 ||1861                number > array.length) {1862                log("Got some bad parameters!");1863                return false;1864            }1865            return array.slice(0, number);1866        }1867        tools.getFirstFromArray = getFirstFromArray;1868        /*1869         *1870         *1871         *      returns TRUE if any element is repeated in the array, otherwise FALSE1872         *1873         *1874         */1875        function arrayContainsDuplicates(array) {1876            var previousItems = [];1877            return array.some(function (thisElement) {1878                if (previousItems.indexOf(thisElement) !== -1) return true;1879                previousItems.push(thisElement);1880            });1881        }1882        tools.arrayContainsDuplicates = arrayContainsDuplicates;1883        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1884         *1885         *1886         *      returns TRUE if an array contains no duplicates1887         *1888         *1889         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1890        function arrayAllUnique(array) {1891            return !arrayContainsDuplicates(array);1892        }1893        tools.arrayAllUnique = arrayAllUnique;1894        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1895         *1896         *1897         *      Checks whether two objects (or arrays, which are objects) are identical1898         *1899         *      Returns "identical", "different", or FALSE if they're not comparable1900         *1901         *      NOTE this works for objects (or arrays) with values of primitive1902         *      types, but not for functions with constructors, etc.1903         *1904         *1905         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1906        function objectsAreIdentical(a1, a2) {1907            if (arguments.length !== 2) return;1908            // checking that they're both objects, or both arrays, and that1909            // their lengths are the same,1910            if (typeof a1 !== "object" ||1911                typeof a2 !== "object" ||1912                typeof a1 === "function" ||1913                typeof a2 === "function" ||1914                Array.isArray(a1) !== Array.isArray(a2) ||1915                Object.keys(a1).length !== Object.keys(a2).length) {1916                return false;1917            }1918            // returning false if ANY members are not identical1919            const areIdentical = Object.keys(a1).every(function (thisKey) {1920                if (!(thisKey in a2)) return;1921                // recursion!1922                if (typeof a1[thisKey] === "object" || typeof a2[thisKey] === "object") {1923                    return objectsAreIdentical(a1[thisKey], a2[thisKey]);1924                }1925                // simply comparing elements1926                return a1[thisKey] === a2[thisKey];1927            });1928            return areIdentical ? "identical" : "different";1929        }1930        tools.objectsAreIdentical = objectsAreIdentical;1931        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1932         *1933         *1934         *      Removes angle brackets and anything between them1935         *1936         *1937         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1938        function removeSSMLTags(string) {1939            return string.replace(/<.*?>/g, "");1940        }1941        tools.removeSSMLTags = removeSSMLTags;1942        function isJapanese(string) {1943            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1944             *1945             *1946             *      Returns TRUE if ANY characters in the string are Japanese1947             *1948             *      Codes mean:1949             *1950             *          3000 - 303f:    Japanese-style punctuation1951             *          3040 - 309f:    Hiragana1952             *          30a0 - 30ff:    Katakana1953             *          ff00 - ff9f:    Full-width Roman characters and half-width Katakana1954             *          4e00 - 9faf:    CJK unified ideographs - Common and uncommon Kanji1955             *          3400 - 4dbf:    CJK unified ideographs Extension A - Rare Kanji1956             *1957             *1958             * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */1959            return !!string.match(/[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/);1960        }1961        tools.isJapanese = isJapanese;1962        function isEnglish(string) {1963            return !isJapanese(string);1964        }1965        tools.isEnglish = isEnglish;1966        function countLanguageShifts(str) {1967            const letters = str.split("");1968            if (!letters) return log("Didn't get any text to process!");1969            return letters.filter((currentLetter, index) => {1970                const precedingLetter = letters[index - 1] ?? currentLetter;1971                return areDifferentLanguages(currentLetter, precedingLetter);1972            }).length;1973        }1974        tools.countLanguageShifts = countLanguageShifts;1975        const areDifferentLanguages = (t1, t2) => isJapanese(t1) !== isJapanese(t2);1976        tools.areDifferentLanguages = areDifferentLanguages;1977        function getIndexOfShift(t) {1978            const letters = t.split("");1979            for (let i = 0; i < letters.length; i++) {1980                const currentLetter = letters[i];1981                const precedingLetter = letters[i - 1] ?? currentLetter;1982                if (isJapanese(currentLetter) !== isJapanese(precedingLetter)) return i;1983            }1984        }1985        tools.getIndexOfShift = getIndexOfShift;1986        function splitAtLanguageShift(t) {1987            const index = getIndexOfShift(t);1988            const first = t.substr(0, index).trim();1989            const second = t.substr(index, t.length - index).trim();1990            return {1991                english: !isJapanese(first) ? first : second,1992                japanese: isJapanese(first) ? first : second,1993            };1994        }1995        tools.splitAtLanguageShift = splitAtLanguageShift;1996        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1997         *1998         *1999         *      Checks that a string has no forward slashes, while allowing "</", used in SSML tags2000         *2001         *2002         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2003        function isSpeakable(text) {2004            return !text.match(/[^<]\/]/g);2005        }2006        tools.isSpeakable = isSpeakable;2007        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2008         *2009         *2010         *      Takes a string with underscores, brackets, etc., and returns a scrubbed version,2011         *      with underscores removed, dummy words at end removed, and with the first word2012         *      in bracketed text extracted. Like this...2013         *2014         *2015         *      From:       "There_is (only) [one, two] thing_to_do! [dummy words]"2016         *      To:         "There is one thing to do!"2017         *2018         *2019         *2020         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2021        function scrubForVoiceSynthesis(string) {2022            if (!tools.isEnglish(string)) return;2023            string = string.replace(/_/g, " "); // removing underscores2024            string = string.replace(/\(.+?\)/g, ""); // removing anything in parentheses2025            string = string.replace(/\[.[^\[]*\]$/, ""); // removing any bracketed content at end of string2026            string = string.replace(/\[(.+?)(,.*?)*\]/g, "$1"); // extracting first word from words in brackets, separated by commas2027            string = string.replace(/\s{2,}/g, " ").trim(); // removing multiple spaces2028            return string;2029        }2030        tools.scrubForVoiceSynthesis = scrubForVoiceSynthesis;2031        function chances(fraction) {2032            if (!fraction || isNaN(fraction) || fraction >= 1 || fraction <= 0) {2033                return log("chances requires a fraction (or decimal number) between 0 and 1!");2034            }2035            return Math.random() < fraction;2036        }2037        tools.chances = chances;2038        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2039         *2040         *2041         *      Uses the "chances" function above to return true 50% of the time2042         *2043         *2044         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2045        function coinToss() {2046            return chances(1 / 2);2047        }2048        tools.coinToss = coinToss;2049        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2050         *2051         *2052         *      Tests for deviceorientation, and executes a callback if it isn't supported.2053         *2054         *      Mostly this is for iOS Safari, which is being stupid.2055         *2056         *2057         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2058        // function ifNoTiltSupport(callback) {2059        //     if (tools.isMobile()) {2060        //         let timeout = setTimeout(callback, 1000);2061        //         window.addEventListener("deviceorientation", (e) => clearTimeout(timeout));2062        //     }2063        // }2064        // tools.ifNoTiltSupport = ifNoTiltSupport;2065        function jqueryuiModal(obj) {2066            if (!obj || typeof obj !== "object" || !obj.title || !obj.body) {2067                return console.log("jqueryuiModal requires an object with properties 'title' and 'body'!");2068            }2069            obj.buttons = forceArray(obj.buttons);2070            const modalID = "jquery-ui-modal";2071            $(`<div id='${modalID}' title='${obj.title}'></div>`).appendTo("body");2072            $(`<p>${obj.body}</p>`).appendTo($(`#${modalID}`));2073            $("#jquery-ui-modal").dialog({2074                buttons: obj.buttons ? obj.buttons : null2075            });2076        }2077        tools.jqueryuiModal = jqueryuiModal;2078        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2079         *2080         *2081         *2082         *      Wiring up any body touchend event to trigger permission for orentation change2083         *2084         *      NOTE that this only activates the permission dialog; it does not wire up any listeners,2085         *      though it does call a callback2086         *2087         *2088         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2089        function activateTiltDetection(obj = {}) {2090            const onDesktop = obj.onDesktop || function () { };2091            const onSuccess = obj.onSuccess || function () { };2092            const onFail = obj.onFail || function () { };2093            if (!tools.isMobile()) return onDesktop();2094            $("body").on("touchend", getTiltPermission);2095            function getTiltPermission() {2096                $("body").off("touchend", getTiltPermission);2097                DeviceMotionEvent.requestPermission().then(function (response) {2098                    if (response === "granted") onSuccess();2099                }).catch(function (e) {2100                    onFail();2101                    log("Failed!");2102                    log.error(e);2103                });2104            }2105        }2106        tools.activateTiltDetection = activateTiltDetection;2107        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2108         *2109         *2110         *      Returns an object with properties x and y, that are constantly updated2111         *2112         *2113         *2114         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2115        function DeviceTiltDetector(params) {2116            params = $.extend({2117                maxTilt: 10 // higher == less sensitive2118            }, params || {});2119            const maxTilt = params.maxTilt;2120            this.maxTilt = maxTilt;2121            // returning null properties if not mobile2122            if (!window.hasOwnProperty("orientation")) {2123                this.x = null;2124                this.y = null;2125                this.maxTilt = null;2126                return true;2127            }2128            // saving tilt info every time the device moves2129            registerNewTilt = event => {2130                const tilt = getTilt(event);2131                this.x = Math.max(Math.min(tilt.x, maxTilt), -maxTilt); // left-to-right2132                this.y = Math.max(Math.min(tilt.y, maxTilt), -maxTilt); // back-to-front2133            };2134            // saving tilt info every time the device moves2135            // NOTE adding this "requestPermission" bullshit2136            DeviceMotionEvent.requestPermission().then(function (response) {2137                response === "granted" && window.addEventListener("deviceorientation", registerNewTilt);2138            }).catch(function (e) {2139                console.error(e);2140            });2141            $(window).trigger("orientationchange");2142        }2143        tools.DeviceTiltDetector = DeviceTiltDetector;2144        // swapping x, y in portrait / landscape mode2145        function getTilt(event) {2146            const directions = {2147                "0": { x: event.gamma, y: event.beta },2148                "180": { x: -event.gamma, y: -event.beta }, // NEW 'cause some tables support this now!2149                "90": { x: event.beta, y: -event.gamma },2150                "-90": { x: -event.beta, y: event.gamma },2151            };2152            return directions[window.orientation];2153        }2154        tools.getTilt = getTilt;2155        function pauser(p) {2156            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *2157             *2158             *2159             *      Takes an array of keyCodes (e.g. [80] == p) and2160             *      toggles a variable ("isPaused") on keyDown2161             *2162             *      NEW:2163             *      Also takes a button or checkbox2164             *2165             *      NEW:2166             *      Added methods "disable", "enable", and "destroy"2167             *2168             *2169             *2170             * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2171            if (!p || typeof p !== "object") {2172                return log("tools.pauser got some bad parameters!");2173            }2174            const settings = $.extend({2175                keyCodes: [80], // the 'p' key **  NOTE this can be a single number, or an array of numbers2176                startValue: false, // false == not paused2177                element: null, // a jQuery element, such as button or checkbox2178                pausedClass: null, // class to add to the element when paused2179                resumedClass: null, // class to add to the element when not paused2180                onPause: function () {2181                    // do something on pause2182                },2183                onResume: function () {2184                    // do something on pause2185                }2186            }, p || {});2187            const $element = settings.element;2188            const kCodes = forceArray(settings.keyCodes);2189            let isPaused = settings.startValue; // false by default2190            let pauserDisabled = false; // USE THIS to comletely disable the pauser2191            keyevent.keydown(kCodes, togglePausedState);2192            // wiring up the element, if specified (e.g. button or checkbox)2193            // NOTE we're using the "click" event even on checkboxes, rather than the "change" method2194            if ($element && $element instanceof jQuery) $element.click(togglePausedState);2195            function togglePausedState() {2196                if (pauserDisabled) return;2197                isPaused = !isPaused;2198                isPaused ? settings.onPause() : settings.onResume();2199                $element && toggleElementState();2200            }2201            function toggleElementState() {2202                $element.toggleClass(settings.pausedClass, !!(isPaused));2203                $element.toggleClass(settings.resumedClass, !(isPaused));2204                $element.is(":checkbox") && $element.prop("checked", isPaused ? true : false); // only affects checkboxes2205            }2206            function getPausedState() {2207                return isPaused;2208            }2209            function disable() {2210                pauserDisabled = true;2211            }2212            function enable() {2213                pauserDisabled = false;2214            }2215            function destroy() {2216                $element && $element.off("click", togglePausedState);2217                keyevent.keydownOff(kCodes);2218            }2219            return {2220                isPaused: getPausedState,2221                togglePausedState: togglePausedState,2222                disable: disable,2223                enable: enable,2224                destroy: destroy2225            };2226        }2227        tools.pauser = pauser;2228        function secondsToOtherFormats(timeInSeconds) {2229            const seconds = timeInSeconds % 60;2230            const minutes = Math.floor(timeInSeconds / 60 % 60);2231            const hours = Math.floor(timeInSeconds / 3600);2232            const totalMinutes = Math.floor(timeInSeconds / 60);2233            return { seconds, minutes, hours, totalMinutes, timeInSeconds, };2234        }2235        tools.secondsToOtherFormats = secondsToOtherFormats;2236        // converts seconds (not miliseconds!) to h:m.s format2237        function secondsToHMS(time, obj = {}) {2238            const settings = $.extend({2239                hoursTag: "h ",2240                minutesTag: "m ",2241                secondsTag: "s",2242                useHours: true,2243                useMinutes: true,2244                useSeconds: true,2245                useLeadingZeroes: true,2246                prefix: "",2247                suffix: "",2248            }, obj);2249            time = secondsToOtherFormats(time);2250            function addLeadingZero(number) {2251                number = parseInt(number);2252                if (number >= 0 && number <= 9) return "0" + number;2253                return number.toString();2254            }2255            let hours = time.hours ?? "",2256                minutes = time.minutes ?? "",2257                seconds = time.seconds;2258            // only adding leading 0's IF there's something to the LEFT2259            if (settings.useLeadingZeroes) {2260                if (time.hours) minutes = addLeadingZero(minutes);2261                if (time.totalMinutes) seconds = addLeadingZero(seconds);2262            }2263            if (hours) hours += settings.hoursTag;2264            if (minutes) minutes += settings.minutesTag;2265            if (seconds) seconds += settings.secondsTag;2266            return hours + minutes + seconds;2267        }2268        tools.secondsToHMS = secondsToHMS;2269        const easer = (function () {2270            return function (power, duration, type) {2271                if (arguments.length !== 3 || isNaN(power) || isNaN(duration) || (type !== "easeIn" && type !== "easeOut")) {2272                    return false;2273                }2274                const easingTypes = {2275                    easeIn: function (t, d) {2276                        d = d || duration;2277                        return Math.pow((t / d), power);2278                    },2279                    easeOut: function (t, d) {2280                        d = d || duration;2281                        return 1 - Math.pow(1 - (t / d), power);2282                    }2283                };2284                return easingTypes[type];2285            };2286        }());2287        tools.easer = easer;2288        function windowHasFocus() {2289            return !document.hidden && document.hasFocus();2290        }2291        tools.windowHasFocus = windowHasFocus;2292        function lightenElementsIncrementally(obj) {2293            if (!obj || typeof obj !== "object" || !obj.elements || isNaN(obj.minOpacity)) {2294                return log("lightenIncrementally received no params, or they're not right!");2295            }2296            let currentOpacity = obj.minOpacity;2297            const lightnessIncrement = (1 - obj.minOpacity) / obj.elements.length;2298            obj.elements.each(function () {2299                $(this).css({ opacity: currentOpacity });2300                currentOpacity += lightnessIncrement;2301            });2302            return true;2303        }2304        tools.lightenElementsIncrementally = lightenElementsIncrementally;2305        function shrinkToFit($inner, $outer, options = {}) {2306            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2307             *2308             *2309             *      Shrinks the font-size of an INNER div until it fits entirely inside an2310             *      OUTER div.2311             *2312             *      Ideal for text within cards.2313             *2314             *2315             * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2316            if (arguments.length < 2) {2317                return console.warn("tools.shrinkToFit requires inner and outer jQuery elements!");2318            }