Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export class ClickEventTest extends AITestClass {
pageType: ""
};

const defaultElementTypes = "A,BUTTON,AREA,INPUT";

const clickAnalyticsPlugin = new ClickAnalyticsPlugin();
const core = new AppInsightsCore();
const channel = new ChannelPlugin();
Expand Down Expand Up @@ -76,6 +78,7 @@ export class ClickEventTest extends AITestClass {
Assert.equal(extConfig.urlCollectQuery, false, "urlCollectQuery should be false by default");
Assert.deepEqual(extConfig.dataTags, dataTagsDefault, "udataTags should be set by default");
Assert.deepEqual(extConfig.coreData, coreDataDefault, "udataTags should be set by default");
Assert.deepEqual(extConfig.trackElementTypes, defaultElementTypes, "trackElementTypes should be set by default");

Assert.ok(extConfig.callback, "callback should be set by default");
let callbacks = extConfig.callback;
Expand Down Expand Up @@ -420,11 +423,50 @@ export class ClickEventTest extends AITestClass {
defaultRightClickBhvr: "",
dropInvalidEvents : false,
urlCollectHash: false,
urlCollectQuery: false
urlCollectQuery: false,
trackElementTypes: "A,BUTTON,AREA,INPUT"
}, core.config.extensionConfig[clickAnalyticsPlugin.identifier]);

}
});
this.testCase({
name: "trackElementTypes: validate empty string, string with spaces, lowercase, and dynamic changes",
useFakeTimers: true,
test: () => {
const config = {
trackElementTypes: "A,BUTTON,AREA,INPUT"
};
const clickAnalyticsPlugin = new ClickAnalyticsPlugin();
const core = new AppInsightsCore();
const channel = new ChannelPlugin();

core.initialize({
instrumentationKey: 'testIkey',
extensionConfig: {
[clickAnalyticsPlugin.identifier]: config
}
} as IConfig & IConfiguration, [clickAnalyticsPlugin, channel]);
this.onDone(() => {
core.unload(false);
});

let currentConfig = core.config["extensionConfig"][clickAnalyticsPlugin.identifier].trackElementTypes;
// Validate default value
Assert.equal("A,BUTTON,AREA,INPUT", currentConfig, "Default trackElementTypes should be 'A,BUTTON,AREA,INPUT'");

// Test empty string
core.config["extensionConfig"][clickAnalyticsPlugin.identifier].trackElementTypes = null;
this.clock.tick(1);
currentConfig = core.config["extensionConfig"][clickAnalyticsPlugin.identifier].trackElementTypes;
Assert.equal("A,BUTTON,AREA,INPUT", currentConfig, "default value would be applied");

// Test dynamic change
core.config["extensionConfig"][clickAnalyticsPlugin.identifier].trackElementTypes = "A,BUTTON,AREA,INPUT,TEST";
this.clock.tick(1);
currentConfig = core.config["extensionConfig"][clickAnalyticsPlugin.identifier].trackElementTypes;
Assert.equal("A,BUTTON,AREA,INPUT,TEST", currentConfig, "spaces and lowercase string will be converted to uppercase and trimmed");
}
});

this.testCase({
name: "PageAction properties are correctly assigned (Populated) with useDefaultContentNameOrId flag false",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ const defaultValues: IConfigDefaults<IClickAnalyticsConfiguration> = objDeepFree
defaultRightClickBhvr: cfgDfString(),
dropInvalidEvents : false,
urlCollectHash: false,
urlCollectQuery: false
urlCollectQuery: false,
trackElementTypes: cfgDfString("A,BUTTON,AREA,INPUT")
});

function _dataPrefixChk(val: any) {
Expand Down Expand Up @@ -147,7 +148,7 @@ export class ClickAnalyticsPlugin extends BaseTelemetryPlugin {
_contentHandler = new DomContentHandler(_config, logger);
let metaTags = _contentHandler.getMetadata();
_pageAction = new PageAction(_self, _config, _contentHandler, _config.callback.pageActionPageTags, metaTags, logger);

// Default to DOM autoCapture handler
if (_autoCaptureHandler) {
_autoCaptureHandler._doUnload();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export interface IClickAnalyticsConfiguration {
* Enables the logging of the query string of the URL. Default is "false."
*/
urlCollectQuery?: boolean;

/**
* A list of element types to track. Default is "undefined" which means default elements ["a", "button", "area", "input"] are tracked.
* If set, it will combine with the default element types.
*/
trackElementTypes?: string;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

import dynamicProto from "@microsoft/dynamicproto-js";
import {
IDiagnosticLogger, IProcessTelemetryUnloadContext, ITelemetryUnloadState, createUniqueNamespace, eventOff, eventOn, getDocument,
getWindow, isNullOrUndefined, mergeEvtNamespace
IDiagnosticLogger, IProcessTelemetryUnloadContext, ITelemetryUnloadState, IUnloadHook, createUniqueNamespace, eventOff, eventOn,
getDocument, getWindow, isNullOrUndefined, mergeEvtNamespace, onConfigChange
} from "@microsoft/applicationinsights-core-js";
import { arrMap, strTrim } from "@nevware21/ts-utils";
import { ClickAnalyticsPlugin } from "../ClickAnalyticsPlugin";
import { ActionType } from "../Enums";
import { IAutoCaptureHandler, IClickAnalyticsConfiguration, IPageActionOverrideValues } from "../Interfaces/Datamodel";
Expand All @@ -23,11 +24,12 @@ export class AutoCaptureHandler implements IAutoCaptureHandler {
*/
constructor(protected _analyticsPlugin: ClickAnalyticsPlugin, protected _config: IClickAnalyticsConfiguration, protected _pageAction: PageAction,
protected _traceLogger: IDiagnosticLogger) {

let _evtNamespace = mergeEvtNamespace(createUniqueNamespace("AutoCaptureHandler"), (_analyticsPlugin as any)._evtNamespace);

let unloadHandler: IUnloadHook = onConfigChange(_config, () => {
_clickCaptureElements = arrMap(_config.trackElementTypes.toUpperCase().split(","), tag => strTrim(tag));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

});
let _clickCaptureElements: string[];
dynamicProto(AutoCaptureHandler, this, (_self) => {

_self.click = () => {
let win = getWindow();
let doc = getDocument();
Expand All @@ -47,6 +49,8 @@ export class AutoCaptureHandler implements IAutoCaptureHandler {
_self._doUnload = (unloadCtx?: IProcessTelemetryUnloadContext, unloadState?: ITelemetryUnloadState, asyncCallback?: () => void): void | boolean => {
eventOff(getWindow(), null, null, _evtNamespace);
eventOff(getDocument(), null, null, _evtNamespace);
unloadHandler && unloadHandler.rm();
unloadHandler = null;
};

function _capturePageAction(element: Element, overrideValues?: IPageActionOverrideValues, customProperties?: { [name: string]: string | number | boolean | string[] | number[] | boolean[] | object }, isRightClick?: boolean): void {
Expand All @@ -58,7 +62,6 @@ export class AutoCaptureHandler implements IAutoCaptureHandler {

// 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
Expand Down Expand Up @@ -89,11 +92,11 @@ export class AutoCaptureHandler implements IAutoCaptureHandler {
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()]) {
if (element.control && _clickCaptureElements[element.control.tagName.toUpperCase()]) {
element = element.control;
}
const tagNameUpperCased = element.tagName.toUpperCase();
if (!clickCaptureElements[tagNameUpperCased]) {
if (!_clickCaptureElements[tagNameUpperCased]) {
element = element.parentElement || element.parentNode;
continue;
} else {
Expand Down
Loading