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 += ' '; 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.