|
@@ -0,0 +1,1538 @@
|
|
|
|
+/*!
|
|
|
|
+ * Draggabilly PACKAGED v2.1.1
|
|
|
|
+ * Make that shiz draggable
|
|
|
|
+ * http://draggabilly.desandro.com
|
|
|
|
+ * MIT license
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Bridget makes jQuery widgets
|
|
|
|
+ * v2.0.0
|
|
|
|
+ * MIT license
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+/* 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
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}( window, function factory( window, jQuery ) {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// ----- 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 ) {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ 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() {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// -------------------------- 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.0.3
|
|
|
|
+ * 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;
|
|
|
|
+ }
|
|
|
|
+ var i = 0;
|
|
|
|
+ var listener = listeners[i];
|
|
|
|
+ args = args || [];
|
|
|
|
+ // once stuff
|
|
|
|
+ var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
|
|
|
|
+
|
|
|
|
+ while ( listener ) {
|
|
|
|
+ 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 );
|
|
|
|
+ // get next listener
|
|
|
|
+ i += isOnce ? 0 : 1;
|
|
|
|
+ listener = listeners[i];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return this;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+return EvEmitter;
|
|
|
|
+
|
|
|
|
+}));
|
|
|
|
+
|
|
|
|
+/*!
|
|
|
|
+ * Unipointer v2.1.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 );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * works as unbinder, as you can ._bindStart( false ) to unbind
|
|
|
|
+ * @param {Boolean} isBind - will unbind 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 );
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 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.onMSPointerDown =
|
|
|
|
+proto.onpointerdown = function( event ) {
|
|
|
|
+ this._pointerDown( event, event );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * pointer start
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
|
+ */
|
|
|
|
+proto._pointerDown = function( event, pointer ) {
|
|
|
|
+ // dismiss other pointers
|
|
|
|
+ if ( 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' ],
|
|
|
|
+ MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ]
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+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.onMSPointerMove =
|
|
|
|
+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.onMSPointerUp =
|
|
|
|
+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() {
|
|
|
|
+ // 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 );
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+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.1.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 ) {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// ----- ----- //
|
|
|
|
+
|
|
|
|
+function noop() {}
|
|
|
|
+
|
|
|
|
+// -------------------------- 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 );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+var navigator = window.navigator;
|
|
|
|
+/**
|
|
|
|
+ * works as unbinder, as you can .bindHandles( false ) to unbind
|
|
|
|
+ * @param {Boolean} isBind - will unbind if falsey
|
|
|
|
+ */
|
|
|
|
+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;
|
|
|
|
+ }
|
|
|
|
+ // bind each handle
|
|
|
|
+ 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 );
|
|
|
|
+ handle[ bindMethod ]( 'click', this );
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// ----- start event ----- //
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * pointer start
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @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;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._dragPointerDown( event, pointer );
|
|
|
|
+ // kludge to blur focused inputs in dragger
|
|
|
|
+ var focused = document.activeElement;
|
|
|
|
+ if ( focused && focused.blur ) {
|
|
|
|
+ focused.blur();
|
|
|
|
+ }
|
|
|
|
+ // 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 );
|
|
|
|
+
|
|
|
|
+ var canPreventDefault = this.canPreventDefaultOnPointerDown( event, pointer );
|
|
|
|
+ if ( canPreventDefault ) {
|
|
|
|
+ event.preventDefault();
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// overwriteable method so Flickity can prevent for scrolling
|
|
|
|
+proto.canPreventDefaultOnPointerDown = function( event ) {
|
|
|
|
+ // prevent default, unless touchstart or <select>
|
|
|
|
+ return event.target.nodeName != 'SELECT';
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// ----- 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 movePoint = Unipointer.getPointerPoint( pointer );
|
|
|
|
+ var moveVector = {
|
|
|
|
+ x: movePoint.x - this.pointerDownPoint.x,
|
|
|
|
+ y: movePoint.y - this.pointerDownPoint.y
|
|
|
|
+ };
|
|
|
|
+ // 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;
|
|
|
|
+ this.dragStartPoint = Unipointer.getPointerPoint( pointer );
|
|
|
|
+ // 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;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // allow click in <input>s and <textarea>s
|
|
|
|
+ var nodeName = event.target.nodeName;
|
|
|
|
+ if ( nodeName == 'INPUT' || nodeName == 'TEXTAREA' ) {
|
|
|
|
+ event.target.focus();
|
|
|
|
+ }
|
|
|
|
+ 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.1.1
|
|
|
|
+ * Make that shiz draggable
|
|
|
|
+ * http://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, module, require */
|
|
|
|
+ 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 ) {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// vars
|
|
|
|
+var document = window.document;
|
|
|
|
+
|
|
|
|
+function noop() {}
|
|
|
|
+
|
|
|
|
+// -------------------------- helpers -------------------------- //
|
|
|
|
+
|
|
|
|
+// extend objects
|
|
|
|
+function extend( a, b ) {
|
|
|
|
+ for ( var prop in b ) {
|
|
|
|
+ a[ prop ] = b[ prop ];
|
|
|
|
+ }
|
|
|
|
+ return a;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function isElement( obj ) {
|
|
|
|
+ return obj instanceof HTMLElement;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// -------------------------- requestAnimationFrame -------------------------- //
|
|
|
|
+
|
|
|
|
+// get rAF, prefixed, if present
|
|
|
|
+var requestAnimationFrame = window.requestAnimationFrame ||
|
|
|
|
+ window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
|
|
|
|
+
|
|
|
|
+// fallback to setTimeout
|
|
|
|
+var lastTime = 0;
|
|
|
|
+if ( !requestAnimationFrame ) {
|
|
|
|
+ requestAnimationFrame = function( callback ) {
|
|
|
|
+ var currTime = new Date().getTime();
|
|
|
|
+ var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
|
|
|
|
+ var id = setTimeout( callback, timeToCall );
|
|
|
|
+ lastTime = currTime + timeToCall;
|
|
|
|
+ return id;
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// -------------------------- support -------------------------- //
|
|
|
|
+
|
|
|
|
+var docElem = document.documentElement;
|
|
|
|
+var transformProperty = typeof docElem.style.transform == 'string' ?
|
|
|
|
+ 'transform' : 'WebkitTransform';
|
|
|
|
+
|
|
|
|
+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 = 'fixed';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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 );
|
|
|
|
+ var jQuery = window.jQuery;
|
|
|
|
+ // trigger jQuery event
|
|
|
|
+ if ( jQuery && this.$element ) {
|
|
|
|
+ if ( event ) {
|
|
|
|
+ // create jQuery event
|
|
|
|
+ var $event = jQuery.Event( event );
|
|
|
|
+ $event.type = type;
|
|
|
|
+ this.$element.trigger( $event, args );
|
|
|
|
+ } else {
|
|
|
|
+ // just trigger with type if no event available
|
|
|
|
+ this.$element.trigger( type, 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[ transformProperty ];
|
|
|
|
+ // 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 -------------------------- //
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * pointer start
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
|
+ */
|
|
|
|
+proto.pointerDown = function( event, pointer ) {
|
|
|
|
+ this._dragPointerDown( event, pointer );
|
|
|
|
+ // kludge to blur focused inputs in dragger
|
|
|
|
+ var focused = document.activeElement;
|
|
|
|
+ // do not blur body for IE10, metafizzy/flickity#117
|
|
|
|
+ if ( focused && focused.blur && focused != document.body ) {
|
|
|
|
+ focused.blur();
|
|
|
|
+ }
|
|
|
|
+ // bind move and end events
|
|
|
|
+ this._bindPostStartEvents( event );
|
|
|
|
+ this.element.classList.add('is-pointer-down');
|
|
|
|
+ this.dispatchEvent( 'pointerDown', event, [ pointer ] );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * drag move
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
|
+ */
|
|
|
|
+proto.pointerMove = function( event, pointer ) {
|
|
|
|
+ var moveVector = this._dragPointerMove( event, pointer );
|
|
|
|
+ this.dispatchEvent( 'pointerMove', event, [ pointer, moveVector ] );
|
|
|
|
+ this._dragMove( event, pointer, moveVector );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * drag start
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @param {Event or 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 containment = this.options.containment;
|
|
|
|
+ if ( !containment ) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // use element if element
|
|
|
|
+ var container = isElement( containment ) ? containment :
|
|
|
|
+ // fallback to querySelector if string
|
|
|
|
+ typeof containment == 'string' ? document.querySelector( containment ) :
|
|
|
|
+ // otherwise just `true`, use the parent
|
|
|
|
+ this.element.parentNode;
|
|
|
|
+
|
|
|
|
+ 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
|
|
|
|
+ };
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// ----- move event ----- //
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * drag move
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
|
+ */
|
|
|
|
+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.min( max, Math.max( min, drag ) );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// ----- end event ----- //
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * pointer up
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
|
+ */
|
|
|
|
+proto.pointerUp = function( event, pointer ) {
|
|
|
|
+ this.element.classList.remove('is-pointer-down');
|
|
|
|
+ this.dispatchEvent( 'pointerUp', event, [ pointer ] );
|
|
|
|
+ this._dragPointerUp( event, pointer );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * drag end
|
|
|
|
+ * @param {Event} event
|
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
|
+ */
|
|
|
|
+proto.dragEnd = function( event, pointer ) {
|
|
|
|
+ if ( !this.isEnabled ) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ // use top left position when complete
|
|
|
|
+ if ( transformProperty ) {
|
|
|
|
+ this.element.style[ transformProperty ] = '';
|
|
|
|
+ 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[ transformProperty ] = 'translate3d( ' + this.dragPoint.x +
|
|
|
|
+ 'px, ' + this.dragPoint.y + 'px, 0)';
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// ----- staticClick ----- //
|
|
|
|
+
|
|
|
|
+proto.staticClick = function( event, pointer ) {
|
|
|
|
+ this.dispatchEvent( 'staticClick', event, [ pointer ] );
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// ----- methods ----- //
|
|
|
|
+
|
|
|
|
+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[ transformProperty ] = '';
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+}));
|
|
|
|
+
|