Skip to content

Commit 6b3b527

Browse files
zhu-xiaoweixiaoweii
andauthored
fix: click event does not respond when disable the event bubbling (#11)
Co-authored-by: xiaoweii <xiaoweii@amazom.com>
1 parent dd678cc commit 6b3b527

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ jobs:
1919
uses: codecov/codecov-action@v3
2020
with:
2121
name: report
22-
files: coverage/clover.xml
22+
files: coverage/coverage-final.json

src/tracker/ClickTracker.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,22 @@ import { Event } from '../provider';
1818
const logger = new Logger('ClickTracker');
1919

2020
export class ClickTracker extends BaseTracker {
21+
processedElements = new WeakSet();
22+
2123
init() {
2224
this.trackClick = this.trackClick.bind(this);
23-
document.addEventListener('click', this.trackClick);
2425
const currentDomain = window.location.host;
2526
const domainList = this.context.configuration.domainList;
2627
if (!domainList.includes(currentDomain)) {
2728
domainList.push(currentDomain);
2829
}
30+
this.addClickListenerForATag();
2931
}
3032

3133
trackClick(event: MouseEvent) {
3234
if (!this.context.configuration.isTrackClickEvents) return;
3335
const targetElement = event.target as Element;
34-
const element = this.findTagA(targetElement);
36+
const element = this.findATag(targetElement);
3537
if (element !== null) {
3638
const linkUrl = element.getAttribute('href');
3739
if (linkUrl === null || linkUrl.length === 0) return;
@@ -60,13 +62,33 @@ export class ClickTracker extends BaseTracker {
6062
}
6163
}
6264

63-
findTagA(element: Element, depth = 0): Element {
65+
addClickListenerForATag() {
66+
const observer = new MutationObserver(mutationsList => {
67+
for (const mutation of mutationsList) {
68+
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
69+
const target = mutation.target;
70+
if (target instanceof Element) {
71+
const aTags = target.querySelectorAll('a');
72+
aTags.forEach(aTag => {
73+
if (!this.processedElements.has(aTags)) {
74+
aTag.addEventListener('click', this.trackClick);
75+
this.processedElements.add(aTag);
76+
}
77+
});
78+
}
79+
}
80+
}
81+
});
82+
observer.observe(document.body, { childList: true, subtree: true });
83+
}
84+
85+
findATag(element: Element, depth = 0): Element {
6486
if (element && depth < 3) {
6587
if (element.tagName === 'A') {
6688
return element;
6789
} else {
6890
depth += 1;
69-
return this.findTagA(element.parentElement, depth);
91+
return this.findATag(element.parentElement, depth);
7092
}
7193
}
7294
return null;

test/tracker/ClickTracker.test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ describe('ClickTracker test', () => {
6565
clickTracker.setUp();
6666
window.document.dispatchEvent(new window.Event('click'));
6767
expect(recordMethodMock).not.toBeCalled();
68-
expect(trackClickMock).toBeCalled();
68+
expect(trackClickMock).not.toBeCalled();
6969
});
7070

7171
test('test click a element with current domain', () => {
@@ -89,6 +89,19 @@ describe('ClickTracker test', () => {
8989
});
9090
});
9191

92+
test('test disable the configuration for track click event', () => {
93+
provider.configuration.isTrackClickEvents = false;
94+
const clickEvent = getMockMouseEvent(
95+
'A',
96+
'https://localhost/collect',
97+
'link-class',
98+
'link-id'
99+
);
100+
clickTracker.setUp();
101+
clickTracker.trackClick(clickEvent);
102+
expect(recordMethodMock).not.toBeCalled();
103+
});
104+
92105
test('test click a element in configured domain', () => {
93106
const clickEvent = getMockMouseEvent(
94107
'A',
@@ -174,6 +187,28 @@ describe('ClickTracker test', () => {
174187
});
175188
});
176189

190+
test('test click a element with out a tag in parent', () => {
191+
const clickEvent = getMockMouseEvent('SPAN', '', '', '');
192+
const targetElement = document.createElement('SPAN');
193+
Object.defineProperty(clickEvent.target, 'parentElement', {
194+
writable: true,
195+
value: targetElement,
196+
});
197+
clickTracker.setUp();
198+
clickTracker.trackClick(clickEvent);
199+
expect(recordMethodMock).not.toBeCalled();
200+
});
201+
202+
test('test add A tag and trigger MutationObserver', async () => {
203+
clickTracker.setUp();
204+
const div = document.createElement('div');
205+
const aTag = document.createElement('A');
206+
div.appendChild(aTag);
207+
document.body.appendChild(div);
208+
await sleep(100);
209+
expect(clickTracker.processedElements.has(aTag)).toBeTruthy();
210+
});
211+
177212
function getMockMouseEvent(
178213
tagName: string,
179214
href: string,
@@ -191,4 +226,8 @@ describe('ClickTracker test', () => {
191226
});
192227
return event;
193228
}
229+
230+
function sleep(ms: number): Promise<void> {
231+
return new Promise(resolve => setTimeout(resolve, ms));
232+
}
194233
});

0 commit comments

Comments
 (0)