Merge pull request #1035 from getmaxun/pag-cap-fix

fix: enable pagination highlighting
This commit is contained in:
Karishma Shukla
2026-04-20 20:50:29 +05:30
committed by GitHub
3 changed files with 187 additions and 67 deletions
+151 -17
View File
@@ -1,10 +1,10 @@
import React, { useCallback, useContext, useEffect, useState } from 'react';
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { generateUUID } from '../../helpers/uuid';
import { useSocketStore } from '../../context/socket';
import { Button } from '@mui/material';
import { GenericModal } from '../ui/GenericModal';
import { useActionContext } from '../../context/browserActions';
import { useBrowserSteps, TextStep, ListStep } from '../../context/browserSteps';
import { useBrowserSteps, TextStep, ListStep, BrowserStep } from '../../context/browserSteps';
import { useGlobalInfoStore } from '../../context/globalInfo';
import { useTranslation } from 'react-i18next';
import { AuthContext } from '../../context/auth';
@@ -86,6 +86,7 @@ export const BrowserWindow = () => {
const [listSelector, setListSelector] = useState<string | null>(null);
const [fields, setFields] = useState<Record<string, TextStep>>({});
const [paginationSelector, setPaginationSelector] = useState<string>('');
const manualHighlightedSelectorRef = useRef<string>("");
const [isCachingChildSelectors, setIsCachingChildSelectors] = useState(false);
const [cachedListSelector, setCachedListSelector] = useState<string | null>(
@@ -1160,6 +1161,7 @@ export const BrowserWindow = () => {
}
setPaginationSelector(highlighterData.selector);
applyManualPaginationHighlight(highlighterData.selector);
notify(
`info`,
t(
@@ -1404,6 +1406,7 @@ export const BrowserWindow = () => {
}
setPaginationSelector(highlighterData.selector);
applyManualPaginationHighlight(highlighterData.selector);
notify(
`info`,
t(
@@ -1576,9 +1579,127 @@ export const BrowserWindow = () => {
setAttributeOptions([]);
};
const manualHighlightedElementsRef = useRef<HTMLElement[]>([]);
const applyManualPaginationHighlight = useCallback((selector: string) => {
if (!selector) return;
let iframeElement = document.querySelector("#dom-browser-iframe") as HTMLIFrameElement;
if (!iframeElement) {
iframeElement = document.querySelector("#browser-window iframe") as HTMLIFrameElement;
}
if (!iframeElement?.contentDocument) return;
const doc = iframeElement.contentDocument;
if (manualHighlightedElementsRef.current.length > 0) {
manualHighlightedElementsRef.current.forEach((el) => {
if (el) {
el.style.outline = "";
el.style.outlineOffset = "";
el.style.zIndex = "";
}
});
manualHighlightedElementsRef.current = [];
}
const prev = manualHighlightedSelectorRef.current;
if (prev) {
try {
const prevEls =
prev.startsWith("//") || prev.startsWith("(//")
? (() => {
const r = doc.evaluate(prev, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
const arr: Element[] = [];
for (let i = 0; i < r.snapshotLength; i++) {
const n = r.snapshotItem(i);
if (n && n.nodeType === Node.ELEMENT_NODE) arr.push(n as Element);
}
return arr;
})()
: Array.from(doc.querySelectorAll(prev));
prevEls.forEach((el) => {
(el as HTMLElement).style.outline = "";
(el as HTMLElement).style.outlineOffset = "";
(el as HTMLElement).style.zIndex = "";
});
} catch (e) {}
}
try {
const elements: HTMLElement[] = (
selector.startsWith("//") || selector.startsWith("(//")
? (() => {
const r = doc.evaluate(selector, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
const arr: HTMLElement[] = [];
for (let i = 0; i < r.snapshotLength; i++) {
const n = r.snapshotItem(i);
if (n && n.nodeType === Node.ELEMENT_NODE) arr.push(n as HTMLElement);
}
return arr;
})()
: Array.from(doc.querySelectorAll(selector))
) as HTMLElement[];
elements.forEach((el) => {
el.style.outline = "3px dashed #ff00c3";
el.style.outlineOffset = "2px";
el.style.zIndex = "9999";
});
manualHighlightedElementsRef.current = elements;
manualHighlightedSelectorRef.current = selector;
} catch (error) {
console.error("Error applying manual pagination highlight:", error);
}
}, []);
const clearManualPaginationHighlight = useCallback(() => {
if (manualHighlightedElementsRef.current.length > 0) {
manualHighlightedElementsRef.current.forEach((el) => {
if (el) {
el.style.outline = "";
el.style.outlineOffset = "";
el.style.zIndex = "";
}
});
manualHighlightedElementsRef.current = [];
}
const selector = manualHighlightedSelectorRef.current;
if (!selector) return;
let iframeElement = document.querySelector("#dom-browser-iframe") as HTMLIFrameElement;
if (!iframeElement) {
iframeElement = document.querySelector("#browser-window iframe") as HTMLIFrameElement;
}
if (!iframeElement?.contentDocument) return;
const doc = iframeElement.contentDocument;
try {
const elements: Element[] =
selector.startsWith("//") || selector.startsWith("(//")
? (() => {
const r = doc.evaluate(selector, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
const arr: Element[] = [];
for (let i = 0; i < r.snapshotLength; i++) {
const n = r.snapshotItem(i);
if (n && n.nodeType === Node.ELEMENT_NODE) arr.push(n as Element);
}
return arr;
})()
: Array.from(doc.querySelectorAll(selector));
elements.forEach((el) => {
(el as HTMLElement).style.outline = "";
(el as HTMLElement).style.outlineOffset = "";
(el as HTMLElement).style.zIndex = "";
});
} catch (e) {
console.error("Error clearing manual pagination highlight:", e);
}
manualHighlightedSelectorRef.current = "";
}, []);
const resetPaginationSelector = useCallback(() => {
setPaginationSelector('');
}, []);
clearManualPaginationHighlight();
setPaginationSelector('');
}, [clearManualPaginationHighlight]);
useEffect(() => {
if (!paginationMode) {
@@ -1595,27 +1716,40 @@ export const BrowserWindow = () => {
useEffect(() => {
if (paginationMode && currentListActionId) {
const currentListStep = browserSteps.find(
step => step.type === 'list' && step.actionId === currentListActionId
) as (ListStep & { type: 'list' }) | undefined;
(step) => step.type === "list" && step.actionId === currentListActionId
) as (BrowserStep & { type: "list" }) | undefined;
const currentSelector = currentListStep?.pagination?.selector;
const stepSelector = currentListStep?.pagination?.selector;
const currentType = currentListStep?.pagination?.type;
if (['clickNext', 'clickLoadMore'].includes(paginationType)) {
if (!currentSelector || (currentType && currentType !== paginationType)) {
setPaginationSelector('');
if (["clickNext", "clickLoadMore"].includes(paginationType)) {
if (!stepSelector || (currentType && currentType !== paginationType)) {
clearManualPaginationHighlight();
setPaginationSelector("");
}
}
const stepSelector = currentListStep?.pagination?.selector;
if (stepSelector && !paginationSelector) {
setPaginationSelector(stepSelector);
} else if (!stepSelector && paginationSelector) {
setPaginationSelector('');
if (stepSelector) {
if (paginationSelector !== stepSelector) {
setPaginationSelector(stepSelector);
}
if (manualHighlightedSelectorRef.current !== stepSelector) {
applyManualPaginationHighlight(stepSelector);
}
} else if (paginationSelector) {
clearManualPaginationHighlight();
setPaginationSelector("");
}
}
}, [browserSteps, paginationMode, currentListActionId, paginationSelector]);
}, [
browserSteps,
paginationMode,
currentListActionId,
paginationSelector,
clearManualPaginationHighlight,
applyManualPaginationHighlight,
paginationType,
]);
return (
<div
+32 -49
View File
@@ -437,6 +437,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
handleStopGetList();
setCurrentListActionId('');
resetInterpretationLog();
setAutoDetectedPagination(null);
finishAction('list');
onFinishCapture();
clientSelectorGenerator.cleanup();
@@ -445,6 +446,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
handleStopGetList();
setCurrentListActionId('');
resetInterpretationLog();
setAutoDetectedPagination(null);
finishAction('list');
onFinishCapture();
clientSelectorGenerator.cleanup();
@@ -598,12 +600,6 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const elements = evaluateSelector(detectionResult.selector, iframeDoc);
if (elements.length > 0) {
elements.forEach((el: Element) => {
(el as HTMLElement).style.outline = '3px dashed #ff00c3';
(el as HTMLElement).style.outlineOffset = '2px';
(el as HTMLElement).style.zIndex = '9999';
});
const firstElement = elements[0] as HTMLElement;
const elementRect = firstElement.getBoundingClientRect();
const iframeWindow = iframeElement.contentWindow;
@@ -721,14 +717,41 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
setShowPaginationOptions(true);
setCaptureStage('pagination');
break;
case 'pagination':
case "pagination":
if (autoDetectedPagination) {
setAutoDetectedPagination(null);
}
if (currentListActionId) {
const currentListStep = browserSteps.find(
(step) => step.type === "list" && step.actionId === currentListActionId
) as (BrowserStep & { type: "list" }) | undefined;
if (currentListStep?.pagination?.selector) {
updateListStepPagination(currentListStep.id, {
type: "",
selector: null,
});
}
}
stopPaginationMode();
setShowPaginationOptions(false);
setAutoDetectedPagination(null);
setCaptureStage('initial');
updatePaginationType("");
setCaptureStage("initial");
break;
}
}, [captureStage, stopLimitMode, startPaginationMode, stopPaginationMode]);
}, [captureStage,
stopLimitMode,
startPaginationMode,
stopPaginationMode,
autoDetectedPagination,
setAutoDetectedPagination,
currentListActionId,
browserSteps,
updateListStepPagination,
updatePaginationType]);
const handlePaginationSettingSelect = (option: PaginationType) => {
updatePaginationType(option);
@@ -761,46 +784,6 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
}
}
if (autoDetectedPagination?.selector) {
const iframeElement = document.querySelector('#browser-window iframe') as HTMLIFrameElement;
if (iframeElement?.contentDocument) {
try {
function evaluateSelector(selector: string, doc: Document): Element[] {
if (selector.startsWith('//') || selector.startsWith('(//')) {
try {
const result = doc.evaluate(selector, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
const elements: Element[] = [];
for (let i = 0; i < result.snapshotLength; i++) {
const node = result.snapshotItem(i);
if (node && node.nodeType === Node.ELEMENT_NODE) {
elements.push(node as Element);
}
}
return elements;
} catch (err) {
return [];
}
} else {
try {
return Array.from(doc.querySelectorAll(selector));
} catch (err) {
return [];
}
}
}
const elements = evaluateSelector(autoDetectedPagination.selector, iframeElement.contentDocument);
elements.forEach((el: Element) => {
(el as HTMLElement).style.outline = '';
(el as HTMLElement).style.outlineOffset = '';
(el as HTMLElement).style.zIndex = '';
});
} catch (error) {
console.error('Error removing pagination highlight on discard:', error);
}
}
}
resetListState();
stopPaginationMode();
stopLimitMode();
+4 -1
View File
@@ -110,8 +110,11 @@ export const ActionProvider = ({ children }: { children: ReactNode }) => {
};
const stopPaginationMode = () => {
setPaginationMode(false),
setPaginationMode(false);
socket?.emit('setPaginationMode', { pagination: false });
if (getList) {
socket?.emit('setGetList', { getList: true });
}
};
const startLimitMode = () => {