PageSourceSearch

https://starrfoundation.org/wp-content/themes/starr/js/lib.js?ver=v1734626961

js starrfoundation.org collected 2026-10-02 04:07:30 UTC 20,342 bytes, 707 lines download raw bytes

1function wait_for_dimensions(jq, callback, iterations) {
2  if (typeof iterations == 'undefined') iterations = 0;
3
4  var item = jq.get(0);
5  if (typeof item.naturalWidth != 'undefined' && item.naturalWidth > 0) {
6    callback(item.naturalWidth, item.naturalHeight, iterations);
7  } else {
8    var me = this;
9    //slowly increase the time between each call
10    setTimeout(function () {
11      wait_for_dimensions(jq, callback, ++iterations);
12    }, iterations + 1);
13  }
14}
15
16function _get(selector, parent = document, makeArray = false) {
17  const found = Array.from(parent.querySelectorAll(selector));
18  if (!found) {
19    return false;
20  } else {
21    if (found.length > 1) {
22      return found;
23    } else {
24      if (makeArray) {
25        return found;
26      } else {
27        return found[0];
28      }
29    }
30  }
31}
32
33function image_zoom(container, src) {
34  var min_zoom = 1.5;
35  var max_zoom = 2.5;
36  var zoom = jQuery(
37    '<div class="image-zoom" style="position: absolute;z-index: 10000;top: 0;left: 0;right: 0;bottom: 0;overflow: hidden;background:black;"/>'
38  );
39  var img = jQuery('<img src="' + src + '" style="position:absolute;top:0;left:0;">');
40  var btn_close = jQuery(
41    '<div class="image-zoom-close" style="position:absolute;z-index:10001;top:0;right:0;cursor:pointer;"><span>X</span></div>'
42  );
43  var running = true;
44
45  zoom.append(img, btn_close);
46  container.append(zoom);
47
48  btn_close.click(function () {
49    if (running) {
50      running = false;
51      zoom.remove();
52    }
53  });
54
55  wait_for_dimensions(img, function (width, height) {
56    var container_width = zoom.width();
57    var container_height = zoom.height();
58
59    var max_width = container_width * max_zoom;
60    var max_height = container_height * max_zoom;
61    var min_width = container_width * min_zoom;
62    var min_height = container_height * min_zoom;
63
64    if (width > max_width) {
65      height = (max_width / width) * height;
66      width = max_width;
67    } else if (width < min_width) {
68      height = (min_width / width) * height;
69      width = min_width;
70    }
71    if (height > max_height) {
72      width = (max_height / height) * width;
73      height = max_height;
74    } else if (height < min_height) {
75      width = (min_height / height) * width;
76      height = min_height;
77    }
78
79    var top = (container_height - height) / 2;
80    var left = (container_width - width) / 2;
81    var min_left = -width + container_width;
82    var min_top = -height + container_height;
83    var updated_left = 0;
84    var updated_top = 0;
85
86    img.css({
87      width: width,
88      height: height,
89      top: top,
90      left: left,
91    });
92
93    track_movement(
94      zoom,
95      function () {},
96      function (x_delta, y_delta) {
97        updated_top = top + y_delta;
98        updated_left = left + x_delta;
99
100        if (updated_top > 0) updated_top = 0;
101        else if (updated_top < min_top) updated_top = min_top;
102        if (updated_left > 0) updated_left = 0;
103        else if (updated_left < min_left) updated_left = min_left;
104
105        img.css({
106          top: updated_top,
107          left: updated_left,
108        });
109      },
110      function () {
111        top = updated_top;
112        left = updated_left;
113      },
114      true
115    );
116  });
117}
118
119function track_movement(
120  jq,
121  start_callback,
122  move_callback,
123  release_callback,
124  track_mouse,
125  ignore_y
126) {
127  var is_down = false;
128  var start_x = 0;
129  var start_y = 0;
130  if (typeof ignore_y == 'undefined') ignore_y = false;
131  if (typeof track_mouse == 'undefined') track_mouse = false;
132  if (track_mouse)
133    jq.mouseleave(function () {
134      if (is_down) {
135        is_down = false;
136        setTimeout(function () {
137          jq.removeClass('noclick');
138        }, 125);
139        release_callback();
140      }
141    });
142  if (track_mouse)
143    jq.on('mousedown', function (ev) {
144      is_down = true;
145      start_x = ev.clientX;
146      start_y = ev.clientY;
147      start_callback(start_x, start_y);
148      return false;
149    });
150  if (track_mouse)
151    jq.on('mouseup', function (ev) {
152      if (is_down) {
153        is_down = false;
154        setTimeout(function () {
155          jq.removeClass('noclick');
156        }, 125);
157        release_callback();
158      }
159    });
160  if (track_mouse)
161    jq.on('mousemove', function (ev) {
162      if (is_down) {
163        var x_delta = ev.clientX - start_x;
164        var y_delta = ev.clientY - start_y;
165        move_callback(x_delta, y_delta, ev.clientX, ev.clientY);
166        jq.addClass('noclick');
167        return false;
168      }
169    });
170  jq.on('touchstart', function (ev) {
171    var touches = ev.originalEvent.touches;
172    if (touches.length >= 1) {
173      start_x = touches[0].clientX;
174      start_y = touches[0].clientY;
175      is_down = true;
176      start_callback(start_x, start_y);
177    }
178  });
179  jq.on('touchend', function (ev) {
180    if (is_down) {
181      is_down = false;
182      release_callback();
183    }
184  });
185  jq.on('touchmove', function (ev) {
186    var touches = ev.originalEvent.touches;
187    if (touches.length >= 1) {
188      var x_delta = touches[0].clientX - start_x;
189      var y_delta = touches[0].clientY - start_y;
190      if (ignore_y && Math.abs(y_delta) > Math.abs(x_delta)) {
191        return true;
192      }
193      move_callback(x_delta, y_delta, touches[0].clientX, touches[0].clientY);
194      ev.stopImmediatePropagation();
195      ev.preventDefault();
196      return false;
197    }
198  });
199}
200
201function getPageScroll() {
202  return document.body.scrollTop || jQuery(window).scrollTop();
203}
204
205function wait_for_visible(jq, callback, delay_callback) {
206  if (jq.length == 0) return;
207
208  if (typeof delay_callback == 'undefined') delay_callback = 10;
209
210  var jq_win = jQuery(window);
211
212  var chk_timer = setInterval(function () {
213    if (jq.is(':visible')) {
214      var t = getPageScroll();
215      var h = jq_win.height();
216      var item_pos = jq.offset().top;
217      if (item_pos > t && item_pos < t + h) {
218        clearInterval(chk_timer);
219        setTimeout(function () {
220          callback(jq);
221        }, delay_callback);
222      }
223    }
224  }, 250);
225
226  return chk_timer;
227}
228
229(function () {
230  var lastTime = 0;
231  var vendors = ['ms', 'moz', 'webkit', 'o'];
232  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
233    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
234    window.cancelAnimationFrame =
235      window[vendors[x] + 'CancelAnimationFrame'] ||
236      window[vendors[x] + 'CancelRequestAnimationFrame'];
237  }
238
239  if (!window.requestAnimationFrame)
240    window.requestAnimationFrame = function (callback, element) {
241      var currTime = new Date().getTime();
242      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
243      var id = window.setTimeout(function () {
244        callback(currTime + timeToCall);
245      }, timeToCall);
246      lastTime = currTime + timeToCall;
247      return id;
248    };
249
250  if (!window.cancelAnimationFrame)
251    window.cancelAnimationFrame = function (id) {
252      clearTimeout(id);
253    };
254})();
255
256(function () {
257  // Reasonable defaults
258  var PIXEL_STEP = 10;
259  var LINE_HEIGHT = 40;
260  var PAGE_HEIGHT = 800;
261
262  window.normalizeWheel = function (/*object*/ event) /*object*/ {
263    var sX = 0,
264      sY = 0, // spinX, spinY
265      pX = 0,
266      pY = 0; // pixelX, pixelY
267
268    // Legacy
269    if ('detail' in event) {
270      sY = event.detail;
271    }
272    if ('wheelDelta' in event) {
273      sY = -event.wheelDelta / 120;
274    }
275    if ('wheelDeltaY' in event) {
276      sY = -event.wheelDeltaY / 120;
277    }
278    if ('wheelDeltaX' in event) {
279      sX = -event.wheelDeltaX / 120;
280    }
281
282    // side scrolling on FF with DOMMouseScroll
283    if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
284      sX = sY;
285      sY = 0;
286    }
287
288    pX = sX * PIXEL_STEP;
289    pY = sY * PIXEL_STEP;
290
291    if ('deltaY' in event) {
292      pY = event.deltaY;
293    }
294    if ('deltaX' in event) {
295      pX = event.deltaX;
296    }
297
298    if ((pX || pY) && event.deltaMode) {
299      if (event.deltaMode == 1) {
300        // delta in LINE units
301        pX *= LINE_HEIGHT;
302        pY *= LINE_HEIGHT;
303      } else {
304        // delta in PAGE units
305        pX *= PAGE_HEIGHT;
306        pY *= PAGE_HEIGHT;
307      }
308    }
309
310    // Fall-back if spin cannot be determined
311    if (pX && !sX) {
312      sX = pX < 1 ? -1 : 1;
313    }
314    if (pY && !sY) {
315      sY = pY < 1 ? -1 : 1;
316    }
317
318    return {
319      spinX: sX,
320      spinY: sY,
321      pixelX: pX,
322      pixelY: pY,
323    };
324  };
325})();
326
327var video = {
328  // Instances are indexed by the video id rather than 1,2,3,etc so that videos are able to be
329  // accessed if they get shuffled around in the UI
330  instances: new Object(),
331
332  // Initialize the videos
333  // opts - an object of options for the videos. With no options set, the videos will default
334  //      - to a looping, muted background video
335  init: function (opts) {
336    if (typeof opts.selector == 'undefined') opts.selector = '.fld-video';
337    if (typeof opts.autoplay == 'undefined') opts.autoplay = true;
338    if (typeof opts.controls == 'undefined') opts.controls = 'none';
339    if (typeof opts.loop == 'undefined') opts.loop = true;
340    if (typeof opts.muted == 'undefined') opts.muted = true;
341    if (typeof opts.playBtn == 'undefined') {
342      opts.playBtn = 'images/play-btn.svg';
343    }
344    if (typeof opts.pauseBtn == 'undefined') {
345      opts.pauseBtn = 'images/pause-btn.svg';
346    }
347
348    jQuery(opts.selector).each(function () {
349      video.buildVideoHTML(jQuery(this), opts);
350    });
351
352    // Hover In:
353    // -    Requests a gif of the video, and displays it once it is ready.
354    // -    If the gif already exists, show the gif
355    // Hover Out:
356    // -    Hide the gif
357    jQuery(opts.selector).hover(
358      function () {
359        var previews = jQuery(this).find('.video-previews');
360        var gif = jQuery(this).find('.gif');
361        if (jQuery(window).width() > 760 && gif.length == 0) {
362          var id = jQuery(this).data('id');
363          var gif = jQuery(
364            '<img class="gif" src="https://videodelivery.net/' +
365              id +
366              '/thumbnails/thumbnail.gif?time=0s&duration=1s">'
367          );
368          gif.on('load', function () {
369            previews.append(gif);
370          });
371        } else {
372          previews.find('.gif').show();
373        }
374      },
375      function () {
376        var previews = jQuery(this).find('.video-previews');
377        previews.find('.gif').hide();
378      }
379    );
380
381    // Hides the video previews (thumbnail and gif) and filter and plays the video
382    jQuery(opts.selector).click(function () {
383      var id = jQuery(this).data('id');
384      jQuery(this).addClass('playing');
385      // video.instances[id].player.play().catch(function() {
386      //     video.instances[id].player.muted = true;
387      //     video.instances[id].player.play();
388      // });
389    });
390  },
391
392  // Create the HTML of the video previews and video. Video properties have defaults,
393  // but can be changed by setting the data-{property} attriutes
394  // jq   - a jQuery object of an instance of the selector specified in the init function
395  // opts - an object of options for the videos.
396  buildVideoHTML: function (jq, opts) {
397    if (jq.data('id') !== undefined) {
398      var id = jq.data('id');
399      var html = jQuery(
400        '<div class="filter"><div class="button" style="background-image: url(' +
401          opts.playBtn +
402          ')"></div></div><div class="video-previews"><img class="still" src="https://videodelivery.net/' +
403          id +
404          '/thumbnails/thumbnail.jpg?time=0s&fit=fill"></div><iframe class="video" src="https://iframe.videodelivery.net/' +
405          id +
406          '" allow="autoplay; accelerometer; gyroscope; encrypted-media; picture-in-picture;"  allowfullscreen="true"></iframe>'
407      );
408      jq.append(html);
409      video.instances[id] = {
410        jq: jq,
411        player: Stream(jq.find('.video')[0]),
412        playBtn: opts.playBtn,
413        pauseBtn: opts.pauseBtn,
414      };
415      var controls =
416        typeof jq.data('controls') !== 'undefined' ? jq.data('controls') : opts.c
416ontrols;
417      if (controls == 'full') {
418        video.instances[id].player.controls = true;
419      } else {
420        video.instances[id].player.controls = false;
421      }
422      // video.instances[id].player.controls = (typeof jq.data('controls') !== 'undefined' ? jq.data('controls') : opts.controls);
423      video.instances[id].player.autoplay =
424        typeof jq.data('autoplay') !== 'undefined' ? jq.data('autoplay') : opts.autoplay;
425      video.instances[id].player.muted =
426        typeof jq.data('muted') !== 'undefined' ? jq.data('muted') : opts.muted;
427      video.instances[id].player.loop =
428        typeof jq.data('loop') !== 'undefined' ? jq.data('loop') : opts.loop;
429
430      if (video.instances[id].player.autoplay) {
431        video.instances[id].player.play();
432      }
433
434      if (controls == 'none') {
435        jq.find('.filter').remove();
436
437        video.instances[id].player.addEventListener('canplay', function () {
438          jq.find('.video-previews').remove();
439        });
440      } else if (controls == 'limited') {
441        jq.find('.filter').css('pointer-events', 'all');
442
443        jq.find('.filter').click(function () {
444          if (video.instances[id].player.paused) {
445            video.instances[id].player.play();
446          } else {
447            video.instances[id].player.pause();
448          }
449        });
450      } else if (controls == 'full') {
451        jq.find('.filter').click(function () {
452          jQuery(this).remove();
453          video.instances[id].player.play();
454        });
455      }
456
457      video.instances[id].player.addEventListener('play', function () {
458        video.onPlay(video.instances[id]);
459      });
460      video.instances[id].player.addEventListener('pause', function () {
461        video.onPause(video.instances[id]);
462      });
463    }
464  },
465
466  onPlay: function (instance) {
467    instance.jq.removeClass('paused');
468    instance.jq.find('.button').css('background-image', 'url("' + instance.pauseBtn + '")');
469  },
470  onPause: function (instance) {
471    instance.jq.addClass('paused');
472    instance.jq.find('.button').css('background-image', 'url("' + instance.playBtn + '")');
473  },
474};
475
476const isInViewport = (elem, direction) => {
477  var bounding = elem.getBoundingClientRect();
478
479  if (direction === 'left') {
480    return bounding.right >= 0;
481  } else {
482    return bounding.left <= window.innerWidth;
483  }
484};
485
486function debounce(func, timeout = 300) {
487  let timer;
488  return (...args) => {
489    clearTimeout(timer);
490    timer = setTimeout(() => {
491      func.apply(this, args);
492    }, timeout);
493  };
494}
495
496/**
497 * Animates bezier-curve
498 *
499 * @param ctx       The canvas context to draw to
500 * @param x0        The x-coord of the start point
501 * @param y0        The y-coord of the start point
502 * @param x1        The x-coord of the control point
503 * @param y1        The y-coord of the control point
504 * @param x2        The x-coord of the end point
505 * @param y2        The y-coord of the end point
506 * @param duration  The duration in milliseconds
507 */
508function animatePathDrawing(ctx, x0, y0, x1, y1, x2, y2, duration) {
509  var start = null;
510
511  var step = function animatePathDrawingStep(timestamp) {
512    if (start === null) start = timestamp;
513
514    var delta = timestamp - start,
515      progress = Math.min(delta / duration, 1);
516
517    // Clear canvas
518    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
519
520    // Draw curve
521    drawBezierSplit(ctx, x0, y0, x1, y1, x2, y2, 0, progress);
522
523    if (progress < 1) {
524      window.requestAnimationFrame(step);
525    }
526  };
527
528  window.requestAnimationFrame(step);
529}
530
531/**
532 * Draws a splitted bezier-curve
533 *
534 * @param ctx       The canvas context to draw to
535 * @param x0        The x-coord of the start point
536 * @param y0        The y-coord of the start point
537 * @param x1        The x-coord of the control point
538 * @param y1        The y-coord of the control point
539 * @param x2        The x-coord of the end point
540 * @param y2        The y-coord of the end point
541 * @param t0        The start ratio of the splitted bezier from 0.0 to 1.0
542 * @param t1        The start ratio of the splitted bezier from 0.0 to 1.0
543 */
544function drawBezierSplit(ctx, x0, y0, x1, y1, x2, y2, t0, t1) {
545  ctx.beginPath();
546
547  if (0.0 == t0 && t1 == 1.0) {
548    ctx.moveTo(x0, y0);
549    ctx.quadraticCurveTo(x1, y1, x2, y2);
550  } else if (t0 != t1) {
551    var t00 = t0 * t0,
552      t01 = 1.0 - t0,
553      t02 = t01 * t01,
554      t03 = 2.0 * t0 * t01;
555
556    var nx0 = t02 * x0 + t03 * x1 + t00 * x2,
557      ny0 = t02 * y0 + t03 * y1 + t00 * y2;
558
559    t00 = t1 * t1;
560    t01 = 1.0 - t1;
561    t02 = t01 * t01;
562    t03 = 2.0 * t1 * t01;
563
564    var nx2 = t02 * x0 + t03 * x1 + t00 * x2,
565      ny2 = t02 * y0 + t03 * y1 + t00 * y2;
566
567    var nx1 = lerp(lerp(x0, x1, t0), lerp(x1, x2, t0), t1),
568      ny1 = lerp(lerp(y0, y1, t0), lerp(y1, y2, t0), t1);
569
570    ctx.moveTo(nx0, ny0);
571    ctx.quadraticCurveTo(nx1, ny1, nx2, ny2);
572  }
573
574  ctx.stroke();
575  ctx.closePath();
576}
577
578/**
579 * Linearly interpolate between two numbers v0, v1 by t
580 */
581function lerp(v0, v1, t) {
582  return (1.0 - t) * v0 + t * v1;
583}
584
585// count-up stats
586var count_up_init = jQuery(function () {
587  function int_format_commas(val) {
588    var v = parseInt(val);
589    return v.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
590  }
591  jQuery('.count-up').each(function () {
592    var jq = jQuery(this);
593    var steps = this.dataset.steps ? this.dataset.steps : 200;
594    var original = jq.html();
595    var prefix = '';
596    var num = '';
597    var num_val = 0;
598    var num_string = ''; // num in string form to use at the end of animtion
599    var postfix = '';
600    var decimals = false;
601    var decimal_places = 0;
602    var commas = false;
603    var phase = 0; //0 before number found, 1 inside number, 2 after number
604    function update(val) {
605      // jq.html(prefix + val + postfix);
606      jq.html(
607        '<span class="prefix">' +
608          prefix +
609          '</span>' +
610          '<span class="val">' +
611          val +
612          '</span>' +
613          '<span class="postfix">' +
614          postfix +
615          '</span>'
616      );
617    }
618    var n = original.length;
619    for (var i = 0; i < n; i++) {
620      var c = original[i];
621      var ci = parseInt(c);
622      var nan = isNaN(ci);
623      if (phase == 0) {
624        if (nan) {
625          prefix += c;
626        } else {
627          phase = 1;
628          num += c;
629          num_string += c;
630        }
631      } else if (phase == 1) {
632        if (!nan) {
633          num += c;
634          num_string += c;
635          if (decimals) {
636            decimal_places++;
637          }
638        } else {
639          if (c == ',') {
640            commas = true;
641            num_string += c;
642          } else if (c == '.') {
643            num += c;
644            num_string += c;
645            decimals = true;
646          } else {
647            phase = 2;
648            postfix += c;
649          }
650        }
651      } else {
652        postfix += c;
653      }
654    }
655    if (decimals) {
656      num_val = parseFloat(num);
657    } else {
658      num_val = parseInt(num);
659    }
660    var cur_val = 0;
661    var step = num_val / steps;
662    var placeholder = '';
663    for (var i = 0; i < num.length; i++) placeholder += '&nbsp;';
664    update(placeholder);
665    function count_up() {
666      cur_val += step;
667      if (cur_val >= num_val) {
668        //all done
669        // jq.html(original);
670        jq.html(
671          '<span class="prefix">' +
672            prefix +
673            '</span>' +
674            '<span class="val">' +
675            num_string +
676            '</span>' +
677            '<span class="postfix">' +
678            postfix +
679            '</span>'
680        );
681        // jq.addClass('done');
682      } else {
683        if (decimals) {
684          var display_val = '' + parseInt(cur_val * Math.pow(10, decimal_places));
685          if (display_val.length < decimal_places + 1) {
686            for (var i = 0; i < decimal_places; i++) {
687              display_val = '0' + display_val;
688            }
689          }
690          var display_val_part_1 = display_val.substr(0, display_val.length - decimal_places);
691          var display_val_part_2 = display_val.substr(display_val.length - decimal_places);
692          display_val =
693            (commas ? int_format_commas(display_val_part_1) : parseInt(display_val_part_1)) +
694            '.' +
695            display_val_part_2;
696        } else {
697          var display_val = commas ? int_format_commas(cur_val) : parseInt(cur_val);
698        }
699        update(display_val);
700        setTimeout(count_up, 16);
701      }
702    }
703    wait_for_visible(jq, function () {
704      count_up();
705    });
706  });
707});

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.