1let spectraImageGalleryLoadStatus = true; 2let clickedImageId = null; 3 4const UAGBImageGalleryMasonry = { 5 initByOffset( $selector, instance ){ 6 // Verify $selector and instance. 7 if ( ! $selector || ! instance ) { 8 return; 9 } 10 11 // Add class for scroll not init. 12 $selector.classList.add( 'scroll-not-init' ); 13 14 // Add class for last image not loaded. 15 $selector.classList.add( 'last-image-not-loaded' ); 16 17 const getAllImages = $selector.querySelectorAll( 'img' ); 18 if( getAllImages.length ){ 19 // Get last image. 20 const getLastImage = getAllImages[ getAllImages.length - 1 ]; 21 // Add event listener for last image. 22 getLastImage.addEventListener( 'load', () => { 23 // You can perform additional actions here once the image has loaded. 24 // Remove class for last image not loaded. 25 $selector.classList.remove( 'last-image-not-loaded' ); 26 setTimeout( function() { 27 instance.layout(); 28 }, 100 ); 29 } 30 ); 31 } 32 33 let timeOutInstance = null; 34 // Get scroll position dynamically. 35 window.addEventListener( 'scroll', function() { 36 if ( ! $selector.classList.contains( 'scroll-not-init' ) ) { 37 return; 38 } 39 // Clear timeout instance. 40 clearTimeout( timeOutInstance ); 41 42 if ( UAGBImageGalleryMasonry.presentInViewport( $selector ) ) { 43 // If $selector comes in view port then init masonry. 44 $selector.classList.remove( 'scroll-not-init' ); 45 // Init masonry. 46 timeOutInstance = setTimeout( function() { 47 instance.layout(); 48 }, 100 ); 49 } 50 } ); 51 }, 52 init( $attr, $selector, lightboxSettings, thumbnailSettings ) { 53 let count = 2; 54 const windowHeight50 = window.innerHeight / 1.25; 55 const $scope = document.querySelector( $selector ); 56 let thumbnailSwiper = null; 57 if ( $attr.lightboxThumbnails ) { 58 thumbnailSwiper = new Swiper( `${$selector}+.spectra-image-gallery__control-lightbox .spectra-image-gallery__control-lightbox--thumbnails`, 59 thumbnailSettings 60 ); 61 lightboxSettings = { 62 ...lightboxSettings, 63 thumbs: { 64 swiper: thumbnailSwiper, 65 }, 66 } 67 } 68 const lightboxSwiper = new Swiper( `${$selector}+.spectra-image-gallery__control-lightbox .spectra-image-gallery__control-lightbox--main`, 69 lightboxSettings 70 ) 71 lightboxSwiper.lazy.load(); 72 loadLightBoxImages( $scope, lightboxSwiper, null, $attr, thumbnailSwiper ); 73 const loader = $scope?.querySelector( '.spectra-image-gallery__control-loader' ); 74 const loadButton = $scope?.querySelector( '.spectra-image-gallery__control-button' ); 75 if ( $attr.feedPagination && $attr.paginateUseLoader ) { 76 window.addEventListener( 'scroll', function () { 77 let mediaItem = $scope?.querySelector( '.spectra-image-gallery__media-wrapper' ); 78 if ( ! mediaItem ) { 79 mediaItem = $scope; 80 } 81 const boundingClientRect = mediaItem.lastElementChild.getBoundingClientRect(); 82 const offsetTop = boundingClientRect.top + window.scrollY; 83 if ( window.pageYOffset + windowHeight50 >= offsetTop ) { 84 const $args = { 85 page_number: count, 86 }; 87 const total = $attr.gridPages; 88 if ( spectraImageGalleryLoadStatus ) { 89 if ( count > total ) { 90 loader.style.display = 'none'; 91 } 92 if ( count <= total ) { 93 UAGBImageGalleryMasonry.callAjax( $scope, $args, $attr, false, count, $selector, lightboxSwiper, thumbnailSwiper ); 94 count++; 95 spectraImageGalleryLoadStatus = false; 96 } 97 } 98 } 99 } ); 100 } else if ( $attr.feedPagination && ! $attr.paginateUseLoader ) { 101 loadButton.onclick = function () { 102 const total = $attr.gridPages; 103 const $args = { 104 total, 105 page_number: count, 106 }; 107 loadButton.classList.add( 'disabled' ); 108 if ( spectraImageGalleryLoadStatus ) { 109 if ( count <= total ) { 110 UAGBImageGalleryMasonry.callAjax( $scope, $args, $attr, false, count, $selector, lightboxSwiper, thumbnailSwiper ); 111 count++; 112 spectraImageGalleryLoadStatus = false; 113 } 114 } 115 }; 116 } 117 }, 118 119 createElementFromHTML( htmlString ) { 120 const htmlElement = document.createElement( 'div' ); 121 const htmlCleanString = htmlString.replace( /\s+/gm, ' ' ).replace( /( )+/gm, ' ' ).trim(); 122 htmlElement.innerHTML = htmlCleanString; 123 return htmlElement; 124 }, 125 126 getCustomURL( image, $attr ) {
127 const urlValidRegex = new RegExp( 128 '^((http|https)://)(www.)?[a-zA-Z0-9@:%._\\+~#?&//=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%._\\+~#?&//=]*)$' 129 ); 130 const imageID = parseInt( image.getAttribute( 'data-spectra-gallery-image-id' ) ); 131 return urlValidRegex.test( $attr?.customLinks[ imageID ] ) ? $attr.customLinks[ imageID ] : undefined; 132 }, 133 134 openCustomURL( customURL ) { 135 window.open( customURL, '_blank' ); 136 }, 137 138 addClickEvents( element, $attr ) { 139 const imageElements = element?.querySelectorAll( '.spectra-image-gallery__media-wrapper' ); 140 imageElements.forEach( ( image ) => { 141 const imageURL = UAGBImageGalleryMasonry.getCustomURL( image, $attr ); 142 if ( imageURL ) { 143 image.style.cursor = 'pointer'; 144 image.addEventListener( 'click', () => UAGBImageGalleryMasonry.openCustomURL( imageURL ) ); 145 image.addEventListener( 'keydown', ( event ) => { 146 if ( 13 === event.keyCode || 32 === event.keyCode ) { 147 event.preventDefault(); 148 UAGBImageGalleryMasonry.openCustomURL( imageURL ); 149 } 150 } ); 151 } 152 } ); 153 }, 154 155 callAjax( $scope, $obj, $attr, append = false, count, $selector, lightboxSwiper, thumbnailSwiper ) { 156 const mediaData = new FormData(); 157 mediaData.append( 'action', 'uag_load_image_gallery_masonry' ); 158 mediaData.append( 'nonce', uagb_image_gallery.uagb_image_gallery_masonry_ajax_nonce ); 159 mediaData.append( 'page_number', $obj.page_number ); 160 mediaData.append( 'attr', JSON.stringify( $attr ) ); 161 fetch( uagb_image_gallery.ajax_url, { 162 method: 'POST', 163 credentials: 'same-origin', 164 body: mediaData, 165 } ) 166 .then( ( resp ) => resp.json() ) 167 .then( function ( data ) { 168 let element = $scope?.querySelector( '.spectra-image-gallery__layout--masonry' ); 169 if ( ! element ) { 170 element = $scope; 171 } 172 173 setTimeout( function () { 174 const isotope = new Isotope( element, { 175 itemSelector: '.spectra-image-gallery__media-wrapper--isotope', 176 stagger: 10, 177 } ); 178 isotope.insert( UAGBImageGalleryMasonry.createElementFromHTML( data.data ) ); 179 imagesLoaded( element ).on( 'progress', function () { 180 isotope.layout(); 181 } ); 182 imagesLoaded( element ).on( 'always', function () { 183 const currentScope = document.querySelector( $selector ); 184 const loadButton = currentScope?.querySelector( '.spectra-image-gallery__control-button' ) 185 loadButton?.classList?.remove( 'disabled' ); 186 loadLightBoxImages( currentScope, lightboxSwiper, null, $attr, thumbnailSwiper ); 187 } ); 188 if ( 'url' === $attr.imageClickEvent && $attr.customLinks ) { 189 UAGBImageGalleryMasonry.addClickEvents( element, $attr ); 190 } 191 spectraImageGalleryLoadStatus = true; 192 if ( true === append ) { 193 $scope?.querySelector( '.spectra-image-gallery__control-button' ).classList.toggle( 'disabled' ); 194 } 195 if ( count === parseInt( $obj.total ) ) { 196 $scope.querySelector( '.spectra-image-gallery__control-button' ).style.opacity = 0; 197 setTimeout( () => { 198 $scope.querySelector( '.spectra-image-gallery__control-button' ).parentElement.style.display = 199 'none'; 200 }, 2000 ); 201 } 202 }, 500 ); 203 } ); 204 }, 205 presentInViewport( element ) { 206 const rect = element.getBoundingClientRect(); 207 return ( 208 rect.top >= 0 && 209 rect.left >= 0 && 210 rect.bottom <= ( window.innerHeight || document.documentElement.clientHeight ) && 211 rect.right <= ( window.innerWidth || document.documentElement.clientWidth ) 212 ); 213 }, 214}; 215 216const UAGBImageGalleryPagedGrid = { 217 init( $attr, $selector, lightboxSettings, thumbnailSettings ) { 218 let count = 1; 219 const $scope = document.querySelector( $selector ); 220 let thumbnailSwiper = null; 221 if ( $attr.lightboxThumbnails ){ 222 thumbnailSwiper = new Swiper( `${$selector}+.spectra-image-gallery__control-lightbox .spectra-image-gallery__control-lightbox--thumbnails`, 223 thumbnailSettings 224 ); 225 lightboxSettings = { 226 ...lightboxSettings, 227 thumbs: { 228 swiper: thumbnailSwiper, 229 }, 230 } 231 } 232 const lightboxSwiper = new Swiper( `${$selector}+.spectra-image-gallery__control-lightbox .spectra-image-gallery__control-lightbox--main`,
233 lightboxSettings 234 ) 235 lightboxSwiper.lazy.load(); 236 loadLightBoxImages( $scope, lightboxSwiper, count, $attr, thumbnailSwiper ); 237 const arrows = $scope?.querySelectorAll( '.spectra-image-gallery__control-arrows--grid' ); 238 const dots = $scope?.querySelectorAll( '.spectra-image-gallery__control-dot' ); 239 for ( let i = 0; i < arrows.length; i++ ) { 240 arrows[ i ].addEventListener( 'click', ( event ) => { 241 const thisArrow = event.currentTarget; 242 let page = count; 243 switch ( thisArrow.getAttribute( 'data-direction' ) ) { 244 case 'Prev': 245 --page; 246 break; 247 case 'Next': 248 ++page; 249 break; 250 } 251 let mediaItem = $scope?.querySelector( '.spectra-image-gallery__media-wrapper' ); 252 if ( ! mediaItem ) { 253 mediaItem = $scope; 254 } 255 const total = $attr.gridPages; 256 const $args = { 257 page_number: page, 258 total, 259 }; 260 if ( page === total || page === 1 ) { 261 thisArrow.disabled = true; 262 } else { 263 arrows.forEach( ( ele ) => { 264 ele.disabled = false; 265 } ); 266 } 267 if ( page <= total && page >= 1 ) { 268 UAGBImageGalleryPagedGrid.callAjax( $scope, $args, $attr, arrows, $selector, lightboxSwiper, thumbnailSwiper ); 269 count = page; 270 } 271 } ); 272 } 273 for ( let i = 0; i < dots.length; i++ ) { 274 dots[ i ].addEventListener( 'click', ( event ) => { 275 const thisDot = event.currentTarget; 276 const page = thisDot.getAttribute( 'data-go-to' ); 277 let mediaItem = $scope?.querySelector( '.spectra-image-gallery__media-wrapper' ); 278 if ( ! mediaItem ) { 279 mediaItem = $scope; 280 } 281 const $args = { 282 page_number: page, 283 total: $attr.gridPages, 284 }; 285 UAGBImageGalleryPagedGrid.callAjax( $scope, $args, $attr, arrows, $selector, lightboxSwiper, thumbnailSwiper ); 286 count = page; 287 } ); 288 } 289 }, 290 291 createElementFromHTML( htmlString ) { 292 const htmlElement = document.createElement( 'div' ); 293 const htmlCleanString = htmlString.replace( /\s+/gm, ' ' ).replace( /( )+/gm, ' ' ).trim(); 294 htmlElement.innerHTML = htmlCleanString; 295 return htmlElement; 296 }, 297 298 getCustomURL( image, $attr ) { 299 const urlValidRegex = new RegExp( 300 '^((http|https)://)(www.)?[a-zA-Z0-9@:%._\\+~#?&//=\\-]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%._\\+~#?&//=]*)$' 301 ); 302 const imageID = parseInt( image.getAttribute( 'data-spectra-gallery-image-id' ) ); 303 return urlValidRegex.test( $attr?.customLinks[ imageID ] ) ? $attr.customLinks[ imageID ] : undefined; 304 }, 305 306 openCustomURL( customURL ) { 307 window.open( customURL, '_blank' ); 308 }, 309 310 addClickEvents( element, $attr ) { 311 const imageElements = element?.querySelectorAll( '.spectra-image-gallery__media-wrapper' ); 312 imageElements.forEach( ( image ) => { 313 const imageURL = UAGBImageGalleryPagedGrid.getCustomURL( image, $attr ); 314 if ( imageURL ) { 315 image.style.cursor = 'pointer'; 316 image.setAttribute( 'tabindex', '0' ); 317 image.addEventListener( 'click', () => UAGBImageGalleryPagedGrid.openCustomURL( imageURL ) ); 318 image.addEventListener( 'keydown', ( event ) => { 319 if ( 13 === event.keyCode || 32 === event.keyCode ) { 320 UAGBImageGalleryPagedGrid.openCustomURL( imageURL ); 321 } 322 } ); 323 } 324 } ); 325 }, 326 327 callAjax( $scope, $obj, $attr, arrows, $selector, lightboxSwiper, thumbnailSwiper ) { 328 const mediaData = new FormData(); 329 mediaData.append( 'action', 'uag_load_image_gallery_grid_pagination' ); 330 mediaData.append( 'nonce', uagb_image_gallery.uagb_image_gallery_grid_pagination_ajax_nonce ); 331 mediaData.append( 'page_number', $obj.page_number ); 332 mediaData.append( 'attr', JSON.stringify( $attr ) ); 333 fetch( uagb_image_gallery.ajax_url, { 334 method: 'POST', 335 credentials: 'same-origin', 336 body: mediaData, 337 } ) 338 .then( ( resp ) => resp.json() ) 339 .then( function ( data ) { 340 if ( data.success === false ) { 341 return; 342 } 343 setTimeout( function () { 344 let element = $scope?.querySelector( '.spectra-image-gallery__layout--isogrid' ); 345 if ( ! element ) { 346 element = $scope; 347 } 348 const mediaElements = element.querySelectorAll( '.spectra-image-gallery__media-wrapper--isotope' ); 349 const isotope = new Isotope( element, { 350 itemSelector: '.spectra-image-gallery__media-wrapper--isotope', 351 layoutMode: 'fitRows', 352 } );
353 mediaElements.forEach( ( mediaEle ) => { 354 isotope.remove( mediaEle ); 355 isotope.layout(); 356 } ); 357 isotope.insert( UAGBImageGalleryPagedGrid.createElementFromHTML( data.data ) ); 358 imagesLoaded( element ).on( 'progress', function () { 359 isotope.layout(); 360 } ); 361 imagesLoaded( element ).on( 'always', function () { 362 const currentScope = document.querySelector( $selector ); 363 loadLightBoxImages( currentScope, lightboxSwiper, parseInt( $obj.page_number ), $attr, thumbnailSwiper ); 364 } ); 365 if ( $attr.customLinks ) { 366 UAGBImageGalleryPagedGrid.addClickEvents( element, $attr ); 367 } 368 if ( parseInt( $obj.page_number ) === 1 ) { 369 arrows.forEach( ( arrow ) => { 370 arrow.disabled = arrow.getAttribute( 'data-direction' ) === 'Prev'; 371 } ); 372 } else if ( parseInt( $obj.page_number ) === parseInt( $obj.total ) ) { 373 arrows.forEach( ( arrow ) => { 374 arrow.disabled = arrow.getAttribute( 'data-direction' ) === 'Next'; 375 } ); 376 } else { 377 arrows.forEach( ( arrow ) => { 378 arrow.disabled = false; 379 } ); 380 } 381 $scope 382 ?.querySelector( '.spectra-image-gallery__control-dot--active' ) 383 .classList.toggle( 'spectra-image-gallery__control-dot--active' ); 384 const $activeDot = $scope?.querySelectorAll( '.spectra-image-gallery__control-dot' ); 385 $activeDot[ parseInt( $obj.page_number ) - 1 ].classList.toggle( 386 'spectra-image-gallery__control-dot--active' 387 ); 388 }, 500 ); 389 } ); 390 }, 391}; 392 393const cycleInLightbox = ( selector, e ) => { 394 // Check if Tab key was pressed 395 if ( e.key === 'Tab' ) { 396 const focusableElements = selector.querySelectorAll( 'button, div[data-role="button"], [href], [tabindex]:not([tabindex="-1"])' ); 397 const firstFocusableElement = focusableElements[0]; 398 const lastFocusableElement = focusableElements[focusableElements.length - 1]; 399 400 // Get the active element using ownerDocument 401 const activeElement = e.target.ownerDocument.activeElement; 402 403 // Check if Shift + Tab was pressed and if the current active element is the first one 404 if ( e.shiftKey && activeElement === firstFocusableElement ) { 405 e.preventDefault(); 406 lastFocusableElement.focus(); 407 } 408 // Check if Tab was pressed and if the current active element is the last one 409 else if ( !e.shiftKey && activeElement === lastFocusableElement ) { 410 e.preventDefault(); 411 firstFocusableElement.focus(); 412 } 413 } 414} 415 416 417const loadLightBoxImages = ( blockScope, lightboxSwiper, pageNum, attr, thumbnailSwiper ) => { 418 if ( ! blockScope ) { 419 return; 420 } 421 const pageLimit = attr.paginateLimit; 422 423 const theBody = document.querySelector( 'body' ); 424 const updateCounter = ( curPage ) => { 425 const lightbox = blockScope?.nextElementSibling; 426 const counter = lightbox.querySelector( '.spectra-image-gallery__control-lightbox--count-page' ); 427 if ( counter ) { 428 counter.innerHTML = parseInt( curPage ) + 1; 429 } 430 }; 431 lightboxSwiper.on( 'activeIndexChange', ( swiperInstance ) => { 432 if ( attr.lightboxThumbnails ) { 433 thumbnailSwiper.slideTo( swiperInstance.activeIndex ); 434 } 435 if ( attr.lightboxDisplayCount ) { 436 updateCounter( swiperInstance.activeIndex ); 437 } 438 lightboxSwiper.lazy.load(); 439 } ) 440 if ( attr.lightboxThumbnails ) { 441 thumbnailSwiper.on( 'activeIndexChange', ( swiperInstance ) => { 442 lightboxSwiper.slideTo( swiperInstance.activeIndex ); 443 } ); 444 445 } 446 const lightbox = blockScope?.nextElementSibling; 447 let lightboxHandlers = {}; 448 if ( lightbox && lightbox?.classList.contains( 'spectra-image-gallery__control-lightbox' ) ) { 449 // create a lightbox cycle listeners. 450 const createListeners = () => { 451 const cycleInLightboxWithID = cycleInLightbox.bind( null, lightbox ); 452 453 // Function to add the event listener 454 function addEventListener() { 455 lightbox.addEventListener( 'keydown', cycleInLightboxWithID ); 456 } 457 458 // Function to remove the event listener 459 function removeEventListener() { 460 lightbox.removeEventListener( 'keydown', cycleInLightboxWithID ); 461 } 462 463 return { addEventListener, removeEventListener }; 464 }; 465 466 lightboxHandlers = createListeners(); 467 468 lightbox.addEventListener( 'keydown', ( event ) => { 469 if ( 27 === event.keyCode ) { 470 theBody.style.overflow = ''; 471 lightbox.style.opacity = 0; 472 setTimeout( () => { 473 lightbox.style.display = 'none'; 474 lightboxHandlers.removeEventListener(); 475 if ( clickedImageId ) { 476 const clickedImage = document.querySelector( `[data-spectra-gallery-image-id="${clickedImageId}"]` ); 477 clickedImage?.focus(); 478 clickedImageId = null; 479 } 480 }, 250 ); 481 } 482 } ); 483 lightbox.style.display = 'none'; 484 if ( attr.lightboxCloseIcon ) { 485 const closeButton = lightbox.querySelector( '.spectra-image-gallery__control-lightbox--close' ); 486 if ( closeButton ) { 487 closeButton.addEventListener( 'click', () => { 488 theBody.style.overflow = ''; 489 lightbox.style.opacity = 0; 490 setTimeout( () => { 491 lightbox.style.display = 'none'; 492 if ( clickedImageId ) { 493 const clickedImage = document.querySelector( `[data-spectra-gallery-image-id="${clickedImageId}"]` ); 494 clickedImage?.focus(); 495 clickedImageId = null; 496 } 497 lightboxHandlers.removeEventListener(); 498 }, 250 ); 499 } ); 500 } 501 } 502 if ( attr.lightboxDisplayCount ) { 503 const lightboxTotal = lightbox.querySelector( '.spectra-image-gallery__control-lightbox--count-total' ); 504 lightboxTotal.innerHTML = attr.mediaGallery.length; 505 } 506 } 507 const enableLightbox = ( goTo, clickedImage ) => { 508 if ( ! lightboxSwiper || !lightbox ) { 509 return; 510 } 511 clickedImageId = clickedImage.getAttribute( 'data-spectra-gallery-image-id' ); 512 lightbox.style.display = ''; 513 lightbox.focus(); 514 setTimeout( () => { 515 lightboxSwiper.slideTo( goTo ); 516 }, 100 ); 517 setTimeout( () => { 518 lightbox.style.opacity = 1; 519 if ( lightbox?.classList.contains( 'spectra-image-gallery__control-lightbox' ) ) { 520 theBody.style.overflow = 'hidden'; 521 } 522 523 lightboxHandlers.addEventListener(); 524 525 }, 250 ); 526 } 527 528 if ( pageNum !== null ) { 529 setTimeout( () => { 530 addClickListeners( blockScope, pageNum, enableLightbox, pageLimit, attr ); 531 }, 1000 ); 532 } else { 533 addClickListeners( blockScope, null, enableLightbox, null, attr ); 534 } 535}; 536 537const generateUniqueId = ( index ) => `image-${index}-${Date.now()}`; 538 539const addClickListeners = ( $scope, pageNum, enableLightbox, pageLimit, attr ) => { 540 const images = $scope.querySelectorAll( '.spectra-image-gallery__media-wrapper' ); 541 const imageUrls = {}; 542 if ( 'image' === attr.imageClickEvent ) { 543 const mediaGallery = attr.mediaGallery;
544 mediaGallery.forEach( media => { 545 imageUrls[ media.id ] = media.url; 546 } ); 547 } 548 549 images.forEach( ( image, index ) => { 550 image.style.cursor = 'pointer'; 551 const uniqueId = generateUniqueId( index ); 552 if( 'lightbox' === attr.imageClickEvent ) { 553 image.setAttribute( 'data-spectra-gallery-image-id', uniqueId ); 554 }; 555 if ( 'image' === attr.imageClickEvent ) { 556 const imgId = image.getAttribute( 'data-spectra-gallery-image-id' ); 557 const imgURL = imageUrls[ imgId ]; 558 image.addEventListener( 'click', () => { 559 openImageInWindow( imgURL ); // To avoid opening multiple tab at same when Popup and redirect is enabled. 560 } ); 561 image.addEventListener( 'keydown', ( event ) => { 562 if ( 13 === event.keyCode || 32 === event.keyCode ) { 563 openImageInWindow( imgURL ); 564 } 565 } ); 566 } else { 567 const nextImg = pageNum !== null ? index + ( pageNum - 1 ) * pageLimit : index; 568 image.addEventListener( 'click', () => enableLightbox( nextImg, image ) ); 569 image.addEventListener( 'keydown', ( event ) => { 570 if ( 13 === event.keyCode || 32 === event.keyCode ) { 571 event.preventDefault(); 572 enableLightbox( nextImg, image ); 573 } 574 } ); 575 } 576 } ); 577} 578 579let imageWindow = null; 580const openImageInWindow = ( imageUrl ) => { 581 // Check if the window is already open 582 if ( imageWindow && !imageWindow.closed ) { 583 // If open, focus on the existing window 584 imageWindow.focus(); 585 } else { 586 // If not open or closed, open a new window 587 imageWindow = window.open( imageUrl, '_blank' ); 588 } 589}
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.