1function metaConversionsTracking() { 2 3 //JC: umesto id proizvoda da se stampa sifra 4 function replaceIdWithCode(){ 5 if(typeof window.replaceIdWithCode !== "undefined" && window.replaceIdWithCode){ 6 return true 7 } 8 return false; 9 } 10 11 function getCookie(name) { 12 const value = `; ${document.cookie}`; 13 const parts = value.split(`; ${name}=`); 14 if (parts.length === 2) return parts.pop().split(';').shift(); 15 } 16 17 function getFbp() { 18 return getCookie('_fbp'); 19 } 20 21 function getFbc() { 22 let fbc = getCookie('_fbc'); 23 const NINETY_DAYS_MS = 90 * 24 * 60 * 60 * 1000; 24 25 if (fbc) { 26 const parts = fbc.split('.'); 27 const creationTime = parseInt(parts[2], 10); // timestamp iz fbc 28 29 if (!creationTime) { 30 return null; 31 } 32 33 const now = Date.now(); 34 const age = now - creationTime; 35 36 // Ako je starije od 90 dana ne salji 37 if (age > NINETY_DAYS_MS) { 38 console.log("Fbc je stariji od 90 dana.") 39 return null; 40 } 41 } 42 43 if (!fbc) { 44 const params = new URLSearchParams(window.location.search); 45 const fbclid = params.get('fbclid'); 46 47 if (fbclid) { 48 fbc = `fb.1.${Date.now()}.${fbclid}`; 49 } 50 } 51 52 return fbc || null; 53 } 54 55 56 function getExternalID() { 57 return getCookie('NBPHPSESSIONSECURE'); 58 } 59 60 function triggerViewContentEvent() { 61 if(nb_type_page === "product") { 62 nbshopJS.CustomEventTrigger('ViewContentEvent', { id: nbMetricObject.NB_METRIC_DATA.id, event_id: metric_onload_event_id}); 63 } 64 } 65 66 function valueExists(value) { 67 return typeof value !== "undefined" && value; 68 } 69 70 function convertValue(value) { 71 if(typeof value === 'string') { 72 var convertedValue = value; 73 var convertedValue2, convertedValue3; 74 75 if(convertedValue.includes('.') && convertedValue.includes(',')) { 76 convertedValue2 = convertedValue.replace(/\./g, ''); 77 } else if(convertedValue.includes('.') && !convertedValue.includes(',')){ 78 convertedValue2 = parseFloat(parseFloat(convertedValue).toFixed(2)); 79 } else convertedValue2 = convertedValue; 80 81 if(typeof convertedValue2 === 'string' && convertedValue2.includes(',')) { 82 convertedValue3 = convertedValue2.replace(/,/g, '.'); 83 } else convertedValue3 = convertedValue2; 84 85 return parseFloat(parseFloat(convertedValue3).toFixed(2)); 86 } else return value; 87 } 88 89 function triggerCartEvent() { 90 91 if(nb_type_page === "cart") { 92 93 let productsInCart = $("#order_cart_content .cart-step [data-productid]"); 94 95 if(typeof productsInCart === "undefined" || productsInCart.length === 0) return; 96 97 let cartProductsArray = []; 98 let productIds = []; 99 100 for(let product of productsInCart) { 101 let cartItem = $(product).data(); 102 let productID = parseFloat(cartItem.productid) 103 //proveriti 104 if(replaceIdWithCode()){ 105 productID = cartItem.productcode; 106 } 107 108 let cartItemConverted = { 109 id: productID, 110 quantity: cartItem.productquantity ? parseFloat(cartItem.productquantity) : parseFloat(cartItem.quantity), 111 item_name: cartItem.productname, 112 item_price: convertValue(cartItem.productprice), 113 } 114 cartProductsArray.push(cartItemConverted); 115 productIds.push('' + productID + ''); 116 } 117 118 nbshopJS.CustomEventTrigger('viewCartEvent', { productsInCart: cartProductsArray, productIds: productIds }); 119 } 120 } 121 122 async function sendConversionEvent(eventData) { 123 124 if (typeof getFbp() === "undefined" || !getFbp()) { 125 return Promise.reject('Missing _fbp cookie - event not sent'); 126 } 127 128 const url = 'https://graph.facebook.com/v18.0/' + fb_pixel_id + '/events'; 129 const payload = { 130 data: [{ 131 event_name: eventData.event_name, 132 event_time: Math.floor(Date.now() / 1000), 133 event_id: eventData.event_id, 134 action_source: 'website', 135 event_source_url: window.location.href, 136 user_data: { 137 ...(eventData.email !== "" && { em: eventData.email }), 138 ...(eventData.phone !== "" && { ph: eventData.phone }), 139 ...(eventData.firstName !== "" && { fn: eventData.firstName }), 140 ...(eventData.lastName !== "" && { ln: eventData.lastName }), 141 ...(getFbp() && { fbp: getFbp() }), 142 ...(getFbc() && { fbc: getFbc() }), 143 client_user_agent: eventData.userAgent, 144 external_id : getExternalID() 145 }, 146 ...( (typeof eventData.custom_data !== "undefined" && eventData.custom_data) && {custom_data: {...eventData.custom_data}}), 147 currency: eventData.currency, 148 value: eventData.value 149 }, 150 ], 151 ...(collectValue(fb_test_event_code) !== "" && { test_event_code: fb_test_event_code }), 152 access_token: fb_token 153 }; 154 155 try { 156 const response = await fetch(url, { 157 method: 'POST', 158 headers: { 159 'Content-Type': 'application/json' 160 }, 161 body: JSON.stringify(payload), 162 keepalive: true 163 }); 164 165 const data = await response.json(); 166 167 if (data.error) { 168 console.log('FB CAPI Error:', data.error); 169 } else { 170 console.log('Success:', data); 171 } 172 } catch (error) { 173 console.error('Fetch Error:', error); 174 } 175 } 176 177 async function getProductCatalogId() { 178 const url = `https://graph.facebook.com/v20.0/${fb_pixel_id}/owned_product_catalogs?access_token=${fb_token}`; 179 180 try { 181 const response = await fetch(url, { 182 method: 'GET', 183 headers: { 184 'Content-Type': 'application/json' 185 } 186 }); 187 188 const data = await response.json(); 189 190 if (data && data.data && data.data.length > 0) { 191 return data.data[0].id; 192 } else { 193 throw new Error('No catalogs found'); 194 } 195 } catch (error) { 196 console.log('Error fetching product catalogs:', error); 197 } 198 } 199 200 201 202 function triggerEvent(eventData) { 203 204 let subscribeEvent = eventData.subscribeEvent !== undefined; 205 206 let eventId = generateEventId(); 207 208 if(typeof eventData.event_id !== "undefined") { 209 eventId = eventData.event_id; 210 } 211 212 const currency = window.nbMetricObject.NB_METRIC_DATA.currencyISO; 213 let value = "0"; 214 215 if(!subscribeEvent) { 216 value = eventData.custom_data.quantity ? eventData.custom_data.item_price * eventData.custom_data.quantity : eventData.custom_data.item_price; 217 } 218 219 let isSearchEvent = eventData.event_name === "Search"; 220 221 let email = window.nbMetricObject.NB_METRIC_DATA.userEmailHashed; 222 let phone = window.nbMetricObject.NB_METRIC_DATA.userPhoneHashed; 223 let firstName = window.nbMetricObject.NB_METRIC_DATA.userFirstNameHashed; 224 let lastName = window.nbMetricObject.NB_METRIC_DATA.userLastNameHashed; 225 226 if(eventData.event_name === "InitiateCheckout" || eventData.event_name === "AddPaymentInfo") { 227 value = eventData.custom_data.value; 228 } 229 230 if(eventData.event_name === "Purchase") { 231 value = eventData.value; 232 email = eventData.custom_data.order_email; 233 phone = eventData.custom_data.order_phone; 234 firstName = eventData.custom_data.order_first_name; 235 lastName = eventData.custom_data.order_last_name; 236 } 237 238 let formattedCustomData = ''; 239 if(typeof eventData.custom_data !== "undefined" && eventData.custom_data) { 240 formattedCustomData = formatMetaData(eventData.custom_data, value, currency); 241 } 242
243 if(subscribeEvent && eventData.event_name !== "Subscribe") { 244 email = eventData.subscribe_data.email; 245 firstName = eventData.subscribe_data.firstName; 246 lastName = eventData.subscribe_data.lastName; 247 } 248 249 console.log(formattedCustomData); 250 251 // Fire fbq event 252 if(readCookie("site_cookie_info") !== "1" && !disableFBBrowserEvents) { 253 fbq('track', eventData.event_name, { 254 ...formattedCustomData, 255 // product_catalog_id: fb_pixel_id 256 }, 257 { 258 eventID: eventId, 259 value: value, 260 currency: currency, 261 ...(email !== "" && { em: email }), 262 ...(firstName !== "" && { fn: firstName }), 263 ...(lastName !== "" && { ln: lastName }), 264 ...(phone !== "" && { ph: phone }), 265 userAgent: navigator.userAgent, 266 fbp: getFbp(), 267 external_id: getExternalID() 268 } 269 ); 270 271 } 272 273 // ukoliko klijent ne zeli serverske vec samo browserske eventove 274 if(typeof window.enableFBBrowserEventsOnly !== "undefined" && window.enableFBBrowserEventsOnly) { 275 return; 276 } 277 278 // Fire AJAX event 279 const capiData = { 280 ...(email !== "" && { email: email }), 281 ...(phone !== "" && { phone: phone }), 282 ...(firstName !== "" && { firstName: firstName }), 283 ...(lastName !== "" && { lastName: lastName }), 284 custom_data: { 285 value: disableFBBrowserEvents ? parseFloat(Number(value).toFixed(0)) : value, 286 currency: currency, 287 ...( !isSearchEvent && !subscribeEvent && { content_ids: formattedCustomData.content_ids } ), 288 ...( !isSearchEvent && !subscribeEvent && { content_type: "product" } ), 289 ...( isSearchEvent && { search_string: formattedCustomData.search_string } ), 290 ...( formattedCustomData !== '' && { contents: mapCapiContents(formattedCustomData.contents) }) 291 }, 292 event_name: eventData.event_name, 293 event_id: eventId, 294 currency: currency, 295 value: disableFBBrowserEvents ? parseFloat(Number(value).toFixed(0)) : value, 296 userAgent: navigator.userAgent 297 }; 298 299 sendConversionEvent(capiData).then(() => { 300 console.log('Conversion event sent successfully'); 301 }).catch((error) => { 302 console.log('Error sending conversion event:', error); 303 }); 304 305 } 306 307 function mapCapiContents(contents) { 308 309 if(typeof contents !== "object" || contents.length === 0) return; 310 311 let contentsNew = []; 312 313 for (let contentItem of contents) { 314 let newItem = { 315 id: contentItem.id, 316 quantity: contentItem.quantity, 317 item_price: contentItem.item_price 318 } 319 320 contentsNew.push(newItem) 321 322 } 323 324 return contentsNew; 325 326 } 327 328 function getProduct(e, event_name) { 329 330 let productId = e.originalEvent.detail.id; 331 let metricData = window.nbMetricObject.NB_METRIC_DATA; 332 333 if(replaceIdWithCode()) { 334 335 let foundProduct = $(".product-item[data-productid='" + productId + "']")[0]; 336 337 if(typeof foundProduct !== "undefined" && foundProduct.length > 0) { 338 productId = $(foundProduct).data('productcode'); 339 } 340 341 if((typeof foundProduct === "undefined" || foundProduct.length === 0) && nb_type_page === "product" && parseFloat(productId) === parseFloat(metricData.id)) { 342 productId = metricData.productCode; 343 } 344 345 } else productId = parseFloat(e.originalEvent.detail.id); 346 347 let metricId = replaceIdWithCode() ? metricData.productCode : parseFloat(metricData.id); 348 349 let productData = {}; 350 351 if(nb_type_page === 'product' && productId === metricId) { 352 353 if(event_name === "AddToCart") { 354 355 let combination = $('.product-attributes li.active').data(); 356 357 productData = { 358 id: ''+ productId + '', 359 quantity: e.originalEvent.detail.amount ? parseFloat(e.originalEvent.detail.amount) : 1, 360 item_name: metricData.name, 361 item_price: convertValue(combination.productsizePrice), 362 } 363 364 } else { 365 productData = { 366 id: ''+ productId + '', 367 quantity: e.originalEvent.detail.amount ? parseFloat(e.originalEvent.detail.amount) : 1, 368 item_name: metricData.name, 369 item_price: metricData.price, 370 } 371 } 372 373 } else { 374 375 let productObj = $('.product-item[data-productid="'+productId+'"]').data(); 376 377 productData = { 378 id: ''+ productId + '', 379 quantity: e.originalEvent.detail.amount ? parseFloat(e.originalEvent.detail.amount) : 1, 380 item_name: productObj.productname, 381 item_price: convertValue(productObj.productprice), 382 } 383 } 384 385 return productData; 386 387 } 388 389 function formatMetaData(data, value, currency) { 390 391 let formattedData = {}; 392 393 if(data.search_string !== undefined) return data; //search event 394 395 formattedData = { 396 content_ids: data.content_ids ? data.content_ids : [ data.id ], 397 content_type: "product", 398 contents: data.contents ? data.contents : [data], 399 value: value, 400 currency: currency,
401 ...(data.content_ids === undefined && { content_name: data.item_name }), 402 ...(data.num_items !== undefined && { num_items: data.num_items }), 403 } 404 405 return formattedData; 406 407 } 408 409 function productEvent(event, event_name) { 410 411 $(window).on(event, function (e) { 412 413 let formattedProduct = getProduct(e, event_name); 414 415 let eventData = { 416 event_name: event_name, 417 custom_data: formattedProduct, 418 ...(typeof e.originalEvent.detail.event_id !== 'undefined' && { event_id: e.originalEvent.detail.event_id }), 419 } 420 421 triggerEvent(eventData); 422 423 }) 424 } 425 426 function addToCartEvent() { 427 productEvent("cartButtonClick", "AddToCart"); 428 } 429 430 function addToWishlistEvent() { 431 productEvent("addToFavoritesProduct", "AddToWishlist"); 432 } 433 434 function viewContentEvent() { 435 productEvent("ViewContentEvent", "ViewContent"); 436 } 437 438 // Cart Events 439 440 function cartEvents() { 441 442 $(window).on("viewCartEvent", function (e) { 443 444 initiateCheckoutEvent("InitiateCheckout", { contents: e.originalEvent.detail.productsInCart, content_ids: e.originalEvent.detail.productIds }); 445 addPaymentInfoEvent("AddPaymentInfo", { contents: e.originalEvent.detail.productsInCart, content_ids: e.originalEvent.detail.productIds }); 446 447 }) 448 } 449 450 function getCartEventsValue(products) { 451 452 if (typeof products !== "undefined" && typeof products === "object") 453 454 var value = 0; 455 456 products.forEach((item) => { 457 value += item.item_price * item.quantity; 458 }) 459 460 return value; 461 462 } 463 464 function initiateCheckoutEvent(event_name, products) { 465 466 let eventData = { 467 event_name: event_name, 468 event_id: metric_onload_event_id, 469 custom_data: { 470 ...products, 471 num_items: products.contents.length, 472 value: getCartEventsValue(products.contents) 473 } 474 } 475 476 triggerEvent(eventData); 477 478 } 479 480 function addPaymentInfoEvent(event_name, products) { 481 482 $("#submit_order_one_page").on("click", function () { 483 484 setTimeout(function () { 485 if(typeof $(".cart .validation-error") === "undefined" || $(".cart .validation-error").length === 0) { 486 487 let typePayment = $("#cart-payment-content input[name='typepayment']:checked").val(); 488 489 let eventData = { 490 event_name: event_name, 491 event_id: metric_onload_event_id, 492 custom_data: { 493 ...products, 494 payment_type: typePayment, 495 value: getCartEventsValue(products.contents) 496 } 497 } 498 triggerEvent(eventData); 499 } 500 }, 200) 501 }) 502 } 503 504 // Subscribe events 505 506 function triggerRegisterEvent() { 507 508 if(nb_type_page === "confirm_registration") { 509 510 let userInfo = { 511 userEmailHashed : valueExists(window.nbMetricObject.NB_METRIC_DATA.userEmailHashed), 512 userFirstNameHashed :valueExists(window.nbMetricObject.NB_METRIC_DATA.userFirstNameHashed), 513 userLastNameHashed: valueExists(window.nbMetricObject.NB_METRIC_DATA.userLastNameHashed), 514 userPhoneHashed: valueExists(window.nbMetricObject.NB_METRIC_DATA.userPhoneHashed) 515 } 516 517 nbshopJS.CustomEventTrigger('RegisterEvent', { userInfo: userInfo, event_id: metric_onload_event_id }); 518 } 519 } 520 521 function subscribeEvents() { 522 523 function newsletterEvent() { 524 525 $(window).on("load", function () { 526 if(typeof window.nbMetricObject.NB_METRIC_DATA.uniqueCode !== "undefined" && window.nbMetricObject.NB_METRIC_DATA.uniqueCode === "ci_newsletter_verification") { 527 nbshopJS.CustomEventTrigger('NewsletterLoginEvent', { ci_event: true, event_id: metric_onload_event_id }); 528 console.log(window.nbMetricObject.NB_METRIC_DATA.uniqueCode) 529 } 530 }) 531 532 } 533 534 function subscribeEventBuilder(fbEvent, eventTrigger) { 535 536 $(window).on(eventTrigger, function (e) { 537 e.preventDefault(); 538 539 let eventData = { 540 event_name: fbEvent, 541 subscribeEvent: true, 542 ...(typeof e.originalEvent.detail.event_id !== 'undefined' && { event_id: e.originalEvent.detail.event_id }), 543 } 544 545 if(valueExists(e.originalEvent.detail.ci_event) && e.originalEvent.detail.ci_event && eventTrigger === "NewsletterLoginEvent") { 546 triggerEvent(eventData); 547 } 548 549 let condition = valueExists(e.originalEvent.detail) && valueExists(e.originalEvent.detail.userInfo); 550 551 if (!condition) return; 552 553 let userInfo = e.originalEvent.detail.userInfo; 554 555 556 eventData = { 557 ...eventData, 558 subscribe_data: { 559 email: valueExists(userInfo.email) ? userInfo.email : '', 560 firstName: valueExists(userInfo.firstName) ? userInfo.firstName : '', 561 lastName: valueExists(userInfo.lastName) ? userInfo.lastName : '', 562 phone: valueExists(userInfo.phone) ? userInfo.phone : '', 563 } 564 } 565 566 localStorage.setItem(fbEvent, JSON.stringify(eventData)) 567 568 triggerEvent(eventData); 569 570 }) 571 572 } 573 574 newsletterEvent(); 575 576 subscribeEventBuilder("CompleteRegistration", 'RegisterEvent')
577 subscribeEventBuilder("Login", 'LoginEvent') 578 subscribeEventBuilder("Subscribe", 'NewsletterLoginEvent') 579 580 triggerRegisterEvent(); 581 582 } 583 584 function searchEvent() { 585 586 $(window).on("searchSuggestAutocomplateNew", function (e) { 587 588 var searchTermVar = $('#search-text').val(); 589 590 let eventData = { 591 event_name: "Search", 592 ...(typeof e.originalEvent.detail.event_id !== 'undefined' && { event_id: e.originalEvent.detail.event_id }), 593 custom_data: { 594 search_string: searchTermVar 595 } 596 } 597 598 triggerEvent(eventData); 599 }) 600 } 601 602 function isPaymentPage() { 603 if(typeof $(".confirm-payment-wrapper") !== "undefined" && $(".confirm-payment-wrapper").length > 0) { 604 return true; 605 } 606 return false; 607 } 608 609 function purchaseEventCAPI(orderItems, orderUser, metricData, orderAddress) { 610 611 if(isPaymentPage()) { 612 return; 613 } 614 615 let orderItemsFormatted = []; 616 let contentIds = []; 617 618 for(let orderItem of orderItems) { 619 620 let productId = replaceIdWithCode() ? orderItem.productCode : parseFloat(orderItem.productId); 621 622 let orderItemFormatted = { 623 id: productId, 624 quantity: parseFloat(orderItem.quantity), 625 item_price: convertValue(orderItem.price), 626 item_name: orderItem.name 627 } 628 629 contentIds.push('' + productId + ''); 630 orderItemsFormatted.push(orderItemFormatted); 631 } 632 633 634 let eventData = { 635 event_name: "Purchase", 636 custom_data: { 637 contents: orderItemsFormatted, 638 content_ids: contentIds, 639 num_items: orderItemsFormatted.length, 640 order_email: orderAddress.userEmailHashed, 641 order_phone: orderAddress.userPhoneHashed, 642 order_first_name: orderAddress.userFirstNameHashed, 643 order_last_name: orderAddress.userLastNameHashed 644 }, 645 value: convertValue(orderUser.total), 646 event_id: metric_onload_event_id 647 } 648 649 triggerEvent(eventData); 650 651 } 652 653 function eventCalls() { 654 addToCartEvent(); 655 addToWishlistEvent(); 656 viewContentEvent(); 657 cartEvents(); 658 searchEvent(); 659 660 triggerViewContentEvent(); 661 triggerCartEvent(); 662 subscribeEvents(); 663 } 664 665 return { 666 init: eventCalls, 667 purchase: purchaseEventCAPI 668 } 669 670} 671 672window.nbMetaConversionsTracking = new metaConversionsTracking(); 673 674// $(document).ready(function () { 675// 676// if(typeof fb_pixel_id === 'undefined' || fb_pixel_id === ''){ 677// console.log('FB PIXEL ne posotji!'); 678// return; 679// } 680// 681// if(typeof fb_token === 'undefined' || fb_token === ''){ 682// console.log('FB TOKEN ne posotji!'); 683// return; 684// } 685// 686// if(typeof fbq !== 'function'){ 687// console.log('Nedefinisan fbq'); 688// return; 689// } 690// 691// nbMetaConversionsTracking.init() 692// 693// })
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.