Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: shadow dom selection #296

Merged
merged 25 commits into from
Jan 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a131ce6
feat: shadow dom selection
amhsirak Dec 24, 2024
a09b03e
feat: get deepest shadowDOM element selector
RohitR311 Dec 29, 2024
542f4d3
feat: change shadowDOM full selector path
RohitR311 Dec 29, 2024
b60f4b7
feat: add functionality to scrape shadowDOM elements
RohitR311 Dec 29, 2024
9f9dc4e
feat: add shadow optional field in SelectorObject
RohitR311 Dec 29, 2024
b696fa5
feat: add shadow param for scrapeSchema config
RohitR311 Dec 29, 2024
415ce02
feat: add shadow bool field to text step
RohitR311 Dec 29, 2024
1a6a481
feat: add shadow selectors field type
RohitR311 Dec 29, 2024
c303181
feat: prioritize returning shadow selector
RohitR311 Dec 29, 2024
cec2397
feat: change shadowDOM full selector path
RohitR311 Dec 29, 2024
05c7921
feat: add shadowInfo in highlighter data
RohitR311 Dec 29, 2024
d2ab81e
feat: add logic to get deeply nested shadowDOM elements
RohitR311 Dec 30, 2024
9287c29
feat: rm host and element info for shadow selector
RohitR311 Dec 30, 2024
e952d8f
feat: add nested shadow-root scraping logic for scrapeSchema
RohitR311 Dec 30, 2024
b757d9c
feat: add func to rm shadow selectors from workflow
RohitR311 Dec 30, 2024
4b4074b
feat: add logic to scrape multiple nested shadow dom elements
RohitR311 Dec 30, 2024
4a09ea6
feat: get deepest element rect coordinates
RohitR311 Dec 31, 2024
42e1306
feat: add shadowDOM support for capture list selector generation
RohitR311 Jan 1, 2025
c6105b4
feat: generate highlighter for shadoDOM and mixedDOM elements
RohitR311 Jan 1, 2025
8db6279
feat: add shadowDOM support for scraping list
RohitR311 Jan 1, 2025
c287340
feat: shadowDOM support for table and non table list scraping
RohitR311 Jan 2, 2025
3f54f11
Merge branch 'develop' into shadow-dom
RohitR311 Jan 2, 2025
8323593
chore: format
amhsirak Jan 2, 2025
5813ae4
Merge branch 'shadow-dom' of https://github.com/getmaxun/maxun into s…
amhsirak Jan 2, 2025
e91a391
chore: cleanup console logs
amhsirak Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
544 changes: 373 additions & 171 deletions maxun-core/src/browserSide/scraper.js

Large diffs are not rendered by default.

21 changes: 19 additions & 2 deletions maxun-core/src/interpret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ export default class Interpreter extends EventEmitter {
await this.options.serializableCallback(scrapeResults);
},

scrapeSchema: async (schema: Record<string, { selector: string; tag: string, attribute: string; }>) => {
scrapeSchema: async (schema: Record<string, { selector: string; tag: string, attribute: string; shadow: string}>) => {
await this.ensureScriptsLoaded(page);

const scrapeResult = await page.evaluate((schemaObj) => window.scrapeSchema(schemaObj), schema);
Expand Down Expand Up @@ -663,11 +663,28 @@ export default class Interpreter extends EventEmitter {
if (isApplicable) {
return actionId;
}
}
}

private removeShadowSelectors(workflow: Workflow) {
for (let actionId = workflow.length - 1; actionId >= 0; actionId--) {
const step = workflow[actionId];

// Check if step has where and selectors
if (step.where && Array.isArray(step.where.selectors)) {
// Filter out selectors that contain ">>"
step.where.selectors = step.where.selectors.filter(selector => !selector.includes('>>'));
}
}

return workflow;
}

private async runLoop(p: Page, workflow: Workflow) {
const workflowCopy: Workflow = JSON.parse(JSON.stringify(workflow));
let workflowCopy: Workflow = JSON.parse(JSON.stringify(workflow));

// remove shadow selectors
workflowCopy = this.removeShadowSelectors(workflowCopy);

// apply ad-blocker to the current page
try {
Expand Down
8 changes: 7 additions & 1 deletion server/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ export interface BaseActionInfo {
hasOnlyText: boolean;
}

interface ShadowSelector {
full: string;
mode: string;
}

/**
* Holds all the possible css selectors that has been found for an element.
* @category Types
Expand All @@ -143,6 +148,7 @@ export interface Selectors {
hrefSelector: string|null;
accessibilitySelector: string|null;
formSelector: string|null;
shadowSelector: ShadowSelector | null;
}

/**
Expand All @@ -156,7 +162,7 @@ export interface BaseAction extends BaseActionInfo{
associatedActions: ActionType[];
inputType: string | undefined;
value: string | undefined;
selectors: { [key: string]: string | null };
selectors: Selectors;
timestamp: number;
isPassword: boolean;
/**
Expand Down
17 changes: 14 additions & 3 deletions server/src/workflow-management/classes/Generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -730,15 +730,26 @@ export class WorkflowGenerator {
const displaySelector = await this.generateSelector(page, coordinates, ActionType.Click);
const elementInfo = await getElementInformation(page, coordinates, this.listSelector, this.getList);
if (rect) {
const highlighterData = {
rect,
selector: displaySelector,
elementInfo,
// Include shadow DOM specific information
shadowInfo: elementInfo?.isShadowRoot ? {
mode: elementInfo.shadowRootMode,
content: elementInfo.shadowRootContent
} : null
};

if (this.getList === true) {
if (this.listSelector !== '') {
const childSelectors = await getChildSelectors(page, this.listSelector || '');
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo, childSelectors })
this.socket.emit('highlighter', { ...highlighterData, childSelectors })
} else {
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo });
this.socket.emit('highlighter', { ...highlighterData });
}
} else {
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo });
this.socket.emit('highlighter', { ...highlighterData });
}
}
}
Expand Down
Loading