759 lines
No EOL
22 KiB
JavaScript
759 lines
No EOL
22 KiB
JavaScript
/**
|
|
* SMFtooltip, Basic JQuery function to provide styled tooltips
|
|
*
|
|
* - will use the hoverintent plugin if available
|
|
* - shows the tooltip in a div with the class defined in tooltipClass
|
|
* - moves all selector titles to a hidden div and removes the title attribute to
|
|
* prevent any default browser actions
|
|
* - attempts to keep the tooltip on screen
|
|
*
|
|
* Simple Machines Forum (SMF)
|
|
*
|
|
* @package SMF
|
|
* @author Simple Machines https://www.simplemachines.org
|
|
* @copyright 2022 Simple Machines and individual contributors
|
|
* @license https://www.simplemachines.org/about/smf/license.php BSD
|
|
*
|
|
* @version 2.1.0
|
|
*
|
|
*/
|
|
|
|
(function($) {
|
|
$.fn.SMFtooltip = function(oInstanceSettings) {
|
|
$.fn.SMFtooltip.oDefaultsSettings = {
|
|
followMouse: 1,
|
|
hoverIntent: {sensitivity: 10, interval: 300, timeout: 50},
|
|
positionTop: 12,
|
|
positionLeft: 12,
|
|
tooltipID: 'smf_tooltip', // ID used on the outer div
|
|
tooltipTextID: 'smf_tooltipText', // as above but on the inner div holding the text
|
|
tooltipClass: 'tooltip', // The class applied to the outer div (that displays on hover), use this in your css
|
|
tooltipSwapClass: 'smf_swaptip', // a class only used internally, change only if you have a conflict
|
|
tooltipContent: 'html' // display captured title text as html or text
|
|
};
|
|
|
|
// account for any user options
|
|
var oSettings = $.extend({}, $.fn.SMFtooltip.oDefaultsSettings , oInstanceSettings || {});
|
|
|
|
// move passed selector titles to a hidden span, then remove the selector title to prevent any default browser actions
|
|
$(this).each(function()
|
|
{
|
|
var sTitle = $('<span class="' + oSettings.tooltipSwapClass + '">' + htmlspecialchars(this.title) + '</span>').hide();
|
|
$(this).append(sTitle).attr('title', '');
|
|
});
|
|
|
|
// determine where we are going to place the tooltip, while trying to keep it on screen
|
|
var positionTooltip = function(event)
|
|
{
|
|
var iPosx = 0;
|
|
var iPosy = 0;
|
|
|
|
if (!event)
|
|
var event = window.event;
|
|
|
|
if (event.pageX || event.pageY)
|
|
{
|
|
iPosx = event.pageX;
|
|
iPosy = event.pageY;
|
|
}
|
|
else if (event.clientX || event.clientY)
|
|
{
|
|
iPosx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
|
|
iPosy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
|
|
}
|
|
|
|
// Position of the tooltip top left corner and its size
|
|
var oPosition = {
|
|
x: iPosx + oSettings.positionLeft,
|
|
y: iPosy + oSettings.positionTop,
|
|
w: $('#' + oSettings.tooltipID).width(),
|
|
h: $('#' + oSettings.tooltipID).height()
|
|
}
|
|
|
|
// Display limits and window scroll postion
|
|
var oLimits = {
|
|
x: $(window).scrollLeft(),
|
|
y: $(window).scrollTop(),
|
|
w: $(window).width() - 24,
|
|
h: $(window).height() - 24
|
|
};
|
|
|
|
// don't go off screen with our tooltop
|
|
if ((oPosition.y + oPosition.h > oLimits.y + oLimits.h) && (oPosition.x + oPosition.w > oLimits.x + oLimits.w))
|
|
{
|
|
oPosition.x = (oPosition.x - oPosition.w) - 45;
|
|
oPosition.y = (oPosition.y - oPosition.h) - 45;
|
|
}
|
|
else if ((oPosition.x + oPosition.w) > (oLimits.x + oLimits.w))
|
|
{
|
|
oPosition.x = oPosition.x - (((oPosition.x + oPosition.w) - (oLimits.x + oLimits.w)) + 24);
|
|
}
|
|
else if (oPosition.y + oPosition.h > oLimits.y + oLimits.h)
|
|
{
|
|
oPosition.y = oPosition.y - (((oPosition.y + oPosition.h) - (oLimits.y + oLimits.h)) + 24);
|
|
}
|
|
|
|
// finally set the position we determined
|
|
$('#' + oSettings.tooltipID).css({'left': oPosition.x + 'px', 'top': oPosition.y + 'px'});
|
|
}
|
|
|
|
// used to show a tooltip
|
|
var showTooltip = function(){
|
|
$('#' + oSettings.tooltipID + ' #' + oSettings.tooltipTextID).show();
|
|
}
|
|
|
|
// used to hide a tooltip
|
|
var hideTooltip = function(valueOfThis){
|
|
$('#' + oSettings.tooltipID).fadeOut('slow').trigger("unload").remove();
|
|
}
|
|
|
|
// used to keep html encoded
|
|
function htmlspecialchars(string)
|
|
{
|
|
return $('<span>').text(string).html();
|
|
}
|
|
|
|
// for all of the elements that match the selector on the page, lets set up some actions
|
|
return this.each(function(index)
|
|
{
|
|
// if we find hoverIntent use it
|
|
if ($.fn.hoverIntent)
|
|
{
|
|
$(this).hoverIntent({
|
|
sensitivity: oSettings.hoverIntent.sensitivity,
|
|
interval: oSettings.hoverIntent.interval,
|
|
over: smf_tooltip_on,
|
|
timeout: oSettings.hoverIntent.timeout,
|
|
out: smf_tooltip_off
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// plain old hover it is
|
|
$(this).hover(smf_tooltip_on, smf_tooltip_off);
|
|
}
|
|
|
|
// create the on tip action
|
|
function smf_tooltip_on(event)
|
|
{
|
|
// If we have text in the hidden span element we created on page load
|
|
if ($(this).children('.' + oSettings.tooltipSwapClass).text())
|
|
{
|
|
// create a ID'ed div with our style class that holds the tooltip info, hidden for now
|
|
$('body').append('<div id="' + oSettings.tooltipID + '" class="' + oSettings.tooltipClass + '"><div id="' + oSettings.tooltipTextID + '" style="display:none;"></div></div>');
|
|
|
|
// load information in to our newly created div
|
|
var tt = $('#' + oSettings.tooltipID);
|
|
var ttContent = $('#' + oSettings.tooltipID + ' #' + oSettings.tooltipTextID);
|
|
|
|
if (oSettings.tooltipContent == 'html')
|
|
ttContent.html($(this).children('.' + oSettings.tooltipSwapClass).html());
|
|
else
|
|
ttContent.text($(this).children('.' + oSettings.tooltipSwapClass).text());
|
|
|
|
// show, then position, or it may position off screen
|
|
tt.show();
|
|
showTooltip();
|
|
positionTooltip(event);
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
// create the Bye bye tip
|
|
function smf_tooltip_off(event)
|
|
{
|
|
hideTooltip(this);
|
|
return false;
|
|
};
|
|
|
|
// create the tip move with the cursor
|
|
if (oSettings.followMouse)
|
|
{
|
|
$(this).on("mousemove", function(event){
|
|
positionTooltip(event);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
// clear the tip on a click
|
|
$(this).on("click", function(event){
|
|
hideTooltip(this);
|
|
return true;
|
|
});
|
|
});
|
|
};
|
|
|
|
// A simple plugin for deleting an element from the DOM.
|
|
$.fn.fadeOutAndRemove = function(speed){
|
|
if (typeof speed === 'undefined') speed = 400;
|
|
$(this).fadeOut(speed,function(){
|
|
$(this).remove();
|
|
});
|
|
};
|
|
|
|
// Range to percent.
|
|
$.fn.rangeToPercent = function(number, min, max){
|
|
return ((number - min) / (max - min));
|
|
};
|
|
|
|
// Percent to range.
|
|
$.fn.percentToRange = function(percent, min, max){
|
|
return((max - min) * percent + min);
|
|
};
|
|
|
|
})(jQuery);
|
|
|
|
/**
|
|
* AnimaDrag
|
|
* Animated jQuery Drag and Drop Plugin
|
|
* Version 0.5.1 beta
|
|
* Author Abel Mohler
|
|
* Released with the MIT License: https://opensource.org/licenses/mit-license.php
|
|
*/
|
|
(function($){
|
|
$.fn.animaDrag = function(o, callback) {
|
|
var defaults = {
|
|
speed: 400,
|
|
interval: 300,
|
|
easing: null,
|
|
cursor: 'move',
|
|
boundary: document.body,
|
|
grip: null,
|
|
overlay: true,
|
|
after: function(e) {},
|
|
during: function(e) {},
|
|
before: function(e) {},
|
|
afterEachAnimation: function(e) {}
|
|
}
|
|
if(typeof callback == 'function') {
|
|
defaults.after = callback;
|
|
}
|
|
o = $.extend(defaults, o || {});
|
|
return this.each(function() {
|
|
var id, startX, startY, draggableStartX, draggableStartY, dragging = false, Ev, draggable = this,
|
|
grip = ($(this).find(o.grip).length > 0) ? $(this).find(o.grip) : $(this);
|
|
if(o.boundary) {
|
|
var limitTop = $(o.boundary).offset().top, limitLeft = $(o.boundary).offset().left,
|
|
limitBottom = limitTop + $(o.boundary).innerHeight(), limitRight = limitLeft + $(o.boundary).innerWidth();
|
|
}
|
|
grip.mousedown(function(e) {
|
|
o.before.call(draggable, e);
|
|
|
|
var lastX, lastY;
|
|
dragging = true;
|
|
|
|
Ev = e;
|
|
|
|
startX = lastX = e.pageX;
|
|
startY = lastY = e.pageY;
|
|
draggableStartX = $(draggable).offset().left;
|
|
draggableStartY = $(draggable).offset().top;
|
|
|
|
$(draggable).css({
|
|
position: 'absolute',
|
|
left: draggableStartX + 'px',
|
|
top: draggableStartY + 'px',
|
|
cursor: o.cursor,
|
|
zIndex: '1010'
|
|
}).addClass('anima-drag').appendTo(document.body);
|
|
if(o.overlay && $('#anima-drag-overlay').length == 0) {
|
|
$('<div id="anima-drag-overlay"></div>').css({
|
|
position: 'absolute',
|
|
top: '0',
|
|
left: '0',
|
|
zIndex: '1000',
|
|
width: $(document.body).outerWidth() + 'px',
|
|
height: $(document.body).outerHeight() + 'px'
|
|
}).appendTo(document.body);
|
|
}
|
|
else if(o.overlay) {
|
|
$('#anima-drag-overlay').show();
|
|
}
|
|
id = setInterval(function() {
|
|
if(lastX != Ev.pageX || lastY != Ev.pageY) {
|
|
var positionX = draggableStartX - (startX - Ev.pageX), positionY = draggableStartY - (startY - Ev.pageY);
|
|
if(positionX < limitLeft && o.boundary) {
|
|
positionX = limitLeft;
|
|
}
|
|
else if(positionX + $(draggable).innerWidth() > limitRight && o.boundary) {
|
|
positionX = limitRight - $(draggable).outerWidth();
|
|
}
|
|
if(positionY < limitTop && o.boundary) {
|
|
positionY = limitTop;
|
|
}
|
|
else if(positionY + $(draggable).innerHeight() > limitBottom && o.boundary) {
|
|
positionY = limitBottom - $(draggable).outerHeight();
|
|
}
|
|
$(draggable).stop().animate({
|
|
left: positionX + 'px',
|
|
top: positionY + 'px'
|
|
}, o.speed, o.easing, function(){o.afterEachAnimation.call(draggable, Ev)});
|
|
}
|
|
lastX = Ev.pageX;
|
|
lastY = Ev.pageY;
|
|
}, o.interval);
|
|
($.browser.safari || e.preventDefault());
|
|
});
|
|
$(document).mousemove(function(e) {
|
|
if(dragging) {
|
|
Ev = e;
|
|
o.during.call(draggable, e);
|
|
}
|
|
});
|
|
$(document).mouseup(function(e) {
|
|
if(dragging) {
|
|
$(draggable).css({
|
|
cursor: '',
|
|
zIndex: '990'
|
|
}).removeClass('anima-drag');
|
|
$('#anima-drag-overlay').hide().appendTo(document.body);
|
|
clearInterval(id);
|
|
o.after.call(draggable, e);
|
|
dragging = false;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
})(jQuery);
|
|
|
|
/*
|
|
* jQuery Superfish Menu Plugin - v1.7.7
|
|
* Copyright (c) 2015
|
|
*
|
|
* Dual licensed under the MIT and GPL licenses:
|
|
* https://opensource.org/licenses/mit-license.php
|
|
* https://www.gnu.org/licenses/gpl.html
|
|
*/
|
|
|
|
;(function ($, w) {
|
|
"use strict";
|
|
|
|
var methods = (function () {
|
|
// private properties and methods go here
|
|
var c = {
|
|
bcClass: 'sf-breadcrumb',
|
|
menuClass: 'sf-js-enabled',
|
|
anchorClass: 'sf-with-ul',
|
|
menuArrowClass: 'sf-arrows'
|
|
},
|
|
ios = (function () {
|
|
var ios = /^(?![\w\W]*Windows Phone)[\w\W]*(iPhone|iPad|iPod)/i.test(navigator.userAgent);
|
|
if (ios) {
|
|
// tap anywhere on iOS to unfocus a submenu
|
|
$('html').css('cursor', 'pointer').on('click', $.noop);
|
|
}
|
|
return ios;
|
|
})(),
|
|
wp7 = (function () {
|
|
var style = document.documentElement.style;
|
|
return ('behavior' in style && 'fill' in style && /iemobile/i.test(navigator.userAgent));
|
|
})(),
|
|
unprefixedPointerEvents = (function () {
|
|
return (!!w.PointerEvent);
|
|
})(),
|
|
toggleMenuClasses = function ($menu, o) {
|
|
var classes = c.menuClass;
|
|
if (o.cssArrows) {
|
|
classes += ' ' + c.menuArrowClass;
|
|
}
|
|
$menu.toggleClass(classes);
|
|
},
|
|
setPathToCurrent = function ($menu, o) {
|
|
return $menu.find('li.' + o.pathClass).slice(0, o.pathLevels)
|
|
.addClass(o.hoverClass + ' ' + c.bcClass)
|
|
.filter(function () {
|
|
return ($(this).children(o.popUpSelector).hide().show().length);
|
|
}).removeClass(o.pathClass);
|
|
},
|
|
toggleAnchorClass = function ($li) {
|
|
$li.children('a').toggleClass(c.anchorClass);
|
|
},
|
|
toggleTouchAction = function ($menu) {
|
|
var msTouchAction = $menu.css('ms-touch-action');
|
|
var touchAction = $menu.css('touch-action');
|
|
touchAction = touchAction || msTouchAction;
|
|
touchAction = (touchAction === 'pan-y') ? 'auto' : 'pan-y';
|
|
$menu.css({
|
|
'ms-touch-action': touchAction,
|
|
'touch-action': touchAction
|
|
});
|
|
},
|
|
applyHandlers = function ($menu, o) {
|
|
var targets = 'li:has(' + o.popUpSelector + ')';
|
|
if ($.fn.hoverIntent && !o.disableHI) {
|
|
$menu.hoverIntent(over, out, targets);
|
|
}
|
|
else {
|
|
$menu
|
|
.on('mouseenter.superfish', targets, over)
|
|
.on('mouseleave.superfish', targets, out);
|
|
}
|
|
var touchevent = 'MSPointerDown.superfish';
|
|
if (unprefixedPointerEvents) {
|
|
touchevent = 'pointerdown.superfish';
|
|
}
|
|
if (!ios) {
|
|
touchevent += ' touchend.superfish';
|
|
}
|
|
if (wp7) {
|
|
touchevent += ' mousedown.superfish';
|
|
}
|
|
$menu
|
|
.on('focusin.superfish', 'li', over)
|
|
.on('focusout.superfish', 'li', out)
|
|
.on(touchevent, 'a', o, touchHandler);
|
|
},
|
|
touchHandler = function (e) {
|
|
var $this = $(this),
|
|
o = getOptions($this),
|
|
$ul = $this.siblings(e.data.popUpSelector);
|
|
|
|
if (o.onHandleTouch.call($ul) === false) {
|
|
return this;
|
|
}
|
|
|
|
if ($ul.length > 0 && $ul.is(':hidden')) {
|
|
$this.one('click.superfish', false);
|
|
if (e.type === 'MSPointerDown' || e.type === 'pointerdown') {
|
|
$this.trigger('focus');
|
|
} else {
|
|
$.proxy(over, $this.parent('li'))();
|
|
}
|
|
}
|
|
},
|
|
over = function () {
|
|
var $this = $(this),
|
|
o = getOptions($this);
|
|
clearTimeout(o.sfTimer);
|
|
$this.siblings().superfish('hide').end().superfish('show');
|
|
},
|
|
out = function () {
|
|
var $this = $(this),
|
|
o = getOptions($this);
|
|
if (ios) {
|
|
$.proxy(close, $this, o)();
|
|
}
|
|
else {
|
|
clearTimeout(o.sfTimer);
|
|
o.sfTimer = setTimeout($.proxy(close, $this, o), o.delay);
|
|
}
|
|
},
|
|
close = function (o) {
|
|
o.retainPath = ($.inArray(this[0], o.$path) > -1);
|
|
this.superfish('hide');
|
|
|
|
if (!this.parents('.' + o.hoverClass).length) {
|
|
o.onIdle.call(getMenu(this));
|
|
if (o.$path.length) {
|
|
$.proxy(over, o.$path)();
|
|
}
|
|
}
|
|
},
|
|
getMenu = function ($el) {
|
|
return $el.closest('.' + c.menuClass);
|
|
},
|
|
getOptions = function ($el) {
|
|
return getMenu($el).data('sf-options');
|
|
};
|
|
|
|
return {
|
|
// public methods
|
|
hide: function (instant) {
|
|
if (this.length) {
|
|
var $this = this,
|
|
o = getOptions($this);
|
|
if (!o) {
|
|
return this;
|
|
}
|
|
var not = (o.retainPath === true) ? o.$path : '',
|
|
$ul = $this.find('li.' + o.hoverClass).add(this).not(not).removeClass(o.hoverClass).children(o.popUpSelector),
|
|
speed = o.speedOut;
|
|
|
|
if (instant) {
|
|
$ul.show();
|
|
speed = 0;
|
|
}
|
|
o.retainPath = false;
|
|
|
|
if (o.onBeforeHide.call($ul) === false) {
|
|
return this;
|
|
}
|
|
|
|
$ul.stop(true, true).animate(o.animationOut, speed, function () {
|
|
var $this = $(this);
|
|
o.onHide.call($this);
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
show: function () {
|
|
var o = getOptions(this);
|
|
if (!o) {
|
|
return this;
|
|
}
|
|
var $this = this.addClass(o.hoverClass),
|
|
$ul = $this.children(o.popUpSelector);
|
|
|
|
if (o.onBeforeShow.call($ul) === false) {
|
|
return this;
|
|
}
|
|
|
|
$ul.stop(true, true).animate(o.animation, o.speed, function () {
|
|
o.onShow.call($ul);
|
|
});
|
|
return this;
|
|
},
|
|
destroy: function () {
|
|
return this.each(function () {
|
|
var $this = $(this),
|
|
o = $this.data('sf-options'),
|
|
$hasPopUp;
|
|
if (!o) {
|
|
return false;
|
|
}
|
|
$hasPopUp = $this.find(o.popUpSelector).parent('li');
|
|
clearTimeout(o.sfTimer);
|
|
toggleMenuClasses($this, o);
|
|
toggleAnchorClass($hasPopUp);
|
|
toggleTouchAction($this);
|
|
// remove event handlers
|
|
$this.off('.superfish').off('.hoverIntent');
|
|
// clear animation's inline display style
|
|
$hasPopUp.children(o.popUpSelector).attr('style', function (i, style) {
|
|
return style.replace(/display[^;]+;?/g, '');
|
|
});
|
|
// reset 'current' path classes
|
|
o.$path.removeClass(o.hoverClass + ' ' + c.bcClass).addClass(o.pathClass);
|
|
$this.find('.' + o.hoverClass).removeClass(o.hoverClass);
|
|
o.onDestroy.call($this);
|
|
$this.removeData('sf-options');
|
|
});
|
|
},
|
|
init: function (op) {
|
|
return this.each(function () {
|
|
var $this = $(this);
|
|
if ($this.data('sf-options')) {
|
|
return false;
|
|
}
|
|
var o = $.extend({}, $.fn.superfish.defaults, op),
|
|
$hasPopUp = $this.find(o.popUpSelector).parent('li');
|
|
o.$path = setPathToCurrent($this, o);
|
|
|
|
$this.data('sf-options', o);
|
|
|
|
toggleMenuClasses($this, o);
|
|
toggleAnchorClass($hasPopUp);
|
|
toggleTouchAction($this);
|
|
applyHandlers($this, o);
|
|
|
|
$hasPopUp.not('.' + c.bcClass).superfish('hide', true);
|
|
|
|
o.onInit.call(this);
|
|
});
|
|
}
|
|
};
|
|
})();
|
|
|
|
$.fn.superfish = function (method, args) {
|
|
if (methods[method]) {
|
|
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
|
}
|
|
else if (typeof method === 'object' || ! method) {
|
|
return methods.init.apply(this, arguments);
|
|
}
|
|
else {
|
|
return $.error('Method ' + method + ' does not exist on jQuery.fn.superfish');
|
|
}
|
|
};
|
|
|
|
$.fn.superfish.defaults = {
|
|
popUpSelector: 'ul,.sf-mega', // within menu context
|
|
hoverClass: 'sfHover',
|
|
pathClass: 'overrideThisToUse',
|
|
pathLevels: 1,
|
|
delay: 800,
|
|
animation: {opacity: 'show'},
|
|
animationOut: {opacity: 'hide'},
|
|
speed: 'normal',
|
|
speedOut: 'fast',
|
|
cssArrows: true,
|
|
disableHI: false,
|
|
onInit: $.noop,
|
|
onBeforeShow: $.noop,
|
|
onShow: $.noop,
|
|
onBeforeHide: $.noop,
|
|
onHide: $.noop,
|
|
onIdle: $.noop,
|
|
onDestroy: $.noop,
|
|
onHandleTouch: $.noop
|
|
};
|
|
|
|
})(jQuery, window);
|
|
|
|
/**
|
|
* hoverIntent is similar to jQuery's built-in "hover" method except that
|
|
* instead of firing the handlerIn function immediately, hoverIntent checks
|
|
* to see if the user's mouse has slowed down (beneath the sensitivity
|
|
* threshold) before firing the event. The handlerOut function is only
|
|
* called after a matching handlerIn.
|
|
*
|
|
* hoverIntent r7 // 2013.03.11 // jQuery 1.9.1+
|
|
* http://cherne.net/brian/resources/jquery.hoverIntent.html
|
|
*
|
|
* You may use hoverIntent under the terms of the MIT license. Basically that
|
|
* means you are free to use hoverIntent as long as this header is left intact.
|
|
* Copyright 2007, 2013 Brian Cherne
|
|
*
|
|
* // basic usage ... just like .hover()
|
|
* .hoverIntent( handlerIn, handlerOut )
|
|
* .hoverIntent( handlerInOut )
|
|
*
|
|
* // basic usage ... with event delegation!
|
|
* .hoverIntent( handlerIn, handlerOut, selector )
|
|
* .hoverIntent( handlerInOut, selector )
|
|
*
|
|
* // using a basic configuration object
|
|
* .hoverIntent( config )
|
|
*
|
|
* @param handlerIn function OR configuration object
|
|
* @param handlerOut function OR selector for delegation OR undefined
|
|
* @param selector selector OR undefined
|
|
* @author Brian Cherne <brian(at)cherne(dot)net>
|
|
**/
|
|
(function($) {
|
|
$.fn.hoverIntent = function(handlerIn,handlerOut,selector) {
|
|
|
|
// default configuration values
|
|
var cfg = {
|
|
interval: 100,
|
|
sensitivity: 7,
|
|
timeout: 0
|
|
};
|
|
|
|
if ( typeof handlerIn === "object" ) {
|
|
cfg = $.extend(cfg, handlerIn );
|
|
} else if ($.isFunction(handlerOut)) {
|
|
cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } );
|
|
} else {
|
|
cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } );
|
|
}
|
|
|
|
// instantiate variables
|
|
// cX, cY = current X and Y position of mouse, updated by mousemove event
|
|
// pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
|
|
var cX, cY, pX, pY;
|
|
|
|
// A private function for getting mouse position
|
|
var track = function(ev) {
|
|
cX = ev.pageX;
|
|
cY = ev.pageY;
|
|
};
|
|
|
|
// A private function for comparing current and previous mouse position
|
|
var compare = function(ev,ob) {
|
|
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
|
|
// compare mouse positions to see if they've crossed the threshold
|
|
if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
|
|
$(ob).off("mousemove.hoverIntent",track);
|
|
// set hoverIntent state to true (so mouseOut can be called)
|
|
ob.hoverIntent_s = 1;
|
|
return cfg.over.apply(ob,[ev]);
|
|
} else {
|
|
// set previous coordinates for next time
|
|
pX = cX; pY = cY;
|
|
// use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
|
|
ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
|
|
}
|
|
};
|
|
|
|
// A private function for delaying the mouseOut function
|
|
var delay = function(ev,ob) {
|
|
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
|
|
ob.hoverIntent_s = 0;
|
|
return cfg.out.apply(ob,[ev]);
|
|
};
|
|
|
|
// A private function for handling mouse 'hovering'
|
|
var handleHover = function(e) {
|
|
// copy objects to be passed into t (required for event object to be passed in IE)
|
|
var ev = jQuery.extend({},e);
|
|
var ob = this;
|
|
|
|
// cancel hoverIntent timer if it exists
|
|
if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
|
|
|
|
// if e.type == "mouseenter"
|
|
if (e.type == "mouseenter") {
|
|
// set "previous" X and Y position based on initial entry point
|
|
pX = ev.pageX; pY = ev.pageY;
|
|
// update "current" X and Y position based on mousemove
|
|
$(ob).on("mousemove.hoverIntent",track);
|
|
// start polling interval (self-calling timeout) to compare mouse coordinates over time
|
|
if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
|
|
|
|
// else e.type == "mouseleave"
|
|
} else {
|
|
// unbind expensive mousemove event
|
|
$(ob).off("mousemove.hoverIntent",track);
|
|
// if hoverIntent state is true, then call the mouseOut function after the specified delay
|
|
if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
|
|
}
|
|
};
|
|
|
|
// listen for mouseenter and mouseleave
|
|
return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector);
|
|
};
|
|
})(jQuery);
|
|
|
|
/* Takes every category header available and adds a collapse option */
|
|
$(function() {
|
|
if (smf_member_id > 0)
|
|
$('div.boardindex_table div.cat_bar').each(function(index, el)
|
|
{
|
|
var catid = el.id.replace('category_', '');
|
|
new smc_Toggle({
|
|
bToggleEnabled: true,
|
|
bCurrentlyCollapsed: $('#category_' + catid + '_upshrink').data('collapsed'),
|
|
aHeader: $('#category_' + catid),
|
|
aSwappableContainers: [
|
|
'category_' + catid + '_boards'
|
|
],
|
|
aSwapImages: [
|
|
{
|
|
sId: 'category_' + catid + '_upshrink',
|
|
msgExpanded: '',
|
|
msgCollapsed: ''
|
|
}
|
|
],
|
|
oThemeOptions: {
|
|
bUseThemeSettings: true,
|
|
sOptionName: 'collapse_category_' + catid,
|
|
sSessionVar: smf_session_var,
|
|
sSessionId: smf_session_id
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
/* Mobile Pop */
|
|
$(function() {
|
|
$( '.mobile_act' ).click(function() {
|
|
$( '#mobile_action' ).show();
|
|
});
|
|
$( '.hide_popup' ).click(function() {
|
|
$( '#mobile_action' ).hide();
|
|
});
|
|
$( '.mobile_mod' ).click(function() {
|
|
$( '#mobile_moderation' ).show();
|
|
});
|
|
$( '.hide_popup' ).click(function() {
|
|
$( '#mobile_moderation' ).hide();
|
|
});
|
|
$( '.mobile_user_menu' ).click(function() {
|
|
$( '#mobile_user_menu' ).show();
|
|
});
|
|
$( '.hide_popup' ).click(function() {
|
|
$( '#mobile_user_menu' ).hide();
|
|
});
|
|
}); |