PageSourceSearch

https://bongda.com.vn/static/js/ads-manager.js?v=1.0.5

js bongda.com.vn collected 2026-10-02 04:43:47 UTC 10,283 bytes, 326 lines download raw bytes

1/**
2 * Quản lý việc tải và hiển thị quảng cáo
3 */
4const AdsManager = {
5  adsData: null,
6  isLoading: false,
7  isLoaded: false,
8  initializedCodes: new Set(),
9
10  isElementVisible: function (element) {
11    if (!element) return false;
12
13    const style = window.getComputedStyle(element);
14    if (style.display === 'none' || style.visibility === 'hidden') {
15      return false;
16    }
17
18    if (typeof element.checkVisibility === 'function') {
19      return element.checkVisibility();
20    }
21
22    return true;
23  },
24
25  getGptSlotsByIds: function (slotIds) {
26    if (!window.googletag?.pubads || !slotIds.length) {
27      return [];
28    }
29
30    return slotIds
31      .map(id => window.googletag.pubads().getSlots().find(slot => slot.getSlotElementId() === id))
32      .filter(Boolean);
33  },
34
35  enableGptServicesOnce: function () {
36    if (window.__ADS_GPT_SERVICES_ENABLED__) {
37      return;
38    }
39
40    window.googletag.pubads().enableSingleRequest();
41    window.googletag.pubads().collapseEmptyDivs(true);
42    window.googletag.enableServices();
43    window.__ADS_GPT_SERVICES_ENABLED__ = true;
44  },
45
46  setAdContainerState: function (container, hasAds) {
47    if (!container) return;
48
49    const stateTargets = [container];
50    const adsWrap = container.closest('.adsWrap');
51
52    if (adsWrap) {
53      stateTargets.push(adsWrap);
54    }
55
56    stateTargets.forEach(element => {
57      element.classList.toggle('no-ads', !hasAds);
58      element.classList.toggle('has-ads', hasAds);
59    });
60  },
61
62  getCategoryId: function () {
63    const categoryElement = document.getElementById('ads-category-id');
64    const rawCategoryId = categoryElement?.textContent?.trim();
65
66    if (!rawCategoryId) {
67      return '';
68    }
69
70    try {
71      return JSON.parse(rawCategoryId);
72    } catch (error) {
73      console.warn('[AdsManager] Category ID không hợp lệ:', error);
74      return '';
75    }
76  },
77
78  getRequestContext: function () {
79    const isMobile = window.innerWidth <= 768;
80    const isDesktop = window.innerWidth > 768;
81    const isHome = window.location.pathname === '/';
82    const isDetail = window.location.pathname.includes('.html');
83    const isCategory = window.location.pathname !== '/' && !window.location.pathname.includes('.html');
84    const categoryId = this.getCategoryId();
85    const params = new URLSearchParams({
86      isMobile: String(isMobile),
87      isDesktop: String(isDesktop),
88      isHome: String(isHome),
89      isDetail: String(isDetail),
90      isCategory: String(isCategory),
91      category_id: categoryId == null ? '' : String(categoryId),
92      current_path: window.location.pathname,
93    });
94
95    return {
96      isMobile,
97      isDesktop,
98      isHome,
99      isDetail,
100      isCategory,
101      categoryId,
102      url: `/api/ads/get-list?${params.toString()}`,
103    };
104  },
105
106  getAdsDataPromise: function () {
107    if (!window.__ADS_DATA_PROMISE__) {
108      const { url } = this.getRequestContext();
109      window.__ADS_DATA_PROMISE__ = fetch(url)
110        .then(response => response.json())
111        .then(data => {
112          if (data && data.status && data.data && data.data.length > 0) {
113            return data.data;
114          } else {
115            return [];
116          }
117        })
118        .catch(error => {
119          console.error('[AdsManager] Lỗi khi tải quảng cáo:', error);
120          return [];
121        });
122    }
123    return window.__ADS_DATA_PROMISE__;
124  },
125
126  initialize: function () {
127    if (this.isLoaded || this.isLoading) {
128      return Promise.resolve(this.adsData);
129    }
130
131    console.log('[AdsManager] Bắt đầu tải dữ liệu quảng cáo...');
132    this.isLoading = true;
133
134    const {
135      isMobile,
136      isDesktop,
137      isHome,
138      isDetail,
139      isCategory,
140      categoryId,
141      url,
142    } = this.getRequestContext();
143
144    console.log(`[AdsManager] Tham số: Mobile=${isMobile}, Desktop=${isDesktop}, Home=${isHome}, Detail=${isDetail}, Category=${isCategory}, CategoryID=${categoryId}`);
145
146    console.log(`[AdsManager] Gọi API: ${url}`);
147
148    return this.getAdsDataPromise().then(data => {
149      this.isLoading = false;
150      this.adsData = data;
151      this.isLoaded = true;
152      console.log(`[AdsManager] Đã tải ${this.adsData.length} vùng quảng cáo thành công`);
153      return this.adsData;
154    });
155  },
156
157  displayAdsV2: function (code, container) {
158    this.initialize().then(adsData => {
159      const adDiv = container || document.getElementById(`ads-${code}`);
160      if (!adDiv) {
161        console.error(`[AdsManager] Không tìm thấy div: ads-${
161code}`);
162        return;
163      }
164
165      const matchingArea = adsData.find(area => area.code === code);
166      if (!matchingArea || !matchingArea.adsCode?.length) {
167        this.setAdContainerState(adDiv, false);
168        return;
169      }
170
171      try {
172        this.setAdContainerState(adDiv, true);
173        adDiv.innerHTML = '';
174        matchingArea.adsCode.forEach(adCodeObj => {
175          const tempDiv = document.createElement('div');
176          tempDiv.innerHTML = adCodeObj.code;
177
178          // Append phần tử không phải script
179          Array.from(tempDiv.childNodes).forEach(node => {
180            if (node.tagName !== 'SCRIPT') {
181              adDiv.appendChild(node.cloneNode(true));
182            } else {
183              const script = document.createElement('script');
184              if (node?.src) {
185                script.src = node.src;
186                script.async = true;
187              } else {
188                script.textContent = node?.textContent;
189              }
190              adDiv.appendChild(script);
191            }
192          });
193        });
194
195        const scriptCode = matchingArea.adsCode[0].head;
196        if (scriptCode) {
197          const adSlotDivs = adDiv.querySelectorAll('div[id^="div-gpt-ad-"]');
198          window.googletag.cmd.push(function() {
199            const adSlotIds = Array.from(adSlotDivs)
200              .map(div => div.id)
201              .filter(Boolean);
202            let slotsToRefresh = AdsManager.getGptSlotsByIds(adSlotIds);
203            const shouldDefineSlots = !adSlotIds.length || slotsToRefresh.length !== adSlotIds.length;
204
205            if (shouldDefineSlots) {
206              try {
207                new Function(scriptCode)();
208              } catch (error) {
209                console.error(`[AdsManager] Lỗi khi định nghĩa GPT slot: ${code}`, error);
210              }
211
212              slotsToRefresh = AdsManager.getGptSlotsByIds(adSlotIds);
213            } else {
214              console.debug(`[AdsManager] Bỏ qua GPT slot đã được định nghĩa: ${code}`);
215            }
216
217            AdsManager.enableGptServicesOnce();
218
219            if (slotsToRefresh.length) {
220              window.googletag.pubads().refresh(slotsToRefresh);
221            }
222          });
223        }
224      } catch (error) {
225        this.setAdContainerState(adDiv, false);
226        console.error(`[AdsManager] Lỗi khi hiển thị quảng cáo: ${code}`, error);
227      }
228    });
229  },
230
231  displayAds: function (code, container) {
232    this.initialize().then(adsData => {
233      const adDiv = container || document.getElementById(`ads-${code}`);
234      if (!adDiv) {
235        console.error(`[AdsManager] Không tìm thấy div: ads-${code}`);
236        return;
237      }
238
239      const matchingArea = adsData.find(area => area.code === code);
240      if (matchingArea && matchingArea.adsCode && matchingArea.adsCode.length > 0) {
241        this.setAdContainerState(adDiv, true);
242        // console.log({matchingArea, code});
243        // console.log(`[AdsManager] Hiển thị quảng cáo cho vùng: ${code} (${matchingArea.adsCode.length} mã)`);
244        adDiv.innerHTML = ''; // clear trước
245        matchingArea.adsCode.forEach(adCodeObj => {
246          const tempDiv = document.createElement('div');
247          tempDiv.innerHTML = adCodeObj.code;
248
249          // Append phần tử không phải script
250          Array.from(tempDiv.childNodes).forEach(node => {
251            if (node.tagName !== 'SCRIPT') {
252              adDiv.appendChild(node.cloneNode(true));
253            }
254          });
255          // Đảm bảo slot đã được define
256          if (adCodeObj.head) {
257            googletag.cmd.push(function () {
258              eval(adCodeObj.head); // defineSlot
259            });
260          }
261
262          // Re-execute script
263          const scripts = tempDiv.querySelectorAll('script');
264          scripts.forEach(oldScript => {
265            const newScript = document.createElement('script');
266
267            if (oldScript.src) {
268              newScript.src = oldScript.src;
269            } else {
270              newScript.text = oldScript.textContent;
271            }
272
273            Array.from(oldScript.attributes).forEach(attr => {
274              if (attr.name !== 'src') {
275                newScript.setAttribute(attr.name, attr.value);
276              }
277            });
278
279            adDiv.appendChild(newScript);
280          });
281        });
282      } else {
283        this.setAdContainerState(adDiv, false);
284        console.log(`[AdsManager] Không tìm thấy quảng cáo cho vùng: ${code}`);
285      }
286    });
287  },
288
289  initAllAdsBlocks: function () {
290    const adsWrappers = document.querySelectorAll('.ads-wrapper');
291    console.log(`[AdsManager] Tìm thấy ${adsWrappers.length} vùng quảng cáo trên trang`);
292
293    const wrappersByCode = new Map();
294
295    adsWrappers.forEach(wrapper => {
296      const codeMatch = wrapper.id.match(/ads-(.+)/);
297      if (codeMatch && codeMatch[1]) {
298        const code = codeMatch[1];
299        const currentWrapper = wrappersByCode.get(code);
300
301        if (!currentWrapper || (!this.isElementVisible(currentWrapper) && this.isElementVisible(wrapper))) {
302          wrappersByCode.set(code, wrapper);
303        }
304      }
305    });
306
307    wrappersByCode.forEach((wrapper, code) => {
308      if (this.initializedCodes.has(code)) {
309        console.debug(`[AdsManager] Bỏ qua vùng quảng cáo đã khởi tạo: ${code}`);
310        return;
311      }
312
313      this.initializedCodes.add(code);
314      console.log(`[AdsManager] Khởi tạo vùng quảng cáo: ${code}`);
315      this.displayAdsV2(code, wrapper);
316    });
317  }
318};
319
320document.addEventListener('DOMContentLoaded', function () {
321  console.log('[AdsManager] DOM đã sẵn sàng, bắt đầu khởi tạo AdsManager');
322
323  AdsManager.initialize().then(() => {
324    AdsManager.initAllAdsBlocks();
325  });
326});

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.