525 lines
12 KiB
JavaScript
525 lines
12 KiB
JavaScript
/************************************************/
|
|
/* IPB3 Javascript */
|
|
/* -------------------------------------------- */
|
|
/* ips.hoverCard.js - Delayed pop-up menu */
|
|
/* (c) IPS, Inc 2010 */
|
|
/* -------------------------------------------- */
|
|
/* Author: Matt Mecham */
|
|
/************************************************/
|
|
|
|
/* ===================================================================================================== */
|
|
/* IPB3 Hover card manager */
|
|
|
|
IPBoard.prototype.hoverCardRegister = {
|
|
|
|
mainStore: $H(),
|
|
|
|
initialize: function( key, options )
|
|
{
|
|
var store = $H();
|
|
|
|
/* Insert into main store */
|
|
if ( ! ipb.hoverCardRegister.mainStore.get( key ) )
|
|
{
|
|
ipb.hoverCardRegister.mainStore.set( key, options );
|
|
}
|
|
|
|
$$('._hovertrigger').each( function( elem )
|
|
{
|
|
try
|
|
{
|
|
_key = $(elem).readAttribute( "hovercard-ref" );
|
|
|
|
if ( key == _key )
|
|
{
|
|
$(elem).addClassName( '___hover___' + key );
|
|
store.set( 'key', key );
|
|
|
|
/* remove trigger class to prevent re-iteration later */
|
|
$(elem).removeClassName('_hovertrigger');
|
|
$(elem).addClassName('_hoversetup');
|
|
}
|
|
}
|
|
catch( err )
|
|
{
|
|
Debug.error( err );
|
|
}
|
|
} );
|
|
|
|
/* Set up cards */
|
|
store.each( function( elem )
|
|
{
|
|
new ipb.hoverCard( '___hover___' + elem.value, options );
|
|
} );
|
|
},
|
|
|
|
/* Post ajax update 'cos new content added via ajax won't be set up */
|
|
postAjaxInit: function()
|
|
{
|
|
ipb.hoverCardRegister.mainStore.each( function( elem )
|
|
{
|
|
ipb.hoverCardRegister.initialize( elem.key, elem.value );
|
|
} );
|
|
}
|
|
};
|
|
|
|
IPBoard.prototype.hoverCard = Class.create( {
|
|
|
|
/**
|
|
* options.ajaxUrl: Pass a complete ajax URL in.
|
|
* options.ajaxCacheExpire: Number of seconds to store the ajax cache. 0 to not cache
|
|
* options.type : Balloon* or pane
|
|
* options.position : Auto, topLeft, bottomLeft*, topRight, bottomRight
|
|
*/
|
|
/*------------------------------*/
|
|
/* Constructor */
|
|
initialize: function( className, options )
|
|
{
|
|
this.id = className;
|
|
this.timer = {},
|
|
this.card = false,
|
|
this.ajaxCache = {},
|
|
this.popupActive = {},
|
|
this.openId = false;
|
|
this.curEvent = false;
|
|
|
|
this.options = Object.extend( {
|
|
type: 'balloon',
|
|
position: 'bottomLeft',
|
|
w: '500px',
|
|
openOnClick: false,
|
|
openOnHover: true,
|
|
ajaxUrl: false,
|
|
delay: 800,
|
|
ajaxCacheExpire: 0,
|
|
black: false,
|
|
getId: false,
|
|
setIdParam: 'id',
|
|
callback: false }, arguments[1] );
|
|
this.init();
|
|
},
|
|
|
|
init: function()
|
|
{
|
|
this.debugWrite( "hoverCard.init()" );
|
|
|
|
/* Scoping issues #ftl */
|
|
var _hc = this;
|
|
|
|
document.observe( 'mousemove', _hc.mMove.bindAsEventListener( _hc ) );
|
|
|
|
/* Set up elements */
|
|
$$('.' + this.id ).each( function( elem )
|
|
{
|
|
elem.identify();
|
|
|
|
try
|
|
{
|
|
Event.stopObserving( $( elem.id ), 'mouseout' );
|
|
Event.stopObserving( $( elem.id ), 'mouseover' );
|
|
|
|
/* title attributes murder the pop-up effect */
|
|
$( elem.id ).writeAttribute( 'title', '' );
|
|
|
|
if ( $( elem.id ).down('a') )
|
|
{
|
|
$( elem.id ).down('a').writeAttribute( 'title', '' );
|
|
}
|
|
|
|
if( $( elem.id ).down('img') )
|
|
{
|
|
$( elem.id ).down('img').writeAttribute( 'title', '' );
|
|
$( elem.id ).down('img').writeAttribute( 'alt', '' );
|
|
}
|
|
}
|
|
catch (aBall){}
|
|
|
|
$( elem.id ).observe( 'contextmenu' , _hc.mContext.bindAsEventListener( _hc, elem.id ) );
|
|
$( elem.id ).observe( 'click' , _hc.mClick.bindAsEventListener( _hc, elem.id ) );
|
|
$( elem.id ).observe( 'mouseover' , _hc.mOver.bindAsEventListener( _hc, elem.id ) );
|
|
$( elem.id ).observe( 'mouseout' , _hc.mOut.bindAsEventListener( _hc, elem.id ) );
|
|
} );
|
|
},
|
|
|
|
/**
|
|
* Mouse Move
|
|
*/
|
|
mMove: function(e)
|
|
{
|
|
/* IE loses reference to event, so we need to copy it instead of use original reference */
|
|
var _newEvent = {};
|
|
for( var i in e ) { _newEvent[i] = e[i]; }
|
|
|
|
this.curEvent = _newEvent;
|
|
},
|
|
|
|
/**
|
|
* ITEM CLICK
|
|
*/
|
|
mClick: function(e, id)
|
|
{
|
|
if ( ! this.options.openOnClick )
|
|
{
|
|
this.close(id);
|
|
}
|
|
else
|
|
{
|
|
|
|
if ( $(id).tagName.toLowerCase() == 'input' && $(id).type.toLowerCase() == 'checkbox' )
|
|
{
|
|
/* If this is a checkbox, and we're choosing to show on click then we probably only
|
|
* want to show the card if we're clicking 'true'
|
|
*/
|
|
|
|
if ( $(id).checked !== true )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
this.show(id);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* ITEM Context menu
|
|
*/
|
|
mContext: function(e, id)
|
|
{
|
|
this.close(id);
|
|
},
|
|
|
|
/**
|
|
* ITEM MOUSEOVER
|
|
*/
|
|
mOver: function(e, id)
|
|
{
|
|
Event.stop(e);
|
|
|
|
if ( this.overPopUp(id) === true )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( this.options.openOnHover !== true )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this.debugWrite( "mover - setting time OVER " + id );
|
|
|
|
if ( ! Object.isUndefined( this.timer[id + '_out'] ) )
|
|
{
|
|
clearTimeout( this.timer[id + '_out'] );
|
|
}
|
|
|
|
/* Set timer */
|
|
this.timer[id + '_over'] = setTimeout( this.show.bind(this, id), this.options.delay );
|
|
},
|
|
|
|
/*
|
|
* ITEM MOUSEOUT
|
|
*/
|
|
mOut: function(e, id)
|
|
{
|
|
Event.stop(e);
|
|
|
|
if ( this.overPopUp(id) === true )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* Pop up class dominates the mouseover class */
|
|
Event.stopObserving( $( id ), 'mouseover' );
|
|
$( id ).observe( 'mouseover' , this.mOver.bindAsEventListener( this, id ) );
|
|
|
|
/* Clear any time out */
|
|
if ( ! Object.isUndefined( this.timer[id + '_over'] ) )
|
|
{
|
|
clearTimeout( this.timer[id + '_over'] );
|
|
}
|
|
|
|
/* Set timer */
|
|
this.debugWrite( "Mout - setting time OUT " + id );
|
|
this.timer[id + '_out'] = setTimeout( this.close.bind(this, id), 800 );
|
|
},
|
|
|
|
/*
|
|
* SHOW POP UP
|
|
*/
|
|
show: function(id)
|
|
{
|
|
var popup = 'pu__' + this.id + '_popup';
|
|
|
|
/* Clear any time out */
|
|
if ( ! Object.isUndefined( this.timer[id + '_out'] ) )
|
|
{
|
|
clearTimeout( this.timer[id + '_out'] );
|
|
}
|
|
|
|
if ( ! Object.isUndefined( this.card ) && this.card !== false )
|
|
{
|
|
this.card.kill();
|
|
this.card = false;
|
|
}
|
|
|
|
/* If we have an old popup from a previous class method, kill it 'cos this.card won't be populated */
|
|
if ( $(popup) )
|
|
{
|
|
$(popup).remove();
|
|
}
|
|
|
|
/* Set this as open */
|
|
this.openId = id;
|
|
|
|
var content = false;
|
|
|
|
if ( this.options.ajaxUrl )
|
|
{
|
|
content = "<div class='general_box pad' style='height: 130px; padding-top: 130px; text-align:center'><img src='" + ipb.vars['loading_img'] + "' alt='' /></div>";
|
|
}
|
|
else
|
|
{
|
|
/* Run call back */
|
|
if ( Object.isFunction( this.options.callback ) )
|
|
{
|
|
content = this.options.callback( this, id );
|
|
|
|
/* Did we decide to skip output? */
|
|
if ( content === false )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.error( "No AJAX or Callback specified. Whaddayagonnado?!" );
|
|
}
|
|
}
|
|
|
|
this.card = new ipb.Popup( 'pu__' + this.id, { type: 'balloon',
|
|
initial: content,
|
|
stem: true,
|
|
hideAtStart: false,
|
|
hideClose: true,
|
|
defer: false,
|
|
black: this.options.black,
|
|
attach: { target: $( id ), position: this.options.position },
|
|
w: this.options.w } );
|
|
|
|
/* Pop up class dominates the mouseover class */
|
|
Event.stopObserving( $( id ), 'mouseout' );
|
|
Event.stopObserving( $( id ), 'contextmenu' );
|
|
Event.stopObserving( $( id ), 'click' );
|
|
|
|
$( id ).observe( 'mouseout' , this.mOut.bindAsEventListener( this, id ) );
|
|
$( id ).observe( 'contextmenu' , this.mContext.bindAsEventListener( this, id ) );
|
|
$( id ).observe( 'click' , this.mClick.bindAsEventListener( this, id ) );
|
|
|
|
if ( this.options.ajaxUrl )
|
|
{
|
|
this.ajax( id );
|
|
}
|
|
},
|
|
|
|
/**
|
|
* CLOSE POP-UP
|
|
*/
|
|
close: function(id)
|
|
{
|
|
/* Don't close if we brushed past another trigger and are now over a pop-up */
|
|
if ( this.overPopUp(id) === true )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this.debugWrite( "Close: " + id );
|
|
|
|
/* Clear all time outs */
|
|
if ( ! Object.isUndefined( this.timer[id + '_out'] ) )
|
|
{
|
|
this.debugWrite( "-- Clearing: " + id + '_out' );
|
|
clearTimeout( this.timer[id + '_out'] );
|
|
}
|
|
|
|
if ( ! Object.isUndefined( this.timer[id + '_over'] ) )
|
|
{
|
|
this.debugWrite( "-- Clearing: " + id + '_over' );
|
|
clearTimeout( this.timer[id + '_over'] );
|
|
}
|
|
|
|
if ( ! Object.isUndefined( this.card ) && this.card !== false && id == this.openId )
|
|
{
|
|
/* Hide makes card fade nicely, we kill it in open */
|
|
this.card.hide();
|
|
this.card = false;
|
|
|
|
/* Set this as closed */
|
|
this.openId = false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Load ajax URL
|
|
*/
|
|
ajax: function( id )
|
|
{
|
|
var now = this.unixtime();
|
|
var url = this.options.ajaxUrl;
|
|
var bDims = {};
|
|
var aDims = {};
|
|
|
|
/* Before we load ajax, grab the top and height of item */
|
|
var popup = 'pu__' + this.id + '_popup';
|
|
//this.debugWrite( $(popup).innerHTML);
|
|
bDims['height'] = $( popup ).getHeight();
|
|
bDims['top'] = parseInt( $( popup ).style.top );
|
|
|
|
if ( ! Object.isUndefined( this.ajaxCache[ id ] ) )
|
|
{
|
|
if ( this.options.AjaxCacheExpire )
|
|
{
|
|
if ( now - parseInt( this.options.AjaxCacheExpire ) < this.ajaxCache[ id ]['time'] )
|
|
{
|
|
this.debugWrite( "Fetching from cache " + id );
|
|
|
|
/* Just update the card with the contents previously fetched */
|
|
this.card.update( this.ajaxCache[ id ]['content'] );
|
|
this.card.ready = true;
|
|
|
|
/* Now Check after and reposition if need be */
|
|
this._rePos( bDims, popup, this.id );
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.debugWrite( "Fetching from cache " + id );
|
|
|
|
/* Just update the card with the contents previously fetched */
|
|
this.card.update( this.ajaxCache[ id ]['content'] );
|
|
this.card.ready = true;
|
|
|
|
/* Now Check after and reposition if need be */
|
|
this._rePos( bDims, popup, this.id );
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Fetching ID? */
|
|
if ( this.options.getId )
|
|
{
|
|
var _id = $(id).readAttribute('hovercard-id');
|
|
url = url + '&' + this.options.setIdParam + '=' + _id;
|
|
}
|
|
|
|
this.debugWrite( "Ajax load " + id + " " + url );
|
|
|
|
new Ajax.Request( url,
|
|
{
|
|
method: 'get',
|
|
onSuccess: function(t)
|
|
{
|
|
if( t.responseText != 'error' )
|
|
{
|
|
if( t.responseText == 'nopermission' )
|
|
{
|
|
alert( ipb.lang['no_permission'] );
|
|
return;
|
|
}
|
|
|
|
/* Check for log out */
|
|
if ( t.responseText.match( "__session__expired__log__out__" ) )
|
|
{
|
|
this.update('');
|
|
alert( "Your session has expired, please refresh the page and log back in" );
|
|
return false;
|
|
}
|
|
|
|
this.debugWrite( "AJAX done!" );
|
|
this.card.update( t.responseText );
|
|
this.card.ready = true;
|
|
|
|
/* Now Check after and reposition if need be */
|
|
this._rePos( bDims, popup, this.id );
|
|
|
|
this.ajaxCache[ id ] = { 'content': t.responseText, 'time': now };
|
|
}
|
|
else
|
|
{
|
|
this.debugWrite( t.responseText );
|
|
return;
|
|
}
|
|
}.bind(this)
|
|
});
|
|
},
|
|
|
|
_rePos: function( bDims, popup, id )
|
|
{
|
|
//Debug.dir( bDims);
|
|
//Debug.write('here'); //Debug.dir( aDims);
|
|
//this.debugWrite(id)/;
|
|
/* Now Check after and reposition if need be */
|
|
aDims = {};
|
|
aDims['height'] = $( popup ).getHeight();
|
|
aDims['top'] = parseInt( $( popup ).getStyle( 'top' ) );
|
|
|
|
if ( $( 'pu__' + id + '_stem').className.match( /top/ ) && ( aDims['height'] != bDims['height'] ) )
|
|
{
|
|
var _nt = bDims['top'] - ( aDims['height'] - bDims['height'] ) - 10;
|
|
|
|
$( popup ).setStyle( { 'top': _nt + 'px' } );
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Fetch unixtime
|
|
*
|
|
*/
|
|
unixtime: function()
|
|
{
|
|
var _time = new Date();
|
|
return Date.parse( _time ) / 1000;
|
|
},
|
|
|
|
/**
|
|
* Hovering over a pop-up?
|
|
*/
|
|
overPopUp: function( id )
|
|
{
|
|
var myevent = this.curEvent;
|
|
|
|
if( !id ){ return; }
|
|
|
|
/* Moz chokes without try. */
|
|
try
|
|
{
|
|
if ( $(Event.findElement(myevent)) && $(Event.findElement(myevent)).descendantOf( $('pu__' + this.id + '_popup') ) )
|
|
{
|
|
this.debugWrite( "*** Over Pop Up ***" );
|
|
|
|
/* Test close again */
|
|
if ( this.openId !== false )
|
|
{
|
|
this.timer[id + '_out'] = setTimeout( this.close.bind(this, id), 800 );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
catch(err){}
|
|
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Debug write. Allows me to turn this off quickly
|
|
*/
|
|
debugWrite: function( text )
|
|
{
|
|
Debug.write( text );
|
|
}
|
|
} );
|