mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-03 01:39:24 +02:00
289 lines
7.8 KiB
JavaScript
289 lines
7.8 KiB
JavaScript
/*!
|
|
* Unidragger v3.0.1
|
|
* Draggable base class
|
|
* MIT license
|
|
*/
|
|
|
|
( function( window, factory ) {
|
|
// universal module definition
|
|
if ( typeof module == 'object' && module.exports ) {
|
|
// CommonJS
|
|
module.exports = factory(
|
|
window,
|
|
require('ev-emitter'),
|
|
);
|
|
} else {
|
|
// browser global
|
|
window.Unidragger = factory(
|
|
window,
|
|
window.EvEmitter,
|
|
);
|
|
}
|
|
|
|
}( typeof window != 'undefined' ? window : this, function factory( window, EvEmitter ) {
|
|
|
|
function Unidragger() {}
|
|
|
|
// inherit EvEmitter
|
|
let proto = Unidragger.prototype = Object.create( EvEmitter.prototype );
|
|
|
|
// ----- bind start ----- //
|
|
|
|
// trigger handler methods for events
|
|
proto.handleEvent = function( event ) {
|
|
let method = 'on' + event.type;
|
|
if ( this[ method ] ) {
|
|
this[ method ]( event );
|
|
}
|
|
};
|
|
|
|
let startEvent, activeEvents;
|
|
if ( 'ontouchstart' in window ) {
|
|
// HACK prefer Touch Events as you can preventDefault on touchstart to
|
|
// disable scroll in iOS & mobile Chrome metafizzy/flickity#1177
|
|
startEvent = 'touchstart';
|
|
activeEvents = [ 'touchmove', 'touchend', 'touchcancel' ];
|
|
} else if ( window.PointerEvent ) {
|
|
// Pointer Events
|
|
startEvent = 'pointerdown';
|
|
activeEvents = [ 'pointermove', 'pointerup', 'pointercancel' ];
|
|
} else {
|
|
// mouse events
|
|
startEvent = 'mousedown';
|
|
activeEvents = [ 'mousemove', 'mouseup' ];
|
|
}
|
|
|
|
// prototype so it can be overwriteable by Flickity
|
|
proto.touchActionValue = 'none';
|
|
|
|
proto.bindHandles = function() {
|
|
this._bindHandles( 'addEventListener', this.touchActionValue );
|
|
};
|
|
|
|
proto.unbindHandles = function() {
|
|
this._bindHandles( 'removeEventListener', '' );
|
|
};
|
|
|
|
/**
|
|
* Add or remove start event
|
|
* @param {String} bindMethod - addEventListener or removeEventListener
|
|
* @param {String} touchAction - value for touch-action CSS property
|
|
*/
|
|
proto._bindHandles = function( bindMethod, touchAction ) {
|
|
this.handles.forEach( ( handle ) => {
|
|
handle[ bindMethod ]( startEvent, this );
|
|
handle[ bindMethod ]( 'click', this );
|
|
// touch-action: none to override browser touch gestures. metafizzy/flickity#540
|
|
if ( window.PointerEvent ) handle.style.touchAction = touchAction;
|
|
} );
|
|
};
|
|
|
|
proto.bindActivePointerEvents = function() {
|
|
activeEvents.forEach( ( eventName ) => {
|
|
window.addEventListener( eventName, this );
|
|
} );
|
|
};
|
|
|
|
proto.unbindActivePointerEvents = function() {
|
|
activeEvents.forEach( ( eventName ) => {
|
|
window.removeEventListener( eventName, this );
|
|
} );
|
|
};
|
|
|
|
// ----- event handler helpers ----- //
|
|
|
|
// trigger method with matching pointer
|
|
proto.withPointer = function( methodName, event ) {
|
|
if ( event.pointerId === this.pointerIdentifier ) {
|
|
this[ methodName ]( event, event );
|
|
}
|
|
};
|
|
|
|
// trigger method with matching touch
|
|
proto.withTouch = function( methodName, event ) {
|
|
let touch;
|
|
for ( let changedTouch of event.changedTouches ) {
|
|
if ( changedTouch.identifier === this.pointerIdentifier ) {
|
|
touch = changedTouch;
|
|
}
|
|
}
|
|
if ( touch ) this[ methodName ]( event, touch );
|
|
};
|
|
|
|
// ----- start event ----- //
|
|
|
|
proto.onmousedown = function( event ) {
|
|
this.pointerDown( event, event );
|
|
};
|
|
|
|
proto.ontouchstart = function( event ) {
|
|
this.pointerDown( event, event.changedTouches[0] );
|
|
};
|
|
|
|
proto.onpointerdown = function( event ) {
|
|
this.pointerDown( event, event );
|
|
};
|
|
|
|
// nodes that have text fields
|
|
const cursorNodes = [ 'TEXTAREA', 'INPUT', 'SELECT', 'OPTION' ];
|
|
// input types that do not have text fields
|
|
const clickTypes = [ 'radio', 'checkbox', 'button', 'submit', 'image', 'file' ];
|
|
|
|
/**
|
|
* any time you set `event, pointer` it refers to:
|
|
* @param {Event} event
|
|
* @param {Event | Touch} pointer
|
|
*/
|
|
proto.pointerDown = function( event, pointer ) {
|
|
// dismiss multi-touch taps, right clicks, and clicks on text fields
|
|
let isCursorNode = cursorNodes.includes( event.target.nodeName );
|
|
let isClickType = clickTypes.includes( event.target.type );
|
|
let isOkayElement = !isCursorNode || isClickType;
|
|
let isOkay = !this.isPointerDown && !event.button && isOkayElement;
|
|
if ( !isOkay ) return;
|
|
|
|
this.isPointerDown = true;
|
|
// save pointer identifier to match up touch events
|
|
this.pointerIdentifier = pointer.pointerId !== undefined ?
|
|
// pointerId for pointer events, touch.indentifier for touch events
|
|
pointer.pointerId : pointer.identifier;
|
|
// track position for move
|
|
this.pointerDownPointer = {
|
|
pageX: pointer.pageX,
|
|
pageY: pointer.pageY,
|
|
};
|
|
|
|
this.bindActivePointerEvents();
|
|
this.emitEvent( 'pointerDown', [ event, pointer ] );
|
|
};
|
|
|
|
// ----- move ----- //
|
|
|
|
proto.onmousemove = function( event ) {
|
|
this.pointerMove( event, event );
|
|
};
|
|
|
|
proto.onpointermove = function( event ) {
|
|
this.withPointer( 'pointerMove', event );
|
|
};
|
|
|
|
proto.ontouchmove = function( event ) {
|
|
this.withTouch( 'pointerMove', event );
|
|
};
|
|
|
|
proto.pointerMove = function( event, pointer ) {
|
|
let moveVector = {
|
|
x: pointer.pageX - this.pointerDownPointer.pageX,
|
|
y: pointer.pageY - this.pointerDownPointer.pageY,
|
|
};
|
|
this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );
|
|
// start drag if pointer has moved far enough to start drag
|
|
let isDragStarting = !this.isDragging && this.hasDragStarted( moveVector );
|
|
if ( isDragStarting ) this.dragStart( event, pointer );
|
|
if ( this.isDragging ) this.dragMove( event, pointer, moveVector );
|
|
};
|
|
|
|
// condition if pointer has moved far enough to start drag
|
|
proto.hasDragStarted = function( moveVector ) {
|
|
return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;
|
|
};
|
|
|
|
// ----- drag ----- //
|
|
|
|
proto.dragStart = function( event, pointer ) {
|
|
this.isDragging = true;
|
|
this.isPreventingClicks = true; // set flag to prevent clicks
|
|
this.emitEvent( 'dragStart', [ event, pointer ] );
|
|
};
|
|
|
|
proto.dragMove = function( event, pointer, moveVector ) {
|
|
this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );
|
|
};
|
|
|
|
// ----- end ----- //
|
|
|
|
proto.onmouseup = function( event ) {
|
|
this.pointerUp( event, event );
|
|
};
|
|
|
|
proto.onpointerup = function( event ) {
|
|
this.withPointer( 'pointerUp', event );
|
|
};
|
|
|
|
proto.ontouchend = function( event ) {
|
|
this.withTouch( 'pointerUp', event );
|
|
};
|
|
|
|
proto.pointerUp = function( event, pointer ) {
|
|
this.pointerDone();
|
|
this.emitEvent( 'pointerUp', [ event, pointer ] );
|
|
|
|
if ( this.isDragging ) {
|
|
this.dragEnd( event, pointer );
|
|
} else {
|
|
// pointer didn't move enough for drag to start
|
|
this.staticClick( event, pointer );
|
|
}
|
|
};
|
|
|
|
proto.dragEnd = function( event, pointer ) {
|
|
this.isDragging = false; // reset flag
|
|
// re-enable clicking async
|
|
setTimeout( () => delete this.isPreventingClicks );
|
|
|
|
this.emitEvent( 'dragEnd', [ event, pointer ] );
|
|
};
|
|
|
|
// triggered on pointer up & pointer cancel
|
|
proto.pointerDone = function() {
|
|
this.isPointerDown = false;
|
|
delete this.pointerIdentifier;
|
|
this.unbindActivePointerEvents();
|
|
this.emitEvent('pointerDone');
|
|
};
|
|
|
|
// ----- cancel ----- //
|
|
|
|
proto.onpointercancel = function( event ) {
|
|
this.withPointer( 'pointerCancel', event );
|
|
};
|
|
|
|
proto.ontouchcancel = function( event ) {
|
|
this.withTouch( 'pointerCancel', event );
|
|
};
|
|
|
|
proto.pointerCancel = function( event, pointer ) {
|
|
this.pointerDone();
|
|
this.emitEvent( 'pointerCancel', [ event, pointer ] );
|
|
};
|
|
|
|
// ----- click ----- //
|
|
|
|
// handle all clicks and prevent clicks when dragging
|
|
proto.onclick = function( event ) {
|
|
if ( this.isPreventingClicks ) event.preventDefault();
|
|
};
|
|
|
|
// triggered after pointer down & up with no/tiny movement
|
|
proto.staticClick = function( event, pointer ) {
|
|
// ignore emulated mouse up clicks
|
|
let isMouseup = event.type === 'mouseup';
|
|
if ( isMouseup && this.isIgnoringMouseUp ) return;
|
|
|
|
this.emitEvent( 'staticClick', [ event, pointer ] );
|
|
|
|
// set flag for emulated clicks 300ms after touchend
|
|
if ( isMouseup ) {
|
|
this.isIgnoringMouseUp = true;
|
|
// reset flag after 400ms
|
|
setTimeout( () => {
|
|
delete this.isIgnoringMouseUp;
|
|
}, 400 );
|
|
}
|
|
};
|
|
|
|
// ----- ----- //
|
|
|
|
return Unidragger;
|
|
|
|
} ) );
|