PageSourceSearch

https://morad.pl/wp-content/themes/theratio/js/before-after.js?ver=20180910

js morad.pl collected 2026-10-08 22:37:44 UTC 21,460 bytes, 750 lines download raw bytes

1/*DOM.event.move
2
32.0.0
4
5Stephen Band
6
7Triggers 'movestart', 'move' and 'moveend' events after
8mousemoves following a mousedown cross a distance threshold,
9similar to the native 'dragstart', 'drag' and 'dragend' events.
10Move events are throttled to animation frames. Move event objects
11have the properties:
12
13pageX:
14pageY:     Page coordinates of pointer.
15startX:
16startY:    Page coordinates of pointer at movestart.
17distX:
18distY:     Distance the pointer has moved since movestart.
19deltaX:
20deltaY:    Distance the finger has moved since last event.
21velocityX:
22velocityY: 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  /*
526  * jQuery special events
527  * jQuery event objects are copies of DOM event objects. They need a little help copying the move properties across.
528  */
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  'use strict';
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: false,
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      var minMaxNumber = function(num, min, max) {
672        return Math.max(min, Math.min(max, num));
673      };
674
675      var getSliderPercentage = function(positionX, positionY) {
676        var sliderPercentage = (sliderOrientation === 'vertical') ?
677          (positionY-offsetY)/imgHeight :
678          (positionX-offsetX)/imgWidth;
679
680        return minMaxNumber(sliderPercentage, 0, 1);
681      };
682
683
684      $(window).on("resize.twentytwenty", function(e) {
685        adjustSlider(sliderPct);
686      });
687
688      var offsetX = 0;
689      var offsetY = 0;
690      var imgWidth = 0;
691      var imgHeight = 0;
692      var onMoveStart = function(e) {
693        if (((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) && sliderOrientation !== 'vertical') {
694          e.preventDefault();
695        }
696        else if (((e.distX < e.distY && e.distX < -e.distY) || (e.distX > e.distY && e.distX > -e.distY)) && sliderOrientation === 'vertical') {
697          e.preventDefault();
698        }
699        container.addClass("active");
700        offsetX = container.offset().left;
701        offsetY = container.offset().top;
702        imgWidth = beforeImg.width(); 
703        imgHeight = beforeImg.height();          
704      };
705      var onMove = function(e) {
706        if (container.hasClass("active")) {
707          sliderPct = getSliderPercentage(e.pageX, e.pageY);
708          adjustSlider(sliderPct);
709        }
710      };
711      var onMoveEnd = function() {
712          container.removeClass("active");
713      };
714
715      var moveTarget = options.move_with_handle_only ? slider : container;
716      moveTarget.on("movestart",onMoveStart);
717      moveTarget.on("move",onMove);
718      moveTarget.on("moveend",onMoveEnd);
719
720      if (options.move_slider_on_hover) {
721        container.on("mouseenter", onMoveStart);
722        container.on("mousemove", onMove);
723        container.on("mouseleave", onMoveEnd);
724      }
725
726      slider.on("touchmove", function(e) {
727        e.preventDefault();
728      });
729
730      container.find("img").on("mousedown", function(event) {
731        event.preventDefault();
732      });
733
734      if (options.click_to_move) {
735        container.on('click', function(e) {
736          offsetX = container.offset().left;
737          offsetY = container.offset().top;
738          imgWidth = beforeImg.width();
739          imgHeight = beforeImg.height();
740
741          sliderPct = getSliderPercentage(e.pageX, e.pageY);
742          adjustSlider(sliderPct);
743        });
744      }
745
746      $(window).trigger("resize.twentytwenty");
747    });
748  };
749
750})(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.