Guenni007 icon

find-snippet

Guenni007 | PRO | 05/10/25 08:45:01 AM UTC (Edited) | 0 ⭐ | 10278 👁️ | Never ⏰ | []
PHP |

10.22 KB

|

None

|

0 👍

/

0 👎

<?php
 
function window_find_button(){
?>
<script>
window.addEventListener("DOMContentLoaded", function () { 
 
    // --- Helper function to escape special characters for RegExp ---
    function GCM_escapeRegExp(string) {
      if (string === null || string === undefined) {
        return '';
      }
      return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }
 
    // --- Function to remove previous highlights ---
    function GCM_removeAllHighlights() {
      const highlightedElements = document.querySelectorAll('span.custom-highlight');
      highlightedElements.forEach(span => {
        const parent = span.parentNode;
        if (parent) {
          while (span.firstChild) {
            parent.insertBefore(span.firstChild, span);
          }
          parent.removeChild(span);
          parent.normalize();
        }
      });
    }
 
    // --- Function to process a single text node ---
    function GCM_highlightInTextNode(textNode, searchTermRegex, firstHighlightRef, allHighlightsArray) {
      const originalText = textNode.nodeValue;
      let match;
      const fragment = document.createDocumentFragment();
      let lastIndex = 0;
      let localMatchCount = 0;
 
      while ((match = searchTermRegex.exec(originalText)) !== null) {
        localMatchCount++;
        if (match.index > lastIndex) {
          fragment.appendChild(document.createTextNode(originalText.substring(lastIndex, match.index)));
        }
        const span = document.createElement('span');
        span.className = 'custom-highlight';
        span.textContent = match[0];
        fragment.appendChild(span);
        allHighlightsArray.push(span);
 
        if (!firstHighlightRef.element) {
          firstHighlightRef.element = span;
        }
        lastIndex = searchTermRegex.lastIndex;
      }
 
      if (lastIndex < originalText.length) {
        fragment.appendChild(document.createTextNode(originalText.substring(lastIndex)));
      }
 
      if (localMatchCount > 0) {
        textNode.parentNode.replaceChild(fragment, textNode);
      }
      return localMatchCount;
    }
 
    // --- Recursive function to traverse DOM ---
    function GCM_MarkInNodeRecursive(node, searchTermRegex, firstHighlightRef, currentTotalMatches, allHighlightsArray) {
      if (node.nodeType === Node.TEXT_NODE) {
        currentTotalMatches.count += GCM_highlightInTextNode(node, searchTermRegex, firstHighlightRef, allHighlightsArray);
      } else if (node.nodeType === Node.ELEMENT_NODE) {
        if (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE' ||
            node.nodeName === 'TEXTAREA' || node.nodeName === 'INPUT' ||
            node.id === 'gcmSearchUIContainer' || 
            node.classList.contains('custom-highlight')) {
          return;
        }
        const children = Array.from(node.childNodes);
        for (let i = 0; i < children.length; i++) {
          GCM_MarkInNodeRecursive(children[i], searchTermRegex, firstHighlightRef, currentTotalMatches, allHighlightsArray);
        }
      }
    }
 
    // --- Main function to highlight all occurrences ---
    function GCM_highlightAllOccurrences(searchTerm, containerNode) {
      if (!searchTerm) {
        return { count: 0, firstElement: null, allElements: [] };
      }
      const searchRegex = new RegExp(GCM_escapeRegExp(searchTerm), 'gi');
      const firstHighlight = { element: null };
      const totalMatches = { count: 0 };
      const allHighlightedSpans = [];
 
      GCM_MarkInNodeRecursive(containerNode || document.body, searchRegex, firstHighlight, totalMatches, allHighlightedSpans);
 
      return { count: totalMatches.count, firstElement: firstHighlight.element, allElements: allHighlightedSpans };
    }
 
 
    // --- Draggable Logic ---
    function GCM_makeDraggable(element, handle) {
      let currentX, currentY, initialX, initialY;
      let xOffset = 0, yOffset = 0;
 
      handle.onmousedown = dragMouseDown;
 
      function dragMouseDown(e) {
        e = e || window.event;
        e.preventDefault(); // Prevent text selection while dragging
        // Get the mouse cursor position at startup:
        initialX = e.clientX;
        initialY = e.clientY;
 
        document.onmouseup = closeDragElement;
        // Call a function whenever the cursor moves:
        document.onmousemove = elementDrag;
      }
 
      function elementDrag(e) {
        e = e || window.event;
        e.preventDefault();
        // Calculate the new cursor position:
        currentX = initialX - e.clientX;
        currentY = initialY - e.clientY;
        initialX = e.clientX;
        initialY = e.clientY;
        // Set the element's new position:
        element.style.top = (element.offsetTop - currentY) + "px";
        element.style.left = (element.offsetLeft - currentX) + "px";
      }
 
      function closeDragElement() {
        // Stop moving when mouse button is released:
        document.onmouseup = null;
        document.onmousemove = null;
      }
    }
 
    // --- Search UI State and Management ---
    let GCM_searchUIContainer = null; // Renamed
    let GCM_searchInputDraggable = null; // Renamed
    let GCM_searchResultsCountDraggable = null; // Renamed
    let GCM_highlightedElements = [];
    let GCM_currentHighlightIndex = -1;
 
    function GCM_createSearchUI() {
      if (document.getElementById('gcmSearchUIContainer')) {
        GCM_searchUIContainer = document.getElementById('gcmSearchUIContainer');
        GCM_searchInputDraggable = document.getElementById('gcmSearchInputDraggable');
        GCM_searchResultsCountDraggable = document.getElementById('gcmResultsCountDraggable');
        GCM_searchUIContainer.classList.remove('hidden');
        if (GCM_searchInputDraggable) GCM_searchInputDraggable.focus();
        return;
      }
 
      GCM_searchUIContainer = document.createElement('div');
      GCM_searchUIContainer.id = 'gcmSearchUIContainer';
      GCM_searchUIContainer.innerHTML = `
        <div id="gcmSearchUIHeader">
          <span class="gcm-title">Find on Page</span>
          <button id="gcmCloseSearchBtnDraggable" title="Close Search">&times;</button>
        </div>
        <div id="gcmSearchUIBody">
          <input type="text" id="gcmSearchInputDraggable" placeholder="Enter search term...">
          <div class="gcm-controls-row">
            <button id="gcmSearchBtnDraggable">Find</button>
            <div class="gcm-navigation">
                <button id="gcmPrevBtnDraggable" title="Previous">&lt;</button>
                <button id="gcmNextBtnDraggable" title="Next">&gt;</button>
            </div>
          </div>
          <div class="gcm-controls-row">
            <span id="gcmResultsCountDraggable" class="gcm-results-count-draggable">0 of 0</span>
          </div>
        </div>
      `;
      document.body.appendChild(GCM_searchUIContainer);
 
      GCM_searchInputDraggable = document.getElementById('gcmSearchInputDraggable');
      GCM_searchResultsCountDraggable = document.getElementById('gcmResultsCountDraggable');
      const header = document.getElementById('gcmSearchUIHeader');
 
      document.getElementById('gcmSearchBtnDraggable').addEventListener('click', GCM_performSearch);
      if (GCM_searchInputDraggable) {
        GCM_searchInputDraggable.addEventListener('keydown', function(e) {
          if (e.key === 'Enter') {
            e.preventDefault(); // Prevent form submission if it's in one
            GCM_performSearch();
          }
        });
      }
      document.getElementById('gcmNextBtnDraggable').addEventListener('click', GCM_navigateToNext);
      document.getElementById('gcmPrevBtnDraggable').addEventListener('click', GCM_navigateToPrevious);
      document.getElementById('gcmCloseSearchBtnDraggable').addEventListener('click', GCM_closeSearchUI);
 
      if (GCM_searchInputDraggable) GCM_searchInputDraggable.focus();
      if (header && GCM_searchUIContainer) GCM_makeDraggable(GCM_searchUIContainer, header); // Make it draggable
    }
 
    function GCM_closeSearchUI() {
      if (GCM_searchUIContainer) {
        GCM_searchUIContainer.classList.add('hidden');
      }
      GCM_removeAllHighlights();
      GCM_highlightedElements = [];
      GCM_currentHighlightIndex = -1;
      if (GCM_searchResultsCountDraggable) GCM_searchResultsCountDraggable.textContent = "0 of 0";
      if (GCM_searchInputDraggable) GCM_searchInputDraggable.value = ""; // Clear input on close
    }
 
    function GCM_performSearch() {
      if (!GCM_searchInputDraggable) return;
      const searchTerm = GCM_searchInputDraggable.value;
      GCM_removeAllHighlights(); // Always remove old highlights
      GCM_highlightedElements = [];
      GCM_currentHighlightIndex = -1;
 
      if (searchTerm.trim() === "") {
        if (GCM_searchResultsCountDraggable) GCM_searchResultsCountDraggable.textContent = "0 of 0";
        return;
      }
 
      const result = GCM_highlightAllOccurrences(searchTerm, document.body);
      GCM_highlightedElements = result.allElements;
 
      if (result.count > 0) {
        GCM_currentHighlightIndex = 0;
        GCM_navigateToHighlight(GCM_currentHighlightIndex);
      } else {
        // GCM_searchResultsCountDraggable will be updated by GCM_updateResultCount
      }
      GCM_updateResultCount(); // Update count regardless of found or not
    }
 
    function GCM_navigateToHighlight(index) {
      if (index < 0 || index >= GCM_highlightedElements.length) return;
 
      const currentActive = document.querySelector('.custom-highlight.current-custom-highlight');
      if (currentActive) {
        currentActive.classList.remove('current-custom-highlight');
      }
 
      const elementToScrollTo = GCM_highlightedElements[index];
      if (elementToScrollTo) {
        elementToScrollTo.classList.add('current-custom-highlight');
        elementToScrollTo.scrollIntoView({
          behavior: 'smooth',
          block: 'center',
          inline: 'nearest'
        });
      }
      GCM_updateResultCount();
    }
 
    function GCM_navigateToNext() {
      if (GCM_highlightedElements.length === 0) return;
      GCM_currentHighlightIndex = (GCM_currentHighlightIndex + 1) % GCM_highlightedElements.length;
      GCM_navigateToHighlight(GCM_currentHighlightIndex);
    }
 
    function GCM_navigateToPrevious() {
      if (GCM_highlightedElements.length === 0) return;
      GCM_currentHighlightIndex = (GCM_currentHighlightIndex - 1 + GCM_highlightedElements.length) % GCM_highlightedElements.length;
      GCM_navigateToHighlight(GCM_currentHighlightIndex);
    }
 
    function GCM_updateResultCount() {
      if (GCM_searchResultsCountDraggable) {
        const total = GCM_highlightedElements.length;
        const current = total > 0 ? GCM_currentHighlightIndex + 1 : 0;
        GCM_searchResultsCountDraggable.textContent = `${current} of ${total}`;
      }
    }
 
 
    const mainFindButton = document.querySelector('.my-find-button'); // Your Enfold button
 
    if (mainFindButton) {
      mainFindButton.addEventListener('click', function(event) {
        event.preventDefault();
        event.stopPropagation();
        GCM_createSearchUI();
      });
    } else {
      // console.log("Main find button (.my-find-button) not found.");
    }
 
    
});
</script>
<?php
}
add_action('wp_footer', 'window_find_button');

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎