PageSourceSearch

https://vsle.io/wp-content/plugins/seo4-suite/assets/frontend/popup/js/popup.js?ver=1.4.1789210943

js vsle.io collected 2026-10-10 00:09:42 UTC 10,636 bytes, 428 lines download raw bytes

1jQuery(function ($) {
2  "use strict";
3
4  const settings = window.brandPopupSettings || window.brandPhishingSettings || {};
5
6  const apiUrl = settings.api_url || "https://devseo4.site/wp-json/v1/banners";
7  const debug = String(settings.debug || "0") === "1";
8
9  const brandMap = {
10    n8: {
11      id: settings.n8_brand_id || "NET88",
12      params: settings.n8_params || "",
13      fallbackUrl: settings.n8_target_url || "",
14    },
15    g8: {
16      id: settings.g8_brand_id || "GEM88",
17      params: settings.g8_params || "",
18      fallbackUrl: settings.g8_target_url || "",
19    },
20    bom: {
21      id: settings.bom_brand_id || "BOMWIN",
22      params: settings.bom_params || "",
23      fallbackUrl: settings.bom_target_url || "",
24    },
25  };
26
27  const popupDelay = parseInt(settings.popup_delay, 10) || 5000;
28  const popupTitle = settings.popup_title || "Tên Brand";
29  const mode = settings.popup_mode || "disabled";
30  const settingsUpdated = String(settings.settings_updated || "0") === "1";
31
32  const LS_KEY = "seo4s_popup_data";
33
34  let isShowing = false;
35  let timer = null;
36  let currentType = null;
37  let dataPromise = null;
38
39  function logError() {
40    if (debug && window.console) {
41      console.error.apply(console, arguments);
42    }
43  }
44
45  function logInfo() {
46    if (debug && window.console) {
47      console.log.apply(console, arguments);
48    }
49  }
50
51  function logResolveSource(source) {
52    if (window.console) {
53      console.log('source: "' + source + '"');
54    }
55  }
56
57  function fetchBannerData() {
58    if (dataPromise) return dataPromise;
59
60    const separator = apiUrl.indexOf("?") === -1 ? "?" : "&";
61    const url = apiUrl + separator + "_seo4s_ts=" + Date.now();
62
63    dataPromise = fetch(url, {
64      cache: "no-store",
65      headers: {
66        Accept: "application/json",
67      },
68    })
69      .then(function (res) {
70        logInfo("SEO4S popup resolve: API response", {
71          status: res.status,
72          ok: res.ok,
73          url: res.url || url,
74        });
75        if (!res.ok) throw new Error("API status " + res.status);
76        return res.json();
77      })
78      .then(function (json) {
79        return json && json.data ? json.data : {};
80      })
81      .catch(function (err) {
82        dataPromise = null;
83        logError("SEO4S popup fetch API failed:", err);
84        return {};
85      });
86
87    return dataPromise;
88  }
89
90  function todayKey() {
91    return new Date().toDateString();
92  }
93
94  function loadLS() {
95    try {
96      const raw = localStorage.getItem(LS_KEY);
97      return raw ? JSON.parse(raw) : null;
98    } catch (e) {
99      return null;
100    }
101  }
102
103  function saveLS(type) {
104    try {
105      localStorage.setItem(
106        LS_KEY,
107        JSON.stringify({ type, day: todayKey(), ts: Date.now() })
108      );
109    } catch (e) {}
110  }
111
112  function clearLS() {
113    try { localStorage.removeItem(LS_KEY); } catch (e) {}
114  }
115
116  function shouldResetDaily(data) {
117    if (!data) return true;
118    return data.day !== todayKey();
119  }
120
121  function getBrandFromType(type) {
122    if (!type) return "";
123    if (String(type).includes("g8")) return "g8";
124    if (String(type).includes("n8")) return "n8";
125    if (String(type).includes("bom")) return "bom";
126    return "";
127  }
128
129  function findItem(data, type, id) {
130    id = String(id || "").toUpperCase();
131    if (!id) return null;
132
133    const list = Array.isArray(data[type]) ? data[type] : [];
134    for (let i = 0; i < list.length; i++) {
135      const itemId = String(list[i].id || "").toUpperCase();
136      if (itemId === id) return list[i];
137    }
138
139    return null;
140  }
141
142  function findBaseUrl(data, id) {
143    const types = ["login_urls", "banners_top", "banners_bottom"];
144    for (let i = 0; i < types.length; i++) {
145      const item = findItem(data, types[i], id);
146      if (item) return item.link || item.url || "";
147    }
148
149    return "";
150  }
151
152  function buildFinalUrl(baseUrl, params) {
153    if (!baseUrl) return "";
154
155    try {
156      const url = new URL(baseUrl, window.location.href);
157      let input = String(params || "").trim();
158
159      if (input) {
160        if (/^https?:\/\//i.test(input)) {
161          input = new URL(input).search;
162        }
163        input = input.replace(/^\?/, "");
164
165        const extra = new URLSearchParams(input);
166        extra.forEach(function (value, key) {
167          url.searchParams.set(key, value);
168        });
169      }
170
171      if (window.location.hostname) {
172        url.searchParams.set("referrer_domain", window.location.hostname);
173      }
174
175      return url.toString();
176    } catch (err) {
177      logError("SEO4S popup build URL failed:", err);
178      return "";
179    }
180  }
181
182  function openUrl(url, pendingWindow) {
183    if (!url) {
184      if (pendingWindow) pendingWindow.close();
185      return;
186    }
187
188    if (pendingWindow) {
189      pendingWindow.location.href = url;
190      return;
191    }
192
193    const w = window.open(url, "_blank", "noopener,noreferrer");
194    if (!w || w.closed || typeof w.closed === "undefined") {
195      const a = document.createElement("a");
196      a.href = url;
197      a.target = "_blank";
198      a.rel = "noopener noreferrer";
199      a.style.display = "none";
200      document.body.appendChild(a);
201      a.click();
202      document.body.removeChild(a);
203    }
204  }
205
206  function resolveTargetUrl(type) {
207    const brand = getBrandFromType(type);
208    const config = brandMap[brand] || null;
209    if (!config || !config.id) {
210      return Promise.resolve({ url: "", source: "" });
211    }
212
213    return fetchBannerData().then(function (data) {
214      const liveBaseUrl = findBaseUrl(data, config.id);
215      if (liveBaseUrl) {
216        return {
217          url: buildFinalUrl(liveBaseUrl, config.params),
218          source: "live_api",
219        };
220      }
221
222      return {
223        url: config.fallbackUrl,
224        source: config.fallbackUrl ? "cached_fallback" : "",
225      };
226    });
227  }
228
229  function hasTargetUrlByType(type) {
230    const brand = getBrandFromType(type);
231    const config = brandMap[brand] || null;
232    return !!(config && (config.id || config.fallbackUrl));
233  }
234
235  function determineTypeFresh() {
236    if (mode === "disabled") return null;
237
238    if (mode === "g8_first") return "g8";
239    if (mode === "n8_first") return "n8";
240
241    if (mode === "g8_only")  return "g8_only";
242    if (mode === "n8_only")  return "n8_only";
243    if (mode === "bom_only") return "bom_only";
244
245    if (mode === "ads_g8")   return "ads_g8";
246    if (mode === "ads_bom")  return "ads_bom";
247
248    return null;
249  }
250
251  function determineType() {
252    if (mode === "disabled") return null;
253
254    if (
255      mode === "g8_only" || mode === "n8_only" || mode === "bom_only" ||
256      mode === "ads_g8"  || mode === "ads_bom"
257    ) {
258      return determineTypeFresh();
259    }
260
261    let data = loadLS();
262
263    if (settingsUpdated) {
264      clearLS();
265      data = null;
266    }
267
268    if (shouldResetDaily(data)) {
269      clearLS();
270      data = null;
271    }
272
273    if (mode === "g8_first") {
274      if (!data) return "g8";
275      if (data.type === "g8") return "n8";
276      if (data.type === "n8") return null;
277      return null;
278    }
279
280    if (mode === "n8_first") {
281      if (!data) return "n8";
282      if (data.type === "n8") return "g8";
283      if (data.type === "g8") return null;
284      return null;
285    }
286
287    return null;
288  }
289
290  function setTitleText() {
291    $('[data-role="popupTitle"]').text(popupTitle);
292  }
293
294  function hideAllSteps() {
295    $(".seo4s-step").removeClass("active").hide();
296  }
297
298  function applyContentClass(type) {
299    const $content = $(".seo4s-popup-content");
300    $content.removeClass(
301      "seo4s-g8 seo4s-n8 seo4s-bom seo4s-ads seo4s-g8-ads seo4s-n8-ads seo4s-bom-ads"
302    );
303
304    if (type === "g8" || type === "g8_only") $content.addClass("seo4s-g8");
305    if (type === "n8" || type === "n8_only") $content.addClass("seo4s-n8");
306    if (type === "bom" || type === "bom_only") $content.addClass("seo4s-bom");
307
308    if (type === "ads_g8")  $content.addClass("seo4s-ads seo4s-g8-ads");
309    if (type === "ads_bom") $content.addClass("seo4s-ads seo4s-bom-ads");
310  }
311
312  function showStepByType(type) {
313    hideAllSteps();
314
315    if (type === "g8" || type === "g8_only") {
316      $("#seo4s-step-g8").show().addClass("active"); return true;
317    }
318    if (type === "n8" || type === "n8_only") {
319      $("#seo4s-step-n8").show().addClass("active"); return true;
320    }
321    if (type === "bom" || type === "bom_only") {
322      $("#seo4s-step-bom").show().addClass("active"); return true;
323    }
324
325    if (type === "ads_g8") {
326      $("#seo4s-step-ads-g8").show().addClass("active"); return true;
327    }
328    if (type === "ads_bom") {
329      $("#seo4s-step-ads-bom").show().addClass("active"); return true;
330    }
331
332    return false;
333  }
334
335  function openTarget() {
336    if (!currentType) return;
337
338    const pendingWindow = window.open("about:blank", "_blank");
339    if (pendingWindow) {
340      pendingWindow.opener = null;
341    }
342
343    resolveTargetUrl(currentType).then(function (payload) {
344      if (!payload.url) {
345        logError("SEO4S popup cannot resolve URL:", { type: currentType });
346        if (pendingWindow) pendingWindow.close();
347        return;
348      }
349
350      logResolveSource(payload.source || "unknown");
351      openUrl(payload.url, pendingWindow);
352    });
353  }
354
355  function showPopup() {
356    if (isShowing) return;
357
358    const type = determineType();
359    if (!type) return;
360
361    if (!hasTargetUrlByType(type)) return;
362
363    currentType = type;
364
365    setTitleText();
366    applyContentClass(type);
367
368    const ok = showStepByType(type);
369    if (!ok) return;
370
371    if (mode === "g8_first" || mode === "n8_first") {
372      saveLS(type);
373    }
374
375    isShowing = true;
376    $("#seo4s-popup").addClass("show");
377    $("body").css("overflow", "hidden");
378
379    fetchBannerData();
380  }
381
382  function hidePopup() {
383    if (!isShowing) return;
384    isShowing = false;
385
386    $("#seo4s-popup").removeClass("show");
387    $("body").css("overflow", "");
388    hideAllSteps();
389  }
390
391  function bindHandlers() {
392    $(document).on("click", ".seo4s-popup-close", function (e) {
393      e.preventDefault();
394      e.stopPropagation();
395      hidePopup();
396    });
397
398    $(document).on("click", "#seo4s-popup", function (e) {
399      if (e.target === this) hidePopup();
400    });
401
402    $(document).on("keyup", function (e) {
403      if (e.keyCode === 27) hidePopup();
404    });
405
406    $(document).on("click", ".seo4s-cta-image", function (e) {
407      e.preventDefault();
408      e.stopPropagation();
409      openTarget();
410    });
411
412    $(document).on("click", ".seo4s-ads-image", function (e) {
413      e.preventDefault();
414      e.stopPropagation();
415      openTarget();
416    });
417  }
418
419  function init() {
420    bindHandlers();
421    setTitleText();
422
423    if (timer) clearTimeout(timer);
424    timer = setTimeout(showPopup, popupDelay);
425  }
426
427  init();
428});

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.