From dce0897d9f427f70de8ebf0d56bf998aaa022900 Mon Sep 17 00:00:00 2001 From: Priyansh Date: Fri, 13 Nov 2020 22:38:25 +0530 Subject: Added Draggabilty by desandroo --- index.html | 1 + js/draggability.js | 1522 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1523 insertions(+) create mode 100644 js/draggability.js diff --git a/index.html b/index.html index 6eedf37..e8a3c4c 100644 --- a/index.html +++ b/index.html @@ -117,6 +117,7 @@ + diff --git a/js/draggability.js b/js/draggability.js new file mode 100644 index 0000000..629739d --- /dev/null +++ b/js/draggability.js @@ -0,0 +1,1522 @@ +/*! + * Draggabilly PACKAGED v2.3.0 + * Make that shiz draggable + * https://draggabilly.desandro.com + * MIT license + */ + +/** + * Bridget makes jQuery widgets + * v2.0.1 + * MIT license + */ + +/* jshint browser: true, strict: true, undef: true, unused: true */ + +( function( window, factory ) { + // universal module definition + /*jshint strict: false */ /* globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) { + return factory( window, jQuery ); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('jquery') + ); + } else { + // browser global + window.jQueryBridget = factory( + window, + window.jQuery + ); + } + + }( window, function factory( window, jQuery ) { + 'use strict'; + + // ----- utils ----- // + + var arraySlice = Array.prototype.slice; + + // helper function for logging errors + // $.error breaks jQuery chaining + var console = window.console; + var logError = typeof console == 'undefined' ? function() {} : + function( message ) { + console.error( message ); + }; + + // ----- jQueryBridget ----- // + + function jQueryBridget( namespace, PluginClass, $ ) { + $ = $ || jQuery || window.jQuery; + if ( !$ ) { + return; + } + + // add option method -> $().plugin('option', {...}) + if ( !PluginClass.prototype.option ) { + // option setter + PluginClass.prototype.option = function( opts ) { + // bail out if not an object + if ( !$.isPlainObject( opts ) ){ + return; + } + this.options = $.extend( true, this.options, opts ); + }; + } + + // make jQuery plugin + $.fn[ namespace ] = function( arg0 /*, arg1 */ ) { + if ( typeof arg0 == 'string' ) { + // method call $().plugin( 'methodName', { options } ) + // shift arguments by 1 + var args = arraySlice.call( arguments, 1 ); + return methodCall( this, arg0, args ); + } + // just $().plugin({ options }) + plainCall( this, arg0 ); + return this; + }; + + // $().plugin('methodName') + function methodCall( $elems, methodName, args ) { + var returnValue; + var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; + + $elems.each( function( i, elem ) { + // get instance + var instance = $.data( elem, namespace ); + if ( !instance ) { + logError( namespace + ' not initialized. Cannot call methods, i.e. ' + + pluginMethodStr ); + return; + } + + var method = instance[ methodName ]; + if ( !method || methodName.charAt(0) == '_' ) { + logError( pluginMethodStr + ' is not a valid method' ); + return; + } + + // apply method, get return value + var value = method.apply( instance, args ); + // set return value if value is returned, use only first value + returnValue = returnValue === undefined ? value : returnValue; + }); + + return returnValue !== undefined ? returnValue : $elems; + } + + function plainCall( $elems, options ) { + $elems.each( function( i, elem ) { + var instance = $.data( elem, namespace ); + if ( instance ) { + // set options & init + instance.option( options ); + instance._init(); + } else { + // initialize new instance + instance = new PluginClass( elem, options ); + $.data( elem, namespace, instance ); + } + }); + } + + updateJQuery( $ ); + + } + + // ----- updateJQuery ----- // + + // set $.bridget for v1 backwards compatibility + function updateJQuery( $ ) { + if ( !$ || ( $ && $.bridget ) ) { + return; + } + $.bridget = jQueryBridget; + } + + updateJQuery( jQuery || window.jQuery ); + + // ----- ----- // + + return jQueryBridget; + + })); + + /*! + * getSize v2.0.2 + * measure size of elements + * MIT license + */ + + /*jshint browser: true, strict: true, undef: true, unused: true */ + /*global define: false, module: false, console: false */ + + ( function( window, factory ) { + 'use strict'; + + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'get-size/get-size',[],function() { + return factory(); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory(); + } else { + // browser global + window.getSize = factory(); + } + + })( window, function factory() { + 'use strict'; + + // -------------------------- helpers -------------------------- // + + // get a number from a string, not a percentage + function getStyleSize( value ) { + var num = parseFloat( value ); + // not a percent like '100%', and a number + var isValid = value.indexOf('%') == -1 && !isNaN( num ); + return isValid && num; + } + + function noop() {} + + var logError = typeof console == 'undefined' ? noop : + function( message ) { + console.error( message ); + }; + + // -------------------------- measurements -------------------------- // + + var measurements = [ + 'paddingLeft', + 'paddingRight', + 'paddingTop', + 'paddingBottom', + 'marginLeft', + 'marginRight', + 'marginTop', + 'marginBottom', + 'borderLeftWidth', + 'borderRightWidth', + 'borderTopWidth', + 'borderBottomWidth' + ]; + + var measurementsLength = measurements.length; + + function getZeroSize() { + var size = { + width: 0, + height: 0, + innerWidth: 0, + innerHeight: 0, + outerWidth: 0, + outerHeight: 0 + }; + for ( var i=0; i < measurementsLength; i++ ) { + var measurement = measurements[i]; + size[ measurement ] = 0; + } + return size; + } + + // -------------------------- getStyle -------------------------- // + + /** + * getStyle, get style of element, check for Firefox bug + * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + */ + function getStyle( elem ) { + var style = getComputedStyle( elem ); + if ( !style ) { + logError( 'Style returned ' + style + + '. Are you running this code in a hidden iframe on Firefox? ' + + 'See http://bit.ly/getsizebug1' ); + } + return style; + } + + // -------------------------- setup -------------------------- // + + var isSetup = false; + + var isBoxSizeOuter; + + /** + * setup + * check isBoxSizerOuter + * do on first getSize() rather than on page load for Firefox bug + */ + function setup() { + // setup once + if ( isSetup ) { + return; + } + isSetup = true; + + // -------------------------- box sizing -------------------------- // + + /** + * WebKit measures the outer-width on style.width on border-box elems + * IE & Firefox<29 measures the inner-width + */ + var div = document.createElement('div'); + div.style.width = '200px'; + div.style.padding = '1px 2px 3px 4px'; + div.style.borderStyle = 'solid'; + div.style.borderWidth = '1px 2px 3px 4px'; + div.style.boxSizing = 'border-box'; + + var body = document.body || document.documentElement; + body.appendChild( div ); + var style = getStyle( div ); + + getSize.isBoxSizeOuter = isBoxSizeOuter = getStyleSize( style.width ) == 200; + body.removeChild( div ); + + } + + // -------------------------- getSize -------------------------- // + + function getSize( elem ) { + setup(); + + // use querySeletor if elem is string + if ( typeof elem == 'string' ) { + elem = document.querySelector( elem ); + } + + // do not proceed on non-objects + if ( !elem || typeof elem != 'object' || !elem.nodeType ) { + return; + } + + var style = getStyle( elem ); + + // if hidden, everything is 0 + if ( style.display == 'none' ) { + return getZeroSize(); + } + + var size = {}; + size.width = elem.offsetWidth; + size.height = elem.offsetHeight; + + var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; + + // get all measurements + for ( var i=0; i < measurementsLength; i++ ) { + var measurement = measurements[i]; + var value = style[ measurement ]; + var num = parseFloat( value ); + // any 'auto', 'medium' value will be 0 + size[ measurement ] = !isNaN( num ) ? num : 0; + } + + var paddingWidth = size.paddingLeft + size.paddingRight; + var paddingHeight = size.paddingTop + size.paddingBottom; + var marginWidth = size.marginLeft + size.marginRight; + var marginHeight = size.marginTop + size.marginBottom; + var borderWidth = size.borderLeftWidth + size.borderRightWidth; + var borderHeight = size.borderTopWidth + size.borderBottomWidth; + + var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; + + // overwrite width and height if we can get it from style + var styleWidth = getStyleSize( style.width ); + if ( styleWidth !== false ) { + size.width = styleWidth + + // add padding and border unless it's already including it + ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); + } + + var styleHeight = getStyleSize( style.height ); + if ( styleHeight !== false ) { + size.height = styleHeight + + // add padding and border unless it's already including it + ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); + } + + size.innerWidth = size.width - ( paddingWidth + borderWidth ); + size.innerHeight = size.height - ( paddingHeight + borderHeight ); + + size.outerWidth = size.width + marginWidth; + size.outerHeight = size.height + marginHeight; + + return size; + } + + return getSize; + + }); + + /** + * EvEmitter v1.1.0 + * Lil' event emitter + * MIT License + */ + + /* jshint unused: true, undef: true, strict: true */ + + ( function( global, factory ) { + // universal module definition + /* jshint strict: false */ /* globals define, module, window */ + if ( typeof define == 'function' && define.amd ) { + // AMD - RequireJS + define( 'ev-emitter/ev-emitter',factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS - Browserify, Webpack + module.exports = factory(); + } else { + // Browser globals + global.EvEmitter = factory(); + } + + }( typeof window != 'undefined' ? window : this, function() { + + + + function EvEmitter() {} + + var proto = EvEmitter.prototype; + + proto.on = function( eventName, listener ) { + if ( !eventName || !listener ) { + return; + } + // set events hash + var events = this._events = this._events || {}; + // set listeners array + var listeners = events[ eventName ] = events[ eventName ] || []; + // only add once + if ( listeners.indexOf( listener ) == -1 ) { + listeners.push( listener ); + } + + return this; + }; + + proto.once = function( eventName, listener ) { + if ( !eventName || !listener ) { + return; + } + // add event + this.on( eventName, listener ); + // set once flag + // set onceEvents hash + var onceEvents = this._onceEvents = this._onceEvents || {}; + // set onceListeners object + var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; + // set flag + onceListeners[ listener ] = true; + + return this; + }; + + proto.off = function( eventName, listener ) { + var listeners = this._events && this._events[ eventName ]; + if ( !listeners || !listeners.length ) { + return; + } + var index = listeners.indexOf( listener ); + if ( index != -1 ) { + listeners.splice( index, 1 ); + } + + return this; + }; + + proto.emitEvent = function( eventName, args ) { + var listeners = this._events && this._events[ eventName ]; + if ( !listeners || !listeners.length ) { + return; + } + // copy over to avoid interference if .off() in listener + listeners = listeners.slice(0); + args = args || []; + // once stuff + var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; + + for ( var i=0; i < listeners.length; i++ ) { + var listener = listeners[i] + var isOnce = onceListeners && onceListeners[ listener ]; + if ( isOnce ) { + // remove listener + // remove before trigger to prevent recursion + this.off( eventName, listener ); + // unset once flag + delete onceListeners[ listener ]; + } + // trigger listener + listener.apply( this, args ); + } + + return this; + }; + + proto.allOff = function() { + delete this._events; + delete this._onceEvents; + }; + + return EvEmitter; + + })); + + /*! + * Unipointer v2.3.0 + * base class for doing one thing with pointer event + * MIT license + */ + + /*jshint browser: true, undef: true, unused: true, strict: true */ + + ( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*global define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'unipointer/unipointer',[ + 'ev-emitter/ev-emitter' + ], function( EvEmitter ) { + return factory( window, EvEmitter ); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('ev-emitter') + ); + } else { + // browser global + window.Unipointer = factory( + window, + window.EvEmitter + ); + } + + }( window, function factory( window, EvEmitter ) { + + + + function noop() {} + + function Unipointer() {} + + // inherit EvEmitter + var proto = Unipointer.prototype = Object.create( EvEmitter.prototype ); + + proto.bindStartEvent = function( elem ) { + this._bindStartEvent( elem, true ); + }; + + proto.unbindStartEvent = function( elem ) { + this._bindStartEvent( elem, false ); + }; + + /** + * Add or remove start event + * @param {Boolean} isAdd - remove if falsey + */ + proto._bindStartEvent = function( elem, isAdd ) { + // munge isAdd, default to true + isAdd = isAdd === undefined ? true : isAdd; + var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener'; + + // default to mouse events + var startEvent = 'mousedown'; + if ( window.PointerEvent ) { + // Pointer Events + startEvent = 'pointerdown'; + } else if ( 'ontouchstart' in window ) { + // Touch Events. iOS Safari + startEvent = 'touchstart'; + } + elem[ bindMethod ]( startEvent, this ); + }; + + // trigger handler methods for events + proto.handleEvent = function( event ) { + var method = 'on' + event.type; + if ( this[ method ] ) { + this[ method ]( event ); + } + }; + + // returns the touch that we're keeping track of + proto.getTouch = function( touches ) { + for ( var i=0; i < touches.length; i++ ) { + var touch = touches[i]; + if ( touch.identifier == this.pointerIdentifier ) { + return touch; + } + } + }; + + // ----- start event ----- // + + proto.onmousedown = function( event ) { + // dismiss clicks from right or middle buttons + var button = event.button; + if ( button && ( button !== 0 && button !== 1 ) ) { + return; + } + this._pointerDown( event, event ); + }; + + proto.ontouchstart = function( event ) { + this._pointerDown( event, event.changedTouches[0] ); + }; + + proto.onpointerdown = function( event ) { + this._pointerDown( event, event ); + }; + + /** + * pointer start + * @param {Event} event + * @param {Event or Touch} pointer + */ + proto._pointerDown = function( event, pointer ) { + // dismiss right click and other pointers + // button = 0 is okay, 1-4 not + if ( event.button || this.isPointerDown ) { + 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; + + this.pointerDown( event, pointer ); + }; + + proto.pointerDown = function( event, pointer ) { + this._bindPostStartEvents( event ); + this.emitEvent( 'pointerDown', [ event, pointer ] ); + }; + + // hash of events to be bound after start event + var postStartEvents = { + mousedown: [ 'mousemove', 'mouseup' ], + touchstart: [ 'touchmove', 'touchend', 'touchcancel' ], + pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ], + }; + + proto._bindPostStartEvents = function( event ) { + if ( !event ) { + return; + } + // get proper events to match start event + var events = postStartEvents[ event.type ]; + // bind events to node + events.forEach( function( eventName ) { + window.addEventListener( eventName, this ); + }, this ); + // save these arguments + this._boundPointerEvents = events; + }; + + proto._unbindPostStartEvents = function() { + // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug) + if ( !this._boundPointerEvents ) { + return; + } + this._boundPointerEvents.forEach( function( eventName ) { + window.removeEventListener( eventName, this ); + }, this ); + + delete this._boundPointerEvents; + }; + + // ----- move event ----- // + + proto.onmousemove = function( event ) { + this._pointerMove( event, event ); + }; + + proto.onpointermove = function( event ) { + if ( event.pointerId == this.pointerIdentifier ) { + this._pointerMove( event, event ); + } + }; + + proto.ontouchmove = function( event ) { + var touch = this.getTouch( event.changedTouches ); + if ( touch ) { + this._pointerMove( event, touch ); + } + }; + + /** + * pointer move + * @param {Event} event + * @param {Event or Touch} pointer + * @private + */ + proto._pointerMove = function( event, pointer ) { + this.pointerMove( event, pointer ); + }; + + // public + proto.pointerMove = function( event, pointer ) { + this.emitEvent( 'pointerMove', [ event, pointer ] ); + }; + + // ----- end event ----- // + + + proto.onmouseup = function( event ) { + this._pointerUp( event, event ); + }; + + proto.onpointerup = function( event ) { + if ( event.pointerId == this.pointerIdentifier ) { + this._pointerUp( event, event ); + } + }; + + proto.ontouchend = function( event ) { + var touch = this.getTouch( event.changedTouches ); + if ( touch ) { + this._pointerUp( event, touch ); + } + }; + + /** + * pointer up + * @param {Event} event + * @param {Event or Touch} pointer + * @private + */ + proto._pointerUp = function( event, pointer ) { + this._pointerDone(); + this.pointerUp( event, pointer ); + }; + + // public + proto.pointerUp = function( event, pointer ) { + this.emitEvent( 'pointerUp', [ event, pointer ] ); + }; + + // ----- pointer done ----- // + + // triggered on pointer up & pointer cancel + proto._pointerDone = function() { + this._pointerReset(); + this._unbindPostStartEvents(); + this.pointerDone(); + }; + + proto._pointerReset = function() { + // reset properties + this.isPointerDown = false; + delete this.pointerIdentifier; + }; + + proto.pointerDone = noop; + + // ----- pointer cancel ----- // + + proto.onpointercancel = function( event ) { + if ( event.pointerId == this.pointerIdentifier ) { + this._pointerCancel( event, event ); + } + }; + + proto.ontouchcancel = function( event ) { + var touch = this.getTouch( event.changedTouches ); + if ( touch ) { + this._pointerCancel( event, touch ); + } + }; + + /** + * pointer cancel + * @param {Event} event + * @param {Event or Touch} pointer + * @private + */ + proto._pointerCancel = function( event, pointer ) { + this._pointerDone(); + this.pointerCancel( event, pointer ); + }; + + // public + proto.pointerCancel = function( event, pointer ) { + this.emitEvent( 'pointerCancel', [ event, pointer ] ); + }; + + // ----- ----- // + + // utility function for getting x/y coords from event + Unipointer.getPointerPoint = function( pointer ) { + return { + x: pointer.pageX, + y: pointer.pageY + }; + }; + + // ----- ----- // + + return Unipointer; + + })); + + /*! + * Unidragger v2.3.0 + * Draggable base class + * MIT license + */ + + /*jshint browser: true, unused: true, undef: true, strict: true */ + + ( function( window, factory ) { + // universal module definition + /*jshint strict: false */ /*globals define, module, require */ + + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'unidragger/unidragger',[ + 'unipointer/unipointer' + ], function( Unipointer ) { + return factory( window, Unipointer ); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('unipointer') + ); + } else { + // browser global + window.Unidragger = factory( + window, + window.Unipointer + ); + } + + }( window, function factory( window, Unipointer ) { + + + + // -------------------------- Unidragger -------------------------- // + + function Unidragger() {} + + // inherit Unipointer & EvEmitter + var proto = Unidragger.prototype = Object.create( Unipointer.prototype ); + + // ----- bind start ----- // + + proto.bindHandles = function() { + this._bindHandles( true ); + }; + + proto.unbindHandles = function() { + this._bindHandles( false ); + }; + + /** + * Add or remove start event + * @param {Boolean} isAdd + */ + proto._bindHandles = function( isAdd ) { + // munge isAdd, default to true + isAdd = isAdd === undefined ? true : isAdd; + // bind each handle + var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener'; + var touchAction = isAdd ? this._touchActionValue : ''; + for ( var i=0; i < this.handles.length; i++ ) { + var handle = this.handles[i]; + this._bindStartEvent( handle, isAdd ); + handle[ bindMethod ]( 'click', this ); + // touch-action: none to override browser touch gestures. metafizzy/flickity#540 + if ( window.PointerEvent ) { + handle.style.touchAction = touchAction; + } + } + }; + + // prototype so it can be overwriteable by Flickity + proto._touchActionValue = 'none'; + + // ----- start event ----- // + + /** + * pointer start + * @param {Event} event + * @param {Event or Touch} pointer + */ + proto.pointerDown = function( event, pointer ) { + var isOkay = this.okayPointerDown( event ); + if ( !isOkay ) { + return; + } + // track start event position + this.pointerDownPointer = pointer; + + event.preventDefault(); + this.pointerDownBlur(); + // bind move and end events + this._bindPostStartEvents( event ); + this.emitEvent( 'pointerDown', [ event, pointer ] ); + }; + + // nodes that have text fields + var cursorNodes = { + TEXTAREA: true, + INPUT: true, + SELECT: true, + OPTION: true, + }; + + // input types that do not have text fields + var clickTypes = { + radio: true, + checkbox: true, + button: true, + submit: true, + image: true, + file: true, + }; + + // dismiss inputs with text fields. flickity#403, flickity#404 + proto.okayPointerDown = function( event ) { + var isCursorNode = cursorNodes[ event.target.nodeName ]; + var isClickType = clickTypes[ event.target.type ]; + var isOkay = !isCursorNode || isClickType; + if ( !isOkay ) { + this._pointerReset(); + } + return isOkay; + }; + + // kludge to blur previously focused input + proto.pointerDownBlur = function() { + var focused = document.activeElement; + // do not blur body for IE10, metafizzy/flickity#117 + var canBlur = focused && focused.blur && focused != document.body; + if ( canBlur ) { + focused.blur(); + } + }; + + // ----- move event ----- // + + /** + * drag move + * @param {Event} event + * @param {Event or Touch} pointer + */ + proto.pointerMove = function( event, pointer ) { + var moveVector = this._dragPointerMove( event, pointer ); + this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] ); + this._dragMove( event, pointer, moveVector ); + }; + + // base pointer move logic + proto._dragPointerMove = function( event, pointer ) { + var moveVector = { + x: pointer.pageX - this.pointerDownPointer.pageX, + y: pointer.pageY - this.pointerDownPointer.pageY + }; + // start drag if pointer has moved far enough to start drag + if ( !this.isDragging && this.hasDragStarted( moveVector ) ) { + this._dragStart( event, pointer ); + } + return 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; + }; + + // ----- end event ----- // + + /** + * pointer up + * @param {Event} event + * @param {Event or Touch} pointer + */ + proto.pointerUp = function( event, pointer ) { + this.emitEvent( 'pointerUp', [ event, pointer ] ); + this._dragPointerUp( event, pointer ); + }; + + proto._dragPointerUp = function( event, pointer ) { + if ( this.isDragging ) { + this._dragEnd( event, pointer ); + } else { + // pointer didn't move enough for drag to start + this._staticClick( event, pointer ); + } + }; + + // -------------------------- drag -------------------------- // + + // dragStart + proto._dragStart = function( event, pointer ) { + this.isDragging = true; + // prevent clicks + this.isPreventingClicks = true; + this.dragStart( event, pointer ); + }; + + proto.dragStart = function( event, pointer ) { + this.emitEvent( 'dragStart', [ event, pointer ] ); + }; + + // dragMove + proto._dragMove = function( event, pointer, moveVector ) { + // do not drag if not dragging yet + if ( !this.isDragging ) { + return; + } + + this.dragMove( event, pointer, moveVector ); + }; + + proto.dragMove = function( event, pointer, moveVector ) { + event.preventDefault(); + this.emitEvent( 'dragMove', [ event, pointer, moveVector ] ); + }; + + // dragEnd + proto._dragEnd = function( event, pointer ) { + // set flags + this.isDragging = false; + // re-enable clicking async + setTimeout( function() { + delete this.isPreventingClicks; + }.bind( this ) ); + + this.dragEnd( event, pointer ); + }; + + proto.dragEnd = function( event, pointer ) { + this.emitEvent( 'dragEnd', [ event, pointer ] ); + }; + + // ----- onclick ----- // + + // handle all clicks and prevent clicks when dragging + proto.onclick = function( event ) { + if ( this.isPreventingClicks ) { + event.preventDefault(); + } + }; + + // ----- staticClick ----- // + + // triggered after pointer down & up with no/tiny movement + proto._staticClick = function( event, pointer ) { + // ignore emulated mouse up clicks + if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) { + return; + } + + this.staticClick( event, pointer ); + + // set flag for emulated clicks 300ms after touchend + if ( event.type != 'mouseup' ) { + this.isIgnoringMouseUp = true; + // reset flag after 300ms + setTimeout( function() { + delete this.isIgnoringMouseUp; + }.bind( this ), 400 ); + } + }; + + proto.staticClick = function( event, pointer ) { + this.emitEvent( 'staticClick', [ event, pointer ] ); + }; + + // ----- utils ----- // + + Unidragger.getPointerPoint = Unipointer.getPointerPoint; + + // ----- ----- // + + return Unidragger; + + })); + + /*! + * Draggabilly v2.3.0 + * Make that shiz draggable + * https://draggabilly.desandro.com + * MIT license + */ + + /* jshint browser: true, strict: true, undef: true, unused: true */ + + ( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /* globals define */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( [ + 'get-size/get-size', + 'unidragger/unidragger', + ], + function( getSize, Unidragger ) { + return factory( window, getSize, Unidragger ); + } ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('get-size'), + require('unidragger') + ); + } else { + // browser global + window.Draggabilly = factory( + window, + window.getSize, + window.Unidragger + ); + } + + }( window, function factory( window, getSize, Unidragger ) { + + // -------------------------- helpers & variables -------------------------- // + + // extend objects + function extend( a, b ) { + for ( var prop in b ) { + a[ prop ] = b[ prop ]; + } + return a; + } + + function noop() {} + + var jQuery = window.jQuery; + + // -------------------------- -------------------------- // + + function Draggabilly( element, options ) { + // querySelector if string + this.element = typeof element == 'string' ? + document.querySelector( element ) : element; + + if ( jQuery ) { + this.$element = jQuery( this.element ); + } + + // options + this.options = extend( {}, this.constructor.defaults ); + this.option( options ); + + this._create(); + } + + // inherit Unidragger methods + var proto = Draggabilly.prototype = Object.create( Unidragger.prototype ); + + Draggabilly.defaults = { + }; + + /** + * set options + * @param {Object} opts + */ + proto.option = function( opts ) { + extend( this.options, opts ); + }; + + // css position values that don't need to be set + var positionValues = { + relative: true, + absolute: true, + fixed: true, + }; + + proto._create = function() { + // properties + this.position = {}; + this._getPosition(); + + this.startPoint = { x: 0, y: 0 }; + this.dragPoint = { x: 0, y: 0 }; + + this.startPosition = extend( {}, this.position ); + + // set relative positioning + var style = getComputedStyle( this.element ); + if ( !positionValues[ style.position ] ) { + this.element.style.position = 'relative'; + } + + // events, bridge jQuery events from vanilla + this.on( 'pointerMove', this.onPointerMove ); + this.on( 'pointerUp', this.onPointerUp ); + + this.enable(); + this.setHandles(); + }; + + /** + * set this.handles and bind start events to 'em + */ + proto.setHandles = function() { + this.handles = this.options.handle ? + this.element.querySelectorAll( this.options.handle ) : [ this.element ]; + + this.bindHandles(); + }; + + /** + * emits events via EvEmitter and jQuery events + * @param {String} type - name of event + * @param {Event} event - original event + * @param {Array} args - extra arguments + */ + proto.dispatchEvent = function( type, event, args ) { + var emitArgs = [ event ].concat( args ); + this.emitEvent( type, emitArgs ); + this.dispatchJQueryEvent( type, event, args ); + }; + + proto.dispatchJQueryEvent = function( type, event, args ) { + var jquery = window.jQuery; + // trigger jQuery event + if ( !jquery || !this.$element ) { + return; + } + // create jQuery event + /* eslint-disable-next-line new-cap */ + var $event = jquery.Event( event ); + $event.type = type; + this.$element.trigger( $event, args ); + }; + + // -------------------------- position -------------------------- // + + // get x/y position from style + proto._getPosition = function() { + var style = getComputedStyle( this.element ); + var x = this._getPositionCoord( style.left, 'width' ); + var y = this._getPositionCoord( style.top, 'height' ); + // clean up 'auto' or other non-integer values + this.position.x = isNaN( x ) ? 0 : x; + this.position.y = isNaN( y ) ? 0 : y; + + this._addTransformPosition( style ); + }; + + proto._getPositionCoord = function( styleSide, measure ) { + if ( styleSide.indexOf('%') != -1 ) { + // convert percent into pixel for Safari, #75 + var parentSize = getSize( this.element.parentNode ); + // prevent not-in-DOM element throwing bug, #131 + return !parentSize ? 0 : + ( parseFloat( styleSide ) / 100 ) * parentSize[ measure ]; + } + return parseInt( styleSide, 10 ); + }; + + // add transform: translate( x, y ) to position + proto._addTransformPosition = function( style ) { + var transform = style.transform; + // bail out if value is 'none' + if ( transform.indexOf('matrix') !== 0 ) { + return; + } + // split matrix(1, 0, 0, 1, x, y) + var matrixValues = transform.split(','); + // translate X value is in 12th or 4th position + var xIndex = transform.indexOf('matrix3d') === 0 ? 12 : 4; + var translateX = parseInt( matrixValues[ xIndex ], 10 ); + // translate Y value is in 13th or 5th position + var translateY = parseInt( matrixValues[ xIndex + 1 ], 10 ); + this.position.x += translateX; + this.position.y += translateY; + }; + + // -------------------------- events -------------------------- // + + proto.onPointerDown = function( event, pointer ) { + this.element.classList.add('is-pointer-down'); + this.dispatchJQueryEvent( 'pointerDown', event, [ pointer ] ); + }; + + proto.pointerDown = function( event, pointer ) { + var isOkay = this.okayPointerDown( event ); + if ( !isOkay || !this.isEnabled ) { + this._pointerReset(); + return; + } + // track start event position + // Safari 9 overrides pageX and pageY. These values needs to be copied. flickity#842 + this.pointerDownPointer = { + pageX: pointer.pageX, + pageY: pointer.pageY, + }; + + event.preventDefault(); + this.pointerDownBlur(); + // bind move and end events + this._bindPostStartEvents( event ); + this.element.classList.add('is-pointer-down'); + this.dispatchEvent( 'pointerDown', event, [ pointer ] ); + }; + + /** + * drag start + * @param {Event} event + * @param {[Event, Touch]} pointer + */ + proto.dragStart = function( event, pointer ) { + if ( !this.isEnabled ) { + return; + } + this._getPosition(); + this.measureContainment(); + // position _when_ drag began + this.startPosition.x = this.position.x; + this.startPosition.y = this.position.y; + // reset left/top style + this.setLeftTop(); + + this.dragPoint.x = 0; + this.dragPoint.y = 0; + + this.element.classList.add('is-dragging'); + this.dispatchEvent( 'dragStart', event, [ pointer ] ); + // start animation + this.animate(); + }; + + proto.measureContainment = function() { + var container = this.getContainer(); + if ( !container ) { + return; + } + + var elemSize = getSize( this.element ); + var containerSize = getSize( container ); + var elemRect = this.element.getBoundingClientRect(); + var containerRect = container.getBoundingClientRect(); + + var borderSizeX = containerSize.borderLeftWidth + containerSize.borderRightWidth; + var borderSizeY = containerSize.borderTopWidth + containerSize.borderBottomWidth; + + var position = this.relativeStartPosition = { + x: elemRect.left - ( containerRect.left + containerSize.borderLeftWidth ), + y: elemRect.top - ( containerRect.top + containerSize.borderTopWidth ), + }; + + this.containSize = { + width: ( containerSize.width - borderSizeX ) - position.x - elemSize.width, + height: ( containerSize.height - borderSizeY ) - position.y - elemSize.height, + }; + }; + + proto.getContainer = function() { + var containment = this.options.containment; + if ( !containment ) { + return; + } + var isElement = containment instanceof HTMLElement; + // use as element + if ( isElement ) { + return containment; + } + // querySelector if string + if ( typeof containment == 'string' ) { + return document.querySelector( containment ); + } + // fallback to parent element + return this.element.parentNode; + }; + + // ----- move event ----- // + + proto.onPointerMove = function( event, pointer, moveVector ) { + this.dispatchJQueryEvent( 'pointerMove', event, [ pointer, moveVector ] ); + }; + + /** + * drag move + * @param {Event} event + * @param {[Event, Touch]} pointer + * @param {Object} moveVector - x and y coordinates + */ + proto.dragMove = function( event, pointer, moveVector ) { + if ( !this.isEnabled ) { + return; + } + var dragX = moveVector.x; + var dragY = moveVector.y; + + var grid = this.options.grid; + var gridX = grid && grid[0]; + var gridY = grid && grid[1]; + + dragX = applyGrid( dragX, gridX ); + dragY = applyGrid( dragY, gridY ); + + dragX = this.containDrag( 'x', dragX, gridX ); + dragY = this.containDrag( 'y', dragY, gridY ); + + // constrain to axis + dragX = this.options.axis == 'y' ? 0 : dragX; + dragY = this.options.axis == 'x' ? 0 : dragY; + + this.position.x = this.startPosition.x + dragX; + this.position.y = this.startPosition.y + dragY; + // set dragPoint properties + this.dragPoint.x = dragX; + this.dragPoint.y = dragY; + + this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] ); + }; + + function applyGrid( value, grid, method ) { + method = method || 'round'; + return grid ? Math[ method ]( value/grid ) * grid : value; + } + + proto.containDrag = function( axis, drag, grid ) { + if ( !this.options.containment ) { + return drag; + } + var measure = axis == 'x' ? 'width' : 'height'; + + var rel = this.relativeStartPosition[ axis ]; + var min = applyGrid( -rel, grid, 'ceil' ); + var max = this.containSize[ measure ]; + max = applyGrid( max, grid, 'floor' ); + return Math.max( min, Math.min( max, drag ) ); + }; + + // ----- end event ----- // + + /** + * pointer up + * @param {Event} event + * @param {[Event, Touch]} pointer + */ + proto.onPointerUp = function( event, pointer ) { + this.element.classList.remove('is-pointer-down'); + this.dispatchJQueryEvent( 'pointerUp', event, [ pointer ] ); + }; + + /** + * drag end + * @param {Event} event + * @param {[Event, Touch]} pointer + */ + proto.dragEnd = function( event, pointer ) { + if ( !this.isEnabled ) { + return; + } + // use top left position when complete + this.element.style.transform = ''; + this.setLeftTop(); + this.element.classList.remove('is-dragging'); + this.dispatchEvent( 'dragEnd', event, [ pointer ] ); + }; + + // -------------------------- animation -------------------------- // + + proto.animate = function() { + // only render and animate if dragging + if ( !this.isDragging ) { + return; + } + + this.positionDrag(); + + var _this = this; + requestAnimationFrame( function animateFrame() { + _this.animate(); + } ); + + }; + + // left/top positioning + proto.setLeftTop = function() { + this.element.style.left = this.position.x + 'px'; + this.element.style.top = this.position.y + 'px'; + }; + + proto.positionDrag = function() { + this.element.style.transform = 'translate3d( ' + this.dragPoint.x + + 'px, ' + this.dragPoint.y + 'px, 0)'; + }; + + // ----- staticClick ----- // + + proto.staticClick = function( event, pointer ) { + this.dispatchEvent( 'staticClick', event, [ pointer ] ); + }; + + // ----- methods ----- // + + /** + * @param {Number} x + * @param {Number} y + */ + proto.setPosition = function( x, y ) { + this.position.x = x; + this.position.y = y; + this.setLeftTop(); + }; + + proto.enable = function() { + this.isEnabled = true; + }; + + proto.disable = function() { + this.isEnabled = false; + if ( this.isDragging ) { + this.dragEnd(); + } + }; + + proto.destroy = function() { + this.disable(); + // reset styles + this.element.style.transform = ''; + this.element.style.left = ''; + this.element.style.top = ''; + this.element.style.position = ''; + // unbind handles + this.unbindHandles(); + // remove jQuery data + if ( this.$element ) { + this.$element.removeData('draggabilly'); + } + }; + + // ----- jQuery bridget ----- // + + // required for jQuery bridget + proto._init = noop; + + if ( jQuery && jQuery.bridget ) { + jQuery.bridget( 'draggabilly', Draggabilly ); + } + + // ----- ----- // + + return Draggabilly; + + } ) ); + \ No newline at end of file -- cgit v1.2.3