1
- /*
2
- * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang
3
- * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * 1. Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * 2. Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * 3. Neither the name of the copyright holder nor the names of its
16
- * contributors may be used to endorse or promote products derived from
17
- * this software without specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- */
30
-
31
1
import {
32
2
getCssClasses ,
33
3
addEventListener ,
@@ -90,12 +60,18 @@ export interface ElementData extends Record<string, string | null | undefined> {
90
60
type ?: string ;
91
61
}
92
62
93
- export type transformFn = ( x : string | null , elt : ElementData | TrackedHTMLElement ) => string | null ;
63
+ export type transformFn = (
64
+ elementValue : string | null ,
65
+ elementInfo : ElementData | TrackedHTMLElement ,
66
+ elt : TrackedHTMLElement
67
+ ) => string | null ;
94
68
95
69
export const innerElementTags : Array < keyof TrackedHTMLElementTagNameMap > = [ 'textarea' , 'input' , 'select' ] ;
96
70
97
71
type TrackedHTMLElementWithMarker = TrackedHTMLElement & Record < string , boolean > ;
98
72
73
+ type ElementDataWrapper = { elementData : ElementData ; originalElement : TrackedHTMLElement } ;
74
+
99
75
const defaultTransformFn : transformFn = ( x ) => x ;
100
76
101
77
interface FormConfiguration {
@@ -242,7 +218,7 @@ function getParentFormIdentifier(elt: Node | null) {
242
218
* Returns a list of the input, textarea, and select elements inside a form along with their values
243
219
*/
244
220
function getInnerFormElements ( trackingMarker : string , elt : HTMLFormElement ) {
245
- var innerElements : Array < ElementData > = [ ] ;
221
+ var innerElements : Array < ElementDataWrapper > = [ ] ;
246
222
Array . prototype . slice . call ( innerElementTags ) . forEach ( ( tagname : 'textarea' | 'input' | 'select' ) => {
247
223
let trackedChildren = Array . prototype . slice . call ( elt . getElementsByTagName ( tagname ) ) . filter ( function ( child ) {
248
224
return child . hasOwnProperty ( trackingMarker ) ;
@@ -252,17 +228,20 @@ function getInnerFormElements(trackingMarker: string, elt: HTMLFormElement) {
252
228
if ( child . type === 'submit' ) {
253
229
return ;
254
230
}
255
- var elementJson : ElementData = {
256
- name : getElementIdentifier ( child ) ,
257
- value : child . value ,
258
- nodeName : child . nodeName ,
231
+ var elementJson : ElementDataWrapper = {
232
+ elementData : {
233
+ name : getElementIdentifier ( child ) ,
234
+ value : child . value ,
235
+ nodeName : child . nodeName ,
236
+ } ,
237
+ originalElement : child ,
259
238
} ;
260
239
if ( child . type && child . nodeName . toUpperCase ( ) === 'INPUT' ) {
261
- elementJson . type = child . type ;
240
+ elementJson . elementData . type = child . type ;
262
241
}
263
242
264
243
if ( ( child . type === 'checkbox' || child . type === 'radio' ) && ! ( child as HTMLInputElement ) . checked ) {
265
- elementJson . value = null ;
244
+ elementJson . elementData . value = null ;
266
245
}
267
246
innerElements . push ( elementJson ) ;
268
247
} ) ;
@@ -285,7 +264,9 @@ function getFormChangeListener(
285
264
if ( elt ) {
286
265
var type = elt . nodeName && elt . nodeName . toUpperCase ( ) === 'INPUT' ? elt . type : null ;
287
266
var value =
288
- elt . type === 'checkbox' && ! ( elt as HTMLInputElement ) . checked ? null : config . fieldTransform ( elt . value , elt ) ;
267
+ elt . type === 'checkbox' && ! ( elt as HTMLInputElement ) . checked
268
+ ? null
269
+ : config . fieldTransform ( elt . value , elt , elt ) ;
289
270
if ( event_type === 'change_form' || ( type !== 'checkbox' && type !== 'radio' ) ) {
290
271
tracker . core . track (
291
272
buildFormFocusOrChange ( {
@@ -317,15 +298,17 @@ function getFormSubmissionListener(
317
298
var elt = e . target as HTMLFormElement ;
318
299
var innerElements = getInnerFormElements ( trackingMarker , elt ) ;
319
300
innerElements . forEach ( function ( innerElement ) {
320
- innerElement . value = config . fieldTransform ( innerElement . value , innerElement ) ?? innerElement . value ;
301
+ var eltData = innerElement . elementData ;
302
+ eltData . value = config . fieldTransform ( eltData . value , eltData , innerElement . originalElement ) ?? eltData . value ;
321
303
} ) ;
304
+ var elementsData = innerElements . map ( ( elt ) => elt . elementData ) ;
322
305
tracker . core . track (
323
306
buildFormSubmission ( {
324
307
formId : getElementIdentifier ( elt ) ?? '' ,
325
308
formClasses : getCssClasses ( elt ) ,
326
- elements : innerElements ,
309
+ elements : elementsData ,
327
310
} ) ,
328
- resolveDynamicContext ( context , elt , innerElements )
311
+ resolveDynamicContext ( context , elt , elementsData )
329
312
) ;
330
313
} ;
331
314
}
0 commit comments