1/** 2 * NOTICE OF LICENSE 3 * 4 * This source file is subject to a commercial license from SAS Comptoir du Code 5 * Use, copy, modification or distribution of this source file without written 6 * license agreement from the SAS Comptoir du Code is strictly forbidden. 7 * In order to obtain a license, please contact us: [email protected] 8 * 9 * @package cdc_googletagmanager 10 * @author Vincent - Comptoir du Code 11 * @copyright Copyright(c) 2015-2025 SAS Comptoir du Code 12 * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 13 * 14 * Project Name : Google Tag Manager Enhanced Ecommerce (UA) Tracking 15 * Created By : Comptoir du Code 16 * Created On : 2016-06-02 17 * Support : https://addons.prestashop.com/contact-community.php?id_product=23806 18 */ 19 20// CDC GTM Datalayer actions 21var cdcGtm = { 22 clearDatalayer : function() { 23 if (typeof dataLayer === 'undefined') { 24 dataLayer = []; 25 } 26 dataLayer.push({ ecommerce: null }); 27 }, 28 29 cloneDatalayer : function(dataLayer) { 30 let cloneDatalayer = JSON.parse(JSON.stringify(dataLayer)); 31 // delete property gtm.uniqueEventId if exist to avoid override event 32 if ('gtm.uniqueEventId' in cloneDatalayer) { 33 delete cloneDatalayer['gtm.uniqueEventId']; 34 } 35 36 return cloneDatalayer; 37 }, 38 39 addToCart : function(product_id, attribute_id, qtity, addedFromProductPage, callerElement) { 40 if(product_id) { 41 cdcGtm.pushProductToDatalayer('cart-add', product_id, attribute_id, qtity); 42 } 43 }, 44 45 removeFromCart : function(product_id, attribute_id, qtity) { 46 if(product_id) { 47 cdcGtm.pushProductToDatalayer('cart-remove', product_id, attribute_id, qtity); 48 } 49 }, 50 51 productClick : function(product_id, attribute_id) { 52 if(product_id) { 53 cdcGtm.pushProductToDatalayer('product-click', product_id, attribute_id); 54 } 55 }, 56 57 displayCategoryAsync : function(product_ids) { 58 if(product_ids) { 59 let params = ''; 60 if (typeof cdcDatalayer !== 'undefined' && cdcDatalayer && cdcDatalayer.ecommerce && cdcDatalayer.ecommerce.items 61 && cdcDatalayer.ecommerce.items.length > 0 && cdcDatalayer.ecommerce.items[0].item_list_id 62 && /^cat_\d+$/.test(cdcDatalayer.ecommerce.items[0].item_list_id)) { 63 64 // Extract the number after 'cat_' 65 const item_list_id = cdcDatalayer.ecommerce.items[0].item_list_id; 66 categoryId = parseInt(item_list_id.split('_')[1], 10); 67 if(categoryId) { 68 params = 'id_category=' + categoryId; 69 } 70 } 71 72 cdcGtm.pushProductListToDatalayer('category-display', product_ids, params); 73 } 74 }, 75 76 pushDalayerFromAjaxResponse : function(cdcgtmreq) { 77 if (cdcgtmreq.readyState == 4) { /* use 4 instead of XMLHttpRequest.DONE for browser compatibility */ 78 if (cdcgtmreq.status == 200) { 79 var datalayerJs = cdcgtmreq.responseText; 80 try { 81 let datalayerJson = JSON.parse(datalayerJs); 82 // debug log - data pushed to datalayer 83 // console.log(JSON.stringify(datalayerJson, undefined, 4)); 84 cdcGtm.clearDatalayer(); 85 dataLayer.push(datalayerJson); 86 } catch(e) { 87 console.log("[CDCGTM] error while parsing json"); 88 } 89 } 90 } 91 }, 92 93 /** 94 * Get product from ajax and push it to datalayer 95 * @param action 96 * @param product_id 97 * @param attribute_id 98 * @param qtity 99 */ 100 pushProductToDatalayer : function(action, product_id, attribute_id, qtity) { 101 102 // convert from NaN to default value 103 attribute_id = attribute_id || 0; 104 qtity = qtity || 1; 105 106 // get product async 107 var cdcgtmreq = new XMLHttpRequest(); 108 cdcgtmreq.onreadystatechange = function () { cdcGtm.pushDalayerFromAjaxResponse(cdcgtmreq); } 109 110 if(typeof cdcGtmApi !== 'undefined' && cdcGtmApi) { 111 cdcgtmreq.open("GET", cdcGtmApi + "?action=" + action + "&id=" + product_id + "&id_attribute=" + attribute_id + "&qtity=" + qtity, true); 112 cdcgtmreq.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 113 cdcgtmreq.send(); 114 } else { 115 console.error("[CDCGTM] cdcGtmApi not defined, cannot send action " + action); 116 } 117 }, 118 119 /** 120 * Get a datalayer from a list of product ids 121 * then push product list to datalayer 122 * @param action 123 * @param product_ids 124 */ 125 pushProductListToDatalayer : function(action, product_ids, params) { 126 127 // get product async 128 var cdcgtmreq = new XMLHttpRequest(); 129 cdcgtmreq.onreadystatechange = function () { cdcGtm.pushDalayerFromAjaxResponse(cdcgtmreq); } 130 131 if(typeof cdcGtmApi !== 'undefined' && cdcGtmApi) { 132 if(params) { 133 params = '&' + params; 134 } else { 135 params = ''; 136 } 137 cdcgtmreq.open("POST", cdcGtmApi + "?action=" + action + params, true); 138 cdcgtmreq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); 139 cdcgtmreq.send("id_products=" + JSON.stringify(product_ids)); 140 } else {
141 console.error("[CDCGTM] cdcGtmApi not defined, cannot send action " + action); 142 } 143 }, 144 145 /** 146 * Use the current datalayer, add data to it 147 * then push it to GTM datalayer 148 * @param data 149 */ 150 /*pushDataToCurrentDatalayer : function(data) { 151 try { 152 dataLayer = dataLayer || []; 153 let baseDatalayer = cdcDatalayer || {} 154 let mergedDatalayer = {...baseDatalayer, ...data} 155 dataLayer.push(mergedDatalayer); 156 } catch(e) { 157 console.log("[CDCGTM][pushDataToCurrentDatalayer] ERROR "); 158 } 159 },*/ 160 161 handleValidateShippingStep : function($submitBtn, event, shippingName, doNotPreventClick) { 162 if(!$submitBtn.hasClass('clicked')) { 163 if(typeof doNotPreventClick === 'undefined' || !doNotPreventClick) { 164 event.preventDefault(); 165 } 166 167 // push infos to datalayer 168 try { 169 dataLayer = dataLayer || []; 170 let cloneDatalayer = cdcGtm.cloneDatalayer(cdcDatalayer); 171 cloneDatalayer.event = 'add_shipping_info'; 172 cloneDatalayer.ecommerce.shipping_tier = shippingName; 173 cdcGtm.clearDatalayer(); 174 dataLayer.push(cloneDatalayer); 175 } catch (e) { 176 console.error(e); 177 } 178 179 // exec button action after waiting to send the datalayer 180 if(typeof doNotPreventClick === 'undefined' || !doNotPreventClick) { 181 setTimeout(function () { 182 $submitBtn.addClass('clicked'); 183 $submitBtn.click(); 184 }, 500); 185 } 186 } 187 }, 188 189 handleValidatePayementStep : function(paymentName) { 190 // push infos to datalayer 191 try { 192 dataLayer = dataLayer || []; 193 let cloneDatalayer = cdcGtm.cloneDatalayer(cdcDatalayer); 194 cloneDatalayer.event = 'add_payment_info'; 195 cloneDatalayer.ecommerce.payment_type = paymentName; 196 cdcGtm.clearDatalayer(); 197 dataLayer.push(cloneDatalayer); 198 } catch (e) { 199 console.error(e); 200 } 201 } 202 203 204} 205 206/* CART : ADD / REMOVE PRODUCT ****************************************************************************************/ 207 208// Prestashop 1.5 || 1.6 209if(typeof(ajaxCart) != 'undefined') { 210 // override ajaxCart.add function 211 var ajaxCartAddFunc = ajaxCart.add; 212 ajaxCart.add = function(idProduct, idCombination, addedFromProductPage, callerElement, quantity, wishlist) { 213 ajaxCartAddFunc(idProduct, idCombination, addedFromProductPage, callerElement, quantity, wishlist); 214 cdcGtm.addToCart(idProduct, idCombination, quantity, addedFromProductPage, callerElement); 215 } 216 217 // override ajax.remove function 218 var ajaxCartRemoveFunc = ajaxCart.remove; 219 ajaxCart.remove = function(idProduct, idCombination, customizationId, idAddressDelivery) { 220 ajaxCartRemoveFunc(idProduct, idCombination, customizationId, idAddressDelivery); 221 cdcGtm.removeFromCart(idProduct, idCombination); 222 } 223} 224 225// Prestashop >= 1.7 226else if(typeof(prestashop) != 'undefined') { 227 $(document).ready(function () { 228 229 // Prestashop ajax cart 230 prestashop.on( 231 'updateCart', 232 function (event) { 233 let requestData = {}; 234 235 if (event && event.reason) { 236 requestData = { 237 id_product_attribute: event.reason.idProductAttribute, 238 id_product: event.reason.idProduct, 239 action: event.reason.linkAction 240 }; 241 242 let quantity = 1; 243 if(event.resp && event.resp.quantity) { 244 quantity = event.resp.quantity; 245 } 246 247 if(requestData.action == 'add-to-cart') { 248 cdcGtm.addToCart(requestData.id_product, requestData.id_product_attribute, quantity, null, null); 249 } else if(requestData.action == 'delete-from-cart') { 250 cdcGtm.removeFromCart(requestData.id_product, requestData.id_product_attribute, quantity); 251 } 252 } 253 } 254 ); 255 256 // cart creativeelements 257 document.addEventListener( 258 'awp-add-to-cart', 259 function (event) { 260 cdcGtm.addToCart(event.detail.productId, event.detail.id_product_attribute, event.detail.quantity, true, 'awp-add-to-cart'); 261 } 262 ); 263 }); 264} 265 266// override deleteProductFromSummary (checkout page) 267var deleteProductFromSummary = (function(id) { 268 var original_deleteProductFromSummary = deleteProductFromSummary; 269 return function(id) { 270 var productId = 0; 271 var productAttributeId = 0; 272 var ids = 0; 273 ids = id.split('_'); 274 productId = parseInt(ids[0]); 275 if (typeof(ids[1]) !== 'undefined') { 276 productAttributeId = parseInt(ids[1]); 277 } 278 279 var cart_qtity = parseInt($('input[name=quantity_' + id + ']').val()); 280 281 cdcGtm.removeFromCart(productId, productAttributeId, cart_qtity); 282 original_deleteProductFromSummary(id); 283 } 284})(); 285 286// override downQuantity (checkout page) 287var downQuantity = (function(id, qty) { 288 var original_downQuantity = downQuantity; 289 return function(id, qty) { 290 var productId = 0; 291 var productAttributeId = 0; 292 var ids = 0; 293 ids = id.split('_'); 294 productId = parseInt(ids[0]); 295 if (typeof(ids[1]) !== 'undefined') { 296 productAttributeId = parseInt(ids[1]); 297 } 298 299 // qty 300 var val = $('input[name=quantity_' + id + ']').val(); 301 var newVal = val; 302 if(typeof(qty) == 'undefined' || !qty) 303 { 304 new_qty = 1; 305 newVal = val - 1; 306 } 307 else if (qty < 0) 308 new_qty = -qty; 309 310 // if qtity is > 0, decrease qtity, if qtity = 0, it will be handled by "deleteProductFromSummary" 311 if(newVal > 0) { 312 cdcGtm.removeFromCart(productId, productAttributeId, new_qty); 313 } 314 315 original_downQuantity(id, qty); 316 } 317})(); 318 319/* CART : CHOSE SHIPPING / PAYMENT ************************************************************************************/ 320$(document).ready(function () { 321
322 if(typeof ajaxShippingEvent !== 'undefined' && ajaxShippingEvent) { 323 // chose shipping - prestashop 1.7 324 $('#checkout').on('click', '#checkout-delivery-step button[type=submit]', function (e) { 325 let $submitBtn = $(this); 326 327 // get shipping name 328 let $selectedShipping = $submitBtn.closest('#checkout-delivery-step').find('.delivery-options input[type=radio]:checked').closest('.delivery-option'); 329 let shippingName = $selectedShipping.find('.carrier-name').text().trim(); 330 331 cdcGtm.handleValidateShippingStep($submitBtn, e, shippingName); 332 }); 333 334 335 // chose shipping - prestashop 1.6 336 $('#order').on('click', 'button[name=processCarrier]', function(e) { 337 let $submitBtn = $(this); 338 339 // get shipping name 340 let $selectedShipping = $submitBtn.closest('form[name=carrier_area]').find('.delivery_options input[type=radio]:checked').closest('.delivery_option'); 341 let shippingName = $selectedShipping.find('td:not(.delivery_option_radio):not(.delivery_option_logo):not(.delivery_option_price)').find('strong').text().trim(); 342 cdcGtm.handleValidateShippingStep($submitBtn, e, shippingName); 343 }); 344 345 346 // chose shipping - module OPC onepagecheckoutps 347 $('#checkout').on('click', '#opc_content button[data-step=payment]', function (e) { 348 let $submitBtn = $(this); 349 350 // get shipping name 351 let $selectedShipping = $('#opc_step_shipping #form-shipping_container input[type=radio]:checked').closest('.carrier-item-content'); 352 let shippingName = $selectedShipping.find('.delivery-detail .delivery_option_title').text().trim(); 353 cdcGtm.handleValidateShippingStep($submitBtn, e, shippingName); 354 }); 355 } 356 357 358 if(typeof ajaxPaymentEvent !== 'undefined' && ajaxPaymentEvent) { 359 // chose payment - prestashop 1.7 360 $('#checkout').on('change', '#checkout-payment-step input[type=radio][name=payment-option]', function (e) { 361 // push infos to datalayer 362 let paymentName = $(this).closest('.payment-option').find('label').text().trim(); 363 cdcGtm.handleValidatePayementStep(paymentName); 364 }); 365 366 // chose payment - prestashop 1.6 367 $('#order').on('click', '#HOOK_PAYMENT .payment_module a', function (e, cdcGtmTriggered) { 368 let $submitBtn = $(this); 369 e.preventDefault(); 370 371 // push infos to datalayer 372 cdcGtm.handleValidatePayementStep($submitBtn.attr('title')); 373 374 // redirect to payment after waiting to send the datalayer 375 setTimeout(function () { 376 window.location.href = $submitBtn.attr("href"); 377 }, 500); 378 }); 379 380 // chose payment - module OPC onepagecheckoutps 381 $('#checkout').on('change', '#opc_step_payment_body input[type=radio][name=payment-option]', function (e) { 382 // push infos to datalayer 383 let paymentName = $(this).closest('.payment-option').find('.payment_content').text().trim(); 384 cdcGtm.handleValidatePayementStep(paymentName); 385 }); 386 } 387 388}); 389 390 391 392/* PRODUCT CLICK ******************************************************************************************************/ 393$(document).ready(function () { 394 395 // prestashop 1.7 396 $('article[data-id-product]').find('a').on('click', function() { 397 let $product = $(this).closest('article[data-id-product]'); 398 let idProduct = $product.data('id-product'); 399 let idProductAttribute = $product.data('id-product-attribute') | 0; 400 cdcGtm.productClick(idProduct, idProductAttribute); 401 }); 402 403 // prestashop 1.6 404 $('.ajax_block_product').find('a.product-name,a.product_img_link,a.lnk_view,a.quick-view-mobile').on('click', function(e) { 405 let $productInfos = $(this).closest('.ajax_block_product').find('.cdcgtm_product'); 406 let idProduct = $productInfos.data('id-product'); 407 let idProductAttribute = $productInfos.data('id-product-attribute') | 0; 408 cdcGtm.productClick(idProduct, idProductAttribute); 409 }); 410}); 411 412 413/* PRODUCT LIST - LAZY LOADING ************************************************************************************/ 414if(typeof(prestashop) != 'undefined') { 415 $(document).ready(function () { 416 417 // update product list 418 prestashop.on( 419 'updateProductList', 420 function (event) { 421 422 // use DOMParser to parse the HTML product list 423 const parser = new DOMParser(); 424 const doc = parser.parseFromString(event.rendered_products, 'text/html'); 425 426 // use a querySelectorAll to get all the products (article) 427 const products = doc.querySelectorAll('article[data-id-product]'); 428 429 // use Array.from to convert the NodeList into an array of products 430 const productsList = Array.from(products).map(product => ( 431 product.getAttribute('data-id-product') + '-' + product.getAttribute('data-id-product-attribute') 432 )); 433 434 cdcGtm.displayCategoryAsync(productsList); 435 } 436 ); 437 438 }); 439}
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.