refactor(services): update browser service for svelte gui integration
- commit
- 79f9593ac5967ea81e34dd870971bb22bf837a54
- author
- bamen · · 2025-09-15 05:21 UTC
- parent
- d70b2b0
- signature
- unsigned
1 file · +65 -18
M services/browser_service.go +65 -18
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | 7 | "embed" | |
| 8 | 8 | "errors" | |
| 9 | 9 | "fmt" | |
| 10 | + | "log" | |
| 10 | 11 | "math" | |
| 11 | 12 | neturl "net/url" | |
| 12 | 13 | "time" | |
| @@ -40,7 +41,7 @@ type BrowserService struct { | |||
| 40 | 41 | windowTitleUpdater WindowTitleUpdater | |
| 41 | 42 | webView *webkit.WebView | |
| 42 | 43 | initialURL string | |
| 43 | - | injectableScript string | |
| 44 | + | guiBundle string | |
| 44 | 45 | } | |
| 45 | 46 | ||
| 46 | 47 | // ServiceName returns the service name for frontend binding | |
| @@ -76,7 +77,7 @@ func NewBrowserService(cfg *config.Config, queries db.DatabaseQuerier) *BrowserS | |||
| 76 | 77 | windowTitleUpdater: nil, | |
| 77 | 78 | webView: nil, | |
| 78 | 79 | initialURL: "", | |
| 79 | - | injectableScript: "", | |
| 80 | + | guiBundle: "", | |
| 80 | 81 | } | |
| 81 | 82 | } | |
| 82 | 83 | ||
| @@ -90,32 +91,78 @@ func (s *BrowserService) AttachWebView(view *webkit.WebView) { | |||
| 90 | 91 | s.webView = view | |
| 91 | 92 | } | |
| 92 | 93 | ||
| 93 | - | // LoadInjectableScript loads the minified injectable controls script from assets | |
| 94 | - | func (s *BrowserService) LoadInjectableScript(assets embed.FS) error { | |
| 95 | - | scriptBytes, err := assets.ReadFile("frontend/dist/injected-controls.min.js") | |
| 94 | + | // LoadGUIBundle loads the unified GUI bundle from assets | |
| 95 | + | func (s *BrowserService) LoadGUIBundle(assets embed.FS) error { | |
| 96 | + | log.Printf("[browser] Attempting to load GUI bundle from assets/gui/gui.min.js") | |
| 97 | + | bundleBytes, err := assets.ReadFile("assets/gui/gui.min.js") | |
| 96 | 98 | if err != nil { | |
| 97 | - | return fmt.Errorf("failed to load injectable script: %w", err) | |
| 99 | + | log.Printf("[browser] ERROR: Failed to load GUI bundle: %v", err) | |
| 100 | + | return fmt.Errorf("failed to load GUI bundle: %w", err) | |
| 98 | 101 | } | |
| 99 | - | s.injectableScript = string(scriptBytes) | |
| 102 | + | s.guiBundle = string(bundleBytes) | |
| 103 | + | log.Printf("[browser] GUI bundle loaded successfully into browser service, size: %d bytes", len(bundleBytes)) | |
| 100 | 104 | return nil | |
| 101 | 105 | } | |
| 102 | 106 | ||
| 103 | - | // InjectControlScript injects the global controls script into the current page | |
| 104 | - | func (s *BrowserService) InjectControlScript(ctx context.Context) error { | |
| 107 | + | // GetGUIBundle returns the loaded GUI bundle string | |
| 108 | + | func (s *BrowserService) GetGUIBundle() string { | |
| 109 | + | return s.guiBundle | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // InjectGUIBundle injects the unified GUI bundle and initializes controls | |
| 113 | + | func (s *BrowserService) InjectGUIBundle(ctx context.Context) error { | |
| 105 | 114 | _ = ctx | |
| 106 | 115 | if s.webView == nil { | |
| 107 | 116 | return fmt.Errorf("webview not attached") | |
| 108 | 117 | } | |
| 109 | - | if s.injectableScript == "" { | |
| 110 | - | return fmt.Errorf("injectable script not loaded") | |
| 118 | + | if s.guiBundle == "" { | |
| 119 | + | return fmt.Errorf("GUI bundle not loaded") | |
| 111 | 120 | } | |
| 112 | - | wrappedScript := "(function(){try{" + | |
| 113 | - | "if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',function(){try{" + | |
| 114 | - | s.injectableScript + | |
| 115 | - | "}catch(e){console.warn('Dumber Browser controls failed to load on DOMContentLoaded:', e);}});}else{" + | |
| 116 | - | s.injectableScript + | |
| 117 | - | "}}catch(e){console.warn('Dumber Browser controls injection failed:', e);}})();" | |
| 118 | - | return s.webView.InjectScript(wrappedScript) | |
| 121 | + | ||
| 122 | + | // Inject the unified GUI bundle first | |
| 123 | + | bundleScript := s.guiBundle + | |
| 124 | + | ";(function(){" + | |
| 125 | + | "if(window.__dumber_gui && window.__dumber_gui.initializeControls){" + | |
| 126 | + | "window.__dumber_gui.initializeControls();" + | |
| 127 | + | "console.log('✅ Controls initialized via GUI bundle');" + | |
| 128 | + | "}else{console.error('❌ GUI bundle not properly loaded');}" + | |
| 129 | + | "})();" | |
| 130 | + | ||
| 131 | + | return s.webView.InjectScript(bundleScript) | |
| 132 | + | } | |
| 133 | + | ||
| 134 | + | // InjectToastSystem injects the GUI bundle and initializes the toast system | |
| 135 | + | func (s *BrowserService) InjectToastSystem(ctx context.Context, theme string) error { | |
| 136 | + | _ = ctx | |
| 137 | + | if s.webView == nil { | |
| 138 | + | return fmt.Errorf("webview not attached") | |
| 139 | + | } | |
| 140 | + | if s.guiBundle == "" { | |
| 141 | + | return fmt.Errorf("GUI bundle not loaded") | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // Set theme if provided | |
| 145 | + | themeScript := "" | |
| 146 | + | if theme != "" { | |
| 147 | + | themeScript = fmt.Sprintf("window.__dumber_initial_theme = '%s';", theme) | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | // Inject the unified GUI bundle and initialize toast system after DOM ready | |
| 151 | + | toastScript := s.guiBundle + ";" + themeScript + | |
| 152 | + | "(function(){" + | |
| 153 | + | "function initToast(){" + | |
| 154 | + | "if(window.__dumber_gui && window.__dumber_gui.initializeToast){" + | |
| 155 | + | "window.__dumber_gui.initializeToast().then(function(){" + | |
| 156 | + | "console.log('✅ Toast system initialized via GUI bundle');" + | |
| 157 | + | "}).catch(function(e){console.error('❌ Toast initialization failed:', e);});" + | |
| 158 | + | "}else{console.error('❌ GUI bundle not properly loaded');}" + | |
| 159 | + | "}" + | |
| 160 | + | "if(document.readyState==='loading'){" + | |
| 161 | + | "document.addEventListener('DOMContentLoaded',initToast);" + | |
| 162 | + | "}else{initToast();}" + | |
| 163 | + | "})();" | |
| 164 | + | ||
| 165 | + | return s.webView.InjectScript(toastScript) | |
| 119 | 166 | } | |
| 120 | 167 | ||
| 121 | 168 | // Navigate handles navigation to a URL and records it in history. | |
| @@ -7,6 +7,7 @@ import ( | |||||
| 7 | "embed" | 7 | "embed" | ||
| 8 | "errors" | 8 | "errors" | ||
| 9 | "fmt" | 9 | "fmt" | ||
| 10 | + | "log" | |||
| 10 | "math" | 11 | "math" | ||
| 11 | neturl "net/url" | 12 | neturl "net/url" | ||
| 12 | "time" | 13 | "time" | ||
| @@ -40,7 +41,7 @@ type BrowserService struct { | |||||
| 40 | windowTitleUpdater WindowTitleUpdater | 41 | windowTitleUpdater WindowTitleUpdater | ||
| 41 | webView *webkit.WebView | 42 | webView *webkit.WebView | ||
| 42 | initialURL string | 43 | initialURL string | ||
| 43 | - | injectableScript string | 44 | + | guiBundle string |
| 44 | } | 45 | } | ||
| 45 | 46 | ||||
| 46 | // ServiceName returns the service name for frontend binding | 47 | // ServiceName returns the service name for frontend binding | ||
| @@ -76,7 +77,7 @@ func NewBrowserService(cfg *config.Config, queries db.DatabaseQuerier) *BrowserS | |||||
| 76 | windowTitleUpdater: nil, | 77 | windowTitleUpdater: nil, | ||
| 77 | webView: nil, | 78 | webView: nil, | ||
| 78 | initialURL: "", | 79 | initialURL: "", | ||
| 79 | - | injectableScript: "", | 80 | + | guiBundle: "", |
| 80 | } | 81 | } | ||
| 81 | } | 82 | } | ||
| 82 | 83 | ||||
| @@ -90,32 +91,78 @@ func (s *BrowserService) AttachWebView(view *webkit.WebView) { | |||||
| 90 | s.webView = view | 91 | s.webView = view | ||
| 91 | } | 92 | } | ||
| 92 | 93 | ||||
| 93 | - | // LoadInjectableScript loads the minified injectable controls script from assets | 94 | + | // LoadGUIBundle loads the unified GUI bundle from assets |
| 94 | - | func (s *BrowserService) LoadInjectableScript(assets embed.FS) error { | 95 | + | func (s *BrowserService) LoadGUIBundle(assets embed.FS) error { |
| 95 | - | scriptBytes, err := assets.ReadFile("frontend/dist/injected-controls.min.js") | 96 | + | log.Printf("[browser] Attempting to load GUI bundle from assets/gui/gui.min.js") |
| 97 | + | bundleBytes, err := assets.ReadFile("assets/gui/gui.min.js") | |||
| 96 | if err != nil { | 98 | if err != nil { | ||
| 97 | - | return fmt.Errorf("failed to load injectable script: %w", err) | 99 | + | log.Printf("[browser] ERROR: Failed to load GUI bundle: %v", err) |
| 100 | + | return fmt.Errorf("failed to load GUI bundle: %w", err) | |||
| 98 | } | 101 | } | ||
| 99 | - | s.injectableScript = string(scriptBytes) | 102 | + | s.guiBundle = string(bundleBytes) |
| 103 | + | log.Printf("[browser] GUI bundle loaded successfully into browser service, size: %d bytes", len(bundleBytes)) | |||
| 100 | return nil | 104 | return nil | ||
| 101 | } | 105 | } | ||
| 102 | 106 | ||||
| 103 | - | // InjectControlScript injects the global controls script into the current page | 107 | + | // GetGUIBundle returns the loaded GUI bundle string |
| 104 | - | func (s *BrowserService) InjectControlScript(ctx context.Context) error { | 108 | + | func (s *BrowserService) GetGUIBundle() string { |
| 109 | + | return s.guiBundle | |||
| 110 | + | } | |||
| 111 | + | ||||
| 112 | + | // InjectGUIBundle injects the unified GUI bundle and initializes controls | |||
| 113 | + | func (s *BrowserService) InjectGUIBundle(ctx context.Context) error { | |||
| 105 | _ = ctx | 114 | _ = ctx | ||
| 106 | if s.webView == nil { | 115 | if s.webView == nil { | ||
| 107 | return fmt.Errorf("webview not attached") | 116 | return fmt.Errorf("webview not attached") | ||
| 108 | } | 117 | } | ||
| 109 | - | if s.injectableScript == "" { | 118 | + | if s.guiBundle == "" { |
| 110 | - | return fmt.Errorf("injectable script not loaded") | 119 | + | return fmt.Errorf("GUI bundle not loaded") |
| 111 | } | 120 | } | ||
| 112 | - | wrappedScript := "(function(){try{" + | 121 | + | |
| 113 | - | "if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',function(){try{" + | 122 | + | // Inject the unified GUI bundle first |
| 114 | - | s.injectableScript + | 123 | + | bundleScript := s.guiBundle + |
| 115 | - | "}catch(e){console.warn('Dumber Browser controls failed to load on DOMContentLoaded:', e);}});}else{" + | 124 | + | ";(function(){" + |
| 116 | - | s.injectableScript + | 125 | + | "if(window.__dumber_gui && window.__dumber_gui.initializeControls){" + |
| 117 | - | "}}catch(e){console.warn('Dumber Browser controls injection failed:', e);}})();" | 126 | + | "window.__dumber_gui.initializeControls();" + |
| 118 | - | return s.webView.InjectScript(wrappedScript) | 127 | + | "console.log('✅ Controls initialized via GUI bundle');" + |
| 128 | + | "}else{console.error('❌ GUI bundle not properly loaded');}" + | |||
| 129 | + | "})();" | |||
| 130 | + | ||||
| 131 | + | return s.webView.InjectScript(bundleScript) | |||
| 132 | + | } | |||
| 133 | + | ||||
| 134 | + | // InjectToastSystem injects the GUI bundle and initializes the toast system | |||
| 135 | + | func (s *BrowserService) InjectToastSystem(ctx context.Context, theme string) error { | |||
| 136 | + | _ = ctx | |||
| 137 | + | if s.webView == nil { | |||
| 138 | + | return fmt.Errorf("webview not attached") | |||
| 139 | + | } | |||
| 140 | + | if s.guiBundle == "" { | |||
| 141 | + | return fmt.Errorf("GUI bundle not loaded") | |||
| 142 | + | } | |||
| 143 | + | ||||
| 144 | + | // Set theme if provided | |||
| 145 | + | themeScript := "" | |||
| 146 | + | if theme != "" { | |||
| 147 | + | themeScript = fmt.Sprintf("window.__dumber_initial_theme = '%s';", theme) | |||
| 148 | + | } | |||
| 149 | + | ||||
| 150 | + | // Inject the unified GUI bundle and initialize toast system after DOM ready | |||
| 151 | + | toastScript := s.guiBundle + ";" + themeScript + | |||
| 152 | + | "(function(){" + | |||
| 153 | + | "function initToast(){" + | |||
| 154 | + | "if(window.__dumber_gui && window.__dumber_gui.initializeToast){" + | |||
| 155 | + | "window.__dumber_gui.initializeToast().then(function(){" + | |||
| 156 | + | "console.log('✅ Toast system initialized via GUI bundle');" + | |||
| 157 | + | "}).catch(function(e){console.error('❌ Toast initialization failed:', e);});" + | |||
| 158 | + | "}else{console.error('❌ GUI bundle not properly loaded');}" + | |||
| 159 | + | "}" + | |||
| 160 | + | "if(document.readyState==='loading'){" + | |||
| 161 | + | "document.addEventListener('DOMContentLoaded',initToast);" + | |||
| 162 | + | "}else{initToast();}" + | |||
| 163 | + | "})();" | |||
| 164 | + | ||||
| 165 | + | return s.webView.InjectScript(toastScript) | |||
| 119 | } | 166 | } | ||
| 120 | 167 | ||||
| 121 | // Navigate handles navigation to a URL and records it in history. | 168 | // Navigate handles navigation to a URL and records it in history. | ||