
/*
Script: TipsX3.js
 Tooltips, BubbleTips, whatever they are, they will appear on mouseover

License:
 MIT-style license.

Credits:
 The idea behind Tips.js is based on Bubble Tooltips (<http://web-graphics.com/mtarchive/001717.php>) by Alessandro Fulcitiniti <http://web-graphics.com>
 TipsX3.js is based on Tips.js, with slight modifications, by razvan@e-magine.ro
*/

/*
Class: TipsX3
 Display a tip on any element with a title and/or href.

Note:
 Tips requires an XHTML doctype.

Arguments:
 elements - a collection of elements to apply the tooltips to on mouseover.
 options - an object. See options Below.

Options:
 maxTitleChars - the maximum number of characters to display in the title of the tip. defaults to 30.

 onShow - optionally you can alter the default onShow behaviour with this option (like displaying a fade in effect);
 onHide - optionally you can alter the default onHide behaviour with this option (like displaying a fade out effect);

 showDelay - the delay the onShow method is called. (defaults to 100 ms)
 hideDelay - the delay the onHide method is called. (defaults to 100 ms)

 className - the prefix for your tooltip classNames. defaults to 'tool'.

 the whole tooltip will have as classname: tool-tip

 the title will have as classname: tool-title

 the text will have as classname: tool-text

 offsets - the distance of your tooltip from the mouse. an Object with x/y properties.
 fixed - if set to true, the toolTip will not follow the mouse.

 loadingText - text to display as a title while loading an AJAX tooltip.

 errTitle, errText - text to display when there's a problem with the AJAX request.

Example:
 (start code)
 <img src="/images/i.png" title="The body of the tooltip is stored in the title" class="toolTipImg"/>
 <script>
 var myTips = new Tips($$('.toolTipImg'), {
 maxTitleChars: 50 //I like my captions a little long
 });
 </script>
 (end)

Note:
 The title of the element will always be used as the tooltip body. If you put :: on your title, the text before :: will become the tooltip title.
 If you put DOM:someElementID in your title, $('someElementID').innerHTML will be used as your tooltip contents (same syntax as above).
 If you put AJAX:http://www.example.com/path/to/ajax_file.php in your title, the response text will be used as tooltip contents (same syntax as above). Either absolute or relative paths are ok.
*/

var TipsX3 = new Class({

 options: { // modded for X3
 onShow: function(tip){
 tip.setStyle('visibility', 'visible');
 },
 onHide: function(tip){
 tip.setStyle('visibility', 'hidden');
 },
 maxTitleChars: 30,
 showDelay: 100,
 hideDelay: 100,
 className: 'tool',
 offsets: {'x': 16, 'y': 16},
 fixed: false,
 loadingText: 'Loading...',
 errTitle: 'Oops..',
 errText: 'There was a problem retrieving the tooltip.'
 },

 initialize: function(elements, options){
 this.setOptions(options);
 this.toolTip = new Element('div', {
 'class': this.options.className + '-tip',
 'styles': {
 'position': 'absolute',
 'top': '0',
 'left': '0',
 'visibility': 'hidden'
 }
 }).inject(document.body);
 this.wrapper = new Element('div').inject(this.toolTip);
 $$(elements).each(this.build, this);
 if (this.options.initialize) this.options.initialize.call(this);
 },

 build: function(el){ // modded for X3
 el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
 if (el.title){

 // check if we need to extract contents from a DOM element
 if (el.title.test('^DOM:', 'i')) {
 el.title = $(el.title.split(':')[1].trim()).innerHTML;
 }

 // check for an URL to retrieve content from
 if (el.title.test('^AJAX:', 'i')) {
 el.title = this.options.loadingText + '::' + el.title;
 }

 var dual = el.title.split('::');
 if (dual.length > 1) {
 el.$tmp.myTitle = dual[0].trim();
 el.$tmp.myText = dual[1].trim();
 } else {
 el.$tmp.myText = el.title;
 }

 el.removeAttribute('title');
 } else {
 el.$tmp.myText = false;
 }
 if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";
 el.addEvent('mouseenter', function(event){
 this.start(el);
 if (!this.options.fixed) this.locate(event);
 else this.position(el);
 }.bind(this));
 if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this));
 var end = this.end.bind(this);
 el.addEvent('mouseleave', end);
 el.addEvent('trash', end);
 },

 start: function(el){ // modded for X3
 this.wrapper.empty();

 // check if we have an AJAX request - if so, show a loading animation and launch the request
 if (el.$tmp.myText && el.$tmp.myText.test('^AJAX:', 'i')) {
 //if (this.ajax) this.ajax.cancel();
 this.ajax = new Ajax (el.$tmp.myText.replace(/AJAX:/i,''), {
 onComplete: function (responseText, responseXML) {
 el.title = responseText;
 this.build(el);
 this.start(el);
 }.bind(this),
 onFailure: function () {
 el.title = this.options.errTitle + '::' + this.options.errText;
 this.build(el);
 this.start(el);
 }.bind(this),
 method: 'get'
 }).request();
 el.$tmp.myText = '<div class="' + this.options.className + '-loading">&nbsp;</div>';
 }

 if (el.$tmp.myTitle){
 this.title = new Element('span').inject(
 new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)
 ).setHTML(el.$tmp.myTitle);
 }
 if (el.$tmp.myText){
 this.text = new Element('span').inject(
 new Element('div', {'class': this.options.className + '-text'}).inject(this.wrapper)
 ).setHTML(el.$tmp.myText);
 }
 $clear(this.timer);
 this.timer = this.show.delay(this.options.showDelay, this);
 },

 end: function(event){
 $clear(this.timer);
 this.timer = this.hide.delay(this.options.hideDelay, this);
 },

 position: function(element){
 var pos = element.getPosition();
 this.toolTip.setStyles({
 'left': pos.x + this.options.offsets.x,
 'top': pos.y + this.options.offsets.y
 });
 },

 locate: function(event){
 var win = {'x': window.getWidth(), 'y': window.getHeight()};
 var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
 var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
 var prop = {'x': 'left', 'y': 'top'};
 for (var z in prop){
 var pos = event.page[z] + this.options.offsets[z];
 if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
 this.toolTip.setStyle(prop[z], pos);
 };
 },

 show: function(){
 if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this);
 this.fireEvent('onShow', [this.toolTip]);
 },

 hide: function(){
 this.fireEvent('onHide', [this.toolTip]);
 }

});

TipsX3.implement(new Events, new Options);
