MediaWiki:Common.js: Difference between revisions

No edit summary
No edit summary
Line 961: Line 961:
     if ( !needle || needle.length < 4 ) return;
     if ( !needle || needle.length < 4 ) return;


     var content = document.querySelector( '.mw-parser-output' );
     // Wait for tagTextNodes() to finish wrapping text in data-deva spans,
    if ( !content ) return;
    // then search those spans rather than raw text nodes.
    function doHighlight() {
      var content = document.querySelector( '.mw-parser-output' );
      if ( !content ) return;


    var walker = document.createTreeWalker( content, NodeFilter.SHOW_TEXT );
      var snippet = needle.slice( 0, 40 );
    var found = false;
      var found   = false;
    while ( walker.nextNode() && !found ) {
 
      var node = walker.currentNode;
      // Search data-deva spans first (post-tagTextNodes state)
      var txt  = node.textContent || '';
      var spans = content.querySelectorAll( '[data-deva]' );
      var snippet = needle.slice( 0, 30 );
      for ( var i = 0; i < spans.length && !found; i++ ) {
      if ( txt.indexOf( snippet ) !== -1 ) {
        var spanEl = spans[ i ];
         var span = document.createElement( 'mark' );
        var orig  = spanEl.getAttribute( 'data-deva' ) || '';
         span.className = 'gr-ullekha-highlight';
        if ( orig.indexOf( snippet ) === -1 ) continue;
         span.style.cssText = 'background:#fff176;border-radius:2px;padding:0 2px;';
 
         var parent = node.parentNode;
        // Replace the span with: text-before + <mark> + text-after
         var idx = txt.indexOf( snippet );
        var idx    = orig.indexOf( snippet );
         if ( idx >= 0 ) {
        var hlText = orig.slice( idx, Math.min( idx + needle.length, orig.length ) );
          var before = document.createTextNode( txt.slice( 0, idx ) );
         var mark  = document.createElement( 'mark' );
          var after  = document.createTextNode( txt.slice( idx + snippet.length ) );
         mark.className = 'gr-ullekha-highlight';
           span.textContent = txt.slice( idx, idx + needle.length > txt.length
         mark.style.cssText = 'background:#fff176;border-radius:2px;padding:0 2px;';
            ? txt.length : needle.length );
         mark.textContent  = hlText;
           parent.insertBefore( before, node );
 
           parent.insertBefore( span,   node );
         var parent = spanEl.parentNode;
           parent.insertBefore( after, node );
         if ( !parent ) continue;
           parent.removeChild( node );
 
        var before = document.createTextNode( orig.slice( 0, idx ) );
        var after  = document.createTextNode( orig.slice( idx + hlText.length ) );
        parent.insertBefore( before, spanEl );
        parent.insertBefore( mark,  spanEl );
        parent.insertBefore( after,  spanEl );
        parent.removeChild( spanEl );
 
        setTimeout( function () {
          mark.scrollIntoView( { behavior: 'smooth', block: 'center' } );
        }, 100 );
        found = true;
      }
 
      // Fallback: raw text nodes (before tagTextNodes runs)
      if ( !found ) {
        var walker = document.createTreeWalker( content, NodeFilter.SHOW_TEXT );
        while ( walker.nextNode() && !found ) {
          var node = walker.currentNode;
          var txt  = node.textContent || '';
          if ( txt.indexOf( snippet ) === -1 ) continue;
          var idx2  = txt.indexOf( snippet );
          var mark2  = document.createElement( 'mark' );
           mark2.className    = 'gr-ullekha-highlight';
          mark2.style.cssText = 'background:#fff176;border-radius:2px;padding:0 2px;';
          mark2.textContent = txt.slice( idx2, Math.min( idx2 + needle.length, txt.length ) );
          var p = node.parentNode;
           p.insertBefore( document.createTextNode( txt.slice( 0, idx2 ) ), node );
           p.insertBefore( mark2, node );
           p.insertBefore( document.createTextNode( txt.slice( idx2 + mark2.textContent.length ) ), node );
           p.removeChild( node );
           setTimeout( function () {
           setTimeout( function () {
             span.scrollIntoView( { behavior: 'smooth', block: 'center' } );
             mark2.scrollIntoView( { behavior: 'smooth', block: 'center' } );
           }, 300 );
           }, 100 );
           found = true;
           found = true;
         }
         }
       }
       }
     }
     }
    // Delay to let tagTextNodes() and MW rendering finish
    setTimeout( doHighlight, 600 );
   }
   }