PageSourceSearch

https://community.greentechinsights.com/widget.js

js greentechinsights.com collected 2026-09-26 02:31:49 UTC 2,950 bytes, 115 lines download raw bytes

1class SwapcardWidget {
2  constructor() {
3    this.listenMessage = this.listenMessage.bind(this);
4    this.init = this.init.bind(this);
5    this.updateVisibleArea = this.updateVisibleArea.bind(this);
6  }
7
8  scrollToIframeTop() {
9    if (!this.iframe) return;
10
11    const rect = this.iframe.getBoundingClientRect();
12
13    const viewportHeight =
14      window.innerHeight || document.documentElement.clientHeight;
15
16    const isTopVisible =
17      rect.top >= this.scrollTopOffset && rect.top <= viewportHeight;
18
19    if (isTopVisible) {
20      return;
21    }
22
23    const iframeTop = rect.top + window.scrollY;
24
25    window.scrollTo({
26      top: iframeTop - this.scrollTopOffset,
27      behavior: "smooth",
28    });
29  }
30
31  // The widget grows to the height of its content, so it never scrolls on its
32  // own. It cannot tell which part of it the visitor has on screen, and a
33  // popup would open in the middle of the whole list. We send it the part of
34  // the widget the visitor sees, measured from the top and the bottom edges.
35  sendVisibleArea() {
36    if (!this.iframe || !this.iframe.contentWindow) return;
37
38    const rect = this.iframe.getBoundingClientRect();
39
40    const viewportHeight =
41      window.innerHeight || document.documentElement.clientHeight;
42
43    const top = Math.min(Math.max(-rect.top, 0), rect.height);
44
45    const bottom = Math.min(
46      Math.max(rect.bottom - viewportHeight, 0),
47      rect.height,
48    );
49
50    const height = rect.height - top - bottom;
51
52    if (height <= 0) return;
53
54    this.iframe.contentWindow.postMessage(
55      { swapcardWidget: { type: "widget-visible-area", top, bottom, height } },
56      "*",
57    );
58  }
59
60  updateVisibleArea() {
61    if (this.visibleAreaFrame) return;
62
63    this.visibleAreaFrame = window.requestAnimationFrame(() => {
64      this.visibleAreaFrame = null;
65      this.sendVisibleArea();
66    });
67  }
68
69  watchVisibleArea() {
70    window.addEventListener("scroll", this.updateVisibleArea, {
71      passive: true,
72    });
73    window.addEventListener("resize", this.updateVisibleArea, {
74      passive: true,
75    });
76  }
77
78  listenMessage({ autoResize }) {
79    window.addEventListener("message", (event) => {
80      if (!event.data.swapcardWidget) return;
81
82      const { type, height } = event.data.swapcardWidget;
83
84      if (type === "widget-resize" && autoResize) {
85        this.iframe.style.height = `${height}px`;
86        this.updateVisibleArea();
87      }
88
89      if (type === "widget-loaded") {
90        this.updateVisibleArea();
91      }
92
93      if (type === "widget-navigate") {
94        this.scrollToIframeTop();
95      }
96    });
97  }
98
99  initIframe(iframeId) {
100    this.iframe = document.getElementById(iframeId);
101  }
102
103  init({
104    iframeId = "sc-widget",
105    autoResize = true,
106    scrollTopOffset = 20,
107  } = {}) {
108    this.initIframe(iframeId);
109    this.listenMessage({ autoResize });
110    this.watchVisibleArea();
111    this.scrollTopOffset = scrollTopOffset;
112  }
113}
114
115window._scWidget = new SwapcardWidget();

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.