diff --git a/.gitignore b/.gitignore index 09b2e7f..f8dc7e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -components/ bower_components/ node_modules/ build/ diff --git a/bower.json b/bower.json index 777c9d6..ba36269 100644 --- a/bower.json +++ b/bower.json @@ -1,14 +1,14 @@ { "name": "draggabilly", - "main": "draggabilly.js", "description": "make that shiz draggable", + "main": "draggabilly.js", "dependencies": { - "get-size": "~2.0.2", + "get-size": "^2.0.2", "unidragger": "^2.3.0" }, "devDependencies": { - "qunit": "~1.20", - "jquery-bridget": "~2.0.0" + "qunit": "^2.5.1", + "jquery-bridget": "^2.0.0" }, "homepage": "https://draggabilly.desandro.com", "authors": [ diff --git a/dist/draggabilly.pkgd.js b/dist/draggabilly.pkgd.js index 03b8021..d7f7548 100644 --- a/dist/draggabilly.pkgd.js +++ b/dist/draggabilly.pkgd.js @@ -1,26 +1,25 @@ /*! - * Draggabilly PACKAGED v2.1.1 + * Draggabilly PACKAGED v2.2.0 * Make that shiz draggable - * http://draggabilly.desandro.com + * https://draggabilly.desandro.com * MIT license */ /** * Bridget makes jQuery widgets - * v2.0.0 + * v2.0.1 * MIT license */ /* jshint browser: true, strict: true, undef: true, unused: true */ ( function( window, factory ) { - - /* globals define: false, module: false, require: false */ - + // 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 ) { - factory( window, jQuery ); + return factory( window, jQuery ); }); } else if ( typeof module == 'object' && module.exports ) { // CommonJS @@ -37,7 +36,7 @@ } }( window, function factory( window, jQuery ) { - +'use strict'; // ----- utils ----- // @@ -160,7 +159,7 @@ return jQueryBridget; /*global define: false, module: false, console: false */ ( function( window, factory ) { - + 'use strict'; if ( typeof define == 'function' && define.amd ) { // AMD @@ -176,7 +175,7 @@ return jQueryBridget; } })( window, function factory() { - +'use strict'; // -------------------------- helpers -------------------------- // @@ -361,7 +360,7 @@ return getSize; }); /** - * EvEmitter v1.0.3 + * EvEmitter v1.1.0 * Lil' event emitter * MIT License */ @@ -441,13 +440,14 @@ proto.emitEvent = function( eventName, args ) { if ( !listeners || !listeners.length ) { return; } - var i = 0; - var listener = listeners[i]; + // copy over to avoid interference if .off() in listener + listeners = listeners.slice(0); args = args || []; // once stuff var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; - while ( listener ) { + for ( var i=0; i < listeners.length; i++ ) { + var listener = listeners[i] var isOnce = onceListeners && onceListeners[ listener ]; if ( isOnce ) { // remove listener @@ -458,20 +458,22 @@ proto.emitEvent = function( eventName, args ) { } // trigger listener listener.apply( this, args ); - // get next listener - i += isOnce ? 0 : 1; - listener = listeners[i]; } return this; }; +proto.allOff = function() { + delete this._events; + delete this._onceEvents; +}; + return EvEmitter; })); /*! - * Unipointer v2.1.0 + * Unipointer v2.3.0 * base class for doing one thing with pointer event * MIT license */ @@ -522,25 +524,24 @@ proto.unbindStartEvent = function( elem ) { }; /** - * works as unbinder, as you can ._bindStart( false ) to unbind - * @param {Boolean} isBind - will unbind if falsey + * Add or remove start event + * @param {Boolean} isAdd - remove if falsey */ -proto._bindStartEvent = function( elem, isBind ) { - // munge isBind, default to true - isBind = isBind === undefined ? true : !!isBind; - var bindMethod = isBind ? 'addEventListener' : 'removeEventListener'; - - if ( window.navigator.pointerEnabled ) { - // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca - elem[ bindMethod ]( 'pointerdown', this ); - } else if ( window.navigator.msPointerEnabled ) { - // IE10 Pointer Events - elem[ bindMethod ]( 'MSPointerDown', this ); - } else { - // listen for both, for devices like Chrome Pixel - elem[ bindMethod ]( 'mousedown', this ); - elem[ bindMethod ]( 'touchstart', this ); +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 @@ -576,7 +577,6 @@ proto.ontouchstart = function( event ) { this._pointerDown( event, event.changedTouches[0] ); }; -proto.onMSPointerDown = proto.onpointerdown = function( event ) { this._pointerDown( event, event ); }; @@ -587,8 +587,9 @@ proto.onpointerdown = function( event ) { * @param {Event or Touch} pointer */ proto._pointerDown = function( event, pointer ) { - // dismiss other pointers - if ( this.isPointerDown ) { + // dismiss right click and other pointers + // button = 0 is okay, 1-4 not + if ( event.button || this.isPointerDown ) { return; } @@ -611,7 +612,6 @@ var postStartEvents = { mousedown: [ 'mousemove', 'mouseup' ], touchstart: [ 'touchmove', 'touchend', 'touchcancel' ], pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ], - MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ] }; proto._bindPostStartEvents = function( event ) { @@ -646,7 +646,6 @@ proto.onmousemove = function( event ) { this._pointerMove( event, event ); }; -proto.onMSPointerMove = proto.onpointermove = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerMove( event, event ); @@ -682,7 +681,6 @@ proto.onmouseup = function( event ) { this._pointerUp( event, event ); }; -proto.onMSPointerUp = proto.onpointerup = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerUp( event, event ); @@ -716,19 +714,21 @@ proto.pointerUp = function( event, pointer ) { // 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; - // remove events - this._unbindPostStartEvents(); - this.pointerDone(); }; proto.pointerDone = noop; // ----- pointer cancel ----- // -proto.onMSPointerCancel = proto.onpointercancel = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerCancel( event, event ); @@ -775,7 +775,7 @@ return Unipointer; })); /*! - * Unidragger v2.1.0 + * Unidragger v2.3.0 * Draggable base class * MIT license */ @@ -811,10 +811,6 @@ return Unipointer; -// ----- ----- // - -function noop() {} - // -------------------------- Unidragger -------------------------- // function Unidragger() {} @@ -832,39 +828,30 @@ proto.unbindHandles = function() { this._bindHandles( false ); }; -var navigator = window.navigator; /** - * works as unbinder, as you can .bindHandles( false ) to unbind - * @param {Boolean} isBind - will unbind if falsey + * Add or remove start event + * @param {Boolean} isAdd */ -proto._bindHandles = function( isBind ) { - // munge isBind, default to true - isBind = isBind === undefined ? true : !!isBind; - // extra bind logic - var binderExtra; - if ( navigator.pointerEnabled ) { - binderExtra = function( handle ) { - // disable scrolling on the element - handle.style.touchAction = isBind ? 'none' : ''; - }; - } else if ( navigator.msPointerEnabled ) { - binderExtra = function( handle ) { - // disable scrolling on the element - handle.style.msTouchAction = isBind ? 'none' : ''; - }; - } else { - binderExtra = noop; - } +proto._bindHandles = function( isAdd ) { + // munge isAdd, default to true + isAdd = isAdd === undefined ? true : isAdd; // bind each handle - var bindMethod = isBind ? 'addEventListener' : 'removeEventListener'; + 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, isBind ); - binderExtra( handle ); + 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 ----- // /** @@ -873,40 +860,57 @@ proto._bindHandles = function( isBind ) { * @param {Event or Touch} pointer */ proto.pointerDown = function( event, pointer ) { - // dismiss range sliders - if ( event.target.nodeName == 'INPUT' && event.target.type == 'range' ) { - // reset pointerDown logic - this.isPointerDown = false; - delete this.pointerIdentifier; + var isOkay = this.okayPointerDown( event ); + if ( !isOkay ) { return; } + // track start event position + this.pointerDownPointer = pointer; - this._dragPointerDown( event, pointer ); - // kludge to blur focused inputs in dragger - var focused = document.activeElement; - if ( focused && focused.blur ) { - focused.blur(); - } + event.preventDefault(); + this.pointerDownBlur(); // bind move and end events this._bindPostStartEvents( event ); this.emitEvent( 'pointerDown', [ event, pointer ] ); }; -// base pointer down logic -proto._dragPointerDown = function( event, pointer ) { - // track to see when dragging starts - this.pointerDownPoint = Unipointer.getPointerPoint( pointer ); +// nodes that have text fields +var cursorNodes = { + TEXTAREA: true, + INPUT: true, + SELECT: true, + OPTION: true, +}; - var canPreventDefault = this.canPreventDefaultOnPointerDown( event, pointer ); - if ( canPreventDefault ) { - event.preventDefault(); +// 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; }; -// overwriteable method so Flickity can prevent for scrolling -proto.canPreventDefaultOnPointerDown = function( event ) { - // prevent default, unless touchstart or s and