1/** 2 * Evertz.com global javascript environment file 3 * 4 * This file should be included on every page that uses the default 5 * Evertz.com website template. It must be included at the end of the 6 * page source. 7 * 8 * Requires: jquery 9 * 10 */ 11 12var PAGE_SUBMENU; 13var PAGE_DOWNROOT = '/'; 14 15const MIRROR = (window.location.protocol == 'file:'); 16if (MIRROR) { 17 let favicon = document.querySelector('link[rel="shortcut icon"]'); 18 if (favicon) PAGE_DOWNROOT = favicon.getAttribute('href').replace(/favicon\.ico/, ''); 19} 20 21 22/** 23 * Handy element positioning function from Quirksmode.org 24 * 25 */ 26function findPos(obj) { 27 var curleft = curtop = 0; 28 do { 29 if (!obj) break; 30 curleft += obj.offsetLeft; 31 curtop += obj.offsetTop; 32 } while (obj = obj.offsetParent); 33 return [curleft, curtop]; 34} 35 36 37/** 38 * Return the dimensions of the viewport, also from Quirksmode.org 39 * 40 */ 41function innerDimensions() { 42 if (self.innerHeight) { 43 return [self.innerWidth, self.innerHeight]; 44 } else if (document.documentElement && document.documentElement.clientHeight) { 45 return [document.documentElement.clientWidth, document.documentElement.clientHeight]; 46 } else if (document.body) 47 return [document.body.clientWidth, document.body.clientHeight]; 48 return [0, 0]; 49} 50 51 52/** 53 * Calculate brightness value by RGB or HEX color. 54 * @param color (String) The color value in RGB or HEX (for example: #000000 || #000 || rgb(0,0,0) || rgba(0,0,0,0)) 55 * @returns (Number) The brightness value (dark) 0 ... 255 (light) 56 */ 57function brightnessByColor(color) { 58 color = '' + color; 59 let r = false, m, isHEX = color.indexOf('#') == 0, isRGB = color.indexOf('rgb') == 0; 60 if (isHEX) { 61 m = color.substr(1).match(color.length == 7 ? /(\S{2})/g : /(\S{1})/g); 62 if (m) r = parseInt(m[0], 16), g = parseInt(m[1], 16), b = parseInt(m[2], 16); 63 } 64 if (isRGB) { 65 m = color.match(/(\d+)/g); 66 if (m) r = m[0], g = m[1], b = m[2]; 67 } 68 if (r) return ((r*299)+(g*587)+(b*114))/1000; 69} 70 71 72/** 73 * Natural sort function 74 * 75 */ 76function alphanum(a, b) { 77 function chunkify(t) { 78 let tz = [], x = 0, y = -1, n = 0, i, j; 79 while (i = (j = t.charAt(x++)).charCodeAt(0)) { 80 let m = (i == 46 || (i >=48 && i <= 57)); 81 if (m !== n) { 82 tz[++y] = ''; 83 n = m; 84 } 85 tz[y] += j; 86 } 87 return tz; 88 } 89 let aa = chunkify(a); 90 let bb = chunkify(b); 91 for (let x = 0; aa[x] && bb[x]; x++) { 92 if (aa[x] !== bb[x]) { 93 let c = Number(aa[x]), d = Number(bb[x]); 94 if (c == aa[x] && d == bb[x]) { 95 return c - d; 96 } else return (aa[x] > bb[x]) ? 1 : -1; 97 } 98 } 99 return aa.length - bb.length; 100} 101 102 103/** 104 * Scroll to an element, accounting for main and sub menus 105 * 106 */ 107function scrollToElem(target) { 108 if (typeof target == 'string') { 109 let href = target; 110 if (href.indexOf('#') === 0) href = href.substring(1); 111 target = document.getElementById(href); 112 if (!target) target = document.querySelector('a[name="' + href + '"]'); 113 } 114 115 if (target) { 116 let pos = findPos(target); 117 let nav1 = document.querySelector('nav.navbar'); 118 nav1 = (nav1) ? nav1.offsetHeight : 0; 119 let nav2 = document.querySelector('.sub-menu'); 120 nav2 = (nav2) ? nav2.offsetHeight : 0; 121 pos = pos[1] - nav1 - nav2 - 10; 122 let oldpos = window.scrollY; 123 124 setTimeout(function() { 125 window.scrollTo({ top: oldpos, left: 0, behavior: 'auto' }); 126 $('html, body').animate({ scrollTop: pos }, 300); 127 }, 0); 128 return true; 129 } else return false; 130} 131 132// Scroll to Top button action 133document.getElementById('scrollToTop').addEventListener('click', function() { 134 $('html, body').animate({ scrollTop: 0 }, 300); 135 window.history.replaceState({}, '', window.location.href.replace(/#.*$/, '')); 136}, false); 137 138 139// Hide vertical scroll bar when main navbar dropdowns are shown on mobile 140let navNavbar = document.querySelector('nav.navbar'); 141if (navNavbar) { 142 navNavbar.addEventListener('show.bs.dropdown', function() { 143 setTimeout(function() { 144 navNavbar.classList.add('dropdown-open'); 145 }, 5);
146 }, false); 147 navNavbar.addEventListener('hidden.bs.dropdown', function() { 148 navNavbar.classList.remove('dropdown-open'); 149 // document.documentElement.style.overflow = ''; 150 }, false); 151 152 navNavbar.addEventListener('show.bs.collapse', function() { 153 setTimeout(function() { 154 navNavbar.classList.add('dropdown-open'); 155 }, 5); 156 // if (innerDimensions()[0] < 768) 157 // document.documentElement.style.overflow = 'hidden'; 158 }); 159 navNavbar.addEventListener('hidden.bs.collapse', function() { 160 navNavbar.classList.remove('dropdown-open'); 161 // document.documentElement.style.overflow = ''; 162 }); 163 164 // Expand and contract the search field on focus and blur 165 let navbarTypeahead = document.querySelectorAll('nav.navbar form .os_typeahead'); 166 let navbarSupportedContent = document.getElementById('navbarSupportedContent'); 167 for (let x = 0; x < navbarTypeahead.length; x++) { 168 navbarTypeahead[x].addEventListener('focus', function() { 169 clearTimeout(navNavbar.timeout); 170 navNavbar.classList.add('searching'); 171 navbarSupportedContent.classList.add('squished'); 172 }, false); 173 navbarTypeahead[x].addEventListener('blur', function() { 174 navNavbar.timeout = setTimeout(function() { 175 navNavbar.classList.remove('searching'); 176 setTimeout(function() { 177 navbarSupportedContent.classList.remove('squished'); 178 }, 300); 179 }, 200); 180 }, false); 181 } 182 183 let searchSubmit = document.getElementById('searchSubmit'); 184 if (searchSubmit) { 185 searchSubmit.addEventListener('click', function(e) { 186 if (!navNavbar.classList.contains('searching')) { 187 e.preventDefault(); 188 clearTimeout(navNavbar.timeout); 189 navNavbar.classList.add('searching'); 190 for (let x = 0; x < navbarTypeahead.length; x++) 191 navbarTypeahead[x].focus(); 192 return false; 193 } return true; 194 }, false); 195 } 196} 197 198 199// Clear and exit an HTTP Authenticated session 200function httpAuthLogout() { 201 let xmlhttp; 202 if (window.XMLHttpRequest) { 203 xmlhttp = new XMLHttpRequest(); 204 205 // code for IE 206 } else if (window.ActiveXObject) 207 xmlhttp = new ActiveXObject('Microsoft.XMLHTTP'); 208 209 // IE clear HTTP Authentication 210 if (window.ActiveXObject) { 211 document.execCommand('ClearAuthenticationCache'); 212 window.location.href = '/'; 213 214 } else { 215 xmlhttp.open('GET', window.location.pathname, true, 'logout', 'logout'); 216 xmlhttp.send(''); 217 xmlhttp.onreadystatechange = function() { 218 if (xmlhttp.readyState == 4) { 219 window.location.href = '/'; 220 } 221 } 222 } 223 return false; 224} 225 226 227 228// Standard Evertz image slideshow 229for (let x = 0, slideShows = document.querySelectorAll('ul.slideshow'); x < slideShows.length; x++) { 230 slideShows[x].lis = slideShows[x].getElementsByTagName('li'); 231 232 for (let y = 0; y < slideShows[x].lis.length; y++) 233 if (y) slideShows[x].lis[y].classList.add('d-none'); 234 235 let prev = document.createElement('div'); 236 prev.classList.add('prev', 'h-100'); 237 prev.setAttribute('role', 'button'); 238 prev.parent = slideShows[x]; 239 prev.addEventListener('click', function() { 240 let idx = 0; 241 for (let y = 0; y < this.parent.lis.length; y++) 242 if (!this.parent.lis[y].classList.contains('d-none')) idx = y; 243 if (--idx < 0) idx = this.parent.lis.length - 1; 244 for (let y = 0; y < this.parent.lis.length; y++) { 245 if (y == idx) { 246 this.parent.lis[y].classList.remove('d-none'); 247 } else this.parent.lis[y].classList.add('d-none'); 248 } 249 }, false); 250 slideShows[x].appendChild(prev); 251 252 let next = document.createElement('div'); 253 next.classList.add('next', 'h-100'); 254 next.setAttribute('role', 'button'); 255 next.parent = slideShows[x]; 256 next.addEventListener('click', function() { 257 let idx = 0; 258 for (let y = 0; y < this.parent.lis.length; y++) 259 if (!this.parent.lis[y].classList.contains('d-none')) idx = y; 260 if (++idx > this.parent.lis.length - 1) idx = 0; 261 for (let y = 0; y < this.parent.lis.length; y++) { 262 if (y == idx) { 263 this.parent.lis[y].classList.remove('d-none'); 264 } else this.parent.lis[y].classList.add('d-none'); 265 } 266 }, false); 267 slideShows[x].appendChild(next); 268} 269 270 271 272// Link Applications/Solutions card blocks 273let cardBlocks = document.querySelectorAll('.card-link'); 274for (let x = 0; x < cardBlocks.length; x++) { 275 let a = cardBlocks[x].getElementsByTagName('a')[0]; 276 if (a) { 277 cardBlocks[x].title = a.href; 278 cardBlocks[x].addEventListener('click', function() { 279 window.location.href = a.href; 280 }, false); 281 } 282} 283 284 285 286// Ensure card-flip blocks are tall enough to fit their backside content 287function cardFlipHeight() { 288 let cardFlips = document.querySelectorAll('.card-flip'); 289 for (let x = 0; x < cardFlips.length; x++) {
290 let cf = cardFlips[x].querySelector('.card-front'); 291 cf.style.minHeight = '0'; 292 cf.classStorage = cf.className; 293 cf.className = 'card-front'; 294 295 if (cf.offsetHeight) { 296 let cb = cardFlips[x].querySelector('.card-back'); 297 cb.classStorage = cb.className; 298 cb.className = 'card-back'; 299 300 if (cb.offsetHeight > cf.offsetHeight) 301 cf.style.minHeight = cb.offsetHeight + 'px'; 302 303 cb.className = cb.classStorage; 304 } 305 cf.className = cf.classStorage; 306 } 307} 308 309 310// Execute on a node which may contain a replaced inline-text-svg logo 311// to ensure it's the proper colour to be read. 312function svgLogoColorSet(node) { 313 let img = node.querySelectorAll(':scope img.inline-text-svg'); 314 for (let x = 0, bright; x < img.length; x++) { 315 bright = brightnessByColor(window.getComputedStyle(img[x].parentNode).color); 316 img[x].src = img[x].src.replace(/(\.white)?\.svg$/, (bright < 128) ? '.svg' : '.white.svg'); 317 } 318} 319 320 321// Parallax section blocks 322let parallaxSections = document.querySelectorAll('#main-content section.parallax'); 323for (let x = 0; x < parallaxSections.length; x++) { 324 let img = parallaxSections[x].getElementsByTagName('img')[0]; 325 if (img) { 326 parallaxSections[x].style.backgroundImage = 'url(' + img.src + ')'; 327 parallaxSections[x].removeChild(img); 328 } 329} 330 331 332 333// Stop videos in modals from playing when modals are closed 334let allModals = document.querySelectorAll('.modal'); 335for (let x = 0; x < allModals.length; x++) { 336 allModals[x].vids = allModals[x].querySelectorAll('video'); 337 if (allModals[x].vids.length) { 338 allModals[x].addEventListener('hide.bs.modal', function() { 339 for (let y = 0; y < this.vids.length; y++) 340 this.vids[y].pause(); 341 }, false); 342 } 343 allModals[x].ytvids = allModals[x].querySelectorAll('iframe.ytvideo'); 344 if (allModals[x].ytvids.length) { 345 allModals[x].addEventListener('hide.bs.modal', function() { 346 for (let y = 0; y < this.ytvids.length; y++) { 347 let dummySrc = this.ytvids[y].src; 348 this.ytvids[y].src = dummySrc; 349 } 350 }, false); 351 } 352} 353 354 355 356// Release Notes modal on Firmware and Software downloads pages 357let modalReleaseNotes = document.getElementById('modalReleaseNotes'); 358if (modalReleaseNotes) { 359 modalReleaseNotes.addEventListener('show.bs.modal', function (event) { 360 let button = event.relatedTarget; 361 let modalText = modalReleaseNotes.querySelector('textarea'); 362 363 let http = getHTTPObject(); 364 http.open('GET', button.getAttribute('href'), true); 365 http.onreadystatechange = function() { 366 if (http.readyState == 4) 367 modalText.value = http.responseText; 368 }; 369 http.send(null); 370 }); 371 modalReleaseNotes.addEventListener('hide.bs.modal', function (event) { 372 let modalText = modalReleaseNotes.querySelector('textarea'); 373 modalText.scrollTop = 0; 374 }); 375} 376 377 378 379/** 380 * Match text in text nodes and replace with callback function 381 * - From: https://stackoverflow.com/a/29301739 382 * 383 * @param node: Element - document node to search through for text nodes 384 * @param regex: Regex - text to match for replacement 385 * @param callback: Function - what to do with the matched text 386 * @param excludeElements: Array - list of elements to exclude 387 * 388 */ 389function matchText(node, regex, callback, excludeElements) { 390 excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas', 'textarea', 'select', 'input']); 391 if (!node || !node.firstChild) return node; 392 let child = node.firstChild; 393 394 while (child) { 395 switch (child.nodeType) { 396 case 1: 397 if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1) break; 398 matchText(child, regex, callback, excludeElements); 399 break; 400 case 3: 401 let bk = 0; 402 child.data.replace(regex, function(all) { 403 let args = [].slice.call(arguments); 404 let newTextNode = child.splitText(args[args.length - 2] + bk); 405 bk -= child.data.length + all.length; 406 newTextNode.data = newTextNode.data.substr(all.length); 407 child.parentNode.insertBefore( 408 callback.apply(window, [child].concat(args)), 409 newTextNode 410 ); 411 child = newTextNode; 412 }); 413 regex.lastIndex = 0; 414 } 415 child = child.nextSibling; 416 } 417 return node; 418} 419 420 421 422// Apply -dark class to the entire carousel depending on current slide 423let frontPageCarousel = document.getElementById('frontPageCarousel'); 424if (frontPageCarousel) { 425 frontPageCarousel.addEventListener('slide.bs.carousel', function(e) { 426 let items = this.querySelectorAll('.carousel-inner .carousel-item'); 427 if (items[e.to]) { 428 if (items[e.to].classList.contains('carousel-dark')) { 429 this.classList.add('carousel-dark'); 430 } else this.classList.remove('carousel-dark'); 431 } 432 }, false); 433} 434 435 436// Hide <time> events in .event-list elements that are in the past 437let eventlist = document.querySelectorAll('.event-list'); 438for (let x = 0, items, today = Math.floor(Date.now() / 1000); x < eventlist.length; x++) { 439 items = 0; 440 let dates = eventlist[x].querySelectorAll('.event-list * time:first-of-type'); 441 for (let y = 0, elemDate; y < dates.length; y++) { 442 elemDate = new Date(dates[y].getAttribute('datetime')); 443 if (Math.floor(elemDate.getTime() / 1000) < today - 86400) { 444 items++; 445 dates[y].parentNode.style.display = 'none'; 446 } 447 } 448 if (items == dates.length) { // If everything was hidden 449 let item = dates[0].parentNode.cloneNode(false); 450 item.style.display = ''; 451 let em = document.createElement('em'); 452 em.appendChild(document.createTextNode('No events scheduled.')); 453 item.appendChild(em); 454 eventlist[x].appendChild(item); 455 } 456} 457 458
459// Attach scrollto functions to accordion open calls 460let accordionElements = document.querySelectorAll('.accordion-collapse'); 461for (let x = 0; x < accordionElements.length; x++) { 462 accordionElements[x].addEventListener('shown.bs.collapse', function() { 463 let elemheaderid = this.getAttribute('aria-labelledby'); 464 scrollToElem(elemheaderid); 465 }, false); 466} 467 468 469 470// Add container <div> elements to all headers in table.display <th> 471let tableDisplayTH = document.querySelectorAll('.product-table table.tip-up thead th'); 472for (let x = 0; x < tableDisplayTH.length; x++) { 473 let div = document.createElement('div'); 474 while (tableDisplayTH[x].firstChild) 475 div.appendChild(tableDisplayTH[x].firstChild); 476 tableDisplayTH[x].appendChild(div); 477} 478function tableDisplayHeaderHeight() { 479 for (let x = 0; x < tableDisplayTH.length; x++) { 480 if (!tableDisplayTH[x].colspan) { 481 let div = tableDisplayTH[x].getElementsByTagName('div')[0]; 482 if (div && window.getComputedStyle(div).position == 'absolute') { 483 tableDisplayTH[x].style.height = (div.offsetWidth + 15) + 'px'; 484 tableDisplayTH[x].style.minWidth = (div.offsetHeight + 10) + 'px'; 485 } else { 486 tableDisplayTH[x].style.height = 'auto'; 487 tableDisplayTH[x].style.minWidth = 0; 488 } 489 } 490 } 491} 492 493 494 495// ********** GLOBAL EVENT LISTENERS ********** */ 496window.addEventListener('DOMContentLoaded', function() { 497 498 if (MIRROR) { 499 let search = document.querySelector('nav.navbar ul.navbar-nav + form'); 500 if (search) { 501 search.method = 'get'; 502 search.action = PAGE_DOWNROOT + 'search/index.html'; 503 } 504 } 505 506 507 // If requested, build a submenu automatically 508 let autoSubmenu = document.querySelector('ul[data-build="auto"]'); 509 if (autoSubmenu) { 510 let mainContentIds = document.querySelectorAll('#main-content *[id]'); 511 for (let x = 0; x < mainContentIds.length; x++) { 512 let li = document.createElement('li'); 513 li.classList.add('nav-item', 'lh-lg'); 514 let a = document.createElement('a'); 515 a.classList.add('nav-link', 'text-light'); 516 a.href = '#' + mainContentIds[x].id; 517 let span = document.createElement('span'); 518 span.innerHTML = mainContentIds[x].innerHTML; 519 a.appendChild(span); 520 li.appendChild(a); 521 autoSubmenu.appendChild(li); 522 } 523 } 524 525 526 // Attach the scrollToElem function to all internal page links 527 let links = document.querySelectorAll('body a[href^="#"]:not(a[href="#"])'); 528 for (let x = 0; x < links.length; x++) { 529 links[x].addEventListener('click', function(e) { 530 scrollToElem(this.getAttribute('href')); 531 }, false); 532 } 533 534 // Create links out of non-<a> elements having data-href attributes 535 // Be sure to add role="button" to these elements 536 // let dataHref = document.querySelectorAll('body [data-href]'); 537 // for (let x = 0; x < dataHref.length; x++) { 538 // dataHref[x].addEventListener('click', function(e) { 539 // let href = this.getAttribute('data-href'); 540 // if (href && href.indexOf('#') === 0) { 541 // if (href.length > 1) { 542 // scrollToElem(href); 543 // } 544 // } else { 545 // let target = this.getAttribute('target'); 546 // if (target && target == '_blank') { 547 // window.open(href, target); 548 // } else window.location.href = href; 549 // } 550 // }, false); 551 // } 552 553 // If the page submenu exists, attach the highlighting function 554 PAGE_SUBMENU = document.querySelector('.sub-menu'); 555 if (PAGE_SUBMENU) { 556 557 // If this page has a sub-menu link that matches the current page 558 // URL, then highlight it 559 PAGE_SUBMENU.links = PAGE_SUBMENU.querySelectorAll('a.nav-link[href^="/"]'); 560 for (let x = 0, u; x < PAGE_SUBMENU.links.length; x++) { 561 PAGE_SUBMENU.links[x].classList.remove('show'); 562 u = new URL(PAGE_SUBMENU.links[x].href); 563 if (u.pathname == window.location.pathname) 564 PAGE_SUBMENU.links[x].classList.add('show'); 565 } 566 567 // Highlight the appropriate link in the submenu, it if exists
568 PAGE_SUBMENU.anchors = PAGE_SUBMENU.querySelectorAll('a.nav-link[href^="#"]'); 569 PAGE_SUBMENU.highlight = function() { 570 571 // Detect if the submenu is currently sticky 572 let nav1 = document.querySelector('nav.navbar').offsetHeight; 573 let npos = findPos(PAGE_SUBMENU); 574 if (Math.ceil(npos[1] - window.scrollY) <= nav1) { 575 this.classList.add('sticky'); 576 } else if (Math.floor(npos[1] - window.scrollY) > nav1) 577 this.classList.remove('sticky'); 578 579 // Remove all previous link highlights 580 for (let y = 0; y < this.anchors.length; y++) 581 this.anchors[y].classList.remove('show'); 582 583 // Highlight appropriate submenu links if we've scrolled to them 584 for (let x = this.anchors.length - 1, href, target, pos; x >= 0; x--) { 585 href = this.anchors[x].getAttribute('href'); 586 587 if (href.indexOf('#') === 0) { 588 href = href.substring(1); 589 target = document.getElementById(href); 590 if (!target) target = document.querySelector('a[name="' + href + '"]'); 591 592 if (target) { 593 pos = findPos(target); 594 595 if (pos[1] < window.scrollY + innerDimensions()[1] / 2) { 596 if (!this.anchors[x].classList.contains('show')) { 597 this.anchors[x].classList.add('show'); 598 break; 599 } 600 } 601 } 602 } 603 } 604 } 605 } 606 607 608 // Set up text-hyphen-nowrap elements 609 [...document.querySelectorAll('.text-hyphen-nowrap')].map( 610 elem => textHyphenNowrap(elem) 611 ); 612 613 614 inlineLogoReplace(document.querySelector('body')); 615 616 [...document.querySelectorAll('img.inline-text-svg')].map(img => { 617 if (img.nextSibling && img.nextSibling.nodeType == 3) { 618 ['.', ',', '\'s'].map(tail => { 619 if (img.nextSibling.nodeValue.substring(0, tail.length) == tail) { 620 img.nextSibling.nodeValue = img.nextSibling.nodeValue.substring(tail.length); 621 let nobr = document.createElement('span'); 622 nobr.classList.add('text-nowrap'); 623 img.parentNode.insertBefore(nobr, img); 624 nobr.appendChild(img); 625 nobr.appendChild(document.createTextNode(tail)); 626 } 627 }); 628 } 629 }); 630 631 632 // Now that the nav-item's in the submenu highlight fully yellow, 633 // make sure any svg .white logos they contain, are swapped to 634 // black on highlight. 635 // let subMenuSVGs = document.querySelectorAll('.sub-menu img.inline-text-svg'); 636 // for (let x = 0; x < subMenuSVGs.length; x++) { 637 // if (subMenuSVGs[x].src.indexOf('.white') > 0) { 638 // let darkSVG = subMenuSVGs[x].cloneNode(); 639 // darkSVG.src = subMenuSVGs[x].src.replace(/\.white/, ''); 640 // subMenuSVGs[x].parentNode.insertBefore(darkSVG, subMenuSVGs[x].nextSibling); 641 // } 642 // } 643 644 // The above is now done by adding a dark drop shadow to any images 645 // in the submenu. 646 647}, false); 648 649 650// Replace words with hyphens with <span class="text-nowrap">word</span> 651function textHyphenNowrap(node) { 652 for (let x = node.childNodes.length - 1; x >= 0; x--) { 653 switch (node.childNodes[x].nodeType) { 654 case 1: textHyphenNowrap(node.childNodes[x]); break; 655 case 3: 656 node.childNodes[x].parentNode.replaceChild( 657 (function(nodeText) { 658 let frag = document.createDocumentFragment(); 659 nodeText = nodeText.split(/<\/?nobr>/); 660 for (let x = 0, nowr; x < nodeText.length; x++) { 661 if (x % 2) { 662 nowr = document.createElement('span'); 663 nowr.classList.add('text-nowrap'); 664 nowr.appendChild(document.createTextNode(nodeText[x])); 665 frag.appendChild(nowr); 666 } else frag.appendChild(document.createTextNode(nodeText[x])); 667 } 668 return frag; 669 })(node.childNodes[x].nodeValue.replace(/\b([a-z0-9]+(-[a-z0-9]+)+)\b/ig, '<nobr>$1</nobr>')), 670 node.childNodes[x] 671 ); 672 } 673 } 674} 675 676 677 678// ***** TEXT NODE LOGO INSERTION *********************************** 679function inlineLogoReplace(element) { 680 function insertInlineLogo(node, match, offset, imagefile, alt) { 681 let parent = node; 682 while (parent = parent.parentNode) { 683 if (parent.nodeName == 'Q' || parent.nodeName == 'MARK') 684 return document.createTextNode(match); 685 if (parent.classList && parent.classList.contains('no-replace')) 686 return document.createTextNode(match); 687 } 688 let bright = brightnessByColor(window.getComputedStyle(node.parentNode).color); 689 let img = document.createElement('img'); 690 img.src = PAGE_DOWNROOT + 'img/evertz/' + imagefile + ((bright < 128) ? '.svg' : '.white.svg'); 691 img.alt = alt; 692 img.title = alt; 693 img.classList.add('inline-text-svg'); 694 img.classList.add(imagefile); 695 696 img.addEventListener('load', function() {
697 this.style.setProperty('--aspect-ratio', this.naturalWidth / this.naturalHeight); 698 this.style.aspectRatio = this.naturalWidth / this.naturalHeight; 699 }); 700 return img; 701 } 702 703 704 // Exponent logo 705 matchText( 706 element, new RegExp('\\b' + 'Exponent' + '\\b', ''), 707 function(node, match, offset) { 708 return insertInlineLogo(node, match, offset, 'exponent', 'Exponent'); 709 } 710 ); 711 712 // Overture logos 713 matchText( 714 element, new RegExp('\\b' + 'Overtureâ¢?(\\s+|-)?RT(\\s+|-)L(IVE|ive)' + '\\b', ''), 715 function(node, match, offset) { 716 return insertInlineLogo(node, match, offset, 'overture-rt-live', 'Overture⢠RT LIVE'); 717 } 718 ); 719 matchText( 720 element, new RegExp('\\b' + 'Overtureâ¢?(\\s+|-)?RT' + '\\b', ''), 721 function(node, match, offset) { 722 return insertInlineLogo(node, match, offset, 'overture-rt', 'Overture⢠RT'); 723 } 724 ); 725 matchText( 726 element, new RegExp('\\b' + 'Overture(?!-)(â¢|\\b)', ''), 727 function(node, match, offset) { 728 return insertInlineLogo(node, match, offset, 'overture', 'Overtureâ¢'); 729 } 730 ); 731 732 // VistaLINK PRO logo 733 matchText( 734 element, new RegExp('\\b' + 'VistaLINK(?=®\\s*IRM|®\\s*CSM|\\s*IRM|\\s*CSM)®?', ''), 735 function(node, match, offset) { 736 return insertInlineLogo(node, match, offset, 'vistalink', 'VistaLINK®'); 737 } 738 ); 739 matchText( 740 element, new RegExp('\\b' + 'VistaLINK®?\\s*PRO', ''), 741 function(node, match, offset) { 742 return insertInlineLogo(node, match, offset, 'vistalink-pro', 'VistaLINK® PRO'); 743 } 744 ); 745 matchText( 746 element, new RegExp('\\b' + 'VistaLINK®?', ''), 747 function(node, match, offset) { 748 return insertInlineLogo(node, match, offset, 'vistalink', 'VistaLINK®'); 749 } 750 ); 751 752 // IntelliGain logo 753 matchText( 754 element, new RegExp('\\b' + 'IntelliGain[â¢Â®]?', ''), 755 function(node, match, offset) { 756 return insertInlineLogo(node, match, offset, 'intelligain', 'IntelliGain®'); 757 } 758 ); 759 760 // SCORPION logo 761 matchText( 762 element, new RegExp('\\b' + '(?<!-)SCORPION(?!-)' + '\\b', ''), 763 function(node, match, offset) { 764 return insertInlineLogo(node, match, offset, 'scorpion', 'SCORPION'); 765 } 766 ); 767 768 // DreamCatcher logo 769 matchText( 770 element, new RegExp('\\b' + 'DreamCatcherâ¢?', ''), 771 function(node, match, offset) { 772 return insertInlineLogo(node, match, offset, 'dreamcatcher', 'DreamCatcherâ¢'); 773 } 774 ); 775 776 // Mediator-X logo 777 matchText( 778 element, new RegExp('\\b' + 'Mediator(\\s+|-)?X' + '\\b', ''), 779 function(node, match, offset) { 780 return insertInlineLogo(node, match, offset, 'mediator-x', 'Mediator-X'); 781 } 782 ); 783 784 // RenderX logo 785 matchText( 786 element, new RegExp('\\b' + 'Render(\\s+|-)?X' + '\\b', ''), 787 function(node, match, offset) { 788 return insertInlineLogo(node, match, offset, 'renderx', 'RenderX'); 789 } 790 ); 791 792 // Vista-in-VUE logo 793 matchText( 794 element, new RegExp('V(ista|ISTA)(\\s+|-)(in|IN)(\\s+|-)VUE', ''), 795 function(node, match, offset) { 796 return insertInlineLogo(node, match, offset, 'vista-in-vue', 'Vista-in-VUE'); 797 } 798 ); 799 800 // VUEAPPS logo 801 matchText( 802 element, new RegExp('\\b' + 'VUEAPPS' + '\\b', ''), 803 function(node, match, offset) { 804 return insertInlineLogo(node, match, offset, 'vueapps', 'VUEAPPS'); 805 } 806 ); 807 808 // REVUE logo 809 matchText( 810 element, new RegExp('\\b' + 'REVUE' + '\\b', ''), 811 function(node, match, offset) { 812 return insertInlineLogo(node, match, offset, 'revue', 'REVUE'); 813 } 814 ); 815 816 // VUE logo 817 matchText( 818 element, new RegExp('\\b' + '(?<!-)VUE(?!-)' + '\\b', ''), 819 function(node, match, offset) { 820 return insertInlineLogo(node, match, offset, 'vue', 'VUE'); 821 } 822 ); 823 824 // MAGNUM logos 825 matchText( 826 element, new RegExp('\\b' + 'MAGNUM(\\s+|-)A(nalytics|NALYTICS)' + '\\b', ''), 827 function(node, match, offset) { 828 return insertInlineLogo(node, match, offset, 'magnum-analytics', 'MAGNUM-ANALYTICS'); 829 } 830 ); 831 matchText( 832 element, new RegExp('\\b' + 'MAGNUM(\\s+|-)NMS' + '\\b', ''), 833 function(node, match, offset) { 834 return insertInlineLogo(node, match, offset, 'magnum-nms', 'MAGNUM-NMS'); 835 } 836 ); 837 matchText( 838 element, new RegExp('\\b' + 'MAGNUM(\\s+|-)OS(?!-)' + '\\b', ''), 839 function(node, match, offset) { 840 return insertInlineLogo(node, match, offset, 'magnum-os', 'MAGNUM OS'); 841 } 842 ); 843 matchText( 844 element, new RegExp('\\b' + 'MAGNUM(?!-)(?! OS)' + '\\b', ''), 845 function(node, match, offset) { 846 return insertInlineLogo(node, match, offset, 'magnum', 'MAGNUM'); 847 } 848 ); 849 850 // Studer logo 851 matchText( 852 element, new RegExp('\\b' + 'Studer®?', ''), 853 function(node, match, offset) { 854 return insertInlineLogo(node, match, offset, 'studer', 'Studer®'); 855 } 856 ); 857 858 // ATCi logo 859 matchText( 860 element, new RegExp('\\b' + 'ATCi' + '\\b', ''), 861 function(node, match, offset) { 862 return insertInlineLogo(node, match, offset, 'atci', 'ATCi'); 863 } 864 ); 865 866 // inSITE logo 867 matchText( 868 element, new RegExp('\\b' + 'inSITEâ¢?', ''), 869 function(node, match, offset) { 870 return insertInlineLogo(node, match, offset, 'insite', 'inSITEâ¢'); 871 } 872 ); 873 874 // evEDGE logo 875 matchText( 876 element, new RegExp('\\b' + 'evEDGEâ¢?(?!-)' + '\\b', ''), 877 function(node, match, offset) { 878 return insertInlineLogo(node, match, offset, 'evedge', 'evEDGEâ¢'); 879 } 880 ); 881 882 // EQX logo 883 let htmlRem = parseFloat(window.getComputedStyle(document.documentElement).fontSize); 884 matchText( 885 element, new RegExp('\\b' + 'EQX(?!-)' + '\\b', ''), 886 function(node, match, offset) { 887 // Only convert title-sized EQX's 888 if (parseFloat(window.getComputedStyle(node.parentNode).fontSize) > htmlRem) { 889 return insertInlineLogo(node, match, offset, 'eqx', 'EQX'); 890 } else return document.createTextNode(match); 891 } 892 ); 893 894 // BRAVO Studio logo 895 matchText( 896 // new RegExp('\\b' + '(?<!-)BRAVO(?!-)' + '\\b', ''), 897 element, new RegExp('\\b' + 'BRAVO\\s+Studio(?!\')' + '\\b', ''), 898 function(node, match, offset) { 899 return insertInlineLogo(node, match, offset, 'bravo-studio', 'BRAVO Studio'); 900 } 901 ); 902 903 // BRAVO logo 904 matchText( 905 // new RegExp('\\b' + '(?<!-)BRAVO(?!-|\\s+Studio)' + '\\b', ''), 906 element, new RegExp('\\b' + 'BRAVO(?!-|\\s+Studio)' + '\\b', ''), 907 function(node, match, offset) { 908 return insertInlineLogo(node, match, offset, 'bravo', 'BRAVO'); 909 } 910 ); 911 912 // evertz.io logo 913 matchText( 914 element, new RegExp('\\b' + 'evertz\\.io' + '\\b', ''), 915 function(node, match, offset) { 916 return insertInlineLogo(node, match, offset, 'evertz-io', 'evertz.io'); 917 } 918 ); 919 920 // Ease Live logo 921 matchText( 922 element, new RegExp('\\b' + 'Ease Live' + '\\b', ''), 923 function(node, match, offset) { 924 return insertInlineLogo(node, match, offset, 'ease-live', 'Ease Live'); 925 } 926 ); 927 928 // Quintech logo 929 matchText( 930 element, new RegExp('\\b' + 'Quintech' + '\\b', ''), 931 function(node, match, offset) { 932 return insertInlineLogo(node, match, offset, 'quintech', 'Quintech'); 933 } 934 ); 935 936 // REFLEKTOR logo 937 matchText( 938 element, new RegExp('\\b' + 'REFLEKTOR' + '\\b', 'i'), 939 function(node, match, offset) { 940 return insertInlineLogo(node, match, offset, 'reflektor', 'REFLEKTOR'); 941 } 942 ); 943 944 // StreamPro logo 945 matchText( 946 element, new RegExp('\\b' + 'StreamPro' + '\\b', ''), 947 function(node, match, offset) { 948 return insertInlineLogo(node, match, offset, 'streampro', 'StreamPro'); 949 } 950 ); 951 952 // NEXX logo 953 matchText( 954 element, new RegExp('\\b' + '(?<!-)NEXX(?!-)' + '\\b', ''), 955 function(node, match, offset) { 956 return insertInlineLogo(node, match, offset, 'nexx', 'NEXX'); 957 } 958 ); 959 960 // NATX logotype 961 matchText( 962 element, new RegExp('\\b' + '(?<!-)NATX(?!-)' + '\\b', ''), 963 function(node, match, offset) { 964 return insertInlineLogo(node, match, offset, 'natx', 'NATX'); 965 } 966 ); 967 968 // PREFEX logotype 969 matchText( 970 element, new RegExp('\\b' + 'PREFEX(?!-)' + '\\b', ''), 971 function(node, match, offset) { 972 return insertInlineLogo(node, match, offset, 'prefex', 'PREFEX'); 973 } 974 ); 975 976 // evTOC logotype 977 matchText( 978 element, new RegExp('\\b' + 'evTOC' + '\\b', ''), 979 function(node, match, offset) { 980 return insertInlineLogo(node, match, offset, 'evtoc', 'evTOC'); 981 } 982 ); 983 984 // SDN-RF logotype 985 matchText( 986 element, new RegExp('\\b' + 'SDN-RF' + '\\b', ''), 987 function(node, match, offset) { 988 return insertInlineLogo(node, match, offset, 'sdn-rf', 'SDN-RF'); 989 } 990 ); 991 992 // ENX logotype 993 matchText( 994 element, new RegExp('\\b' + '(?<!-)ENX(?!-)' + '\\b', ''), 995 function(node, match, offset) { 996 return insertInlineLogo(node, match, offset, 'enx', 'ENX'); 997 } 998 ); 999 1000 // XChange logo 1001 matchText( 1002 element, new RegExp('\\b' + 'XChange' + '\\b', ''), 1003 function(node, match, offset) { 1004 return insertInlineLogo(node, match, offset, 'xchange', 'XChange'); 1005 } 1006 ); 1007 1008 // EXE logotype 1009 // matchText( 1010 // element, new RegExp('\\b' + '(?<!-)EXE(?!-)' + '\\b', ''), 1011 // function(node, match, offset) { 1012 // return insertInlineLogo(node, match, offset, 'exe', 'EXE'); 1013 // } 1014 // ); 1015 1016 // Check for slashes without proper spacing 1017 // matchText( 1018 // element, new RegExp('\\b' + '/' + '\\b', 'g'), 1019 // function(node, match, offset) { 1020 // return document.createTextNode(':::::/:::::'); 1021 // } 1022 // ); 1023} 1024 1025 1026window.addEventListener('load', function() { 1027
1028 // Background blocks min-height 1029 let sectBkgImg = document.querySelectorAll('#main-content section > img.background.full-height'); 1030 for (let x = 0; x < sectBkgImg.length; x++) { 1031 let ratio = sectBkgImg[x].parentNode.offsetWidth / sectBkgImg[x].naturalWidth; 1032 sectBkgImg[x].parentNode.style.minHeight = Math.floor(sectBkgImg[x].naturalHeight * ratio) + 'px'; 1033 } 1034 1035 1036 // Fake position:fixed; for parallaxed video backgrounds 1037 var parallaxVideos = document.querySelectorAll('.parallax > video:first-child'); 1038 for (var x = 0; x < parallaxVideos.length; x++) 1039 parallaxVideos[x].style.top = -parallaxVideos[x].parentNode.getBoundingClientRect().top + 'px'; 1040 window.addEventListener('scroll', function() { 1041 for (var x = 0; x < parallaxVideos.length; x++) 1042 parallaxVideos[x].style.top = -parallaxVideos[x].parentNode.getBoundingClientRect().top + 'px'; 1043 }, false); 1044 1045 1046 // If a hash value exists in the address 1047 if (location.hash != null && location.hash != '' && location.hash.match(/^#\w[\w\d_-]+$/)) { 1048 1049 // If an accordion id with the hash exists, expand it
1050 let collapse = document.querySelector('.accordion ' + location.hash + '.collapse'); 1051 if (collapse) { 1052 collapse = new bootstrap.Collapse(collapse); 1053 collapse.show(); 1054 } 1055 1056 // If a modal exists with this ID, show it 1057 let hashModal = document.querySelector(location.hash + '.modal'); 1058 if (hashModal) { 1059 hashModal = new bootstrap.Modal(location.hash); 1060 hashModal.show(true); 1061 } 1062 1063 // Scroll to the hash element 1064 scrollToElem(window.location.hash); 1065 1066 // Else if there is any element with id "results", scroll to it 1067 } else { 1068 let results = document.getElementById('results'); 1069 if (results) scrollToElem(results); 1070 } 1071 1072 tableDisplayHeaderHeight(); 1073 cardFlipHeight(); 1074 1075 // Since W3C has removed support for the media attribute on <source> 1076 // elements, we cannot serve videos responsively by screen size. 1077 // Remove all videos with the media attribute so only the largest 1078 // video remains. There is a campaign on to restore the media 1079 // attribute so this code might be removed someday. 1080 let htmlVideo = document.getElementsByTagName('video'); 1081 for (let x = 0, s; x < htmlVideo.length; x++) { 1082 s = htmlVideo[x].getElementsByTagName('source'); 1083 for (let y = 0; y < s.length; y++) 1084 if (s[y].getAttribute('media')) 1085 htmlVideo[x].removeChild(s[y]); 1086 } 1087 1088 // Set the data-scroll value on the <html> element to the document 1089 // scroll value, for CSS selectors. 1090 document.documentElement.setAttribute('data-scroll', window.scrollY); 1091 1092 // Enable Popper.js tooltips 1093 let toolTipElems = document.querySelectorAll('[data-bs-toggle="tooltip"]'); 1094 let toolTipList = [...toolTipElems].map(elem => new bootstrap.Tooltip(elem)); 1095 1096 1097 // Change replaced SVG logo colour on tab events 1098 let tabs = document.querySelectorAll('.nav-tabs .nav-item *[role="tab"]'); 1099 for (let x = 0; x < tabs.length; x++) { 1100 tabs[x].addEventListener('shown.bs.tab', function(e) { 1101 setTimeout(function() { 1102 svgLogoColorSet(e.target); 1103 svgLogoColorSet(e.relatedTarget); 1104 }, 100); 1105 }, false); 1106 } 1107 1108 1109 // Enable lightbox video links 1110 let lightboxVideo = document.querySelectorAll('*[data-lightbox-video]'); 1111 for (let x = 0; x < lightboxVideo.length; x++) { 1112 lightboxVideo[x].addEventListener('click', function() { 1113 PAGE_LIGHTBOX.activate(JSON.parse(this.getAttribute('data-lightbox-video')), true); 1114 }); 1115 } 1116 1117}, false); 1118 1119 1120document.addEventListener('scroll', function() { 1121 1122 // Record the scroll distance of the page in the <html> element 1123 document.documentElement.setAttribute('data-scroll', window.scrollY); 1124 1125 if (PAGE_SUBMENU) PAGE_SUBMENU.highlight(); 1126}, false); 1127 1128 1129// Replace characters and images on user copy 1130// document.body.addEventListener('copy', function(e) { 1131// let contents = window.getSelection().getRangeAt(0).cloneContents(); 1132 1133// // Remove nodes that shouldn't be visible 1134// let invisiNodes = [ 1135// 'head', 1136// 'script', 1137// '.d-none', 1138// '.invisible', 1139// '.skip-nav', 1140// 'noscript', 1141// '[aria-hidden="true"]', 1142// '[aria-expanded="false"] + .dropdown-menu' 1143// ]; 1144// for (let x = 0, n; x < invisiNodes.length; x++) { 1145// n = contents.querySelectorAll(invisiNodes[x]); 1146// for (let y = 0; y < n.length; y++) 1147// n[y].parentNode.removeChild(n[y]); 1148// } 1149 1150// let doc = document.createElement('html'); 1151// doc.appendChild(contents); 1152// e.clipboardData.setData('text/html', doc.innerHTML); 1153 1154// // Replace images with alt-text 1155// let imgs = contents.querySelectorAll('img'); 1156// for (let x = 0; x < imgs.length; x++) 1157// imgs[x].parentNode.replaceChild(document.createTextNode(imgs[x].alt), imgs[x]); 1158 1159// // Get text content of remaining node tree 1160// let text = contents.textContent; 1161 1162// // Replace non-breaking hyphens with regular hyphens 1163// text = text.replace(/\u2011/g, '-'); 1164 1165// // Remove zero-width no-break space 1166// text = text.replace(/\ufeff/g, ''); 1167 1168// e.clipboardData.setData('text/plain', text); 1169// e.preventDefault(); 1170// }, false); 1171 1172 1173window.addEventListener('resize', function() { 1174
1175 // Background blocks min-height 1176 let sectBkgImg = document.querySelectorAll('#main-content section > img.background.full-height'); 1177 for (let x = 0; x < sectBkgImg.length; x++) { 1178 let ratio = sectBkgImg[x].parentNode.offsetWidth / sectBkgImg[x].naturalWidth; 1179 sectBkgImg[x].parentNode.style.minHeight = Math.floor(sectBkgImg[x].naturalHeight * ratio) + 'px'; 1180 } 1181 1182 tableDisplayHeaderHeight(); 1183 cardFlipHeight(); 1184 1185}, false);
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.