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