1/* ------------------------------------------------------------------------------ 2 * 3 * # Template JS core 4 * 5 * Includes minimum required JS code for proper template functioning 6 * 7 * ---------------------------------------------------------------------------- */ 8 9 10// Setup module 11// ------------------------------ 12 13const App = function () { 14 15 16 // Utils 17 // ------------------------- 18 19 // 20 // Transitions 21 // 22 23 // Disable all transitions 24 const transitionsDisabled = function() { 25 document.body.classList.add('no-transitions'); 26 }; 27 28 // Enable all transitions 29 const transitionsEnabled = function() { 30 document.body.classList.remove('no-transitions'); 31 }; 32 33 34 // 35 // Detect OS to apply custom scrollbars 36 // 37 38 // Custom scrollbar style is controlled by CSS. This function is needed to keep default 39 // scrollbars on MacOS and avoid usage of extra JS libraries 40 const detectOS = function() { 41 const platform = window.navigator.platform, 42 windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'], 43 customScrollbarsClass = 'custom-scrollbars'; 44 45 // Add class if OS is windows 46 windowsPlatforms.indexOf(platform) != -1 && document.documentElement.classList.add(customScrollbarsClass); 47 }; 48 49 50 51 // Sidebars 52 // ------------------------- 53 54 // 55 // On desktop 56 // 57 58 // Resize main sidebar 59 const sidebarMainResize = function() { 60 61 // Elements 62 const sidebarMainElement = document.querySelector('.sidebar-main'), 63 sidebarMainToggler = document.querySelectorAll('.sidebar-main-resize'), 64 resizeClass = 'sidebar-main-resized', 65 unfoldClass = 'sidebar-main-unfold'; 66 67 68 // Config 69 if (sidebarMainElement) { 70 71 // Define variables 72 const unfoldDelay = 150; 73 let timerStart, 74 timerFinish; 75 76 // Toggle classes on click 77 sidebarMainToggler.forEach(function(toggler) { 78 toggler.addEventListener('click', function(e) { 79 e.preventDefault(); 80 sidebarMainElement.classList.toggle(resizeClass); 81 !sidebarMainElement.classList.contains(resizeClass) && sidebarMainElement.classList.remove(unfoldClass); 82 }); 83 }); 84 85 // Add class on mouse enter 86 sidebarMainElement.addEventListener('mouseenter', function() { 87 clearTimeout(timerFinish); 88 timerStart = setTimeout(function() { 89 sidebarMainElement.classList.contains(resizeClass) && sidebarMainElement.classList.add(unfoldClass); 90 }, unfoldDelay); 91 }); 92 93 // Remove class on mouse leave 94 sidebarMainElement.addEventListener('mouseleave', function() { 95 clearTimeout(timerStart); 96 timerFinish = setTimeout(function() { 97 sidebarMainElement.classList.remove(unfoldClass); 98 }, unfoldDelay); 99 }); 100 } 101 }; 102 103 // Toggle main sidebar 104 const sidebarMainToggle = function() { 105 106 // Elements 107 const sidebarMainElement = document.querySelector('.sidebar-main'), 108 sidebarMainRestElements = document.querySelectorAll('.sidebar:not(.sidebar-main):not(.sidebar-component)'), 109 sidebarMainDesktopToggler = document.querySelectorAll('.sidebar-main-toggle'), 110 sidebarMainMobileToggler = document.querySelectorAll('.sidebar-mobile-main-toggle'), 111 sidebarCollapsedClass = 'sidebar-collapsed', 112 sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; 113 114 // On desktop 115 sidebarMainDesktopToggler.forEach(function(toggler) { 116 toggler.addEventListener('click', function(e) { 117 e.preventDefault(); 118 sidebarMainElement.classList.toggle(sidebarCollapsedClass); 119 }); 120 }); 121 122 // On mobile 123 sidebarMainMobileToggler.forEach(function(toggler) { 124 toggler.addEventListener('click', function(e) { 125 e.preventDefault(); 126 sidebarMainElement.classList.toggle(sidebarMobileExpandedClass); 127
128 sidebarMainRestElements.forEach(function(sidebars) { 129 sidebars.classList.remove(sidebarMobileExpandedClass); 130 }); 131 }); 132 }); 133 }; 134 135 // Toggle secondary sidebar 136 const sidebarSecondaryToggle = function() { 137 138 // Elements 139 const sidebarSecondaryElement = document.querySelector('.sidebar-secondary'), 140 sidebarSecondaryRestElements = document.querySelectorAll('.sidebar:not(.sidebar-secondary):not(.sidebar-component)'), 141 sidebarSecondaryDesktopToggler = document.querySelectorAll('.sidebar-secondary-toggle'), 142 sidebarSecondaryMobileToggler = document.querySelectorAll('.sidebar-mobile-secondary-toggle'), 143 sidebarCollapsedClass = 'sidebar-collapsed', 144 sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; 145 146 // On desktop 147 sidebarSecondaryDesktopToggler.forEach(function(toggler) { 148 toggler.addEventListener('click', function(e) { 149 e.preventDefault(); 150 sidebarSecondaryElement.classList.toggle(sidebarCollapsedClass); 151 }); 152 }); 153 154 // On mobile 155 sidebarSecondaryMobileToggler.forEach(function(toggler) { 156 toggler.addEventListener('click', function(e) { 157 e.preventDefault(); 158 sidebarSecondaryElement.classList.toggle(sidebarMobileExpandedClass); 159 160 sidebarSecondaryRestElements.forEach(function(sidebars) { 161 sidebars.classList.remove(sidebarMobileExpandedClass); 162 }); 163 }); 164 }); 165 }; 166 167 // Toggle right sidebar 168 const sidebarRightToggle = function() { 169 170 // Elements 171 const sidebarRightElement = document.querySelector('.sidebar-end'), 172 sidebarRightRestElements = document.querySelectorAll('.sidebar:not(.sidebar-end):not
172(.sidebar-component)'), 173 sidebarRightDesktopToggler = document.querySelectorAll('.sidebar-end-toggle'), 174 sidebarRightMobileToggler = document.querySelectorAll('.sidebar-mobile-end-toggle'), 175 sidebarCollapsedClass = 'sidebar-collapsed', 176 sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; 177 178 // On desktop 179 sidebarRightDesktopToggler.forEach(function(toggler) { 180 toggler.addEventListener('click', function(e) { 181 e.preventDefault(); 182 sidebarRightElement.classList.toggle(sidebarCollapsedClass); 183 }); 184 }); 185 186 // On mobile 187 sidebarRightMobileToggler.forEach(function(toggler) { 188 toggler.addEventListener('click', function(e) { 189 e.preventDefault(); 190 sidebarRightElement.classList.toggle(sidebarMobileExpandedClass); 191 192 sidebarRightRestElements.forEach(function(sidebars) { 193 sidebars.classList.remove(sidebarMobileExpandedClass); 194 }); 195 }); 196 }); 197 }; 198 199 // Toggle component sidebar 200 const sidebarComponentToggle = function() { 201 202 // Elements 203 const sidebarComponentElement = document.querySelector('.sidebar-component'), 204 sidebarComponentMobileToggler = document.querySelectorAll('.sidebar-mobile-component-toggle'), 205 sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; 206 207 // Toggle classes 208 sidebarComponentMobileToggler.forEach(function(toggler) { 209 toggler.addEventListener('click', function(e) { 210 e.preventDefault(); 211 sidebarComponentElement.classList.toggle(sidebarMobileExpandedClass); 212 }); 213 }); 214 }; 215 216 217 // Navigations 218 // ------------------------- 219 220 // Sidebar navigation 221 const navigationSidebar = function() { 222 223 // Elements 224 const navContainerClass = 'nav-sidebar', 225 navItemOpenClass = 'nav-item-open', 226 navLinkClass = 'nav-link', 227 navLinkDisabledClass = 'disabled', 228 navSubmenuContainerClass = 'nav-item-submenu', 229 navSubmenuClass = 'nav-group-sub', 230 navScrollSpyClass = 'nav-scrollspy', 231 sidebarNavElement = document.querySelectorAll(`.${navContainerClass}:not(.${navScrollSpyClass})`); 232 233 // Setup 234 sidebarNavElement.forEach(function(nav) { 235 nav.querySelectorAll(`.${navSubmenuContainerClass} > .${navLinkClass}:not(.${navLinkDisabledClass})`).forEach(function(link) { 236 link.addEventListener('click', function(e) { 237 e.preventDefault(); 238 const submenuContainer = link.closest(`.${navSubmenuContainerClass}`); 239 const submenu = link.closest(`.${navSubmenuContainerClass}`).querySelector(`:scope > .${navSubmenuClass}`); 240 241 // Collapsible 242 if(submenuContainer.classList.contains(navItemOpenClass)) { 243 new bootstrap.Collapse(submenu).hide(); 244 submenuContainer.classList.remove(navItemOpenClass); 245 } 246 else { 247 new bootstrap.Collapse(submenu).show(); 248 submenuContainer.classList.add(navItemOpenClass); 249 } 250 251 // Accordion 252 if (link.closest(`.${navContainerClass}`).getAttribute('data-nav-type') == 'accordion') { 253 for (let sibling of link.parentNode.parentNode.children) { 254 if (sibling != link.parentNode && sibling.classList.contains(navItemOpenClass)) { 255 sibling.querySelectorAll(`:scope > .${navSubmenuClass}`).forEach(function(submenu) { 256 new bootstrap.Collapse(submenu).hide(); 257 sibling.classList.remove(navItemOpenClass); 258 }); 259 } 260 } 261 } 262 }); 263 }); 264 }); 265 }; 266 267 268 // Components 269 // ------------------------- 270 271 // Tooltip 272 const componentTooltip = function() { 273 const tooltipSelector = document.querySelectorAll('[data-bs-popup="tooltip"]'); 274 275 tooltipSelector.forEach(function(popup) { 276 new bootstrap.Tooltip(popup, { 277 boundary: '.page-content' 278 }); 279 }); 280 }; 281 282 // Popover 283 const componentPopover = function() { 284 const popoverSelector = document.querySelectorAll('[data-bs-popup="popover"]'); 285 286 popoverSelector.forEach(function(popup) { 287 new bootstrap.Popover(popup, { 288 boundary: '.page-content' 289 }); 290 }); 291 }; 292 293 // "Go to top" button 294 const componentToTopButton = function() { 295 296 // Elements 297 const toTopContainer = document.querySelector('.content-wrapper'), 298 toTopElement = document.createElement('button'), 299 toTopElementIcon = document.createElement('i'), 300 toTopButtonContainer = document.createElement('div'), 301 toTopButtonColorClass = 'btn-secondary', 302 toTopButtonIconClass = 'ph-arrow-up', 303 scrollableContainer = document.querySelector('.content-inner'), 304 scrollableDistance = 250, 305 footerContainer = document.querySelector('.navbar-footer'); 306 307
308 // Append only if container exists 309 if (scrollableContainer) { 310 311 // Create button container 312 toTopContainer.appendChild(toTopButtonContainer); 313 toTopButtonContainer.classList.add('btn-to-top'); 314 315 // Create button 316 toTopElement.classList.add('btn', toTopButtonColorClass, 'btn-icon', 'rounded-pill'); 317 toTopElement.setAttribute('type', 'button'); 318 toTopButtonContainer.appendChild(toTopElement); 319 toTopElementIcon.classList.add(toTopButtonIconClass); 320 toTopElement.appendChild(toTopElementIcon); 321 322 // Show and hide on scroll 323 const to_top_button = document.querySelector('.btn-to-top'), 324 add_class_on_scroll = () => to_top_button.classList.add('btn-to-top-visible'), 325 remove_class_on_scroll = () => to_top_button.classList.remove('btn-to-top-visible'); 326 327 scrollableContainer.addEventListener('scroll', function() { 328 const scrollpos = scrollableContainer.scrollTop; 329 scrollpos >= scrollableDistance ? add_class_on_scroll() : remove_class_on_scroll(); 330 if(footerContainer) { 331 if (this.scrollHeight - this.scrollTop - this.clientHeight <= footerContainer.clientHeight) { 332 to_top_button.style.bottom = footerContainer.clientHeight + 20 + 'px'; 333 } 334 else { 335 to_top_button.removeAttribute('style'); 336 } 337 } 338 }); 339 340 // Scroll to top on click 341 document.querySelector('.btn-to-top .btn').addEventListener('click', function() { 342 scrollableContainer.scrollTo(0, 0); 343 }); 344 } 345 }; 346 347 348 // Card actions 349 // ------------------------- 350 351 // Reload card (uses BlockUI extension) 352 const cardActionReload = function() { 353 354 // Elements 355 const buttonClass = '[data-card-action=reload]', 356 containerClass = 'card', 357 overlayClass = 'card-overlay', 358 spinnerClass = 'ph-circle-notch', 359 overlayAnimationClass = 'card-overlay-fadeout'; 360 361 // Configure 362 document.querySelectorAll(buttonClass).forEach(function(button) { 363 button.addEventListener('click', function(e) { 364 e.preventDefault(); 365 366 // Elements 367 const parentContainer = button.closest(`.${containerClass}`), 368 overlayElement = document.createElement('div'), 369 overlayElementIcon = document.createElement('i'); 370 371 // Append overlay with icon 372 overlayElement.classList.add(overlayClass); 373 parentContainer.appendChild(overlayElement); 374 overlayElementIcon.classList.add(spinnerClass, 'spinner', 'text-body'); 375 overlayElement.appendChild(overlayElementIcon); 376 377 // Remove overlay after 2.5s, for demo only 378 setTimeout(function() { 379 overlayElement.classList.add(overlayAnimationClass); 380 ['animationend', 'animationcancel'].forEach(function(e) { 381 overlayElement.addEventListener(e, function() { 382 overlayElement.remove(); 383 }); 384 }); 385 }, 2500); 386 }); 387 }); 388 }; 389 390 // Collapse card 391 const cardActionCollapse = function() { 392 393 // Elements 394 const buttonClass = '[data-card-action=collapse]', 395 cardCollapsedClass = 'card-collapsed'; 396 397 // Setup 398 document.querySelectorAll(buttonClass).forEach(function(button) { 399 button.addEventListener('click', function(e) { 400 e.preventDefault(); 401 402 const parentContainer = button.closest('.card'), 403 collapsibleContainer = parentContainer.querySelectorAll(':scope > .collapse'); 404 405 if (parentContainer.classList.contains(cardCollapsedClass)) { 406 parentContainer.classList.remove(cardCollapsedClass); 407 collapsibleContainer.forEach(function(toggle) { 408 new bootstrap.Collapse(toggle, { 409 show: true 410 }); 411 }); 412 } 413 else { 414 parentContainer.classList.add(cardCollapsedClass); 415 collapsibleContainer.forEach(function(toggle) { 416 new bootstrap.Collapse(toggle, { 417 hide: true 418 }); 419 }); 420 } 421 }); 422 }); 423 }; 424 425 // Remove card 426 const cardActionRemove = function() { 427 428 // Elements 429 const buttonClass = '[data-card-action=remove]', 430 containerClass = 'card' 431 432 // Config
433 document.querySelectorAll(buttonClass).forEach(function(button) { 434 button.addEventListener('click', function(e) { 435 e.preventDefault(); 436 button.closest(`.${containerClass}`).remove(); 437 }); 438 }); 439 }; 440 441 // Card fullscreen mode 442 const cardActionFullscreen = function() { 443 444 // Elements 445 const buttonAttribute = '[data-card-action=fullscreen]', 446 buttonClass = 'text-body', 447 buttonContainerClass = 'd-inline-flex', 448 cardFullscreenClass = 'card-fullscreen', 449 collapsedClass = 'collapsed-in-fullscreen', 450 scrollableContainerClass = 'content-inner', 451 fullscreenAttr = 'data-fullscreen'; 452 453 // Configure 454 document.querySelectorAll(buttonAttribute).forEach(function(button) { 455 button.addEventListener('click', function(e) { 456 e.preventDefault(); 457 458 // Get closest card container 459 const cardFullscreen = button.closest('.card'); 460 461 // Toggle required classes 462 cardFullscreen.classList.toggle(cardFullscreenClass); 463 464 // Toggle classes depending on state 465 if (!cardFullscreen.classList.contains(cardFullscreenClass)) { 466 button.removeAttribute(fullscreenAttr); 467 cardFullscreen.querySelectorAll(`:scope > .${collapsedClass}`).forEach(function(collapsedElement) { 468 collapsedElement.classList.remove('show'); 469 }); 470 document.querySelector(`.${scrollableContainerClass}`).classList.remove('overflow-hidden'); 471 button.closest(`.${buttonContainerClass}`).querySelectorAll(`:scope > .${buttonClass}:not(${buttonAttribute})`).forEach(function(actions) { 472 actions.classList.remove('d-none'); 473 }); 474 } 475 else { 476 button.setAttribute(fullscreenAttr, 'active'); 477 cardFullscreen.removeAttribute('style'); 478 cardFullscreen.querySelectorAll(`:scope > .collapse:not(.show)`).forEach(function(collapsedElement) { 479 collapsedElement.classList.add('show', `.${collapsedClass}`); 480 }); 481 document.querySelector(`.${scrollableContainerClass}`).classList.add('overflow-hidden'); 482 button.closest(`.${buttonContainerClass}`).querySelectorAll(`:scope > .${buttonClass}:not(${buttonAttribute})`).forEach(function(actions) { 483 actions.classList.add('d-none'); 484 }); 485 } 486 }); 487 }); 488 }; 489 490 491 // Misc 492 // ------------------------- 493 494 // Dropdown submenus. Trigger on click 495 const dropdownSubmenu = function() { 496 497 // Classes 498 const menuClass = 'dropdown-menu', 499 submenuClass = 'dropdown-submenu', 500 menuToggleClass = 'dropdown-toggle', 501 disabledClass = 'disabled', 502 showClass = 'show'; 503 504 if(submenuClass) { 505 506 // Toggle submenus on all levels 507 document.querySelectorAll(`.${menuClass} .${submenuClass}:not(.${disabledClass}) .${menuToggleClass}`).forEach(function(link) { 508 link.addEventListener('click', function(e) { 509 e.stopPropagation(); 510 e.preventDefault(); 511 512 // Toggle classes 513 link.closest(`.${submenuClass}`).classList.toggle(showClass); 514 link.closest(`.${submenuClass}`).querySelectorAll(`:scope > .${menuClass}`).forEach(function(children) { 515 children.classList.toggle(showClass); 516 }); 517 518 // When submenu is shown, hide others in all siblings 519 for (let sibling of link.parentNode.parentNode.children) { 520 if (sibling != link.parentNode) { 521 sibling.classList.remove(showClass); 522 sibling.querySelectorAll(`.${showClass}`).forEach(function(submenu) { 523 submenu.classList.remove(showClass); 524 }); 525 } 526 } 527 }); 528 }); 529 530 // Hide all levels when parent dropdown is closed 531 document.querySelectorAll(`.${menuClass}`).forEach(function(link) { 532 if(!link.parentElement.classList.contains(submenuClass)) { 533 link.parentElement.addEventListener('hidden.bs.dropdown', function(e) { 534 link.querySelectorAll(`.${menuClass}.${showClass}`).forEach(function(children) { 535 children.classList.remove(showClass); 536 }); 537 }); 538 } 539 }); 540 } 541 }; 542 543 544 545 // 546 // Return objects assigned to module 547 // 548 549 return { 550 551 // Disable transitions before page is fully loaded
552 initBeforeLoad: function() { 553 detectOS(); 554 transitionsDisabled(); 555 }, 556 557 // Enable transitions when page is fully loaded 558 initAfterLoad: function() { 559 transitionsEnabled(); 560 }, 561 // Initialize all components 562 initComponents: function() { 563 componentTooltip(); 564 componentPopover(); 565 componentToTopButton(); 566 }, 567 568 // Initialize all sidebars 569 initSidebars: function() { 570 sidebarMainResize(); 571 sidebarMainToggle(); 572 sidebarSecondaryToggle(); 573 sidebarRightToggle(); 574 sidebarComponentToggle(); 575 }, 576 577 // Initialize all navigations 578 initNavigations: function() { 579 navigationSidebar(); 580 }, 581 582 // Initialize all card actions 583 initCardActions: function() { 584 cardActionReload(); 585 cardActionCollapse(); 586 cardActionRemove(); 587 cardActionFullscreen(); 588 }, 589 590 // Dropdown submenu 591 initDropdowns: function() { 592 dropdownSubmenu(); 593 }, 594 595 // Initialize core 596 initCore: function() { 597 App.initBeforeLoad(); 598 App.initSidebars(); 599 App.initNavigations(); 600 App.initComponents(); 601 App.initCardActions(); 602 App.initDropdowns(); 603 } 604 }; 605}(); 606 607 608 609// Initialize module 610// ------------------------------ 611function ChonMenu(menu) { 612 $("#_NavMenu li.nav-item a.nav-link").removeClass('active'); 613 $("#_NavMenu li.nav-item a.nav-link[href='" + menu + "']").addClass('active'); 614 615 $("#_NavMenu").find("li[class*='nav-item-submenu']").removeClass('nav-item-expanded'); 616 $("#_NavMenu").find("li[class*='nav-item-submenu']").removeClass('nav-item-open'); 617 $("#_NavMenu").find("ul[class*='nav-group-sub']").attr('style', 'display:none'); 618 619 var _class = $("#_NavMenu li.nav-item a.nav-link[href='" + menu + "']").parent().parent().parent().attr('class'); 620 if (_class === undefined) return; 621 if (_class.toString().indexOf("nav-item-submenu") >= 0) { 622 $("#_NavMenu li.nav-item a.nav-link[href='" + menu + "']").parent().parent().parent().addClass("nav-item-expanded"); 623 $("#_NavMenu li.nav-item a.nav-link[href='" + menu + "']").parent().parent().parent().addClass("nav-item-open"); 624 $("#_NavMenu li.nav-item a.nav-link[href='" + menu + "']").parent().parent().attr('style', 'display:block'); 625 } 626 627 if (getWidth() < 1000) { 628 if ($('body').hasClass('sidebar-xs') === true) { 629 $('body').removeClass('sidebar-xs'); 630 } 631 632 if ($('body').hasClass('sidebar-mobile-main') === true) { 633 $('body').removeClass('sidebar-mobile-main'); 634 } 635 //sidebar-mobile-main 636 } 637 638} 639 640function getWidth() { 641 return Math.max( 642 document.body.scrollWidth, 643 document.documentElement.scrollWidth, 644 document.body.offsetWidth, 645 document.documentElement.offsetWidth, 646 document.documentElement.clientWidth 647 ); 648} 649 650function KhoiTaoApp() { 651 652 if (localStorage.getItem('sidebarType') != null) { 653 $('body').addClass(localStorage.getItem('sidebarType')); 654 } 655 656 App.initBeforeLoad(); 657 App.initCore(); 658 App.initAfterLoad(); 659 // FixedSidebarCustomScroll.init(); 660} 661 662// Initialize module 663// ------------------------------ 664 665// When content is loaded 666document.addEventListener('DOMContentLoaded', function() { 667 App.initCore(); 668}); 669 670// When page is fully loaded 671window.addEventListener('load', function() { 672 App.initAfterLoad(); 673}); 674 675function toggleFullScreen() { 676 677 var elem = document.body; 678 // ## The below if statement seems to work better ## if ((document.fullScreenElement && document.fullScreenElement !== null) || (document.msfullscreenElement && document.msfullscreenElement !== null) || (!document.mozFullScreen && !document.webkitIsFullScreen)) { 679 if ((document.fullScreenElement !== undefined && document.fullScreenElement === null) || (document.msFullscreenElement !== undefined && document.msFullscreenElement === null) || (document.mozFullScreen !== undefined && !document.mozFullScreen) || (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen)) { 680 if (elem.requestFullScreen) { 681 elem.requestFullScreen(); 682 } else if (elem.mozRequestFullScreen) { 683 elem.mozRequestFullScreen(); 684 } else if (elem.webkitRequestFullScreen) { 685 elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); 686 } else if (elem.msRequestFullscreen) { 687 elem.msRequestFullscreen(); 688 } 689 } else { 690 if (document.cancelFullScreen) { 691 document.cancelFullScreen(); 692 } else if (document.mozCancelFullScreen) { 693 document.mozCancelFullScreen(); 694 } else if (document.webkitCancelFullScreen) { 695 document.webkitCancelFullScreen(); 696 } else if (document.msExitFullscreen) { 697 document.msExitFullscreen(); 698 } 699 } 700}
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.