1+ ( function ( ) {
2+ 'use strict' ;
3+
4+ // ==================== Configuration ====================
5+ var CONFIG = {
6+ apiKey : 'sk_live_vEFiRm_CGXO3AUsmOjcu1H7lEnk32J1zvrQhcY8M' ,
7+ agentId : '243f7652-5185-4d9f-974b-b5b0d1ce29d2' ,
8+ modeShortId : 'web-qa-bnb' ,
9+ primaryBrandColor : '#f0b90b' ,
10+ botAvatar : 'https://static.bnbchain.org/home-ui/static/images/logo.svg' ,
11+ botName : 'Ask BNB Chain AI' ,
12+ introMessage : 'How do I get started?' ,
13+ quickQuestions : [
14+ 'How do I get BNB?' ,
15+ 'How do I get started with RWA?' ,
16+ 'How do I start building or deploying a dApp?' ,
17+ 'Where can I find funding or grants?'
18+ ] ,
19+ disclaimerText : 'My answers might not always be 100% accurate. Double-check when in doubt.' ,
20+ disclaimerLink : 'https://www.bnbchain.org/en/ai-bot-disclaimer' ,
21+ analyticsEvent : 'click_AiBot_floatBtn'
22+ } ;
23+
24+ // ==================== State ====================
25+ var sdkButton = null ;
26+
27+ // ==================== Helper Functions ====================
28+ function findSdkButton ( ) {
29+ var buttons = document . querySelectorAll ( 'button' ) ;
30+ for ( var i = 0 ; i < buttons . length ; i ++ ) {
31+ var btn = buttons [ i ] ;
32+ if ( ! btn . closest ( '.ai-bot-wrapper' ) && ! btn . closest ( 'dialog' ) ) {
33+ var text = btn . textContent || '' ;
34+ if ( text . indexOf ( 'Ask AI' ) !== - 1 ) {
35+ return btn ;
36+ }
37+ }
38+ }
39+ return null ;
40+ }
41+
42+ function triggerSdkButton ( ) {
43+ if ( ! sdkButton ) {
44+ sdkButton = findSdkButton ( ) ;
45+ }
46+ if ( sdkButton ) {
47+ sdkButton . click ( ) ;
48+ }
49+ }
50+
51+ function trackAnalytics ( ) {
52+ if ( window . dataLayer ) {
53+ window . dataLayer . push ( { event : CONFIG . analyticsEvent } ) ;
54+ }
55+ }
56+
57+ // ==================== Event Binding ====================
58+ function bindCustomButton ( ) {
59+ var wrapper = document . querySelector ( '.ai-bot-wrapper' ) ;
60+ if ( ! wrapper ) return ;
61+
62+ // Skip if already bound
63+ if ( wrapper . _boundClick ) return ;
64+
65+ // Remove existing listeners by cloning
66+ var newWrapper = wrapper . cloneNode ( true ) ;
67+ wrapper . parentNode . replaceChild ( newWrapper , wrapper ) ;
68+
69+ // Re-select after clone
70+ newWrapper = document . querySelector ( '.ai-bot-wrapper' ) ;
71+ if ( ! newWrapper ) return ;
72+
73+ newWrapper . addEventListener ( 'click' , function ( e ) {
74+ e . preventDefault ( ) ;
75+ e . stopPropagation ( ) ;
76+ triggerSdkButton ( ) ;
77+ trackAnalytics ( ) ;
78+ } ) ;
79+
80+ // Mark as bound
81+ newWrapper . _boundClick = true ;
82+ }
83+
84+ // ==================== SDK Initialization ====================
85+ function initSuperIntern ( ) {
86+ if ( ! window . SuperIntern ) {
87+ console . warn ( 'SuperIntern SDK not loaded' ) ;
88+ return ;
89+ }
90+
91+ window . SuperIntern . ChatButton ( {
92+ baseSettings : {
93+ apiKey : CONFIG . apiKey ,
94+ environment : 'production' ,
95+ agentId : CONFIG . agentId ,
96+ modeShortId : CONFIG . modeShortId ,
97+ primaryBrandColor : CONFIG . primaryBrandColor ,
98+ theme : { colorMode : { type : 'dark' } }
99+ } ,
100+ aiChatSettings : {
101+ botAvatarSrcUrl : CONFIG . botAvatar ,
102+ aiAssistantName : CONFIG . botName ,
103+ introMessage : CONFIG . introMessage ,
104+ quickQuestions : CONFIG . quickQuestions ,
105+ disclaimer : {
106+ text : CONFIG . disclaimerText ,
107+ link : CONFIG . disclaimerLink
108+ }
109+ } ,
110+ modalSettings : {
111+ onOpenChange : function ( isOpen ) {
112+ console . log ( 'Modal:' , isOpen ? 'opened' : 'closed' ) ;
113+ }
114+ } ,
115+ label : 'Ask AI' ,
116+ // Visually hide SDK button (still functional for click events)
117+ style : {
118+ position : 'absolute' ,
119+ width : '1px' ,
120+ height : '1px' ,
121+ padding : '0' ,
122+ margin : '-1px' ,
123+ overflow : 'hidden' ,
124+ clip : 'rect(0,0,0,0)' ,
125+ border : '0' ,
126+ opacity : '0'
127+ }
128+ } ) ;
129+
130+ // Cache SDK button reference
131+ setTimeout ( function ( ) {
132+ sdkButton = findSdkButton ( ) ;
133+ bindCustomButton ( ) ;
134+ } , 100 ) ;
135+ }
136+
137+ // ==================== SPA Navigation Support ====================
138+ function rebindAfterNavigation ( ) {
139+ // Re-find SDK button (it may have been re-rendered)
140+ sdkButton = null ;
141+ setTimeout ( function ( ) {
142+ sdkButton = findSdkButton ( ) ;
143+ bindCustomButton ( ) ;
144+ } , 100 ) ;
145+ // Double-check after a longer delay for slow page transitions
146+ setTimeout ( function ( ) {
147+ if ( ! sdkButton ) sdkButton = findSdkButton ( ) ;
148+ bindCustomButton ( ) ;
149+ } , 500 ) ;
150+ setTimeout ( function ( ) {
151+ if ( ! sdkButton ) sdkButton = findSdkButton ( ) ;
152+ bindCustomButton ( ) ;
153+ } , 1000 ) ;
154+ }
155+
156+ function setupSpaSupport ( ) {
157+ // Handle pushState
158+ var originalPushState = history . pushState ;
159+ history . pushState = function ( ) {
160+ originalPushState . apply ( this , arguments ) ;
161+ rebindAfterNavigation ( ) ;
162+ } ;
163+
164+ // Handle replaceState
165+ var originalReplaceState = history . replaceState ;
166+ history . replaceState = function ( ) {
167+ originalReplaceState . apply ( this , arguments ) ;
168+ rebindAfterNavigation ( ) ;
169+ } ;
170+
171+ // Handle popstate (back/forward)
172+ window . addEventListener ( 'popstate' , rebindAfterNavigation ) ;
173+
174+ // Handle hashchange
175+ window . addEventListener ( 'hashchange' , rebindAfterNavigation ) ;
176+
177+ // MutationObserver for DOM changes (covers Discourse and other SPAs)
178+ var observer = new MutationObserver ( function ( mutations ) {
179+ var shouldRebind = false ;
180+ for ( var i = 0 ; i < mutations . length ; i ++ ) {
181+ var mutation = mutations [ i ] ;
182+ // Check if our wrapper was removed or major DOM changes occurred
183+ if ( mutation . removedNodes . length > 0 ) {
184+ for ( var j = 0 ; j < mutation . removedNodes . length ; j ++ ) {
185+ var node = mutation . removedNodes [ j ] ;
186+ if ( node . nodeType === 1 &&
187+ ( node . classList && node . classList . contains ( 'ai-bot-wrapper' ) ||
188+ node . querySelector && node . querySelector ( '.ai-bot-wrapper' ) ) ) {
189+ shouldRebind = true ;
190+ break ;
191+ }
192+ }
193+ }
194+ }
195+ if ( shouldRebind ) {
196+ rebindAfterNavigation ( ) ;
197+ }
198+ } ) ;
199+
200+ observer . observe ( document . body , {
201+ childList : true ,
202+ subtree : true
203+ } ) ;
204+
205+ // Periodic check as fallback (every 2 seconds)
206+ setInterval ( function ( ) {
207+ var wrapper = document . querySelector ( '.ai-bot-wrapper' ) ;
208+ if ( wrapper && ! wrapper . _boundClick ) {
209+ rebindAfterNavigation ( ) ;
210+ }
211+ } , 2000 ) ;
212+ }
213+
214+ // ==================== Bootstrap ====================
215+ function init ( ) {
216+ if ( window . SuperIntern ) {
217+ initSuperIntern ( ) ;
218+ } else {
219+ window . addEventListener ( 'load' , initSuperIntern ) ;
220+ }
221+ setupSpaSupport ( ) ;
222+ }
223+
224+ if ( document . readyState === 'loading' ) {
225+ document . addEventListener ( 'DOMContentLoaded' , init ) ;
226+ } else {
227+ init ( ) ;
228+ }
229+ } ) ( ) ;
0 commit comments