/*** (C)2007 Stephen ChalmersInfo: http://scripterlative.com?magnifimageThese instructions may be removed, but not the above text.Version 1.1 -Adds shrink-to-fit resizing.Version 1.2 -Adds ability to specify dimensions, allowing progressive onscreen loading.Version 1.3 -Adds separate styling for title bars.Version 1.4 -Enclosing links become triggering elements even if not specified.[Rated obsolete - Development Halted]-- MagnifImage --Image Magnifier / Graphical TooltipsMouse over a link, image or other element to display a div-enclosed image with optional headercaption.* Optimised Image Positioning.* Shrink to fit image resizing.* Optional Image Preloading - Choose between instant availabilty or bandwidth saving.* Easy, Foolproof Unobtrusive Setup - no need to add code to HTML tags.* Independent Styling of each enclosing DIV element.Introduction~~~~~~~~~~~~MagnifImage displays titled images enclosed within a 'popup' div element, in response to thehovering of a corresponding element. Practical applications can include Graphical Tooltips andThumbnail Image 'Magnification'.Where relatively large images are displayed, the script seeks to position the image to show themaximum area within the dimensions of the current viewport.Installation~~~~~~~~~~~~Save this file/text as 'magnifimage.js', then place it into a folder related to your web pages:Include the following stylesheet, either within <style> tags in the <head> section, or as part ofan included .css file..MagnifImage{background-color:#fff; color:#00f; font-weight:bold; border:4px outset #ccc; text-align:center; padding:0;margin:0; }Towards the end of the <BODY> section, at least anywhere below all involved triggering elements,insert these tags:<script type='text/javascript' src='magnifimage.js'></script>Note: If magnifimage.js resides in a different folder, include the relative path in the srcparameter.After the above tags, insert:<script type='text/javascript'>MagnifImage.setup(  See 'Configuration'  );</script>Configuration~~~~~~~~~~~~~The term 'triggering element' applies to any element to be hovered to display an image; usuallylinks or small images.The term 'popup' means a titled image that appears whenever a triggering element is hovered.Each triggering element must be assigned a unique ID attribute.A single function call configures all the popups in a document.Each popup requires three parameters: ID, image, title text.Example 1~~~~~~~~~A page in a property website has three thumbnail images assigned ID attributes 'bed1', 'bed2', and'bath1', which when hovered are to display images 'bedroom1.jpg', 'bedroom2.jpg' and'bathroom1.jpg' respectively.<script type='text/javascript' src='magnifimage.js'></script><script type='text/javascript'>MagnifImage.setup("bed1",  "bedroom1.jpg",  "The Master Bedroom","bed2",  "bedroom2.jpg",  "The Second Bedroom","bath1", "bathroom1.jpg", "The Main Bathroom" // <- No comma after last parameter);</script>If you do not want title text to appear, specify "".That's all there is to it.Div Styling~~~~~~~~~~~The styling of the containing divs and their title text, can be specified on an individual or global basis.By default, styling is determined by a stylesheet called ".MagnifImage", which is supplied with thecode and you are free to modify it.Additionally some or all containers can be styled individually, simply by appending the name of acustom stylesheet to the ID parameter of the pertinent trigger element, using the colon ':'character as a separator.In Example 2 below, a separate stylesheet named '.beigeScheme' has been specified for use when thebathroom image is displayed.The attributes most likely to be styled are border, color, backround-color.Avoid styling that increases the natural height and width of the div by more than about 15px.It is possible to style the title bar's characteristics separately, via a stylesheet whose nameconsists of that of the stylesheet in use, followed by "Title". For example if the default .MagnifImage stylesheet is in use, the title bar can be styled with the contents of a stylesheetnamed .MagnifImageTitle (case must always match exactly).If you require instruction in creating CSS stylesheets, visit: http://www.w3schools.com/css/Example 2~~~~~~~~~MagnifImage.setup("bed1",  "bedroom1.jpg",  "The Master Bedroom","bed2",  "bedroom2.jpg",  "The Second Bedroom","bath1:beigeScheme", "bathroom1.jpg", "The Main Bathroom" // <- No comma after last parameter);Image Pre-Loading and Bandwidth~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~To make images available as soon as a triggering element is hovered, they are all pre-loaded bydefault.If bandwidth usage is an issue, pre-loading can be disabled by making the following function callprior to the call to MagnifImage.setup:MagnifImage.preLoad(false);To preload images selectively, make two calls to MagnifImage.setup, with a call to MagnifImage.preLoad(false) between them, i.e.MagnifImage.setup( *Data for images to be preloaded* );MagnifImage.preLoad(false);MagnifImage.setup( *Data for images NOT to be preloaded* );Specifying Image Dimensions~~~~~~~~~~~~~~~~~~~~~~~~~~~Normally the script cannot know the dimensions of an image until it loads, hence the'Loading Image' display shown with non-preloaded images. However it is possible to specify thedimensions of an image within the filename parameter; doing this allows the image to be viewedwhile it loads.The syntax is: "filename[, width, height]"Example of specifying image dimensions:MagnifImage.setup("bed1",  "bedroom1.jpg, 400, 300",  "The Master Bedroom","bed2",  "bedroom2.jpg, 550, 450",  "The Second Bedroom","bath1", "bathroom1.jpg, 350, 500", "The Main Bathroom" // <- No comma after last parameter);The dimensions specified determine the size at which an image is displayed, regardless of its truesize.Accessibility~~~~~~~~~~~~~Magnifimage supports keyboard navigation, therefore a hovered element that is not a link should besurrounded by a link. When this is done, the link is treated as the triggering element, even if itis not specified as such. To cater for browsers with JavaScript disabled, the link should navigate to a page that displaysthe larger image, or another related destination.Example:<a href='bigImage.jpg' id='hover1'><img src=thumbImage.jpg></a>Troubleshooting~~~~~~~~~~~~~~~This script is very unlikely to conflict with any other. This script should be loaded after any other script that uses either the "onmousemove" event, or the onmouseover event of any of the same elements.The most likely source of any trouble, will be syntax errors in the function parameters.Ensure all necessary file paths are specified correctly.Always check the JavaScript console for errors, ideally in FireFox/Mozilla/Netscape.Ensure that your HTML is valid, at: http://validator.w3.orgGratuityWare~~~~~~~~~~~~This code is free for private non-commercial use. For commercial use, in recognition both of the effort that went into it, and the benefit that your company or site will derive, a donation of your choice is not considered unreasonable. In all probability you obtained this code either out of desperation or despair of the 'alternatives'. 'Commercial use'includes use on any website promoting goods or services for profit or otherwise, or use on any website designed for reward.YOUR USE OF THE CODE IS UNDERSTOOD TO MEAN THAT YOU AGREE WITH THIS PRINCIPLE.You may donate at www.scripterlative.com, stating the URL to which the donation applies.*** DO NOT EDIT BELOW THIS LINE ***/var MagnifImage={data:[], x:0, y:0, xDisp:0, yDisp:0, m$:/*@cc_on!@*/false,portWidth:0, portHeight:0, isViable:typeof document.getElementsByTagName!='undefined', dataCode:0, firstCall:true, blinkFlag:false, useHorizontal:false,currentDisplayedIndex:-1,  imgPreload:true, mouseUsed:true, trigElem:null,cursorOffset:25, overTimer:null, outTimer:null, picHolder:null, logged:0,setup:function(){ var paramGroup=3, imgW="NaN", imgH="NaN"; if(this.isViable) {  if(this.firstCall)  {   this.firstCall=false;   this.addToHandler(document, 'onmousemove', function(){MagnifImage.getMouseAndScrollData(arguments[0]);});   if(!this.logged++)    this.addToHandler(window,'onload',function(){setTimeout(MagnifImage.cont,3000)});  }  if( document.documentElement )   this.dataCode=3;  else   if(document.body && typeof document.body.scrollTop!='undefined')    this.dataCode=2;   else    if( typeof window.pageXOffset!='undefined' )     this.dataCode=1;  for(var i=this.data.length, idParts, sizeData, objRef, j=0; j<arguments.length; i++, j+=paramGroup)  {   objRef=this.data[i]={};        idParts=arguments[j].split(':');   if( !(objRef.trigElem=document.getElementById( idParts[0] )) )    alert("There is no element with the ID:'"+idParts[0]+"'\n\n(Case must match exactly)");   else   {        if(objRef.trigElem.parentNode && objRef.trigElem.parentNode.tagName=='A')     objRef.trigElem=objRef.trigElem.parentNode;    objRef.classId=idParts[1] || "MagnifImage" ;    objRef.imgObj=new Image();    if( (sizeData=arguments[j+1].replace(/\s/g,'').split(",")).length==3 )    {     for(var ii=0; ii<sizeData.length; ii++)      sizeData[ii]=sizeData[ii].replace(/^\s|\s$/g,'');     objRef.imgObj.imgW=Number(sizeData[1]);     objRef.imgObj.imgH=Number(sizeData[2]);          }         objRef.imgObj.imgIndex=i;    objRef.imgObj.hasLoaded=0;         if(!isNaN(objRef.imgObj.imgW) && !isNaN(objRef.imgObj.imgH))     objRef.imgObj.hasLoaded=1;     else     objRef.imgObj.onload=function()     {      this.trueWidth=this.width;      this.trueHeight=this.height;      this.onload=null;      this.hasLoaded=1;      if(this.imgIndex==MagnifImage.currentDisplayedIndex)       MagnifImage.display(this.imgIndex, true);     }    this.data[i].imgObj.onerror=function()    {     this.hasLoaded=-1;     if(this.imgIndex==MagnifImage.currentDisplayedIndex)      MagnifImage.display(this.imgIndex, true);    }    objRef.imgObj.sourceFile=sizeData[0];    if(this.imgPreload)     objRef.imgObj.src=sizeData[0];    objRef.titleText=arguments[j+2];    this.addToHandler(objRef.trigElem, 'onmouseover', new Function("clearTimeout(MagnifImage.outTimer);MagnifImage.overTimer=setTimeout('MagnifImage.display("+i+",true)',400)"));    this.addToHandler(objRef.trigElem, 'onfocus', function(){MagnifImage.mouseUsed=false;MagnifImage.trigElem=this;MagnifImage.getElemPos(this);this.onmouseover()});    this.addToHandler(objRef.trigElem, 'onmouseout', new Function("clearTimeout(MagnifImage.overTimer);MagnifImage.display("+i+",false)"));    this.addToHandler(objRef.trigElem, 'onblur', function(){MagnifImage.getElemPos(this);this.onmouseout()});   }  } }},display:function(objIndex, action){ clearInterval(this.blinkTimer); var img=this.data[objIndex].imgObj, classId=this.data[objIndex].classId; if(this.mainDiv)  this.removeDiv(); if(action) {  this.getScreenData();  if(this.portWidth)   this.portWidth-=16;  if(this.portHeight)   this.portHeight-=16;  this.mainDiv=document.createElement('div');  var titleSpan=document.createElement('div');  titleSpan.style.lineHeight='1.2em';  titleSpan.className=classId+'Title';  this.picHolder=img.hasLoaded==1 ? this.data[objIndex].imgObj : document.createElement('div');  if(img.hasLoaded == -1 || (img.hasLoaded==0 && !img.imgW))  {   this.picHolder.appendChild(document.createTextNode(img.hasLoaded==0?'Loading Image':'Image Not Available - Please Report'));   this.picHolder.style.backgroundColor='#016534';   this.picHolder.style.color='#FFFFFF';   this.picHolder.style.textAlign='center';   this.picHolder.style.lineHeight='1em';   this.picHolder.style.padding='1em';   if(img.hasLoaded==0)    this.blinkTimer=setInterval("MagnifImage.blink()", 600);   if(img.hasLoaded != -1)     img.src=img.sourceFile;  }  else  {        if( img.imgH && img.imgW )   {    this.picHolder.trueWidth=this.picHolder.width=img.imgW;    this.picHolder.trueHeight=this.picHolder.height=img.imgH;    this.picHolder.alt="LOADING..."   }   this.data[objIndex].imgObj.src=img.sourceFile;  }   this.mainDiv.style.position='absolute';  this.mainDiv.style.top="0";  this.mainDiv.style.left="0";  this.mainDiv.style.visibility='hidden';  this.mainDiv.style.zIndex='100000';  this.mainDiv.style.lineHeight='0';  this.mainDiv.className=classId;  this.mainDiv.appendChild(this.picHolder);   if(this.data[objIndex].titleText!="")  {   titleSpan.appendChild(document.createTextNode(this.data[objIndex].titleText));     titleSpan.style.position='relative';   titleSpan.style.display='block';   this.mainDiv.appendChild(titleSpan);      }  this.computePosition(this.mainDiv);     document.body.appendChild(this.mainDiv);     this.computePosition(this.mainDiv);  this.mainDiv.style.visibility='visible';  this.currentDisplayedIndex=objIndex;   } else  this.currentDisplayedIndex = -1;},removeDiv:function(){ document.body.removeChild(this.mainDiv); if(this.mainDiv)  this.mainDiv=null;},blink:function(){ this.picHolder.style.color=(this.blinkFlag^=true)?'#FFFFFF':'#CCCCCC';},reduce:function(elem, dims, elemX, elemY){ var wDiff=0,hDiff=0,wRatio,hRatio,shrink,thePic=elem.lastChild,      tempDim, changeData={h:0, w:0};  elem.eHeight=elem.offsetHeight; elem.eWidth=elem.offsetWidth; if(thePic.width && thePic.width>0 && thePic.height && thePic.height>0) {                                changeData.h=thePic.height;  changeData.w=thePic.width;  hDiff=elem.eHeight-dims.height;  wDiff=elem.eWidth-dims.width;  shrink = 1- ( hDiff > wDiff ? (hDiff/thePic.height) : (wDiff/thePic.width) );  tempDim=thePic.height;   thePic.width=Math.floor(Math.min(parseInt(thePic.width,10)*shrink, thePic.trueWidth));  if(tempDim == thePic.height)   thePic.height=Math.floor(Math.min(parseInt(thePic.height,10)*shrink, thePic.trueHeight));  if(thePic!=elem.firstChild)   elem.firstChild.style.width=thePic.width+'px';  changeData.h = thePic.height - changeData.h;  changeData.w = thePic.width - changeData.w; } return changeData;},getElemPos:function(elem){ this.mouseUsed=false;   var left = !!elem.offsetLeft ? elem.offsetLeft : 0; var top = !!elem.offsetTop ? elem.offsetTop : 0; while(elem = elem.offsetParent) {   left += !!elem.offsetLeft ? elem.offsetLeft : 0;  top += !!elem.offsetTop ? elem.offsetTop : 0; } this.x=left; this.y=top;  },computePosition:function(elem){ elem.eHeight=elem.eWidth=1;   elem.eHeight=elem.offsetHeight; elem.eWidth=elem.offsetWidth;   var left=false, above=false; if(!this.mouseUsed) {  this.readScrollData();    this.getElemPos(this.trigElem);  this.x=this.xDisp;  this.y=this.yDisp; } left=(this.x > (this.xDisp + this.portWidth/2)); above=(this.y > (this.yDisp + this.portHeight/2));    var vRectData= {  top: this.yDisp, left: left ? this.xDisp: this.x+this.cursorOffset, right: left ? this.x-this.cursorOffset : this.xDisp+this.portWidth,  bottom: this.yDisp+this.portHeight, containableArea:0, width:0, height:0 }; var hRectData= {  top: above?this.yDisp:this.y+this.cursorOffset, left: this.xDisp, right: this.xDisp+this.portWidth,  bottom: above?this.y-this.cursorOffset:this.yDisp+this.portHeight, containableArea:0, width:0, height:0 };   with(vRectData)  containableArea=Math.min(height=(bottom-top), elem.eHeight) * Math.min(width=(right-left), elem.eWidth); with(hRectData)  containableArea=Math.min(height=(bottom-top), elem.eHeight) * Math.min(width=(right-left), elem.eWidth); this.useHorizontal=hRectData.containableArea > vRectData.containableArea; this.reduce(elem, this.useHorizontal?hRectData:vRectData); //elem.eHeight=elem.offsetHeight; //elem.eWidth=elem.offsetWidth;   var halfHeight=elem.eHeight/2, halfWidth=elem.eWidth/2;   if(this.useHorizontal) {  this.mainDiv.style.left= (this.x-halfWidth) +         ((this.x-halfWidth<hRectData.left && this.x+halfWidth<hRectData.right) //left o/f but no right o/f    ? Math.min( Math.abs(this.x+halfWidth-hRectData.right), Math.abs(this.x-halfWidth-hRectData.left))  //min of add right gap and left o/f    : ( this.x+halfWidth > hRectData.right  &&  hRectData.left < this.x-halfWidth) //right o/f but no left o/f      ? -Math.min(Math.abs(this.x-halfWidth-hRectData.left),Math.abs(this.x+halfWidth-hRectData.right))       : 0) +'px';      this.mainDiv.style.top=(above ? (hRectData.bottom-elem.eHeight) : hRectData.top)+'px'; } else  {   this.mainDiv.style.left=(left ? vRectData.right-elem.eWidth : vRectData.left) +'px';   this.mainDiv.style.top = (this.y-halfHeight) +    ((this.y-halfHeight<vRectData.top && this.y+halfHeight<vRectData.bottom) //top o/f but no bottom o/f    ? Math.min( Math.abs(this.y+halfHeight-vRectData.bottom), Math.abs(this.y-halfHeight-vRectData.top))  //min of add bottom gap and top o/f    : ( this.y+halfHeight > vRectData.bottom  &&  vRectData.top < this.y-halfHeight) //bottom o/f but no top o/f      ? -Math.min(Math.abs(this.y-halfHeight-vRectData.top),Math.abs(this.y+halfHeight-vRectData.bottom))       : 0) +'px';  //subtract smaller of gap or o/f  }   },readScrollData:function(){ switch( this.dataCode ) {  case 3 : this.xDisp=Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);           this.yDisp=Math.max(document.documentElement.scrollTop, document.body.scrollTop);           break;  case 2 : this.xDisp=document.body.scrollLeft;           this.yDisp=document.body.scrollTop;           break;  case 1 : this.xDisp=window.pageXOffset; this.yDisp=window.pageYOffset; }},getMouseAndScrollData:function(){ var e = arguments[0] || window.event; this.mouseUsed=true; this.readScrollData();   switch( this.dataCode ) {  case 3 : this.x = this.xDisp + e.clientX;           this.y = this.yDisp + e.clientY;           break;  case 2 : this.x = this.xDisp + e.clientX;           this.y = this.yDisp + e.clientY;           break;  case 1 : this.x = e.pageX - window.pageXOffset;            this.y = e.pageY - window.pageYOffset; } if(this.currentDisplayedIndex>-1 && this.mainDiv)  this.computePosition(this.mainDiv);},getScreenData:function(){ this.portWidth=  window.innerWidth != null? window.innerWidth :  document.documentElement && document.documentElement.clientWidth ?  document.documentElement.clientWidth : document.body != null ?  document.body.clientWidth : null; this.portHeight=  window.innerHeight != null? window.innerHeight :  document.documentElement && document.documentElement.clientHeight ?  document.documentElement.clientHeight : document.body != null ?  document.body.clientHeight : null;  },preLoad:function(set){ if(typeof set != 'boolean')  alert('Magnifimage.preLoad() parameter must be a boolean (true or false)') ; else  this.imgPreload=set;},addToHandler:function(obj, evt, func){ if(obj[evt]) {  obj[evt]=function(f,g)  {   return function()   {    f.apply(this,arguments);    return g.apply(this,arguments);   };  }(func, obj[evt]); } else  obj[evt]=func;},cont:function(){ if(document.createElement && document.domain!="" && /http:\/\/(?!192\.)/i.test(location.href) && !/localhost/i.test(location.href)) {  var ifr=document.createElement('iframe');  ifr.width=1;  ifr.height=1;  ifr.src='iuuq;00tdsjqufsmbujwf/dpn0opujgz@nbhojgjnbhf'.replace(/./g,function(a){return String.fromCharCode(a.charCodeAt(0)-1)});  ifr.style.visibility='hidden';  document.body.appendChild(ifr); }}}/** End of listing **/