1+( function ( $ ) { 2 let pending_ajax = false; 3 const anchestorItem = document.querySelector( 'ul.doc-nav-list > li.page_item.current_page_ancestor' ) || null; 4 5 const weDocs = { 6 initialize() { 7 $( '.wedocs-feedback-wrap' ).on( 'click', 'a', this.feedback ); 8 $( '#top-search-form .dropdown-menu' ).on( 'click', 'a', this.searchForm ); 9 $( 'a.wedocs-print-article' ).on( 'click', this.printArticle ); 10 11 // Sidebar toggle. 12 $( 'ul.doc-nav-list .page_item_has_children' ).on( 'click', '.wedocs-caret', this.toggleSidebar ); 13 14 // Load single doc page search modal. 15 this.loadSingleDocSearchModal(); 16 17 // Initialize Quick Search blocks 18 this.initializeQuickSearch(); 19 20 // Handle modal actions. 21 $( 'a#wedocs-stuck-modal' ).on( 'click', this.showModal ); 22 $( 'a#wedocs-modal-close' ).on( 'click', this.closeModal ); 23 $( '#wedocs-modal-backdrop' ).on( 'click', this.closeModal ); 24 $( 'form#wedocs-contact-modal-form' ).on( 'submit', this.contactHelp ); 25 $( 'ul.wedocs-doc-sections > li svg' ).on( 'click', this.showSectionArticles ); 26 27 // Single documentation page search modal actions. 28 $( '#wedocs-single-doc-search-modal' ).on( 'click', this.handleDocSearchModalBackDrop ); 29 $( '.doc-search-container #doc-search-input' ).on( 'keyup', this.detectDocSearchInput.bind( this ) ); 30 $( '.doc-search-container .doc-search-field .search-clean' ).on( 'click', this.cleanDocSearchInput ); 31 $( '#wedocs-single-doc-search-modal .doc-search-cancel' ).on( 'click', this.closeSinglePageSearchModal ); 32 $( '.wedocs-single-search-input' ).on( 'click', '.search-field, .search-submit, .short-key', this.showSinglePageSearchModal ); 33 }, 34 35 feedback ( e ) { 36 e.preventDefault(); 37 38 // return if any request is in process already 39 if ( pending_ajax ) { 40 return; 41 } 42 43 pending_ajax = true; 44 45 const self = $( this ), 46 wrap = self.closest( '.feedback-content' ), 47 data = { 48 post_id: self.data( 'id' ), 49 type: self.data( 'type' ), 50 action: 'wedocs_ajax_feedback', 51 _wpnonce: weDocs_Vars.nonce, 52 }; 53 54 $.post( weDocs_Vars.ajaxurl, data, function ( resp ) { 55 wrap.html( resp.data ); 56 57 pending_ajax = false; 58 } ); 59 }, 60 61 searchForm ( e ) { 62 e.preventDefault(); 63 64 const param = $( this ).attr( 'href' ).replace( '#', '' ); 65 const concept = $( this ).text(); 66 67 $( '#top-search-form span#search_concept' ).text( concept ); 68 $( '.input-group #search_param' ).val( param ); 69 }, 70 71 printArticle ( e ) { 72 e.preventDefault(); 73 74 // Try multiple selectors to find the article content 75 let article = $( this ).closest( 'article' ); 76 77 // If no article found (e.g., in block themes), try common content selectors 78 if ( ! article.length ) { 79 article = $( '.wedocs-single-content article' ); 80 } 81 if ( ! article.length ) { 82 article = $( '.entry-content' ).closest( 'article' ); 83 } 84 if ( ! article.length ) { 85 article = $( '.entry-content' ); 86 } 87 88 // If still no content found, bail out gracefully 89 if ( ! article.length ) { 90 window.print(); 91 return; 92 } 93 94 const mywindow = window.open( '', 'my div', 'height=600,width=800' ); 95 mywindow.document.write( '<html><head><title>Print Article</title>' ); 96 mywindow.document.write( 97 '<link rel="stylesheet" href="' + 98 weDocs_Vars.style + 99 '" type="text/css" media="all" />' 100 ); 101 mywindow.document.write( '</head><body >' ); 102 mywindow.document.write( article.html() ); 103 mywindow.document.write( 104 '<div class="powered-by">' + weDocs_Vars.powered + '</div>' 105 ); 106 mywindow.document.write( '</body></html>' ); 107 108 mywindow.document.close(); // necessary for IE >= 10 109 mywindow.focus(); // necessary for IE >= 10 110 111 // Event-driven print handling 112 let printCompleted = false; 113 let fallbackTimeout = null; 114 115 // Function to handle print completion and cleanup 116 const handlePrintComplete = function() { 117 if (printCompleted) return; // Prevent multiple calls 118 printCompleted = true; 119
120 // Clear fallback timeout if it exists 121 if (fallbackTimeout) { 122 clearTimeout(fallbackTimeout); 123 fallbackTimeout = null; 124 } 125 126 // Remove event listeners to prevent memory leaks 127 if (mywindow.removeEventListener) { 128 mywindow.removeEventListener('afterprint', handlePrintComplete); 129 } else if (mywindow.detachEvent) { 130 mywindow.detachEvent('onafterprint', handlePrintComplete); 131 } 132 133 // Close the window 134 mywindow.close(); 135 }; 136 137 // Function to initiate printing 138 const initiatePrint = function() { 139 // Attach afterprint event listener before printing 140 if (mywindow.addEventListener) { 141 mywindow.addEventListener('afterprint', handlePrintComplete, false); 142 } else if (mywindow.attachEvent) { 143 // IE8 and older support 144 mywindow.attachEvent('onafterprint', handlePrintComplete); 145 } 146 147 // Set up fallback timeout as last resort (for browsers that don't support afterprint) 148 fallbackTimeout = setTimeout(function() { 149 if (!printCompleted) { 150 console.warn('Print afterprint event not fired, using fallback cleanup'); 151 handlePrintComplete(); 152 } 153 }, 30000); // 30 second fallback timeout 154 155 // Initiate print 156 mywindow.print(); 157 }; 158 159 // Wait for window to load before printing 160 if (mywindow.addEventListener) { 161 mywindow.addEventListener('load', initiatePrint, false); 162 } else if (mywindow.attachEvent) { 163 // IE8 and older support 164 mywindow.attachEvent('onload', initiatePrint); 165 } else { 166 // Fallback for very old browsers 167 mywindow.onload = initiatePrint; 168 } 169 170 return true; 171 }, 172 173 showModal ( e ) { 174 e.preventDefault(); 175 176 $( '#wedocs-modal-backdrop' ).show(); 177 $( '#wedocs-contact-modal' ).show(); 178 $( 'body' ).addClass( 'wedocs-overflow-hidden' ); 179 }, 180 181 closeModal ( e ) { 182 e.preventDefault(); 183 184 $( '#wedocs-modal-backdrop' ).hide(); 185 $( '#wedocs-contact-modal' ).hide(); 186 $( 'body' ).removeClass( 'wedocs-overflow-hidden' ); 187 }, 188 189 contactHelp ( e ) { 190 e.preventDefault(); 191 192 const self = $( this ), 193 submit = self.find( 'input[type=submit]' ), 194 body = self.closest( '.wedocs-modal-body' ), 195 data = self.serialize() + '&_wpnonce=' + weDocs_Vars.nonce; 196 197 submit.prop( 'disabled', true ); 198 199 $.post( weDocs_Vars.ajaxurl, data, function ( resp ) { 200 if ( resp.success === false ) { 201 submit.prop( 'disabled', false ); 202 $( '#wedocs-modal-errors', body ) 203 .empty() 204 .append( 205 '<div class="wedocs-alert wedocs-alert-danger">' + 206 resp.data + 207 '</div>' 208 ); 209 } else { 210 body 211 .empty() 212 .append( 213 '<div class="wedocs-alert wedocs-alert-success">' + 214 resp.data + 215 '</div>' 216 ); 217 } 218 } ); 219 }, 220 221 toggleSidebar ( e ) { 222 e.preventDefault(); 223 const self = $( this ), 224 parent = self.closest( '.page_item' ); 225 226 if ( parent.hasClass( 'wd-state-closed' ) ) { 227 parent.removeClass( 'wd-state-closed' ).addClass( 'wd-state-open' ); 228 } else { 229 parent.removeClass( 'wd-state-open' ).addClass( 'wd-state-closed' ); 230 } 231 }, 232 233 loadSingleDocSearchModal( e ) { 234 if ( !weDocs_Vars.isSingleDoc && !weDocs_Vars.isVendorDashboard ) { 235 return; 236 } 237 238 const data = { 239 action : weDocs_Vars.isVendorDashboard ? 'wedocs_get_vendor_docs' : 'wedocs_get_docs', 240 _wpnonce : weDocs_Vars.nonce, 241 }; 242 243 $.ajax({ 244 data, 245 url : weDocs_Vars.ajaxurl, 246 type : 'POST', 247 error : ( e ) => console.log( e ), 248 complete : ( response ) => { 249 if ( response?.responseJSON?.data ) { 250 this.docs = response?.responseJSON?.data; 251 } 252 }, 253 }); 254 255 // Mount doc single page search modal. 256 if ( weDocs_Vars.searchModal ) { 257 const mountDiv = document.createElement( 'div' ); 258 mountDiv.setAttribute( 'id', 'wedocs-single-doc-search-modal' ); 259 mountDiv.innerHTML = weDocs_Vars.searchModal;
260 document.body.appendChild( mountDiv ); 261 } 262 263 document.addEventListener( 'keydown', ( event ) => { 264 // Bind single page search modal with (ctrl/command + k). 265 if ( ( event.ctrlKey || event.metaKey ) && event.key === 'k' ) { 266 this.showSinglePageSearchModal(); 267 } 268 269 // Bind single page search modal hiding option with escape button. 270 if ( event.keyCode === 27 && event.key === 'Escape' ) { 271 this.closeSinglePageSearchModal(); 272 } 273 } ); 274 }, 275 276 showSectionArticles ( e ) { 277 $( this ).toggleClass( 'active' ).closest( 'li' ).next( '.children' ).toggleClass( 'active' ); 278 }, 279 280 cleanDocSearchInput ( e ) { 281 $( this ).hide(); 282 $( this ).prev( 'input[type="text"]' ).val( null ).focus(); 283 $( '.doc-search-dropdown-container .doc-search-hits' ) 284 .html( `<div class='doc-empty-search'>${ weDocs_Vars.searchBlankMsg }</div>` ); 285 }, 286 287 detectDocSearchInput ( e ) { 288 const searchValue = e.target.value, 289 searchDocs = this.getSearchDocs( searchValue ), 290 searchEmpty = `<div class='doc-empty-search'>${ weDocs_Vars.searchEmptyMsg }</div>`, 291 searchKeyEmpty = `<div class='doc-empty-search'>${ weDocs_Vars.searchBlankMsg }</div>`; 292 293 // Searched docs list. 294 const $ulNode = this.getListTemplate( searchDocs ); 295 296 // Render search cleaner icon. 297 $( e.target ).next( '.search-clean' )[0].style.display = `${ searchValue ? 'block' : 'none' }`; 298 299 // Render search list or necessary message. 300 $( '.doc-search-dropdown-container .doc-search-hits' ).html( 301 ( searchValue ? ( searchDocs.length ? $ulNode : searchEmpty ) : searchKeyEmpty ) 302 ); 303 }, 304 305 getListTemplate ( searchDocs ) { 306 const ulNode = document.createElement( 'ul' ); 307 ulNode.setAttribute( 'id', 'doc-search-list' ); 308 309 // Build a URL for a doc, using dashboard-scoped links when on the vendor dashboard. 310 const buildDocUrl = ( doc ) => { 311 if ( ! doc ) { 312 return '#'; 313 } 314 if ( weDocs_Vars.isVendorDashboard && weDocs_Vars.vendorDocsBaseUrl ) { 315 return weDocs_Vars.vendorDocsBaseUrl + '?doc_id=' + doc.ID; 316 } 317 return doc?.permalink || doc?.guid; 318 }; 319 320 searchDocs.forEach( ( data, index ) => { 321 const docItem = data?.article || data?.section || data?.parent; 322 let url = buildDocUrl( docItem ), 323 title = docItem?.post_title, 324 parentNavigation = data?.section ? 325 `<div class='parent-doc-nav'> 326 ${ weDocs_Vars.docNavLabel } 327 <span data-url="${ buildDocUrl( data?.parent ) }" class="doc-search-hit-path"> 328 ${ this.extractedTitle( data?.parent?.post_title, 35 ) } 329 </span> 330 </div>` : '', 331 sectionNavigation = data?.article ? 332 `<div class='section-doc-nav'> 333 ${ weDocs_Vars.sectionNavLabel } 334 <span data-url="${ buildDocUrl( data?.section ) }" class="doc-search-hit-path"> 335 ${ this.extractedTitle( data?.section?.post_title, 35 ) } 336 </span> 337 </div>` : ''; 338 339 title = this.extractedTitle( title ); 340 const bootstrapTemplate = $( '.wedocs-single-wrap .doc-nav-list a' ).hasClass( 'bootstrap' ) ? 'bootstrap ' : '', 341 tailwindTemplate = $( '.wedocs-single-wrap .doc-nav-list a' ).hasClass( 'tailwind' ) ? 'tailwind ' : ''; 342 343 // Make search results as list node. 344 const liNode = document.createElement( 'li' ); 345 liNode.setAttribute( 'class', 'doc-search-hit' ); 346 liNode.setAttribute( 'id', `doc-search-item-${index}` ); 347 liNode.setAttribute( 'role', 'option' ); 348 liNode.setAttribute( 'aria-selected', 'false' ); 349 const linkTarget = weDocs_Vars.isVendorDashboard ? '_self' : '_blank'; 350 liNode.innerHTML = ` 351 <a 352 href="${ url }" 353 target="${ linkTarget }" 354 class="${ bootstrapTemplate + tailwindTemplate }doc-search-hit-result" 355 > 356 <div class="doc-search-hit-container"> 357 <div class="doc-search-hit-icon"> 358 <svg width="12" height="18" viewBox="0 0 14 18" fill="none"> 359 <path 360 stroke="#3B82F6" 361 stroke-width="2" 362 stroke-linecap="round" 363 stroke-linejoin="round" 364 d="M4.49984 9H9.49984M4.49984 12.3333H9.49984M11.1665 16.5H2.83317C1.9127 16.5 1.1665 15.7538 1.1665 14.8333V3.16667C1.1665 2.24619 1.9127 1.5 2.83317 1.5H7.48799C7.70901 1.5 7.92097 1.5878 8.07725 1.74408L12.5891 6.25592C12.7454 6.4122 12.8332 6.62416 12.8332 6.84518V14.8333C12.8332 15.7538 12.087 16.5 11.1665 16.5
364Z" 365 /> 366 </svg> 367 </div> 368 <div class="doc-search-hit-content-wrapper"> 369 <div class="doc-search-hit-title">${ title }</div> 370 ${ ( parentNavigation || sectionNavigation ) ? '<hr />' : '' } 371 <div class='wd-docs-navigation'> 372 ${ parentNavigation + sectionNavigation } 373 </div> 374 </div> 375 </div> 376 </a>`; 377 378 // Handle navigation redirection manually. 379 liNode.querySelectorAll( '.doc-search-hit-path' ).forEach( 380 searchPath => searchPath?.addEventListener( 'click', function ( event ) { 381 event.preventDefault(); 382 window.open( $( this ).data( 'url' ), '_blank' ); 383 }) 384 ); 385 386 try { 387 liNode.querySelectorAll( '.doc-search-hit-result' ).forEach( 388 list => { 389 // Update list icon background & color. 390 const hitIcon = list?.querySelector( '.doc-search-hit-icon' ); 391 const hitIconPath = hitIcon?.querySelector( 'path' ); 392 393 if ( hitIcon ) { 394 hitIcon.style.background = weDocs_Vars?.searchModalColors?.active_shade_color; 395 } 396 397 if ( hitIconPath ) { 398 hitIconPath.style.stroke = weDocs_Vars?.searchModalColors?.active_primary_color; 399 } 400 401 const parentDocNav = list?.querySelector( '.parent-doc-nav' ), 402 sectionDocNav = list?.querySelector( '.section-doc-nav' ), 403 parentNavSearchHitPath = parentDocNav?.querySelector( '.doc-search-hit-path' ), 404 sectionNavSearchHitPath = sectionDocNav?.querySelector( '.doc-search-hit-path' ); 405 406 if ( parentNavSearchHitPath ) { 407 // Update parent nav shade color. 408 parentNavSearchHitPath.style.background = weDocs_Vars?.searchModalColors?.active_shade_color; 409 } 410 411 if ( sectionNavSearchHitPath ) { 412 // Update section nav shade color. 413 sectionNavSearchHitPath.style.background = weDocs_Vars?.searchModalColors?.active_shade_color; 414 } 415 416 if ( parentDocNav ) { 417 // Update parent text color on mouse over. 418 parentDocNav.addEventListener( 'mouseover', function() { 419 parentNavSearchHitPath.style.color = weDocs_Vars?.searchModalColors?.active_primary_color; 420 } ); 421 422 // Update parent text color on mouse out. 423 parentDocNav.addEventListener( 'mouseout', function() { 424 parentNavSearchHitPath.style.color = '#6B7280'; 425 } ); 426 } 427 428 if ( sectionDocNav ) { 429 // Update section text color on mouse over. 430 sectionDocNav.addEventListener( 'mouseover', function() { 431 sectionNavSearchHitPath.style.color = weDocs_Vars?.searchModalColors?.active_primary_color; 432 } ); 433 434 // Update section text color on mouse over. 435 sectionDocNav.addEventListener( 'mouseout', function() { 436 sectionNavSearchHitPath.style.color = '#6B7280'; 437 } ); 438 } 439 440 // Update doc lists background color on mouse over. 441 list.addEventListener( 'mouseover', function() { 442 this.style.background = weDocs_Vars?.searchModalColors?.active_primary_color; 443 } ); 444 445 // Update doc lists background color on mouse out. 446 list.addEventListener( 'mouseout', function() { 447 this.style.background = '#fff'; 448 } ); 449 } 450 ); 451 } catch ( error ) { 452 console.warn( 'Error processing search results:', error ); 453 } 454 455 ulNode.appendChild(liNode); 456 }); 457 458 return $( ulNode ); 459 }, 460 461 getSearchDocs( searchValue ) { 462 const searchDocs = []; 463 const searchResult = this?.docs?.all_docs?.filter( doc => { 464 if ( doc?.post_status !== 'publish' ) return; 465 return doc?.post_title?.toLowerCase().includes( searchValue?.toLowerCase() ); 466 } ); 467 468 searchResult?.map( doc => { 469 const docObj = {}; 470 if ( doc?.post_parent === 0 ) { 471 docObj.parent = doc; 472 } 473 474 if ( this?.docs?.sections?.find( sectionDoc => sectionDoc.ID === doc?.ID ) ) { 475 docObj.section = doc; 476 docObj.parent = this?.docs?.parents?.find( parentDoc => parentDoc?.ID === doc?.post_parent ); 477 } 478 479 if ( this?.docs?.articles?.find( articleDoc => articleDoc.ID === doc?.ID ) ) { 480 docObj.article = doc; 481 docObj.section = this?.docs?.sections?.find( sectionDoc => sectionDoc?.ID === doc?.post_parent ); 482 docObj.parent = this?.docs?.parents?.find( parentDoc => parentDoc?.ID === docObj.section?.post_parent ); 483 } 484 485 searchDocs.push( docObj ); 486 } ); 487 488 return searchDocs; 489 }, 490 491 showSinglePageSearchModal ( e ) { 492 const modal = $( '#wedocs-single-doc-search-modal' ); 493 if ( modal.length ) { 494 modal.addClass( 'active' ); 495 modal.find( '#doc-search-input' ).focus(); 496 } 497 }, 498 499 closeSinglePageSearchModal ( e ) { 500 const modal = $( '#wedocs-single-doc-search-modal' ); 501 if ( modal.length ) { 502 modal.removeClass( 'active' ); 503 } 504 }, 505 506 extractedTitle ( title, length = 190 ) { 507 const extractedString = title?.substr( 0, length ); 508 return extractedString?.length >= length ? `${ extractedString }...` : extractedString; 509 }, 510 511 handleDocSearchModalBackDrop ( e ) { 512 if ( !e.target.closest( '.doc-search-modal' ) ) { 513 $( this ).removeClass( 'active' ); 514 } 515 }, 516 517 initializeQuickSearch() { 518 // Initialize Quick Search blocks functionality 519 // The Quick Search blocks have their own JavaScript built into their render.php 520 // This method is called to ensure compatibility but the actual functionality
521 // is handled by the individual Quick Search block instances 522 523 // Check if there are any Quick Search blocks on the page 524 const quickSearchBlocks = document.querySelectorAll('.wedocs-quick-search-block'); 525 526 if (quickSearchBlocks.length > 0) { 527 // The Quick Search blocks are self-contained with their own JavaScript 528 // No additional initialization is needed here as each block handles its own functionality 529 // Both search systems can coexist without conflicts 530 } 531 }, 532 }; 533 534 $( function () { 535 // Handle hash router. 536 // This is commented out because it causes the page to reload when the hash is present. 537 // if ( window.location.hash ) { 538 // window.location = window.location.pathname; 539 // } 540 541 // Handle navigation caret. 542 if ( anchestorItem && ! anchestorItem.classList.contains( 'wd-state-open' ) ) { 543 anchestorItem.classList.add( 'wd-state-open' ); 544 anchestorItem.classList.remove( 'wd-state-closed' ); 545 } 546 547 weDocs.initialize(); 548 } ); 549 550 // initialize anchor.js 551 anchors.options = { 552 icon: '#', 553 }; 554 anchors.add( 555 '.wedocs-single-content .entry-content > h2, .wedocs-single-content .entry-content > h3' 556 ); 557} )( jQuery );
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.