/* ------------------------------------------------------------------------ *
* SAS Institute, Inc.
*
* Copyright (c) 2005 Institute, Inc. All rights reserved.
*
* Purpose: Contains common javascript functionality meant to be
* reused in order to perform certain functions consistently
* across CDD space.
*
* Ideally this common functionality should be compatible across
* major browsers.
*
* ------------------------------------------------------------------------ */
// Determine Browser
// xOp7 = Opera v7, xOp5or6= Opera v5 or v6
// xIE = Internet Explorer, xNN4 = Netscape 4
xOp7=false,xOp5or6=false,xIE=false,xNN4=false;
var xUA=navigator.userAgent.toLowerCase();
if(window.opera){
xOp7=(xUA.indexOf('opera 7')!=-1 || xUA.indexOf('opera/7')!=-1);
if (!xOp7) xOp5or6=(xUA.indexOf('opera 5')!=-1 || xUA.indexOf('opera/5')!=-1 || xUA.indexOf('opera 6')!=-1 || xUA.indexOf('opera/6')!=-1);
}
else if(document.layers) xNN4=true;
else {xIE=document.all && xUA.indexOf('msie')!=-1 && parseInt(navigator.appVersion)>=4;}
/* ------------------------------------------------------------- *
* Get the current style for an element in browser
* independant fashion. IE uses currentStyle while Mozilla
* currently uses window.getComputedStyle(...)
* ------------------------------------------------------------- */
function sas_getCurrentStyle(element, style)
{
var styleValue="";
if(element!=null)
{
if (document.defaultView && document.defaultView.getComputedStyle)
{
styleValue=document.defaultView.getComputedStyle(element,null).getPropertyValue(style);
}
else
{
if(element.currentStyle)
{
styleValue=element.currentStyle[style];
}
}
}
return styleValue;
}
/* ------------------------------------------------------------- *
* --Begin createXMLHttpRequest--
*
* Attempt to create an xmlhttprequest for communicating
* with server
* ------------------------------------------------------------- */
function sas_createXMLHttpRequest()
{
var xmlhttp;
if(xIE)
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); // IE
}
else
{
xmlhttp = new XMLHttpRequest();
}
return xmlhttp;
}
/* ------------------------------------------------------------- *
* --Begin sas_registerEventHandler--
*
* Attempt to register an event listener in cross browser
* fashion.
*
* Parm: element - object on which to register the handler.
* Parm: eventType - event type to register this handler for.
* don't use 'on' prefix as this will be added
* automatically. 'click' rather than 'onclick'.
* Parm: listener - the function to register as the handler.
* Parm: capture - specifies whether the handler should capture events.
*
* Example Useage...
* sas_registerEventHandler(document, 'click', handleClick, false);
*
* ------------------------------------------------------------- */
function sas_registerEventHandler ( element, eventType, listener, capture )
{
if (element != null && eventType!=null && listener!=null)
{
if( element.attachEvent != null) // IE way
{
element.attachEvent( "on" + eventType, listener);
}
else
{
element.addEventListener( eventType, listener, capture );
}
}
}
/* ------------------------------------------------------------- *
* --Begin sas_unRegisterEventHandler--
*
* Attempt to remove an event listener in cross browser
* fashion.
*
* Parm: element - object on which to unregister event handler
* Parm: eventType - event type to unregister this handler for.
* don't use 'on' prefix as this will be added
* automatically. 'click' rather than 'onclick'.
* Parm: listener - the function to unregister as the handler.
* Parm: capture - specifies whether the handler being removed
* captures events.
*
* Example Useage...
* sas_unRegisterEventHandler(document, 'click', handleClick, false);
*
* ------------------------------------------------------------- */
function sas_unRegisterEventHandler ( element, eventType, listener, capture )
{
if (element != null && eventType!=null && listener!=null)
{
if( element.attachEvent != null) // IE way
{
element.detachEvent( "on" + eventType, listener);
}
else
{
element.removeEventListener( eventType, listener, capture );
}
}
}
/* ------------------------------------------------------------- *
* --Begin sas_autoPosition--
*
* Attempt to automatically do an absolute positioning on an html
* element relative to some other element. Will attempt several
* predefined relative positions until it finds one that doesn't
* cause the element to be clipped. If none of the predefined
* positions work without clipping then we just dump the element
* anywhere.
*
* Example Useage...
* relativeToElement = document.getElementById("MyImageId");
* DivToPosition = document.getELementById("MyPopupMenu");
* sas_autoPosition(DivToPosition, relativeToELement);
*
* ------------------------------------------------------------- */
function sas_autoPosition(elementToPosition, relativeToElement)
{
var relativeToCoordinates = new sas_Coordinates(relativeToElement);
relativeToCoordinates.setRelativeToSharedBreakoutBox(elementToPosition);
// lets try several positions which we would consider ideal and
// if none of them work without clipping then we'll have to resort to
// just dumping it somewhere even though it does clip
//sas_log_println('-----Start sas_autoPosition-------');
// 1. try positioning elementToPosition left edge aligned with left edge
// of relativeToElement and top edge aligned with bottomtop edge of relativeToElement.
proposedLeft = relativeToCoordinates.getX();
proposedTop = relativeToCoordinates.getY() + relativeToCoordinates.getHeight();
//sas_log_println('-----Attempt #1-------');
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// 2. try positioning element right edge aligned with right edge
// of relativeToElement and top edge aligned with bottom edge of relativeToElement
proposedLeft = relativeToCoordinates.getX() - (elementToPosition.offsetWidth - relativeToCoordinates.getWidth());
proposedTop = relativeToCoordinates.getY() + relativeToCoordinates.getHeight();
//sas_log_println('-----Attempt #2-------');
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// 3. try positioning elementToPosition left edge aligned with left edge of
// relativeToElement area and bottom edge aligned with top edge of relativeToElement
proposedLeft = relativeToCoordinates.getX();
proposedTop = relativeToCoordinates.getY() - elementToPosition.offsetHeight;
//sas_log_println('-----Attempt #3-------');
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// 3. try positioning elementToPosition right edge aligned with right edge
// of relativeToElement image and bottom edge aligned with top edge of relativeToElement
proposedLeft = relativeToCoordinates.getX() - (elementToPosition.offsetWidth - relativeToCoordinates.getWidth());
proposedTop = relativeToCoordinates.getY() - elementToPosition.offsetHeight;
//sas_log_println('-----Attempt #4-------');
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// 5. try positioning elementToPosition right edge aligned with left edge
// of relativeToElement and center aligned with center of relativeToElement
proposedLeft = relativeToCoordinates.getX() - elementToPosition.offsetWidth;
proposedTop = relativeToCoordinates.getY() - (elementToPosition.offsetHeight/2) + (relativeToCoordinates.getWidth()/2);
//sas_log_println('-----Attempt #5-------');
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// 6. try positioning elementToPosition left edge aligned with right edge
// of relativeToElement and center aligned with center of relativeToElement
proposedLeft = relativeToCoordinates.getX() + relativeToCoordinates.getWidth();
proposedTop = relativeToCoordinates.getY() - (elementToPosition.offsetHeight/2) + (relativeToCoordinates.getWidth()/2);
//sas_log_println('-----Attempt #6-------');
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// 7. last ditch effort... Could probably write another attempt that tries to figure out how much space is available
// on each side of the relativeToELement and optimize where the elementToPosition goes for the last try.
// Just dump it at our ideal spot (#1) even though it will clip
proposedLeft = relativeToCoordinates.getX();
proposedTop = relativeToCoordinates.getY() + relativeToCoordinates.getHeight();
//sas_log_println('-----Attempt #7 (Last Ditch)-------');
}
}
}
}
}
}
elementToPosition.style.left = proposedLeft;
elementToPosition.style.top = proposedTop;
//sas_log_println('-----End sas_autoPosition-------');
}
/* ------------------------------------------------------------- *
* --End sas_autoPosition--
* ------------------------------------------------------------- */
/* ------------------------------------------------------------- *
* --Begin sas_autoPositionHorizontally--
*
* Attempt to automatically do an absolute positioning on an html
* element relative to some other element. This version
* is meant for items which have a preference of positioning
* horizontally relative to an item. Such items include
* submenus or popups off of vertical menus.
* If we can't find suitable horizontal alignment then we just
* run through as if it weren't a horizontal preference until
* we hit a good position or give up.
*
* Example Useage...
* relativeToElement = document.getElementById("MyImageId");
* DivToPosition = document.getELementById("MyPopupMenu");
* sas_autoPositionHorizontally(DivToPosition, relativeToELement);
*
* ------------------------------------------------------------- */
function sas_autoPositionHorizontally(elementToPosition, relativeToElement)
{
var relativeToCoordinates = new sas_Coordinates(relativeToElement);
relativeToCoordinates.setRelativeToSharedBreakoutBox(elementToPosition);
// lets try several positions which we would consider ideal and
// if none of them work without clipping then we'll have to resort to
// just dumping it somewhere (0,0)??
// 1. try positioning elementToPosition left edge indented from right edge
// of relativeToElement and top edge aligned with top edge of relativeToElement.
proposedLeft = relativeToCoordinates.getX() + relativeToCoordinates.getWidth();
proposedTop = relativeToCoordinates.getY();
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// 2. try positioning element right edge indented from left edge
// of relativeToElement and top edge aligned with top edge of relativeToElement
proposedLeft = relativeToCoordinates.getX() - elementToPosition.offsetWidth;
proposedTop = relativeToCoordinates.getY();
if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
{
// if the preferred submenu alignments didn't work go through
// the position posibilities for non submenus.
sas_autoPosition(elementToPosition, relativeToElement);
return;
}
}
elementToPosition.style.left = proposedLeft;
elementToPosition.style.top = proposedTop;
}
/* ------------------------------------------------------------- *
* --End sas_autoPositionHorizontal--
* ------------------------------------------------------------- */
/* ------------------------------------------------------------- *
* --Begin sas_checkClipping--
*
* js function to try and determine whether placing a given html element
* at a specified set of absolute coordinates would cause the element
* to be clipped.
*
* Example Useage...
* if(sas_checkClipping(palette, proposedLeft, proposedTop)==true)
* this would clip so figure out somewhere else to place it.
*
* ------------------------------------------------------------- */
function sas_checkClipping(element, proposedLeft, proposedTop)
{
var clip=false;
elementWidth = element.offsetWidth;
elementHeight = element.offsetHeight;
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
// proposedLeft and proposedTop coming in are likely relative
// to elements breaking box. For clipping check we need to
// convert proposedLeft and proposedTop to be relative to the
// entire page. so.. Get breaking box of element. and then
// get that breaking boxes coordinates relative to the entire
// document. add that height and width to proposedTop and proposedLeft
breakoutBox = sas_getBreakoutBox(element);
if(breakoutBox!=null)
{
// Note: the above statement about clipping should be checked
// relative to entire page is generally true unless element
// lives in a breaking box that can itself cut off content such
// as overflows of clip, scroll, etc... so need to not adjust
// to entire page if this is the case.
if(sas_getCurrentStyle(breakoutBox,'overflowY')!='auto')
// if(breakoutBox.currentStyle.overflowY!='auto')
{
breakoutBoxCoordinates = new sas_Coordinates(breakoutBox);
breakoutBoxCoordinates.setRelativeToPage();
proposedLeft += breakoutBoxCoordinates.getX();
proposedTop += breakoutBoxCoordinates.getY();
}
}
// if element lives in scrollable overflow area then
// proposedLeft and proposedTop are likely relative
// to the virtual area (included nonvisible scroll areas)
// in checking clipping it needs to be going against
// the physical area instead so adjust them as needed.
if (element != null)
{
parentComponent = element;
while(parentComponent!=null)
{
//*** Note: the check for scrollTop>0, scrollLeft>0 deals with any scrollable area
// that is currently scrolled including the main browser window itself.
// The subsequent check for overflow settings specifically catches scroll areas OTHER
// than the main browser window itself.
// alter proposedTop and proposedLeft to take into account scrolling space.
// this will treat the proposed top relative to the physical
// top/left of the overflow area instead of relative to the virtual
// top/left of the overflow area
if(parentComponent.scrollTop>0 || parentComponent.scrollLeft>0)
{
proposedTop = proposedTop - parentComponent.scrollTop;
proposedLeft = proposedLeft - parentComponent.scrollLeft;
}
// if the scrollable area is something other than body then
// we need to alter the window width and height used as
// clipping checks to be the internal scrollable area
// instead of the entire window.
// settings other than auto creating scrollable areas?
if(sas_getCurrentStyle(parentComponent,'overflowY')=='auto' ||
sas_getCurrentStyle(parentComponent,'overflowX')=='auto')
{
windowWidth=parentComponent.offsetWidth;
windowHeight=parentComponent.offsetHeight;
break;
}
parentComponent = parentComponent.offsetParent;
}
}
// will it clip on left?
if(proposedLeft<0)
clip = true;
// will it clip on top?
if(proposedTop<0)
clip = true;
// will it clip on right side?
if(proposedLeft+elementWidth>windowWidth)
clip = true;
// will it clip on bottom
if(proposedTop+elementHeight>windowHeight)
clip = true;
//if(clip)
// sas_log_println('INVALID!! Proposed=[' +proposedLeft + ', ' + proposedTop + '], Dimensions=['+elementWidth+', '+elementHeight+'], WindowDimensions=[' + windowWidth + ', ' + windowHeight + ']');
//else
// sas_log_println('Valid Proposed=[' +proposedLeft + ', ' + proposedTop + '], Dimensions=['+elementWidth+', '+elementHeight+'], WindowDimensions=[' + windowWidth + ', ' + windowHeight + ']');
return clip;
}
/* ------------------------------------------------------------- *
* --End sas_checkClipping--
* ------------------------------------------------------------- */
/* ------------------------------------------------------------- *
* --Begin sas_Coordinates--
*
* js object for determining absolute coordinates of an
* html element. Useful for positioning one element relative
* to another with absolute position such as popup menus,
* Calendar popup, Color Picker popup, etc...
*
*
*
* NOTE:
* Depending on what you plan on doing with the coordinates of a given element you may want either
* coordinates relative to the top/left of the page OR coordinates relative to the top/left of the
* nearest relatively positioned containing box(breakout box).
*
* This is because an absolutely positioned element withing a breakoutbox (SPAN, DIV, etc..) that
* has a position of relative or absolute uses coordinates relative to that breakoutbox rather than to the the page.
* breakoutbox html elements that this is true for seem to differ based on browser. In IE it appears to
* be supported fairly widely across the board. In Mozilla it seems more restricted to things like Spans, Divs
* and not supported for things like Table, TH, TD, etc...
*
* Adding third case where you want coordinates of element relative to a breakoutbox for a different
* element. Take a popup div(p) which you want to position relative to an image (i). If p lives inside of
* different breakoutbox than i then the coordinates of i relative to page or its own breakoutbox do
* you know good. In this case you really need to the coordinates of i relative to the first breakoutbox
* that both i and p have in common.
*
*
* default coordinates will be relative to parent breakoutbox.
*
* Example Useage getting coordinates relative to parent breakoutbox.
* var coords = new sas_Coordinates(document.getElementById("someelement"));
* coords.getX()
* coords.getY()
* coords.getWidth()
* coords.getHeight()
*
* Example Useage getting coordinates relative to page.
* var coords = new sas_Coordinates(document.getElementById("someelement"));
* coords.setRelativeToPage();
*
* Example Useage getting coordinates relative to first breakoutbox shared with
* some other element.
* var coords = new sas_Coordinates(document.getElementById("someimage"));
* coords.setRelativeToSharedBreakoutBox("menudiv");
*
* Parameters:
* element - the html element you want to get coordinates for
*
* ------------------------------------------------------------- */
function sas_Coordinates(element)
{
this.element=element;
// determine absolute coordinates of the element
elementLeft=0;
elementTop=0;
if (element != null)
{
parentComponent = element;
while(parentComponent!=null)
{
// need to deal with horizontal overflows as well and
// also deal with anytime it creates a separate container box.
// Settings other than auto could trigger this such as "scroll".
if(sas_getCurrentStyle(parentComponent,'overflowY')=='auto')
// if(parentComponent.currentStyle.overflowY=="auto")
break;
// as we walk up the chain if we find an appropriate item with relative positioning then
// don't count it and stop immediately so that we return coordinates relative
// to this relative containing box
if(sas_getCurrentStyle(parentComponent,'position')=='relative' || sas_getCurrentStyle(parentComponent,'position')=='absolute')
{
// IE elements which honor 'relative' position
if(xIE)
break;
// Mozilla elements which honor 'relative' position
if(parentComponent.tagName=='SPAN' || parentComponent.tagName=='DIV')
break;
}
elementLeft = elementLeft + parentComponent.offsetLeft;
elementTop = elementTop + parentComponent.offsetTop;
parentComponent = parentComponent.offsetParent;
}
}
this.x=elementLeft;
this.y=elementTop;
this.init();
return this;
}
function sas_Coordinates_init()
{
if(xIE)
{
this.width=this.element.offsetWidth;
this.height=this.element.offsetHeight;
}
else
{
this.width=this.element.offsetWidth;
this.height=this.element.offsetHeight;
}
}
function sas_Coordinates_getX()
{
return this.x;
}
function sas_Coordinates_getY()
{
return this.y;
}
function sas_Coordinates_getWidth()
{
return this.width;
}
function sas_Coordinates_getHeight()
{
return this.height;
}
// comment the caveaut
function sas_Coordinates_setRelativeToSharedBreakoutBox(breakoutBoxChild)
{
// determine absolute coordinates of the element
elementLeft=0;
elementTop=0;
breakoutBox = sas_getBreakoutBox(breakoutBoxChild);
if (this.element != null)
{
parentComponent = this.element;
while(parentComponent!=null && parentComponent!=breakoutBox)
{
elementLeft = elementLeft + parentComponent.offsetLeft;
elementTop = elementTop + parentComponent.offsetTop;
parentComponent = parentComponent.offsetParent;
}
}
this.x=elementLeft;
this.y=elementTop;
this.init();
}
function sas_Coordinates_setRelativeToPage()
{
// determine absolute coordinates of the element
elementLeft=0;
elementTop=0;
if (this.element != null)
{
parentComponent = this.element;
while(parentComponent!=null)
{
elementLeft = elementLeft + parentComponent.offsetLeft;
elementTop = elementTop + parentComponent.offsetTop;
parentComponent = parentComponent.offsetParent;
}
}
this.x=elementLeft;
this.y=elementTop;
this.init();
}
sas_Coordinates.prototype.getX=sas_Coordinates_getX;
sas_Coordinates.prototype.getY=sas_Coordinates_getY;
sas_Coordinates.prototype.getWidth=sas_Coordinates_getWidth;
sas_Coordinates.prototype.getHeight=sas_Coordinates_getHeight;
sas_Coordinates.prototype.setRelativeToSharedBreakoutBox=sas_Coordinates_setRelativeToSharedBreakoutBox;
sas_Coordinates.prototype.setRelativeToPage=sas_Coordinates_setRelativeToPage;
sas_Coordinates.prototype.init=sas_Coordinates_init;
/* ------------------------------------------------------------- *
* --End sas_Coordinates--
* ------------------------------------------------------------- */
/* ------------------------------------------------------------- *
* find the container box (breakout box) for this element.
* This will walk up the dom tree until it finds an ancestor
* which causes absolute child coordinates to be relative to
* the box. This could walk all the way back up to the root
* document.
* ------------------------------------------------------------- */
function sas_getBreakoutBox(element)
{
if (element != null)
{
parentComponent = element;
while(parentComponent.offsetParent!=null)
{
parentComponent = parentComponent.offsetParent;
if(sas_getCurrentStyle(parentComponent,'overflowY')=='auto')
// if(parentComponent.currentStyle.overflowY=="auto")
break;
if(sas_getCurrentStyle(parentComponent,'position')=='relative' || sas_getCurrentStyle(parentComponent,'position')=='absolute')
{
// IE elements which honor 'relative' position
if(xIE)
break;
// Mozilla elements which honor 'relative' position
if(parentComponent.tagName=='SPAN' || parentComponent.tagName=='DIV')
break;
}
}
}
return parentComponent;
}
/* ------------------------------------------------------------- *
* --Begin Javascript logging helpers--
*
* js functions for helping log from javascript without using
* alerts. This will open a separate window and dump all log
* messages to this window instead of opening alert dialog.
*
* Example Useage:
*
* // print a simple debug message
* sas_log_println("Hey I'm logging a message");
*
* // print all the elements and their values for a form.
* sas_log_printFormElements(someform);
*
* // print all the properties for a given element.
* sas_log_printObjectProperties(somediv, "Popup_Div");
*
* ------------------------------------------------------------- */
var sas_log = null; //handle to log window
var sas_logging_enabled=true; //to log or not to log... that is the question!
function sas_log_enable(enable)
{
if (sas_logging_enabled != enable)
{
sas_logging_enabled = enable;
}
}
function sas_log_println(msg)
{
if(sas_logging_enabled==true)
{
sas_log_getLog().document.write(msg, "
");
sas_log_getLog().scrollBy(0,1000000); //scroll to the end
window.status = msg;
}
}
function sas_log_printFormElements(form)
{
if(sas_logging_enabled==true)
{
var text = "Form["+form.name+"] Elements:
\n";
if (form != null && form.elements == null)
{
//must be the ID for the form try to find the real form object
form = document.getElementById(form);
}
if (form != null && form.elements != null)
{
var elText;
for (i=0; i