1/* defines */ 2 3tableIsRendered = "false"; 4ordery = "desc"; 5orderCol = 0; 6 7/* Stripe kart hatası mesajları â TEK KAYNAK: PHP l() (window.lang.stripe, 8 * header.php'de aktif dilde basılır). window.lang yoksa İngilizce fallback. */ 9stripeErrors = (window.lang && window.lang.stripe) ? window.lang.stripe : { 10 "invalid_number": "Your card number is not a valid credit card number", 11 "invalid_expiry_month": "Your card's expiration month is invalid", 12 "invalid_expiry_year": "Your card's expiration year is invalid", 13 "invalid_cvc": "Your card's security code is invalid", 14 "incorrect_number": "Your card number is incorrect", 15 "incomplete_number": "Your card number is incomplete", 16 "incomplete_cvc": "Your card's security code is incomplete", 17 "incomplete_expiry": "Your card's expiration date is incomplete", 18 "expired_card": "Your card has expired", 19 "incorrect_cvc": "Your card's security code is incorrect", 20 "incorrect_zip": "Your card's ZIP code could not be verified", 21 "invalid_expiry_year_past": "Your card's expiration year is in the past", 22 "card_declined": "Your card was declined", 23 "missing": "There is no card on file for the customer", 24 "processing_error": "An error occurred while processing your card", 25 "authentication_required": "Your bank needs to verify this payment. Please complete the verification and try again.", 26 "insufficient_funds": "Your card has insufficient funds. Please use a different card.", 27 "do_not_honor": "Your bank declined the payment. Please contact your bank or try another card.", 28 "generic_decline": "Your card was declined. Please contact your bank or try another card.", 29 "fraudulent": "This payment couldn't be processed. Please try another card or contact your bank.", 30 "lost_card": "Your card was declined. Please use a different card.", 31 "stolen_card": "Your card was declined. Please use a different card.", 32 "pickup_card": "Your card was declined. Please use a different card.", 33 "try_again_later": "The payment couldn't be processed right now. Please try again in a moment.", 34 "card_velocity_exceeded": "This card has reached its limit. Please use a different card.", 35 "currency_not_supported": "Your card doesn't support this currency. Please use a different card." 36}; 37 38/* AÄ hatası mesajları â TEK KAYNAK: window.lang.errors (PHP l(), header.php'de aktif dilde 39 * basılır, stripeErrors ile aynı desen). window.lang.errors yoksa İngilizce fallback. Amaç: 40 * transient network hatalarında (request.js -> {'result':'error'}) bare alert(undefined) veya 41 * hardcoded İngilizce blocking alert yerine, dismissible + retry sunan tek kaynaklı mesaj. */ 42netErrors = (window.lang && window.lang.errors) ? window.lang.errors : { 43 "network": "We couldn't reach the server. Please check your connection and try again.", 44 "retry": "Retry" 45}; 46 47$.wait = function (ms) { 48 var defer = $.Deferred(); 49 setTimeout(function () { 50 defer.resolve(); 51 }, ms); 52 return defer; 53}; 54 55function isset(keyword) { 56 keyword = $.trim(keyword); 57 if (typeof keyword === "undefined" || keyword.length == 0 || keyword === null || keyword === "" || keyword == "false" || keyword == false) { 58 return false; 59 } else { 60 return keyword; 61 } 62} 63 64function urlEncode(deger) { 65 return encodeURIComponent(deger); 66} 67 68function goUrl(url) { 69 window.open(url); 70} 71 72function urlDecode(deger) { 73 return unescape(decodeURIComponent((escape(deger)))); 74} 75 76$.fn.justNumerics = 77 function (type) { 78 return this.each(function () { 79 $(this).keydown(function (e) { 80 var key = e.charCode || e.keyCode || 0; 81 82 if (type == "float") { 83 return ( 84 key == 8 || 85 key == 9 || 86 key == 13 || 87 key == 46 || 88 key == 110 || 89 key == 190 || 90 (key >= 35 && key <= 40) || 91 (key >= 48 && key <= 57) || 92 (key >= 96 && key <= 105)); 93 } else { 94 return ( 95 key == 8 || 96 key == 9 || 97 key == 13 || 98 key == 46 || 99 key == 110 || 100 (key >= 35 && key <= 40) || 101 (key >= 48 && key <= 57) || 102 (key >= 96 && key <= 105)); 103 } 104 105 }); 106 }); 107 }; 108 109 110$.fn.removeSlowly = function () { 111 $(this).animate({ 112 height: 'hide', 113 opacity: 'hide' 114 }, 400, function () { 115 $(this).addClass("none"); 116 $(this).remove(); 117 }); 118}; 119 120 121function currencyFormat(price, currency) { 122 123 if (typeof currency == "undefined") { 124 currency = ""; 125 } 126 127 /* SITE_CURRENCY_v1 â DİL, PARA BİRİMİ DEÄİLDİR. Buradaki eski eÅleme 'tr' dilini 128 'tl' para birimine çeviriyordu; maÄaza USD tahsil ettiÄi için (Stripe 'usd', 129 PayPal 'USD') Türkçe arayüzde $0,84'lük bir tutar "0,84 TL" olarak gösteriliyordu 130 â ~40 kat yanlıÅ. es/pt/ar/it/nl dillerinde ise hiç sembol basılmıyordu. 131 ÃaÄıranlar hâlâ dil kodu geçtiÄi için burada normalize ediyoruz; gerçek çoklu para 132 birimi geldiÄinde sembol SUNUCUDAN gelmeli (PHP tarafı: SITE_CURRENCY_SYMBOL). */ 133 if (currency == "" || currency == "tr" || currency == "en" || currency == "es" 134 || currency == "pt" || currency == "ar" || currency == "it" || currency == "nl") { 135 currency = "$"; 136 } 137 138 /* MONEY_DECIMALS_v1 â biçim PHP tarafındaki currencyFormat() ile BİREBİR aynı olmalı. 139 Eskiden deÄer olduÄu gibi yapıÅtırılıyordu: sunucudan gelen "9.00" dizesi "$9.00" 140 basıyor, ama istemcide hesaplanan (fiyat à adet) sayısı "$13.5" / "$9" basıyordu â 141 aynı ekranda iki farklı para yazımı. Ondalık her zaman 2 hane: 142 TL -> ondalık virgül, binlik nokta (moneyFormat varsayılanı, PHP ile aynı) 143 $ -> ondalık nokta, binlik virgül (PHP: number_format($p, 2, '.', ',')) */ 144 if (currency == "tl" || currency == "TL" || currency == "TRY" || currency == "try") { 145 money = moneyFormat(price) + " TL"; 146 } else { 147 money = currency + moneyFormat(price, 2, ".", ","); 148 } 149 150 return money; 151} 152 153function moneyFormat(number, decimals, decPoint, thousandsSep) { 154 155 if (typeof decimals == "undefined") { 156 decimals = 2; 157 } 158 159 if (typeof decPoint == "undefined" || typeof decPoint == undefined) { 160 decPoint = ","; 161 } 162 163 if (typeof thousandsSep == "undefined" || typeof thousandsSep == undefined) { 164 thousandsSep = "."; 165 } 166 167 number = parseFloat(number); 168 number = number.toFixed(decimals); 169 170 var nstr = number.toString(); 171 nstr += ''; 172 x = nstr.split('.'); 173 x1 = x[0]; 174 x2 = x.length > 1 ? decPoint + x[1] : ''; 175 var rgx = /(\d+)(\d{3})/; 176 177 while (rgx.test(x1)) 178 x1 = x1.replace(rgx, '$1' + thousandsSep + '$2'); 179 180 return x1 + x2; 181} 182 183/* EXPRESS_CHECKOUT_v1 â Stripe Express Checkout Element (Apple Pay / Google Pay / Link). 184 * 185 * NEDEN AYRI BİR ELEMENT: PaymentIntent'te `automatic_payment_methods` açık olması 186 * cüzdanları yalnız "uygun" yapar; Payment Element bunları kart formunun İÃİNDE, en 187 * altta ve çoÄu zaman hiç göstermez. Tek dokunuÅluk Apple/Google Pay düÄmeleri ancak 188 * ayrı bir 'expressCheckout' element'i mount edilirse çıkar â projede bu element 189 * Hİà yoktu, bu yüzden hiçbir yerde cüzdan düÄmesi görünmüyordu. 190 * 191 * TEK KAYNAK: hem quick-buy modal'ı (footer.php) hem ödeme sihirbazı (payment.php) bu 192 * fonksiyonu çaÄırır. İki yüzey aynı sayfada birlikte render edildiÄi için (bkz. 193 * startWizardCardPayment'taki isim-çakıÅması notu) mount hedefi ÃAÄIRANDAN gelir. 194 * 195 * ÃNEMLİ â cüzdan ödemesinde `payment_method_data.billing_details` GÃNDERİLMEZ: fatura 196 * bilgisini Apple/Google cüzdanın kendisi verir; bizim ön-doldurduÄumuz deÄerleri 197 * göndermek cüzdanın verdiÄiyle çakıÅır ve Stripe ödemeyi reddeder. Kart yolundaki 198 * confirm çaÄrısı bu yüzden AYNEN korunur, burada ayrı bir çaÄrı kurulur. 199 * 200 * @param {object} o 201 * o.stripe Stripe örneÄi (clientSecret ile kurulmuÅ elements'in sahibi) 202 * o.elements stripe.elements({clientSecret}) â kart element'iyle AYNI örnek olmalı 203 * o.container mount edilecek CSS seçici (ör. '#quickbuy-express-checkout') 204 * o.surface analitik etiketi ('quick_buy' | 'wizard') 205 * o.returnUrl 3DS/redirect dönüŠadresi 206 * o.onDone function(errorMessage, paymentIntent) â ödeme denemesi bittiÄinde 207 * @return {object|null} element örneÄi, kurulamazsa null 208 */ 209function esimMountExpressCheckout(o) { 210
211 if (!o || !o.stripe || !o.elements || !o.container) { return null; } 212 213 var host = document.querySelector(o.container); 214 if (!host) { return null; } 215 216 var ece; 217 try { 218 ece = o.elements.create('expressCheckout', { 219 /* QUICKBUY_COMPACT_v1 â 40 Stripe'ın izin verdiÄi en küçük yükseklik. Düzen: 220 en çok 2 sütun à 1 satır; eskiden (otomatik düzen) 400 px'lik modalda tek 221 sütun seçiliyor, ikinci cüzdan (ör. Link + Google Pay) "Daha fazla göster" 222 baÄlantısının arkasına saklanıyor ve kutu iki kat yer kaplıyordu. Tek cüzdan 223 varsa düÄme satırı tek baÅına doldurur; 3+ cüzdan (nadir) yine taÅma 224 baÄlantısına düÅer, hiçbiri gizlenmez. */ 225 buttonHeight: 40, 226 layout: { maxColumns: 2, maxRows: 1, overflow: 'auto' }, 227 /* YALNIZ üç cüzdan açık. DiÄerleri BİLEREK kapalı: 228 - paypal: kendi PayPal entegrasyonumuz var (createPaypalOrder/capturePaypal); 229 Stripe üzerinden ikinci bir PayPal yolu iki farklı sipariÅ kaydı demek olurdu. 230 - klarna / amazonPay: yönlendirme (redirect) gerektirir, oysa PaymentIntent 231 `allow_redirects: 'never'` ile kuruluyor (paymentStripeHelpers) â düÄme 232 görünür ama ödeme confirm aÅamasında reddedilirdi. 233 Kart burada YOK: zaten ayrı Payment Element'te, iki kart formu olurdu. */ 234 paymentMethods: { 235 link: 'auto', applePay: 'auto', googlePay: 'auto', 236 paypal: 'never', klarna: 'never', amazonPay: 'never' 237 } 238 }); 239 } catch (e) { 240 /* Eski Stripe.js sürümü veya desteklenmeyen ortam â sessizce vazgeç; kart 241 yolu bozulmasın (cüzdan bir hızlandırıcıdır, tek ödeme yolu deÄil). */ 242 return null; 243 } 244 245 /* Kutu VARSAYILAN OLARAK GİZLİ durur ve yalnız gerçekten kullanılabilir bir cüzdan 246 varsa açılır. Aksi hâlde Apple Pay'i olmayan bir masaüstü kullanıcı boÅ bir 247 kutu + gereksiz "veya" ayıracı görürdü. */ 248 host.style.display = 'none'; 249 250 ece.on('ready', function (ev) { 251 var avail = (ev && ev.availablePaymentMethods) || null; 252 var any = !!avail && (avail.applePay || avail.googlePay || avail.link || avail.amazonPay || avail.paypal); 253 254 if (!any) { return; } 255 256 host.style.display = ''; 257 258 /* EXPRESS_SEP_GUARD_v1 â "veya" ayıracı yalnız cüzdan kutusu GERÃEKTEN çizildiyse 259 gösterilir. Stripe 'ready' olayında bir cüzdanı "uygun" bildirse bile düÄme kimi 260 ortamlarda hiç boyanmıyor (kutu 0 yükseklikte kalıyor) â o durumda ekranın en 261 üstünde, hiçbir Åeyi ayırmayan tek baÅına bir "veya" kalıyordu ve ödeme adımı 262 özensiz görünüyordu. Ãlçüm hemen yapılamaz: display:'' aynı karede layout 263 üretmez ve Stripe iframe'i yüksekliÄini sonradan bildirir. Bu yüzden kısa 264 aralıklarla yoklanır; süre dolduÄunda kutu da ayıraç da gizlenir. */ 265 var sep = document.querySelector(o.container + '-sep'); 266 var waited = 0; 267 (function settle() { 268 if (host.offsetHeight > 8) { 269 /* 'flex' ÅART: ayıracın iki yanındaki ince çizgiler flex çocuklarıdır. 270 style.display='' yazıldıÄında element CSS varsayılanı olan 'block'a 271 dönüyor, çizgiler yassılıyor ve geriye sola yapıÅmıŠtek bir "veya" 272 kelimesi kalıyordu (canlıda görüldü). */ 273 if (sep) { sep.style.display = 'flex'; } 274 return; 275 } 276 waited += 100; 277 if (waited > 3000) { /* cömert tavan: çalıÅan bir cüzdan düÄmesini asla gizlemesin */ 278 host.style.display = 'none'; 279 if (sep) { sep.style.display = 'none'; } 280 return; 281 } 282 setTimeout(settle, 100); 283 })(); 284 285 try { 286 if (window.GA4) {
287 GA4.event('express_checkout_shown', { 288 surface: o.surface || '', 289 apple_pay: !!avail.applePay, 290 google_pay: !!avail.googlePay, 291 link: !!avail.link 292 }); 293 } 294 } catch (e) {} 295 }); 296 297 /* Stripe, click olayında resolve() çaÄrılmasını bekler; kayıtlı bir handler yoksa 298 varsayılanlarla devam eder. Handler'ı kaydedip resolve()'u çaÄırmamak akıÅı 299 KİLİTLER â bu yüzden try/catch içinde ve her koÅulda resolve edilir. */ 300 ece.on('click', function (event) { 301 try { if (event && typeof event.resolve === 'function') { event.resolve(); } } catch (e) {} 302 }); 303 304 ece.on('confirm', function () { 305 try { 306 if (window.GA4) { 307 GA4.event('add_payment_info', { currency: 'USD', payment_type: 'wallet', surface: o.surface || '' }); 308 } 309 } catch (e) {} 310 311 o.stripe.confirmPayment({ 312 elements: o.elements, 313 confirmParams: { return_url: o.returnUrl }, 314 redirect: 'if_required' 315 }).then(function (result) { 316 317 var msg = ""; 318 if (result && result.error) { 319 var code = result.error.code; 320 if (typeof stripeErrors !== "undefined" && stripeErrors[code]) { 321 msg = stripeErrors[code]; 322 } else { 323 msg = result.error.message || ""; 324 } 325 } 326 327 if (typeof o.onDone === 'function') { 328 o.onDone(msg, result ? result.paymentIntent : null); 329 } 330 }); 331 }); 332 333 /* Kullanıcı cüzdan sayfasını kapattı â hata DEÄİL, sessizce kart formuna dönülür. */ 334 ece.on('cancel', function () { 335 try { 336 if (window.GA4) { GA4.event('express_checkout_cancelled', { surface: o.surface || '' }); } 337 } catch (e) {} 338 }); 339 340 try { 341 ece.mount(o.container); 342 } catch (e) { 343 return null; 344 } 345 346 return ece;
347} 348 349/* DELIVERABLE_MAIL_v1 â "eSIM teslim edilebilir bir e-posta" duvarı (TEK KAYNAK). 350 * 351 * Sunucu tarafındaki karÅılıÄı Payment::deliverableMailBlock(): ödemeyi BAÅLATAN uçlar 352 * (web Stripe /payment/add, mobil /payment/createIntent, /payment/createPaypalOrder, 353 * /payment/createTikoOrder) hesabın maili boÅ/bozuk/sentetik ise 403 + mail_required=1 354 * döner. Sebebi: eSIM'in tek teslim kanalı e-postadır; böyle bir hesaptan ödeme alınırsa 355 * para çekilir ama eSIM eline geçmez. 356 * 357 * Bu fonksiyon kutuyu açar, /profile/mail'e yazar ve onSaved() ile ÃAÄIRANIN isteÄini 358 * tekrarlatır. request.js bunu merkezden çaÄırdıÄı için hiçbir ödeme yüzeyine ayrı 359 * kod eklemek gerekmez â yeni bir ödeme yöntemi eklendiÄinde de kendiliÄinden çalıÅır. 360 * 361 * @param {function} onSaved Mail baÅarıyla kaydedildiÄinde çaÄrılır (isteÄi tekrarlar). 362 */ 363function esimRequireMail(onSaved) { 364 365 var T = (window.lang && window.lang.mailWall) ? window.lang.mailWall : {}; 366 var BASE = window.esimBase || ''; 367 368 function esc(v) { 369 return String(v == null ? '' : v) 370 .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') 371 .replace(/"/g, '"').replace(/'/g, '''); 372 } 373 374 var html = 375 '<p class="mb-2">' + esc(T.desc || '') + '</p>' + 376 '<input type="email" id="esimMailWallInput" class="form-control" autocomplete="email" ' + 377 'inputmode="email" placeholder="' + esc(T.mail || '') + '" aria-label="' + esc(T.mail || '') + '">' + 378 '<div id="esimMailWallErr" class="text-danger mt-2" style="display:none;" role="alert" aria-live="polite"></div>'; 379 380 boxup(html, { 381 'confirm': true, 382 'title': T.title || '', 383 'textOk': T.save || 'Ok', 384 'textCancel': T.cancel || 'Cancel' 385 }, function (ok) { 386 387 if (ok !== true) { 388 return; 389 } 390 391 var mail = (jQuery('#esimMailWallInput').val() || '').trim(); 392 393 /* Format kontrolü sunucuda da var (UserProcess::updateMail SSoT); buradaki 394 yalnız kullanıcıya anında geri bildirim içindir. */ 395 if (mail === '' || mail.indexOf('@') < 1 || mail.lastIndexOf('.') < mail.indexOf('@') + 2) { 396 esimRequireMail(onSaved); 397 jQuery('#esimMailWallErr').text(T.errMail || '').show(0); 398 return; 399 } 400 401 jQuery.ajax({ 402 url: BASE + '/profile/mail?format=json', 403 method: 'POST', 404 data: {mail: mail}, 405 dataType: 'json' 406 }).done(function (r) { 407 408 if (r && r.result === 'ok') { 409 jQuery('#boxUpModal').fadeOut(100).remove(); 410 if (typeof onSaved === 'function') { 411 onSaved(mail); 412 } 413 return; 414 } 415 416 /* Hata (ör. e-posta baÅka hesapta kayıtlı) â kutuyu sunucunun mesajıyla 417 tekrar aç; kullanıcı sepetini kaybetmeden baÅka adres deneyebilsin. */ 418 esimRequireMail(onSaved); 419 jQuery('#esimMailWallInput').val(mail); 420 jQuery('#esimMailWallErr') 421 .text((r && (r.error || r.description)) || T.errGeneric || '') 422 .show(0); 423 424 }).fail(function () { 425 esimRequireMail(onSaved); 426 jQuery('#esimMailWallInput').val(mail); 427 jQuery('#esimMailWallErr').text(T.errGeneric || '').show(0); 428 }); 429 430 }); 431 432 /* boxup içeriÄi DOM'a eklendikten sonra odak: kullanıcı doÄrudan yazmaya baÅlasın. */ 433 setTimeout(function () { 434 jQuery('#esimMailWallInput').trigger('focus'); 435 }, 320); 436} 437 438function boxup(string, args, callback) { 439 440 var defaultArray = 441 { 442 'confirm': false, 443 'textOk': 'Ok', 444 'textCancel': 'Cancel', 445 'classs': "", 446 'close': 0, 447 'title': "" 448 449 } 450 451 if (args) { 452 for (var index in defaultArray) { 453 if (typeof args[index] == "undefined") { 454 args[index] = defaultArray[index]; 455 } 456 } 457 } else { 458 args = defaultArray; 459 } 460 461 jQuery('#boxUpModal').hide(200).remove(); 462 463 newHtml = '<div class="modal modal-new fade show ' + args['classs'] + '" id="boxUpModal" tabindex="-1" role="dialog" aria-modal="true"><div class="modal-dialog" style="display:none;" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="staticBackdropLabel">' + args['title'] + '</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div>';
464 newHtml = newHtml + '<div class="modal-body"><div class="text">' + string + '</div></div>'; 465 newHtml = newHtml + '<div class="boxupButtons modal-footer"></div>'; 466 newHtml = newHtml + '</div></div></div>'; 467 468 jQuery('body').append(newHtml); 469 470 if (args['confirm']) { 471 jQuery('.boxupButtons').append('<button class="btn btn-primary" value="ok">' + args['textOk'] + '</button>'); 472 jQuery('.boxupButtons').append('<button class="btn btn-danger" value="cancel">' + args['textCancel'] + '</button>'); 473 } else { 474 if (args['textOk']) { 475 jQuery('.boxupButtons').append('<button class="btn btn-primary" value="ok">' + args['textOk'] + '</button>'); 476 } else { 477 jQuery('.boxupButtons').append('<button class="btn btn-primary" value="ok">Tamam</button>'); 478 } 479 } 480 481 jQuery('#boxUpModal').show(0); 482 jQuery('#boxUpModal .modal-dialog').fadeIn(300); 483 484 jQuery(document).on('click', '#boxUpModal .btn-close', function () { 485 jQuery('#boxUpModal').fadeOut(100).remove(); 486 callback(false); 487 }); 488 489 $(document).keydown(function (e) { 490 if ($('#boxUpModal').is(':visible')) { 491 if (e.keyCode == 13) { 492 $('#boxUpModal .boxupButtons button[value="ok"]').click(); 493 } 494 if (e.keyCode == 27) { 495 $('#boxUpModal .boxupButtons button[value="cancel"]').click(); 496 } 497 } 498 }); 499 500 jQuery(document).on('click', '#boxUpModal .boxupButtons button', function () { 501 502 if (callback) { 503 var wButton = jQuery(this).attr("value"); 504 if (wButton == 'ok') { 505 if (args) { 506 callback(true); 507 } else { 508 callback(true); 509 } 510 } else if (wButton == 'cancel') { 511 callback(false); 512 } 513 } 514 515 jQuery('#boxUpModal').fadeOut(100, function () { 516 // jQuery('#boxUpModal').remove(); 517 }); 518 519 callback = ""; 520 }); 521 522 if (args['close'] > 0) { 523 setTimeout(function () { 524 jQuery('#boxUpModal').fadeOut(100).remove(); 525 }, args['close']); 526 } 527 528} 529 530 531/* BUY_CONTEXT_v1 (2026-08-26) â "bu eSIM hangi ülke araması / hangi sayfa üzerinden 532 * alındı?" sorusunun TEK yakalama noktası. Bu bilgi sunucuda hiçbir yerde yoktu: 533 * sepete ekleme bir AJAX çaÄrısıdır, sunucu yalnız /basket/add/<id> yolunu görür, 534 * kullanıcının o an hangi sayfada olduÄunu GÃREMEZ. Bu yüzden baÄlam istemcide 535 * üretilir ve sepet satırına yazılır; oradan satıÅa (_sale.context) kopyalanır. 536 * 537 * Biçim (admin tarafındaki okuyucu: buyContextFacts() / buyContextBadge()): 538 * q=<kullanıcının yazdıÄı arama>|s=<seçtiÄi ülke slug'ı>|p=</sayfa/yolu> 539 * Alanlar opsiyoneldir. Arama terimi sessionStorage'da yaÅar (arama kutusu 540 * multi-select.js'te; kullanıcı arayıp ülke sayfasına gidiyor, alım orada oluyor). 541 */ 542function esimBuyContext() { 543 var parts = []; 544 try { 545 var term = (sessionStorage.getItem('esimSearchTerm') || '').trim(); 546 var slug = (sessionStorage.getItem('esimSearchSlug') || '').trim(); 547 if (term) { parts.push('q=' + term.slice(0, 60)); } 548 if (slug) { parts.push('s=' + slug.slice(0, 40)); } 549 } catch (e) { /* private mode / storage kapalı â baÄlam kaybı ödemeyi ETKİLEMEZ */ } 550 551 try { 552 var path = (location.pathname || '/').replace(/\/+$/, '') || '/'; 553 parts.push('p=' + path.slice(0, 80)); 554 } catch (e) {} 555 556 return parts.join('|'); 557} 558 559/* Basket Process */ 560/* QUICKBUY_COUPON_FIELD_v1 â kupon doÄrulama isteÄinin TEK evi. İki yüzey kullanır: 561 * /payment sihirbazı (payment.php checkCouponCode) ve hızlı satın al modalı (footer.php). 562 * Uç (/payment/checkCoupon) kuponu SUNUCUDA doÄrular ve sepet oturumuna yazar; toplamlar 563 * yanıttan ve sonraki /payment/add turundan gelir â burada para hesabı YOK. Kod ham gelir, 564 * URL kaçıÅı burada tek yerde. validator:false â sayfadaki baÅka bir formun boÅ alanı
565 * kupon denemesini engellememeli (istek kendi verisini taÅımaz). */ 566function couponCheck(code, callback) { 567 $(document).request({ 568 'url': sa + "/payment/checkCoupon/" + encodeURIComponent(code), 569 'returnAlert': false, 570 'method': 'GET', 571 'validator': false 572 }, callback); 573} 574 575function addBasket(id, returnAlert, callback) { 576 577 if (typeof returnAlert == "undefined") { 578 returnAlert = false; 579 } 580 581 // GA4: select_item + add_to_cart (item data resolved from the page's product cards). 582 try { if (window.GA4) { GA4.addToCart(id); } } catch (e) {} 583 584 /* ctx boÅ olabilir (storage kapalı, bilinmeyen sayfa) â sunucu boÅu sorunsuz kabul 585 eder, ödeme akıÅı baÄlamdan BAÄIMSIZDIR. */ 586 var __ctx = ""; 587 try { __ctx = esimBuyContext(); } catch (e) {} 588 589 $(this).request({ 590 "url": sa + "/basket/add/" + id + (__ctx ? "?ctx=" + encodeURIComponent(__ctx) : ""), 591 'returnAlert': returnAlert, 592 "method": "get" 593 }, function (response) { 594 595 if (response.result === "ok") { 596 if (callback) { 597 callback(response); 598 } 599 600 initPayment(); 601 602 } else if (response.result === "error") { 603 /* Transient network failure (request.js error-handler -> {'result':'error'}, no 604 * .error/.title) â NOT a real server response. Do not fire the old hardcoded 605 * blocking alert('Could not add to cart.'); show a graceful, localized, dismissible 606 * message with a retry option instead (real server 'fail' messages still fall 607 * through to the branch below, untouched). */ 608 boxup(netErrors.network, { 609 'confirm': true, 610 'textOk': netErrors.retry 611 }, function (retryConfirmed) { 612 if (retryConfirmed) { 613 addBasket(id, returnAlert, callback); 614 } 615 }); 616 } else { 617 if (response.error && response.error.indexOf("User") >= 0) { 618 window.location = sa + '/register'; 619 } else { 620 alert(response.error ? response.error : (response.title ? response.title : 'Could not add to cart.')); 621 } 622 } 623 }); 624 625} 626
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.