1. Declare the new object anywhere in the body section.
var tt=new tooltip("style1","style2");
2. .style and .style2 must exist in style section (if not, font is ugly). For example:
.tooltiptitle{COLOR: #FFFFFF; TEXT-DECORATION: none; CURSOR: Default; font-family: arial; font-weight: bold; font-size: 8pt} .tooltipcontent{COLOR: #000000; TEXT-DECORATION: none; CURSOR: Default; font-family: arial; font-size: 8pt}
3. Add the following in an element to call the tooltip: (1st method)
<a onmousemove="tt.move(event)" onmouseover="tt.on('title text','content text')" onmouseout="tt.off()">
4. Change the object's attributes (if desired):
tt.top_color(color); tt.sub_color(color); tt.width(number|string); // Two modes: fixed width or native width tt.format = function(ary) { return(htmltext) }; // Changing the tooltip text-format entirely e.g. var xx = new tooltip(); // arguments to tooltip are useless if .format is overridden xx.format=function(ary) { return('html format '+ary[0]+'etc, etc'+ary[1]+ary[2]); // number of ary elements depends upon the call to .on() or .textassign }
5. Two modes of tooltip size: Fixed width mode (.width(number)) and native width mode (.width(string))
If number, then the number is the pixel-width. Tooltip will be fixed width. If string, then tooltip will be native width (The width of the input text). string is used as a padding at start and end (e.g. "& nbsp; & nbsp;"). Default is native width.
6. Multiple tooltip object could be created if different color/width/text-format is desired.
7. The 2nd method of assigning tooltips is via javascript assignment:
<body><div id="i1">This is the text</div> <script> var xx = new tooltip("tooltiptitle","tooltipcontent"); xx.textassign('i1', "title text", "content text"); // mouse events are automatically added </script>
<head> <style> .tooltiptitle {COLOR: #FFFFFF; TEXT-DECORATION: none; CURSOR: Default; font-family: arial; font-weight: bold; font-size: 8pt} .tooltipcontent {COLOR: #000000; TEXT-DECORATION: none; CURSOR: Default; font-family: arial; font-size: 8pt} .tooltiptitle1 {COLOR: #FFFF00; TEXT-DECORATION: none; CURSOR: Default; font-family: arial; font-weight: bold; font-size: 8pt} .tooltipcontent1 {COLOR: #0000FF; TEXT-DECORATION: none; CURSOR: Default; font-family: arial; font-size: 8pt} </style> ... put tooltip script here... </head> <body> <div onmousemove="x.move(event)" onmouseover="x.on('hi There! Hello There!There! Hello There!There! Hello There!There! Hello There!')" onmouseout="x.off()">1. This is a long-single line tooltip (native width)</div> <div onmousemove="x.move(event)" onmouseover="x.on('This is the title', 'This is the body. This is the body text')" onmouseout="x.off()">2. This is a two line tooltip (native width)</div> <div onmousemove="y.move(event)" onmouseover="y.on('hi There! Hello There!There! Hello There!There! Hello There!There! Hello There!')" onmouseout="y.off()">3. This is a long-single line tooltip (fixed width)</div> <div onmousemove="y.move(event)" onmouseover="y.on('This is the title', 'This is the body. This is the body text')" onmouseout="y.off()">4. This is a two line tooltip (fixed width)</div> <div onmousemove="z.move(event)" onmouseover="z.on('This is a wow! ','abc')" onmouseout="z.off()">5. Self configured tooltip</div> <hr> <div id="i1">6. This is a long-single line tooltip (native width)</div> <div id="i2">7. This is a two line tooltip (native width)</div> <div id="i3">8. This is a long-single line tooltip (fixed width)</div> <div id="i4">9. This is a two line tooltip (fixed width)</div> <div id="i5">10. Self configured tooltip</div> <script> // Create the tooltip objects var x = new tooltip("tooltiptitle","tooltipcontent"); var y = new tooltip("tooltiptitle1","tooltipcontent1"); y.width(350); var z = new tooltip(); z.format = function(ary) { return('<font color="blue">'+ary[0]+ary[1]+(ary[2]?ary[2]:"")+(ary[3]?ary[3]:"")+'</font>') }; x.textassign('i1', "textassign: This is a very long one. Very Long. This is a very long one. Very Long. This is a very long one. Very Long. This is a very long one. Very Long. "); x.textassign('i2', "textassign: This is TITLE", "This is MESSAGE"); y.textassign('i3', "textassign: This is a very long one. Very Long. This is a very long one. Very Long. This is a very long one. Very Long. This is a very long one. Very Long. "); y.textassign('i4', "textassign: This is TITLE", "This is MESSAGE"); z.textassign('i5', "textassign: WOW! ","abc ","def ","ghi"); </script> </body>
// Developed by JohnDR function tooltip(title_font_classname, content_font_classname) { // argument is the FONT class names defined in style section // The following are default variables that could be changed via object methods var tt_top_color = "#0099CC"; // default values var tt_sub_color = "#99CCFF"; var tt_width; // width of tooltip var tt_internal_tble_width; // table width (92% for fixed pixel width, 100% for native width) var tt_internal_top_width; // top table width (exist for fixed pixel, non-existent for native width) var tt_pad; // padding, used for native width // Object variables var tt_title_classname = title_font_classname; var tt_content_classname = content_font_classname; var ttdiv = document.getElementById('tooltipdiv'); var h_title = new Array; var tt_this = this; // This is a neat trick for storing "this" during mouse events. see tt_this usage in .on_from_java() // object methods this.top_color = function(txt) { tt_top_color=txt }; this.sub_color = function(txt) { tt_sub_color=txt }; // There are two modes: Fixed width mode (nn is number) and native width mode (nn is string) this.width = function(nn) { // set width to number for fixed pixel width or string for the padding. if(typeof(nn)=='number') { tt_width=nn; tt_internal_tble_width=92; // 92% to allow table margin tt_internal_top_width='width='+tt_width; tt_pad=''; } else { // This is native width tt_width=0; tt_internal_tble_width=100; tt_internal_top_width=''; // empty if(typeof(nn)=='string') { tt_pad=nn; } else { tt_pad='&'+'nbsp;&'+'nbsp;&'+'nbsp;'; // default spacer (beginning and end). 4 times of "& nbsp;" without the space } } } this.move = function(ee) { // move the tooltip var myEvent = ee ? ee : window.event; // just in case ee doesnt exist (msie) var yy; ttdiv.style.top=myEvent.clientY + document.body.scrollTop + 5; if(tt_pad==='') { // fixed tooltip width yy= myEvent.clientX - (tt_width/2); // tooltip starts at middle of the mouse cursor. if(yy<0) yy=0; ttdiv.style.left=yy + document.body.scrollLeft + 5; } else { // native tooltip width ttdiv.style.left=myEvent.clientX + document.body.scrollLeft + 5; } } this.off = function() { ttdiv.style.visibility='hidden'; } // This method is only called from within html (1st method only). this.on = function() { ttdiv.innerHTML = this.format(arguments); // There could be as many arguments ttdiv.style.visibility='visible'; } this.on_from_java = function(the_event) { var ee = the_event ? the_event : window.event; // just in case the_event doesnt exist (msie) var elm_id = ee.target ? ee.target.id : ee.srcElement.id; // ff : msie var ary = new Array; var i; if(h_title[elm_id]==undefined) { ary[0] = "No tooltip text defined for id="+elm_id; } else { for (i in h_title[elm_id]) { ary.push(h_title[elm_id][i]); } } ttdiv.innerHTML = tt_this.format(ary); // Cannot use a simple "this." bec of mouseevent ttdiv.style.visibility='visible'; } // This could be overridden. Below only takes two arguments. this.format = function(ary) { return('<table border=0 '+ tt_internal_top_width +' cellspacing=0 cellpadding=0>' + ' <tr><td bgcolor=#000000>' + ' <table width="100%" border=0 cellspacing=1 cellpadding=0>' + ' <tr><td width="100%" bgcolor='+ tt_top_color +'>' + ' <table border=0 width="'+ tt_internal_tble_width +'%" cellspacing=0 cellpadding=0 align="center">' + ' <tr><td width="100%" class="'+ tt_title_classname +'"><b>'+ tt_pad+ ary[0] + tt_pad+'</b></td></tr>' + ' </table></td></tr>' + ( ary[1] ? ' <tr><td width="100%" bgcolor='+ tt_sub_color +'>' + ' <table border=0 width="'+ tt_internal_tble_width +'%" cellpadding=0 cellspacing=1 align="center">' + ' <tr><td width="100%" class="'+ tt_content_classname +'">'+ tt_pad+ ary[1] + tt_pad+'</td></tr>' : '') + ' </table></td></tr>' + ' </table></td></tr>' + ' </table>'); } // This is the 2nd method of using this object. (Adding the event dynamically) this.textassign = function() { // vid, TTitle, [TContent] var vid=arguments[0]; var i; if(arguments[1]==undefined) { alert('textassign needs at least two arguments'); return; } h_title[vid]=new Array; for(i=1;i<100;i++) { if(arguments[i]==undefined) break; h_title[vid].push(arguments[i]); } // Add the events var elm = document.getElementById(vid); if(!elm) { alert('element id='+vid+' is not found'); return; } elm.onmousemove= this.move; elm.onmouseout = this.off; elm.onmouseover= this.on_from_java; } // create the new div if(!ttdiv) { // try to create the new div element var newdiv = document.createElement("div"); newdiv.id="tooltipdiv"; document.body.appendChild(newdiv); ttdiv = document.getElementById('tooltipdiv'); if(!ttdiv) alert("Cannot create empty div"); } // Initialize the object. ttdiv.style.position = 'absolute'; ttdiv.style.visibility = 'hidden'; this.width(); // Set the default to Native width } // end tooltip object
// Just add: <TABLE class="sortable" id="unique_id"> in your table. addEvent(window, "load", ts_resortTable); // Original sortable code is from http://www.kryogenix.org/code/browser/sorttable/ // This version is modified to make it more encapsulated function ts_resortTable(lnk) { var nbsp = '&'+'nbsp;'; // so that wiki copy+paste will work // check initialization if(typeof(ts_resortTable_init)=='undefined') { sortables_init(); ts_resortTable_init=1; // global variable, sortables_init is executed only once. return; } // get the span var span; for (var ci=0;ci<lnk.childNodes.length;ci++) { if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') span = lnk.childNodes[ci]; } var spantext = ts_getInnerText(span); var td = lnk.parentNode; var column = td.cellIndex; var table = getParent(td,'TABLE'); var SORT_COLUMN_INDEX; // Work out a type for the column if (table.rows.length <= 1) return; var itm = ts_getInnerText(table.rows[1].cells[column]); sortfn = ts_sort_caseinsensitive; if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^[£$]/)) sortfn = ts_sort_currency; if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric; SORT_COLUMN_INDEX = column; var firstRow = new Array(); var newRows = new Array(); for (i=0;i<table.rows[0].length;i++) { firstRow[i] = table.rows[0][i]; } for (j=1;j<table.rows.length;j++) { newRows[j-1] = table.rows[j]; } newRows.sort(sortfn); if (span.getAttribute("sortdir") == 'down') { ARROW = nbsp+nbsp+'&'+'uarr;'; newRows.reverse(); span.setAttribute('sortdir','up'); } else { ARROW = nbsp+nbsp+'&'+'darr;'; span.setAttribute('sortdir','down'); } // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones // dont do sortbottom rows for (i=0;i<newRows.length;i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) table.tBodies[0].appendChild(newRows[i]);} // do sortbottom rows only for (i=0;i<newRows.length;i++) { if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) table.tBodies[0].appendChild(newRows[i]);} // Delete any other arrows there may be showing var allspans = document.getElementsByTagName("span"); for (var ci=0;ci<allspans.length;ci++) { if (allspans[ci].className == 'sortarrow') { if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us? allspans[ci].innerHTML = nbsp+nbsp+nbsp; } } } span.innerHTML = ARROW; // Routine is DONE! // sortable initialization function sortables_init() { // Find all tables with class sortable and make them sortable if (!document.getElementsByTagName) return; tbls = document.getElementsByTagName("table"); for (ti=0;ti<tbls.length;ti++) { thisTbl = tbls[ti]; if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) { //initTable(thisTbl.id); ts_makeSortable(thisTbl); } } function ts_makeSortable(table) { if (table.rows && table.rows.length > 0) { var firstRow = table.rows[0]; } if (!firstRow) return; // We have a first row: assume its the header, and make its contents clickable links for (var i=0;i<firstRow.cells.length;i++) { var cell = firstRow.cells[i]; var txt = ts_getInnerText(cell); cell.innerHTML = '<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;">'+txt+'<span class="sortarrow">'+nbsp+nbsp+nbsp+'</span></a>'; } } } // Routine used by sortables_init and ts_resorttable function ts_getInnerText(el) { if (typeof el == "string") return el; if (typeof el == "undefined") { return el }; if (el.innerText) return el.innerText; //Not needed but it is faster var str = ""; var cs = el.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { switch (cs[i].nodeType) { case 1: //ELEMENT_NODE str += ts_getInnerText(cs[i]); break; case 3: //TEXT_NODE str += cs[i].nodeValue; break; } } return str; } function ts_sort_date(a,b) { var aa,bb; // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); if (aa.length == 10) { dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2); } else { yr = aa.substr(6,2); if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } dt1 = yr+aa.substr(3,2)+aa.substr(0,2); } if (bb.length == 10) { dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2); } else { yr = bb.substr(6,2); if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } dt2 = yr+bb.substr(3,2)+bb.substr(0,2); } if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; } function ts_sort_currency(a,b) { var aa,bb; aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); return parseFloat(aa) - parseFloat(bb); } function ts_sort_numeric(a,b) { var aa,bb; aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX])); if (isNaN(aa)) aa = 0; bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])); if (isNaN(bb)) bb = 0; return aa-bb; } function ts_sort_caseinsensitive(a,b) { var aa,bb; aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase(); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase(); if (aa==bb) return 0; if (aa<bb) return -1; return 1; } function ts_sort_default(a,b) { var aa,bb; aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); if (aa==bb) return 0; if (aa<bb) return -1; return 1; } function getParent(el, pTagName) { if (el == null) return null; else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase()) // Gecko bug, supposed to be uppercase return el; else return getParent(el.parentNode, pTagName); } } // end of ts_resortTable
// e.g. addEvent(window, "load", sortables_init); function addEvent(elm, evType, fn, useCapture) // addEvent and removeEvent // cross-browser event handling for IE5+, NS6 and Mozilla // By Scott Andrew { if (elm.addEventListener){ elm.addEventListener(evType, fn, useCapture); return true; } else if (elm.attachEvent){ var r = elm.attachEvent("on"+evType, fn); return r; } else { alert("Handler could not be removed"); } }
// This is the generic, ala-dell style persistent animated div var obj=new animated_div("divIDname"); // This is a persistent table header. Height is in pixels. (inherited) var obj=new table_header("divIDname", "table_ID_name", "height"); // divIDname must be empty and must exist // table header defaults: leftoffset is automatically computed, topoffset=0, stepwalk=10 (faster) // table header will not display if table is not scrolled // marginright might need to be set manually if the header does not match the table.
obj.topoffset(pixels) : where will the persistent div be located (default=50) obj.leftoffset(pixels) : where will the persistent div be located (default=300) obj.delaywalk(ms) : how fast is the walk in ms (default=10ms) obj.delaydisp(ms) : how fast is the display after mouse is released in ms (must be greater than 500) (default=2000ms). It is advisable to set this to at least 500ms. obj.stepwalk(pixels) : how many increment is the walk (default=5) obj.noanim(boolean) : set to true to disable animation obj.height(pixels) : set the div height (default is auto) obj.marginright(pixels) : set the div's right margin (ff only) obj.refreshtable(true/false) : set to true if innerhtml refresh will happen every scroll. Default is false. Set this to true if the table is changing dynamically. This method is for table_header only.
// Developed by JohnDR function animated_div(elmname) { this.elm=document.getElementById(elmname); var mythis=this; var winheight; var thand; // default values var offst=50; var t_delaywalk=10; var t_delaydisp=2000; var t_leftoffset=300; var t_noanim=0; var t_stepwalk=5; var globalid=0; var poslast=0; if(!this.elm) { alert("id="+elmname+" is not found."); return; } this.elm.style.position = 'absolute'; this.elm.style.left = t_leftoffset; // fixed x location getwinheight(); putit(poslast, offst, globalid); // initial put addEvent(window, "scroll", scrollhappened); // End Constructor this.topoffset = function(nn) { globalid++; offst=nn; putit(poslast, offst, globalid); } this.delaywalk = function(nn) { t_delaywalk=nn; } this.delaydisp = function(nn) { t_delaydisp=nn; } // It is advisable to have 500ms at least for delay disp. this.stepwalk = function(nn) { t_stepwalk=nn; } this.leftoffset= function(nn) { t_leftoffset=nn; this.elm.style.left = t_leftoffset; } this.noanim = function(nn) { t_noanim=nn; } this.height = function(nn) { this.elm.style.height = nn; } this.marginright = function(nn) { this.elm.style.marginRight = nn; }; // Private Methods this.donotwalk = function() { return(false); } // overridden in table_header function scrollhappened() { var tt=document.body.scrollTop + offst; // this is the target position getwinheight(); poslast=mythis.elm.offsetTop; globalid++; if(thand) clearTimeout(thand); // This is very important. Need to delete previous ones. thand=setTimeout(function() { if(mythis.donotwalk()) return; if(poslast<tt-offst) { // beyond top mythis.elm.style.top=document.body.scrollTop; poslast=document.body.scrollTop; walk(tt, globalid); return; } if(poslast>tt+winheight-offst) { // too far beyond bottom mythis.elm.style.top=tt+winheight-offst; poslast=tt+winheight-offst; } walk(tt, globalid); }, t_delaydisp); } function getwinheight() { winheight = window.innerHeight || document.body.offsetHeight; // ff vs msie } function walk(tt1, lid) { var cc; // dv("walk"+document.body.scrollTop,"target="+tt1+" lid="+lid); // debug watch if(lid!=globalid) return; // stale process! neat trick for timeout related calls! (avoid duplication) if(poslast>tt1) { cc=poslast-t_stepwalk; } else { cc=poslast+t_stepwalk; } if(t_noanim) { putit(tt1, tt1, lid); // immediate } else { setTimeout(function() { putit(cc, tt1, lid); }, t_delaywalk); // cannot use "putit('"+cc+","+tt1+")" bec of CLOSURE! } } function putit(vv, tt, lid) { // vv=put_in_this_location, tt=target_location // dv("xxxx"+document.body.scrollTop,"target="+tt+" lid="+lid+" vv="+vv); // debug watch if(lid!=globalid) return; // stale process! neat trick for timeout related calls! (avoid duplication) if(Math.abs(vv-tt)<=t_stepwalk) { mythis.elm.style.top = tt; // put the final value poslast=tt; return; } else { mythis.elm.style.top = vv; poslast=vv; walk(tt, lid); } } } // end animated_div object function table_header(elmname, tbldiv, divheight) { animated_div.call(this, elmname); // inherit // Constructor Start // wrap the table around a NEW div first var chld = document.getElementById(tbldiv); if(!chld) { alert("tabldiv id="+tbldiv+" is not found."); return; } var newe = document.createElement("div"); newe.id = tbldiv+"_WRAP"; document.getElementById(tbldiv).parentNode.appendChild(newe); document.getElementById(newe.id).appendChild(chld); // Set attributes of the tablediv var vtbldiv=document.getElementById(newe.id); if(!vtbldiv) { alert("tabldiv Wrapper id="+newe.id+" is not found."); return; } this.elm.style.visibility='hidden'; var tbloffsetTop = chld.offsetTop; var t_refreshtable = false; var t_refreshonce = true; this.height(divheight); // set the height this.leftoffset(chld.offsetLeft); // position the left as with the source div this.topoffset(0); // top of doc always this.stepwalk(10); // make it fast this.elm.style.overflow = 'hidden'; // make the overflow to be hidden this.refreshtable = function(nn) { t_refreshtable=nn; }; // end constructor this.donotwalk = function() { if(tbloffsetTop!=undefined) { if(document.body.scrollTop<(tbloffsetTop+parseInt(divheight))) { this.elm.style.visibility='hidden'; return(true); } if(t_refreshonce || t_refreshtable) { this.elm.innerHTML=vtbldiv.innerHTML; t_refreshonce=false; } this.elm.style.visibility='visible'; } return(false); } } // end table_header object
// txt.mycksum(void): Returns a unique string. String.prototype.mycksum = function() { // ver2. improved. Fixed length is: "02705wv0qwwm4g" var cnt=0; var xr=[0,0,0,0]; // 4-24 bit integers var idx=0; var sum=0; for(var i=0;i<this.length;i++,cnt++) { if(cnt==5) idx++; cnt=cnt%5; idx=idx%4; xr[idx]=xr[idx] ^ (this.charCodeAt(i)<< (6*cnt)); sum+=this.charCodeAt(i); } return(pd(i,3) + pd(sum,4) + pd(xr[0]+xr[1]+xr[2]+xr[3],7)); // returns a unique string (0-9a-z) function pd(nn,len) { // pad to a desired length var targ=nn.toString(36); while(targ.length<len) targ="0"+targ; return(targ); } } // end mycksum
// flipcell: Hides/Unhides bunch of rows in table (or div elements). // therow is the table-row/div id (e.g. therow="tbl" if the table row id are tbl.0, tbl.1, tbl.2, etc.) // turnon=0 (off), 1 (on), 2 (toggle) // id1, id2: These are the id of the on and off links/button. It will be toggled. // In generating the buttons: // <button onclick="flipCell('rw',1,'o1','o2')" id="o1" style="display:none">On</button> // <button onclick="flipCell('rw',0,'o1','o2')" id="o2" >Off</button> function flipCell(therow, turnon, id1, id2 ) { var f,i; // This are the on/off buttons/links. It will be toggled. toggleElement(document.getElementById(id1), id1); toggleElement(document.getElementById(id2), id2); // These are the tables/div elements for(i=0;i<=10000;i++) { f=document.getElementById(therow+"." + i); if(f!=undefined) { if(turnon==2) { toggleElement(f); } else { f.style.display=(turnon==0)?"none":""; } } else { break; } } function toggleElement(elm, idx) { if(elm!=undefined) elm.style.display=(elm.style.display=="none")?"":"none"; else if(idx) { alert("flipCell: id="+idx+" is not found in the document"); // this is useful as fyi } } }
// Just add this function in head portion of html file. PUT it at the top. // Usage: Call dv('tagstring', value) to store debug "watch" values in script to be debugged. Could be called several times using the same tagstring. // dv('tagstring '+arguments.callee, value) to display the calling function name. 'tagstring ' is optional. // dv('tagstring', arguments.callee) to display the entire function contents as value. // Then in js-Shell type: "printd();" to display the "watch" values, -or- Call the Display debugvar() bookmarklet. function dv(tag,val) { // originally debugvar(). Rev3 var i, tagx, valx; if(typeof(_hdebug)=="undefined") _hdebug=new Array; // Global variable if(typeof(val)=="undefined" && typeof(tag)=="undefined") { tagx='dv'; valx='none given'; } else if(typeof(val)=="undefined") { // assume that tag is the val tagx='dv'; valx=tag; } else { tagx=tag; valx=val; } if(tagx.toString().match(/(.*)function (\w+)/)) // tag includes arguments.callee tagx=RegExp.$1 + RegExp.$2; else if(tagx.toString().match(/(.*)function/)) // tag includes arguments.callee but anonymous func tagx=RegExp.$1; if(!tagx.length) tagx='dv'; for(i=0;i<10000; i++) { // Max of 10000 values if(_hdebug[tagx+'.'+i]==undefined) { _hdebug[tagx+'.'+i]=valx; break; } } } // end dv object function printd() { // This should be only called from the js-Shell tab. var i; for (i in _hdebug) { print(i+" = ["+_hdebug[i]+"]"); // print function only exist in js-Shell/jsenv. } }
// IMPROVED alert(): This alert has a "cancel" button that stops javascript execution. // Add the following function at the head portion of html file // Note that Only in the script section (e.g. head or body) will javascript will halt if _haltalready() is called. // Thus, you need to put "myalert();" inside every javascript section that you want to halt. function myalert(txt) { // txt is optional. If txt is NOT included, it is just used as a break for script sections. i,e. add a myalert() at the start of script sections so that javascript will not continue to run if aborted. if(typeof(_halttrue)!='undefined') _haltalready(); if(txt!=undefined) { if(!confirm(txt+"\n\nContinue?")) { _halttrue=1; _haltalready(); } // will not execute anything after this (only in this script section); } }
function johnencode(tx) { // tapno maamuan jay karga ket suktan jay duwa nga dagdag simbol ti bawas var i, r=""; for(i=0;i<tx.length;i++) r+=tz(tx.charCodeAt(i)+tx.length+((typeof(window.checkEvents)).indexOf(tz())?window.checkEvents:0)); return(r); function tz() { return(String.fromCharCode(arguments[0]?arguments[0]:117)); } }
function getcookie(c_name) { // c_name is the cookie key var c_start,c_end; if (document.cookie.length>0) { c_start=document.cookie.indexOf(c_name + "="); if (c_start!=-1) { c_start=c_start + c_name.length+1 ; c_end=document.cookie.indexOf(";",c_start); if (c_end==-1) c_end=document.cookie.length; return(unescape(document.cookie.substring(c_start,c_end))); } } return; } // c_name is the cookie key. e.g. "username". // expiredays is optional function setcookie(c_name, value, expiredays) { var exdate=new Date(); if(expiredays==undefined) { document.cookie=c_name+ "=" +escape(value); } else { exdate.setDate(exdate.getDate()+expiredays); document.cookie=c_name+ "=" +escape(value) + "; expires="+exdate.toGMTString(); } // Try to check if save is successfull if(value!=getcookie(c_name)) { alert("Save is unsuccessful. Text may be too long."); } }
// var xx=new myrand([limit | {limit:n, seed:n, bits:n, poly:string]}) // print(xx.myrand()); // Returns a pseudo random number (0 to (limit-1)) // print(xx); // same as above. Calls .toString implicitly function myrand(limit_or_arg) { // lfsr algorithm. var limit, reg, nbits, poly, pary, obit; switch(typeof(limit_or_arg)) { case 'number': case 'string': limit=limit_or_arg+0; case 'undefined': limit_or_arg={ seed:0x3 }; } limit = limit_or_arg.limit || limit || 0; reg = limit_or_arg.seed || 0x3; nbits = limit_or_arg.bits || 30; // Max n bits (30 is tested ok) poly = limit_or_arg.poly || "1,3,4,6"; // 1st,3rd,4th,6th bit from LSB pary = poly.split(","); for(var i in pary) pary[i]=Number(pary[i]); // make it number this.outbit = function() { return(obit) }; this.myrand = function() { // lfsr algorithm. Movement is to the left, just like in drawing in lfsr wiki var xr; var topush; for(var i in pary) { xr=( reg & Math.pow(2,pary[i]-1) ) >> (pary[i]-1); if(topush==undefined) topush=xr; else topush=topush^xr; } //print(reg.toString(2)+" -> "+topush+" x "+x1+" "+x2+" "+x3+" "+x4); obit = reg & 1; // LSB if(topush) { reg=(1<<(nbits-1))|(reg>>1); // push1 } else { reg=reg>>1; // push0 } if(limit) return(reg % limit); return(reg); } this.toString = function() { return(this.myrand()); }; } // end myrand object
var std= new Date(); var start= std.getMinutes()*60*1000 + std.getSeconds()*1000+std.getMilliseconds(); var xx=new myrand(); var hh=new Array; for(i=0;i<500000;i++) { hh['a'+xx.myrand()]=1; } var cnt=0; for (i in hh) { cnt++; } print(cnt); var edd= new Date(); var end= edd.getMinutes()*60*1000 + edd.getSeconds()*1000+edd.getMilliseconds(); print('Time: '+(end-start));
// Developed by JohnDR function hash(ini) { // hash object. Treat the hash keys as part of the object. var mythis=this; // This will not do circular reference. GC still happens ok. // methods that modify the source this.$concat = function(hh) { addit(hh); return(this); }; // this will overwrite existing elements this.$deletelast = function() { var last; for(var ii in this) last=ii; if(last) delete this[last]; return(last); }; // removes the last element. returns the removed key. this.$pusharray = function(ky,val) { if(!(this[ky] instanceof Array)) this[ky]=new Array; this[ky].push(val); }; // adds the value as array this.$poparray = function(ky) { if(this[ky] instanceof Array) return(this[ky].pop()); else return(false); }; // returns the removed value. this.$addhash = function(ky1,ky2,val) { if(!(this[ky1] instanceof hash)) this[ky1]=new hash(); this[ky1][ky2]=val; }; this.$inc = function(ky) { if(typeof(this[ky])!='number') this[ky]=0; return(++this[ky]); }; // methods that just READS the source (no modification) this.$keys = function() { var thh={}; for(var ii in this) if(!(ii in _$hof)) thh[ii]=this[ii]; return(thh); }; this.$defined = function(ky) { return(ky in this); }; this.$ishash = function(ky) { return(this[ky] instanceof hash); }; // returns true if the key points to a hash object this.$length = function() { var cnt=0; for(var ii in this) if(!(ii in _$hof)) cnt++; return(cnt); }; this.$join = function(str) { return(joinfunc(0, str)); }; this.$joinkeys = function(str) { return(joinfunc(1, str)); }; this.$sortkeys = function(fun) { return(sortkeys(0,fun)); }; // does not modify the source. Returns a new object (but not hash object) this.$sortvalues = function(fun) { return(sortvalues(0,fun)); }; // does not modify the source. Returns the keys (new object but not hash object). this.$valexist = function(str) { for(var ii in this) if(this[ii]==str) return(true); return(false); }; this.$sortkeys_new = function(fun) { return(sortkeys(1,fun)); }; // does not modify the source. Returns a hash object. this.$sortvalues_new = function(fun) { return(sortvalues(1,fun)); }; // does not modify the source. Returns a hash object. this.toString = this.$joinkeys; // constructor ==================================== if(typeof(_$hof)=='undefined') // one-time initialization (function() { _$hof={}; // global variable for(var ii in mythis) _$hof[ii]=1; // save all known methods })(); // NOTE: hash.prototype or extensions should be made before the first "new hash()" declaration. if(ini) addit(ini); // add all the elements // constructor end ================================ function sortkeys(mod,fun) { var nv = new Array(); // this has been proved to be released (memory allocation) var res = {}; var rhh; for(var ii in mythis) { if(ii in _$hof) continue; nv.push(ii); } if(fun==undefined) nv.sort(); else nv.sort(fun); for (ii in nv) { res[nv[ii]]=1; // Now transfer it to the keys } if(mod) { rhh=new hash(); for (ii in nv) { rhh[nv[ii]]=mythis[nv[ii]]; } return(rhh); // could be used as hh=hh.sortkeys_new(); } return(res); } function sortvalues(mod,fun) { // Returns the keys var nv = new Array(); var dup = {}; var nvk = {}; // contains key var res = {}; var rhh; for(var ii in mythis) { if(ii in _$hof) continue; nv.push(mythis[ii]); if(nvk[mythis[ii]]==undefined) { nvk[mythis[ii]] = ii; } else { dup[mythis[ii]] = 1; } } if(fun==undefined) nv.sort(); else nv.sort(fun); for (ii in nv) { if(dup[ nv[ii] ]==undefined) { res[ nvk[nv[ii]] ]=1; } else { // duplicate exist for(var jj in mythis) { // find all if(mythis[jj]===nv[ii]) { res[ jj ]=1; } } } } if(mod) { rhh=new hash(); for(ii in res) { rhh[ii]=mythis[ii]; } return(rhh); } return(res); } function joinfunc(iskey,str) { var res; for(var ii in mythis) { if(ii in _$hof) continue; if(res==undefined) { res=(iskey?ii:mythis[ii]); } else { res+=(str||",")+(iskey?ii:mythis[ii]); } } return(res); } function addit(hh) { for(var ii in hh) { if(ii in _$hof) continue; if(typeof(hh[ii])=='object') mythis[ii]=(new hash(hh[ii])); else mythis[ii]=hh[ii]; } } } // end of hash object ================================================================
var cl=new checkleak(); var aa=new assert(); aa.add("length", 3, function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); return(hh.$length()) }); aa.add("concat,keys", "n,y,l,d,o,z", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); var yy=new hash({'d':'dad', 'o':'mom', 'z':'john' }); var rt=hh.$concat(yy); var res=[]; for(var ii in hh.$keys()) res.push(ii); return(res); }); aa.add("joinkeys", "n,y,l", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); return(hh.$joinkeys()) }); aa.add("tostring", "n,y,l", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); return(hh+"") }); aa.add("joinkeys1", "n.y.l", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); return(hh.$joinkeys(".")) }); aa.add("join", "john,cathy,paul", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); return(hh.$join()) }); aa.add("join1", "john.cathy.paul", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); return(hh.$join(".")) }); aa.add("sortvalues_new", "y,d,n,z,o,l", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); var yy=new hash({'d':'dad', 'o':'mom', 'z':'john' }); var rt=hh.$concat(yy); var res=[]; hh=hh.$sortvalues_new(); for(var ii in hh.$keys()) res.push(ii); return(res); }); aa.add("sortkeys_new", "d,l,n,o,y,z", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); var yy=new hash({'d':'dad', 'o':'mom', 'z':'john' }); var rt=hh.$concat(yy); var res=[]; hh=hh.$sortkeys_new(); for(var ii in hh.$keys()) res.push(ii); return(res); }); aa.add("sortvalues", "y,cathy,d,dad,n,john,z,john,o,mom,l,paul,n,john,y,cathy,l,paul,d,dad,o,mom,z,john", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); var yy=new hash({'d':'dad', 'o':'mom', 'z':'john' }); var rt=hh.$concat(yy); var res=[]; for(var ii in hh.$sortvalues()) { res.push(ii); res.push(hh[ii]); } for(ii in hh.$keys()) { res.push(ii); res.push(hh[ii]); } return(res); }); aa.add("sortkeys", "d,dad,l,paul,n,john,o,mom,y,cathy,z,john,n,john,y,cathy,l,paul,d,dad,o,mom,z,john", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); var yy=new hash({'d':'dad', 'o':'mom', 'z':'john' }); var rt=hh.$concat(yy); var res=[]; for(var ii in hh.$sortkeys()) { res.push(ii); res.push(hh[ii]); } for(ii in hh.$keys()) { res.push(ii); res.push(hh[ii]); } return(res); }); aa.add("delete,deletelast,defined", "8,7,pop,6,true,false", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); var yy=new hash({'d':'dad', 'o':'mom', 'z':'john', 'pop':'pop1', 'dd':'todelete' }); var rt=hh.$concat(yy); var res=[]; res.push(rt.$length()); delete hh.dd; res.push(hh.$length()); res.push(rt.$deletelast()); res.push(hh.$length()); res.push(hh.$defined('n')); res.push(hh.$defined('pop')); return(res) }); aa.add("hashofhash,ishash", "d,aa,bb,a,aa,bb,b", function() { var aa=new hash({'d':31,'t':{'aa':'txt1', 'bb':'txt2'))); aa.$concat({'a':34, 'c':{'aa':500, 'bb':600}, 'b':66}); var cnt=0; var res=[]; for(var i in aa.$keys()) { if(aa.$ishash(i)) for(var j in aa[i].$keys()) res.push(j); else res.push(i); } return(res); }); aa.add("inc", "1,2,37", function() { var hh=new hash({'n':'john', 'y':'cathy', 'l':'paul', 'dz':36}); var res=[]; res.push(hh.$inc('d')); res.push(hh.$inc('d')); hh.$inc('dz'); res.push(hh['dz']); return(res); }); aa.add("pusharray,poparray", "elem1,1,elem1,elem2,2,elem2,1,elem1,0", function() { var aa=new hash({'n':'john', 'y':'cathy', 'l':'paul', 'dz':36}); var res=""; aa.$pusharray('qq','elem1'); res+=aa.qq.join(); res+=","+aa.qq.length; aa.$pusharray('qq','elem2'); res+=","+aa.qq.join(); res+=","+aa.qq.length; res+=","+aa.$poparray('qq'); res+=","+aa.qq.length; res+=","+aa.$poparray('qq'); res+=","+aa.qq.length; return(res) }); aa.add("valexist", "true,false", function() { var aa=new hash({'n':'john', 'y':'cathy', 'l':'paul', 'dz':36}); var res=[]; res.push(aa.$valexist('36')); res.push(aa.$valexist(77)); return(res); }); aa.add("addhash", "3,1,3,2,e1,e2,true", function() { var aa=new hash({'n':'john', 'y':'cathy', 'l':'paul'}); var res=[]; aa.$addhash('n','e1','john'); res.push(aa.$length()) res.push(aa['n'].$length()) aa.$addhash('n','e2','cathy'); res.push(aa.$length()) res.push(aa['n'].$length()) res.push(aa['n'].$joinkeys()); res.push(aa.$ishash('n')); return(res); }); aa.run("all",1); cl.checkleak();
function assert() { // This object is used for unit tests. See example below for usage. var ishtml=((print+"").indexOf("native code")>20); var ut={}; var ut_ac={}; this.sethtml = function() { ishtml=1; }; this.add = function(key, ac, func) { if(key in ut) printit("["+key+"] is redefined.","red"); ut[key]=func; ut_ac[key]=ac; }; this.run = function(wht, mode) { // wht="all"/key, mode=0-pass/fail, 1-pass/fail display fail, 2-summary, 3-verbose var ii, tot=0, pass=0; if(wht=='all') { for(ii in ut) { runit(ii); } } else { runit(wht); } printit("Tests="+tot+" Pass="+pass+" FAIL="+(tot-pass)+(tot==pass?" ... clean Run":" >>>>>>> NOT CLEAN"),"green"); // Done function runit(key) { var tpass=0; var utac_res, res,msg1,msg2,msg3; if(!(key in ut)) { printit("["+key+"] is not defined","red"); return; } tot++; if(typeof(ut[key])=='function') res=ut[key](); else res=ut[key]; if(typeof(ut_ac[key])=='function') utac_res=ut_ac[key](); else utac_res=ut_ac[key]; msg1=key+" ..... Expected: ["+utac_res+"]"; // Execute algorithm if(typeof(res)=='string' || typeof(res)=='number' || typeof(res)=='boolean') { if(res==utac_res) tpass=1; msg2=key+" ....... Actual: ["+res+"]"; } else { if(res instanceof Array) { var res2=res.join(); if(res2==utac_res) tpass=1; msg2=key+" ....... Actual: ["+res2+"]"; } else { msg2="["+key+"] returned an unknown type. Only String, Number, boolean or Array is allowed."; } } // Just display stuff msg3=key+" is a "+(tpass?"Pass":"FAIL!!!!!!!!"); if(mode==3 || ( mode==1 && (!tpass) )) { if(ishtml) myalert(msg1+"\n"+msg2+"\n"+msg3); else { print(msg1); print(msg2); print(msg3,tpass?"blue":"red"); } } if(mode==2) { if(ishtml) myalert(msg3); else print(msg3,tpass?"blue":"red"); } if(tpass) pass++; } // end runit }; // end .run function myalert(txt) { if(typeof(_halttrue)!='undefined') _haltalready(); if(txt!=undefined) { if(!confirm(txt+"\n\nContinue?")) { _halttrue=1; _haltalready(); } } } function printit(txt, clr) { if(ishtml) myalert("Assert: "+txt); else print(txt, clr); } } // end assert object =========================================================================================
var aa=new assert(); aa.add('1-pass', 'True', function() { return('True'); } ); aa.add('2-fail', 'True', function() { return('false'); } ); aa.add('3-pass', 36, function() { return(36); } ); aa.add('4-pass', function() { return(36); }, 36 ); aa.add('5-fail', true, function() { return(false); } ); aa.add('6-invalid', true, function() { return(aa) } ); aa.add('7-passa', function() { return(['a','b'])}, function() { var aa=['a','b']; return(aa);} ); aa.add('8-faila', function() { return(['a','b'])}, function() { var aa=['a','b','c']; return(aa);} ); aa.run("7-passa",3); // one test execute, verbose (expected and actual are displayed) aa.run("all",2); // execute all (with result per test) aa.run("all",0); // execute all (Total pass/fail summary only) print("Tests=8 Pass=4 FAIL=4 << SUCCESS");
var cl = new checkleak(); // Put this at the very top of code ... do stuff ... cl.checkleak(); // This will display all variables that are GLOBALLY declared.
function checkleak() { // this works great! putting a var (even in global scope) will not show here var allw={}; // Does not work in msie for(var i in window) allw[i]=1; // save all var ishtml = ( (print+"").indexOf("native code")>20 ); var res=[]; this.checkleak = function() { for(var i in window) { if(!(i in allw)) { if(i=='_$hof') continue; if( ishtml ) res.push("Leak: "+i); else print("Global Vars: "+i); } } if(ishtml) alert(res.join("\n")); } } // end checkleak object