// $Id: util.js 771 2009-11-25 23:21:18Z jason $
/**
* Converts an integral duration to HH:MM:SS.
* @param timeval duration in seconds
* @return @a timeval as HH:MM:SS.
*/
function _formatInterval( timeval )
{
if( timeval <= 0 )
return '00:00:00';
var seconds = parseInt( timeval%60 );
if( seconds <= 9 ) seconds = '0' + (seconds);
var minutes = Math.floor(timeval/60)%60;
if( minutes <= 9 ) minutes = '0' + (minutes);
var hours = Math.floor(timeval/3600);
if( hours <= 9 ) hours = '0' + (hours);
return hours + ':' + minutes + ':' + seconds;
}
// Stolen from Chris's autosug.js :)
function _make_xhr( )
{
var xhr = null;
try {
xhr = new XMLHttpRequest();
} catch (trymicrosoft) {
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
xhr = false;
}
}
}
return xhr;
}
/* from http://onlinetools.org/articles/unobtrusivejavascript/chapter4.html
* (in turn based on http://www.scottandrew.com/weblog/articles/cbs-events) */
function _addEvent( obj, evType, fn )
{
if (obj.addEventListener){
obj.addEventListener(evType, fn, false);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
return false;
}
}
// from: http://www.openjs.com/articles/prevent_default_action/
function _stopEvent(e) {
e = e || window.event;
//e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = false;
//e.stopPropagation works only in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
//----------------------------------------------------
// credit for the following goes to PPK@quirksmode.org
// pp]{
function _findPos(obj)
{
var curleft = 0;
var curtop = 0;
if (obj.offsetParent)
while( obj )
{
curtop += obj.offsetTop;
curleft += obj.offsetLeft;
obj = obj.offsetParent;
}
else if (obj.x)
{
curleft += obj.x;
curtop += obj.y;
}
return [ curleft,curtop ];
}
function _findMouse( e )
{
var posx = 0;
var posy = 0;
e = e || window.event;
if( e.pageX || e.pageY )
{
posx = e.pageX;
posy = e.pageY;
}
else if( e.clientX || e.clientY )
{
posx = e.clientX + ( document.documentElement.scrollLeft ||
document.body.scrollLeft || 0 );
posy = e.clientY + ( document.documentElement.scrollTop ||
document.body.scrollTop || 0 );
}
return [ posx,posy ];
}
//}[
//--
/**
* Returns the value if the selected element of the provided radio button group.
* Why radio groups act as single elements rather than one-element arrays when
* only one item is present seems like a horrible design flaw.
*
* @param el radio button element
*
* @return the value of the selected element, null if none chosen
*/
function radio_get_selected( el )
{
if( typeof el.length == 'undefined' )
return el.checked ? el.value : null; // single element
else
for( var i=0; i < el.length; ++i )
if( el[i].checked )
return el[i].value;
return null;
}
/**
* Request a new page number for a large result set.
* @a fieldid is updated to the new page number, and its associated form is
* submitted.
* @param fieldid ID of the field to update
* @param pagenum page number to switch
*/
function changepage( fieldid, pagenum )
{
var field = document.getElementById( fieldid );
field.value = pagenum;
field.form.submit( );
}
/**
* Escapes characters matching [&<>].
* @param str string to escape
* @return escaped version of @a str
*/
function escape_html( str )
{
return str.split("&").join("&").split("<").join("<").
split(">").join(">");
}
/**
* Given a form ID, checks all of its check boxes.
* @param formId ID of form
* @param selected true to check, false to uncheck
* @param name if not null, restrict to inputs with this name
*/
function form_select_all( formId, selected, name )
{
var formEl = document.getElementById( formId );
if( !formEl ) return;
for( var i = 0; i < formEl.length; ++i )
if(
formEl.elements[i].type == 'checkbox' &&
(name && formEl.elements[i].name == name)
)
formEl.elements[i].checked = selected;
}
/**
* Simple function to push a class name onto a class tag.
* @param el element instance
* @param classn class tname
* @see popclass()
*/
function pushclass( el, classn )
{
if( el.className )
el.className = el.className + " " + classn;
else
el.className = classn;
}
/**
* Simple function to pop off the last item in a class tag.
* @param el element instance
* @see pushclass()
*/
function popclass( el )
{
if( !el.className ) return; // dumbass :P
len = el.className.length;
spaceat = el.className.lastIndexOf( " " );
if( spaceat == -1 )
el.className = "";
else
el.className = el.className.substring( 0,spaceat );
}
/**
* Returns the requested attribute value, or null if it does not exist.
*
* @note
* The whole namespace thing only works with proper XML; that is, the document
* must be served as application/xhtml+xml. We don't do that right now.
* When we do, @a namespace must contain the namespace URI, not the namespace
* prefix. Sigh.
*
* @note
* Okay, I guess this is wholly pointless right now since IE doesn't do
* hasAttribute().
*
* @param element instantiated element
* @param namespace attribute namespace ('' for no namespace)
* @param attrname attribute name (local part)
* @return attribute value, or null if not found
*/
function getAttribute( element, namespace, attrname )
{
/* applicable when served as application/xhtml+xml...?
if( element.getAttributeNS )
return element.hasAttributeNS( namespace, attrname )
? element.getAttributeNS( namespace, attrname )
: null;
else */
return element.hasAttribute( namespace + ':' + attrname )
? element.getAttribute( namespace + ':' + attrname )
: null;
}
/**
* Creates an XML document from the provided string.
*
* @note
* It is important that the returned document *not* contain a DOCTYPE (or, that
* it is correct for the returned document), and/or that the XML prologue is
* present. If the IE parser chokes, make sure that you've met these conditions.
*
* @param xmlstr string representing XML content
* @return DOMDocument instance (?)
*/
function _loadXML( xmlstr )
{
if( typeof DOMParser != 'undefined' )
{
var parser = new DOMParser();
return parser.parseFromString( xmlstr, 'text/xml' );
}
else if( typeof ActiveXObject != 'undefined' )
{
var doc = new ActiveXObject( 'Microsoft.XMLDOM' );
doc.async = 'false';
doc.loadXML( xmlstr );
return doc;
}
else return null;
}
/**
* Inserts a retrieved HTML fragment into the page.
* In a post-innerHTML world (specifically, when in XHTML mode) you must add
* external nodes to the document using W3C methods. However, simply cloning
* those external nodes won't work as they're missing the necessary XHTML
* metadata. This function creates the XHTML-ified nodes and inserts them into
* the document.
*
* @param nodeset the DOMXML node set (see _loadXML())
* @param parent parent node
* @param insert_before insert new nodes before this; if null, appends
* @param clear if true, remove existing children of parent
*/
function _cloneHTML( nodeset, parent, insert_before, clear )
{
if( clear )
while( parent.hasChildNodes() )
parent.removeChild( parent.firstChild );
for( var node_idx = 0; node_idx < nodeset.length; ++node_idx )
{
parent.insertBefore(
_replicate(nodeset.item(node_idx)), insert_before
);
}
}
/**
* _cloneHTML helper function which replicates a node.
* @param node node to replicate
* @return replicated version of @a node
*/
function _replicate( node )
{
if( node.nodeName == '#text' )
return document.createTextNode( node.nodeValue );
var newnode = document.createElement( node.nodeName );
/* IE has a strange concept of attributes -- they map to element properties.
* For example, to set the "class" attribute, you must refer to it as
* "className"; to set "colspan", you must refer to "colSpan". Luckily the
* latter can be worked around by setting IE's proprietary third argument to
* setAttribute() ("case_sensitive") to false. The former workaround must be
* hardcoded... :P */
var is_IE = typeof newnode.hasAttribute == 'undefined';
for( var attr_idx = 0; attr_idx < node.attributes.length; ++attr_idx )
{
if( !is_IE )
newnode.setAttribute(
node.attributes[attr_idx].name, node.attributes[attr_idx].value
);
else
{
var attrname = node.attributes[attr_idx].name;
if( attrname == 'class' ) attrname = 'className';
else if( attrname == 'for' ) attrname = 'htmlFor';
// ...any others?
newnode.setAttribute(
attrname, node.attributes[attr_idx].value, false
);
}
}
for( var node_idx = 0; node_idx < node.childNodes.length; ++node_idx )
newnode.appendChild( _replicate( node.childNodes[node_idx] ) );
return newnode;
}
/*!
* Carlos R. L. Rodrigues
* http://jsfromhell.com/array/average [rev. #1]
*/
average = function(a){
var r = {mean: 0, variance: 0, deviation: 0}, t = a.length;
for(var m, s = 0, l = t; l--; s += a[l]);
for(m = r.mean = s / t, l = t, s = 0; l--; s += Math.pow(a[l] - m, 2));
return r.deviation = Math.sqrt(r.variance = s / t), r;
}