PageSourceSearch

https://www.eslfast.com/js/time_spend_on_page.js

js eslfast.com collected 2026-10-02 04:59:11 UTC 60,298 bytes, 2,281 lines download raw bytes

1getMyCookie = function (name) {
2    var value = document.cookie.split(/;\s*/).find((row) => row.startsWith(name));
3    if (value) {
4        return decodeURIComponent(value.split("=")[1]);
5    }
6    return "";
7};
8
9
10let curr_page_url = window.location.href;
11let curr_content_id = window.location.hostname.replace(/[^\/]*:\/\//, "").replace(/^www\./, "").replace(/(.*)\.[^\.]+$/, "$1") + "_" + document.location.pathname.replace(/^\//, "").replaceAll(/\//g, "_").replace(/\.html?$/, "");
12let curr_user_login_token = (new URLSearchParams(window.location.search).get("token") || getMyCookie("login_token"));
13var curr_user_actv_sts = 0;
14var page_key =Math.floor(Date.now() + Math.random());
15//alert(document.readyState);
16if(document.readyState === 'loading') {
17  localStorage.setItem("page_key", page_key);
18//  alert(page_key);
19}
20
21Date.prototype.today = function () { 
22    return this.getFullYear() +"-"+(((this.getMonth()+1) < 10)?"0":"") + (this.getMonth()+1) +"-"+ ((this.getDate() < 10)?"0":"") + this.getDate() ;
23}
24
25// For the time now
26Date.prototype.timeNow = function () {
27     return ((this.getHours() < 10)?"0":"") + this.getHours() +":"+ ((this.getMinutes() < 10)?"0":"") + this.getMinutes() +":"+ ((this.getSeconds() < 10)?"0":"") + this.getSeconds();
28}
29
30jQuery.ajax({
31    type: 'POST',
32    dataType : 'json',
33    url: `https://www.eslfast.com/membership/api/valid-token/${curr_user_login_token}`
34}).done(function (res) {
35    //update_active_on_page(curr_page_url, curr_content_id, curr_user_login_token);
36    
37    if ((res.token_key != '') /*&& (res.memb_status == 1)*/) { 
38        curr_user_actv_sts = 1;   
39        if(res.memb_status != 1){
40          console.log('Adblock detected or not1');
41          startAntiAdblock();
42        }  
43        setInterval(function () {
44//            let curr_date = new Date().today();
45//            let datetime = new Date().today() + " " + new Date().timeNow();
46//            console.log(datetime);
47            update_active_on_page(curr_page_url, curr_content_id, curr_user_login_token);
48        }, 130000);     
49    }else{
50      
51      console.log('Adblock detected or not2');
52      startAntiAdblock();
53    }
54}).fail(function (jqXHR, textStatus) {
55    console.log('Adblock detected or not3');
56      startAntiAdblock();
57});
58update_active_on_page = (curr_page_url, curr_content_id, curr_user_login_token) => {
59  let curr_date = new Date().today();
60  let curr_datetime = new Date().today() + " " + new Date().timeNow();
61  jQuery.ajax({
62    type: 'POST',
63    dataType : 'json',
64    data:{curr_page_url:curr_page_url, curr_content_id:curr_content_id, curr_user_login_token:curr_user_login_token,curr_date: curr_date, curr_datetime:curr_datetime, page_key:page_key},
65    url: `https://www.eslfast.com/membership/api/time-spend-course/`
66    }).done(function (res) {
67
68    }).fail(function (jqXHR, textStatus) {
69
70    });
71} 
72// Every 3 min 1reward
73let rewardTimer = null;
74let confirmTimer = null;
75
76let lastActivity = Date.now();
77let popupShowing = false;
78let rewardStopped = false;
79
80// User activity events
81[
82    "mousemove",
83    "mousedown",
84    "click",
85    "scroll",
86    "keydown",
87    "touchstart"
88].forEach(function (event) {
89    document.addEventListener(event, function () {
90        lastActivity = Date.now();
91    }, true);
92});
93
94// User switches tab
95document.addEventListener("visibilitychange", function () {
96    if (!document.hidden) {
97        lastActivity = Date.now();
98    }
99});
100
101// Start reward timer
102rewardTimer = setInterval(checkReward, 180000); // Every 3 min
103
104function checkReward() {
105
106    if (rewardStopped)
107        return;
108
109    // inactive for 7 min
110    let inactiveTime = Date.now() - lastActivity;
111
112    if (inactiveTime >= 420000) {
113
114        if (!popupShowing) {
115            askUserActive();
116        }
117
118        return;
119    }
120
121    every3minReward(
122        curr_page_url,
123        curr_content_id,
124        curr_user_login_token
125    );
126}
127
128function askUserActive() {
129    if(curr_user_actv_sts == 0){
130      return;
131    }
132    popupShowing = true;
133
134    showDialog({
135        title: "Activity Check",
136        message: "You've been inactive for a while.<br><br>Click <b>Continue</b> to keep earning rewards.",
137        okText: "Continue",
138        showCancel: true,
139
140        onOk: function () {
141
142            popupShowing = false;
143
144            lastActivity = Date.now();
145
146            every3minReward(
147                curr_page_url,
148                curr_content_id,
149                curr_user_login_token
150            );
151        },
152
153        onCancel: function () {
154
155            popupShowing = false;
156
157            stopRewardSystem();
158        }
159    });
160
161}
162
163function stopRewardSystem() {
164
165    rewardStopped = true;
166
167    clearInterval(rewardTimer);
168
169    showDialog({
170        title: "Reward Stopped",
171        message: "Reward tracking has been stopped because no activity was detected.",
172        okText: "Close",
173        showCancel: false
174    });
175}
176
177function every3minReward(curr_page_url, curr_content_id, curr_user_login_token) {
178
179    let curr_date = new Date().today();
180
181    $.ajax({
182        type: "POST",
183        dataType: "json",
184        url: "https://www.eslfast.com/membership/api/everyThreeMinReward/",
185        data: {
186            curr_page_url,
187            curr_content_id,
188            curr_user_login_token,
189            curr_date,
190            page_key
191        }
192    })
193    .done(function(res){
194
195        if(res.status === "error"){
196
197          const storageKey = "every3minRewardErrorShown";
198            const now = Date.now();
199
200            // 10 minutes
201            const showAgainAfter = 120 * 60 * 1000;
202
203            const lastShown = localStorage.getItem(storageKey);
204
205            // Show only if never shown OR 10 minutes have passed
206            if (!lastShown || (now - parseInt(lastShown)) >= showAgainAfter) {
207              showInvalidLoginPopup(
208                  res.msg +
209                  `<div>
210                      <a href="https://www.eslfast.com/"
211                        style="display:inline-block;padding:12px 24px;background:#ff4d4d;color:#fff;text-decoration:none;border-radius:10px;font-weight:bold;">
212                          Sign In Now
213                      </a>
214                  </div>`
215              );
216              // Save current time
217              localStorage.setItem(storageKey, now);
218            }
219        }
220
221    });
222}
223
224function showDialog(options = {}) {
225
226    // Remove old dialog if exists
227    const old = document.getElementById("customDialog");
228    if (old) old.remove();
229
230    const dialog = document.createElement("div");
231    dialog.id = "customDialog";
232
233    dialog.innerHTML = `
234        <div class="dialog-overlay"></div>
235
236        <div class="dialog-box">
237
238            <div class="dialog-title">${options.title || "Message"}</div>
239
240            <div class="dialog-body">
241                ${options.message || ""}
242            </div>
243
244            <div class="dialog-footer">
245                ${
246                    options.showCancel !== false
247                    ? `<button class="dialog-btn dialog-cancel">Cancel</button>`
248                    : ""
249                }
250
251                <button class="dialog-btn dialog-ok">
252                    ${options.okText || "OK"}
253                </button>
254            </div>
255
256        </div>
257    `;
258
259    document.body.appendChild(dialog);
260
261    if (!document.getElementById("dialogStyle")) {
262
263        const style = document.createElement("style");
264
265        style.id = "dialogStyle";
266
267        style.innerHTML = `
268        #customDialog{
269            position:fixed;
270            inset:0;
271            z-index:999999;
272        }
273
274        .dialog-overlay{
275            position:absolute;
276            inset:0;
277            background:rgba(0,0,0,.45);
278        }
279
280        .dialog-box{
281            position:absolute;
282            left:50%;
283            top:50%;
284            transform:translate(-50%,-50%);
285            width:380px;
286            max-width:90%;
287            background:#fff;
288            border-radius:10px;
289            overflow:hidden;
290            font-family:Arial,sans-serif;
291            box-shadow:0 10px 30px rgba(0,0,0,.3);
292        }
293
294        .dialog-title{
295            padding:15px;
296            font-size:18px;
297            font-weight:bold;
298            border-bottom:1px solid #ddd;
299        }
300
301        .dialog-body{
302            padding:20px;
303            line-height:1.5;
304        }
305
306        .dialog-footer{
307            padding:15px;
308            text-align:right;
309            border-top:1px solid #ddd;
310        }
311
312        .dialog-btn{
313            padding:8px 20px;
314            margin-left:10px;
315            cursor:pointer;
316            border:none;
317            border-radius:5px;
318        }
319
320        .dialog-ok{
321            background:#0d6efd;
322            color:#fff;
323        }
324
325        .dialog-cancel{
326            background:#6c757d;
327            color:#fff;
328        }
329        `;
330
331        document.head.appendChild(style);
332    }
333
334    dialog.querySelector(".dialog-ok").onclick = function () {
335
336        dialog.remove();
337
338        if (typeof options.onOk === "function")
339            options.onOk();
340    };
341
342    const cancel = dialog.querySelector(".dialog-cancel");
343
344    if (cancel) {
345        cancel.onclick = function () {
346
347            dialog.remove();
348
349            if (typeof options.onCancel === "function")
350                options.onCancel();
351        };
352    }
353}
354//------
355
356//const chat_socket = 'https://socket.eslfast.com/';
357//const socket = io(chat_socket, {
358//                query: { userId: curr_user_login_token, pageId: curr_content_id  }
359//            });
360//            
361//socket.emit('joinRoom', curr_content_id);
362//
363//socket.on('userOnline', (data) => {
364//    const { userId, pageId } = data;
365//    alert(`User ${userId} is now online ${pageId}`);
366//});
367//socket.on('userOffline', (data) => {
368//    const { userId, pageId } = data;
369//    alert(`User ${userId} is now offline ${pageId} `);
370//});
371
372 function completePageTask(point = 5){
373    // alert('vv : '+ curr_user_actv_sts);
374    let curr_datetime = new Date().today() + " " + new Date().timeNow();
375    if(curr_user_actv_sts == 1){
376        jQuery.ajax({
377            type: 'POST',
378            dataType : 'json',
379            data:{curr_page_url:curr_page_url, 
380                curr_content_id:curr_content_id, 
381                curr_user_login_token:curr_user_login_token,
382                curr_datetime:curr_datetime, 
383                page_key:page_key,
384                point:point
385              },
386            url: `https://www.eslfast.com/membership/api/page-task-complete/`
387            }).done(function (res) {
388                if(res.status=="success"){
389                    showLessonCompleteAnimation(res.total_point, point);
390                    //If promte
391                    if(res.promot_status == 1){
392                        setTimeout(function() {
393                            let parentDivxc = $('.lesson-complete-popup').parent('div');
394                            if (parentDivxc.length) {
395                                parentDivxc.remove();
396                            }
397                            const audiox = new Audio('https://www.eslfast.com/js/sound/applause_sound.mp3');
398                            audiox.play().catch(err => {
399                              console.warn('Audio permission denied:', err.message);
400                            });
401                            
402                            let prom_txt = `${res.medal_tire} unlocked! Your excellence is now officially tiered .<img src='https://www.eslfast.com/js/img/Medal_Tier_${res.medal_tire}.png' width='50' />`;
403                            showLessonCompleteAnimationText(prom_txt);                            
404                        }, 1000);
405                    }
406                }else{
407                  if (res && typeof res === 'object' && 'msg' in res) {
408                      if(res.msg == "Already completed"){
409                        showAlreadyCompletedPopup();
410                        deleteCookieIfPresent('pageQuestionAnswer');
411                      }else{
412                        showInvalidLoginPopup(res.msg);
413                      }
414                  }else{
415                    showTryAgainPopup();
416                  }
417                }
418            }).fail(function (jqXHR, textStatus) {
419
420            });
421    }
422 }
423
424 //point for dictation
425 function completeDictPageTask(point = 5){
426    // alert('vv : '+ curr_user_actv_sts);
427    let curr_datetime = new Date().today() + " " + new Date().timeNow();
428    // if(curr_user_actv_sts == 1){
429        jQuery.ajax({
430            type: 'POST',
431            dataType : 'json',
432            data:{curr_page_url:curr_page_url, 
433                curr_content_id:curr_content_id, 
434                curr_user_login_token:curr_user_login_token,
435                curr_datetime:curr_datetime, 
436                page_key:page_key,
437                point:point
438              },
439            url: `https://www.eslfast.com/membership/api/page-task-complete/`
440            }).done(function (res) {
441                if(res.status=="success"){
442                    showLessonCompleteAnimation(res.total_point, point);
443                    //If promte
444                    if(res.promot_status == 1){
445                        setTimeout(function() {
446                            let parentDivxc = $('.lesson-complete-popup').closest('div');
447                            if (parentDivxc.length) {
448                                parentDivxc.remove();
449                            }
450                            const audiox = new Audio('https://www.eslfast.com/js/sound/applause_sound.mp3');
451                            audiox.play().catch(err => {
452                              console.warn('Audio permission denied:', err.message);
453                            });
454                            
455//                            let prom_txt = `${res.medal_tire} unlocked! Your excellence is now officially tiered .<img src='https://www.eslfast.com/js/img/Medal_Tier_${res.medal_tire}.png' width='50' />`;
456//                            showLessonCompleteAnimationText(prom_txt);     
457                            showTierPromotionPopup(res.medal_tire);
458                        }, 1000);
459                    }
460                }else{
461                  if (res && typeof res === 'object' && 'msg' in res) {
462                      if(res.msg == "Already completed"){
463                        showAlreadyCompletedPopup();
464                        deleteCookieIfPresent('pageQuestionAnswer');
465                      }else{
466                        showInvalidLoginPopup(res.msg);
467                      }
468                  }else{
469                    showTryAgainPopup();
470                  }
471                }
472            }).fail(function (jqXHR, textStatus) {
473
474            });
475    // }
476 }
477
478
479
480function showLessonCompleteAnimation(total_point, curr_point = 5) {
481  // Try to play audio
482  const audio = new Audio('https://www.eslfast.com/js/sound/sound1.mp3');
483  audio.play().catch(err => {
484    console.warn('Audio permission denied:', err.message);
485  });
486
487  // Random praise phrase
488  const phrases = ["Great Job!", "Well Done!", "Awesome!", "Amazing!", "Excellent!", "Great!"];
489  const randomPhrase = phrases[Math.floor(Math.random() * phrases.length)];
490
491  // Create overlay
492  const overlay = document.createElement('div');
493  Object.assign(overlay.style, {
494    position: 'fixed',
495    top: 0,
496    left: 0,
497    width: '100vw',
498    height: '100vh',
499    backgroundColor: 'rgba(0,0,0,0.5)',
500    display: 'flex',
501    alignItems: 'center',
502    justifyContent: 'center',
503    zIndex: 9999,
504    padding: '20px',
505  });
506
507  // Create popup
508  const popup = document.createElement('div');
509  popup.className = 'lesson-complete-popup';
510  Object.assign(popup.style, {
511    background: 'linear-gradient(135deg, #fff8dc, #e0ffe0)',
512    borderRadius: '20px',
513    padding: '30px 20px',
514    boxShadow: '0 0 30px rgba(0,0,0,0.3)',
515    textAlign: 'center',
516    position: 'relative',
517    animation: 'bounceIn 0.8s ease-out, glowPulse 3s infinite alternate',
518    maxWidth: '90%',
519    width: '400px',
520    fontFamily: 'Segoe UI, sans-serif',
521    color: '#1a1a1a',
522    overflow: 'hidden',
523  });
524
525  // Character Image
526  const character = document.createElement('img');
527  character.src = 'https://www.eslfast.com/js/img/susan3.jpg';
528  Object.assign(character.style, {
529    width: '100px',
530    borderRadius: '50%',
531    animation: 'floatSwing 3s ease-in-out infinite',
532    marginBottom: '15px',
533    display: 'block',
534    marginLeft: 'auto',
535    marginRight: 'auto'
536  });
537
538  // Heading
539  const heading = document.createElement('h2');
540  heading.innerText = '🎉 Completed!';
541  Object.assign(heading.style, {
542    marginBottom: '15px',
543    fontSize: '28px',
544    color: '#006400',
545    textAlign: 'center',
546  });
547
548  // Random praise
549  const praise = document.createElement('p');
550  praise.innerText = randomPhrase;
551  Object.assign(praise.style, {
552    fontSize: '22px',
553    color: '#222',
554    fontWeight: 'bold',
555    marginBottom: '20px',
556    textAlign: 'center',
557  });
558
559  // Subtext
560  const subtext = document.createElement('p');
561  subtext.innerHTML = `<div style="text-align:center;">
562   ${curr_point > 0 ? `You’ve earned <strong>⚡${curr_point} points</strong>` : ''} 
563   ${total_point > 0 ? `<br>and <strong>${total_point} total points</strong> so far!` : ''}
564</div>`;
565  Object.assign(subtext.style, {
566    fontSize: '18px',
567    color: '#333',
568    marginBottom: '20px',
569    textAlign: 'center',
570  });
571
572  // Close button
573  const closeBtn = document.createElement('div');
574  closeBtn.innerHTML = '&times;';
575  Object.assign(closeBtn.style, {
576    position: 'absolute',
577    top: '0px',
578    right: '7px',
579    fontSize: '26px',
580    color: '#666',
581    cursor: 'pointer',
582    border: '1px dotted',
583    padding: '0px 8px 0px 8px'
584  });
585  closeBtn.onclick = () => overlay.remove();
586
587  // Append elements
588  popup.appendChild(closeBtn);
589  popup.appendChild(character);
590  popup.appendChild(heading);
591  popup.appendChild(praise);
592  popup.appendChild(subtext);
593  overlay.appendChild(popup);
594  document.body.appendChild(overlay);
595
596  // Confetti animation
597  for (let i = 0; i < 50; i++) {
598    const confetti = document.createElement('div');
599    Object.assign(confetti.style, {
600      position: 'fixed',
601      top: '50%',
602      left: '50%',
603      width: '8px',
604      height: '8px',
605      backgroundColor: `hsl(${Math.random()*360}, 100%, 50%)`,
606      borderRadius: '50%',
607      transform: `translate(-50%, -50%)`,
608      animation: `confettiFly ${1 + Math.random()*1.5}s ease-out forwards`,
609      zIndex: 10000
610    });
611    confetti.style.setProperty('--x', `${(Math.random() - 0.5) * 400}px`);
612    confetti.style.setProperty('--y', `${(Math.random() - 0.5) * 400}px`);
613    document.body.appendChild(confetti);
614    setTimeout(() => confetti.remove(), 3000);
615  }
616
617  // Style animations
618  const style = document.createElement('style');
619  style.textContent = `
620    @keyframes bounceIn {
621      0% { transform: scale(0.7); opacity: 0; }
622      80% { transform: scale(1.1); opacity: 1; }
623      100% { transform: scale(1); }
624    }
625    @keyframes floatSwing {
626      0%, 100% { transform: translateY(0) rotate(0deg); }
627      50% { transform: translateY(-10px) rotate(3deg); }
628    }
629    @keyframes glowPulse {
630      0% { box-shadow: 0 0 10px #aaffaa; }
631      100% { box-shadow: 0 0 30px #55ff55; }
632    }
633    @keyframes confettiFly {
634      to {
635        transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) rotate(720deg);
636        opacity: 0;
637      }
638    }
639
640    /* Responsive */
641    @media (max-width: 768px) {
642      .lesson-complete-popup {
643        width: 90% !important;
644        padding: 20px 15px !important;
645      }
646    }
647
648    @media (max-width: 480px) {
649      .lesson-complete-popup {
650        width: 95% !important;
651        font-size: 16px !important;
652      }
653    }
654  `;
655  document.head.appendChild(style);
656}
657
658function showLessonCompleteAnimationText(txt_msg) {
659  // Try to play audio
660  const audio = new Audio('https://www.eslfast.com/js/sound/sound1.mp3');
661  audio.play().catch(err => {
662    console.warn('Audio permission denied:', err.message);
663  });
664
665  // Random praise phrase
666  const phrases = ["Great Job!", "Well Done!", "Awesome!", "Amazing!", "Excellent!", "Great!"];
667  const randomPhrase = phrases[Math.floor(Math.random() * phrases.length)];
668
669  // Create overlay
670  const overlay = document.createElement('div');
671  Object.assign(overlay.style, {
672    position: 'fixed',
673    top: 0,
674    left: 0,
675    width: '100vw',
676    height: '100vh',
677    backgroundColor: 'rgba(0,0,0,0.5)',
678    display: 'flex',
679    alignItems: 'center',
680    justifyContent: 'center',
681    zIndex: 9999,
682    padding: '20px',
683  });
684
685  // Create popup
686  const popup = document.createElement('div');
687  popup.className = 'lesson-complete-popup';
688  Object.assign(popup.style, {
689    background: 'linear-gradient(135deg, #fff8dc, #e0ffe0)',
690    borderRadius: '20px',
691    padding: '30px 20px',
692    boxShadow: '0 0 30px rgba(0,0,0,0.3)',
693    textAlign: 'center',
694    position: 'relative',
695    animation: 'bounceIn 0.8s ease-out, glowPulse 3s infinite alternate',
696    maxWidth: '90%',
697    width: '400px',
698    fontFamily: 'Segoe UI, sans-serif',
699    color: '#1a1a1a',
700    overflow: 'hidden',
701  });
702
703  // Character Image
704  const character = document.createElement('img');
705  character.src = 'https://www.eslfast.com/js/img/susan3.jpg';
706  Object.assign(character.style, {
707    width: '100px',
708    borderRadius: '50%',
709    animation: 'floatSwing 3s ease-in-out infinite',
710    marginBottom: '15px',
711    display: 'block',
712    marginLeft: 'auto',
713    marginRight: 'auto'
714  });
715
716  // Heading
717  const heading = document.createElement('h2');
718  heading.innerText = '🎉 Completed!';
719  Object.assign(heading.style, {
720    marginBottom: '15px',
721    fontSize: '28px',
722    color: '#006400',
723    textAlign: 'center',
724  });
725
726  // Random praise
727  const praise = document.createElement('p');
728  praise.innerText = randomPhrase;
729  Object.assign(praise.style, {
730    fontSize: '22px',
731    color: '#222',
732    fontWeight: 'bold',
733    marginBottom: '20px',
734    textAlign: 'center',
735  });
736
737  // Subtext
738  const subtext = document.createElement('p');
739  subtext.innerHTML = `<div style="text-align:center;">${txt_msg}</div>`;
740  Object.assign(subtext.style, {
741    fontSize: '18px',
742    color: '#333',
743    marginBottom: '20px',
744    textAlign: 'center',
745  });
746
747  // Close button
748  const closeBtn = document.createElement('div');
749  closeBtn.innerHTML = '&times;';
750  Object.assign(closeBtn.style, {
751    position: 'absolute',
752    top: '0px',
753    right: '7px',
754    fontSize: '26px',
755    color: '#666',
756    cursor: 'pointer',
757    border: '1px dotted',
758    padding: '0px 8px 0px 8px'
759  });
760  closeBtn.onclick = () => overlay.remove();
761
762  // Append elements
763  popup.appendChild(closeBtn);
764  popup.appendChild(character);
765  popup.appendChild(heading);
766  popup.appendChild(praise);
767  popup.appendChild(subtext);
768  overlay.appendChild(popup);
769  document.body.appendChild(overlay);
770
771  // Confetti animation
772  for (let i = 0; i < 50; i++) {
773    const confetti = document.createElement('div');
774    Object.assign(confetti.style, {
775      position: 'fixed',
776      top: '50%',
777      left: '50%',
778      width: '8px',
779      height: '8px',
780      backgroundColor: `hsl(${Math.random()*360}, 100%, 50%)`,
781      borderRadius: '50%',
782      transform: `translate(-50%, -50%)`,
783      animation: `confettiFly ${1 + Math.random()*1.5}s ease-out forwards`,
784      zIndex: 10000
785    });
786    confetti.style.setProperty('--x', `${(Math.random() - 0.5) * 400}px`);
787    confetti.style.setProperty('--y', `${(Math.random() - 0.5) * 400}px`);
788    document.body.appendChild(confetti);
789    setTimeout(() => confetti.remove(), 3000);
790  }
791
792  // Style animations
793  const style = document.createElement('style');
794  style.textContent = `
795    @keyframes bounceIn {
796      0% { transform: scale(0.7); opacity: 0; }
797      80% { transform: scale(1.1); opacity: 1; }
798      100% { transform: scale(1); }
799    }
800    @keyframes floatSwing {
801      0%, 100% { transform: translateY(0) rotate(0deg); }
802      50% { transform: translateY(-10px) rotate(3deg); }
803    }
804    @keyframes glowPulse {
805      0% { box-shadow: 0 0 10px #aaffaa; }
806      100% { box-shadow: 0 0 30px #55ff55; }
807    }
808    @keyframes confettiFly {
809      to {
810        transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) rotate(720deg);
811        opacity: 0;
812      }
813    }
814
815    /* Responsive */
816    @media (max-width: 768px) {
817      .lesson-complete-popup {
818        width: 90% !important;
819        padding: 20px 15px !important;
820      }
821    }
822
823    @media (max-width: 480px) {
824      .lesson-complete-popup {
825        width: 95% !important;
826        font-size: 16px !important;
827      }
828    }
829  `;
830  document.head.appendChild(style);
831}
832
833function showAlreadyCompletedPopup() {
834  // Play audio
835  // const audio = new Audio('https://www.eslfast.com/js/sound/sound2.mp3');
836  // audio.play().catch(err => {
837  //   console.warn('Audio blocked:', err.message);
838  // });
839
840  // Create overlay
841  const overlay = document.createElement('div');
842  Object.assign(overlay.style, {
843    position: 'fixed',
844    top: '0',
845    left: '0',
846    width: '100vw',
847    height: '100vh',
848    backgroundColor: 'rgba(0,0,0,0.5)',
849    display: 'flex',
850    alignItems: 'center',
851    justifyContent: 'center',
852    zIndex: '9999',
853    padding: '20px',
854  });
855
856  // Create popup box
857  const popup = document.createElement('div');
858  popup.className = 'already-complete-popup';
859  Object.assign(popup.style, {
860    background: 'linear-gradient(135deg, #003030, #004040)',
861    borderRadius: '20px',
862    padding: '30px 20px',
863    boxShadow: '0 0 30px rgba(0,0,0,0.4)',
864    position: 'relative',
865    animation: 'slideBounce 0.8s ease-out',
866    maxWidth: '90%',
867    width: '400px',
868    color: '#ffffff',
869    textAlign: 'center',
870    display: 'flex',
871    flexDirection: 'column',
872    alignItems: 'center',
873    fontFamily: 'Segoe UI, sans-serif',
874  });
875
876  // Icon
877  const mascot = document.createElement('div');
878  mascot.innerText = '✅';
879  Object.assign(mascot.style, {
880    fontSize: '50px',
881    animation: 'pulseGlow 1.5s infinite',
882    marginBottom: '15px',
883    textAlign: 'center'
884  });
885
886  // Title
887  const title = document.createElement('h2');
888  title.innerText = 'Already Completed!';
889  Object.assign(title.style, {
890    fontSize: '26px',
891    color: '#00ffaa',
892    marginBottom: '10px',
893    textAlign: 'center'
894  });
895
896  // Message
897  const message = document.createElement('p');
898  message.innerHTML = 'You’ve already finished this activity.<br>No need to do it again!';
899  Object.assign(message.style, {
900    fontSize: '18px',
901    color: '#eeeeee',
902    marginBottom: '15px',
903    lineHeight: '1.5',
904    textAlign: 'center'
905  });
906
907  // Close Button
908  const closeBtn = document.createElement('div');
909  closeBtn.innerHTML = '&times;';
910  Object.assign(closeBtn.style, {
911    position: 'absolute',
912    top: '0px',
913    right: '7px',
914    fontSize: '26px',
915    color: '#00ffaa',
916    cursor: 'pointer',
917    textAlign: 'center',
918  });
919  closeBtn.onclick = () => overlay.remove();
920
921  // Assemble popup
922  popup.appendChild(closeBtn);
923  popup.appendChild(mascot);
924  popup.appendChild(title);
925  popup.appendChild(message);
926  overlay.appendChild(popup);
927  document.body.appendChild(overlay);
928
929  // Animations and responsive styles
930  const style = document.createElement('style');
931  style.textContent = `
932    @keyframes pulseGlow {
933      0% { transform: scale(1); text-shadow: 0 0 5px #00ffaa; }
934      50% { transform: scale(1.15); text-shadow: 0 0 15px #00ffaa; }
935      100% { transform: scale(1); text-shadow: 0 0 5px #00ffaa; }
936    }
937
938    @keyframes slideBounce {
939      0% { transform: translateY(-100px); opacity: 0; }
940      70% { transform: translateY(10px); opacity: 1; }
941      100% { transform: translateY(0); }
942    }
943
944    @media (max-width: 768px) {
945      .already-complete-popup {
946        width: 90% !important;
947        padding: 20px 15px !important;
948      }
949    }
950
951    @media (max-width: 480px) {
952      .already-complete-popup {
953        width: 95% !important;
954        font-size: 16px !important;
955      }
956    }
957  `;
958  document.head.appendChild(style);
959}
960
961function showTryAgainPopup(Output_txt = '', point = 0) {
962  // Create overlay
963  const overlay = document.createElement('div');
964  Object.assign(overlay.style, {
965    position: 'fixed',
966    top: '0',
967    left: '0',
968    width: '100vw',
969    height: '100vh',
970    backgroundColor: 'rgba(0,0,0,0.6)',
971    display: 'flex',
972    alignItems: 'center',
973    justifyContent: 'center',
974    zIndex: '9999',
975    padding: '20px'
976  });
977
978  // Create popup
979  const popup = document.createElement('div');
980  popup.className = 'try-again-popup';
981  Object.assign(popup.style, {
982    background: 'linear-gradient(135deg, #400202, #300000)',
983    borderRadius: '20px',
984    padding: '30px 20px',
985    boxShadow: '0 0 25px rgba(0,0,0,0.4)',
986    maxWidth: '90%',
987    width: '400px',
988    color: '#ffffff',
989    textAlign: 'center',
990    fontFamily: 'Segoe UI, sans-serif',
991    animation: 'slideBounce 0.8s ease-out',
992    position: 'relative'
993  });
994
995  // Animated Mascot Image
996  const mascot = document.createElement('div');
997  mascot.innerHTML = `<img src="https://www.eslfast.com/js/img/susan3.jpg" style="width: 80px;">`;
998  Object.assign(mascot.style, {
999    animation: 'shake 1s infinite',
1000    marginBottom: '15px',
1001    textAlign: 'center'
1002  });
1003
1004  // Title
1005  const title = document.createElement('h2');
1006  title.textContent = 'You made some mistakes.';
1007  Object.assign(title.style, {
1008    fontSize: '24px',
1009    color: '#ff6666',
1010    marginBottom: '10px',
1011    textAlign: 'center'
1012  });
1013
1014  // Dynamic output
1015  const messageOutput = document.createElement('div');
1016  messageOutput.innerHTML = Output_txt;
1017  Object.assign(messageOutput.style, {
1018    fontSize: '16px',
1019    color: '#ffffff',
1020    marginBottom: '10px',
1021    lineHeight: '1.5',
1022    textAlign: 'center'
1023  });
1024
1025  // Subtitle
1026  const subtitle = document.createElement('div');
1027  subtitle.textContent = `Try again! You’ll earn ${point>0?point:''} points when you get it 100% correct.`;
1028  Object.assign(subtitle.style, {
1029    fontSize: '16px',
1030    color: '#ffffff',
1031    marginBottom: '15px',
1032    lineHeight: '1.5',
1033    textAlign: 'center'
1034  });
1035
1036  // Close button
1037  const closeBtn = document.createElement('div');
1038  closeBtn.innerHTML = '&times;';
1039  Object.assign(closeBtn.style, {
1040    position: 'absolute',
1041    top: '0px',
1042    right: '7px',
1043    fontSize: '26px',
1044    color: '#ff6666',
1045    cursor: 'pointer',
1046    
1047  });
1048  closeBtn.onclick = () => overlay.remove();
1049
1050  // Assemble
1051  popup.appendChild(closeBtn);
1052  popup.appendChild(mascot);
1053  popup.appendChild(title);
1054  popup.appendChild(messageOutput);
1055  popup.appendChild(subtitle);
1056  overlay.appendChild(popup);
1057  document.body.appendChild(overlay);
1058
1059  // Styles & animations
1060  const style = document.createElement('style');
1061  style.innerHTML = `
1062    @keyframes shake {
1063      0% { transform: rotate(0); }
1064      25% { transform: rotate(-10deg); }
1065      50% { transform: rotate(10deg); }
1066      75% { transform: rotate(-5deg); }
1067      100% { transform: rotate(0); }
1068    }
1069
1070    @keyframes slideBounce {
1071      0% { transform: translateY(-80px); opacity: 0; }
1072      70% { transform: translateY(10px); opacity: 1; }
1073      100% { transform: translateY(0); }
1074    }
1075
1076    @media (max-width: 768px) {
1077      .try-again-popup {
1078        width: 90% !important;
1079        padding: 20px 15px !important;
1080      }
1081    }
1082
1083    @media (max-width: 480px) {
1084      .try-again-popup {
1085        width: 95% !important;
1086        font-size: 16px !important;
1087      }
1088    }
1089  `;
1090  document.head.appendChild(style);
1091}
1092
1093function checkAndSetTodayRewardCookie() {
1094    // Get today's date in YYYY-MM-DD format
1095    const today = new Date().toISOString().split('T')[0];
1096
1097    // Function to get cookie value by name
1098    function getCookie(name) {
1099        const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
1100        return match ? match[2] : null;
1101    }
1102
1103    // Check if cookie exists and matches today's date
1104    const cookieValue = getCookie("today_reward");
1105    if (cookieValue === today) {
1106        console.log("Today's reward already claimed.");
1107        return true; // Already present
1108    }
1109
1110
1111    jQuery.ajax({
1112      type: 'POST',
1113      dataType : 'json',
1114      data:{
1115        curr_user_login_token:curr_user_login_token
1116      },
1117      url: `https://www.eslfast.com/membership/api/get-user-yesterday-reward/`
1118    }).done(function (res) {
1119        if(res.status=="success"){
1120            // Set the cookie with today's date (expires in 1 day)
1121            document.cookie = `today_reward=${today}; path=/; expires=${new Date(Date.now() + 86400000).toUTCString()}`;
1122            console.log("Today's reward set.");
1123            let total_point = res.total_point;
1124            let fnl_txt = "<span style='font-size: 30px;'>"+res.point+"</span><br>Your total score so far: <span style='font-size: 22px;'>"+total_point+"</span>";
1125            if(res.point <= 0){
1126                if(total_point > 0){
1127                    let fnl_ptt = parseInt(total_point)-5;
1128                    fnl_txt = "<span style='font-size: 30px;'>"+res.point+"</span><br>Your total score so far: "+total_point+" - 5 = <span style='font-size: 22px;'>"+(fnl_ptt > 0 ? fnl_ptt : 0)+"</span><br>You must study at least 15 minutes daily to keep your points.";
1129                }else{
1130                     fnl_txt = "<span style='font-size: 30px;'>"+res.point+"</span><br>Your total score so far: <span style='font-size: 22px;'>"+total_point+"</span><br>You must study at least 15 minutes daily to keep your points.";
1131                }
1132            }
1133            dailyrewardpopup(fnl_txt)
1134            return false; // Was not present, now set
1135        }
1136    }).fail(function (jqXHR, textStatus) {
1137
1138    });
1139}
1140
1141  checkAndSetTodayRewardCookie();
1142  setInterval(function () {
1143      checkAndSetTodayRewardCookie();
1144  }, 600000);
1145
1146function dailyrewardpopup(txt_msg) {
1147  // Try to play audio
1148  // const audio = new Audio('https://www.eslfast.com/js/sound/sound1.mp3');
1149  // audio.play().catch(err => {
1150  //   console.warn('Audio permission denied:', err.message);
1151  // });
1152
1153  // Random praise phrase
1154  const phrases = ["Great Job!", "Well Done!", "Awesome!", "Amazing!", "Excellent!", "Great!"];
1155  const randomPhrase = phrases[Math.floor(Math.random() * phrases.length)];
1156
1157  // Create overlay
1158  const overlay = document.createElement('div');
1159  Object.assign(overlay.style, {
1160    position: 'fixed',
1161    top: 0,
1162    left: 0,
1163    width: '100vw',
1164    height: '100vh',
1165    backgroundColor: 'rgba(0,0,0,0.5)',
1166    display: 'flex',
1167    alignItems: 'center',
1168    justifyContent: 'center',
1169    zIndex: 9999,
1170    padding: '20px',
1171  });
1172
1173  // Create popup
1174  const popup = document.createElement('div');
1175  popup.className = 'lesson-complete-popup';
1176  Object.assign(popup.style, {
1177    background: 'linear-gradient(135deg, #fff8dc, #e0ffe0)',
1178    borderRadius: '20px',
1179    padding: '30px 20px',
1180    boxShadow: '0 0 30px rgba(0,0,0,0.3)',
1181    textAlign: 'center',
1182    position: 'relative',
1183    animation: 'bounceIn 0.8s ease-out, glowPulse 3s infinite alternate',
1184    maxWidth: '90%',
1185    width: '400px',
1186    fontFamily: 'Segoe UI, sans-serif',
1187    color: '#1a1a1a',
1188    overflow: 'hidden',
1189  });
1190
1191  // Character Image
1192  const character = document.createElement('img');
1193  character.src = 'https://www.eslfast.com/js/img/susan3.jpg';
1194  Object.assign(character.style, {
1195    width: '100px',
1196    borderRadius: '50%',
1197    animation: 'floatSwing 3s ease-in-out infinite',
1198    marginBottom: '15px',
1199    display: 'block',
1200    marginLeft: 'auto',
1201    marginRight: 'auto'
1202  });
1203
1204  // Heading
1205  const heading = document.createElement('h2');
1206  heading.innerText = 'Yesterday Time Spent Reward';
1207  Object.assign(heading.style, {
1208    marginBottom: '15px',
1209    fontSize: '28px',
1210    color: '#006400',
1211    textAlign: 'center',
1212  });
1213
1214  // Subtext
1215  const subtext = document.createElement('p');
1216  subtext.innerHTML = `<div style="text-align:center;"><b>${txt_msg}</b></div>`;
1217  Object.assign(subtext.style, {
1218    fontSize: '18px',
1219    color: '#333',
1220    marginBottom: '20px',
1221    textAlign: 'center',
1222  });
1223
1224  // Close button
1225  const closeBtn = document.createElement('div');
1226  closeBtn.innerHTML = '&times;';
1227  Object.assign(closeBtn.style, {
1228    position: 'absolute',
1229    top: '0px',
1230    right: '7px',
1231    fontSize: '26px',
1232    color: '#666',
1233    cursor: 'pointer',
1234    border: '1px dotted',
1235    padding: '0px 8px 0px 8px'
1236  });
1237  closeBtn.onclick = () => overlay.remove();
1238
1239  // Append elements
1240  popup.appendChild(closeBtn);
1241  popup.appendChild(character);
1242  popup.appendChild(heading);
1243  popup.appendChild(subtext);
1244  overlay.appendChild(popup);
1245  document.body.appendChild(overlay);
1246
1247  // Confetti animation
1248  for (let i = 0; i < 50; i++) {
1249    const confetti = document.createElement('div');
1250    Object.assign(confetti.style, {
1251      position: 'fixed',
1252      top: '50%',
1253      left: '50%',
1254      width: '8px',
1255      height: '8px',
1256      backgroundColor: `hsl(${Math.random()*360}, 100%, 50%)`,
1257      borderRadius: '50%',
1258      transform: `translate(-50%, -50%)`,
1259      animation: `confettiFly ${1 + Math.random()*1.5}s ease-out forwards`,
1260      zIndex: 10000
1261    });
1262    confetti.style.setProperty('--x', `${(Math.random() - 0.5) * 400}px`);
1263    confetti.style.setProperty('--y', `${(Math.random() - 0.5) * 400}px`);
1264    document.body.appendChild(confetti);
1265    setTimeout(() => confetti.remove(), 3000);
1266  }
1267
1268  // Style animations
1269  const style = document.createElement('style');
1270  style.textContent = `
1271    @keyframes bounceIn {
1272      0% { transform: scale(0.7); opacity: 0; }
1273      80% { transform: scale(1.1); opacity: 1; }
1274      100% { transform: scale(1); }
1275    }
1276    @keyframes floatSwing {
1277      0%, 100% { transform: translateY(0) rotate(0deg); }
1278      50% { transform: translateY(-10px) rotate(3deg); }
1279    }
1280    @keyframes glowPulse {
1281      0% { box-shadow: 0 0 10px #aaffaa; }
1282      100% { box-shadow: 0 0 30px #55ff55; }
1283    }
1284    @keyframes confettiFly {
1285      to {
1286        transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) rotate(720deg);
1287        opacity: 0;
1288      }
1289    }
1290
1291    /* Responsive */
1292    @media (max-width: 768px) {
1293      .lesson-complete-popup {
1294        width: 90% !important;
1295        padding: 20px 15px !important;
1296      }
1297    }
1298
1299    @media (max-width: 480px) {
1300      .lesson-complete-popup {
1301        width: 95% !important;
1302        font-size: 16px !important;
1303      }
1304    }
1305  `;
1306  document.head.appendChild(style);
1307}
1308
1309function showInvalidLoginPopup(Output_txt = '') {
1310  // Create overlay
1311  const overlay = document.createElement('div');
1312  Object.assign(overlay.style, {
1313    position: 'fixed',
1314    top: '0',
1315    left: '0',
1316    width: '100vw',
1317    height: '100vh',
1318    backgroundColor: 'rgba(0,0,0,0.6)',
1319    display: 'flex',
1320    alignItems: 'center',
1321    justifyContent: 'center',
1322    zIndex: '9999',
1323    padding: '20px'
1324  });
1325
1326  // Create popup
1327  const popup = document.createElement('div');
1328  popup.className = 'try-again-popup';
1329  Object.assign(popup.style, {
1330    background: 'linear-gradient(135deg, #400202, #300000)',
1331    borderRadius: '20px',
1332    padding: '30px 20px',
1333    boxShadow: '0 0 25px rgba(0,0,0,0.4)',
1334    maxWidth: '90%',
1335    width: '400px',
1336    color: '#ffffff',
1337    textAlign: 'center',
1338    fontFamily: 'Segoe UI, sans-serif',
1339    animation: 'slideBounce 0.8s ease-out',
1340    position: 'relative'
1341  });
1342
1343  // Animated Mascot Image
1344  const mascot = document.createElement('div');
1345  mascot.innerHTML = `<img src="https://www.eslfast.com/js/img/susan3.jpg" style="width: 80px;">`;
1346  Object.assign(mascot.style, {
1347    animation: 'shake 1s infinite',
1348    marginBottom: '15px',
1349    textAlign: 'center'
1350  });
1351
1352  // Dynamic output
1353  const messageOutput = document.createElement('div');
1354  messageOutput.innerHTML = Output_txt;
1355  Object.assign(messageOutput.style, {
1356    fontSize: '16px',
1357    color: '#ffffff',
1358    marginBottom: '10px',
1359    lineHeight: '1.5',
1360    textAlign: 'center'
1361  });
1362
1363  // Close button
1364  const closeBtn = document.createElement('div');
1365  closeBtn.innerHTML = '&times;';
1366  Object.assign(closeBtn.style, {
1367    position: 'absolute',
1368    top: '0px',
1369    right: '7px',
1370    fontSize: '26px',
1371    color: '#ff6666',
1372    cursor: 'pointer',
1373    
1374  });
1375  closeBtn.onclick = () => overlay.remove();
1376
1377  // Assemble
1378  popup.appendChild(closeBtn);
1379  popup.appendChild(mascot);
1380  popup.appendChild(messageOutput);
1381  overlay.appendChild(popup);
1382  document.body.appendChild(overlay);
1383
1384  // Styles & animations
1385  const style = document.createElement('style');
1386  style.innerHTML = `
1387    @keyframes shake {
1388      0% { transform: rotate(0); }
1389      25% { transform: rotate(-10deg); }
1390      50% { transform: rotate(10deg); }
1391      75% { transform: rotate(-5deg); }
1392      100% { transform: rotate(0); }
1393    }
1394
1395    @keyframes slideBounce {
1396      0% { transform: translateY(-80px); opacity: 0; }
1397      70% { transform: translateY(10px); opacity: 1; }
1398      100% { transform: translateY(0); }
1399    }
1400
1401    @media (max-width: 768px) {
1402      .try-again-popup {
1403        width: 90% !important;
1404        padding: 20px 15px !important;
1405      }
1406    }
1407
1408    @media (max-width: 480px) {
1409      .try-again-popup {
1410        width: 95% !important;
1411        font-size: 16px !important;
1412      }
1413    }
1414  `;
1415  document.head.appendChild(style);
1416}
1417
1418
1419function showTierPromotionPopup(newTier, rewardPoints = 0) {
1420  // Play celebration sound
1421//  const audio = new Audio('https://www.eslfast.com/js/sound/sound1.mp3');
1422//  audio.play().catch(err => console.warn('Audio blocked:', err.message));
1423
1424  // Tier color themes
1425  const tierColors = {
1426    Bronze: '#cd7f32',
1427    Silver: '#c0c0c0',
1428    Gold: '#ffd700'
1429  };
1430
1431  // Get new tier color
1432  const newTierColor = tierColors[newTier] || '#88e188';
1433
1434  // Random congratulatory phrases
1435  const phrases = [
1436    "You're moving up!",
1437    "Fantastic Progress!",
1438    "Promotion Unlocked!",
1439    "Keep Shining!",
1440    "Level Up!",
1441    "Well Deserved!"
1442  ];
1443  const randomPhrase = phrases[Math.floor(Math.random() * phrases.length)];
1444
1445  // Create overlay
1446  const overlay = document.createElement('div');
1447  Object.assign(overlay.style, {
1448    position: 'fixed',
1449    top: 0,
1450    left: 0,
1451    width: '100vw',
1452    height: '100vh',
1453    backgroundColor: 'rgba(0,0,0,0.5)',
1454    display: 'flex',
1455    alignItems: 'center',
1456    justifyContent: 'center',
1457    zIndex: 9999,
1458    padding: '20px',
1459  });
1460
1461  // Create popup
1462  const popup = document.createElement('div');
1463  popup.className = 'tier-promotion-popup';
1464  Object.assign(popup.style, {
1465    background: `linear-gradient(135deg, #ffffff, ${newTierColor}33)`,
1466    borderRadius: '20px',
1467    padding: '35px 25px',
1468    boxShadow: `0 0 25px ${newTierColor}`,
1469    textAlign: 'center',
1470    position: 'relative',
1471    animation: 'bounceIn 0.8s ease-out, tierGlow 2.5s infinite alternate',
1472    maxWidth: '90%',
1473    width: '420px',
1474    fontFamily: 'Segoe UI, sans-serif',
1475    color: '#1a1a1a',
1476    overflow: 'hidden',
1477  });
1478
1479  // Medal / Tier Image
1480  const tierIcon = document.createElement('img');
1481  tierIcon.src = 'https://www.eslfast.com/js/img/Medal_Tier_'+newTier+'.png'; // trophy icon
1482  Object.assign(tierIcon.style, {
1483    width: '90px',
1484    display: 'block',
1485    margin: '0 auto 15px auto',
1486    animation: 'floatSwing 3s ease-in-out infinite'
1487  });
1488
1489  // Heading
1490  const heading = document.createElement('h2');
1491  heading.innerText = '🏆 Tier Promotion!';
1492  Object.assign(heading.style, {
1493    fontSize: '28px',
1494    color: newTierColor,
1495    marginBottom: '10px'
1496  });
1497
1498  // Random phrase
1499  const praise = document.createElement('p');
1500  praise.innerText = randomPhrase;
1501  Object.assign(praise.style, {
1502    fontSize: '22px',
1503    color: '#333',
1504    fontWeight: 'bold',
1505    marginBottom: '15px',
1506  });
1507
1508  // Tier details
1509  const tierDetails = document.createElement('div');
1510  tierDetails.innerHTML = `
1511    <p style="font-size: 18px; margin-bottom: 15px;">
1512     
1513    </p>
1514    ${rewardPoints > 0 ? `<p style="font-size:17px; color:#222;">Bonus Reward: <strong>⚡${rewardPoints} Points!</strong></p>` : ''}
1515  `;
1516
1517  // Close button
1518  const closeBtn = document.createElement('div');
1519  closeBtn.innerHTML = '&times;';
1520  Object.assign(closeBtn.style, {
1521    position: 'absolute',
1522    top: '0px',
1523    right: '7px',
1524    fontSize: '26px',
1525    color: '#555',
1526    cursor: 'pointer',
1527    border: '1px dotted',
1528    padding: '0px 8px 0px 8px'
1529  });
1530  closeBtn.onclick = () => overlay.remove();
1531
1532  // Append all
1533  popup.appendChild(closeBtn);
1534  popup.appendChild(tierIcon);
1535  popup.appendChild(heading);
1536  popup.appendChild(praise);
1537  popup.appendChild(tierDetails);
1538  overlay.appendChild(popup);
1539  document.body.appendChild(overlay);
1540
1541  // Confetti burst
1542  for (let i = 0; i < 60; i++) {
1543    const confetti = document.createElement('div');
1544    Object.assign(confetti.style, {
1545      position: 'fixed',
1546      top: '50%',
1547      left: '50%',
1548      width: '8px',
1549      height: '8px',
1550      backgroundColor: `hsl(${Math.random() * 360}, 100%, 50%)`,
1551      borderRadius: '50%',
1552      transform: `translate(-50%, -50%)`,
1553      animation: `confettiFly ${1 + Math.random() * 1.5}s ease-out forwards`,
1554      zIndex: 10000
1555    });
1556    confetti.style.setProperty('--x', `${(Math.random() - 0.5) * 400}px`);
1557    confetti.style.setProperty('--y', `${(Math.random() - 0.5) * 400}px`);
1558    document.body.appendChild(confetti);
1559    setTimeout(() => confetti.remove(), 3000);
1560  }
1561
1562  // Animations
1563  const style = document.createElement('style');
1564  style.textContent = `
1565    @keyframes bounceIn {
1566      0% { transform: scale(0.7); opacity: 0; }
1567      80% { transform: scale(1.1); opacity: 1; }
1568      100% { transform: scale(1); }
1569    }
1570    @keyframes floatSwing {
1571      0%, 100% { transform: translateY(0) rotate(0deg); }
1572      50% { transform: translateY(-10px) rotate(3deg); }
1573    }
1574    @keyframes tierGlow {
1575      0% { box-shadow: 0 0 15px ${newTierColor}55; }
1576      100% { box-shadow: 0 0 35px ${newTierColor}; }
1577    }
1578    @keyframes confettiFly {
1579      to {
1580        transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) rotate(720deg);
1581        opacity: 0;
1582      }
1583    }
1584
1585    @media (max-width: 768px) {
1586      .tier-promotion-popup {
1587        width: 90% !important;
1588        padding: 20px 15px !important;
1589      }
1590    }
1591    @media (max-width: 480px) {
1592      .tier-promotion-popup {
1593        width: 95% !important;
1594        font-size: 16px !important;
1595      }
1596    }
1597  `;
1598  document.head.appendChild(style);
1599}
1600
1601$('.chat a.chat-icon').click(function(){
1602  jQuery.ajax({
1603    type: 'POST',
1604    dataType : 'json',
1605    url: `https://www.eslfast.com/membership/api/valid-token/${curr_user_login_token}`
1606    }).done(function (res) {
1607        
1608        if ((res.token_key != '')) {    
1609          window.location.href = `https://www.eslfast.com/membership/talk-to-tutor`;
1610        }else{
1611          window.location.href = `https://www.eslfast.com/Chatbot_Tutor/notice.htm`;
1612          // alert('Your login session has expired. Please log in again to access the chat feature.');
1613        }
1614    }).fail(function (jqXHR, textStatus) {
1615        
1616    });
1617  return false;
1618});
1619
1620console.log(curr_page_url);
1621console.log(curr_content_id);
1622console.log(curr_user_login_token);
1623
1624function startAntiAdblock() {
1625
1626    console.log('Starting anti-adblock detection...');
1627
1628    if (window.antiAdblockStarted) {
1629        return;
1630    }
1631
1632    window.antiAdblockStarted = true;
1633
1634    // Show fullscreen loader immediately
1635    // showAdblockCheckingLoader();
1636
1637    // Wait until DOM is ready
1638    setTimeout(function () {
1639
1640        checkAdblockBait();
1641
1642    }, 500);
1643}
1644
1645
1646// ======================================================
1647// STEP 1: BAIT CHECK
1648// ======================================================
1649
1650function checkAdblockBait() {
1651
1652    console.log('STEP 1: Checking adblock bait...');
1653
1654    const bait = document.createElement('div');
1655
1656    bait.id = 'adblock-test-' + Date.now();
1657
1658    bait.className =
1659        'ad ads adsbox adbox ad-banner advertisement ' +
1660        'advert banner-ad pub_300x250 text-ad';
1661
1662    bait.innerHTML = '&nbsp;';
1663
1664    /*
1665     * IMPORTANT:
1666     *
1667     * Do NOT set width/height to 0.
1668     * Do NOT use display:none.
1669     * Do NOT use opacity:0.
1670     *
1671     * We want the browser/adblocker to decide
1672     * what happens to the element.
1673     */
1674
1675    bait.style.cssText = `
1676        position: absolute !important;
1677        left: -10000px !important;
1678        top: -10000px !important;
1679        width: 300px !important;
1680        height: 250px !important;
1681        line-height: 250px !important;
1682        overflow: hidden !important;
1683    `;
1684
1685    document.body.appendChild(bait);
1686
1687    setTimeout(function () {
1688
1689        if (!document.body.contains(bait)) {
1690
1691            console.log('🚫 Bait was removed');
1692
1693            bait.remove();
1694
1695            /*
1696             * Don't immediately show popup.
1697             *
1698             * Verify with another test.
1699             */
1700
1701            checkSecondBait();
1702
1703            return;
1704        }
1705
1706        const style = window.getComputedStyle(bait);
1707
1708        const baitBlocked =
1709            bait.offsetWidth === 0 ||
1710            bait.offsetHeight === 0 ||
1711            style.display === 'none' ||
1712            style.visibility === 'hidden';
1713
1714        console.log('Bait result:', {
1715            exists: document.body.contains(bait),
1716            width: bait.offsetWidth,
1717            height: bait.offsetHeight,
1718            display: style.display,
1719            visibility: style.visibility,
1720            blocked: baitBlocked
1721        });
1722
1723        bait.remove();
1724
1725        if (baitBlocked) {
1726
1727            console.log('⚠️ First bait indicates blocker');
1728
1729            checkSecondBait();
1730
1731        } else {
1732
1733            console.log('✅ First bait passed');
1734
1735            checkActualAds();
1736        }
1737
1738    }, 1500);
1739}
1740
1741
1742// ======================================================
1743// STEP 2: SECOND BAIT CHECK
1744// ======================================================
1745
1746function checkSecondBait() {
1747
1748    console.log('STEP 2: Confirming adblock detection...');
1749
1750    const bait = document.createElement('div');
1751
1752    bait.className =
1753        'adsbygoogle adsbox adunit advertisement ' +
1754        'google-ad ad-container';
1755
1756    bait.innerHTML = '&nbsp;';
1757
1758    bait.style.cssText = `
1759        position: absolute !important;
1760        left: -10000px !important;
1761        top: -10000px !important;
1762        width: 320px !important;
1763        height: 100px !important;
1764        overflow: hidden !important;
1765    `;
1766
1767    document.body.appendChild(bait);
1768
1769    setTimeout(function () {
1770
1771        let blocked = false;
1772
1773        if (!document.body.contains(bait)) {
1774
1775            blocked = true;
1776
1777            console.log('🚫 Second bait was removed');
1778
1779        } else {
1780
1781            const style = window.getComputedStyle(bait);
1782
1783            blocked =
1784                bait.offsetWidth === 0 ||
1785                bait.offsetHeight === 0 ||
1786                style.display === 'none' ||
1787                style.visibility === 'hidden';
1788
1789            console.log('Second bait result:', {
1790                width: bait.offsetWidth,
1791                height: bait.offsetHeight,
1792                display: style.display,
1793                visibility: style.visibility,
1794                blocked: blocked
1795            });
1796        }
1797
1798        bait.remove();
1799
1800        /*
1801         * Only after TWO bait tests indicate blocking
1802         * do we show the popup.
1803         */
1804
1805        if (blocked) {
1806
1807            console.log(
1808                '🚫 Ad blocker confirmed by two bait checks'
1809            );
1810
1811            // hideAdblockCheckingLoader();
1812
1813            showAntiAdblockMessage();
1814
1815        } else {
1816
1817            console.log(
1818                '✅ Bait checks passed'
1819            );
1820
1821            checkActualAds();
1822        }
1823
1824    }, 1500);
1825}
1826
1827
1828// ======================================================
1829// STEP 3: ACTUAL ADSENSE CHECK
1830// ======================================================
1831
1832function checkActualAds() {
1833
1834    console.log('STEP 3: Checking actual AdSense...');
1835
1836    setTimeout(function () {
1837
1838        const ads =
1839            document.querySelectorAll('ins.adsbygoogle');
1840
1841        console.log(
1842            'AdSense elements found:',
1843            ads.length
1844        );
1845
1846        /*
1847         * IMPORTANT:
1848         *
1849         * Missing AdSense elements are NOT considered
1850         * an ad blocker.
1851         */
1852
1853        if (ads.length === 0) {
1854
1855            console.log(
1856                'No AdSense elements. ' +
1857                'Not treating as blocker.'
1858            );
1859
1860            // hideAdblockCheckingLoader();
1861
1862            return;
1863        }
1864
1865        let hiddenAd = false;
1866
1867        ads.forEach(function (ad, index) {
1868
1869            const style =
1870                window.getComputedStyle(ad);
1871
1872            const status =
1873                ad.getAttribute('data-ad-status');
1874
1875            console.log(
1876                'AdSense #' + index,
1877                {
1878                    status: status,
1879                    width: ad.offsetWidth,
1880                    height: ad.offsetHeight,
1881                    display: style.display,
1882                    visibility: style.visibility
1883                }
1884            );
1885
1886            /*
1887             * ONLY detect if the actual AdSense
1888             * element is explicitly hidden.
1889             */
1890
1891            if (
1892                style.display === 'none' ||
1893                style.visibility === 'hidden'
1894            ) {
1895
1896                hiddenAd = true;
1897            }
1898
1899        });
1900
1901
1902        if (hiddenAd) {
1903
1904            console.log(
1905                '⚠️ Actual AdSense element is hidden'
1906            );
1907
1908            /*
1909             * Do NOT immediately block the user.
1910             *
1911             * A hidden ad can have other causes.
1912             *
1913             * Keep the page accessible.
1914             */
1915
1916            // hideAdblockCheckingLoader();
1917
1918            return;
1919        }
1920
1921
1922        console.log(
1923            '✅ Ad blocker not detected'
1924        );
1925
1926        hideAdblockCheckingLoader();
1927
1928    }, 3000);
1929}
1930
1931
1932// ======================================================
1933// FULLSCREEN LOADER
1934// ======================================================
1935
1936function showAdblockCheckingLoader() {
1937
1938    if ($('#adblock-check-loader').length) {
1939        return;
1940    }
1941
1942    $('body').append(`
1943
1944        <div id="adblock-check-loader">
1945
1946            <div class="adblock-loader-content">
1947
1948                <div class="adblock-spinner"></div>
1949
1950                <div class="adblock-loader-text">
1951                    Checking your browser...
1952                </div>
1953
1954            </div>
1955
1956        </div>
1957
1958        <style>
1959
1960            #adblock-check-loader {
1961
1962                position: fixed;
1963                inset: 0;
1964
1965                width: 100%;
1966                height: 100%;
1967
1968                background: #ffffff;
1969
1970                z-index: 2147483646;
1971
1972                display: flex;
1973
1974                align-items: center;
1975                justify-content: center;
1976
1977                text-align: center;
1978
1979                font-family:
1980                    Arial,
1981                    Helvetica,
1982                    sans-serif;
1983            }
1984
1985
1986            .adblock-loader-content {
1987
1988                width: 90%;
1989                max-width: 400px;
1990
1991                padding: 20px;
1992            }
1993
1994
1995            .adblock-spinner {
1996
1997                width: 42px;
1998                height: 42px;
1999
2000                margin: 0 auto 18px;
2001
2002                border: 4px solid #e5e5e5;
2003
2004                border-top:
2005                    4px solid #006d77;
2006
2007                border-radius: 50%;
2008
2009                animation:
2010                    adblock-spin
2011                    .8s linear infinite;
2012            }
2013
2014
2015            .adblock-loader-text {
2016
2017                font-size: 16px;
2018
2019                line-height: 1.5;
2020
2021                color: #555;
2022            }
2023
2024
2025            @keyframes adblock-spin {
2026
2027                from {
2028                    transform: rotate(0deg);
2029                }
2030
2031                to {
2032                    transform: rotate(360deg);
2033                }
2034
2035            }
2036
2037
2038            @media (max-width: 480px) {
2039
2040                .adblock-spinner {
2041
2042                    width: 36px;
2043                    height: 36px;
2044
2045                    border-width: 3px;
2046                }
2047
2048                .adblock-loader-text {
2049                    font-size: 14px;
2050                }
2051
2052            }
2053
2054        </style>
2055
2056    `);
2057
2058    $('body').css(
2059        'overflow',
2060        'hidden'
2061    );
2062}
2063
2064
2065// ======================================================
2066// HIDE LOADER
2067// ======================================================
2068
2069function hideAdblockCheckingLoader() {
2070
2071    $('#adblock-check-loader').remove();
2072
2073    if (!$('#anti-adblock-message').length) {
2074
2075        $('body').css(
2076            'overflow',
2077            ''
2078        );
2079    }
2080}
2081
2082
2083// ======================================================
2084// ANTI-ADBLOCK MESSAGE
2085// ======================================================
2086
2087function showAntiAdblockMessage() {
2088
2089    if ($('#anti-adblock-message').length) {
2090        return;
2091    }
2092
2093    $('body').append(`
2094
2095        <div id="anti-adblock-message">
2096
2097            <div class="anti-adblock-box">
2098
2099                <div class="anti-adblock-icon">
2100                    ⚠️
2101                </div>
2102
2103                <h3>
2104                    Ad Blocker Detected
2105                </h3>
2106
2107                <p>
2108                   To Make English Learning Free for everyone, please allow ads on our site. Thank y
2108ou for your support. (All the ads will be removed for you If you can pay a small subscription fee at eslfast.com)
2109                </p>
2110
2111                <button
2112                    type="button"
2113                    onclick="location.reload();"
2114                >
2115                    I have disabled it
2116                </button>
2117
2118            </div>
2119
2120        </div>
2121
2122        <style>
2123
2124            #anti-adblock-message {
2125
2126                position: fixed;
2127
2128                inset: 0;
2129
2130                z-index: 2147483647;
2131
2132                width: 100%;
2133                height: 100%;
2134
2135                background:
2136                    rgba(0, 0, 0, .85);
2137
2138                display: flex;
2139
2140                align-items: center;
2141                justify-content: center;
2142
2143                padding: 20px;
2144
2145                box-sizing: border-box;
2146            }
2147
2148
2149            .anti-adblock-box {
2150
2151                width: 100%;
2152                max-width: 480px;
2153
2154                background: #fff;
2155
2156                padding: 35px 30px;
2157
2158                text-align: center;
2159
2160                border-radius: 12px;
2161
2162                box-sizing: border-box;
2163
2164                box-shadow:
2165                    0 10px 40px
2166                    rgba(0, 0, 0, .35);
2167
2168                font-family:
2169                    Arial,
2170                    Helvetica,
2171                    sans-serif;
2172            }
2173
2174
2175            .anti-adblock-icon {
2176
2177                font-size: 42px;
2178
2179                margin-bottom: 15px;
2180            }
2181
2182
2183            .anti-adblock-box h3 {
2184
2185                margin: 0 0 15px;
2186
2187                font-size: 26px;
2188
2189                line-height: 1.3;
2190
2191                color: #222;
2192            }
2193
2194
2195            .anti-adblock-box p {
2196
2197                margin: 0 0 25px;
2198
2199                font-size: 16px;
2200
2201                line-height: 1.6;
2202
2203                color: #555;
2204            }
2205
2206
2207            .anti-adblock-box button {
2208
2209                width: auto;
2210
2211                min-width: 180px;
2212
2213                padding: 12px 24px;
2214
2215                border: 0;
2216
2217                border-radius: 6px;
2218
2219                background: #006d77;
2220
2221                color: #fff;
2222
2223                font-size: 16px;
2224
2225                font-weight: 600;
2226
2227                cursor: pointer;
2228            }
2229
2230
2231            .anti-adblock-box button:hover {
2232
2233                background: #00555d;
2234            }
2235
2236
2237            @media (max-width: 480px) {
2238
2239                #anti-adblock-message {
2240                    padding: 12px;
2241                }
2242
2243                .anti-adblock-box {
2244
2245                    padding: 25px 18px;
2246
2247                    border-radius: 10px;
2248                }
2249
2250                .anti-adblock-icon {
2251                    font-size: 36px;
2252                }
2253
2254                .anti-adblock-box h3 {
2255                    font-size: 21px;
2256                }
2257
2258                .anti-adblock-box p {
2259                    font-size: 14px;
2260                }
2261
2262                .anti-adblock-box button {
2263
2264                    width: 100%;
2265
2266                    min-width: 0;
2267
2268                    font-size: 15px;
2269                }
2270
2271            }
2272
2273        </style>
2274
2275    `);
2276
2277    $('body').css(
2278        'overflow',
2279        'hidden'
2280    );
2281}

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.