<?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">×</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"><</button>
<button id="gcmNextBtnDraggable" title="Next">></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
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎