@microsoft/applicationinsights-clickanalytics-js 2.8.0-beta.2203-08 → 2.8.0-beta.2203-11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/browser/{ai.clck.2.8.0-beta.2203-08.cjs.js → ai.clck.2.8.0-beta.2203-11.cjs.js} +701 -505
  2. package/browser/ai.clck.2.8.0-beta.2203-11.cjs.js.map +1 -0
  3. package/browser/ai.clck.2.8.0-beta.2203-11.cjs.min.js +6 -0
  4. package/browser/ai.clck.2.8.0-beta.2203-11.cjs.min.js.map +1 -0
  5. package/browser/{ai.clck.2.8.0-beta.2203-08.gbl.js → ai.clck.2.8.0-beta.2203-11.gbl.js} +701 -505
  6. package/browser/ai.clck.2.8.0-beta.2203-11.gbl.js.map +1 -0
  7. package/browser/ai.clck.2.8.0-beta.2203-11.gbl.min.js +6 -0
  8. package/browser/ai.clck.2.8.0-beta.2203-11.gbl.min.js.map +1 -0
  9. package/browser/ai.clck.2.8.0-beta.2203-11.integrity.json +66 -0
  10. package/browser/{ai.clck.2.8.0-beta.2203-08.js → ai.clck.2.8.0-beta.2203-11.js} +701 -505
  11. package/browser/ai.clck.2.8.0-beta.2203-11.js.map +1 -0
  12. package/browser/ai.clck.2.8.0-beta.2203-11.min.js +6 -0
  13. package/browser/ai.clck.2.8.0-beta.2203-11.min.js.map +1 -0
  14. package/browser/ai.clck.2.cjs.js +700 -504
  15. package/browser/ai.clck.2.cjs.js.map +1 -1
  16. package/browser/ai.clck.2.cjs.min.js +2 -2
  17. package/browser/ai.clck.2.cjs.min.js.map +1 -1
  18. package/browser/ai.clck.2.gbl.js +700 -504
  19. package/browser/ai.clck.2.gbl.js.map +1 -1
  20. package/browser/ai.clck.2.gbl.min.js +2 -2
  21. package/browser/ai.clck.2.gbl.min.js.map +1 -1
  22. package/browser/ai.clck.2.js +700 -504
  23. package/browser/ai.clck.2.js.map +1 -1
  24. package/browser/ai.clck.2.min.js +2 -2
  25. package/browser/ai.clck.2.min.js.map +1 -1
  26. package/dist/applicationinsights-clickanalytics-js.api.json +15 -1
  27. package/dist/applicationinsights-clickanalytics-js.api.md +1 -0
  28. package/dist/applicationinsights-clickanalytics-js.d.ts +2 -5
  29. package/dist/applicationinsights-clickanalytics-js.js +700 -504
  30. package/dist/applicationinsights-clickanalytics-js.js.map +1 -1
  31. package/dist/applicationinsights-clickanalytics-js.min.js +2 -2
  32. package/dist/applicationinsights-clickanalytics-js.min.js.map +1 -1
  33. package/dist/applicationinsights-clickanalytics-js.rollup.d.ts +2 -5
  34. package/dist-esm/Behaviours.js +1 -1
  35. package/dist-esm/ClickAnalyticsPlugin.js +74 -50
  36. package/dist-esm/ClickAnalyticsPlugin.js.map +1 -1
  37. package/dist-esm/DataCollector.js +4 -2
  38. package/dist-esm/DataCollector.js.map +1 -1
  39. package/dist-esm/Enums.js +1 -1
  40. package/dist-esm/Interfaces/Datamodel.js +1 -1
  41. package/dist-esm/applicationinsights-clickanalytics-js.js +1 -1
  42. package/dist-esm/common/Utils.js +1 -1
  43. package/dist-esm/events/PageAction.js +128 -126
  44. package/dist-esm/events/PageAction.js.map +1 -1
  45. package/dist-esm/events/WebEvent.js +109 -94
  46. package/dist-esm/events/WebEvent.js.map +1 -1
  47. package/dist-esm/handlers/AutoCaptureHandler.js +85 -83
  48. package/dist-esm/handlers/AutoCaptureHandler.js.map +1 -1
  49. package/dist-esm/handlers/DomContentHandler.js +279 -276
  50. package/dist-esm/handlers/DomContentHandler.js.map +1 -1
  51. package/package.json +5 -5
  52. package/src/ClickAnalyticsPlugin.ts +92 -47
  53. package/src/DataCollector.ts +24 -22
  54. package/src/Interfaces/Datamodel.ts +20 -21
  55. package/src/common/Utils.ts +8 -8
  56. package/src/events/PageAction.ts +165 -131
  57. package/src/events/WebEvent.ts +147 -78
  58. package/src/handlers/AutoCaptureHandler.ts +89 -79
  59. package/src/handlers/DomContentHandler.ts +336 -303
  60. package/types/ClickAnalyticsPlugin.d.ts +1 -4
  61. package/types/Interfaces/Datamodel.d.ts +3 -2
  62. package/types/events/PageAction.d.ts +6 -6
  63. package/types/events/WebEvent.d.ts +17 -17
  64. package/types/handlers/AutoCaptureHandler.d.ts +2 -10
  65. package/types/handlers/DomContentHandler.d.ts +3 -50
  66. package/types/tsdoc-metadata.json +1 -1
  67. package/browser/ai.clck.2.8.0-beta.2203-08.cjs.js.map +0 -1
  68. package/browser/ai.clck.2.8.0-beta.2203-08.cjs.min.js +0 -6
  69. package/browser/ai.clck.2.8.0-beta.2203-08.cjs.min.js.map +0 -1
  70. package/browser/ai.clck.2.8.0-beta.2203-08.gbl.js.map +0 -1
  71. package/browser/ai.clck.2.8.0-beta.2203-08.gbl.min.js +0 -6
  72. package/browser/ai.clck.2.8.0-beta.2203-08.gbl.min.js.map +0 -1
  73. package/browser/ai.clck.2.8.0-beta.2203-08.integrity.json +0 -66
  74. package/browser/ai.clck.2.8.0-beta.2203-08.js.map +0 -1
  75. package/browser/ai.clck.2.8.0-beta.2203-08.min.js +0 -6
  76. package/browser/ai.clck.2.8.0-beta.2203-08.min.js.map +0 -1
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * @copyright Microsoft 2020
3
3
  */
4
+
5
+ import dynamicProto from "@microsoft/dynamicproto-js";
4
6
  import {
5
7
  removeInvalidElements,
6
8
  walkUpDomChainWithElementValidation,
7
9
  extend, _ExtendedInternalMessageId, isValueAssigned
8
10
  } from "../common/Utils";
9
- import { IDiagnosticLogger, LoggingSeverity, getDocument, isNullOrUndefined, hasDocument} from "@microsoft/applicationinsights-core-js";
11
+ import { IDiagnosticLogger, LoggingSeverity, getDocument, isNullOrUndefined, hasDocument, IProcessTelemetryUnloadContext, ITelemetryUnloadState} from "@microsoft/applicationinsights-core-js";
10
12
  import { IClickAnalyticsConfiguration, IContent, IContentHandler } from "../Interfaces/Datamodel";
11
13
 
12
14
  const MAX_CONTENTNAME_LENGTH = 200;
@@ -18,347 +20,378 @@ export class DomContentHandler implements IContentHandler {
18
20
  * @param traceLogger - Trace logger to log to console.
19
21
  */
20
22
  constructor(protected _config: IClickAnalyticsConfiguration, protected _traceLogger: IDiagnosticLogger) {
21
- }
22
23
 
23
- /**
24
- * Collect metatags from DOM.
25
- * Collect data from meta tags.
26
- * @returns {object} - Metatags collection/property bag
27
- */
28
- public getMetadata(): { [name: string]: string } {
24
+ dynamicProto(DomContentHandler, this, (_self) => {
25
+
26
+ _self.getMetadata = (): { [name: string]: string } => {
27
+ let dataTags = (_self._config || {}).dataTags;
28
+ let metaTags = {};
29
+ if (hasDocument) {
30
+ metaTags = isValueAssigned(dataTags.metaDataPrefix) ? _getMetaDataFromDOM(dataTags.captureAllMetaDataContent, dataTags.metaDataPrefix, false) :
31
+ _getMetaDataFromDOM(dataTags.captureAllMetaDataContent ,"", false);
32
+ }
33
+ return metaTags;
34
+ };
35
+
36
+ _self.getElementContent = (element: Element): IContent => {
29
37
 
30
- let metaTags = {};
31
- if (hasDocument) {
32
- metaTags = isValueAssigned(this._config.dataTags.metaDataPrefix) ? this._getMetaDataFromDOM(this._config.dataTags.captureAllMetaDataContent ,this._config.dataTags.metaDataPrefix, false) :
33
- this._getMetaDataFromDOM(this._config.dataTags.captureAllMetaDataContent ,"", false);
34
- }
35
- return metaTags;
36
- }
38
+ if (!element) {
39
+ return {};
40
+ }
41
+
42
+ let dataTags = (_self._config || {}).dataTags;
43
+ let elementContent: any = {};
44
+ let biBlobValue;
45
+ let parentDataTagPrefix;
46
+ const dataTagPrefix:string = dataTags.customDataPrefix;
47
+ const aiBlobAttributeTag:string = dataTagPrefix + dataTags.aiBlobAttributeTag;
48
+ if(isValueAssigned(dataTags.parentDataTag)) {
49
+ parentDataTagPrefix = dataTagPrefix + dataTags.parentDataTag;
50
+ }
51
+
52
+ if (!_isTracked(element, dataTagPrefix, aiBlobAttributeTag)) {
53
+ // capture blob from element or hierarchy
54
+ biBlobValue = element.getAttribute(aiBlobAttributeTag);
55
+ if (biBlobValue) {
56
+ try {
57
+ elementContent = JSON.parse(biBlobValue);
58
+ } catch (e) {
59
+ _self._traceLogger.throwInternal(
60
+ LoggingSeverity.CRITICAL,
61
+ _ExtendedInternalMessageId.CannotParseAiBlobValue, "Can not parse " + biBlobValue
62
+ );
63
+ }
64
+ } else {
65
+ // traverse up the DOM to find the closest parent with data-* tag defined
66
+ //contentElement = walkUpDomChainWithElementValidation(element, _self._isTracked, dataTagPrefix);
67
+ elementContent = extend(elementContent, _populateElementContent(element, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag));
68
+ }
69
+ } else {
70
+ elementContent = extend(elementContent, _populateElementContentwithDataTag(element, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag));
71
+ }
37
72
 
38
- /**
39
- * Collect data-* attributes for the given element.
40
- * All attributes with data-* prefix or user provided customDataPrefix are collected.'data-*' prefix is removed from the key name.
41
- * @param element - The element from which attributes need to be collected.
42
- * @returns String representation of the Json array of element attributes
43
- */
44
- public getElementContent(element: Element): IContent {
73
+ removeInvalidElements(elementContent);
74
+
75
+ if (parentDataTagPrefix) {
76
+ elementContent = extend(elementContent, _getParentDetails(element, elementContent, dataTagPrefix, aiBlobAttributeTag ));
77
+ }
45
78
 
46
- if (!element) {
47
- return {};
48
- }
49
-
50
- let elementContent: any = {};
51
- let biBlobValue;
52
- let parentDataTagPrefix;
53
- const dataTagPrefix:string = this._config.dataTags.customDataPrefix;
54
- const aiBlobAttributeTag:string = dataTagPrefix + this._config.dataTags.aiBlobAttributeTag;
55
- if(isValueAssigned(this._config.dataTags.parentDataTag)) {
56
- parentDataTagPrefix = dataTagPrefix + this._config.dataTags.parentDataTag;
57
- }
79
+ return elementContent;
80
+ };
58
81
 
59
- if (!this._isTracked(element, dataTagPrefix, aiBlobAttributeTag)) {
60
- // capture blob from element or hierarchy
61
- biBlobValue = element.getAttribute(aiBlobAttributeTag);
62
- if (biBlobValue) {
63
- try {
64
- elementContent = JSON.parse(biBlobValue);
65
- } catch (e) {
66
- this._traceLogger.throwInternal(
67
- LoggingSeverity.CRITICAL,
68
- _ExtendedInternalMessageId.CannotParseAiBlobValue, "Can not parse " + biBlobValue
69
- );
82
+ /**
83
+ * Capture current level Element content
84
+ */
85
+ function _captureElementContentWithDataTag(contentElement: Element, elementContent: any, dataTagPrefix: string) {
86
+
87
+ for (var i = 0, attrib; i < contentElement.attributes.length; i++) {
88
+ attrib = contentElement.attributes[i];
89
+
90
+ if ( attrib.name.indexOf(dataTagPrefix) !== 0 ) {
91
+ continue;
92
+ }
93
+
94
+ var attribName = attrib.name.replace(dataTagPrefix, "");
95
+ elementContent[attribName] = attrib.value;
70
96
  }
71
- } else {
72
- // traverse up the DOM to find the closest parent with data-* tag defined
73
- //contentElement = walkUpDomChainWithElementValidation(element, this._isTracked, dataTagPrefix);
74
- elementContent = extend(elementContent, this._populateElementContent(element, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag));
75
97
  }
76
- } else {
77
- elementContent = extend(elementContent, this._populateElementContentwithDataTag(element, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag));
78
- }
79
- removeInvalidElements(elementContent);
80
- if (parentDataTagPrefix) {
81
- elementContent = extend(elementContent, this._getParentDetails(element, elementContent, dataTagPrefix, aiBlobAttributeTag ));
82
- }
83
-
84
- return elementContent;
85
- }
86
98
 
87
- /**
88
- * Capture current level Element content
89
- */
90
- private _captureElementContentWithDataTag(contentElement: Element, elementContent: any, dataTagPrefix: string) {
99
+ /**
100
+ * Walk Up the DOM to capture Element content
101
+ */
102
+ function _walkUpDomChainCaptureData(el: Element, elementContent: any, dataTagPrefix: string, parentDataTagPrefix: string, aiBlobAttributeTag: string ): void {
103
+ let element = el;
104
+ let parentDataTagFound: boolean = false;
105
+ let elementLevelFlag: boolean = false; // Use this flag to capture 'id' only at the incoming html element level.
91
106
 
92
- for (var i = 0, attrib; i < contentElement.attributes.length; i++) {
93
- attrib = contentElement.attributes[i];
107
+ while(!isNullOrUndefined(element) && !isNullOrUndefined(element.attributes)) {
108
+ let attributes=element.attributes;
94
109
 
95
- if ( attrib.name.indexOf(dataTagPrefix) !== 0 ) {
96
- continue;
110
+ for (let i = 0; i < attributes.length; i++) {
111
+ const attrib = attributes[i];
112
+
113
+ if ( attrib.name.indexOf(dataTagPrefix) !== 0 ) {
114
+ continue;
115
+ }
116
+
117
+ if (attrib.name.indexOf(parentDataTagPrefix) === 0) {
118
+ parentDataTagFound = true;
119
+ }
120
+
121
+ // Todo handle blob data
122
+ if (attrib.name.indexOf(aiBlobAttributeTag) === 0) {
123
+ continue;
124
+ }
125
+
126
+ const attribName = attrib.name.replace(dataTagPrefix, "");
127
+ if (elementLevelFlag && attribName === "id") {
128
+ continue; // skip capturing id if not at the first level.
129
+ }
130
+
131
+ if (!isValueAssigned(elementContent[attribName])) {
132
+ elementContent[attribName] = attrib.value;
133
+ }
134
+ }
135
+
136
+ // break after current level;
137
+ if (parentDataTagFound) {
138
+ break;
139
+ }
140
+
141
+ elementLevelFlag = true; // after the initial level set this flag to true.
142
+ element = (element.parentNode as Element);
143
+ }
97
144
  }
98
145
 
99
- var attribName = attrib.name.replace(dataTagPrefix, "");
100
- elementContent[attribName] = attrib.value;
101
- }
102
- }
146
+ /**
147
+ * Capture Element content along with Data Tag attributes and values
148
+ */
149
+ function _populateElementContent(element: Element, dataTagPrefix: string, parentDataTagPrefix: string, aiBlobAttributeTag: string) {
150
+
151
+ let elementContent: any = {};
152
+ if(!element) {
153
+ return elementContent;
154
+ }
103
155
 
104
- /**
105
- * Walk Up the DOM to capture Element content
106
- */
107
- private _walkUpDomChainCaptureData(el: Element, elementContent: any, dataTagPrefix: string, parentDataTagPrefix: string, aiBlobAttributeTag: string ): void {
108
- let element = el;
109
- let parentDataTagFound: boolean = false;
110
- let elementLevelFlag: boolean = false; // Use this flag to capture 'id' only at the incoming html element level.
111
- while(!isNullOrUndefined(element) && !isNullOrUndefined(element.attributes)) {
112
- let attributes=element.attributes;
113
- for (let i = 0; i < attributes.length; i++) {
114
- const attrib = attributes[i];
115
-
116
- if ( attrib.name.indexOf(dataTagPrefix) !== 0 ) {
117
- continue;
156
+ let htmlContent = _getHtmlIdAndContentName(element);
157
+ elementContent = {
158
+ id: htmlContent.id || "",
159
+ contentName: htmlContent.contentName || ""
160
+ };
161
+
162
+ if(isValueAssigned(parentDataTagPrefix)) {
163
+ _walkUpDomChainCaptureData(element, elementContent, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag);
118
164
  }
119
165
 
120
- if( attrib.name.indexOf(parentDataTagPrefix) === 0) {
121
- parentDataTagFound = true;
166
+ // Validate to ensure the minimum required field 'id' or 'contentName' is present.
167
+ // The content schema defines id, aN and sN as required fields. However,
168
+ // requiring these fields would result in majority of adopter's content from being collected.
169
+ // Just throw a warning and continue collection.
170
+ if (!elementContent.id && !elementContent.contentName) {
171
+ _traceLogger.throwInternal(
172
+ LoggingSeverity.WARNING,
173
+ _ExtendedInternalMessageId.InvalidContentBlob, "Invalid content blob. Missing required attributes (id, contentName. " +
174
+ " Content information will still be collected!"
175
+ )
176
+ }
177
+
178
+ return elementContent;
179
+ }
180
+
181
+ /**
182
+ * Capture Element content along with Data Tag attributes and values
183
+ */
184
+ function _populateElementContentwithDataTag(element: Element, dataTagPrefix: string, parentDataTagPrefix: string, aiBlobAttributeTag: string) {
185
+ let dataTags = (_self._config || {}).dataTags;
186
+ let elementContent: any = {};
187
+ if(!element) {
188
+ return elementContent;
122
189
  }
123
190
 
124
- // Todo handle blob data
125
- if( attrib.name.indexOf(aiBlobAttributeTag) === 0) {
126
- continue;
191
+ let htmlContent = _getHtmlIdAndContentName(element);
192
+
193
+ if(isValueAssigned(parentDataTagPrefix)) {
194
+ _walkUpDomChainCaptureData(element, elementContent, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag);
195
+ } else {
196
+ _captureElementContentWithDataTag(element, elementContent, dataTagPrefix);
127
197
  }
128
- const attribName = attrib.name.replace(dataTagPrefix, "");
129
- if(elementLevelFlag && attribName ==="id") continue; // skip capturing id if not at the first level.
130
- if(!isValueAssigned(elementContent[attribName])) {
131
- elementContent[attribName] = attrib.value;
198
+
199
+
200
+ if (dataTags.useDefaultContentNameOrId) {
201
+ if(!isValueAssigned(elementContent.id)) {
202
+ elementContent.id = htmlContent.id || "";
203
+ }
204
+
205
+ elementContent.contentName = htmlContent.contentName || "";
132
206
  }
207
+
208
+ // Validate to ensure the minimum required field 'id' or 'contentName' is present.
209
+ // The content schema defines id, aN and sN as required fields. However,
210
+ // requiring these fields would result in majority of adopter's content from being collected.
211
+ // Just throw a warning and continue collection.
212
+ if (!elementContent.id && !elementContent.contentName) {
213
+ _traceLogger.throwInternal(
214
+ LoggingSeverity.WARNING,
215
+ _ExtendedInternalMessageId.InvalidContentBlob, "Invalid content blob. Missing required attributes (id, contentName. " +
216
+ " Content information will still be collected!"
217
+ )
218
+ }
219
+
220
+ return elementContent;
133
221
  }
134
-
135
- // break after current level;
136
- if(parentDataTagFound) {
137
- break;
138
- }
139
- elementLevelFlag = true; // after the initial level set this flag to true.
140
- element = (element.parentNode as Element);
141
- }
142
- }
143
222
 
144
- /**
145
- * Capture Element content along with Data Tag attributes and values
146
- */
147
- private _populateElementContent(element: Element, dataTagPrefix: string, parentDataTagPrefix: string, aiBlobAttributeTag: string) {
148
-
149
- let elementContent: any = {};
150
- if(!element) return elementContent;
151
-
152
- let htmlContent = this._getHtmlIdAndContentName(element);
153
- elementContent = {
154
- id: htmlContent.id || "",
155
- contentName: htmlContent.contentName || ""
156
- };
157
-
158
- if(isValueAssigned(parentDataTagPrefix)) {
159
- this._walkUpDomChainCaptureData(element, elementContent, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag);
160
- }
161
-
162
- // Validate to ensure the minimum required field 'id' or 'contentName' is present.
163
- // The content schema defines id, aN and sN as required fields. However,
164
- // requiring these fields would result in majority of adopter's content from being collected.
165
- // Just throw a warning and continue collection.
166
- if (!elementContent.id && !elementContent.contentName) {
167
- this._traceLogger.throwInternal(
168
- LoggingSeverity.WARNING,
169
- _ExtendedInternalMessageId.InvalidContentBlob, "Invalid content blob. Missing required attributes (id, contentName. " +
170
- " Content information will still be collected!"
171
- )
172
- }
173
-
174
- return elementContent;
175
- }
176
223
 
177
- /**
178
- * Capture Element content along with Data Tag attributes and values
179
- */
180
- private _populateElementContentwithDataTag(element: Element, dataTagPrefix: string, parentDataTagPrefix: string, aiBlobAttributeTag: string) {
181
-
182
- let elementContent: any = {};
183
- if(!element) return elementContent;
184
-
185
-
186
- let htmlContent = this._getHtmlIdAndContentName(element);
187
-
188
- if(isValueAssigned(parentDataTagPrefix)) {
189
- this._walkUpDomChainCaptureData(element, elementContent, dataTagPrefix, parentDataTagPrefix, aiBlobAttributeTag);
190
- } else {
191
- this._captureElementContentWithDataTag(element, elementContent, dataTagPrefix);
192
- }
193
-
194
-
195
- if (this._config.dataTags.useDefaultContentNameOrId) {
196
- if(!isValueAssigned(elementContent.id)) {
197
- elementContent.id = htmlContent.id || "";
224
+ /**
225
+ * Retrieve a specified metadata tag value from the DOM.
226
+ * @param captureAllMetaDataContent - Flag to capture all metadata content
227
+ * @param prefix - Prefix to search the metatags with.
228
+ * @param removePrefix - Specifies if the prefix must be excluded from key names in the returned collection.
229
+ * @returns Metadata collection/property bag
230
+ */
231
+ function _getMetaDataFromDOM(captureAllMetaDataContent:boolean, prefix: string, removePrefix: boolean): { [name: string]: string } {
232
+ var metaElements: any;
233
+ var metaData = {};
234
+ if (hasDocument) {
235
+ metaElements = document.querySelectorAll("meta");
236
+ for (var i = 0; i < metaElements.length; i++) {
237
+ var meta = metaElements[i];
238
+ if (meta.name) {
239
+ if(captureAllMetaDataContent || meta.name.indexOf(prefix) === 0) {
240
+ const name = removePrefix ? meta.name.replace(prefix, "") : meta.name;
241
+ metaData[name] = meta.content;
242
+ }
243
+ }
244
+ }
245
+ }
246
+
247
+ return metaData;
198
248
  }
199
- elementContent.contentName = htmlContent.contentName || "";
200
- }
201
-
202
- // Validate to ensure the minimum required field 'id' or 'contentName' is present.
203
- // The content schema defines id, aN and sN as required fields. However,
204
- // requiring these fields would result in majority of adopter's content from being collected.
205
- // Just throw a warning and continue collection.
206
- if (!elementContent.id && !elementContent.contentName) {
207
- this._traceLogger.throwInternal(
208
- LoggingSeverity.WARNING,
209
- _ExtendedInternalMessageId.InvalidContentBlob, "Invalid content blob. Missing required attributes (id, contentName. " +
210
- " Content information will still be collected!"
211
- )
212
- }
213
-
214
- return elementContent;
215
- }
216
249
 
250
+ /**
251
+ * Gets the default content name.
252
+ * @param element - An html element
253
+ * @param useDefaultContentNameOrId -Flag indicating if an element is market PII.
254
+ * @returns Content name
255
+ */
256
+ function _getDefaultContentName(element: any, useDefaultContentName: boolean) {
257
+ if (useDefaultContentName === false || !element.tagName) {
258
+ return "";
259
+ }
217
260
 
218
- /**
219
- * Retrieve a specified metadata tag value from the DOM.
220
- * @param captureAllMetaDataContent - Flag to capture all metadata content
221
- * @param prefix - Prefix to search the metatags with.
222
- * @param removePrefix - Specifies if the prefix must be excluded from key names in the returned collection.
223
- * @returns Metadata collection/property bag
224
- */
225
- private _getMetaDataFromDOM(captureAllMetaDataContent:boolean, prefix: string, removePrefix: boolean): { [name: string]: string } {
226
- var metaElements: any;
227
- var metaData = {};
228
- if (hasDocument) {
229
- metaElements = document.querySelectorAll("meta");
230
- for (var i = 0; i < metaElements.length; i++) {
231
- var meta = metaElements[i];
232
- if (meta.name) {
233
- if(captureAllMetaDataContent || meta.name.indexOf(prefix) === 0) {
234
- const name = removePrefix ? meta.name.replace(prefix, "") : meta.name;
235
- metaData[name] = meta.content;
261
+ var doc = getDocument() || ({} as Document);
262
+ var contentName;
263
+ switch (element.tagName) {
264
+ case "A":
265
+ contentName = doc.all ? element.innerText || element.innerHTML : element.text || element.innerHTML;
266
+ break;
267
+ case "IMG":
268
+ case "AREA":
269
+ contentName = element.alt;
270
+ break;
271
+ default:
272
+ contentName = element.value || element.name || element.alt || element.innerText || element.id;
273
+ }
274
+
275
+ return contentName.substring(0, MAX_CONTENTNAME_LENGTH);
276
+ }
277
+
278
+ /**
279
+ * Check if the user wants to track the element, which means if the element has any tags with data-* or customDataPrefix
280
+ * @param element - An html element
281
+ * @returns true if any data-* exist, otherwise return false
282
+ */
283
+ function _isTracked(element: Element, dataTag: string, aiBlobAttributeTag: string): boolean {
284
+ const attrs = element.attributes;
285
+ let dataTagFound = false;
286
+ for (let i = 0; i < attrs.length; i++) {
287
+ const attributeName = attrs[i].name;
288
+ if(attributeName === aiBlobAttributeTag) {
289
+ // ignore if the attribute name is equal to aiBlobAttributeTag
290
+ return false;
291
+ } else if (attributeName.indexOf(dataTag) === 0) {
292
+ dataTagFound = true;
236
293
  }
237
294
  }
295
+ return dataTagFound;
238
296
  }
239
- }
240
297
 
241
- return metaData;
242
- }
298
+ function _getHtmlIdAndContentName(element:Element) {
299
+ let dataTags = (_self._config || {}).dataTags;
300
+ let callback = (_self._config || {}).callback;
301
+ let htmlContent: any = {};
302
+ if(!element) {
303
+ return htmlContent;
304
+ }
243
305
 
244
- /**
245
- * Gets the default content name.
246
- * @param element - An html element
247
- * @param useDefaultContentNameOrId -Flag indicating if an element is market PII.
248
- * @returns Content name
249
- */
250
- private _getDefaultContentName(element: any, useDefaultContentName: boolean) {
251
- if (useDefaultContentName === false || !element.tagName) {
252
- return "";
253
- }
254
-
255
- var doc = getDocument() || ({} as Document);
256
- var contentName;
257
- switch (element.tagName) {
258
- case "A":
259
- contentName = doc.all ? element.innerText || element.innerHTML : element.text || element.innerHTML;
260
- break;
261
- case "IMG":
262
- case "AREA":
263
- contentName = element.alt;
264
- break;
265
- default:
266
- contentName = element.value || element.name || element.alt || element.innerText || element.id;
267
- }
268
-
269
- return contentName.substring(0, MAX_CONTENTNAME_LENGTH);
270
- }
306
+ if (dataTags.useDefaultContentNameOrId) {
307
+ const customizedContentName = callback.contentName ? callback.contentName(element, dataTags.useDefaultContentNameOrId) : "";
308
+ const defaultContentName = _getDefaultContentName(element, dataTags.useDefaultContentNameOrId);
271
309
 
272
- /**
273
- * Check if the user wants to track the element, which means if the element has any tags with data-* or customDataPrefix
274
- * @param element - An html element
275
- * @returns true if any data-* exist, otherwise return false
276
- */
277
- private _isTracked(element: Element, dataTag: string, aiBlobAttributeTag: string): boolean {
278
- const attrs = element.attributes;
279
- let dataTagFound = false;
280
- for (let i = 0; i < attrs.length; i++) {
281
- const attributeName = attrs[i].name;
282
- if(attributeName === aiBlobAttributeTag) {
283
- // ignore if the attribute name is equal to aiBlobAttributeTag
284
- return false;
285
- } else if (attributeName.indexOf(dataTag) === 0) {
286
- dataTagFound = true;
287
- }
288
- }
289
- return dataTagFound;
290
- }
310
+ htmlContent = {
311
+ id: element.id,
312
+ contentName: customizedContentName || defaultContentName || element.getAttribute("alt")
313
+ };
314
+ }
291
315
 
292
- private _getHtmlIdAndContentName(element:Element) {
293
- let htmlContent: any = {};
294
- if(!element) return htmlContent;
316
+ return htmlContent;
317
+ }
295
318
 
296
- if (this._config.dataTags.useDefaultContentNameOrId) {
297
- const customizedContentName = this._config.callback.contentName ? this._config.callback.contentName(element, this._config.dataTags.useDefaultContentNameOrId) : "";
298
- const defaultContentName = this._getDefaultContentName(element, this._config.dataTags.useDefaultContentNameOrId);
319
+ /**
320
+ * Computes the parentId of a given element.
321
+ * @param element - An html element
322
+ * @returns An object containing the closest parentId , can be empty if nothing was found
323
+ */
324
+ function _getParentDetails(element: Element, elementContent: any, dataTagPrefix: string, aiBlobAttributeTag: string): IContent {
325
+ const parentId = elementContent["parentid"];
326
+ const parentName = elementContent["parentname"];
327
+ let parentInfo = {};
328
+
329
+ if (parentId || parentName || !element) {
330
+ return parentInfo;
331
+ }
299
332
 
300
- htmlContent = {
301
- id: element.id,
302
- contentName: customizedContentName || defaultContentName || element.getAttribute("alt")
303
- };
304
- }
333
+ return _populateParentInfo(element, dataTagPrefix, aiBlobAttributeTag);
334
+ }
335
+ /**
336
+ * Check if parent info already set up, if so take and put into content, if not walk up the DOM to find correct info
337
+ * @param element - An html element that the user wants to track
338
+ * @returns An object containing the parent info, can be empty if nothing was found
339
+ */
340
+ function _populateParentInfo(element: Element, dataTagPrefix: string, aiBlobAttributeTag: string): IContent {
341
+ let parentInfo: IContent = {};
342
+ let parentId;
343
+
344
+ // if the user does not set up parent info, walk to the DOM, find the closest parent element (with tags) and populate the info
345
+ const closestParentElement = walkUpDomChainWithElementValidation(element.parentElement, _isTracked, dataTagPrefix);
346
+ if (closestParentElement) {
347
+ const dataAttr = closestParentElement.getAttribute(aiBlobAttributeTag) || element[aiBlobAttributeTag];
348
+ if (dataAttr) {
349
+ try {
350
+ var telemetryObject = JSON.parse(dataAttr);
351
+ } catch (e) {
352
+ _traceLogger.throwInternal(
353
+ LoggingSeverity.CRITICAL,
354
+ _ExtendedInternalMessageId.CannotParseAiBlobValue, "Can not parse " + dataAttr
355
+ );
356
+ }
357
+ if (telemetryObject) {
358
+ parentId = telemetryObject.id;
359
+ }
360
+ } else {
361
+ parentId = closestParentElement.getAttribute(dataTagPrefix+"id");
362
+ }
363
+ }
364
+ if (parentId) {
365
+ parentInfo["parentid"] = parentId;
366
+ } else {
367
+ let htmlContent= _getHtmlIdAndContentName(element.parentElement);
368
+ parentInfo["parentid"] = htmlContent.id;
369
+ parentInfo["parentname"] = htmlContent.contentName;
370
+ }
305
371
 
306
- return htmlContent;
372
+ return parentInfo;
373
+ }
374
+ });
307
375
  }
308
376
 
309
377
  /**
310
- * Computes the parentId of a given element.
311
- * @param element - An html element
312
- * @returns An object containing the closest parentId , can be empty if nothing was found
313
- */
314
- private _getParentDetails(element: Element, elementContent: any, dataTagPrefix: string, aiBlobAttributeTag: string): IContent {
315
- const parentId = elementContent["parentid"];
316
- const parentName = elementContent["parentname"];
317
- let parentInfo = {};
318
-
319
- if (parentId || parentName || !element) {
320
- return parentInfo;
321
- }
322
-
323
- return this._populateParentInfo(element, dataTagPrefix, aiBlobAttributeTag);
378
+ * Collect metatags from DOM.
379
+ * Collect data from meta tags.
380
+ * @returns {object} - Metatags collection/property bag
381
+ */
382
+ public getMetadata(): { [name: string]: string } {
383
+ // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
384
+ return null;
324
385
  }
386
+
325
387
  /**
326
- * Check if parent info already set up, if so take and put into content, if not walk up the DOM to find correct info
327
- * @param element - An html element that the user wants to track
328
- * @returns An object containing the parent info, can be empty if nothing was found
329
- */
330
- private _populateParentInfo(element: Element, dataTagPrefix: string, aiBlobAttributeTag: string): IContent {
331
- let parentInfo: IContent = {};
332
- let parentId;
333
-
334
- // if the user does not set up parent info, walk to the DOM, find the closest parent element (with tags) and populate the info
335
- const closestParentElement = walkUpDomChainWithElementValidation(element.parentElement, this._isTracked, dataTagPrefix);
336
- if (closestParentElement) {
337
- const dataAttr = closestParentElement.getAttribute(aiBlobAttributeTag) || element[aiBlobAttributeTag];
338
- if (dataAttr) {
339
- try {
340
- var telemetryObject = JSON.parse(dataAttr);
341
- } catch (e) {
342
- this._traceLogger.throwInternal(
343
- LoggingSeverity.CRITICAL,
344
- _ExtendedInternalMessageId.CannotParseAiBlobValue, "Can not parse " + dataAttr
345
- );
346
- }
347
- if (telemetryObject) {
348
- parentId = telemetryObject.id;
349
- }
350
- } else {
351
- parentId = closestParentElement.getAttribute(dataTagPrefix+"id");
352
- }
353
- }
354
- if (parentId) {
355
- parentInfo["parentid"] = parentId;
356
- }
357
- else {
358
- let htmlContent= this._getHtmlIdAndContentName(element.parentElement);
359
- parentInfo["parentid"] = htmlContent.id;
360
- parentInfo["parentname"] = htmlContent.contentName;
361
- }
362
- return parentInfo;
388
+ * Collect data-* attributes for the given element.
389
+ * All attributes with data-* prefix or user provided customDataPrefix are collected.'data-*' prefix is removed from the key name.
390
+ * @param element - The element from which attributes need to be collected.
391
+ * @returns String representation of the Json array of element attributes
392
+ */
393
+ public getElementContent(element: Element): IContent {
394
+ // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
395
+ return null;
363
396
  }
364
397
  }