PageSourceSearch

https://www.canaltrust.org/wp-content/plugins/salient-core/js/third-party/jquery.twentytwenty.js?ver=1.9.9

js canaltrust.org collected 2026-09-24 08:55:26 UTC 19,453 bytes, 691 lines download raw bytes

1// jquery.event.move
2//
3// 1.3.6
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 (module) {
26  if (typeof define === 'function' && define.amd) {
27    // AMD. Register as an anonymous module.
28    define(['jquery'], module);
29  } else {
30    // Browser globals
31    module(jQuery);
32  }
33})(function(jQuery, undefined){
34
35  var // Number of pixels a pressed pointer travels before movestart
36      // event is fired.
37      threshold = 6,
38  
39      add = jQuery.event.add,
40  
41      remove = jQuery.event.remove,
42
43      // Just sugar, so we can have arguments in the same order as
44      // add and remove.
45      trigger = function(node, type, data) {
46        jQuery.event.trigger(type, data, node);
47      },
48
49      // Shim for requestAnimationFrame, falling back to timer. See:
50      // see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
51      requestFrame = (function(){
52        return (
53          window.requestAnimationFrame ||
54          window.webkitRequestAnimationFrame ||
55          window.mozRequestAnimationFrame ||
56          window.oRequestAnimationFrame ||
57          window.msRequestAnimationFrame ||
58          function(fn, element){
59            return window.setTimeout(function(){
60              fn();
61            }, 25);
62          }
63        );
64      })(),
65      
66      ignoreTags = {
67        textarea: true,
68        input: true,
69        select: true,
70        button: true
71      },
72      
73      mouseevents = {
74        move: 'mousemove',
75        cancel: 'mouseup dragstart',
76        end: 'mouseup'
77      },
78      
79      touchevents = {
80        move: 'touchmove',
81        cancel: 'touchend',
82        end: 'touchend'
83      };
84
85
86  // Constructors
87  
88  function Timer(fn){
89    var callback = fn,
90        active = false,
91        running = false;
92    
93    function trigger(time) {
94      if (active){
95        callback();
96        requestFrame(trigger);
97        running = true;
98        active = false;
99      }
100      else {
101        running = false;
102      }
103    }
104    
105    this.kick = function(fn) {
106      active = true;
107      if (!running) { trigger(); }
108    };
109    
110    this.end = function(fn) {
111      var cb = callback;
112      
113      if (!fn) { return; }
114      
115      // If the timer is not running, simply call the end callback.
116      if (!running) {
117        fn();
118      }
119      // If the timer is running, and has been kicked lately, then
120      // queue up the current callback and the end callback, otherwise
121      // just the end callback.
122      else {
123        callback = active ?
124          function(){ cb(); fn(); } : 
125          fn ;
126        
127        active = true;
128      }
129    };
130  }
131
132
133  // Functions
134  
135  function returnTrue() {
136    return true;
137  }
138  
139  function returnFalse() {
140    return false;
141  }
142  
143  function preventDefault(e) {
144    e.preventDefault();
145  }
146  
147  function preventIgnoreTags(e) {
148    // Don't prevent interaction with form elements.
149    if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; }
150    
151    e.preventDefault();
152  }
153
154  function isLeftButton(e) {
155    // Ignore mousedowns on any button other than the left (or primary)
156    // mouse button, or when a modifier key is pressed.
157    return (e.which === 1 && !e.ctrlKey && !e.altKey);
158  }
159
160  function identifiedTouch(touchList, id) {
161    var i, l;
162
163    if (touchList.identifiedTouch) {
164      return touchList.identifiedTouch(id);
165    }
166    
167    // touchList.identifiedTouch() does not exist in
168    // webkit yet… we must do the search ourselves...
169    
170    i = -1;
171    l = touchList.length;
172    
173    while (++i < l) {
174      if (touchList[i].identifier === id) {
175        return touchList[i];
176      }
177    }
178  }
179
180  function changedTouch(e, event) {
181    var touch = identifiedTouch(e.changedTouches, event.identifier);
182
183    // This isn't the touch you're looking for.
184    if (!touch) { return; }
185
186    // Chrome Android (at least) includes touches that have not
187    // changed in e.changedTouches. That's a bit annoying. Check
188    // that this touch has changed.
189    if (touch.pageX === event.pageX && touch.pageY === event.pageY) { return; }
190
191    return touch;
192  }
193
194
195  // Handlers that decide when the first movestart is triggered
196  
197  function mousedown(e){
198    var data;
199
200    if (!isLeftButton(e)) { return; }
201
202    data = {
203      target: e.target,
204      startX: e.pageX,
205      startY: e.pageY,
206      timeStamp: e.timeStamp
207    };
208
209    add(document, mouseevents.move, mousemove, data);
210    add(document, mouseevents.cancel, mouseend, data);
211  }
212
213  function mousemove(e){
214    var data = e.data;
215
216    checkThreshold(e, data, e, removeMouse);
217  }
218
219  function mouseend(e) {
220    removeMouse();
221  }
222
223  function removeMouse() {
224    remove(document, mouseevents.move, mousemove);
225    remove(document, mouseevents.cancel, mouseend);
226  }
227
228  function touchstart(e) {
229    var touch, template;
230
231    // Don't get in the way of interaction with form elements.
232    if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; }
233
234    touch = e.changedTouches[0];
235    
236    // iOS live updates the touch objects whereas Android gives us copies.
237    // That means we can't trust the touchstart object to stay the same,
238    // so we must copy the data. This object acts as a template for
239    // movestart, move and moveend event objects.
240    template = {
241      target: touch.target,
242      startX: touch.pageX,
243      startY: touch.pageY,
244      timeStamp: e.timeStamp,
245      identifier: touch.identifier
246    };
247
248    // Use the touch identifier as a namespace, so that we can later
249    // remove handlers pertaining only to this touch.
250    add(document, touchevents.move + '.' + touch.identifier, touchmove, template);
251    add(document, touchevents.cancel + '.' + touch.identifier, touchend, template);
252  }
253
254  function touchmove(e){
255    var data = e.data,
256        touch = changedTouch(e, data);
257
258    if (!touch) { return; }
259
260    checkThreshold(e, data, touch, removeTouch);
261  }
262
263  function touchend(e) {
264    var template = e.data,
265        touch = identifiedTouch(e.changedTouches, template.identifier);
266
267    if (!touch) { return; }
268
269    removeTouch(template.identifier);
270  }
271
272  function removeTouch(identifier) {
273    remove(document, '.' + identifier, touchmove);
274    remove(document, '.' + identifier, touchend);
275  }
276
277
278  // Logic for deciding when to trigger a movestart.
279
280  function checkThreshold(e, template, touch, fn) {
281    var distX = touch.pageX - template.startX,
282        distY = touch.pageY - template.startY;
283
284    // Do nothing if the threshold has not been crossed.
285    if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; }
286
287    triggerStart(e, template, touch, distX, distY, fn);
288  }
289
290  function handled() {
291    // this._handled should return false once, and after return true.
292    this._handled = returnTrue;
293    return false;
294  }
295
296  function flagAsHandled(e) {
297    e._handled();
298  }
299
300  function triggerStart(e, template, touch, distX, distY, fn) {
301    var node = template.target,
302        touches, time;
303
304    touches = e.targetTouches;
305    time = e.timeStamp - template.timeStamp;
306
307    // Create a movestart object with some special properties that
308    // are passed only to the movestart handlers.
309    template.type = 'movestart';
310    template.distX = distX;
311    template.distY = distY;
312    template.deltaX = distX;
313    template.deltaY = distY;
314    template.pageX = touch.pageX;
315    template.pageY = touch.pageY;
316    template.velocityX = distX / time;
317    template.velocityY = distY / time;
318    template.targetTouches = touches;
319    template.finger = touches ?
320      touches.length :
321      1 ;
322
323    // The _handled method is fired to tell the default movestart
324    // handler that one of the move events is bound.
325    template._handled = handled;
326      
327    // Pass the touchmove event so it can be prevented if or when
328    // movestart is handled.
329    template._preventTouchmoveDefault = function() {
330      e.preventDefault();
331    };
332
333    // Trigger the movestart event.
334    trigger(template.target, template);
335
336    // Unbind handlers that tracked the touch or mouse up till now.
337    fn(template.identifier);
338  }
339
340
341  // Handlers that control what happens following a movestart
342
343  function activeMousemove(e) {
344    var timer = e.data.timer;
345
346    e.data.touch = e;
347    e.data.timeStamp = e.timeStamp;
348    timer.kick();
349  }
350
351  function activeMouseend(e) {
352    var event = e.data.event,
353        timer = e.data.timer;
354    
355    removeActiveMouse();
356
357    endEvent(event, timer, function() {
358      // Unbind the click suppressor, waiting until after mouseup
359      // has been handled.
360      setTimeout(function(){
361        remove(event.target, 'click', returnFalse);
362      }, 0);
363    });
364  }
365
366  function removeActiveMouse(event) {
367    remove(document, mouseevents.move, activeMousemove);
368    remove(document, mouseevents.end, activeMouseend);
369  }
370
371  function activeTouchmove(e) {
372    var event = e.data.event,
373        timer = e.data.timer,
374        touch = changedTouch(e, event);
375
376    if (!touch) { return; }
377
378    // Stop the interface from gesturing
379    e.preventDefault();
380
381    event.targetTouches = e.targetTouches;
382    e.data.touch = touch;
383    e.data.timeStamp = e.timeStamp;
384    timer.kick();
385  }
386
387  function activeTouchend(e) {
388    var event = e.data.event,
389        timer = e.data.timer,
390        touch = identifiedTouch(e.changedTouches, event.identifier);
391
392    // This isn't the touch you're looking for.
393    if (!touch) { return; }
394
395    removeActiveTouch(event);
396    endEvent(event, timer);
397  }
398
399  function removeActiveTouch(event) {
400    remove(document, '.' + event.identifier, activeTouchmove);
401    remove(document, '.' + event.identifier, activeTouchend);
402  }
403
404
405  // Logic for triggering move and moveend events
406
407  function updateEvent(event, touch, timeStamp, timer) {
408    var time = timeStamp - event.timeStamp;
409
410    event.type = 'move';
411    event.distX =  touch.pageX - event.startX;
412    event.distY =  touch.pageY - event.startY;
413    event.deltaX = touch.pageX - event.pageX;
414    event.deltaY = touch.pageY - event.pageY;
415    
416    // Average the velocity of the last few events using a decay
417    // curve to even out spurious jumps in values.
418    event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time;
419    event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time;
420    event.pageX =  touch.pageX;
421    event.pageY =  touch.pageY;
422  }
423
424  function endEvent(event, timer, fn) {
425    timer.end(function(){
426      event.type = 'moveend';
427
428      trigger(event.target, event);
429      
430      return fn && fn();
431    });
432  }
433
434
435  // jQuery special event definition
436
437  function setup(data, namespaces, eventHandle) {
438    // Stop the node from being dragged
439    //add(this, 'dragstart.move drag.move', preventDefault);
440    
441    // Prevent text selection and touch interface scrolling
442    //add(this, 'mousedown.move', preventIgnoreTags);
443    
444    // Tell movestart default handler that we've handled this
445    add(this, 'movestart.move', flagAsHandled);
446
447    // Don't bind to the DOM. For speed.
448    return true;
449  }
450  
451  function teardown(namespaces) {
452    remove(this, 'dragstart drag', preventDefault);
453    remove(this, 'mousedown touchstart', preventIgnoreTags);
454    remove(this, 'movestart', flagAsHandled);
455    
456    // Don't bind to the DOM. For speed.
457    return true;
458  }
459  
460  function addMethod(handleObj) {
461    // We're not interested in preventing defaults for handlers that
462    // come from internal move or moveend bindings
463    if (handleObj.namespace === "move" || handleObj.namespace === "moveend") {
464      return;
465    }
466    
467    // Stop the node from being dragged
468    add(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid, preventDefault, undefined, handleObj.selector);
469    
470    // Prevent text selection and touch interface scrolling
471    add(this, 'mousedown.' + handleObj.guid, preventIgnoreTags, undefined, handleObj.selector);
472  }
473  
474  function removeMethod(handleObj) {
475    if (handleObj.namespace === "move" || handleObj.namespace === "moveend") {
476      return;
477    }
478    
479    remove(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid);
480    remove(this, 'mousedown.' + handleObj.guid);
481  }
482  
483  jQuery.event.special.movestart = {
484    setup: setup,
485    teardown: teardown,
486    add: addMethod,
487    remove: removeMethod,
488
489    _default: function(e) {
490      var event, data;
491      
492      // If no move events were bound to any ancestors of this
493      // target, high tail it out of here.
494      if (!e._handled()) { return; }
495
496      function update(time) {
497        updateEvent(event, data.touch, data.timeStamp);
498        trigger(e.target, event);
499      }
500
501      event = {
502        target: e.target,
503        startX: e.startX,
504        startY: e.startY,
505        pageX: e.pageX,
506        pageY: e.pageY,
507        distX: e.distX,
508        distY: e.distY,
509        deltaX: e.deltaX,
510        deltaY: e.deltaY,
511        velocityX: e.velocityX,
512        velocityY: e.velocityY,
513        timeStamp: e.timeStamp,
514        identifier: e.identifier,
515        targetTouches: e.targetTouches,
516        finger: e.finger
517      };
518
519      data = {
520        event: event,
521        timer: new Timer(update),
522        touch: undefined,
523        timeStamp: undefined
524      };
525      
526      if (e.identifier === undefined) {
527        // We're dealing with a mouse
528        // Stop clicks from propagating during a move
529        add(e.target, 'click', returnFalse);
530        add(document, mouseevents.move, activeMousemove, data);
531        add(document, mouseevents.end, activeMouseend, data);
532      }
533      else {
534        // We're dealing with a touch. Stop touchmove doing
535        // anything defaulty.
536        e._preventTouchmoveDefault();
537        add(document, touchevents.move + '.' + e.identifier, activeTouchmove, data);
538        add(document, touchevents.end + '.' + e.identifier, activeTouchend, data);
539      }
540    }
541  };
542
543  jQuery.event.special.move = {
544    setup: function() {
545      // Bind a noop to movestart. Why? It's the movestart
546      // setup that decides whether other move events are fired.
547      add(this, 'movestart.move', jQuery.noop);
548    },
549    
550    teardown: function() {
551      remove(this, 'movestart.move', jQuery.noop);
552    }
553  };
554  
555  jQuery.event.special.moveend = {
556    setup: function() {
557      // Bind a noop to movestart. Why? It's the movestart
558      // setup that decides whether other move events are fired.
559      add(this, 'movestart.moveend', jQuery.noop);
560    },
561    
562    teardown: function() {
563      remove(this, 'movestart.moveend', jQuery.noop);
564    }
565  };
566
567  add(document, 'mousedown.move', mousedown);
568  add(document, 'touchstart.move', touchstart);
569
570  // Make jQuery copy touch event properties over to the jQuery event
571  // object, if they are not already listed. But only do the ones we
572  // really need. IE7/8 do not have Array#indexOf(), but nor do they
573  // have touch events, so let's assume we can ignore them.
574  if (typeof Array.prototype.indexOf === 'function') {
575    (function(jQuery, undefined){
576      var props = ["changedTouches", "targetTouches"],
577          l = props.length;
578      
579      while (l--) {
580        if (jQuery.event.props.indexOf(props[l]) === -1) {
581          jQuery.event.props.push(props[l]);
582        }
583      }
584    })(jQuery);
585  };
586});
587
588
589(function($){
590
591  $.fn.twentytwenty = function(options) {
592    var options = $.extend({default_offset_pct: 0.5, orientation: 'horizontal'}, options);
593    return this.each(function() {
594
595      var sliderPct = options.default_offset_pct;
596      var container = $(this);
597      var sliderOrientation = options.orientation;
598      var beforeDirection = (sliderOrientation === 'vertical') ? 'down' : 'left';
599      var afterDirection = (sliderOrientation === 'vertical') ? 'up' : 'right';
600      
601      
602      container.wrap("<div class='twentytwenty-wrapper twentytwenty-" + sliderOrientation + "'></div>");
603      container.append("<div class='twentytwenty-overlay'></div>");
604      var beforeImg = container.find("img:first");
605      var afterImg = container.find("img:last");
606      container.append("<div class='twentytwenty-handle'></div>");
607      var slider = container.find(".twentytwenty-handle");
608      slider.append("<span class='twentytwenty-" + beforeDirection + "-arrow'></span>");
609      slider.append("<span class='twentytwenty-" + afterDirection + "-arrow'></span>");
610      container.addClass("twentytwenty-container");
611      beforeImg.addClass("twentytwenty-before");
612      afterImg.addClass("twentytwenty-after");
613      
614      var overlay = container.find(".twentytwenty-overlay");
615      overlay.append("<div class='twentytwenty-before-label'></div>");
616      overlay.append("<div class='twentytwenty-after-label'></div>");
617
618      var calcOffset = function(dimensionPct) {
619        var w = beforeImg.width();
620        var h = beforeImg.height();
621        return {
622          w: w+"px",
623          h: h+"px",
624          cw: (dimensionPct*w)+"px",
625          ch: (dimensionPct*h)+"px"
626        };
627      };
628
629      var adjustContainer = function(offset) {
630      	if (sliderOrientation === 'vertical') {
631      	  beforeImg.css("clip", "rect(0,"+offset.w+","+offset.ch+",0)");
632      	}
633      	else {
634          beforeImg.css("clip", "rect(0,"+offset.cw+","+offset.h+",0)");
635    	}
636        container.css("height", offset.h);
637      };
638
639      var adjustSlider = function(pct) {
640        var offset = calcOffset(pct);
641        slider.css((sliderOrientation==="vertical") ? "top" : "left", (sliderOrientation==="vertical") ? offset.ch : offset.cw);
642        adjustContainer(offset);
643      }
644
645      $(window).on("resize.twentytwenty", function(e) {
646        adjustSlider(sliderPct);
647      });
648
649      var offsetX = 0;
650      var imgWidth = 0;
651      
652      slider.on("movestart", function(e) {
653        if (((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) && sliderOrientation !== 'vertical') {
654          e.preventDefault();
655        }
656        else if (((e.distX < e.distY && e.distX < -e.distY) || (e.distX > e.distY && e.distX > -e.distY)) && sliderOrientation === 'vertical') {
657          e.preventDefault();
658        }
659        container.addClass("active");
660        offsetX = container.offset().left;
661        offsetY = container.offset().top;
662        imgWidth = beforeImg.width(); 
663        imgHeight = beforeImg.height();          
664      });
665
666      slider.on("moveend", function(e) {
667        container.removeClass("active");
668      });
669
670      slider.on("move", function(e) {
671        if (container.hasClass("active")) {
672          sliderPct = (sliderOrientation === 'vertical') ? (e.pageY-offsetY)/imgHeight : (e.pageX-offsetX)/imgWidth;
673          if (sliderPct < 0) {
674            sliderPct = 0;
675          }
676          if (sliderPct > 1) {
677            sliderPct = 1;
678          }
679          adjustSlider(sliderPct);
680        }
681      });
682
683      container.find("img").on("mousedown", function(event) {
684        event.preventDefault();
685      });
686
687      $(window).trigger("resize.twentytwenty");
688    });
689  };
690
691})(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.