1(function($) { 2 var eventIds = { 3 fieldCompleted: "2ca692cb-bdb2-4c9d-a3b5-917b3656c46a", 4 fieldError: "ea27aca5-432f-424a-b000-26ba5f8ae60a" 5 }; 6 7 function endsWith(str, suffix) { 8 return str.toLowerCase().indexOf(suffix.toLowerCase(), str.length - suffix.length) !== -1; 9 } 10 11 function getOwner(form, elementId) { 12 var targetId = elementId.slice(0, -(elementId.length - elementId.lastIndexOf(".") - 1)) + "Value"; 13 return form.find("input[name=\"" + targetId + "\"]")[0]; 14 } 15 16 function getSessionId(form) { 17 var formId = form[0].id; 18 var targetId = formId.slice(0, -(formId.length - formId.lastIndexOf("_") - 1)) + "FormSessionId"; 19 var element = form.find("input[type='hidden'][id=\"" + targetId + "\"]"); 20 return element.val(); 21 } 22 23 function getElementName(element) { 24 var fieldName = element.name; 25 if (!endsWith(fieldName, "value")) { 26 return getFieldGuid(fieldName) + "Value"; 27 } 28 29 return fieldName; 30 } 31 32 function getElementValue(element) { 33 var value; 34 if (element.type === "checkbox" || element.type === "radio") { 35 var form = $(element).closest("form"); 36 var checkboxList = form.find("input[name='" + element.name + "']"); 37 if (checkboxList.length > 1) { 38 value = []; 39 checkboxList = checkboxList.not(":not(:checked)"); 40 $.each(checkboxList, function () { 41 value.push($(this).val()); 42 }); 43 } else { 44 value = element.checked ? "1" : "0"; 45 } 46 } else { 47 value = $(element).val(); 48 } 49 50 if (value && Object.prototype.toString.call(value) === "[object Array]") { 51 value = value.join(","); 52 } 53 54 return value; 55 } 56 57 function getFieldGuid(fieldName) { 58 var searchPattern = "fields["; 59 var index = fieldName.toLowerCase().indexOf(searchPattern); 60 return fieldName.substring(0, index + searchPattern.length + 38); 61 } 62 63 function getFieldName(element) { 64 return $(element).attr("data-sc-field-name"); 65 } 66 67 $.fxbFormTracker = function (el, options) { 68 this.el = el; 69 this.$el = $(el); 70 this.options = $.extend({}, $.fxbFormTracker.defaultOptions, options); 71 this.init(); 72 }, 73 74 $.fxbFormTracker.parse = function (formId) { 75 var $form = $(formId); 76 $form.track_fxbForms(); 77 78 var isSessionExpired = parseInt($("[name$='.IsSessionExpired']").val()); 79 if (isSessionExpired) { 80 alert($.fxbFormTracker.texts.expiredWebSession); 81 } 82 }, 83 84 $.extend($.fxbFormTracker, 85 { 86 defaultOptions: { 87 formId: null, 88 sessionId: null, 89 fieldId: null, 90 fieldValue: null, 91 duration: null 92 }, 93 94 prototype: { 95 init: function () { 96 this.options.duration = 0; 97 this.options.formId = this.$el.attr("data-sc-fxb"); 98 }, 99 100 startTracking: function () { 101 this.options.sessionId = getSessionId(this.$el); 102 103 var self = this; 104 var inputs = this.$el.find("input:not([type='submit']), select, textarea"); 105 var trackedInputs = inputs.filter("[data-sc-tracking='True'], [data-sc-tracking='true']"); 106 var trackedNonDateInputs = trackedInputs.not("[type='date']"); 107 108 if (trackedInputs.length) { 109 inputs.not(trackedInputs).on("focus", 110 function () { 111 self.onFocusField(this); 112 }); 113 114 trackedInputs.on("focus", 115 function () { 116 self.onFocusField(this, true); 117 }).on("blur", 118 function () { 119 self.onBlurField(this); 120 }); 121 122 trackedNonDateInputs.on("change", 123 function () { 124 self.onBlurField(this); 125 }); 126 } 127 }, 128 129 onFocusField: function (element, hasTracking) { 130 if (!hasTracking) { 131 this.options.fieldId = ""; 132 return; 133 } 134 135 var fieldId = getElementName(element); 136 137 if (this.options.fieldId !== fieldId) { 138 this.options.fieldId = fieldId; 139 this.options.duration = $.now(); 140 this.options.fieldValue = getElementValue(element); 141 } 142 }, 143 144 onBlurField: function (element) { 145 var fieldId = getElementName(element); 146 var timeStamp = $.now(); 147 148 if (!endsWith(fieldId, "value")) { 149 var owner = getOwner(this.$el, fieldId); 150 if (!owner) { 151 return; 152 } 153 154 element = owner; 155 } 156 157 var duration = this.options.duration ? Math.round((timeStamp - this.options.duration) / 1000) : 0; 158 var value = getElementValue(element); 159 var fieldChanged = this.options.fieldId !== fieldId; 160 if (fieldChanged) { 161 this.options.fieldId = fieldId; 162 this.options.duration = $.now(); 163 duration = 0; 164 } 165 if (fieldChanged || this.options.fieldValue !== value) { 166 this.options.fieldValue = value; 167 168 var fieldName = getFieldName(element); 169 var clientEvent = this.buildEvent(fieldId, fieldName, eventIds.fieldCompleted, duration); 170
171 var validator = this.$el.data("validator"); 172 var validationEvents = []; 173 if (validator && !validator.element(element)) { 174 validationEvents = this.checkClientValidation(element, fieldName, validator, duration); 175 } 176 177 this.trackEvents($.merge([clientEvent], validationEvents)); 178 } 179 }, 180 181 buildEvent: function (fieldId, fieldName, eventId, duration) { 182 var fieldIdHidden = getFieldGuid(fieldId) + "ItemId"; 183 184 fieldId = $("input[name=\"" + fieldIdHidden + "\"]").val(); 185 186 return { 187 'formId': this.options.formId, 188 'sessionId': this.options.sessionId, 189 'eventId': eventId, 190 'fieldId': fieldId, 191 'duration': duration, 192 'fieldName': fieldName 193 }; 194 }, 195 196 checkClientValidation: function (element, fieldName, validator, duration) { 197 var tracker = this; 198 var events = []; 199 200 $.each(validator.errorMap, 201 function (key) { 202 if (key === element.name) { 203 var clientEvent = tracker.buildEvent(key, fieldName, eventIds.fieldError, duration); 204 events.push(clientEvent); 205 } 206 }); 207 208 return events; 209 }, 210 211 trackEvents: function (events) { 212 $.ajax({
213 type: "POST", 214 url: "/fieldtracking/register", 215 data: JSON.stringify(events), 216 contentType: "application/json" 217 }).done(function (data, textStatus, jqXhr) { 218 if ((jqXhr.statusText === "OK" || jqXhr.statusText === "success") && jqXhr.responseText !== "") { 219 alert(jqXhr.responseText); 220 } 221 }); 222 } 223 } 224 }); 225 226 $.fn.track_fxbForms = function (options) { 227 return this.each(function () { 228 var tracker = $.data(this, "fxbForms.tracking"); 229 if (tracker) { 230 tracker.startTracking(); 231 } else { 232 tracker = new $.fxbFormTracker(this, options); 233 $.data(this, "fxbForms.tracking", tracker); 234 tracker.startTracking(); 235 } 236 }); 237 }; 238 239 $("form[data-sc-fxb]").track_fxbForms(); 240})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.