/*jslint browser: true */
//Copyright (c) 2007 Lewis Linn White Jr.
//Author: Lewis Linn White Jr.
//Permission is hereby granted, free of charge, to any person
//obtaining a copy of this software and associated documentation
//files (the "Software"), to deal in the Software without
//restriction, including without limitation the rights to use,
//copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following
//conditions:
//The above copyright notice and this permission notice shall be
//included in all copies or substantial portions of the Software.
//Except as contained in this notice, the name(s) of the above
//copyright holders shall not be used in advertising or otherwise
//to promote the sale, use or other dealings in this Software without
//prior written authorization.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.
//All images distributed with this project are public domain
//Constructor. Sets up a few methods and registers a few events that need to be registered
//at create time. Also creates a internal namespace for our internal class/objects
function JCritter(agent)
{
var me, div, divArray, i, e;
me = this;
//States
this.isHidden = true;
this.isSpeaking = false;
this.isMute = false;
//create an internal namespace that we can reference in our prototype
this.internal = {};
//Cretae an IE6 flag for use later
this.internal.IE6 = (document.all && window.external && (typeof document.documentElement.style.maxHeight === 'undefined')) ? true : false;
//Assign agent
this.internal.agent = agent;
//Semi-internal page functions
this.internal.getPageWidth = function ()
{
return window.innerWidth || (document.documentElement.clientWidth || (document.body.clientWidth || 0));
};
this.internal.getPageHeight = function ()
{
return window.innerHeight || (document.documentElement.clientHeight || (document.body.clientHeight || 0));
};
//Create divs for our agent
divArray = ['bubbleDiv', 'bubbleTop', 'bubbleBottom', 'bubbleText', 'critterDiv'];
for(i = 0, e = divArray.length; i < e; i++)
{
this.internal[divArray[i]] = document.createElement('div');
}
this.internal.critterImg = document.createElement('img');
//bubbleDiv Holds top and bottom bubble divs
this.internal.bubbleDiv.style.position = this.internal.IE6 ? 'absolute' : 'fixed';
this.internal.bubbleDiv.style.visibility = 'hidden';
this.internal.bubbleDiv.style.width = '275px';
//bubbleTop
//this.internal.bubbleTop.style.textAlign = 'center';
this.internal.bubbleTop.style.background = 'url(bubble.gif) no-repeat top';
this.internal.bubbleTop.style.padding = '25px 8px 0px';
//bubbleBottom
//this.internal.bubbleBottom.style.textAlign = 'center';
this.internal.bubbleBottom.innerHTML = ' ';
this.internal.bubbleBottom.style.background = 'url(bubble.gif) no-repeat bottom';
this.internal.bubbleBottom.style.padding = '35px 8px 0px';
//bubbleText
this.internal.bubbleText.style.paddingLeft = '10px';
this.internal.bubbleText.style.paddingRight = '10px';
this.internal.bubbleText.style.textAlign = 'center';
//critterDiv
this.internal.critterDiv.style.position = this.internal.IE6 ? 'absolute' : 'fixed';
this.internal.critterDiv.style.visibility = 'hidden';
//critterImg
this.internal.critterImg.onclick = function ()
{
me.onClick();
};
this.internal.critterImg.onmouseover = function ()
{
me.onMouseIn();
};
this.internal.critterImg.onmouseout = function ()
{
me.onMouseOut();
};
//Add critter to page
this.internal.bubbleTop.appendChild(this.internal.bubbleText);
this.internal.bubbleDiv.appendChild(this.internal.bubbleTop);
this.internal.bubbleDiv.appendChild(this.internal.bubbleBottom);
this.internal.critterDiv.appendChild(this.internal.critterImg);
document.body.appendChild(this.internal.critterDiv);
document.body.appendChild(this.internal.bubbleDiv);
//If we are IE6, we need to add the draw() event to the window.onscroll event.
if (this.internal.IE6)
{
window.onscroll = function ()
{
me.draw();
};
}
}
JCritter.prototype =
{
//Drawing functions
drawBalloon: function ()
{
this.internal.bubbleDiv.style.left = this.internal.critterDiv.offsetLeft - this.internal.bubbleDiv.offsetWidth + this.internal.agent.speechLeft + 'px';
this.internal.bubbleDiv.style.top = this.internal.critterDiv.offsetTop - this.internal.bubbleDiv.offsetHeight + this.internal.agent.speechTop + 'px';
},
drawAgent: function ()
{
var pageY, pageX;
this.internal.critterImg.src = this.internal.agent.src;
this.internal.critterImg.style.width = this.internal.agent.width + 'px';
this.internal.critterImg.style.height = this.internal.agent.height + 'px';
pageY = this.internal.IE6 ? (window.pageYOffset || (document.documentElement.scrollTop || 0)) : 0;
pageX = this.internal.IE6 ? (window.pageXOffset || (document.documentElement.scrollLeft || 0)) : 0;
this.internal.critterDiv.style.left = this.internal.getPageWidth() + pageX - this.internal.agent.width - this.internal.agent.adjustLeft + 'px';
this.internal.critterDiv.style.top = this.internal.getPageHeight() + pageY - this.internal.agent.height - this.internal.agent.adjustTop + 'px';
},
draw: function ()
{
this.drawAgent();
this.drawBalloon();
},
//Methods
show: function ()
{
this.isHidden = false;
this.internal.critterDiv.style.visibility = 'visible';
},
say: function (text, align)
{
if (!text)
{
return this.internal.bubbleText.innerHTML;
}
if (this.isHidden || this.isMute)
{
return;
}
this.isSpeaking = true;
this.show();
if (align)
{
this.internal.bubbleText.style.textAlign = align;
}
this.internal.bubbleText.innerHTML = text;
this.drawBalloon();
this.internal.bubbleDiv.style.visibility = 'visible';
},
hush: function ()
{
this.isSpeaking = false;
this.internal.bubbleText.innerHTML = '';
this.internal.bubbleDiv.style.visibility = 'hidden';
},
hide: function ()
{
this.isHidden = true;
this.hush();
this.internal.critterDiv.style.visibility = 'hidden';
},
play: function (animationName)
{
this.internal.critterImg.src = this.internal.agent.animations[animationName];
this.draw();
},
mute: function ()
{
this.isMute = true;
this.hush();
},
unMute: function ()
{
this.isMute = false;
},
setFontColor: function (color)
{
this.internal.bubbleText.style.color = color;
},
setFontSize: function (size)
{
this.internal.bubbleText.style.fontSize = size;
},
setAgent: function (agent)
{
this.internal.agent = agent;
this.draw();
},
//Event Handlers
onClick: function ()
{
this.hush();
},
onMouseIn: function ()
{
return;
},
onMouseOut: function ()
{
return;
},
//Desstructor
destroy: function ()
{
var i, prop;
//We can't destroy our methods, since they are prototyped. However, we can destroy all our objects;
for (i in this.internal)
{
//delete our html elements
if (this.internal[i].parentNode)
{
this.internal[i].onclick = null;
this.internal[i].onmousein = null;
this.internal[i].onmouseout = null;
this.internal[i].parentNode.removeChild(this.internal[i]);
delete this.internal[i];
}
//delete everything else in internal
else
{
delete this.internal[i];
}
}
//delete everything else;
for (prop in this)
{
if (true)
{
this[prop] = null;
delete this[prop];
}
}
this.onClick = null;
this.onMouseIn = null;
this.onMouseOut = null;
}
};