PageSourceSearch

https://argenbio.org/templates/theme3136/js/jquery.pep.js

js argenbio.org collected 2026-10-02 06:41:41 UTC 40,381 bytes, 1,166 lines download raw bytes

1/*
2 *         ________                                                            ________
3 *         ______(_)_____ ____  __________________  __ _____________________   ______(_)_______
4 *         _____  /_  __ `/  / / /  _ \_  ___/_  / / / ___  __ \  _ \__  __ \  _____  /__  ___/
5 *         ____  / / /_/ // /_/ //  __/  /   _  /_/ /____  /_/ /  __/_  /_/ /______  / _(__  )
6 *         ___  /  \__, / \__,_/ \___//_/    _\__, /_(_)  .___/\___/_  .___/_(_)__  /  /____/
7 *         /___/     /_/                     /____/    /_/          /_/        /___/
8 *
9 *        http://pep.briangonzalez.org
10 *        Kinetic drag for mobile/desktop.
11 *
12 *        Copyright (c) 2014 Brian Gonzalez
13 *        Licensed under the MIT license.
14 *
15 *        Title generated using "Speed" @
16 *        http://patorjk.com/software/taag/#p=display&f=Speed&t=jquery.pep.js
17 */
18
19;(function ( $, window, undefined ) {
20
21  "use strict";
22
23  //  create the defaults once
24  var pluginName = 'pep';
25  var defaults   = {
26
27    // Options
28    // ----------------------------------------------------------------------------------------------
29    // See ** https://github.com/briangonzalez/jquery.pep.js ** for fully documented options.
30    // It was too hard to manage options here and in the readme.
31    // ----------------------------------------------------------------------------------------------
32    initiate:                       function(){},
33    start:                          function(){},
34    drag:                           function(){},
35    stop:                           function(){},
36    easing:                         null,
37    rest:                           function(){},
38    moveTo:                         false,
39    callIfNotStarted:               ['stop', 'rest'],
40    startThreshold:                 [0,0],
41    grid:                           [1,1],
42    debug:                          false,
43    activeClass:                    'pep-active',
44    multiplier:                     1,
45    velocityMultiplier:             2.5,
46    shouldPreventDefault:           true,
47    allowDragEventPropagation:      true,
48    stopEvents:                     '',
49    hardwareAccelerate:             true,
50    useCSSTranslation:              true,
51    disableSelect:                  true,
52    cssEaseString:                  "cubic-bezier(0.190, 1.000, 0.220, 1.000)",
53    cssEaseDuration:                1000,
54    shouldEase:                     true,
55    droppable:                      false,
56    droppableActiveClass:           'pep-dpa',
57    overlapFunction:                false,
58    constrainTo:                    false,
59    removeMargins:                  true,
60    place:                          true,
61    deferPlacement:                 false,
62    axis:                           null,
63    forceNonCSS3Movement:           false,
64    elementsWithInteraction:        'input',
65    revert:                         false,
66    revertAfter:                    'stop',
67    revertIf:                       function(){ return true; },
68    ignoreRightClick:               true
69  };
70
71  //  ---------------------------------
72  //  -----  Our main Pep object  -----
73  //  ---------------------------------
74  function Pep( el, options ) {
75
76    this.name = pluginName;
77
78    // reference to our DOM object
79    // and it's jQuery equivalent.
80    this.el  = el;
81    this.$el = $(el);
82
83    //  merge in defaults
84    this.options    = $.extend( {}, defaults, options) ;
85
86    // store document/body so we don't need to keep grabbing them
87    // throughout the code
88    this.$document  = $(this.$el[0].ownerDocument);
89    this.$body      = this.$document.find('body');
90
91    //  Create our triggers based on touch/click device
92    this.moveTrigger        = "MSPointerMove touchmove mousemove";
93    this.startTrigger       = "MSPointerDown touchstart mousedown";
94    this.stopTrigger        = "MSPointerUp touchend mouseup";
95    this.startTriggerArray  = this.startTrigger.split(' ');
96    this.moveTriggerArray   = this.moveTrigger.split(' ');
97    this.stopTriggerArray   = this.stopTrigger.split(' ');
98    this.stopEvents         = [ this.stopTrigger, this.options.stopEvents ].join(' ');
99
100    if ( this.options.constrainTo === 'window' )
101      this.$container = this.$document;
102    else if ( this.options.constrainTo && (this.options.constrainTo !== 'parent') )
103      this.$container = $(this.options.constrainTo);
104    else
105      this.$container = this.$el.parent();
106
107    // IE need this
108    if ( this.isPointerEventCompatible() )
109      this.applyMSDefaults();
110
111    this.CSSEaseHash    = this.getCSSEaseHash();
112    this.scale          = 1;
113    this.started        = false;
114    this.disabled       = false;
115    this.activeDropRegions = [];
116    this.resetVelocityQueue();
117
118    this.init();
119    return this;
120  }
121
122  //  init();
123  //    initialization logic
124  //    you already have access to the DOM el and the options via the instance,
125  //    e.g., this.el and this.options
126  Pep.prototype.init = function () {
127
128    if ( this.options.debug )
129      this.buildDebugDiv();
130
131    if ( this.options.disableSelect )
132      this.disableSelect();
133
134    // position the parent & place the object, if necessary.
135    if ( this.options.place && !this.options.deferPlacement ) {
136      this.positionParent();
137      this.placeObject();
138    }
139
140    this.ev = {};       // to store our event movements
141    this.pos = {};      // to store positions
142    this.subscribe();
143  };
144
145  //  subscribe();
146  //    useful in the event we want to programmatically
147  //    interact with our Pep object.
148  //      e.g.:     $('#pep').trigger('stop')
149  Pep.prototype.subscribe = function () {
150    var self = this;
151
152    // Subscribe to our start event
153    this.onStartEvent = function(ev){ self.handleStart(ev); };
154    this.$el.on(this.startTrigger, this.onStartEvent);
155
156    // Prevent start events from being gobbled by elements that should allow user interaction
157    this.onStartEventOnElementsWithInteraction = function(ev){ ev.stopPropagation(); };
158    this.$el.on(
159      this.startTrigger,
160      this.options.elementsWithInteraction,
161      this.onStartEventOnElementsWithInteraction
162    );
163
164    // Subscribe to our stop event
165    this.onStopEvents = function(ev) { self.handleStop(ev); };
166    this.$document.on(this.stopEvents, this.onStopEvents);
167
168    // Subscribe to our move event
169    this.onMoveEvents = function(ev){ self.moveEvent = ev; };
170    this.$document.on(this.moveTrigger, this.onMoveEvents);
171  };
172
173  Pep.prototype.unsubscribe = function() {
174    this.$el.off(this.startTrigger, this.onStartEvent);
175    this.$el.off(
176      this.startTrigger,
177      this.options.elementsWithInteraction,
178      this.onStartEventOnElementsWithInteraction
179    );
180    this.$document.off(this.stopEvents, this.onStopEvents);
181    this.$document.off(this.moveTrigger, this.onMoveEvents);
182  };
183
184  //  handleStart();
185  //    once this.startTrigger occurs, handle all of the logic
186  //    that must go on. This is where Pep's heavy lifting is done.
187  Pep.prototype.handleStart = function(ev) {
188    var self = this;
189
190            // only continue chugging if our start event is a valid move event.
191            if ( this.isValidMoveEvent(ev) && !this.disabled ){
192
193              if( !(this.options.ignoreRightClick && ev.which === 3) ) {
194
195                    // IE10 Hack. Me not happy.
196                    if ( this.isPointerEventCompatible() && ev.preventManipulation )
197                      ev.preventManipulation();
198
199                    // normalize event
200                    ev = this.normalizeEvent(ev);
201
202                    // position the parent & place the object, if necessary.
203                    if ( this.options.place && this.options.deferPlacement ) {
204                      this.positionParent();
205                      this.placeObject();
206                    }
207
208                    // log it
209                    this.log({ type: 'event', event: ev.type });
210
211                    // hardware accelerate, if necessary.
212                    if ( this.options.hardwareAccelerate && !this.hardwareAccelerated ) {
213                      this.hardwareAccelerate();
214                      this.hardwareAccelerated = true;
215                    }
216
217                    // fire user's initiate event.
218                    var shouldContinue = this.options.initiate.call(this, ev, this);
219                    if ( shouldContinue === false )
220                      return;
221
222
223                    // cancel the rest timeout
224                    clearTimeout( this.restTimeout );
225
226                    // add active class and reset css animation, if necessary
227                    this.$el.addClass( this.options.activeClass );
228                    this.removeCSSEasing();
229
230                    // store event's x & y values for later use
231                    this.startX = this.ev.x = ev.pep.x;
232                    this.startY = this.ev.y = ev.pep.y;
233
234                    // store initial offset.
235                    this.initialPosition = this.initialPosition || this.$el.position();
236
237                    // store the initial touch/click event, used to calculate the inital delta values.
238                    this.startEvent = this.moveEvent = ev;
239
240                    // make object active, so watchMoveLoop starts looping.
241                    this.active     = true;
242
243                    // preventDefault(), is necessary
244                    if ( this.options.shouldPreventDefault )
245                      ev.preventDefault();
246
247                    // allow / disallow event bubbling
248                    if ( !this.options.allowDragEventPropagation )
249                      ev.stopPropagation();
250
251                    // animation loop to ensure we don't fire
252                    // too many unneccessary repaints
253                    (function watchMoveLoop(){
254                        if ( !self.active ) return;
255                        self.handleMove();
256                        self.requestAnimationFrame( watchMoveLoop );
257                    })();
258
259                    (function watchEasingLoop(){
260                        if ( !self.options.easing ) return;
261                        if ( self.easing ) self.options.easing.call(self, null, self);
262                        self.requestAnimationFrame( watchEasingLoop );
263                    })();
264              }
265            }
266  };
267
268  //  handleMove();
269  //    the logic for when the move events occur
270  Pep.prototype.handleMove = function() {
271
272            // setup our event object
273            if ( typeof(this.moveEvent) === 'undefined' )
274              return;
275
276            // get our move event's x & y
277            var ev      = this.normalizeEvent( this.moveEvent );
278            var curX    = window.parseInt(ev.pep.x / this.options.grid[0]) * this.options.grid[0];
279            var curY    = window.parseInt(ev.pep.y / this.options.grid[1]) * this.options.grid[1];
280
281            // last in, first out (LIFO) queue to help us manage velocity
282            this.addToLIFO( { time: ev.timeStamp, x: curX, y: curY } );
283
284            // calculate values necessary to moving
285            var dx, dy;
286
287            if ( $.inArray( ev.type, this.startTriggerArray ) > -1  ){
288              dx = 0;
289              dy = 0;
290            } else{
291              dx = curX - this.ev.x;
292              dy = curY - this.ev.y;
293            }
294
295            this.dx   = dx;
296            this.dy   = dy;
297            this.ev.x = curX;
298            this.ev.y = curY;
299
300            // no movement in either direction -- so return
301            if (dx === 0 && dy === 0){
302              this.log({ type: 'event', event: '** stopped **' });
303              return;
304            }
305
306            // check if object has moved past X/Y thresholds
307            // if so, fire users start event
308            var initialDx  = Math.abs(this.startX - curX);
309            var initialDy  = Math.abs(this.startY - curY);
310            if ( !this.started && ( initialDx > this.options.startThreshold[0] || initialDy > this.options.startThreshold[1] ) ){
311              this.started = true;
312              this.$el.addClass('pep-start');
313              this.options.start.call(this, this.startEvent, this);
314            }
315
316            // Calculate our drop regions
317            if ( this.options.droppable ) {
318              this.calculateActiveDropRegions();
319            }
320
321            // fire user's drag event.
322            var continueDrag = this.options.drag.call(this, ev, this);
323
324            if ( continueDrag === false ) {
325              this.resetVelocityQueue();
326              return;
327            }
328
329            // log the move trigger & event position
330            this.log({ type: 'event', event: ev.type });
331            this.log({ type: 'event-coords', x: this.ev.x, y: this.ev.y });
332            this.log({ type: 'velocity' });
333
334            this.doMoveTo(dx, dy);
335  };
336
337  Pep.prototype.doMoveTo = function(dx, dy) {
338            var hash = this.handleConstraint(dx, dy);
339            var xOp, yOp;
340
341            // if using not using CSS transforms, move object via absolute position
342            if ( typeof this.options.moveTo === 'function') {
343              xOp     = ( dx >= 0 ) ? "+=" + Math.abs(dx/this.scale)*this.options.multiplier : "-=" + Math.abs(dx/this.scale)*this.options.multiplier;
344              yOp     = ( dy >= 0 ) ? "+=" + Math.abs(dy/this.scale)*this.options.multiplier : "-=" + Math.abs(dy/this.scale)*this.options.multiplier;
345
346              if ( this.options.constrainTo ) {
347                xOp = (hash.x !== false) ? hash.x : xOp;
348                yOp = (hash.y !== false) ? hash.y : yOp;
349              }
350
351              // only move along single axis, if necessary
352              if ( this.options.axis  === 'x' ) yOp = hash.y;
353              if ( this.options.axis  === 'y' ) xOp = hash.x;
354
355              this.options.moveTo.call(this, xOp, yOp);
356            } else if ( !this.shouldUseCSSTranslation() ){
357              xOp     = ( dx >= 0 ) ? "+=" + Math.abs(dx/this.scale)*this.options.multiplier : "-=" + Math.abs(dx/this.scale)*this.options.multiplier;
358              yOp     = ( dy >= 0 ) ? "+=" + Math.abs(dy/this.scale)*this.options.multiplier : "-=" + Math.abs(dy/this.scale)*this.options.multiplier;
359
360              if ( this.options.constrainTo ) {
361                xOp = (hash.x !== false) ? hash.x : xOp;
362                yOp = (hash.y !== false) ? hash.y : yOp;
363              }
364
365              // only move along single axis, if necessary
366              if ( this.options.axis  === 'x' ) yOp = hash.y;
367              if ( this.options.axis  === 'y' ) xOp = hash.x;
368
369              this.moveTo(xOp, yOp);
370            }
371            else {
372
373              dx = (dx/this.scale)*this.options.multiplier;
374              dy = (dy/this.scale)*this.options.multiplier;
375
376              if ( this.options.constrainTo ) {
377                dx = (hash.x === false) ? dx : 0 ;
378                dy = (hash.y === false) ? dy : 0 ;
379              }
380
381              // only move along single axis, if necessary
382              if ( this.options.axis  === 'x' ) dy = 0;
383              if ( this.options.axis  === 'y' ) dx = 0;
384
385              this.moveToUsingTransforms( dx, dy );
386            }
387  };
388
389  //  handleStop();
390  //    the logic for when the stop events occur
391  Pep.prototype.handleStop = function(ev) {
392
393            // no need to handle stop event if we're not active
394            if (!this.active)
395              return;
396
397            // log it
398            this.log({ type: 'event', event: ev.type });
399
400            // make object inactive, so watchMoveLoop returns
401            this.active = false;
402
403            // make object easing.
404            this.easing = true;
405
406            // remove our start class
407            this.$el.removeClass('pep-start')
408                    .addClass('pep-ease');
409
410            // Calculate our drop regions
411            if ( this.options.droppable ) {
412              this.calculateActiveDropRegions();
413            }
414
415            // fire user's stop event.
416            if ( this.started || (!this.started &&  $.inArray('stop', this.options.callIfNotStarted) > -1 ) ) {
417              this.options.stop.call(this, ev, this);
418            }
419
420            // ease the object, if necessary.
421            if (this.options.shouldEase) {
422              this.ease(ev, this.started);
423            } else {
424              this.removeActiveClass();
425            }
426
427            if ( this.options.revert && (this.options.revertAfter === 'stop' || !this.options.shouldEase) && ( this.options.revertIf && this.options.revertIf.call(this) ) ) {
428              this.revert();
429            }
430
431            // this must be set to false after
432            // the user's stop event is called, so the dev
433            // has access to it.
434            this.started = false;
435
436            // reset the velocity queue
437            this.resetVelocityQueue();
438
439  };
440
441  //  ease();
442  //    used in conjunction with the LIFO queue
443  //    to ease the object after stop
444  Pep.prototype.ease = function(ev, started){
445
446            var pos       = this.$el.position();
447            var vel       = this.velocity();
448            var dt        = this.dt;
449            var x         = (vel.x/this.scale) * this.options.multiplier;
450            var y         = (vel.y/this.scale) * this.options.multiplier;
451
452            var hash      = this.handleConstraint(x, y, true);
453
454            // ✪  Apply the CSS3 animation easing magic  ✪
455            if ( this.cssAnimationsSupported() )
456              this.$el.css( this.getCSSEaseHash() );
457
458            var xOp = ( vel.x >
458 0 ) ? "+=" + x : "-=" + Math.abs(x);
459            var yOp = ( vel.y > 0 ) ? "+=" + y : "-=" + Math.abs(y);
460
461            if ( this.options.constrainTo ) {
462              xOp = (hash.x !== false) ? hash.x : xOp;
463              yOp = (hash.y !== false) ? hash.y : yOp;
464            }
465
466            if ( this.options.axis  === 'x' ) yOp = "+=0";
467            if ( this.options.axis  === 'y' ) xOp = "+=0";
468
469            // ease it via JS, the last true tells it to animate.
470            var jsAnimateFallback = !this.cssAnimationsSupported() || this.options.forceNonCSS3Movement;
471            if (typeof this.options.moveTo === 'function') {
472              this.options.moveTo.call(this, xOp, yOp);
473            } else {
474              this.moveTo(xOp, yOp, jsAnimateFallback);
475            }
476
477            // when the rest occurs, remove active class and call
478            // user's rest event.
479            var self = this;
480            this.restTimeout = setTimeout( function(){
481
482              // Calculate our drop regions
483              if ( self.options.droppable ) {
484                self.calculateActiveDropRegions();
485              }
486
487              self.easing = false;
488
489              // call users rest event.
490              if ( started || ( !started && $.inArray('rest', self.options.callIfNotStarted) > -1 ) ) {
491                self.options.rest.call(self, ev, self);
492              }
493
494              // revert thy self!
495              if ( self.options.revert && (self.options.revertAfter === 'ease' && self.options.shouldEase) && ( self.options.revertIf && self.options.revertIf.call(self) ) ) {
496                self.revert();
497              }
498
499              // remove active class
500              self.removeActiveClass();
501
502            }, this.options.cssEaseDuration );
503
504  };
505
506  // normalizeEvent()
507  Pep.prototype.normalizeEvent = function(ev) {
508      ev.pep        = {};
509
510      if ( this.isPointerEventCompatible() || !this.isTouch(ev) ) {
511
512        if ( ev.pageX  ) {
513          ev.pep.x      = ev.pageX;
514          ev.pep.y      = ev.pageY;
515        } else {
516          ev.pep.x      = ev.originalEvent.pageX;
517          ev.pep.y      = ev.originalEvent.pageY;
518        }
519
520        ev.pep.type   = ev.type;
521
522      }
523      else {
524        ev.pep.x      = ev.originalEvent.touches[0].pageX;
525        ev.pep.y      = ev.originalEvent.touches[0].pageY;
526        ev.pep.type   = ev.type;
527      }
528
529       return ev;
530   };
531
532  // resetVelocityQueue()
533  //
534  Pep.prototype.resetVelocityQueue = function() {
535    this.velocityQueue = new Array(5);
536  };
537
538  //  moveTo();
539  //    move the object to an x and/or y value
540  //    using jQuery's .css function -- this fxn uses the
541  //    .css({top: "+=20", left: "-=30"}) syntax
542  Pep.prototype.moveTo = function(x,y, animate) {
543
544    this.log({ type: 'delta', x: x, y: y });
545    if ( animate ) {
546      this.$el.animate({ top: y, left: x }, 0, 'easeOutQuad', {queue: false});
547    } else{
548      this.$el.stop(true, false).css({ top: y , left: x });
549    }
550
551  };
552
553  //  moveToUsingTransforms();
554  //    move the object to an x and/or y value
555  Pep.prototype.moveToUsingTransforms = function(x,y) {
556
557    // Check for our initial values if we don't have them.
558    var matrixArray  = this.matrixToArray( this.matrixString() );
559    if ( !this.cssX )
560      this.cssX = this.xTranslation( matrixArray );
561
562    if ( !this.cssY )
563      this.cssY = this.yTranslation( matrixArray );
564
565    // CSS3 transforms are additive from current position
566    this.cssX = this.cssX + x;
567    this.cssY = this.cssY + y;
568
569    this.log({ type: 'delta', x: x, y: y });
570
571    matrixArray[4]    = this.cssX;
572    matrixArray[5]    = this.cssY;
573
574    this.translation  = this.arrayToMatrix( matrixArray );
575    this.transform( this.translation );
576  };
577
578  Pep.prototype.transform = function(value) {
579    this.$el.css({
580        '-webkit-transform': value,
581           '-moz-transform': value,
582            '-ms-transform': value,
583             '-o-transform': value,
584                'transform': value  });
585  };
586
587  Pep.prototype.xTranslation = function(matrixArray) {
588    matrixArray  = matrixArray || this.matrixToArray( this.matrixString() );
589    return parseInt(matrixArray[4], 10);
590  };
591
592  Pep.prototype.yTranslation = function(matrixArray) {
593    matrixArray  = matrixArray || this.matrixToArray( this.matrixString() );
594    return parseInt(matrixArray[5], 10);
595  };
596
597
598  // 3 helper functions for working with the
599  // objects CSS3 transforms
600  // matrixString
601  // matrixToArray
602  // arrayToMatrix
603  Pep.prototype.matrixString = function() {
604
605    var validMatrix = function(o){
606      return !( !o || o === 'none' || o.indexOf('matrix') < 0  );
607    };
608
609    var matrix = "matrix(1, 0, 0, 1, 0, 0)";
610
611    if ( validMatrix( this.$el.css('-webkit-transform') ) )
612      matrix = this.$el.css('-webkit-transform');
613
614    if ( validMatrix( this.$el.css('-moz-transform') ) )
615      matrix = this.$el.css('-moz-transform');
616
617    if ( validMatrix( this.$el.css('-ms-transform') ) )
618      matrix = this.$el.css('-ms-transform');
619
620    if ( validMatrix( this.$el.css('-o-transform') ) )
621      matrix = this.$el.css('-o-transform');
622
623    if ( validMatrix( this.$el.css('transform') ) )
624      matrix = this.$el.css('transform');
625
626    return matrix;
627  };
628
629  Pep.prototype.matrixToArray = function(str) {
630      return str.split('(')[1].split(')')[0].split(',');
631  };
632
633  Pep.prototype.arrayToMatrix = function(array) {
634      return "matrix(" +  array.join(',')  + ")";
635  };
636
637  //  addToLIFO();
638  //    a Last-In/First-Out array of the 5 most recent
639  //    velocity points, which is used for easing
640  Pep.prototype.addToLIFO = function(val){
641    // last in, first out
642    var arr = this.velocityQueue;
643    arr = arr.slice(1, arr.length);
644    arr.push(val);
645    this.velocityQueue = arr;
646  };
647
648  //  velocity();
649  //    using the LIFO, calculate velocity and return
650  //    velocity in each direction (x & y)
651  Pep.prototype.velocity = function(){
652    var sumX = 0;
653    var sumY = 0;
654
655    for ( var i = 0; i < this.velocityQueue.length -1; i++  ){
656      if ( this.velocityQueue[i] ){
657        sumX        += (this.velocityQueue[i+1].x - this.velocityQueue[i].x);
658        sumY        += (this.velocityQueue[i+1].y - this.velocityQueue[i].y);
659        this.dt     = ( this.velocityQueue[i+1].time - this.velocityQueue[i].time );
660      }
661    }
662
663    // return velocity in each direction.
664    return { x: sumX*this.options.velocityMultiplier, y: sumY*this.options.velocityMultiplier};
665  };
666
667  Pep.prototype.revert = function() {
668    if ( this.shouldUseCSSTranslation() ){
669      this.moveToUsingTransforms(-this.xTranslation(),-this.yTranslation());
670    }
671
672    this.moveTo(this.initialPosition.left, this.initialPosition.top);
673  };
674
675  //  requestAnimationFrame();
676  //    requestAnimationFrame Polyfill
677  //    More info:
678  //    http://paulirish.com/2011/requestanimationframe-for-smart-animating/
679  Pep.prototype.requestAnimationFrame = function(callback) {
680    return  window.requestAnimationFrame        && window.requestAnimationFrame(callback)         ||
681            window.webkitRequestAnimationFrame  && window.webkitRequestAnimationFrame(callback)   ||
682            window.mozRequestAnimationFrame     && window.mozRequestAnimationFrame(callback)      ||
683            window.oRequestAnimationFrame       && window.mozRequestAnimationFrame(callback)      ||
684            window.msRequestAnimationFrame      && window.msRequestAnimationFrame(callback)       ||
685            window.setTimeout(callback, 1000 / 60);
686  };
687
688  //  positionParent();
689  //    add the right positioning to the parent object
690  Pep.prototype.positionParent = function() {
691
692    if ( !this.options.constrainTo || this.parentPositioned )
693      return;
694
695    this.parentPositioned = true;
696
697    // make `relative` parent if necessary
698    if ( this.options.constrainTo === 'parent' ) {
699      this.$container.css({ position: 'relative' });
700    } else if ( this.options.constrainTo === 'window'             &&
701                this.$container.get(0).nodeName !== "#document"   &&
702                this.$container.css('position') !== 'static' )
703    {
704      this.$container.css({ position: 'static' });
705    }
706
707  };
708
709  //  placeObject();
710  //    add the right positioning to the object
711  Pep.prototype.placeObject = function() {
712
713    if ( this.objectPlaced )
714      return;
715
716    this.objectPlaced = true;
717
718    this.offset = (this.options.constrainTo === 'parent' || this.hasNonBodyRelative() ) ?
719                    this.$el.position() : this.$el.offset();
720
721    // better to leave absolute position alone if
722    // it already has one.
723    if ( parseInt( this.$el.css('left'), 10 ) )
724      this.offset.left = this.$el.css('left');
725
726    if ( parseInt( this.$el.css('top'), 10 ) )
727      this.offset.top = this.$el.css('top');
728
729    if ( this.options.removeMargins )
730      this.$el.css({margin: 0});
731
732    this.$el.css({
733      position:   'absolute',
734      top:        this.offset.top,
735      left:       this.offset.left
736    });
737
738  };
739
740  //  hasNonBodyRelative()
741  //    returns true if any parent other than the body
742  //    has relative positioning
743  Pep.prototype.hasNonBodyRelative = function() {
744    return this.$el.parents().filter(function() {
745        var $this = $(this);
746        return $this.is('body') || $this.css('position') === 'relative';
747    }).length > 1;
748  };
749
750  //  setScale()
751  //    set the scale of the object being moved.
752  Pep.prototype.setScale = function(val) {
753    this.scale = val;
754  };
755
756  //  setMultiplier()
757  //    set the multiplier of the object being moved.
758  Pep.prototype.setMultiplier = function(val) {
759    this.options.multiplier = val;
760  };
761
762  //  removeCSSEasing();
763  //    remove CSS easing properties, if necessary
764  Pep.prototype.removeCSSEasing = function() {
765    if ( this.cssAnimationsSupported() )
766      this.$el.css( this.getCSSEaseHash(true) );
767  };
768
769  //  disableSelect();
770  //    add the property which causes the object
771  //    to not be selected user drags over text areas
772  Pep.prototype.disableSelect = function() {
773
774    this.$el.css({
775      '-webkit-touch-callout' : 'none',
776        '-webkit-user-select' : 'none',
777         '-khtml-user-select' : 'none',
778           '-moz-user-select' : 'none',
779            '-ms-user-select' : 'none',
780                'user-select' : 'none'
781    });
782
783  };
784
785  // removeActiveClass()
786  //  Removes the active class.
787  Pep.prototype.removeActiveClass = function() {
788    this.$el.removeClass( [this.options.activeClass, 'pep-ease'].join(' ') );
789  };
790
791  //  handleConstraint();
792  //    returns a hash of where to move to
793  //    when we constrain to parent/window
794  Pep.prototype.handleConstraint = function(dx, dy, accountForTranslation) {
795    var pos               = this.$el.position();
796    this.pos.x            = pos.left;
797    this.pos.y            = pos.top;
798
799    var hash              = { x: false, y: false };
800
801    var upperYLimit, upperXLimit, lowerXLimit, lowerYLimit;
802
803    // log our positions
804    this.log({ type: "pos-coords", x: this.pos.x, y: this.pos.y});
805
806    if ( $.isArray( this.options.constrainTo ) ) {
807
808      if ( this.options.constrainTo[3] !== undefined && this.options.constrainTo[1] !== undefined ) {
809        upperXLimit     = this.options.constrainTo[1] === false ?  Infinity : this.options.constrainTo[1];
810        lowerXLimit     = this.options.constrainTo[3] === false ? -Infinity : this.options.constrainTo[3];
811      }
812      if ( this.options.constrainTo[0] !== false && this.options.constrainTo[2] !== false ) {
813        upperYLimit       = this.options.constrainTo[2] === false ?  Infinity : this.options.constrainTo[2];
814        lowerYLimit       = this.options.constrainTo[0] === false ? -Infinity : this.options.constrainTo[0];
815      }
816
817      // is our object trying to move outside lower X & Y limits?
818      if ( this.pos.x + dx < lowerXLimit)     hash.x = lowerXLimit;
819      if ( this.pos.y + dy < lowerYLimit)     hash.y = lowerYLimit;
820
821    } else if ( typeof this.options.constrainTo === 'string' ) {
822      lowerXLimit       = 0;
823      lowerYLimit       = 0;
824      upperXLimit       = this.$container.width()  - this.$el.outerWidth();
825      upperYLimit       = this.$container.height() - this.$el.outerHeight();
826
827      // is our object trying to move outside lower X & Y limits?
828      if ( this.pos.x + dx < 0 )              hash.x = 0;
829      if ( this.pos.y + dy < 0 )              hash.y = 0;
830    }
831
832    // is our object trying to move outside upper X & Y limits?
833    if ( this.pos.x + dx > upperXLimit )    hash.x = upperXLimit;
834    if ( this.pos.y + dy > upperYLimit )    hash.y = upperYLimit;
835
836    // Account for translation, which makes movement a little tricky.
837    if ( this.shouldUseCSSTranslation() && accountForTranslation ){
838      if (hash.x === lowerXLimit && this.xTranslation() ) hash.x = lowerXLimit - this.xTranslation();
839      if (hash.x === upperXLimit && this.xTranslation() ) hash.x = upperXLimit - this.xTranslation();
840
841      if (hash.y === lowerYLimit && this.yTranslation() ) hash.y = lowerYLimit - this.yTranslation();
842      if (hash.y === upperYLimit && this.yTranslation() ) hash.y = upperYLimit - this.yTranslation();
843    }
844
845    return hash;
846  };
847
848  //  getCSSEaseHash();
849  //    returns a hash of params used in conjunction
850  //    with this.options.cssEaseString
851  Pep.prototype.getCSSEaseHash = function(reset){
852    if ( typeof(reset) === 'undefined' ) reset = false;
853
854    var cssEaseString;
855    if (reset){
856      cssEaseString = '';
857    } else if ( this.CSSEaseHash ) {
858      return this.CSSEaseHash;
859    } else {
860      cssEaseString = ['all', this.options.cssEaseDuration + 'ms', this.options.cssEaseString].join(' ');
861    }
862
863    return {
864                  '-webkit-transition'   : cssEaseString,   // chrome, safari, etc.
865                     '-moz-transition'   : cssEaseString,   // firefox
866                      '-ms-transition'   : cssEaseString,   // microsoft
867                       '-o-transition'   : cssEaseString,   // opera
868                          'transition'   : cssEaseString    // future
869          };
870  };
871
872  // calculateActiveDropRegions()
873  //    sets parent droppables of this.
874  Pep.prototype.calculateActiveDropRegions = function() {
875    var self = this;
876    this.activeDropRegions.length = 0;
877
878    $.each( $(this.options.droppable), function(idx, el){
879      var $el = $(el);
880      if ( self.isOverlapping($el, self.$el) ){
881        $el.addClass(self.options.droppableActiveClass);
882        self.activeDropRegions.push($el);
883      } else {
884        $el.removeClass(self.options.droppableActiveClass);
885      }
886    });
887
888  };
889
890  //  isOverlapping();
891  //    returns true if element a over
892  Pep.prototype.isOverlapping = function($a,$b) {
893
894    if ( this.options.overlapFunction ) {
895      return this.options.overlapFunction($a,$b);
896    }
897
898    var rect1 = $a[0].getBoundingClientRect();
899    var rect2 = $b[0].getBoundingClientRect();
900
901    return !( rect1.right   < rect2.left  ||
902              rect1.left    > rect2.right ||
903              rect1.bottom  < rect2.top   ||
904              rect1.top     > rect2.bottom  );
905  };
906
907  //  isTouch();
908  //    returns whether or not event is a touch event
909  Pep.prototype.isTouch = function(ev){
910    return ev.type.search('touch') > -1;
911  };
912
913  // isPointerEventCompatible();
914  //    return whether or note our device is pointer
915  //    event compatible; typically means where on a
916  //    touch Win8 device
917  Pep.prototype.isPointerEventCompatible = function() {
918    return ("MSPointerEvent" in window);
919  };
920
921  // applyMSDefaults();
922  Pep.prototype.applyMSDefaults = function(first_argument) {
923    this.$el.css({
924        '-ms-touch-action' :    'none',
925        'touch-action' :        'none',
926        '-ms-scroll-chaining':  'none',
927        '-ms-scroll-limit':     '0 0 0 0'
928    });
929  };
930
931  //  isValidMoveEvent();
932  //    returns true if we're on a non-touch device -- or --
933  //    if the event is **single** touch event on a touch device
934  Pep.prototype.isValidMoveEvent = function(ev){
935    return ( !this.isTouch(ev) || ( this.isTouch(ev) && ev.originalEvent && ev.originalEvent.touches && ev.originalEvent.touches.length === 1 ) );
936  };
937
938  //  shouldUseCSSTranslation();
939  //    return true if we should use CSS transforms for move the object
940  Pep.prototype.shouldUseCSSTranslation = function() {
941
942    if ( this.options.forceNonCSS3Movement )
943      return false;
944
945    if ( typeof(this.useCSSTranslation) !== "undefined" )
946      return this.useCSSTranslation;
947
948    var useCSSTranslation = false;
949
950    if ( !this.options.useCSSTranslation || ( typeof(Modernizr) !== "undefined" && !Modernizr.csstransforms)){
951      useCSSTranslation = false;
952    }
953    else{
954      useCSSTranslation = true;
955    }
956
957    this.useCSSTranslation =  useCSSTranslation;
958    return useCSSTranslation;
959  };
960
961  //  cssAnimationsSupported():
962  //    returns true if the browser supports CSS animations
963  //    which are used for easing..
964  Pep.prototype.cssAnimationsSupported = function() {
965
966    if ( typeof(this.cssAnimationsSupport) !== "undefined" ){
967      return this.cssAnimationsSupport;
968    }
969
970    // If the page has Modernizr, let them do the heavy lifting.
971    if ( ( typeof(Modernizr) !== "undefined" && Modernizr.cssanimations) ){
972      this.cssAnimationsSupport = true;
973      return true;
974    }
975
976    var animation = false,
977        elm = document.createElement('div'),
978        animationstring = 'animation',
979        keyframeprefix = '',
980        domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
981        pfx  = '';
982
983    if( elm.style.animationName ) { animation = true; }
984
985    if( animation === false ) {
986      for( var i = 0; i < domPrefixes.length; i++ ) {
987        if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
988          pfx = domPrefixes[ i ];
989          animationstring = pfx + 'Animation';
990          keyframeprefix = '-' + pfx.toLowerCase() + '-';
991          animation = true;
992          break;
993        }
994      }
995    }
996
997    this.cssAnimationsSupport = animation;
998    return animation;
999  };
1000
1001  //  hardwareAccelerate();
1002  //    add fool-proof CSS3 hardware acceleration.
1003  Pep.prototype.hardwareAccelerate = function() {
1004    this.$el.css({
1005      '-webkit-perspective':          1000,
1006      'perspective':                  1000,
1007      '-webkit-backface-visibility':  'hidden',
1008      'backface-visibility':          'hidden'
1009    });
1010   };
1011
1012  //  getMovementValues();
1013  //    returns object pos, event position, and velocity in each direction.
1014  Pep.prototype.getMovementValues = function() {
1015    return { ev: this.ev, pos: this.pos, velocity: this.velocity() };
1016   };
1017
1018  //  buildDebugDiv();
1019  //    Create a little div in the lower right corner of the window
1020  //    for extra info about the object currently moving
1021  Pep.prototype.buildDebugDiv = function() {
1022
1023    // Build the debugDiv and it's inner HTML -- if necessary
1024    var $debugDiv;
1025    if ( $('#pep-debug').length === 0 ){
1026      $debugDiv = $('<div></div>');
1027      $debugDiv
1028        .attr('id', 'pep-debug')
1029        .append("<div style='font-weight:bold; background: red; color: white;'>DEBUG MODE</div>")
1030        .append("<div id='pep-debug-event'>no event</div>")
1031        .append("<div id='pep-debug-ev-coords'>event coords: <span class='pep-x'>-</span>, <span class='pep-y'>-</span></div>")
1032        .append("<div id='pep-debug-pos-coords'>position coords: <span class='pep-x'>-</span>, <span class='pep-y'>-</span></div>")
1033        .append("<div id='pep-debug-velocity'>velocity: <span class='pep-x'>-</span>, <span class='pep-y'>-</span></div>")
1034        .append("<div id='pep-debug-delta'>&Delta; movement: <span class='pep-x'>-</span>, <span class='pep-y'>-</span></div>")
1035        .css({
1036          position:   'fixed',
1037          bottom:     5,
1038          right:      5,
1039          zIndex:     99999,
1040          textAlign:  'right',
1041          fontFamily: 'Arial, sans',
1042          fontSize:   10,
1043          border:     '1px solid #DDD',
1044          padding:    '3px',
1045          background: 'white',
1046          color:      '#333'
1047        });
1048    }
1049
1050    var self = this;
1051    setTimeout(function(){
1052      self.debugElements = {
1053        $event:      $("#pep-debug-event"),
1054        $velocityX:  $("#pep-debug-velocity .pep-x"),
1055        $velocityY:  $("#pep-debug-velocity .pep-y"),
1056        $dX:         $("#pep-debug-delta .pep-x"),
1057        $dY:         $("#pep-debug-delta .pep-y"),
1058        $evCoordsX:  $("#pep-debug-ev-coords .pep-x"),
1059        $evCoordsY:  $("#pep-debug-ev-coords .pep-y"),
1060        $posCoordsX: $("#pep-debug-pos-coords .pep-x"),
1061        $posCoordsY: $("#pep-debug-pos-coords .pep-y")
1062      };
1063    }, 0);
1064
1065    $('body').append( $debugDiv );
1066  };
1067
1068  // log()
1069  Pep.prototype.log = function(opts) {
1070    if ( !this.options.debug ) return;
1071
1072    switch (opts.type){
1073    case "event":
1074      this.debugElements.$event.text(opts.event);
1075      break;
1076    case "pos-coords":
1077      this.debugElements.$posCoordsX.text(opts.x);
1078      this.debugElements.$posCoordsY.text(opts.y);
1079      break;
1080    case "event-coords":
1081      this.debugElements.$evCoordsX.text(opts.x);
1082      this.debugElements.$evCoordsY.text(opts.y);
1083      break;
1084    case "delta":
1085      this.debugElements.$dX.text(opts.x);
1086      this.debugElements.$dY.text(opts.y);
1087      break;
1088    case "velocity":
1089      var vel = this.velocity();
1090      this.debugElements.$velocityX.text( Math.round(vel.x) );
1091      this.debugElements.$velocityY.text( Math.round(vel.y) );
1092      break;
1093    }
1094  };
1095
1096  // toggle()
1097  //  toggle the pep object
1098  Pep.prototype.toggle = function(on) {
1099    if ( typeof(on) === "undefined"){
1100      this.disabled = !this.disabled;
1101    }
1102    else {
1103      this.disabled = !on;
1104    }
1105  };
1106
1107  //  *** Special Easings functions ***
1108  //    Used for JS easing fallback
1109  //    We can use any of these for a
1110  //    good intertia ease
1111  $.extend($.easing,
1112  {
1113    easeOutQuad: function (x, t, b, c, d) {
1114      return -c *(t/=d)*(t-2) + b;
1115    },
1116    easeOutCirc: function (x, t, b, c, d) {
1117      return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
1118    },
1119    easeOutExpo: function (x, t, b, c, d) {
1120      return (t===d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
1121    }
1122  });
1123
1124  //  wrap it
1125  //    A really lightweight plugin wrapper around the constructor,
1126  //    preventing against multiple instantiations.
1127  $.fn[pluginName] = function ( options ) {
1128    return this.each(function () {
1129      if (!$.data(this, 'plugin_' + pluginName)) {
1130        var pepObj = new Pep( this, options );
1131        $.data(this, 'plugin_' + pluginName, pepObj);
1132        $.pep.peps.push(pepObj);
1133      }
1134    });
1135  };
1136
1137  //  The   _   ___ ___
1138  //       /_\ | _ \_ _|
1139  //      / _ \|  _/| |
1140  //     /_/ \_\_| |___|
1141  //
1142  $.pep = {};
1143  $.pep.peps = [];
1144  $.pep.toggleAll = function(on){
1145    $.each(this.peps, function(index, pepObj){
1146      pepObj.toggle(on);
1147    });
1148  };
1149
1150  $.pep.unbind = function($obj){
1151    var pep = $obj.data('plugin_' + pluginName);
1152
1153    if ( typeof pep === 'undefined' )
1154      return;
1155
1156    pep.toggle(false);
1157    pep.unsubscribe();
1158    $obj.removeData('plugin_' + pluginName);
1159
1160  };
1161
1162}(jQuery, window));
1163
1164
1165
1166

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.