PageSourceSearch

https://www.adriacats.ru/js/addons/adria_design/plugins/jquery.twentytwenty.js?ver=4.5.1.SP1

js adriacats.ru collected 2026-10-01 16:37:43 UTC 20,900 bytes, 752 lines download raw bytes

1// DOM.event.move
2//
3// 2.0.0
4//
5// Stephen Band
6//
7// Triggers 'movestart', 'move' and 'moveend' events after
8// mousemoves following a mousedown cross a distance threshold,
9// similar to the native 'dragstart', 'drag' and 'dragend' events.
10// Move events are throttled to animation frames. Move event objects
11// have the properties:
12//
13// pageX:
14// pageY:     Page coordinates of pointer.
15// startX:
16// startY:    Page coordinates of pointer at movestart.
17// distX:
18// distY:     Distance the pointer has moved since movestart.
19// deltaX:
20// deltaY:    Distance the finger has moved since last event.
21// velocityX:
22// velocityY: Average velocity over last few events.
23
24
25(function(fn) {
26  if (typeof define === 'function' && define.amd) {
27    define([], fn);
28  } else if ((typeof module !== "undefined" && module !== null) && module.exports) {
29    module.exports = fn;
30  } else {
31    fn();
32  }
33})(function(){
34  var assign = Object.assign || window.jQuery && jQuery.extend;
35
36  // Number of pixels a pressed pointer travels before movestart
37  // event is fired.
38  var threshold = 8;
39
40  // Shim for requestAnimationFrame, falling back to timer. See:
41  // see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
42  var requestFrame = (function(){
43    return (
44        window.requestAnimationFrame ||
45        window.webkitRequestAnimationFrame ||
46        window.mozRequestAnimationFrame ||
47        window.oRequestAnimationFrame ||
48        window.msRequestAnimationFrame ||
49        function(fn, element){
50          return window.setTimeout(function(){
51            fn();
52          }, 25);
53        }
54    );
55  })();
56
57  // Shim for customEvent
58  // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
59  (function () {
60    if ( typeof window.CustomEvent === "function" ) return false;
61    function CustomEvent ( event, params ) {
62      params = params || { bubbles: false, cancelable: false, detail: undefined };
63      var evt = document.createEvent( 'CustomEvent' );
64      evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
65      return evt;
66    }
67
68    CustomEvent.prototype = window.Event.prototype;
69    window.CustomEvent = CustomEvent;
70  })();
71
72  var ignoreTags = {
73    textarea: true,
74    input: true,
75    select: true,
76    button: true
77  };
78
79  var mouseevents = {
80    move:   'mousemove',
81    cancel: 'mouseup dragstart',
82    end:    'mouseup'
83  };
84
85  var touchevents = {
86    move:   'touchmove',
87    cancel: 'touchend',
88    end:    'touchend'
89  };
90
91  var rspaces = /\s+/;
92
93
94  // DOM Events
95
96  var eventOptions = { bubbles: true, cancelable: true };
97
98  var eventsSymbol = typeof Symbol === "function" ? Symbol('events') : {};
99
100  function createEvent(type) {
101    return new CustomEvent(type, eventOptions);
102  }
103
104  function getEvents(node) {
105    return node[eventsSymbol] || (node[eventsSymbol] = {});
106  }
107
108  function on(node, types, fn, data, selector) {
109    types = types.split(rspaces);
110
111    var events = getEvents(node);
112    var i = types.length;
113    var handlers, type;
114
115    function handler(e) { fn(e, data); }
116
117    while (i--) {
118      type = types[i];
119      handlers = events[type] || (events[type] = []);
120      handlers.push([fn, handler]);
121      node.addEventListener(type, handler);
122    }
123  }
124
125  function off(node, types, fn, selector) {
126    types = types.split(rspaces);
127
128    var events = getEvents(node);
129    var i = types.length;
130    var type, handlers, k;
131
132    if (!events) { return; }
133
134    while (i--) {
135      type = types[i];
136      handlers = events[type];
137      if (!handlers) { continue; }
138      k = handlers.length;
139      while (k--) {
140        if (handlers[k][0] === fn) {
141          node.removeEventListener(type, handlers[k][1]);
142          handlers.splice(k, 1);
143        }
144      }
145    }
146  }
147
148  function trigger(node, type, properties) {
149    // Don't cache events. It prevents you from triggering an event of a
150    // given type from inside the handler of another event of that type.
151    var event = createEvent(type);
152    if (properties) { assign(event, properties); }
153    node.dispatchEvent(event);
154  }
155
156
157  // Constructors
158
159  function Timer(fn){
160    var callback = fn,
161        active = false,
162        running = false;
163
164    function trigger(time) {
165      if (active){
166        callback();
167        requestFrame(trigger);
168        running = true;
169        active = false;
170      }
171      else {
172        running = false;
173      }
174    }
175
176    this.kick = function(fn) {
177      active = true;
178      if (!running) { trigger(); }
179    };
180
181    this.end = function(fn) {
182      var cb = callback;
183
184      if (!fn) { return; }
185
186      // If the timer is not running, simply call the end callback.
187      if (!running) {
188        fn();
189      }
190      // If the timer is running, and has been kicked lately, then
191      // queue up the current callback and the end callback, otherwise
192      // just the end callback.
193      else {
194        callback = active ?
195            function(){ cb(); fn(); } :
196            fn ;
197
198        active = true;
199      }
200    };
201  }
202
203
204  // Functions
205
206  function noop() {}
207
208  function preventDefault(e) {
209    e.preventDefault();
210  }
211
212  function isIgnoreTag(e) {
213    return !!ignoreTags[e.target.tagName.toLowerCase()];
214  }
215
216  function isPrimaryButton(e) {
217    // Ignore mousedowns on any button other than the left (or primary)
218    // mouse button, or when a modifier key is pressed.
219    return (e.which === 1 && !e.ctrlKey && !e.altKey);
220  }
221
222  function identifiedTouch(touchList, id) {
223    var i, l;
224
225    if (touchList.identifiedTouch) {
226      return touchList.identifiedTouch(id);
227    }
228
229    // touchList.identifiedTouch() does not exist in
230    // webkit yet… we must do the search ourselves...
231
232    i = -1;
233    l = touchList.length;
234
235    while (++i < l) {
236      if (touchList[i].identifier === id) {
237        return touchList[i];
238      }
239    }
240  }
241
242  function changedTouch(e, data) {
243    var touch = identifiedTouch(e.changedTouches, data.identifier);
244
245    // This isn't the touch you're looking for.
246    if (!touch) { return; }
247
248    // Chrome Android (at least) includes touches that have not
249    // changed in e.changedTouches. That's a bit annoying. Check
250    // that this touch has changed.
251    if (touch.pageX === data.pageX && touch.pageY === data.pageY) { return; }
252
253    return touch;
254  }
255
256
257  // Handlers that decide when the first movestart is triggered
258
259  function mousedown(e){
260    // Ignore non-primary buttons
261    if (!isPrimaryButton(e)) { return; }
262
263    // Ignore form and interactive elements
264    if (isIgnoreTag(e)) { return; }
265
266    on(document, mouseevents.move, mousemove, e);
267    on(document, mouseevents.cancel, mouseend, e);
268  }
269
270  function mousemove(e, data){
271    checkThreshold(e, data, e, removeMouse);
272  }
273
274  function mouseend(e, data) {
275    removeMouse();
276  }
277
278  function removeMouse() {
279    off(document, mouseevents.move, mousemove);
280    off(document, mouseevents.cancel, mouseend);
281  }
282
283  function touchstart(e) {
284    // Don't get in the way of interaction with form elements
285    if (ignoreTags[e.target.tagName.toLowerCase()]) { return; }
286
287    var touch = e.changedTouches[0];
288
289    // iOS live updates the touch objects whereas Android gives us copies.
290    // That means we can't trust the touchstart object to stay the same,
291    // so we must copy the data. This object acts as a template for
292    // movestart, move and moveend event objects.
293    var data = {
294      target:     touch.target,
295      pageX:      touch.pageX,
296      pageY:      touch.pageY,
297      identifier: touch.identifier,
298
299      // The only way to make handlers individually unbindable is by
300      // making them unique.
301      touchmove:  function(e, data) { touchmove(e, data); },
302      touchend:   function(e, data) { touchend(e, data); }
303    };
304
305    on(document, touchevents.move, data.touchmove, data);
306    on(document, touchevents.cancel, data.touchend, data);
307  }
308
309  function touchmove(e, data) {
310    var touch = changedTouch(e, data);
311    if (!touch) { return; }
312    checkThreshold(e, data, touch, removeTouch);
313  }
314
315  function touchend(e, data) {
316    var touch = identifiedTouch(e.changedTouches, data.identifier);
317    if (!touch) { return; }
318    removeTouch(data);
319  }
320
321  function removeTouch(data) {
322    off(document, touchevents.move, data.touchmove);
323    off(document, touchevents.cancel, data.touchend);
324  }
325
326  function checkThreshold(e, data, touch, fn) {
327    var distX = touch.pageX - data.pageX;
328    var distY = touch.pageY - data.pageY;
329
330    // Do nothing if the threshold has not been crossed.
331    if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; }
332
333    triggerStart(e, data, touch, distX, distY, fn);
334  }
335
336  function triggerStart(e, data, touch, distX, distY, fn) {
337    var touches = e.targetTouches;
338    var time = e.timeStamp - data.timeStamp;
339
340    // Create a movestart object with some special properties that
341    // are passed only to the movestart handlers.
342    var template = {
343      altKey:     e.altKey,
344      ctrlKey:    e.ctrlKey,
345      shiftKey:   e.shiftKey,
346      startX:     data.pageX,
347      startY:     data.pageY,
348      distX:      distX,
349      distY:      distY,
350      deltaX:     distX,
351      deltaY:     distY,
352      pageX:      touch.pageX,
353      pageY:      touch.pageY,
354      velocityX:  distX / time,
355      velocityY:  distY / time,
356      identifier: data.identifier,
357      targetTouches: touches,
358      finger: touches ? touches.length : 1,
359      enableMove: function() {
360        this.moveEnabled = true;
361        this.enableMove = noop;
362        e.preventDefault();
363      }
364    };
365
366    // Trigger the movestart event.
367    trigger(data.target, 'movestart', template);
368
369    // Unbind handlers that tracked the touch or mouse up till now.
370    fn(data);
371  }
372
373
374  // Handlers that control what happens following a movestart
375
376  function activeMousemove(e, data) {
377    var timer  = data.timer;
378
379    data.touch = e;
380    data.timeStamp = e.timeStamp;
381    timer.kick();
382  }
383
384  function activeMouseend(e, data) {
385    var target = data.target;
386    var event  = data.event;
387    var timer  = data.timer;
388
389    removeActiveMouse();
390
391    endEvent(target, event, timer, function() {
392      // Unbind the click suppressor, waiting until after mouseup
393      // has been handled.
394      setTimeout(function(){
395        off(target, 'click', preventDefault);
396      }, 0);
397    });
398  }
399
400  function removeActiveMouse() {
401    off(document, mouseevents.move, activeMousemove);
402    off(document, mouseevents.end, activeMouseend);
403  }
404
405  function activeTouchmove(e, data) {
406    var event = data.event;
407    var timer = data.timer;
408    var touch = changedTouch(e, event);
409
410    if (!touch) { return; }
411
412    // Stop the interface from gesturing
413    e.preventDefault();
414
415    event.targetTouches = e.targetTouches;
416    data.touch = touch;
417    data.timeStamp = e.timeStamp;
418
419    timer.kick();
420  }
421
422  function activeTouchend(e, data) {
423    var target = data.target;
424    var event  = data.event;
425    var timer  = data.timer;
426    var touch  = identifiedTouch(e.changedTouches, event.identifier);
427
428    // This isn't the touch you're looking for.
429    if (!touch) { return; }
430
431    removeActiveTouch(data);
432    endEvent(target, event, timer);
433  }
434
435  function removeActiveTouch(data) {
436    off(document, touchevents.move, data.activeTouchmove);
437    off(document, touchevents.end, data.activeTouchend);
438  }
439
440
441  // Logic for triggering move and moveend events
442
443  function updateEvent(event, touch, timeStamp) {
444    var time = timeStamp - event.timeStamp;
445
446    event.distX =  touch.pageX - event.startX;
447    event.distY =  touch.pageY - event.startY;
448    event.deltaX = touch.pageX - event.pageX;
449    event.deltaY = touch.pageY - event.pageY;
450
451    // Average the velocity of the last few events using a decay
452    // curve to even out spurious jumps in values.
453    event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time;
454    event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time;
455    event.pageX =  touch.pageX;
456    event.pageY =  touch.pageY;
457  }
458
459  function endEvent(target, event, timer, fn) {
460    timer.end(function(){
461      trigger(target, 'moveend', event);
462      return fn && fn();
463    });
464  }
465
466
467  // Set up the DOM
468
469  function movestart(e) {
470    if (e.defaultPrevented) { return; }
471    if (!e.moveEnabled) { return; }
472
473    var event = {
474      startX:        e.startX,
475      startY:        e.startY,
476      pageX:         e.pageX,
477      pageY:         e.pageY,
478      distX:         e.distX,
479      distY:         e.distY,
480      deltaX:        e.deltaX,
481      deltaY:        e.deltaY,
482      velocityX:     e.velocityX,
483      velocityY:     e.velocityY,
484      identifier:    e.identifier,
485      targetTouches: e.targetTouches,
486      finger:        e.finger
487    };
488
489    var data = {
490      target:    e.target,
491      event:     event,
492      timer:     new Timer(update),
493      touch:     undefined,
494      timeStamp: e.timeStamp
495    };
496
497    function update(time) {
498      updateEvent(event, data.touch, data.timeStamp);
499      trigger(data.target, 'move', event);
500    }
501
502    if (e.identifier === undefined) {
503      // We're dealing with a mouse event.
504      // Stop clicks from propagating during a move
505      on(e.target, 'click', preventDefault);
506      on(document, mouseevents.move, activeMousemove, data);
507      on(document, mouseevents.end, activeMouseend, data);
508    }
509    else {
510      // In order to unbind correct handlers they have to be unique
511      data.activeTouchmove = function(e, data) { activeTouchmove(e, data); };
512      data.activeTouchend = function(e, data) { activeTouchend(e, data); };
513
514      // We're dealing with a touch.
515      on(document, touchevents.move, data.activeTouchmove, data);
516      on(document, touchevents.end, data.activeTouchend, data);
517    }
518  }
519
520  on(document, 'mousedown', mousedown);
521  on(document, 'touchstart', touchstart);
522  on(document, 'movestart', movestart);
523
524
525  // jQuery special events
526  //
527  // jQuery event objects are copies of DOM event objects. They need
528  // a little help copying the move properties across.
529
530  if (!window.jQuery) { return; }
531
532  var properties = ("startX startY pageX pageY distX distY deltaX deltaY velocityX velocityY").split(' ');
533
534  function enableMove1(e) { e.enableMove(); }
535  function enableMove2(e) { e.enableMove(); }
536  function enableMove3(e) { e.enableMove(); }
537
538  function add(handleObj) {
539    var handler = handleObj.handler;
540
541    handleObj.handler = function(e) {
542      // Copy move properties across from originalEvent
543      var i = properties.length;
544      var property;
545
546      while(i--) {
547        property = properties[i];
548        e[property] = e.originalEvent[property];
549      }
550
551      handler.apply(this, arguments);
552    };
553  }
554
555  jQuery.event.special.movestart = {
556    setup: function() {
557      // Movestart must be enabled to allow other move events
558      on(this, 'movestart', enableMove1);
559
560      // Do listen to DOM events
561      return false;
562    },
563
564    teardown: function() {
565      off(this, 'movestart', enableMove1);
566      return false;
567    },
568
569    add: add
570  };
571
572  jQuery.event.special.move = {
573    setup: function() {
574      on(this, 'movestart', enableMove2);
575      return false;
576    },
577
578    teardown: function() {
579      off(this, 'movestart', enableMove2);
580      return false;
581    },
582
583    add: add
584  };
585
586  jQuery.event.special.moveend = {
587    setup: function() {
588      on(this, 'movestart', enableMove3);
589      return false;
590    },
591
592    teardown: function() {
593      off(this, 'movestart', enableMove3);
594      return false;
595    },
596
597    add: add
598  };
599});
600
601(function($){
602
603  $.fn.twentytwenty = function(options) {
604    var options = $.extend({
605      default_offset_pct: 0.5,
606      orientation: 'horizontal',
607      before_label: 'Before',
608      after_label: 'After',
609      no_overlay: false,
610      move_slider_on_hover: false,
611      move_with_handle_only: true,
612      click_to_move: false
613    }, options);
614
615    return this.each(function() {
616
617      var sliderPct = options.default_offset_pct;
618      var container = $(this);
619      var sliderOrientation = options.orientation;
620      var beforeDirection = (sliderOrientation === 'vertical') ? 'down' : 'left';
621      var afterDirection = (sliderOrientation === 'vertical') ? 'up' : 'right';
622
623
624      container.wrap("<div class='twentytwenty-wrapper twentytwenty-" + sliderOrientation + "'></div>");
625      if(!options.no_overlay) {
626        container.append("<div class='twentytwenty-overlay'></div>");
627      }
628      var beforeImg = container.find("img:first");
629      var afterImg = container.find("img:last");
630      container.append("<div class='twentytwenty-handle'></div>");
631      var slider = container.find(".twentytwenty-handle");
632      slider.append("<span class='twentytwenty-" + beforeDirection + "-arrow'></span>");
633      slider.append("<span class='twentytwenty-" + afterDirection + "-arrow'></span>");
634      container.addClass("twentytwenty-container");
635      beforeImg.addClass("twentytwenty-before");
636      afterImg.addClass("twentytwenty-after");
637
638      var overlay = container.find(".twentytwenty-overlay");
639      overlay.append("<div class='twentytwenty-before-label' data-content='"+options.before_label+"'></div>");
640      overlay.append("<div class='twentytwenty-after-label' data-content='"+options.after_label+"'></div>");
641
642      var calcOffset = function(dimensionPct) {
643        var w = beforeImg.width();
644        var h = beforeImg.height();
645        return {
646          w: w+"px",
647          h: h+"px",
648          cw: (dimensionPct*w)+"px",
649          ch: (dimensionPct*h)+"px"
650        };
651      };
652
653      var adjustContainer = function(offset) {
654      	if (sliderOrientation === 'vertical') {
655          beforeImg.css("clip", "rect(0,"+offset.w+","+offset.ch+",0)");
656          afterImg.css("clip", "rect("+offset.ch+","+offset.w+","+offset.h+",0)");
657      	}
658      	else {
659          beforeImg.css("clip", "rect(0,"+offset.cw+","+offset.h+",0)");
660          afterImg.css("clip", "rect(0,"+offset.w+","+offset.h+","+offset.cw+")");
661    	}
662        container.css("height", offset.h);
663      };
664
665      var adjustSlider = function(pct) {
666        var offset = calcOffset(pct);
667        slider.css((sliderOrientation==="vertical") ? "top" : "left", (sliderOrientation==="vertical") ? offset.ch : offset.cw);
668        adjustContainer(offset);
669      };
670
671      // Return the number specified or the min/max number if it outside the range given.
672      var minMaxNumber = function(num, min, max) {
673        return Math.max(min, Math.min(max, num));
674      };
675
676      // Calculate the slider percentage based on the position.
677      var getSliderPercentage = function(positionX, positionY) {
678        var sliderPercentage = (sliderOrientation === 'vertical') ?
679          (positionY-offsetY)/imgHeight :
680          (positionX-offsetX)/imgWidth;
681
682        return minMaxNumber(sliderPercentage, 0, 1);
683      };
684
685
686      $(window).on("resize.twentytwenty", function(e) {
687        adjustSlider(sliderPct);
688      });
689
690      var offsetX = 0;
691      var offsetY = 0;
692      var imgWidth = 0;
693      var imgHeight = 0;
694      var onMoveStart = function(e) {
695        if (((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) && sliderOrientation !== 'vertical') {
696          e.preventDefault();
697        }
698        else if (((e.distX < e.distY && e.distX < -e.distY) || (e.distX > e.distY && e.distX > -e.distY)) && sliderOrientation === 'vertical') {
699          e.preventDefault();
700        }
701        container.addClass("active");
702        offsetX = container.offset().left;
703        offsetY = container.offset().top;
704        imgWidth = beforeImg.width(); 
705        imgHeight = beforeImg.height();          
706      };
707      var onMove = function(e) {
708        if (container.hasClass("active")) {
709          sliderPct = getSliderPercentage(e.pageX, e.pageY);
710          adjustSlider(sliderPct);
711        }
712      };
713      var onMoveEnd = function() {
714          container.removeClass("active");
715      };
716
717      var moveTarget = options.move_with_handle_only ? slider : container;
718      moveTarget.on("movestart",onMoveStart);
719      moveTarget.on("move",onMove);
720      moveTarget.on("moveend",onMoveEnd);
721
722      if (options.move_slider_on_hover) {
723        container.on("mouseenter", onMoveStart);
724        container.on("mousemove", onMove);
725        container.on("mouseleave", onMoveEnd);
726      }
727
728      slider.on("touchmove", function(e) {
729        e.preventDefault();
730      });
731
732      container.find("img").on("mousedown", function(event) {
733        event.preventDefault();
734      });
735
736      if (options.click_to_move) {
737        container.on('click', function(e) {
738          offsetX = container.offset().left;
739          offsetY = container.offset().top;
740          imgWidth = beforeImg.width();
741          imgHeight = beforeImg.height();
742
743          sliderPct = getSliderPercentage(e.pageX, e.pageY);
744          adjustSlider(sliderPct);
745        });
746      }
747
748      $(window).trigger("resize.twentytwenty");
749    });
750  };
751
752})(jQuery);

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.