Skip to content

Commit

Permalink
Merge pull request #63 from aryangupta701/floating-div
Browse files Browse the repository at this point in the history
added floating window to indicate and stop recording
  • Loading branch information
psiinon authored Aug 30, 2023
2 parents 9921781 + 4b2b7ce commit eedd475
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 8 deletions.
162 changes: 155 additions & 7 deletions source/ContentScript/recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
ZestStatementSwitchToFrame,
} from '../types/zestScript/ZestStatement';
import {getPath} from './util';
import {ZEST_SCRIPT} from '../utils/constants';
import {STOP_RECORDING, ZEST_SCRIPT} from '../utils/constants';

class Recorder {
previousDOMState: string;
Expand All @@ -40,6 +40,8 @@ class Recorder {

haveListenersBeenAdded = false;

floatingWindowInserted = false;

async sendZestScriptToZAP(zestStatement: ZestStatement): Promise<number> {
return Browser.runtime.sendMessage({
type: ZEST_SCRIPT,
Expand Down Expand Up @@ -71,7 +73,7 @@ class Recorder {
params: {level: number; frame: number; element: Document},
event: Event
): void {
if (!this.active) return;
if (!this.shouldRecord(event.target as HTMLElement)) return;
const {level, frame, element} = params;
this.handleFrameSwitches(level, frame);
console.log(event, 'clicked');
Expand All @@ -81,7 +83,7 @@ class Recorder {
}

handleScroll(params: {level: number; frame: number}, event: Event): void {
if (!this.active) return;
if (!this.shouldRecord(event.target as HTMLElement)) return;
const {level, frame} = params;
this.handleFrameSwitches(level, frame);
console.log(event, 'scrolling.. ');
Expand All @@ -92,7 +94,7 @@ class Recorder {
params: {level: number; frame: number; element: Document},
event: Event
): void {
if (!this.active) return;
if (!this.shouldRecord(event.target as HTMLElement)) return;
const {level, frame, element} = params;
const currentDOMState = element.documentElement.outerHTML;
if (currentDOMState === this.previousDOMState) {
Expand All @@ -108,7 +110,7 @@ class Recorder {
params: {level: number; frame: number; element: Document},
event: Event
): void {
if (!this.active) return;
if (!this.shouldRecord(event.target as HTMLElement)) return;
const {level, frame, element} = params;
this.handleFrameSwitches(level, frame);
console.log(event, 'change', (event.target as HTMLInputElement).value);
Expand Down Expand Up @@ -170,6 +172,12 @@ class Recorder {
});
}

shouldRecord(element: HTMLElement): boolean {
if (!this.active) return this.active;
if (element.className === 'ZapfloatingDivElements') return false;
return true;
}

getBrowserName(): string {
let browserName: string;
const {userAgent} = navigator;
Expand All @@ -193,15 +201,155 @@ class Recorder {
console.log('user interactions');
this.active = true;
this.previousDOMState = document.documentElement.outerHTML;
if (this.haveListenersBeenAdded) return;
if (this.haveListenersBeenAdded) {
this.insertFloatingPopup();
return;
}
this.haveListenersBeenAdded = true;
window.addEventListener('resize', debounce(this.handleResize, 100));
this.addListenersToDocument(document, -1, 0);
try {
this.addListenersToDocument(document, -1, 0);
} catch (err) {
// Sometimes throw DOMException: Blocked a frame with current origin from accessing a cross-origin frame.
console.log(err);
}
this.insertFloatingPopup();
}

stopRecordingUserInteractions(): void {
console.log('Stopping Recording User Interactions ...');
Browser.storage.sync.set({zaprecordingactive: false});
this.active = false;
const floatingDiv = document.getElementById('ZapfloatingDiv');
if (floatingDiv) {
floatingDiv.style.display = 'none';
}
}

insertFloatingPopup(): void {
if (this.floatingWindowInserted) {
const floatingDiv = document.getElementById('ZapfloatingDiv');
if (floatingDiv) {
floatingDiv.style.display = 'flex';
return;
}
}

const fa = document.createElement('style');
fa.textContent =
"@font-face { font-family: 'Roboto';font-style: normal;font-weight: 400;" +
`src: url("${Browser.runtime.getURL(
'assets/fonts/Roboto-Regular.ttf'
)}"); };`;

document.head.appendChild(fa);

const floatingDiv = document.createElement('div');
floatingDiv.style.all = 'initial';
floatingDiv.className = 'ZapfloatingDivElements';
floatingDiv.id = 'ZapfloatingDiv';
floatingDiv.style.position = 'fixed';
floatingDiv.style.top = '100%';
floatingDiv.style.left = '50%';
floatingDiv.style.width = '400px';
floatingDiv.style.height = '100px';
floatingDiv.style.transform = 'translate(-50%, -105%)';
floatingDiv.style.backgroundColor = '#f9f9f9';
floatingDiv.style.border = '2px solid #e74c3c';
floatingDiv.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
floatingDiv.style.zIndex = '999999';
floatingDiv.style.textAlign = 'center';
floatingDiv.style.borderRadius = '5px';
floatingDiv.style.fontFamily = 'Roboto';
floatingDiv.style.display = 'flex';
floatingDiv.style.flexDirection = 'column';
floatingDiv.style.justifyContent = 'center';
floatingDiv.style.alignItems = 'center';

const textElement = document.createElement('p');
textElement.style.all = 'initial';
textElement.className = 'ZapfloatingDivElements';
textElement.style.margin = '0';
textElement.style.zIndex = '999999';
textElement.style.fontSize = '16px';
textElement.style.color = '#333';
textElement.style.fontFamily = 'Roboto';
textElement.textContent = 'ZAP Browser Extension is Recording...';

const buttonElement = document.createElement('button');
buttonElement.style.all = 'initial';
buttonElement.className = 'ZapfloatingDivElements';
buttonElement.style.marginTop = '10px';
buttonElement.style.padding = '8px 15px';
buttonElement.style.background = '#e74c3c';
buttonElement.style.color = 'white';
buttonElement.style.zIndex = '999999';
buttonElement.style.border = 'none';
buttonElement.style.borderRadius = '3px';
buttonElement.style.cursor = 'pointer';
buttonElement.style.fontFamily = 'Roboto';
buttonElement.textContent = 'Stop Recording';

buttonElement.addEventListener('click', () => {
this.stopRecordingUserInteractions();
Browser.runtime.sendMessage({type: STOP_RECORDING});
});

floatingDiv.appendChild(textElement);
floatingDiv.appendChild(buttonElement);

document.body.appendChild(floatingDiv);
this.floatingWindowInserted = true;

let isDragging = false;
let initialMouseX: number;
let initialMouseY: number;
let initialDivX: number;
let initialDivY: number;

// Mouse down event listener
floatingDiv.addEventListener('mousedown', (e) => {
isDragging = true;
initialMouseX = e.clientX;
initialMouseY = e.clientY;
initialDivX = floatingDiv.offsetLeft;
initialDivY = floatingDiv.offsetTop;
});

// Mouse move event listener
window.addEventListener('mousemove', (e) => {
if (!isDragging) return;

const offsetX = e.clientX - initialMouseX;
const offsetY = e.clientY - initialMouseY;

floatingDiv.style.left = `${initialDivX + offsetX}px`;
floatingDiv.style.top = `${initialDivY + offsetY}px`;
});

// Mouse up event listener
window.addEventListener('mouseup', () => {
if (!isDragging || floatingDiv.style.left.includes('%')) {
isDragging = false;
return;
}
const width =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;

const height =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;

const leftPercent = (parseInt(floatingDiv.style.left) / width) * 100;
const topPercent = (parseInt(floatingDiv.style.top) / height) * 100;

floatingDiv.style.left = `${leftPercent}%`;
floatingDiv.style.top = `${topPercent}%`;
isDragging = false;
});
}
}

Expand Down
12 changes: 11 additions & 1 deletion source/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,15 @@
"js": [
"js/contentScript.bundle.js"
]
}]
}],

"web_accessible_resources": [
{
"resources": [ "assets/fonts/Roboto-Regular.ttf"],
"matches": [
"http://*/*",
"https://*/*"
]
}
]
}
17 changes: 17 additions & 0 deletions test/ContentScript/integrationTests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,23 @@ function integrationTests(
'["{\\"action\\":{\\"action\\":\\"reportZestScript\\"},\\"body\\":{\\"scriptJson\\":\\"{\\"windowHandle\\":\\"windowHandle1\\",\\"frameIndex\\":0,\\"frameName\\":\\"\\",\\"parent\\":false,\\"index\\":1,\\"enabled\\":true,\\"elementType\\":\\"ZestClientSwitchToFrame\\"}\\",\\"apikey\\":\\"not set\\"}}","{\\"action\\":{\\"action\\":\\"reportZestScript\\"},\\"body\\":{\\"scriptJson\\":\\"{\\"windowHandle\\":\\"windowHandle1\\",\\"type\\":\\"id\\",\\"element\\":\\"test-btn\\",\\"index\\":2,\\"enabled\\":true,\\"elementType\\":\\"ZestClientElementClick\\"}\\",\\"apikey\\":\\"not set\\"}}"]'
);
});

test('Should not record interactions on floating container', async () => {
// Given / When
server = getFakeZapServer(actualData, _JSONPORT);
const context = await driver.getContext(_JSONPORT, true);
await driver.setEnable(false);
const page = await context.newPage();
await page.goto(
`http://localhost:${_HTTPPORT}/webpages/interactions.html`
);
await page.click('#ZapfloatingDiv');
await page.waitForLoadState('networkidle');
await page.waitForTimeout(1000);
await page.close();
// Then
expect(JSON.stringify(Array.from(actualData))).toBe('[]');
});
}
}

Expand Down

0 comments on commit eedd475

Please sign in to comment.