-
Notifications
You must be signed in to change notification settings - Fork 235
/
AutoCaptureHandler.ts
121 lines (107 loc) · 6.4 KB
/
AutoCaptureHandler.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* @copyright Microsoft 2020
*/
import dynamicProto from "@microsoft/dynamicproto-js";
import {
IDiagnosticLogger, IProcessTelemetryUnloadContext, ITelemetryUnloadState, createUniqueNamespace, eventOff, eventOn, getDocument,
getWindow, isNullOrUndefined, mergeEvtNamespace
} from "@microsoft/applicationinsights-core-js";
import { ClickAnalyticsPlugin } from "../ClickAnalyticsPlugin";
import { ActionType } from "../Enums";
import { IAutoCaptureHandler, IClickAnalyticsConfiguration, IPageActionOverrideValues } from "../Interfaces/Datamodel";
import { isElementDnt, isKeyboardEnter, isKeyboardSpace, isLeftClick, isMiddleClick, isRightClick } from "../common/Utils";
import { PageAction } from "../events/PageAction";
const clickCaptureInputTypes = { BUTTON: true, CHECKBOX: true, RADIO: true, RESET: true, SUBMIT: true };
export class AutoCaptureHandler implements IAutoCaptureHandler {
/**
* @param analyticsPlugin - WebAnalytics plugin
* @param traceLogger - Trace logger to log to console.
*/
constructor(protected _analyticsPlugin: ClickAnalyticsPlugin, protected _config: IClickAnalyticsConfiguration, protected _pageAction: PageAction,
protected _traceLogger: IDiagnosticLogger) {
let _evtNamespace = mergeEvtNamespace(createUniqueNamespace("AutoCaptureHandler"), (_analyticsPlugin as any)._evtNamespace);
dynamicProto(AutoCaptureHandler, this, (_self) => {
_self.click = () => {
let win = getWindow();
let doc = getDocument();
if (win) {
// IE9 onwards addEventListener is available, 'click' event captures mouse click. mousedown works on other browsers
const event = (navigator.appVersion.indexOf("MSIE") !== -1) ? "click" : "mousedown";
eventOn(win, event, _processClick, _evtNamespace);
eventOn(win, "keyup", _processClick, _evtNamespace);
} else if (doc) {
// IE8 and below doesn't have addEventListener so it will use attachEvent
// attaching to window does not work in IE8
eventOn(doc, "click", _processClick, _evtNamespace);
eventOn(doc, "keyup", _processClick, _evtNamespace);
}
};
_self._doUnload = (unloadCtx?: IProcessTelemetryUnloadContext, unloadState?: ITelemetryUnloadState, asyncCallback?: () => void): void | boolean => {
eventOff(getWindow(), null, null, _evtNamespace);
eventOff(getDocument(), null, null, _evtNamespace);
};
function _capturePageAction(element: Element, overrideValues?: IPageActionOverrideValues, customProperties?: { [name: string]: string | number | boolean | string[] | number[] | boolean[] | object }, isRightClick?: boolean): void {
const donotTrackTag = _self._config.dataTags.customDataPrefix + _self._config.dataTags.dntDataTag;
if (!isElementDnt(element, donotTrackTag)) {
_self._pageAction.capturePageAction(element, overrideValues, customProperties, isRightClick);
}
}
// Process click event
function _processClick(clickEvent: any) {
var clickCaptureElements = { A: true, BUTTON: true, AREA: true, INPUT: true };
let win = getWindow();
if (isNullOrUndefined(clickEvent) && win) {
clickEvent = win.event; // IE 8 does not pass the event
}
if (clickEvent) {
let element = clickEvent.srcElement || clickEvent.target;
// populate overrideValues
var overrideValues: IPageActionOverrideValues = {
clickCoordinateX: clickEvent.pageX,
clickCoordinateY: clickEvent.pageY
};
var isRightClickObj = isRightClick(clickEvent as MouseEvent);
if (isRightClickObj) {
overrideValues.actionType = ActionType.CLICKRIGHT;
} else if (isLeftClick(clickEvent as MouseEvent)) {
overrideValues.actionType = ActionType.CLICKLEFT;
} else if (isKeyboardEnter(clickEvent as KeyboardEvent)) {
overrideValues.actionType = ActionType.KEYBOARDENTER;
} else if (isKeyboardSpace(clickEvent as KeyboardEvent)) {
overrideValues.actionType = ActionType.KEYBOARDSPACE;
} else if (isMiddleClick(clickEvent as MouseEvent)) {
overrideValues.actionType = ActionType.CLICKMIDDLE;
} else {
return;
}
while (element && element.tagName) {
// control property will be available for <label> elements with 'for' attribute, only use it when is a
// valid JSLL capture element to avoid infinite loops
if (element.control && clickCaptureElements[element.control.tagName.toUpperCase()]) {
element = element.control;
}
const tagNameUpperCased = element.tagName.toUpperCase();
if (!clickCaptureElements[tagNameUpperCased]) {
element = element.parentElement || element.parentNode;
continue;
} else {
// Check allowed INPUT types
var sendEvent = tagNameUpperCased === "INPUT" ? clickCaptureInputTypes[element.type.toUpperCase()] : true;
if (sendEvent) {
_capturePageAction(element, overrideValues, {}, isRightClickObj);
}
break;
}
}
}
}
});
}
// handle automatic event firing on user click
public click() {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}
public _doUnload(unloadCtx?: IProcessTelemetryUnloadContext, unloadState?: ITelemetryUnloadState, asyncCallback?: () => void): void | boolean {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}
}