PageSourceSearch

https://chatbot-cdn.nsws.gov.in/scripts/chat-embedding.js

js nsws.gov.in collected 2026-10-02 05:01:29 UTC 13,574 bytes, 495 lines download raw bytes

1/**
2 * NSWS Chat Embedding Script
3 * This script can be included in any project to embed the NSWS Chatbot via an iframe
4 *
5 * Usage:
6 * <script src="https://chatbot.nsws.gov.in/chat-embedding.js"></script>
7 */
8
9(function () {
10  "use strict";
11
12  // Configuration
13  const MESSAGE_ORIGIN = "https://chatbot.nsws.gov.in";
14  // const MESSAGE_ORIGIN = "http://localhost:3001"; // Use localhost for development and testing
15  const EMBEDDED_PAGE_URL = `${MESSAGE_ORIGIN}/embedded`;
16
17  // Styles
18  const STYLES = `
19    .nsws-chat-widget {
20      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
21        "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
22        sans-serif;
23      -webkit-font-smoothing: antialiased;
24      -moz-osx-font-smoothing: grayscale;
25      position: fixed;
26      top: 0;
27      left: 0;
28      width: 0;
29      height: 0;
30      pointer-events: none;
31      z-index: 9998;
32    }
33
34    .nsws-chat-logo-button {
35      position: fixed;
36      bottom: 24px;
37      right: 24px;
38      z-index: 9998;
39      width: 60px;
40      height: 60px;
41      border: none;
42      border-radius: 50%;
43      background: transparent;
44      cursor: pointer;
45      display: flex;
46      align-items: center;
47      justify-content: center;
48      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
49      transition: all 0.3s ease;
50      padding: 0;
51      overflow: hidden;
52      pointer-events: auto;
53    }
54
55    .nsws-chat-logo-button:hover {
56      transform: scale(1.1);
57      box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
58    }
59
60    .nsws-chat-logo-button img {
61      width: 100%;
62      height: 100%;
63      object-fit: contain;
64    }
65
66    .nsws-chat-notification-badge {
67      position: absolute;
68      bottom: 0;
69      left: 0;
70      width: 12px;
71      height: 12px;
72      border-radius: 50%;
73      background-color: #00d084;
74      border: 2px solid white;
75      animation: pulse 1.5s ease-in-out infinite;
76    }
77
78    @keyframes pulse {
79      0%, 100% {
80        transform: scale(1);
81      }
82      50% {
83        transform: scale(1.1);
84      }
85    }
86
87    .nsws-chat-container {
88      position: fixed;
89      bottom: 24px;
90      right: 24px;
91      z-index: 9999;
92      width: 512px;
93      max-height: calc(100vh - 80px);
94      height: 90vh;
95      background: white;
96      border-radius: 16px;
97      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
98      display: flex;
99      flex-direction: column;
100      overflow: hidden;
101      opacity: 0;
102      visibility: hidden;
103      transform: scale(0.95) translateY(40px);
104      transition: all 0.3s ease;
105      pointer-events: none;
106    }
107
108    .nsws-chat-container.open {
109      opacity: 1;
110      visibility: visible;
111      transform: scale(1) translateY(0);
112      pointer-events: auto;
113    }
114
115    .nsws-chat-container.fullscreen {
116      position: fixed;
117      inset: 0;
118      width: 100%;
119      height: 100%;
120      border-radius: 0;
121      max-height: 100vh;
122      bottom: auto;
123      right: auto;
124    }
125
126    .nsws-chat-logo-button.hidden {
127      display: none !important;
128    }
129
130    .nsws-chat-controls {
131      position: absolute;
132      top: 1rem;
133      right: 1rem;
134      display: flex;
135      align-items: center;
136      gap: 0;
137      z-index: 9998;
138      pointer-events: auto;
139    }
140
141    .nsws-chat-icon-button {
142      background: rgba(255, 255, 255, 0.1);
143      border: none;
144      color: white;
145      cursor: pointer;
146      padding: 4px;
147      display: flex;
148      align-items: center;
149      justify-content: center;
150      font-size: 20px;
151      transition: all 0.2s ease;
152      border-radius: 4px;
153      margin: 0 4px;
154    }
155
156    .nsws-chat-icon-button:hover {
157      background-color: rgba(255, 255, 255, 0.2);
158      transform: scale(1.05);
159    }
160
161    .nsws-chat-iframe {
162      flex: 1;
163      border: none;
164      background: white;
165      pointer-events: auto;
166      overflow: hidden;
167    }
168
169    .nsws-chat-loader {
170      position: absolute;
171      top: 0;
172      left: 0;
173      right: 0;
174      bottom: 0;
175      display: flex;
176      align-items: center;
177      justify-content: center;
178      background: #EAF3FF;
179      z-index: 10000;
180      transition: opacity 0.3s ease, visibility 0.3s ease;
181      opacity: 1;
182      visibility: visible;
183    }
184
185    .nsws-chat-loader.hidden {
186      opacity: 0;
187      visibility: hidden;
188      pointer-events: none;
189    }
190
191    .nsws-loader-dots {
192      display: flex;
193      align-items: center;
194      justify-content: center;
195      gap: 8px;
196    }
197
198    .nsws-loader-dot {
199      width: 12px;
200      height: 12px;
201      border-radius: 50%;
202      animation: nsws-dot-bounce 1.4s infinite ease-in-out both;
203    }
204
205    .nsws-loader-dot:nth-child(1) {
206      background: #011C4D;
207      animation-delay: -0.32s;
208    }
209
210    .nsws-loader-dot:nth-child(2) {
211      background: #F89B46;
212      animation-delay: -0.16s;
213    }
214
215    .nsws-loader-dot:nth-child(3) {
216      background: #011C4D;
217      animation-delay: 0s;
218    }
219
220    @keyframes nsws-dot-bounce {
221      0%, 80%, 100% {
222        transform: scale(0.8);
223        opacity: 0.6;
224      }
225      40% {
226        transform: scale(1.2);
227        opacity: 1;
228      }
229    }
230
231    /* Animation for chat opening */
232    @media (max-width: 640px) {
233      .nsws-chat-container {
234        width: 100%;
235        height: 100%;
236        bottom: 0;
237        right: 0;
238        border-radius: 0;
239      }
240
241      .nsws-chat-logo-button {
242        width: 56px;
243        height: 56px;
244      }
245    }
246
247    /* Utility classes */
248    .nsws-hidden {
249      display: none !important;
250    }
251
252    .nsws-visible {
253      display: flex !important;
254    }
255  `;
256
257  /**
258   * Initialize the chat widget
259   */
260  function initializeChatWidget() {
261    // Create style element
262    const styleElement = document.createElement("style");
263    styleElement.textContent = STYLES;
264    document.head.appendChild(styleElement);
265
266    // Create widget container
267    const widgetContainer = document.createElement("div");
268    widgetContainer.className = "nsws-chat-widget";
269    widgetContainer.id = "nsws-chat-widget";
270
271    // Create logo button
272    const logoButton = document.createElement("button");
273    logoButton.className = "nsws-chat-logo-button";
274    logoButton.id = "nsws-chat-logo";
275    logoButton.title = "Chat with BharatAssist";
276    logoButton.innerHTML = `
277      <img src="https://chatbot-cdn.nsws.gov.in/images/botIcon.png" alt="BharatAssist" />
278      <div class="nsws-chat-notification-badge" id="nsws-notification-badge" style="display: none;"></div>
279    `;
280
281    // Create chat container
282    const chatContainer = document.createElement("div");
283    chatContainer.className = "nsws-chat-container";
284    chatContainer.id = "nsws-chat-container";
285
286    // Create control buttons overlay
287    const controlsContainer = document.createElement("div");
288    controlsContainer.className = "nsws-chat-controls";
289    controlsContainer.id = "nsws-chat-controls";
290    controlsContainer.innerHTML = `
291      <button class="nsws-chat-icon-button" id="nsws-minimize-btn" title="Minimize Chat" aria-label="Minimize">
292        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
293          <line x1="5" y1="12" x2="19" y2="12"></line>
294        </svg>
295      </button>
296      <button class="nsws-chat-icon-button" id="nsws-expand-btn" title="Toggle Fullscreen" aria-label="Expand">
297        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
298          <polyline points="15 3 21 3 21 9"></polyline>
299          <polyline points="9 21 3 21 3 15"></polyline>
300          <line x1="21" y1="3" x2="3" y2="21"></line>
301        </svg>
302      </button>
303      <button class="nsws-chat-icon-button" id="nsws-close-btn" title="Close Chat" aria-label="Close">
304        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
305          <line x1="18" y1="6" x2="6" y2="18"></line>
306          <line x1="6" y1="6" x2="18" y2="18"></line>
307        </svg>
308      </button>
309    `;
310
311    // Create iframe
312    const iframe = document.createElement("iframe");
313    iframe.className = "nsws-chat-iframe";
314    iframe.id = "nsws-chat-iframe";
315    iframe.src = EMBEDDED_PAGE_URL;
316    iframe.allow = "clipboard-write";
317
318    // Create loader
319    const loader = document.createElement("div");
320    loader.className = "nsws-chat-loader";
321    loader.id = "nsws-chat-loader";
322    loader.innerHTML = `
323      <div class="nsws-loader-dots">
324        <div class="nsws-loader-dot"></div>
325        <div class="nsws-loader-dot"></div>
326        <div class="nsws-loader-dot"></div>
327      </div>
328    `;
329
330    // Build chat container
331    chatContainer.appendChild(iframe);
332    chatContainer.appendChild(loader);
333    chatContainer.appendChild(controlsContainer);
334
335    // Add to widget container
336    widgetContainer.appendChild(logoButton);
337    widgetContainer.appendChild(chatContainer);
338
339    // Add widget to page
340    document.body.appendChild(widgetContainer);
341
342    // Set up event listeners
343    setupEventListeners(logoButton, chatContainer, iframe);
344  }
345
346  /**
347   * Setup event listeners for the chat widget
348   */
349  function setupEventListeners(logoButton, chatContainer, iframe) {
350    let isOpen = false;
351    let isFullscreen = false;
352    let hasMessages = false;
353    const notificationBadge = document.getElementById(
354      "nsws-notification-badge",
355    );
356    const loader = document.getElementById("nsws-chat-loader");
357
358    // Hide loader when iframe finishes loading
359    iframe.addEventListener("load", () => {
360      if (loader) {
361        loader.classList.add("hidden");
362      }
363    });
364
365    // Show loader if iframe fails to load after timeout
366    const loaderTimeout = setTimeout(() => {
367      if (loader && !loader.classList.contains("hidden")) {
368        loader.classList.add("hidden");
369      }
370    }, 10000); // 10 second timeout
371
372    // Clear timeout when iframe loads
373    iframe.addEventListener("load", () => {
374      clearTimeout(loaderTimeout);
375    });
376
377    // Logo button click
378    logoButton.addEventListener("click", () => {
379      isOpen = !isOpen;
380      if (isOpen) {
381        chatContainer.classList.add("open");
382        logoButton.classList.add("hidden");
383        notificationBadge.style.display = "none";
384        // Send message to iframe to show chat
385        iframe.contentWindow.postMessage(
386          { type: "SHOW_CHAT", isEmbedded: true },
387          MESSAGE_ORIGIN,
388        );
389      } else {
390        chatContainer.classList.remove("open");
391        logoButton.classList.remove("hidden");
392        if (hasMessages) {
393          notificationBadge.style.display = "block";
394        }
395        // Send message to iframe to hide chat
396        iframe.contentWindow.postMessage(
397          { type: "HIDE_CHAT", isEmbedded: true },
398          MESSAGE_ORIGIN,
399        );
400      }
401    });
402
403    // Minimize button
404    document
405      .getElementById("nsws-minimize-btn")
406      .addEventListener("click", () => {
407        isOpen = false;
408        chatContainer.classList.remove("open");
409        logoButton.classList.remove("hidden");
410        if (hasMessages) {
411          notificationBadge.style.display = "block";
412        }
413        if (isFullscreen) {
414          isFullscreen = false;
415          chatContainer.classList.remove("fullscreen");
416        }
417      });
418
419    // Expand button
420    document.getElementById("nsws-expand-btn").addEventListener("click", () => {
421      isFullscreen = !isFullscreen;
422      if (isFullscreen) {
423        chatContainer.classList.add("fullscreen");
424        logoButton.classList.add("hidden");
425        // Notify iframe about fullscreen state
426        iframe.contentWindow.postMessage(
427          { type: "TOGGLE_FULLSCREEN", isFullscreen: true },
428          MESSAGE_ORIGIN,
429        );
430      } else {
431        chatContainer.classList.remove("fullscreen");
432        logoButton.classList.remove("hidden");
433        // Notify iframe about fullscreen state
434        iframe.contentWindow.postMessage(
435          { type: "TOGGLE_FULLSCREEN", isFullscreen: false },
436          MESSAGE_ORIGIN,
437        );
438      }
439    });
440
441    // Close button
442    document.getElementById("nsws-close-btn").addEventListener("click", () => {
443      isOpen = false;
444      chatContainer.classList.remove("open");
445      logoButton.classList.remove("hidden");
446      if (isFullscreen) {
447        isFullscreen = false;
448        chatContainer.classList.remove("fullscreen");
449      }
450      // Reset the conversation in iframe
451      iframe.contentWindow.postMessage(
452        { type: "RESET_CHAT", isEmbedded: true },
453        MESSAGE_ORIGIN,
454      );
455    });
456
457    // Listen for messages from iframe
458    window.addEventListener("message", (event) => {
459      // Verify the message origin
460      if (event.origin !== MESSAGE_ORIGIN) return;
461
462      const { type, data } = event.data;
463
464      if (type === "CHAT_HAS_MESSAGES") {
465        hasMessages = true;
466        // Show notification badge only if chat is not open
467        if (!isOpen) {
468          notificationBadge.style.display = "block";
469        }
470      }
471
472      if (type === "CHAT_CLOSED") {
473        isOpen = false;
474        isFullscreen = false;
475        chatContainer.classList.remove("open");
476        chatContainer.classList.remove("fullscreen");
477        logoButton.style.display = "flex";
478      }
479    });
480
481    // Handle resize to ensure proper display
482    window.addEventListener("resize", () => {
483      if (isFullscreen && chatContainer.classList.contains("fullscreen")) {
484        // Fullscreen handles itself via CSS
485      }
486    });
487  }
488
489  // Initialize when DOM is ready
490  if (document.readyState === "loading") {
491    document.addEventListener("DOMContentLoaded", initializeChatWidget);
492  } else {
493    initializeChatWidget();
494  }
495})();

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.