PageSourceSearch

https://www.jbhifi.business/Scripts/Tracker/cv.css.tracker.Implementation.GA4.js?v=2026-07-14A91987520

js jbhifi.business collected 2026-10-02 14:33:31 UTC 14,890 bytes, 321 lines download raw bytes

1(function ($, undefined) {
2    $.cv = $.cv || {};
3    $.cv.css = $.cv.css || {};
4    $.cv.css.tracker = $.cv.css.tracker || {};
5    $.cv.css.tracker.implementation = $.cv.css.tracker.implementation || {};
6    /**
7     * Google Analytis 4 Issues with dataLayer.push();
8     *
9     * WARNING: this should be use for ALL push()es to the data layer for
10     * Google Analytics 4.
11     *
12     * For some reason we can't just dataLayer.push() an object or an array
13     * of the correct structure, the only way that the gtag stuff works
14     * is if we have a function we call and we push the 'arguments' value
15     * onto the dataLayer. Thus we need to implement the push abstraction
16     * here to permit pushing 'arguments' onto the data layer for GA4.
17     */
18    $.cv.css.tracker.implementation.push = function () {
19        var _ = [];
20        for (var _i = 0; _i < arguments.length; _i++) {
21            _[_i] = arguments[_i];
22        }
23        var dataLayer = $.cv.css.tracker.getDataLayer();
24        dataLayer.push(arguments);
25    };
26    function rename(obj, oldName, newName) {
27        var oldValue = obj[oldName];
28        if (oldValue != null) {
29            obj[newName] = obj[oldName];
30            delete obj[oldName];
31        }
32    }
33    function splitCategory(category) {
34        category = category || '';
35        return _.filter(category.split(/\//), function (item) { return item != null && item.length > 0; });
36    }
37    $.cv.css.tracker.implementation.splitCategory = splitCategory;
38    function mapProduct(product) {
39        // Create a copy so we don't modify the original object.
40        var mappedProduct = JSON.parse(JSON.stringify(product));
41        rename(mappedProduct, 'name', 'item_name');
42        rename(mappedProduct, 'id', 'item_id');
43        rename(mappedProduct, 'brand', 'item_brand');
44        rename(mappedProduct, 'variant', 'item_variant');
45        rename(mappedProduct, 'position', 'index');
46        var categories = splitCategory(mappedProduct.category);
47        mappedProduct.item_category = categories[0];
48        mappedProduct.item_category2 = categories[1];
49        mappedProduct.item_category3 = categories[2];
50        mappedProduct.item_category4 = categories[3];
51        mappedProduct.item_category5 = categories[4];
52        mappedProduct.price = parseFloat(mappedProduct.price);
53        mappedProduct.index = parseInt(mappedProduct.index);
54        delete mappedProduct.category;
55        return mappedProduct;
56    }
57    $.cv.css.tracker.implementation.mapProduct = mapProduct;
58    function getReturnedValue(pushData) {
59        var _a;
60        // WARNING:
61        // When AnalyticsVersion does not contain Universal Analytics (selected version is GA4).
62        // Associated implementations modify and trigger the gtag() style call and return undefined on purpose.
63        // The call site will not do anything with the undefined or event callback only return value;
64        if ($.cv.css.tracker.options.AnalyticsVersion !== SiteTrackerAnalyticsVersion.GA4) {
65            return pushData;
66        }
67        // It uses for finialise the event callback function if exists, it doesn't actually push to data layer
68        if (pushData.hasOwnProperty(TrackerEventCallbackName)) {
69            return _a = {}, _a[TrackerEventCallbackName] = pushData[TrackerEventCallbackName], _a;
70        }
71        return undefined;
72    }
73    function getLineItemsData() {
74        var lines = _.filter($.cv.css.localGetCurrentOrderLines(), function (p) {
75            return $.cv.util.hasValue(p, "Product[0].ProductCode");
76        });
77        var itemsValue = 0;
78        var lineItems = _.map(lines, function (line) {
79            itemsValue += line.OrderLineAmount;
80            return mapProduct({
81                name: line.Description,
82                id: line.StockCode,
83                brand: line.Product[0].BrandText,
84                category: line.Product[0].CategoryHierarchy,
85                quantity: line.OrderedQty,
86                price: line.ItemPrice,
87                position: line.LineSeq
88            });
89        });
90        return { itemsValue: parseFloat(itemsValue.toFixed($.cv.css.tracker.options.DecimalPlaces)), lineItems: lineItems };
91    }
92    $.cv.css.tracker.implementation.productImpressions = function (impressions) {
93        var returnedValue = getReturnedValue(impressions);
94        var isProduct = $.cv.util.hasValue(impressions, 'ecommerce.detail.products');
95        var items = impressions.ecommerce.impressions || impressions.ecommerce.detail.products;
96        var payload = {
97            value: 0,
98            currency: impressions.ecommerce.currencyCode,
99            items: []
100        };
101        var listName = impressions.ecommerce.impressions != undefined && impressions.ecommerce.impressions.length > 0
102            ? impressions.ecommerce.impressions[0].list
103            : impressions.ecommerce.detail.actionField.list;
104        var eventName = isProduct ? 'view_item' : 'view_item_list';
105        var itemsValue = 0;
106        var mappedItems = [];
107        // NOTE: we need to map some fields that have had field name
108        // renames from prior UA dimensions. All other fields
109        // we be retained as they were as they are valid in GA4.
110        for (var i = 0; i < items.length; i++) {
111            var product = items[i];
112            var mappedProduct = mapProduct(product);
113            if (isProduct) {
114                mappedProduct.index = 0;
115                mappedProduct.item_list_name = listName;
116                itemsValue += mappedProduct.price;
117            }
118            mappedItems.push(mappedProduct);
119        }
120        payload.items = mappedItems;
121        payload.value = itemsValue;
122        // view_item_list does not have the 'value' field
123        if (!isProduct) {
124            delete payload.value;
125            // TODO: danielv this is to handle the campaign list type but we have't decided yet how it would work
126            // Will need to revisit once we have a better understanding of how the campaign list type will work
127            //if (listName.startsWith($.cv.css.tracker.options.CampaignListPrefix)) {
128            //    payload.promotion_id = $.cv.css.tracker.options.CampaignCode;
129            //    payload.promotion_name = listName;
130            //    eventName = 'view_promotion';
131            //} else {
132            //    payload.item_list_name = listName;
133            //}
134            payload.item_list_name = listName;
135        }
136        // Trigger the event
137        $.cv.css.tracker.implementation.push('event', eventName, payload);
138        return returnedValue;
139    };
140    $.cv.css.tracker.implementation.productClick = function (pushData) {
141        var returnedValue = getReturnedValue(pushData);
142        var listName = pushData.ecommerce.click.actionField.list;
143        var items = pushData.ecommerce.click.products;
144        var payload = {
145            value: 0,
146            currency: pushData.ecommerce.currencyCode,
147            item_list_name: listName,
148            items: []
149        };
150        var itemsValue = 0;
151        for (var i = 0; i < items.length; i++) {
152            var product = items[i];
153            var mappedProduct = mapProduct(product);
154            itemsValue += mappedProduct.price;
155            payload.items.push(mappedProduct);
156        }
157        payload.value = itemsValue;
158        // Trigger the event
159        $.cv.css.tracker.implementation.push('event', 'select_item', payload);
160        return returnedValue;
161    };
162    $.cv.css.tracker.implementation.bannerClick = function (pushData) {
163        return processBannerData(pushData, 'select_banner');
164    };
165    $.cv.css.tracker.implementation.bannerView = function (pushData) {
166        return processBannerData(pushData, 'view_banner');
167    };
168    function processBannerData(pushData, eventName) {
169        var returnedValue = getReturnedValue(pushData);
170        var payload = {
171            banner_description: pushData.Description
172        };
173        $.cv.css.tracker.implementation.push('event', eventName, payload);
174        return returnedValue;
175    }
176    $.cv.css.tracker.implementation.addToCart = function (products, listName) {
177        var returnedValue = getReturnedValue(products);
178        var payload = {
179            value: 0,
180            currency: $.cv.css.tracker.options.CurrencyCode,
181            items: []
182        };
183        var itemsValue = 0;
184        for (var i = 0; i < products.length; i++) {
185            var product = products[i];
186            var mappedProduct = mapProduct(product);
187            if (!$.cv.css.tracker.options.PageFlags.IsProductDisplayCampaignPage) {
188                mappedProduct.item_list_name = listName;
189            }
190            if (!$.cv.css.tracker.options.HidePricing) {
191                itemsValue += mappedProduct.quantity * mappedProduct.price;
192            }
193            payload.items.push(mappedProduct);
194        }
195        // This is to avoid the case that itemsValue is calculated with multiple decimal places
196        payload.value = parseFloat(itemsValue.toFixed($.cv.css.tracker.options.DecimalPlaces));
197        // TODO: danielv this is to handle the campaign list type but we have't decided yet how it would work
198        // Will need to revisit once we have a better understanding of how the campaign list type will work
199        //if (listName.startsWith($.cv.css.tracker.options.CampaignListPrefix)) {
200        //    payload.promotion_id = $.cv.css.tracker.options.CampaignCode;
201        //    payload.promotion_name = listName;
202        //    $.cv.css.tracker.implementation.push('event', 'select_promotion', payload);
203        //} else {
204        //    $.cv.css.tracker.implementation.push('event', 'add_to_cart', payload);
205        //}
206        $.cv.css.tracker.implementation.push('event', 'add_to_cart', payload);
207        return returnedValue;
208    };
209    $.cv.css.tracker.implementation.removeFromCart = function (products) {
210        var returnedValue = getReturnedValue(products);
211        var payload = {
212            value: 0,
213            currency: $.cv.css.tracker.options.CurrencyCode,
214            items: []
215        };
216        var listName = $.cv.css.tracker.options.ListTypes.CartLines;
217        var hidePricing = $.cv.css.tracker.options.HidePricing;
218        for (var i = 0; i < products.length; i++) {
219            var product = products[i];
220            var mappedProduct = mapProduct(product);
221            mappedProduct.item_list_name = listName;
222            if (!hidePricing) {
223                payload.value += mappedProduct.price * mappedProduct.quantity;
224            }
225            payload.items.push(mappedProduct);
226        }
227        // Trigger the event
228        $.cv.css.tracker.implementation.push('event', 'remove_from_cart', payload);
229        return returnedValue;
230    };
231    $.cv.css.tracker.implementation.checkout = function (pushData) {
232        var returnedValue = getReturnedValue(pushData);
233        var lines = getLineItemsData();
234        var step = pushData.ecommerce.checkout.actionField.step;
235        var checkoutData = {
236            value: lines.itemsValue,
237            currency: $.cv.css.tracker.options.CurrencyCode,
238            step: step,
239            items: lines.lineItems,
240        };
241        if (step == 1) {
242            $.cv.css.tracker.implementation.push("event", "view_cart", checkoutData);
243        }
244        if (step == 2) {
245            $.cv.css.tracker.implementation.push("event", "begin_checkout", checkoutData);
246        }
247        return returnedValue;
248    };
249    $.cv.css.tracker.implementation.checkoutOption = function (pushData) {
250        var returnedValue = getReturnedValue(pushData);
251        var lines = getLineItemsData();
252        var step = pushData.ecommerce.checkout_option.actionField.step;
253        if (step == 3) {
254            $.cv.css.tracker.implementation.push("event", "add_shipping_info", {
255                value: lines.itemsValue,
256                currency: $.cv.css.tracker.options.CurrencyCode,
257                shipping_tier: pushData.ecommerce.checkout_option.actionField.option,
258                step: step,
259                items: lines.lineItems,
260            });
261        }
262        if (step == 4) {
263            $.cv.css.tracker.implementation.push("event", "add_payment_info", {
264                value: lines.itemsValue,
265                currency: $.cv.css.tracker.options.CurrencyCode,
266                payment_type: pushData.ecommerce.checkout_option.actionField.option,
267                step: step,
268                items: lines.lineItems,
269            });
270        }
271        return returnedValue;
272    };
273    $.cv.css.tracker.implementation.transactionProducts = function (pushData) {
274        var returnedValue = getReturnedValue(pushData);
275        var products = pushData.ecommerce.purchase.products;
276        var itemsValue = 0;
277        var payload = {
278            transaction_id: pushData.ecommerce.purchase.actionField.id,
279            value: 0,
280            tax: pushData.ecommerce.purchase.actionField.tax,
281            shipping: pushData.ecommerce.purchase.actionField.shipping,
282            currency: pushData.ecommerce.currencyCode,
283            items: []
284        };
285        for (var i = 0; i < products.length; i++) {
286            var product = products[i];
287            var mappedProduct = mapProduct(product);
288            itemsValue += mappedProduct.price * mappedProduct.quantity;
289            payload.items.push(mappedProduct);
290        }
291        payload.value = parseFloat(itemsValue.toFixed($.cv.css.tracker.options.DecimalPlaces));
292        // Trigger the event
293        $.cv.css.tracker.implementation.push('event', 'purchase', payload);
294        return returnedValue;
295    };
296    $.cv.css.tracker.implementation.productSearch = function (pushData) {
297        var returnedValue = getReturnedValue(pushData);
298        var payload = {
299            search_term: pushData.searchTerm,
300            search_type: pushData.searchType,
301        };
302        // Trigger the event
303        $.cv.css.tracker.implementation.push('event', 'search', payload);
304        return returnedValue;
305    };
306    $.cv.css.tracker.implementation.addToWishList = function (pushData, listName) {
307        var returnedValue = getReturnedValue(pushData);
308        var payload = {
309            value: 0,
310            currency: $.cv.css.tracker.options.CurrencyCode,
311            items: []
312        };
313        var mappedProduct = mapProduct(pushData);
314        mappedProduct.item_list_name = listName;
315        payload.items.push(mappedProduct);
316        payload.value = mappedProduct.price;
317        // Trigger the event
318        $.cv.css.tracker.implementation.push('event', 'add_to_wishlist', payload);
319        return returnedValue;
320    };
321})(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.