PageSourceSearch

https://www.grlcopper.com/wp-content/themes/grl_super/static/js/super.js?v=1791045745

js grlcopper.com collected 2026-10-04 04:51:50 UTC 9,552 bytes, 315 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function () {
2  var buttons = document.querySelectorAll('.super_get_quote_button');
3  var modalEl = document.getElementById('fixed_feedback');
4
5  if (!modalEl || buttons.length === 0) return;
6
7  var modal = bootstrap.Modal.getOrCreateInstance(modalEl);
8
9  buttons.forEach(function (btn) {
10      btn.addEventListener('click', function (e) {
11          e.preventDefault();
12          modal.show();
13      });
14  });
15});
16
17document.addEventListener("DOMContentLoaded", function () {
18  document.querySelectorAll(".has_video").forEach(function (el) {
19    el.addEventListener("click", function () {
20      const modalId = el.getAttribute("data-modal");
21      const modalEl = document.getElementById(modalId);
22      if (modalEl) {
23        const modal = new bootstrap.Modal(modalEl);
24        modal.show();
25      }
26    });
27  });
28});
29document.addEventListener('DOMContentLoaded', () => {
30  // 监听所有 modal 的 show 和 hide 事件
31  document.querySelectorAll('.modal').forEach(modal => {
32      // 缓存初始 src 到 data-src 上(只做一次)
33      const iframe = modal.querySelector('iframe');
34      if (iframe && !iframe.dataset.src) {
35          iframe.dataset.src = iframe.src;
36      }
37
38      // 模态框关闭时清空 src,让 iframe 失效
39      modal.addEventListener('hide.bs.modal', () => {
40          const iframe = modal.querySelector('iframe');
41          if (iframe && iframe.src) {
42              iframe.src = '';
43          }
44      });
45
46      // 模态框打开时恢复原始 src
47      modal.addEventListener('show.bs.modal', () => {
48          const iframe = modal.querySelector('iframe');
49          if (iframe && iframe.dataset.src) {
50              iframe.src = iframe.dataset.src;
51          }
52      });
53  });
54});
55document.addEventListener("DOMContentLoaded", function () {
56  document.querySelectorAll(".super_edit_button").forEach(function (el) {
57    el.addEventListener("click", function () {
58      const modalId = el.getAttribute("data-modal");
59      const modalEl = document.getElementById(modalId);
60      if (modalEl) {
61        const modal = new bootstrap.Modal(modalEl);
62        modal.show();
63      }
64    });
65  });
66});
67$(document).off("focusin.bs.modal");
68
69function updateFormWithGeoData(data) {
70  // console.log(data);
71  $(".feedback").each(function () {
72    // console.log(data.ip);
73    $(this)
74      .find('input[name="device-type"]')
75      .val(/Mobi|Android/i.test(navigator.userAgent) ? "Mobile" : "PC");
76    $(this).find('input[name="userip"]').val(data.ip);
77    $(this).find('input[name="ip2country"]').val(data.country_name);
78    $(this)
79      .find('input[name="ip2city"]')
80      .val(
81        data.continent_name +
82          "--" +
83          data.country_name +
84          "--" +
85          data.state_prov +
86          "--" +
87          data.district +
88          "--" +
89          data.city
90      );
91    $(this).find('input[name="ip2calling_code"]').val(data.calling_code);
92    $(this).find('input[name="phone"]').val(data.calling_code);
93    $(this).find('input[name="country"]').val(data.country_name);
94    $(this).find('input[name="page_url"]').val(window.location.href);
95  });
96}
97document.addEventListener("DOMContentLoaded", () => {
98  let geoData = localStorage.getItem("geoData");
99  if (geoData) {
100    geoData = JSON.parse(geoData);
101    // if (geoData.country_name == "China") {
102    //   if (window.location.pathname !== "/404") {
103    //     window.location = "/404";
104    //   }
105    // }
106    updateFormWithGeoData(geoData);
107  } else {
108    // 如果没有缓存数据,则发起 API 请求获取
109    fetch(
110      "https://api.ipgeolocation.io/ipgeo?apiKey=8c66569730c747febd2b69490a7eaa42&fields=continent_name,country_name,state_prov,district,city,calling_code"
111    )
112      .then((response) => response.json())
113      .then((data) => {
114        localStorage.setItem("geoData", JSON.stringify(data));
115        // if (data.country_name == "China") {
116        //   if (window.location.pathname !== "/404") {
117        //     window.location = "/404";
118        //   }
119        // }
120        updateFormWithGeoData(data);
121      })
122      .catch((error) => {
123        console.error("Error fetching geo data:", error);
124      });
125  }
126});
127// 数字递增动画
128document.addEventListener("DOMContentLoaded", () => {
129  const counters = document.querySelectorAll(".counter");
130
131  const animateCounters = () => {
132    counters.forEach((counter) => {
133      if (counter.dataset.animated) return;
134
135      const countValue = counter.getAttribute("data-count").trim();
136
137      // 正则提取数字部分和单位后缀(包括 m+、k+、% 等)
138      const match = countValue.match(/^([\d\.]+)(.*)$/);
139      if (!match) return; // 无法匹配时跳过
140
141      const [_, numberStr, suffix] = match;
142      const target = parseFloat(numberStr);
143      if (isNaN(target)) return; // 不是有效数字则跳过
144
145      let current = 0;
146      const increment = target / 100;
147
148      const updateCounter = () => {
149        if (current < target) {
150          current += increment;
151          counter.textContent = Math.ceil(current) + suffix;
152          requestAnimationFrame(updateCounter);
153        } else {
154          counter.textContent = target + suffix;
155          counter.dataset.animated = "true";
156        }
157      };
158
159      // 进入可视区域才触发动画
160      const rect = counter.getBoundingClientRect();
161      if (rect.top < window.innerHeight && rect.bottom >= 0) {
162        updateCounter();
163      }
164    });
165  };
166
167  window.addEventListener("scroll", animateCounters);
168  window.addEventListener("load", animateCounters);
169});
170 
171
172
173
174
175
176
177class FocusCarousel {
178  constructor(container) {
179    this.container = typeof container === 'string' ? document.getElementById(container) : container;
180    this.track = this.container.querySelector('.slider-track');
181    this.prevBtn = this.container.querySelector('.prevBtn');
182    this.nextBtn = this.container.querySelector('.nextBtn');
183    this.isAnimating = false;
184
185    // 绑定事件
186    this.nextBtn.addEventListener('click', () => this.slideNext());
187    this.prevBtn.addEventListener('click', () => this.slidePrev());
188
189    window.addEventListener('resize', () => this.updateMargins(true));
190
191    this.updateMargins(true);
192  }
193
194  getItemWidth() {
195    const firstItem = this.track.querySelector('.slider-item');
196    return firstItem ? firstItem.getBoundingClientRect().width : 300;
197  }
198
199  updateMargins(immediate = false) {
200    const items = this.track.querySelectorAll('.slider-item');
201    const itemWidth = this.getItemWidth();
202    const halfWidth = itemWidth / 2;
203
204    items.forEach(item => {
205      item.classList.remove('active');
206      item.style.transition = immediate ? 'none' : 'margin-left 0.6s ease, transform 0.6s ease, z-index 0.6s ease';
207      item.style.zIndex = 1;
208    });
209
210    if (items.length === 0) return;
211
212    items[0].classList.add('active');
213    items[0].style.zIndex = 10;
214
215    items.forEach((item, i) => {
216      if (i === 0 || i === 1) {
217        item.style.marginLeft = '0px';
218      } else {
219        item.style.marginLeft = `-${halfWidth}px`;
220      }
221    });
222  }
223
224  slideNext() {
225    if (this.isAnimating) return;
226    this.isAnimating = true;
227
228    const itemWidth = this.getItemWidth();
229    const halfWidth = itemWidth / 2;
230    const items = this.track.querySelectorAll('.slider-item');
231    if (items.length < 3) {
232      this.isAnimating = false;
233      return;
234    }
235
236    const activeItem = items[0];
237    const thirdItem = items[2];
238
239    const duration = 600;
240    const startTime = performance.now();
241
242    const animate = (time) => {
243      let elapsed = time - startTime;
244      let progress = Math.min(elapsed / duration, 1);
245
246      activeItem.style.marginLeft = `${-itemWidth * progress}px`;
247      thirdItem.style.marginLeft = `${-halfWidth * (1 - progress)}px`;
248
249      if (progress < 1) {
250        requestAnimationFrame(animate);
251      } else {
252        const first = this.track.children[0];
253        this.track.appendChild(first);
254        this.updateMargins(true);
255        this.isAnimating = false;
256      }
257    };
258
259    requestAnimationFrame(animate);
260  }
261
262  slidePrev() {
263    if (this.isAnimating) return;
264    this.isAnimating = true;
265
266    const itemWidth = this.getItemWidth();
267    const halfWidth = itemWidth / 2;
268    const items = this.track.querySelectorAll('.slider-item');
269    if (items.length < 3) {
270      this.isAnimating = false;
271      return;
272    }
273
274    const last = this.track.children[this.track.children.length - 1];
275    this.track.insertBefore(last, this.track.children[0]);
276    this.updateMargins(true);
277
278    const itemsAfter = this.track.querySelectorAll('.slider-item');
279    const activeItem = itemsAfter[0];
280    const thirdItem = itemsAfter[2];
281
282    activeItem.style.marginLeft = `-${itemWidth}px`;
283    thirdItem.style.marginLeft = '0px';
284
285    const duration = 600;
286    const startTime = performance.now();
287
288    const animate = (time) => {
289      let elapsed = time - startTime;
290      let progress = Math.min(elapsed / duration, 1);
291
292      activeItem.style.marginLeft = `${-itemWidth + itemWidth * progress}px`;
293      thirdItem.style.marginLeft = `${-halfWidth * progress}px`;
294
295      if (progress < 1) {
296        requestAnimationFrame(animate);
297      } else {
298        this.updateMargins(true);
299        this.isAnimating = false;
300      }
301    };
302
303    requestAnimationFrame(animate);
304  }
305}
306
307
308
309document.addEventListener('DOMContentLoaded', function () {
310  document.querySelectorAll('.with-hidden-more').forEach(function (el) {
311      el.addEventListener('click', function () {
312          el.classList.toggle('expanded');
313      });
314  });
315});

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.