mirror of
https://github.com/getmaxun/maxun.git
synced 2026-10-26 18:29:52 +08:00
Merge pull request #1035 from getmaxun/pag-cap-fix
fix: enable pagination highlighting
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
Reference in New Issue
Block a user