File: /var/www/intranet.kauko.lt/wp-content/plugins/dpProEventCalendar/js/jquery.touch.js
/* jquery.touch v1.1.0 | (c) @ajlkn | github.com/ajlkn/jquery.touch | MIT licensed */
(function($) {
var $document = $(document),
dragTarget = null,
dropTargetElement = null;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Defaults
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Default settings.
*
* @type {object}
*/
var defaultSettings = {
// If true, touch inputs will trigger touch events.
useTouch: true,
// If true, mouse inputs will trigger touch events.
useMouse: true,
// If true, certain events (like drag) can continue to track even if the mouse cursor leaves the originating element.
trackDocument: false,
// If true, when "trackDocument" is enabled, coordinates will be normalized to the confines of the originating element.
trackDocumentNormalize: false,
// Disables "click" event (prevents both "tap" and "click" firing on certain elements like <label>).
noClick: false,
// Distance from tap to register a drag (lower = more sensitive, higher = less sensitive).
dragThreshold: 10,
// Time to wait before registering a drag (needs to be high enough to not interfere with scrolling).
dragDelay: 200,
// Distance from tap to register a swipe (lower = more sensitive, higher = less sensitive).
swipeThreshold: 30,
// Delay between taps.
tapDelay: 250,
// Time to wait before triggering "tapAndHold".
tapAndHoldDelay: 500,
// If defined, delegates touch events to descendants matching this selector.
delegateSelector: null,
// Filters drop target elements. Can be any of the following:
// - "selector" Target element must match this selector.
// - function(element, target) { ... } Use boolean return value of a custom callback.
// - true Target element must be a sibling of dragged element.
// - false No filtering.
dropFilter: false,
// If true, traverses through parents for a match when dropFilter is a selector or function.
dropFilterTraversal: true,
// Coordinate point of reference (page, screen, client).
coordinates: 'page',
// Prevent or allow default actions for certain event classes. Can be any of the following:
// - true Prevent default actions for this event class.
// - false Allow default actions for this event class.
// - function(state) { ... } Use boolean return value of a custom callback (state = touch state object)
preventDefault: {
drag: false,
swipe: false,
tap: false
}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// touch Class
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Touch class. Keeps track of all touch event states.
*
* @param {jQuery} $element Target element.
* @param {jQuery} $sourceElement Source element.
* @param {object} settings Settings.
*/
function pec_touch($element, $sourceElement, settings) {
var t = this;
t.settings = settings;
// Properties.
t.$element = $element;
t.$sourceElement = $sourceElement;
t.inTap = false;
t.inTapAndHold = false;
t.inDrag = false;
t.tapStart = null;
t.dragStart = null;
t.timerTap = null;
t.timerTapAndHold = null;
t.mouseDown = false;
t.x = null;
t.y = null;
t.ex = null;
t.ey = null;
t.xStart = null;
t.yStart = null;
t.exStart = null;
t.eyStart = null;
t.taps = 0;
t.started = false;
t.ended = false;
}
/**
* Determines if the target element uses a particular class of gesture.
*
* @param {string} x Gesture class.
* @return {bool} If true, target element has at least one bound event for the specified gesture class. If false, it doesn't.
*/
pec_touch.prototype.uses = function(x) {
var events = $._data(this.$sourceElement[0], 'events');
switch (x) {
case 'swipe':
return (events.hasOwnProperty(x) || events.hasOwnProperty('swipeUp') || events.hasOwnProperty('swipeDown') || events.hasOwnProperty('swipeLeft') || events.hasOwnProperty('swipeRight'));
case 'drag':
return (events.hasOwnProperty(x) || events.hasOwnProperty('dragStart') || events.hasOwnProperty('dragEnd'));
case 'tapAndHold':
case 'doubleTap':
return events.hasOwnProperty(x);
case 'tap':
return (events.hasOwnProperty(x) || events.hasOwnProperty('doubleTap') || events.hasOwnProperty('tapAndHold'));
default:
break;
}
return false;
};
/**
* Cancels all touch events.
*
* @param {bool} mouseDown If true, also cancel events relying on mouseDown.
*/
pec_touch.prototype.cancel = function(mouseDown) {
var t = this;
t.taps = 0;
t.inTap = false;
t.inTapAndHold = false;
t.inDrag = false;
t.tapStart = null;
t.dragStart = null;
t.xStart = null;
t.yStart = null;
t.exStart = null;
t.eyStart = null;
if (mouseDown)
t.mouseDown = false;
};
/**
* Touch start handler.
*
* @param {object} event Original event.
* @param {integer} x X position.
* @param {integer} y Y position.
*/
pec_touch.prototype.doStart = function(event, x, y) {
var t = this,
offset = t.$element.offset();
// Prevent original event from bubbling.
event.stopPropagation();
// Prevent default if the element has a swipe or drag event (and the user has "preventDefault" turned on).
if ((t.uses('drag') && (t.settings.preventDefault.drag)(t))
|| (t.uses('swipe') && (t.settings.preventDefault.swipe)(t))
|| (t.uses('tap') && (t.settings.preventDefault.tap)(t)))
event.preventDefault();
// Hack: Clear touch callout/user select stuff on Webkit if the element has a tapAndHold event.
if (t.uses('tapAndHold'))
t.$element
.css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)')
.css('-webkit-touch-callout', 'none')
.css('-webkit-user-select', 'none');
// Set x, y, ex, ey.
t.x = x;
t.y = y;
t.ex = x - offset.left;
t.ey = y - offset.top;
// Set timestamp.
t.tapStart = Date.now();
// Set timers.
// tap.
// Stop tap timer.
clearTimeout(t.timerTap);
// Set new tap timer.
t.timerTap = setTimeout(function() {
// In a valid tap? Trigger "tap".
if (t.inTap && t.taps > 0) {
t.$element.trigger(
(t.taps == 2 ? 'doubleTap' : 'tap'),
{
'taps': t.taps,
'x': t.x,
'y': t.y,
'ex': t.ex,
'ey': t.ey,
'duration': Date.now() - t.tapStart,
'event': event
}
);
t.cancel();
}
// Clear tap timer.
t.timerTap = null;
}, t.settings.tapDelay);
// tapAndHold.
if (t.uses('tapAndHold')) {
// Stop tapAndHold timer.
clearTimeout(t.timerTapAndHold);
// Set new tapAndHold timer.
t.timerTapAndHold = setTimeout(function() {
// Use tapAndHold and in a valid tap? Trigger "tapAndHold".
if (t.inTap) {
t.$element.trigger(
'tapAndHold',
{
'x': t.x,
'y': t.y,
'ex': t.ex,
'ey': t.ey,
'duration': Date.now() - t.tapStart,
'event': event
}
);
t.cancel();
}
// Clear tapAndHold timer.
t.timerTapAndHold = null;
// We're now in a tap and hold.
t.inTapAndHold = true;
}, t.settings.tapAndHoldDelay);
}
// We're now in a tap.
t.inTap = true;
};
/**
* Touch move handler.
*
* @param {object} event Original event.
* @param {integer} x X position.
* @param {integer} y Y position.
*/
pec_touch.prototype.doMove = function(event, x, y) {
var t = this,
offset = t.$element.offset(),
diff = (Math.abs(t.x - x) + Math.abs(t.y - y)) / 2,
e, s;
// Prevent original event from bubbling.
event.stopPropagation();
// Prevent default if the element has a swipe or drag event (and the user has "preventDefault" turned on).
if ((t.uses('swipe') && (t.settings.preventDefault.swipe)(t))
|| (t.uses('drag') && (t.settings.preventDefault.drag)(t)))
event.preventDefault();
// Stop tapAndHold timer.
// Note: Only if cursor moves too much. Needed to compensate for hypersensitive touchscreens.
if (diff > 2)
clearTimeout(t.timerTapAndHold);
// In a drag? Trigger "drag".
if (t.inDrag
&& dragTarget == t) {
t.$element.trigger(
'drag',
{
'x': x,
'y': y,
'ex': x - offset.left,
'ey': y - offset.top,
'start': {
'x': t.xStart,
'y': t.yStart,
'ex': t.exStart,
'ey': t.eyStart
},
'event': event,
// Deprecated.
'exStart': t.exStart,
'eyStart': t.eyStart,
}
);
// Handle drop target events.
// Get element below the cursor.
// Temporarily turn off this element's pointer events.
t.$element.css('pointer-events', 'none');
// Get element below this one.
// Note: Offset by document scroll if this element is position: fixed.
if (t.$element.css('position') == 'fixed')
e = document.elementFromPoint(
x - $document.scrollLeft(),
y - $document.scrollTop()
);
else
e = document.elementFromPoint(
x,
y
);
// Turn this element's pointer events back on.
t.$element.css('pointer-events', '');
// Found a drop target?
if (e) {
// Drop filter set? Apply it.
if (t.settings.dropFilter !== false) {
s = typeof t.settings.dropFilter;
switch (s) {
// Selector.
case 'string':
// Drop filter traversal enabled? Go through parents until we find a match (or don't).
if (t.settings.dropFilterTraversal) {
while (e) {
// Found a match? Stop traversing.
if ($(e).is(t.settings.dropFilter))
break;
// Traverse up to parent.
e = e.parentElement;
}
}
// Otherwise, perform single match.
else if (!$(e).is(t.settings.dropFilter))
e = null;
break;
// Callback.
case 'function':
// Drop filter traversal enabled? Go through parents until we find a match (or don't).
if (t.settings.dropFilterTraversal) {
while (e) {
// Found a match? Stop traversing.
if ((t.settings.dropFilter)(t.$element[0], e) === true)
break;
// Traverse up to parent.
e = e.parentElement;
}
}
// Otherwise, perform single match.
else if ((t.settings.dropFilter)(t.$element[0], e) === false)
e = null;
break;
// Siblings only.
default:
case 'boolean':
if (t.settings.dropFilter === true) {
while (e.parentElement != t.$element[0].parentElement) {
e = e.parentElement;
if (!e) {
e = null;
break;
}
}
}
break;
}
}
// Make sure drop target isn't the element being dragged (because that would be weird).
if (e === t.$element[0])
e = null;
}
// Handle "leave".
// Triggered when we already have a drop target, but the cursor's no longer above it.
if (dropTargetElement
&& dropTargetElement !== e) {
// Trigger "dragLeave".
t.$element.trigger(
'dragLeave',
{
'element': dropTargetElement,
'event': event
}
);
// Clear drop target.
dropTargetElement = null;
}
// Handle "enter".
// Triggered when we don't have a drop target yet but we're above one.
if (!dropTargetElement
&& e) {
// Set drop target.
dropTargetElement = e;
// Trigger "dragEnter".
t.$element.trigger(
'dragEnter',
{
'element': dropTargetElement,
'event': event
}
);
}
// Handle "over".
// Triggered when we have a drop target.
if (dropTargetElement) {
// Get offset.
offset = $(dropTargetElement).offset();
// Trigger "dragOver".
t.$element.trigger(
'dragOver',
{
'element': dropTargetElement,
'event': event,
'x': x,
'y': y,
'ex': x - offset.left,
'ey': y - offset.top
}
);
}
}
// If we've moved past the drag threshold ...
else if (diff > t.settings.dragThreshold) {
// Enough time to start?
if (Date.now() - t.tapStart < t.settings.dragDelay) {
t.cancel();
return;
}
// Cancel everything.
t.cancel();
// We're now in a drag.
t.inDrag = true;
// Set timestamp.
t.dragStart = Date.now();
// Set starting element coordinates.
t.xStart = x;
t.yStart = y;
t.exStart = x - offset.left;
t.eyStart = y - offset.top;
// Prevent default if the element has a drag event.
if (t.uses('drag') && (t.settings.preventDefault.drag)(t))
event.preventDefault();
// Trigger "dragStart".
t.$element.trigger(
'dragStart',
{
'x': t.xStart,
'y': t.yStart,
'ex': t.exStart,
'ey': t.eyStart,
'event': event
}
);
// Set drag target.
dragTarget = t;
}
};
/**
* Touch end handler.
*
* @param {object} event Original event.
* @param {integer} x X position.
* @param {integer} y Y position.
*/
pec_touch.prototype.doEnd = function(event, x, y) {
var t = this,
offset = t.$element.offset(),
dx = Math.abs(t.x - x),
dy = Math.abs(t.y - y),
distance,
velocity,
duration;
// Prevent original event from bubbling.
event.stopPropagation();
// If we're in a tap ...
if (t.inTap) {
// Stop tapAndHold timer.
clearTimeout(t.timerTapAndHold);
// Increase the tap count.
t.taps++;
// Did we hit an end tap condition?
if (!t.timerTap // Timer ran out?
|| (t.taps == 1 && !t.uses('doubleTap')) // Got one tap (and the element doesn't have a doubleTap event)?
|| (t.taps == 2 && t.uses('doubleTap'))) { // Got two taps (and the element does have a doubleTap event)?
t.$element.trigger(
(t.taps == 2 ? 'doubleTap' : 'tap'),
{
'taps': t.taps,
'x': t.x,
'y': t.y,
'ex': t.ex,
'ey': t.ey,
'duration': Date.now() - t.tapStart,
'event': event
}
);
t.cancel();
}
}
// If we're in a drag ...
else if (t.inDrag) {
// Handle drop target events.
// Handle "drop".
// Triggered when we have a drop target.
if (dropTargetElement) {
// Get offset.
offset = $(dropTargetElement).offset();
// Trigger "drop".
t.$element.trigger(
'drop',
{
'element': dropTargetElement,
'event': event,
'x': x,
'y': y,
'ex': x - offset.left,
'ey': y - offset.top
}
);
// Clear drop target.
dropTargetElement = null;
}
// Calculate some stuff.
duration = Date.now() - t.dragStart;
distance = Math.sqrt(Math.pow(Math.abs(t.x - x), 2) + Math.pow(Math.abs(t.y - y), 2));
velocity = distance / duration;
// Trigger "dragEnd".
t.$element.trigger(
'dragEnd',
{
'start': {
'x': t.x,
'y': t.y,
'ex': t.ex,
'ey': t.ey
},
'end': {
'x': x,
'y': y,
'ex': x - offset.left,
'ey': y - offset.top
},
'distance': distance,
'duration': duration,
'velocity': velocity,
'event': event
}
);
// Clear drag target.
dragTarget = null;
// Swipe?
if (dx > t.settings.swipeThreshold
|| dy > t.settings.swipeThreshold) {
// Trigger "swipe".
t.$element.trigger(
'swipe',
{
'distance': distance,
'duration': duration,
'velocity': velocity,
'event': event
}
);
// Left/Right?
if (dx > dy)
{
// Calculate velocity.
velocity = dx / duration;
// Left? Trigger "swipeLeft".
if (x < t.x)
t.$element.trigger(
'swipeLeft',
{
'distance': dx,
'duration': duration,
'velocity': velocity,
'event': event
}
);
// Right? Trigger "swipeRight".
else
t.$element.trigger(
'swipeRight',
{
'distance': dx,
'duration': duration,
'velocity': velocity,
'event': event
}
);
}
// Up/Down?.
else if (dy > dx) {
// Calculate velocity.
velocity = dy / duration;
// Up? Trigger "swipeUp".
if (y < t.y)
t.$element.trigger(
'swipeUp',
{
'distance': dy,
'duration': duration,
'velocity': velocity,
'event': event
}
);
// Down? Trigger "swipeDown".
else
t.$element.trigger(
'swipeDown',
{
'distance': dy,
'duration': duration,
'velocity': velocity,
'event': event
}
);
}
}
// Cancel drag.
t.inDrag = false;
}
// If we're in a tap and hold ...
else if (t.inTapAndHold) {
// Stop tapAndHold timer.
clearTimeout(t.timerTapAndHold);
// Trigger "tapAndHoldEnd".
t.$element.trigger(
'tapAndHoldEnd',
{
'x': t.x,
'y': t.y,
'event': event
}
);
// Cancel tap and hold.
t.inTapAndHold = false;
}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// jQuery function
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enables touch events on a selector.
*
* @param {object} userSettings User settings.
*/
$.fn.pec_touch = function(userSettings) {
var $this = $(this);
// Multiple elements?
if (this.length > 1) {
for (var i=0; i < this.length; i++)
$.pec_touch($(this[i]), userSettings);
}
// Single element?
else if (this.length == 1)
$.pec_touch($this, userSettings);
return $this;
};
/**
* Alias for touch() function.
*
* @param {object} userSettings User settings.
*/
$.fn.enableTouch = function(userSettings) {
return $(this).pec_touch(userSettings);
};
/**
* Enables touch events on a jQuery element.
*
* @param {jQuery} $this Element.
* @param {object} userSettings User settings.
*/
$.pec_touch = function($this, userSettings) {
var settings = {};
// Build settings.
settings = $.extend(settings, defaultSettings);
settings = $.extend(settings, userSettings);
// Expand non-function preventDefault properties to functions.
if (typeof settings.preventDefault.drag != 'function')
settings.preventDefault.drag = (settings.preventDefault.drag === true ? function(t) { return true; } : function(t) { return false; });
if (typeof settings.preventDefault.swipe != 'function')
settings.preventDefault.swipe = (settings.preventDefault.swipe === true ? function(t) { return true; } : function(t) { return false; });
if (typeof settings.preventDefault.tap != 'function')
settings.preventDefault.tap = (settings.preventDefault.tap === true ? function(t) { return true; } : function(t) { return false; });
// Disable click event?
// Needed for some elements, otherwise "click" triggers in addition to "tap".
if (settings.noClick)
$this
.on('click', function(event) {
event.preventDefault();
});
// Bind touch events.
if (settings.useTouch) {
// Start (touchstart).
var onTouchStart = function(event) {
var $element = $(this),
touch = getTouch($element, $this, settings);
// Mark as started.
touch.started = true;
// Start.
touch.doStart(
event,
event.originalEvent.touches[0][settings.coordinates + 'X'],
event.originalEvent.touches[0][settings.coordinates + 'Y']
);
// Clear started after delay.
setTimeout(function() {
touch.started = false;
}, 1000);
};
// Bind event.
$this.on('touchstart', onTouchStart);
// Delegate?
if (settings.delegateSelector)
$this.on('touchstart', settings.delegateSelector, onTouchStart);
// Move (touchmove).
var onTouchMove = function(event) {
var $element = $(this),
touch = getTouch($element, $this, settings);
// Get coordinates.
var x = event.originalEvent.touches[0][settings.coordinates + 'X'],
y = event.originalEvent.touches[0][settings.coordinates + 'Y'];
// Normalize coordinates?
if (touch.settings.trackDocument
&& touch.settings.trackDocumentNormalize) {
var pos = fixPos(
touch,
x,
y
);
x = pos.x;
y = pos.y;
}
// Move.
touch.doMove(
event,
x,
y
);
};
// Bind event.
$this.on('touchmove', onTouchMove);
// Delegate?
if (settings.delegateSelector)
$this.on('touchmove', settings.delegateSelector, onTouchMove);
// End (touchend).
var onTouchEnd = function(event) {
var $element = $(this),
touch = getTouch($element, $this, settings);
// Mark as ended.
touch.ended = true;
// Get position.
var pos = fixPos(
touch,
event.originalEvent.changedTouches[0][settings.coordinates + 'X'],
event.originalEvent.changedTouches[0][settings.coordinates + 'Y']
);
// End.
touch.doEnd(
event,
pos.x,
pos.y
);
// Clear ended after delay.
setTimeout(function() {
touch.ended = false;
}, 1000);
};
// Bind event.
$this.on('touchend', onTouchEnd);
// Delegate?
if (settings.delegateSelector)
$this.on('touchend', settings.delegateSelector, onTouchEnd);
}
// Bind mouse events.
if (settings.useMouse) {
// Start (mousedown).
var onMouseDown = function(event) {
var $element = $(this),
touch = getTouch($element, $this, settings);
// If we've already been started (which would *only* happen if touchstart were just triggered),
// bail immediately so we don't attempt to double start.
if (touch.started)
return false;
// Mark mouse down.
touch.mouseDown = true;
// Start.
touch.doStart(
event,
event[settings.coordinates + 'X'],
event[settings.coordinates + 'Y']
);
};
// Bind event.
$this.on('mousedown', onMouseDown);
// Delegate?
if (settings.delegateSelector)
$this.on('mousedown', settings.delegateSelector, onMouseDown);
// Move (mousemove).
var onMouseMove = function(event) {
var $element = $(this),
touch = getTouch($element, $this, settings);
// If mouse down, move.
if (touch.mouseDown)
touch.doMove(
event,
event[settings.coordinates + 'X'],
event[settings.coordinates + 'Y']
);
};
// Bind event.
$this.on('mousemove', onMouseMove);
// Delegate?
if (settings.delegateSelector)
$this.on('mousemove', settings.delegateSelector, onMouseMove);
// End (mouseup).
var onMouseUp = function(event) {
var $element = $(this),
touch = getTouch($element, $this, settings);
// If we've already ended (which would *only* happen if touchend were just triggered),
// bail immediately so we don't attempt to double end.
if (touch.ended)
return false;
// Trigger document's mouseup handler (in case this event was fired on this element while dragging another).
$document.triggerHandler('mouseup', event);
// End.
touch.doEnd(
event,
event[settings.coordinates + 'X'],
event[settings.coordinates + 'Y']
);
// Clear mouse down.
touch.mouseDown = false;
};
// Bind event.
$this.on('mouseup', onMouseUp);
// Delegate?
if (settings.delegateSelector)
$this.on('mouseup', settings.delegateSelector, onMouseUp);
}
// No document tracking? Watch for "mouseleave".
if (!settings.trackDocument)
$this
.on('mouseleave', function(event) {
var $element = $(this),
touch = getTouch($element, $this, settings);
touch.doEnd(
event,
event[settings.coordinates + 'X'],
event[settings.coordinates + 'Y']
);
touch.mouseDown = false;
})
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Init.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets an element's touch property.
*
* @param {jQuery} $element Target element.
* @param {jQuery} $sourceElement Source element.
* @param {object} userSettings User settings.
*/
function getTouch($element, $sourceElement, userSettings) {
var element = $element[0];
// No touch property? Initialize it.
if (typeof element._touch == 'undefined')
element._touch = new pec_touch($element, $sourceElement, userSettings);
return element._touch;
};
/**
* Adjusts a pair of coordinates to ensure they're within the boundaries of a given touch object's element.
*
* @param t {object} Touch object.
* @param x {integer} X value.
* @param y {integer} y value.
* @return {object} New coordinates.
*/
function fixPos(t, x, y) {
var offset, width, height, nx, ny;
// Get element's offset and dimenions.
offset = t.$element.offset(),
width = t.$element.width(),
height = t.$element.height();
// Normalize x and y.
nx = Math.min(Math.max(x, offset.left), offset.left + width);
ny = Math.min(Math.max(y, offset.top), offset.top + height);
// Return new coordinates.
return {
x: nx,
y: ny
};
};
// Documnet-level events (mouse only).
// These are used to trigger drag events on an element even if the mouse cursor is beyond its boundaries.
$document
.on('mousemove', function(event) {
var t = dragTarget;
if (t
&& t.settings.useMouse
&& t.mouseDown
&& t.settings.trackDocument) {
// Get coordinates.
var x = event[t.settings.coordinates + 'X'],
y = event[t.settings.coordinates + 'Y'];
// Normalize coordinates?
if (t.settings.trackDocumentNormalize) {
var pos = fixPos(
t,
x,
y
);
x = pos.x;
y = pos.y;
}
// Trigger "move".
t.doMove(
event,
x,
y
);
}
})
.on('mouseup', function(event, previousEvent) {
var t = dragTarget;
if (t
&& t.settings.useMouse
&& t.settings.trackDocument) {
// Previous event provided? Use that instead.
if (typeof previousEvent !== 'undefined')
event = previousEvent;
// No X coordinate in event? "mouseup" likely already handled by originating element, so bail.
if (!((t.settings.coordinates + 'X') in event))
return;
// Get coordinates.
var x = event[t.settings.coordinates + 'X'],
y = event[t.settings.coordinates + 'Y'];
// Normalize coordinates?
if (t.settings.trackDocumentNormalize) {
var pos = fixPos(
t,
x,
y
);
x = pos.x;
y = pos.y;
}
// Trigger "end".
t.doEnd(
event,
x,
y
);
// Clear mouseDown state.
t.mouseDown = false;
}
});
})(jQuery);