diff --git a/dist/draggabilly.pkgd.js b/dist/draggabilly.pkgd.js index 9289408..28c46ec 100644 --- a/dist/draggabilly.pkgd.js +++ b/dist/draggabilly.pkgd.js @@ -1,5 +1,5 @@ /*! - * Draggabilly PACKAGED v1.2.4 + * Draggabilly PACKAGED v2.0.0 * Make that shiz draggable * http://draggabilly.desandro.com * MIT license @@ -7,297 +7,173 @@ /** * Bridget makes jQuery widgets - * v1.1.0 + * v2.0.0 * MIT license */ -( function( window ) { +/* jshint browser: true, strict: true, undef: true, unused: true */ +( function( window, factory ) { + + /* globals define: false, module: false, require: false */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) { + 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 + ); + } -// -------------------------- utils -------------------------- // - -var slice = Array.prototype.slice; - -function noop() {} - -// -------------------------- definition -------------------------- // - -function defineBridget( $ ) { - -// bail if no jQuery -if ( !$ ) { - return; -} - -// -------------------------- addOptionMethod -------------------------- // +}( window, function factory( window, jQuery ) { -/** - * adds option method -> $().plugin('option', {...}) - * @param {Function} PluginClass - constructor class - */ -function addOptionMethod( PluginClass ) { - // don't overwrite original option method - if ( PluginClass.prototype.option ) { - return; - } - // option setter - PluginClass.prototype.option = function( opts ) { - // bail out if not an object - if ( !$.isPlainObject( opts ) ){ - return; - } - this.options = $.extend( true, this.options, opts ); - }; -} +// ----- utils ----- // -// -------------------------- plugin bridge -------------------------- // +var arraySlice = Array.prototype.slice; // helper function for logging errors // $.error breaks jQuery chaining -var logError = typeof console === 'undefined' ? noop : +var console = window.console; +var logError = typeof console == 'undefined' ? function() {} : function( message ) { console.error( message ); }; -/** - * jQuery plugin bridge, access methods like $elem.plugin('method') - * @param {String} namespace - plugin name - * @param {Function} PluginClass - constructor class - */ -function bridge( namespace, PluginClass ) { - // add to jQuery fn namespace - $.fn[ namespace ] = function( options ) { - if ( typeof options === 'string' ) { - // call plugin method when first argument is a string - // get arguments for method - var args = slice.call( arguments, 1 ); - - for ( var i=0, len = this.length; i < len; i++ ) { - var elem = this[i]; - var instance = $.data( elem, namespace ); - if ( !instance ) { - logError( "cannot call methods on " + namespace + " prior to initialization; " + - "attempted to call '" + options + "'" ); - continue; - } - if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) { - logError( "no such method '" + options + "' for " + namespace + " instance" ); - continue; - } +// ----- jQueryBridget ----- // - // trigger method with arguments - var returnValue = instance[ options ].apply( instance, args ); +function jQueryBridget( namespace, PluginClass, $ ) { + $ = $ || jQuery || window.jQuery; + if ( !$ ) { + return; + } - // break look and return first value if provided - if ( returnValue !== undefined ) { - return returnValue; - } + // 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; } - // return this if no return value - return this; - } else { - return this.each( function() { - var instance = $.data( this, namespace ); - if ( instance ) { - // apply options & init - instance.option( options ); - instance._init(); - } else { - // initialize new instance - instance = new PluginClass( this, options ); - $.data( this, namespace, instance ); - } - }); - } - }; - -} - -// -------------------------- bridget -------------------------- // - -/** - * converts a Prototypical class into a proper jQuery plugin - * the class must have a ._init method - * @param {String} namespace - plugin name, used in $().pluginName - * @param {Function} PluginClass - constructor class - */ -$.bridget = function( namespace, PluginClass ) { - addOptionMethod( PluginClass ); - bridge( namespace, PluginClass ); -}; - -return $.bridget; - -} - -// transport -if ( typeof define === 'function' && define.amd ) { - // AMD - define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget ); -} else if ( typeof exports === 'object' ) { - defineBridget( require('jquery') ); -} else { - // get jquery from browser global - defineBridget( window.jQuery ); -} - -})( window ); - -/*! - * classie v1.0.1 - * class helper functions - * from bonzo https://github.com/ded/bonzo - * MIT license - * - * classie.has( elem, 'my-class' ) -> true/false - * classie.add( elem, 'my-new-class' ) - * classie.remove( elem, 'my-unwanted-class' ) - * classie.toggle( elem, 'my-class' ) - */ - -/*jshint browser: true, strict: true, undef: true, unused: true */ -/*global define: false, module: false */ - -( function( window ) { - - - -// class helper functions from bonzo https://github.com/ded/bonzo - -function classReg( className ) { - return new RegExp("(^|\\s+)" + className + "(\\s+|$)"); -} - -// classList support for class management -// altho to be fair, the api sucks because it won't accept multiple classes at once -var hasClass, addClass, removeClass; + this.options = $.extend( true, this.options, opts ); + }; + } -if ( 'classList' in document.documentElement ) { - hasClass = function( elem, c ) { - return elem.classList.contains( c ); - }; - addClass = function( elem, c ) { - elem.classList.add( c ); - }; - removeClass = function( elem, c ) { - elem.classList.remove( c ); - }; -} -else { - hasClass = function( elem, c ) { - return classReg( c ).test( elem.className ); - }; - addClass = function( elem, c ) { - if ( !hasClass( elem, c ) ) { - elem.className = elem.className + ' ' + c; + // 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; }; - removeClass = function( elem, c ) { - elem.className = elem.className.replace( classReg( c ), ' ' ); - }; -} - -function toggleClass( elem, c ) { - var fn = hasClass( elem, c ) ? removeClass : addClass; - fn( elem, c ); -} -var classie = { - // full names - hasClass: hasClass, - addClass: addClass, - removeClass: removeClass, - toggleClass: toggleClass, - // short names - has: hasClass, - add: addClass, - remove: removeClass, - toggle: toggleClass -}; - -// transport -if ( typeof define === 'function' && define.amd ) { - // AMD - define( 'classie/classie',classie ); -} else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = classie; -} else { - // browser global - window.classie = classie; -} + // $().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; + } -})( window ); + var method = instance[ methodName ]; + if ( !method || methodName.charAt(0) == '_' ) { + logError( pluginMethodStr + ' is not a valid method' ); + return; + } -/*! - * getStyleProperty v1.0.4 - * original by kangax - * http://perfectionkills.com/feature-testing-css-properties/ - * MIT license - */ + // 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; + }); -/*jshint browser: true, strict: true, undef: true */ -/*global define: false, exports: false, module: false */ + return returnValue !== undefined ? returnValue : $elems; + } -( function( window ) { + 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( $ ); +} -var prefixes = 'Webkit Moz ms Ms O'.split(' '); -var docElemStyle = document.documentElement.style; +// ----- updateJQuery ----- // -function getStyleProperty( propName ) { - if ( !propName ) { +// set $.bridget for v1 backwards compatibility +function updateJQuery( $ ) { + if ( !$ || ( $ && $.bridget ) ) { return; } + $.bridget = jQueryBridget; +} - // test standard property first - if ( typeof docElemStyle[ propName ] === 'string' ) { - return propName; - } +updateJQuery( jQuery || window.jQuery ); - // capitalize - propName = propName.charAt(0).toUpperCase() + propName.slice(1); +// ----- ----- // - // test vendor specific properties - var prefixed; - for ( var i=0, len = prefixes.length; i < len; i++ ) { - prefixed = prefixes[i] + propName; - if ( typeof docElemStyle[ prefixed ] === 'string' ) { - return prefixed; - } - } -} +return jQueryBridget; -// transport -if ( typeof define === 'function' && define.amd ) { - // AMD - define( 'get-style-property/get-style-property',[],function() { - return getStyleProperty; - }); -} else if ( typeof exports === 'object' ) { - // CommonJS for Component - module.exports = getStyleProperty; -} else { - // browser global - window.getStyleProperty = getStyleProperty; -} - -})( window ); +})); /*! - * getSize v1.2.2 + * getSize v2.0.1 * measure size of elements * MIT license */ /*jshint browser: true, strict: true, undef: true, unused: true */ -/*global define: false, exports: false, require: false, module: false, console: false */ +/*global define: false, module: false, console: false */ -( function( window, undefined ) { +( function( window, factory ) { + + if ( typeof define == 'function' && define.amd ) { + // AMD + define( factory() ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory(); + } else { + // browser global + window.getSize = factory(); + } + +})( window, function factory() { // -------------------------- helpers -------------------------- // @@ -306,13 +182,13 @@ if ( typeof define === 'function' && define.amd ) { function getStyleSize( value ) { var num = parseFloat( value ); // not a percent like '100%', and a number - var isValid = value.indexOf('%') === -1 && !isNaN( num ); + var isValid = value.indexOf('%') == -1 && !isNaN( num ); return isValid && num; } function noop() {} -var logError = typeof console === 'undefined' ? noop : +var logError = typeof console == 'undefined' ? noop : function( message ) { console.error( message ); }; @@ -334,6 +210,8 @@ var measurements = [ 'borderBottomWidth' ]; +var measurementsLength = measurements.length; + function getZeroSize() { var size = { width: 0, @@ -343,27 +221,39 @@ function getZeroSize() { outerWidth: 0, outerHeight: 0 }; - for ( var i=0, len = measurements.length; i < len; i++ ) { + for ( var i=0; i < measurementsLength; i++ ) { var measurement = measurements[i]; size[ measurement ] = 0; } return size; } +// -------------------------- getStyle -------------------------- // - -function defineGetSize( getStyleProperty ) { +/** + * 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 getStyle, boxSizingProp, isBoxSizeOuter; +var isBoxSizeOuter; /** - * setup vars and functions - * do it on initial getSize(), rather than on script load - * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + * setup + * check isBoxSizerOuter + * do on first getSize() rather than on page load for Firefox bug */ function setup() { // setup once @@ -372,50 +262,25 @@ function setup() { } isSetup = true; - var getComputedStyle = window.getComputedStyle; - getStyle = ( function() { - var getStyleFn = getComputedStyle ? - function( elem ) { - return getComputedStyle( elem, null ); - } : - function( elem ) { - return elem.currentStyle; - }; - - return function getStyle( elem ) { - var style = getStyleFn( 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; - }; - })(); - // -------------------------- box sizing -------------------------- // - boxSizingProp = getStyleProperty('boxSizing'); - /** * WebKit measures the outer-width on style.width on border-box elems - * IE & Firefox measures the inner-width + * IE & Firefox<29 measures the inner-width */ - if ( boxSizingProp ) { - 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[ boxSizingProp ] = 'border-box'; - - var body = document.body || document.documentElement; - body.appendChild( div ); - var style = getStyle( div ); - - isBoxSizeOuter = getStyleSize( style.width ) === 200; - body.removeChild( div ); - } + 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 ); } @@ -425,19 +290,19 @@ function getSize( elem ) { setup(); // use querySeletor if elem is string - if ( typeof elem === 'string' ) { + if ( typeof elem == 'string' ) { elem = document.querySelector( elem ); } // do not proceed on non-objects - if ( !elem || typeof elem !== 'object' || !elem.nodeType ) { + if ( !elem || typeof elem != 'object' || !elem.nodeType ) { return; } var style = getStyle( elem ); // if hidden, everything is 0 - if ( style.display === 'none' ) { + if ( style.display == 'none' ) { return getZeroSize(); } @@ -445,14 +310,12 @@ function getSize( elem ) { size.width = elem.offsetWidth; size.height = elem.offsetHeight; - var isBorderBox = size.isBorderBox = !!( boxSizingProp && - style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' ); + var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; // get all measurements - for ( var i=0, len = measurements.length; i < len; i++ ) { + for ( var i=0; i < measurementsLength; i++ ) { var measurement = measurements[i]; var value = style[ measurement ]; - value = mungeNonPixel( elem, value ); var num = parseFloat( value ); // any 'auto', 'medium' value will be 0 size[ measurement ] = !isNaN( num ) ? num : 0; @@ -491,135 +354,11 @@ function getSize( elem ) { return size; } -// IE8 returns percent values, not pixels -// taken from jQuery's curCSS -function mungeNonPixel( elem, value ) { - // IE8 and has percent value - if ( window.getComputedStyle || value.indexOf('%') === -1 ) { - return value; - } - var style = elem.style; - // Remember the original values - var left = style.left; - var rs = elem.runtimeStyle; - var rsLeft = rs && rs.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - rs.left = elem.currentStyle.left; - } - style.left = value; - value = style.pixelLeft; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - rs.left = rsLeft; - } - - return value; -} - return getSize; -} - -// transport -if ( typeof define === 'function' && define.amd ) { - // AMD for RequireJS - define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize ); -} else if ( typeof exports === 'object' ) { - // CommonJS for Component - module.exports = defineGetSize( require('desandro-get-style-property') ); -} else { - // browser global - window.getSize = defineGetSize( window.getStyleProperty ); -} - -})( window ); - -/*! - * eventie v1.0.6 - * event binding helper - * eventie.bind( elem, 'click', myFn ) - * eventie.unbind( elem, 'click', myFn ) - * MIT license - */ - -/*jshint browser: true, undef: true, unused: true */ -/*global define: false, module: false */ - -( function( window ) { - - - -var docElem = document.documentElement; - -var bind = function() {}; - -function getIEEvent( obj ) { - var event = window.event; - // add event.target - event.target = event.target || event.srcElement || obj; - return event; -} - -if ( docElem.addEventListener ) { - bind = function( obj, type, fn ) { - obj.addEventListener( type, fn, false ); - }; -} else if ( docElem.attachEvent ) { - bind = function( obj, type, fn ) { - obj[ type + fn ] = fn.handleEvent ? - function() { - var event = getIEEvent( obj ); - fn.handleEvent.call( fn, event ); - } : - function() { - var event = getIEEvent( obj ); - fn.call( obj, event ); - }; - obj.attachEvent( "on" + type, obj[ type + fn ] ); - }; -} - -var unbind = function() {}; - -if ( docElem.removeEventListener ) { - unbind = function( obj, type, fn ) { - obj.removeEventListener( type, fn, false ); - }; -} else if ( docElem.detachEvent ) { - unbind = function( obj, type, fn ) { - obj.detachEvent( "on" + type, obj[ type + fn ] ); - try { - delete obj[ type + fn ]; - } catch ( err ) { - // can't delete window object properties - obj[ type + fn ] = undefined; - } - }; -} +}); -var eventie = { - bind: bind, - unbind: unbind -}; - -// ----- module definition ----- // - -if ( typeof define === 'function' && define.amd ) { - // AMD - define( 'eventie/eventie',eventie ); -} else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = eventie; -} else { - // browser global - window.eventie = eventie; -} - -})( window ); +define("get-size/get-size", function(){}); /*! * EventEmitter v4.2.11 - git.io/ee @@ -1095,7 +834,7 @@ if ( typeof define === 'function' && define.amd ) { }.call(this)); /*! - * Unipointer v1.1.0 + * Unipointer v2.0.0 * base class for doing one thing with pointer event * MIT license */ @@ -1110,28 +849,25 @@ if ( typeof define === 'function' && define.amd ) { if ( typeof define == 'function' && define.amd ) { // AMD define( 'unipointer/unipointer',[ - 'eventEmitter/EventEmitter', - 'eventie/eventie' - ], function( EventEmitter, eventie ) { - return factory( window, EventEmitter, eventie ); + 'eventEmitter/EventEmitter' + ], function( EventEmitter ) { + return factory( window, EventEmitter ); }); - } else if ( typeof exports == 'object' ) { + } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, - require('wolfy87-eventemitter'), - require('eventie') + require('wolfy87-eventemitter') ); } else { // browser global window.Unipointer = factory( window, - window.EventEmitter, - window.eventie + window.EventEmitter ); } -}( window, function factory( window, EventEmitter, eventie ) { +}( window, function factory( window, EventEmitter ) { @@ -1140,13 +876,13 @@ function noop() {} function Unipointer() {} // inherit EventEmitter -Unipointer.prototype = new EventEmitter(); +var proto = Unipointer.prototype = Object.create( EventEmitter.prototype ); -Unipointer.prototype.bindStartEvent = function( elem ) { +proto.bindStartEvent = function( elem ) { this._bindStartEvent( elem, true ); }; -Unipointer.prototype.unbindStartEvent = function( elem ) { +proto.unbindStartEvent = function( elem ) { this._bindStartEvent( elem, false ); }; @@ -1154,26 +890,26 @@ Unipointer.prototype.unbindStartEvent = function( elem ) { * works as unbinder, as you can ._bindStart( false ) to unbind * @param {Boolean} isBind - will unbind if falsey */ -Unipointer.prototype._bindStartEvent = function( elem, isBind ) { +proto._bindStartEvent = function( elem, isBind ) { // munge isBind, default to true isBind = isBind === undefined ? true : !!isBind; - var bindMethod = isBind ? 'bind' : 'unbind'; + var bindMethod = isBind ? 'addEventListener' : 'removeEventListener'; if ( window.navigator.pointerEnabled ) { // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca - eventie[ bindMethod ]( elem, 'pointerdown', this ); + elem[ bindMethod ]( 'pointerdown', this ); } else if ( window.navigator.msPointerEnabled ) { // IE10 Pointer Events - eventie[ bindMethod ]( elem, 'MSPointerDown', this ); + elem[ bindMethod ]( 'MSPointerDown', this ); } else { // listen for both, for devices like Chrome Pixel - eventie[ bindMethod ]( elem, 'mousedown', this ); - eventie[ bindMethod ]( elem, 'touchstart', this ); + elem[ bindMethod ]( 'mousedown', this ); + elem[ bindMethod ]( 'touchstart', this ); } }; // trigger handler methods for events -Unipointer.prototype.handleEvent = function( event ) { +proto.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); @@ -1181,8 +917,8 @@ Unipointer.prototype.handleEvent = function( event ) { }; // returns the touch that we're keeping track of -Unipointer.prototype.getTouch = function( touches ) { - for ( var i=0, len = touches.length; i < len; i++ ) { +proto.getTouch = function( touches ) { + for ( var i=0; i < touches.length; i++ ) { var touch = touches[i]; if ( touch.identifier == this.pointerIdentifier ) { return touch; @@ -1192,7 +928,7 @@ Unipointer.prototype.getTouch = function( touches ) { // ----- start event ----- // -Unipointer.prototype.onmousedown = function( event ) { +proto.onmousedown = function( event ) { // dismiss clicks from right or middle buttons var button = event.button; if ( button && ( button !== 0 && button !== 1 ) ) { @@ -1201,12 +937,12 @@ Unipointer.prototype.onmousedown = function( event ) { this._pointerDown( event, event ); }; -Unipointer.prototype.ontouchstart = function( event ) { +proto.ontouchstart = function( event ) { this._pointerDown( event, event.changedTouches[0] ); }; -Unipointer.prototype.onMSPointerDown = -Unipointer.prototype.onpointerdown = function( event ) { +proto.onMSPointerDown = +proto.onpointerdown = function( event ) { this._pointerDown( event, event ); }; @@ -1215,7 +951,7 @@ Unipointer.prototype.onpointerdown = function( event ) { * @param {Event} event * @param {Event or Touch} pointer */ -Unipointer.prototype._pointerDown = function( event, pointer ) { +proto._pointerDown = function( event, pointer ) { // dismiss other pointers if ( this.isPointerDown ) { return; @@ -1230,7 +966,7 @@ Unipointer.prototype._pointerDown = function( event, pointer ) { this.pointerDown( event, pointer ); }; -Unipointer.prototype.pointerDown = function( event, pointer ) { +proto.pointerDown = function( event, pointer ) { this._bindPostStartEvents( event ); this.emitEvent( 'pointerDown', [ event, pointer ] ); }; @@ -1243,54 +979,46 @@ var postStartEvents = { MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ] }; -Unipointer.prototype._bindPostStartEvents = function( event ) { +proto._bindPostStartEvents = function( event ) { if ( !event ) { return; } // get proper events to match start event var events = postStartEvents[ event.type ]; - // IE8 needs to be bound to document - var node = event.preventDefault ? window : document; // bind events to node - for ( var i=0, len = events.length; i < len; i++ ) { - var evnt = events[i]; - eventie.bind( node, evnt, this ); - } + events.forEach( function( eventName ) { + window.addEventListener( eventName, this ); + }, this ); // save these arguments - this._boundPointerEvents = { - events: events, - node: node - }; + this._boundPointerEvents = events; }; -Unipointer.prototype._unbindPostStartEvents = function() { - var args = this._boundPointerEvents; - // IE8 can trigger dragEnd twice, check for _boundEvents - if ( !args || !args.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 ); - for ( var i=0, len = args.events.length; i < len; i++ ) { - var event = args.events[i]; - eventie.unbind( args.node, event, this ); - } delete this._boundPointerEvents; }; // ----- move event ----- // -Unipointer.prototype.onmousemove = function( event ) { +proto.onmousemove = function( event ) { this._pointerMove( event, event ); }; -Unipointer.prototype.onMSPointerMove = -Unipointer.prototype.onpointermove = function( event ) { +proto.onMSPointerMove = +proto.onpointermove = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerMove( event, event ); } }; -Unipointer.prototype.ontouchmove = function( event ) { +proto.ontouchmove = function( event ) { var touch = this.getTouch( event.changedTouches ); if ( touch ) { this._pointerMove( event, touch ); @@ -1303,30 +1031,30 @@ Unipointer.prototype.ontouchmove = function( event ) { * @param {Event or Touch} pointer * @private */ -Unipointer.prototype._pointerMove = function( event, pointer ) { +proto._pointerMove = function( event, pointer ) { this.pointerMove( event, pointer ); }; // public -Unipointer.prototype.pointerMove = function( event, pointer ) { +proto.pointerMove = function( event, pointer ) { this.emitEvent( 'pointerMove', [ event, pointer ] ); }; // ----- end event ----- // -Unipointer.prototype.onmouseup = function( event ) { +proto.onmouseup = function( event ) { this._pointerUp( event, event ); }; -Unipointer.prototype.onMSPointerUp = -Unipointer.prototype.onpointerup = function( event ) { +proto.onMSPointerUp = +proto.onpointerup = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerUp( event, event ); } }; -Unipointer.prototype.ontouchend = function( event ) { +proto.ontouchend = function( event ) { var touch = this.getTouch( event.changedTouches ); if ( touch ) { this._pointerUp( event, touch ); @@ -1339,20 +1067,20 @@ Unipointer.prototype.ontouchend = function( event ) { * @param {Event or Touch} pointer * @private */ -Unipointer.prototype._pointerUp = function( event, pointer ) { +proto._pointerUp = function( event, pointer ) { this._pointerDone(); this.pointerUp( event, pointer ); }; // public -Unipointer.prototype.pointerUp = function( event, pointer ) { +proto.pointerUp = function( event, pointer ) { this.emitEvent( 'pointerUp', [ event, pointer ] ); }; // ----- pointer done ----- // // triggered on pointer up & pointer cancel -Unipointer.prototype._pointerDone = function() { +proto._pointerDone = function() { // reset properties this.isPointerDown = false; delete this.pointerIdentifier; @@ -1361,18 +1089,18 @@ Unipointer.prototype._pointerDone = function() { this.pointerDone(); }; -Unipointer.prototype.pointerDone = noop; +proto.pointerDone = noop; // ----- pointer cancel ----- // -Unipointer.prototype.onMSPointerCancel = -Unipointer.prototype.onpointercancel = function( event ) { +proto.onMSPointerCancel = +proto.onpointercancel = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerCancel( event, event ); } }; -Unipointer.prototype.ontouchcancel = function( event ) { +proto.ontouchcancel = function( event ) { var touch = this.getTouch( event.changedTouches ); if ( touch ) { this._pointerCancel( event, touch ); @@ -1385,23 +1113,23 @@ Unipointer.prototype.ontouchcancel = function( event ) { * @param {Event or Touch} pointer * @private */ -Unipointer.prototype._pointerCancel = function( event, pointer ) { +proto._pointerCancel = function( event, pointer ) { this._pointerDone(); this.pointerCancel( event, pointer ); }; // public -Unipointer.prototype.pointerCancel = function( event, pointer ) { +proto.pointerCancel = function( event, pointer ) { this.emitEvent( 'pointerCancel', [ event, pointer ] ); }; // ----- ----- // -// utility function for getting x/y cooridinates from event, because IE8 +// utility function for getting x/y coords from event Unipointer.getPointerPoint = function( pointer ) { return { - x: pointer.pageX !== undefined ? pointer.pageX : pointer.clientX, - y: pointer.pageY !== undefined ? pointer.pageY : pointer.clientY + x: pointer.pageX, + y: pointer.pageY }; }; @@ -1412,7 +1140,7 @@ return Unipointer; })); /*! - * Unidragger v1.1.0 + * Unidragger v2.0.0 * Draggable base class * MIT license */ @@ -1427,28 +1155,25 @@ return Unipointer; if ( typeof define == 'function' && define.amd ) { // AMD define( 'unidragger/unidragger',[ - 'eventie/eventie', 'unipointer/unipointer' - ], function( eventie, Unipointer ) { - return factory( window, eventie, Unipointer ); + ], function( Unipointer ) { + return factory( window, Unipointer ); }); - } else if ( typeof exports == 'object' ) { + } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, - require('eventie'), require('unipointer') ); } else { // browser global window.Unidragger = factory( window, - window.eventie, window.Unipointer ); } -}( window, function factory( window, eventie, Unipointer ) { +}( window, function factory( window, Unipointer ) { @@ -1456,38 +1181,20 @@ return Unipointer; function noop() {} -// handle IE8 prevent default -function preventDefaultEvent( event ) { - if ( event.preventDefault ) { - event.preventDefault(); - } else { - event.returnValue = false; - } -} - -function getParentLink( elem ) { - while ( elem != document.body ) { - elem = elem.parentNode; - if ( elem.nodeName == 'A' ) { - return elem; - } - } -} - // -------------------------- Unidragger -------------------------- // function Unidragger() {} // inherit Unipointer & EventEmitter -Unidragger.prototype = new Unipointer(); +var proto = Unidragger.prototype = Object.create( Unipointer.prototype ); // ----- bind start ----- // -Unidragger.prototype.bindHandles = function() { +proto.bindHandles = function() { this._bindHandles( true ); }; -Unidragger.prototype.unbindHandles = function() { +proto.unbindHandles = function() { this._bindHandles( false ); }; @@ -1496,7 +1203,7 @@ var navigator = window.navigator; * works as unbinder, as you can .bindHandles( false ) to unbind * @param {Boolean} isBind - will unbind if falsey */ -Unidragger.prototype._bindHandles = function( isBind ) { +proto._bindHandles = function( isBind ) { // munge isBind, default to true isBind = isBind === undefined ? true : !!isBind; // extra bind logic @@ -1512,62 +1219,34 @@ Unidragger.prototype._bindHandles = function( isBind ) { handle.style.msTouchAction = isBind ? 'none' : ''; }; } else { - binderExtra = function() { - // TODO re-enable img.ondragstart when unbinding - if ( isBind ) { - disableImgOndragstart( handle ); - } - }; + binderExtra = noop; } // bind each handle - var bindMethod = isBind ? 'bind' : 'unbind'; - for ( var i=0, len = this.handles.length; i < len; i++ ) { + var bindMethod = isBind ? 'addEventListener' : 'removeEventListener'; + for ( var i=0; i < this.handles.length; i++ ) { var handle = this.handles[i]; this._bindStartEvent( handle, isBind ); binderExtra( handle ); - eventie[ bindMethod ]( handle, 'click', this ); - } -}; - -// remove default dragging interaction on all images in IE8 -// IE8 does its own drag thing on images, which messes stuff up - -function noDragStart() { - return false; -} - -// TODO replace this with a IE8 test -var isIE8 = 'attachEvent' in document.documentElement; - -// IE8 only -var disableImgOndragstart = !isIE8 ? noop : function( handle ) { - - if ( handle.nodeName == 'IMG' ) { - handle.ondragstart = noDragStart; - } - - var images = handle.querySelectorAll('img'); - for ( var i=0, len = images.length; i < len; i++ ) { - var img = images[i]; - img.ondragstart = noDragStart; + handle[ bindMethod ]( 'click', this ); } }; // ----- start event ----- // -var allowTouchstartNodes = Unidragger.allowTouchstartNodes = { - INPUT: true, - A: true, - BUTTON: true, - SELECT: true -}; - /** * pointer start * @param {Event} event * @param {Event or Touch} pointer */ -Unidragger.prototype.pointerDown = function( event, 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; + return; + } + this._dragPointerDown( event, pointer ); // kludge to blur focused inputs in dragger var focused = document.activeElement; @@ -1580,20 +1259,22 @@ Unidragger.prototype.pointerDown = function( event, pointer ) { }; // base pointer down logic -Unidragger.prototype._dragPointerDown = function( event, pointer ) { +proto._dragPointerDown = function( event, pointer ) { // track to see when dragging starts this.pointerDownPoint = Unipointer.getPointerPoint( pointer ); - var targetNodeName = event.target.nodeName; - // HACK iOS, allow clicks on buttons, inputs, and links, or children of links - var isTouchstartNode = event.type == 'touchstart' && - ( allowTouchstartNodes[ targetNodeName ] || getParentLink( event.target ) ); - // do not prevent default on touchstart nodes or + return event.target.nodeName != 'SELECT'; +}; + // ----- move event ----- // /** @@ -1601,14 +1282,14 @@ Unidragger.prototype._dragPointerDown = function( event, pointer ) { * @param {Event} event * @param {Event or Touch} pointer */ -Unidragger.prototype.pointerMove = function( event, 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 -Unidragger.prototype._dragPointerMove = function( event, pointer ) { +proto._dragPointerMove = function( event, pointer ) { var movePoint = Unipointer.getPointerPoint( pointer ); var moveVector = { x: movePoint.x - this.pointerDownPoint.x, @@ -1622,7 +1303,7 @@ Unidragger.prototype._dragPointerMove = function( event, pointer ) { }; // condition if pointer has moved far enough to start drag -Unidragger.prototype.hasDragStarted = function( moveVector ) { +proto.hasDragStarted = function( moveVector ) { return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3; }; @@ -1634,12 +1315,12 @@ Unidragger.prototype.hasDragStarted = function( moveVector ) { * @param {Event} event * @param {Event or Touch} pointer */ -Unidragger.prototype.pointerUp = function( event, pointer ) { +proto.pointerUp = function( event, pointer ) { this.emitEvent( 'pointerUp', [ event, pointer ] ); this._dragPointerUp( event, pointer ); }; -Unidragger.prototype._dragPointerUp = function( event, pointer ) { +proto._dragPointerUp = function( event, pointer ) { if ( this.isDragging ) { this._dragEnd( event, pointer ); } else { @@ -1651,21 +1332,21 @@ Unidragger.prototype._dragPointerUp = function( event, pointer ) { // -------------------------- drag -------------------------- // // dragStart -Unidragger.prototype._dragStart = function( event, pointer ) { +proto._dragStart = function( event, pointer ) { this.isDragging = true; - this.dragStartPoint = Unidragger.getPointerPoint( pointer ); + this.dragStartPoint = Unipointer.getPointerPoint( pointer ); // prevent clicks this.isPreventingClicks = true; this.dragStart( event, pointer ); }; -Unidragger.prototype.dragStart = function( event, pointer ) { +proto.dragStart = function( event, pointer ) { this.emitEvent( 'dragStart', [ event, pointer ] ); }; // dragMove -Unidragger.prototype._dragMove = function( event, pointer, moveVector ) { +proto._dragMove = function( event, pointer, moveVector ) { // do not drag if not dragging yet if ( !this.isDragging ) { return; @@ -1674,70 +1355,78 @@ Unidragger.prototype._dragMove = function( event, pointer, moveVector ) { this.dragMove( event, pointer, moveVector ); }; -Unidragger.prototype.dragMove = function( event, pointer, moveVector ) { +proto.dragMove = function( event, pointer, moveVector ) { + event.preventDefault(); this.emitEvent( 'dragMove', [ event, pointer, moveVector ] ); }; // dragEnd -Unidragger.prototype._dragEnd = function( event, pointer ) { +proto._dragEnd = function( event, pointer ) { // set flags this.isDragging = false; // re-enable clicking async - var _this = this; setTimeout( function() { - delete _this.isPreventingClicks; - }); + delete this.isPreventingClicks; + }.bind( this ) ); this.dragEnd( event, pointer ); }; -Unidragger.prototype.dragEnd = function( event, pointer ) { +proto.dragEnd = function( event, pointer ) { this.emitEvent( 'dragEnd', [ event, pointer ] ); }; // ----- onclick ----- // // handle all clicks and prevent clicks when dragging -Unidragger.prototype.onclick = function( event ) { +proto.onclick = function( event ) { if ( this.isPreventingClicks ) { - preventDefaultEvent( event ); + event.preventDefault(); } }; // ----- staticClick ----- // // triggered after pointer down & up with no/tiny movement -Unidragger.prototype._staticClick = function( event, pointer ) { - // allow click in text input - if ( event.target.nodeName == 'INPUT' && event.target.type == 'text' ) { +proto._staticClick = function( event, pointer ) { + // ignore emulated mouse up clicks + if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) { + return; + } + + // allow click in s and