plusui-native-core 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Core/Features/Browser/browser.cpp +162 -115
- package/Core/Features/Browser/browser.ts +13 -1
- package/Core/Features/WebView/webview.cpp +68 -0
- package/Core/include/plusui/browser.hpp +46 -43
- package/Core/include/plusui/plusui +18 -0
- package/Core/include/plusui/plusui.hpp +40 -0
- package/Core/scripts/generate-umbrella-header.mjs +77 -0
- package/package.json +2 -2
|
@@ -1,182 +1,229 @@
|
|
|
1
|
+
#include <algorithm>
|
|
1
2
|
#include <iostream>
|
|
2
3
|
#include <plusui/browser.hpp>
|
|
3
4
|
#include <plusui/webview.hpp>
|
|
5
|
+
#include <plusui/window.hpp>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
#ifdef _WIN32
|
|
10
|
+
#define WIN32_LEAN_AND_MEAN
|
|
11
|
+
#include <shellapi.h>
|
|
12
|
+
#include <windows.h>
|
|
13
|
+
|
|
14
|
+
#endif
|
|
4
15
|
|
|
5
16
|
namespace plusui {
|
|
6
17
|
|
|
18
|
+
// Keep secondary windows alive
|
|
19
|
+
static std::vector<std::shared_ptr<Window>> g_windows;
|
|
20
|
+
static std::vector<std::shared_ptr<WebView>> g_webviews;
|
|
21
|
+
|
|
7
22
|
struct Browser::Impl {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
23
|
+
WebView *webview = nullptr;
|
|
24
|
+
std::map<std::string, std::string> routes;
|
|
25
|
+
std::string currentRoute;
|
|
26
|
+
BrowserState state;
|
|
27
|
+
|
|
28
|
+
std::vector<NavigateCallback> navigateCallbacks;
|
|
29
|
+
std::vector<StateCallback> stateCallbacks;
|
|
30
|
+
std::vector<LoadCallback> loadStartCallbacks;
|
|
31
|
+
std::vector<LoadCallback> loadEndCallbacks;
|
|
32
|
+
std::vector<std::function<void(const std::string &)>> loadErrorCallbacks;
|
|
33
|
+
|
|
34
|
+
void updateState() {
|
|
35
|
+
if (webview) {
|
|
36
|
+
state.url = webview->getURL();
|
|
37
|
+
state.title = webview->getTitle();
|
|
38
|
+
state.canGoBack = webview->canGoBack();
|
|
39
|
+
state.canGoForward = webview->canGoForward();
|
|
40
|
+
state.isLoading = webview->isLoading();
|
|
41
|
+
|
|
42
|
+
for (auto &cb : stateCallbacks) {
|
|
43
|
+
cb(state);
|
|
44
|
+
}
|
|
31
45
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
updateState();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void notifyNavigate(const std::string &url) {
|
|
49
|
+
state.url = url;
|
|
50
|
+
for (auto &cb : navigateCallbacks) {
|
|
51
|
+
cb(url);
|
|
39
52
|
}
|
|
53
|
+
updateState();
|
|
54
|
+
}
|
|
40
55
|
};
|
|
41
56
|
|
|
42
57
|
Browser::Browser() : pImpl(std::make_shared<Impl>()) {}
|
|
43
58
|
|
|
44
59
|
Browser::~Browser() = default;
|
|
45
60
|
|
|
46
|
-
Browser Browser::create(WebView*
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
Browser Browser::create(WebView *webview) {
|
|
62
|
+
Browser browser;
|
|
63
|
+
browser.pImpl->webview = webview;
|
|
64
|
+
|
|
65
|
+
if (webview) {
|
|
66
|
+
webview->onNavigationStart([impl = browser.pImpl](const std::string &url) {
|
|
67
|
+
impl->notifyNavigate(url);
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
webview->onLoadStart([impl = browser.pImpl]() {
|
|
72
|
+
impl->state.isLoading = true;
|
|
73
|
+
for (auto &cb : impl->loadStartCallbacks) {
|
|
74
|
+
cb();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
webview->onLoadEnd([impl = browser.pImpl]() {
|
|
79
|
+
impl->state.isLoading = false;
|
|
80
|
+
impl->updateState();
|
|
81
|
+
for (auto &cb : impl->loadEndCallbacks) {
|
|
82
|
+
cb();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
webview->onLoadError(
|
|
87
|
+
[impl = browser.pImpl](const std::string &error, int code) {
|
|
88
|
+
(void)code; // Suppress unused warning
|
|
89
|
+
impl->state.isLoading = false;
|
|
90
|
+
for (auto &cb : impl->loadErrorCallbacks) {
|
|
91
|
+
cb(error);
|
|
92
|
+
}
|
|
61
93
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
impl->updateState();
|
|
66
|
-
for (auto& cb : impl->loadEndCallbacks) {
|
|
67
|
-
cb();
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
webview->onLoadError([impl = browser.pImpl](const std::string& error, int code) {
|
|
72
|
-
(void)code; // Suppress unused warning
|
|
73
|
-
impl->state.isLoading = false;
|
|
74
|
-
for (auto& cb : impl->loadErrorCallbacks) {
|
|
75
|
-
cb(error);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return browser;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return browser;
|
|
81
97
|
}
|
|
82
98
|
|
|
83
|
-
void Browser::navigate(const std::string&
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
99
|
+
void Browser::navigate(const std::string &url) {
|
|
100
|
+
if (pImpl->webview) {
|
|
101
|
+
pImpl->webview->navigate(url);
|
|
102
|
+
pImpl->notifyNavigate(url);
|
|
103
|
+
}
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
void Browser::goBack() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
107
|
+
if (pImpl->webview && pImpl->webview->canGoBack()) {
|
|
108
|
+
pImpl->webview->goBack();
|
|
109
|
+
pImpl->updateState();
|
|
110
|
+
}
|
|
95
111
|
}
|
|
96
112
|
|
|
97
113
|
void Browser::goForward() {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
114
|
+
if (pImpl->webview && pImpl->webview->canGoForward()) {
|
|
115
|
+
pImpl->webview->goForward();
|
|
116
|
+
pImpl->updateState();
|
|
117
|
+
}
|
|
102
118
|
}
|
|
103
119
|
|
|
104
120
|
void Browser::reload() {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
if (pImpl->webview) {
|
|
122
|
+
pImpl->webview->reload();
|
|
123
|
+
}
|
|
108
124
|
}
|
|
109
125
|
|
|
110
126
|
void Browser::stop() {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
if (pImpl->webview) {
|
|
128
|
+
pImpl->webview->stop();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
void Browser::openExternal(const std::string &url) {
|
|
133
|
+
#ifdef _WIN32
|
|
134
|
+
ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
|
135
|
+
#elif __APPLE__
|
|
136
|
+
std::string command = "open \"" + url + "\"";
|
|
137
|
+
system(command.c_str());
|
|
138
|
+
#else
|
|
139
|
+
std::string command = "xdg-open \"" + url + "\"";
|
|
140
|
+
system(command.c_str());
|
|
141
|
+
#endif
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
void Browser::openNewWindow(const std::string &url) {
|
|
145
|
+
WindowConfig winConfig;
|
|
146
|
+
winConfig.title = "New Window";
|
|
147
|
+
|
|
148
|
+
auto win = std::make_shared<Window>(Window::create(winConfig));
|
|
149
|
+
win->show();
|
|
150
|
+
g_windows.push_back(win);
|
|
151
|
+
|
|
152
|
+
WebViewConfig webConfig;
|
|
153
|
+
auto wv = std::make_shared<WebView>(
|
|
154
|
+
WebView::create(win->nativeHandle(), webConfig));
|
|
155
|
+
wv->setWindow(win);
|
|
156
|
+
wv->navigate(url);
|
|
157
|
+
g_webviews.push_back(wv);
|
|
158
|
+
|
|
159
|
+
win->onClose([win, wv]() {
|
|
160
|
+
auto itW = std::find(g_windows.begin(), g_windows.end(), win);
|
|
161
|
+
if (itW != g_windows.end())
|
|
162
|
+
g_windows.erase(itW);
|
|
163
|
+
|
|
164
|
+
auto itV = std::find(g_webviews.begin(), g_webviews.end(), wv);
|
|
165
|
+
if (itV != g_webviews.end())
|
|
166
|
+
g_webviews.erase(itV);
|
|
167
|
+
});
|
|
114
168
|
}
|
|
115
169
|
|
|
116
170
|
std::string Browser::getURL() const {
|
|
117
|
-
|
|
171
|
+
return pImpl->webview ? pImpl->webview->getURL() : "";
|
|
118
172
|
}
|
|
119
173
|
|
|
120
174
|
std::string Browser::getTitle() const {
|
|
121
|
-
|
|
175
|
+
return pImpl->webview ? pImpl->webview->getTitle() : "";
|
|
122
176
|
}
|
|
123
177
|
|
|
124
|
-
BrowserState Browser::getState() const {
|
|
125
|
-
return pImpl->state;
|
|
126
|
-
}
|
|
178
|
+
BrowserState Browser::getState() const { return pImpl->state; }
|
|
127
179
|
|
|
128
180
|
bool Browser::canGoBack() const {
|
|
129
|
-
|
|
181
|
+
return pImpl->webview ? pImpl->webview->canGoBack() : false;
|
|
130
182
|
}
|
|
131
183
|
|
|
132
184
|
bool Browser::canGoForward() const {
|
|
133
|
-
|
|
185
|
+
return pImpl->webview ? pImpl->webview->canGoForward() : false;
|
|
134
186
|
}
|
|
135
187
|
|
|
136
|
-
bool Browser::isLoading() const {
|
|
137
|
-
return pImpl->state.isLoading;
|
|
138
|
-
}
|
|
188
|
+
bool Browser::isLoading() const { return pImpl->state.isLoading; }
|
|
139
189
|
|
|
140
190
|
void Browser::onNavigate(NavigateCallback callback) {
|
|
141
|
-
|
|
191
|
+
pImpl->navigateCallbacks.push_back(callback);
|
|
142
192
|
}
|
|
143
193
|
|
|
144
194
|
void Browser::onStateChange(StateCallback callback) {
|
|
145
|
-
|
|
195
|
+
pImpl->stateCallbacks.push_back(callback);
|
|
146
196
|
}
|
|
147
197
|
|
|
148
198
|
void Browser::onLoadStart(LoadCallback callback) {
|
|
149
|
-
|
|
199
|
+
pImpl->loadStartCallbacks.push_back(callback);
|
|
150
200
|
}
|
|
151
201
|
|
|
152
202
|
void Browser::onLoadEnd(LoadCallback callback) {
|
|
153
|
-
|
|
203
|
+
pImpl->loadEndCallbacks.push_back(callback);
|
|
154
204
|
}
|
|
155
205
|
|
|
156
|
-
void Browser::onLoadError(
|
|
157
|
-
|
|
206
|
+
void Browser::onLoadError(
|
|
207
|
+
std::function<void(const std::string &error)> callback) {
|
|
208
|
+
pImpl->loadErrorCallbacks.push_back(callback);
|
|
158
209
|
}
|
|
159
210
|
|
|
160
|
-
void Browser::setRoutes(const std::map<std::string, std::string
|
|
161
|
-
|
|
211
|
+
void Browser::setRoutes(const std::map<std::string, std::string> &routes) {
|
|
212
|
+
pImpl->routes = routes;
|
|
162
213
|
}
|
|
163
214
|
|
|
164
|
-
void Browser::push(const std::string&
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
215
|
+
void Browser::push(const std::string &route) {
|
|
216
|
+
pImpl->currentRoute = route;
|
|
217
|
+
auto it = pImpl->routes.find(route);
|
|
218
|
+
if (it != pImpl->routes.end()) {
|
|
219
|
+
navigate(it->second);
|
|
220
|
+
} else {
|
|
221
|
+
navigate(route);
|
|
222
|
+
}
|
|
172
223
|
}
|
|
173
224
|
|
|
174
|
-
void Browser::replace(const std::string& route)
|
|
175
|
-
push(route);
|
|
176
|
-
}
|
|
225
|
+
void Browser::replace(const std::string &route) { push(route); }
|
|
177
226
|
|
|
178
|
-
std::string Browser::getCurrentRoute() const {
|
|
179
|
-
return pImpl->currentRoute;
|
|
180
|
-
}
|
|
227
|
+
std::string Browser::getCurrentRoute() const { return pImpl->currentRoute; }
|
|
181
228
|
|
|
182
229
|
} // namespace plusui
|
|
@@ -25,7 +25,7 @@ async function invoke(method: string, args?: unknown[]): Promise<unknown> {
|
|
|
25
25
|
throw new Error('Browser API not initialized');
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
return _invoke(method, args);
|
|
28
|
+
return _invoke!(method, args);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const _navigateCallbacks: NavigateCallback[] = [];
|
|
@@ -66,6 +66,18 @@ export const browser = {
|
|
|
66
66
|
await invoke('browser.navigate', [url]);
|
|
67
67
|
},
|
|
68
68
|
|
|
69
|
+
async open(url: string): Promise<void> {
|
|
70
|
+
await invoke('browser.navigate', [url]);
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
async openExternal(url: string): Promise<void> {
|
|
74
|
+
await invoke('browser.openExternal', [url]);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
async openNewWindow(url: string): Promise<void> {
|
|
78
|
+
await invoke('browser.openNewWindow', [url]);
|
|
79
|
+
},
|
|
80
|
+
|
|
69
81
|
async goBack(): Promise<void> {
|
|
70
82
|
await invoke('browser.goBack', []);
|
|
71
83
|
},
|
|
@@ -140,6 +140,35 @@ WebView WebView::create(void *windowHandle, const WebViewConfig &config) {
|
|
|
140
140
|
nullptr);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
// Disable default webview drag & drop behavior
|
|
144
|
+
// This prevents files from being loaded in the browser
|
|
145
|
+
// and allows the native FileDrop API to handle them instead
|
|
146
|
+
std::string disableDragDropScript = R"(
|
|
147
|
+
(function() {
|
|
148
|
+
// Prevent default drag and drop behavior on document/window
|
|
149
|
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(function(eventName) {
|
|
150
|
+
document.addEventListener(eventName, function(e) {
|
|
151
|
+
// Only prevent default on document.body or document.documentElement
|
|
152
|
+
// to allow custom drop zones to still work
|
|
153
|
+
if (e.target === document.body || e.target === document.documentElement || e.target === document) {
|
|
154
|
+
e.preventDefault();
|
|
155
|
+
e.stopPropagation();
|
|
156
|
+
}
|
|
157
|
+
}, true);
|
|
158
|
+
|
|
159
|
+
window.addEventListener(eventName, function(e) {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
e.stopPropagation();
|
|
162
|
+
}, true);
|
|
163
|
+
});
|
|
164
|
+
})();
|
|
165
|
+
)";
|
|
166
|
+
pImpl->webview->AddScriptToExecuteOnDocumentCreated(
|
|
167
|
+
std::wstring(disableDragDropScript.begin(),
|
|
168
|
+
disableDragDropScript.end())
|
|
169
|
+
.c_str(),
|
|
170
|
+
nullptr);
|
|
171
|
+
|
|
143
172
|
// Set up WebMessageReceived handler for JS->C++ bridge
|
|
144
173
|
pImpl->webview->add_WebMessageReceived(
|
|
145
174
|
Callback<
|
|
@@ -617,6 +646,45 @@ WebView WebView::create(void *windowHandle, const WebViewConfig &config) {
|
|
|
617
646
|
[config.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
|
|
618
647
|
}
|
|
619
648
|
|
|
649
|
+
// Disable default drag & drop behavior to allow native FileDrop API
|
|
650
|
+
NSString *disableDragDropScript = @"(function() {"
|
|
651
|
+
"['dragenter', 'dragover', 'dragleave', 'drop'].forEach(function(eventName) {"
|
|
652
|
+
"document.addEventListener(eventName, function(e) {"
|
|
653
|
+
"if (e.target === document.body || e.target === document.documentElement || e.target === document) {"
|
|
654
|
+
"e.preventDefault();"
|
|
655
|
+
"e.stopPropagation();"
|
|
656
|
+
"}"
|
|
657
|
+
"}, true);"
|
|
658
|
+
"window.addEventListener(eventName, function(e) {"
|
|
659
|
+
"e.preventDefault();"
|
|
660
|
+
"e.stopPropagation();"
|
|
661
|
+
"}, true);"
|
|
662
|
+
"});"
|
|
663
|
+
"})();";
|
|
664
|
+
|
|
665
|
+
WKUserScript *userScript = [[WKUserScript alloc]
|
|
666
|
+
initWithSource:disableDragDropScript
|
|
667
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
|
|
668
|
+
forMainFrameOnly:NO];
|
|
669
|
+
[config.userContentController addUserScript:userScript];
|
|
670
|
+
|
|
671
|
+
// Hide scrollbars if disabled
|
|
672
|
+
if (!wv.pImpl->config.scrollbars) {
|
|
673
|
+
NSString *scrollbarScript = @"(function() {"
|
|
674
|
+
"var css = 'html, body { overflow: hidden !important; margin: 0 !important; padding: 0 !important; } ::-webkit-scrollbar { display: none !important; width: 0 !important; height: 0 !important; }';"
|
|
675
|
+
"var style = document.createElement('style');"
|
|
676
|
+
"style.type = 'text/css';"
|
|
677
|
+
"style.appendChild(document.createTextNode(css));"
|
|
678
|
+
"(document.head || document.documentElement).appendChild(style);"
|
|
679
|
+
"})();";
|
|
680
|
+
|
|
681
|
+
WKUserScript *scrollScript = [[WKUserScript alloc]
|
|
682
|
+
initWithSource:scrollbarScript
|
|
683
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
|
|
684
|
+
forMainFrameOnly:NO];
|
|
685
|
+
[config.userContentController addUserScript:scrollScript];
|
|
686
|
+
}
|
|
687
|
+
|
|
620
688
|
NSView *parentView = (__bridge NSView *)windowHandle;
|
|
621
689
|
wv.pImpl->wkWebView =
|
|
622
690
|
[[WKWebView alloc] initWithFrame:parentView.bounds configuration:config];
|
|
@@ -1,66 +1,69 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include <functional>
|
|
4
|
+
#include <map>
|
|
4
5
|
#include <memory>
|
|
5
6
|
#include <string>
|
|
6
|
-
#include <map>
|
|
7
7
|
|
|
8
8
|
namespace plusui {
|
|
9
9
|
|
|
10
10
|
class WebView;
|
|
11
11
|
|
|
12
12
|
struct BrowserState {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
std::string url;
|
|
14
|
+
std::string title;
|
|
15
|
+
bool canGoBack = false;
|
|
16
|
+
bool canGoForward = false;
|
|
17
|
+
bool isLoading = false;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
struct RouteConfig {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
std::string path;
|
|
22
|
+
std::string url;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
class Browser {
|
|
26
26
|
public:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
27
|
+
using NavigateCallback = std::function<void(const std::string &url)>;
|
|
28
|
+
using StateCallback = std::function<void(const BrowserState &state)>;
|
|
29
|
+
using LoadCallback = std::function<void()>;
|
|
30
|
+
|
|
31
|
+
Browser();
|
|
32
|
+
~Browser();
|
|
33
|
+
|
|
34
|
+
static Browser create(WebView *webview);
|
|
35
|
+
|
|
36
|
+
void navigate(const std::string &url);
|
|
37
|
+
void goBack();
|
|
38
|
+
void goForward();
|
|
39
|
+
void reload();
|
|
40
|
+
void stop();
|
|
41
|
+
|
|
42
|
+
void openExternal(const std::string &url);
|
|
43
|
+
void openNewWindow(const std::string &url);
|
|
44
|
+
|
|
45
|
+
std::string getURL() const;
|
|
46
|
+
std::string getTitle() const;
|
|
47
|
+
BrowserState getState() const;
|
|
48
|
+
|
|
49
|
+
bool canGoBack() const;
|
|
50
|
+
bool canGoForward() const;
|
|
51
|
+
bool isLoading() const;
|
|
52
|
+
|
|
53
|
+
void onNavigate(NavigateCallback callback);
|
|
54
|
+
void onStateChange(StateCallback callback);
|
|
55
|
+
void onLoadStart(LoadCallback callback);
|
|
56
|
+
void onLoadEnd(LoadCallback callback);
|
|
57
|
+
void onLoadError(std::function<void(const std::string &error)> callback);
|
|
58
|
+
|
|
59
|
+
void setRoutes(const std::map<std::string, std::string> &routes);
|
|
60
|
+
void push(const std::string &route);
|
|
61
|
+
void replace(const std::string &route);
|
|
62
|
+
std::string getCurrentRoute() const;
|
|
60
63
|
|
|
61
64
|
private:
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
struct Impl;
|
|
66
|
+
std::shared_ptr<Impl> pImpl;
|
|
64
67
|
};
|
|
65
68
|
|
|
66
69
|
} // namespace plusui
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PlusUI - Main Framework Header
|
|
3
|
+
*
|
|
4
|
+
* Standard library style include (no .hpp extension needed)
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* #include <plusui>
|
|
8
|
+
* using namespace plusui;
|
|
9
|
+
*
|
|
10
|
+
* This provides access to all core framework features including:
|
|
11
|
+
* - App & Window management
|
|
12
|
+
* - Browser & WebView
|
|
13
|
+
* - Events & Bindings
|
|
14
|
+
* - FileDrop, Keyboard, Clipboard
|
|
15
|
+
* - Display, Tray, Menu
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include <plusui/plusui.hpp>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PlusUI - Umbrella Header (Auto-generated)
|
|
5
|
+
*
|
|
6
|
+
* This file is automatically generated by scripts/generate-umbrella-header.mjs
|
|
7
|
+
* DO NOT EDIT MANUALLY - your changes will be overwritten!
|
|
8
|
+
*
|
|
9
|
+
* To regenerate: node Core/scripts/generate-umbrella-header.mjs
|
|
10
|
+
*
|
|
11
|
+
* This umbrella header includes all PlusUI framework headers.
|
|
12
|
+
* Include this single file to access the entire framework:
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* #include <plusui> // Standard library style (recommended)
|
|
16
|
+
* // OR
|
|
17
|
+
* #include <plusui/plusui.hpp>
|
|
18
|
+
*
|
|
19
|
+
* using namespace plusui;
|
|
20
|
+
*
|
|
21
|
+
* For faster compile times in production, you can include only
|
|
22
|
+
* the specific headers you need instead of this convenience header.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
#include <plusui/app.hpp>
|
|
26
|
+
#include <plusui/bindings.hpp>
|
|
27
|
+
#include <plusui/browser.hpp>
|
|
28
|
+
#include <plusui/clipboard.hpp>
|
|
29
|
+
#include <plusui/custom_bindings.hpp>
|
|
30
|
+
#include <plusui/display.hpp>
|
|
31
|
+
#include <plusui/events.hpp>
|
|
32
|
+
#include <plusui/filedrop.hpp>
|
|
33
|
+
#include <plusui/keyboard.hpp>
|
|
34
|
+
#include <plusui/menu.hpp>
|
|
35
|
+
#include <plusui/native_bindings.hpp>
|
|
36
|
+
#include <plusui/tray.hpp>
|
|
37
|
+
#include <plusui/webgpu.hpp>
|
|
38
|
+
#include <plusui/webview.hpp>
|
|
39
|
+
#include <plusui/window.hpp>
|
|
40
|
+
#include <plusui/window_manager.hpp>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Generate the plusui.hpp umbrella header
|
|
4
|
+
*
|
|
5
|
+
* This script automatically scans all .hpp files in Core/include/plusui/
|
|
6
|
+
* and generates the umbrella header that includes them all.
|
|
7
|
+
*
|
|
8
|
+
* Run this whenever you add a new header file to the framework.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readdir, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { resolve, dirname } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
|
|
18
|
+
const includeDir = resolve(__dirname, '../include/plusui');
|
|
19
|
+
const outputFile = resolve(includeDir, 'plusui.hpp');
|
|
20
|
+
|
|
21
|
+
async function generateUmbrellaHeader() {
|
|
22
|
+
// Read all files in the include directory
|
|
23
|
+
const files = await readdir(includeDir);
|
|
24
|
+
|
|
25
|
+
// Filter to only .hpp files, excluding plusui.hpp itself
|
|
26
|
+
const headerFiles = files
|
|
27
|
+
.filter(file => file.endsWith('.hpp') && file !== 'plusui.hpp')
|
|
28
|
+
.sort();
|
|
29
|
+
|
|
30
|
+
if (headerFiles.length === 0) {
|
|
31
|
+
throw new Error('No header files found to include');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Generate the header content
|
|
35
|
+
const includes = headerFiles
|
|
36
|
+
.map(file => `#include <plusui/${file}>`)
|
|
37
|
+
.join('\n');
|
|
38
|
+
|
|
39
|
+
const content = `#pragma once
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* PlusUI - Umbrella Header (Auto-generated)
|
|
43
|
+
*
|
|
44
|
+
* This file is automatically generated by scripts/generate-umbrella-header.mjs
|
|
45
|
+
* DO NOT EDIT MANUALLY - your changes will be overwritten!
|
|
46
|
+
*
|
|
47
|
+
* To regenerate: node Core/scripts/generate-umbrella-header.mjs
|
|
48
|
+
*
|
|
49
|
+
* This umbrella header includes all PlusUI framework headers.
|
|
50
|
+
* Include this single file to access the entire framework:
|
|
51
|
+
*
|
|
52
|
+
* Usage:
|
|
53
|
+
* #include <plusui> // Standard library style (recommended)
|
|
54
|
+
* // OR
|
|
55
|
+
* #include <plusui/plusui.hpp>
|
|
56
|
+
*
|
|
57
|
+
* using namespace plusui;
|
|
58
|
+
*
|
|
59
|
+
* For faster compile times in production, you can include only
|
|
60
|
+
* the specific headers you need instead of this convenience header.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
${includes}
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
// Write the generated header
|
|
67
|
+
await writeFile(outputFile, content, 'utf8');
|
|
68
|
+
|
|
69
|
+
console.log('✓ Generated plusui.hpp');
|
|
70
|
+
console.log(` Included ${headerFiles.length} headers:`);
|
|
71
|
+
headerFiles.forEach(file => console.log(` - ${file}`));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
generateUmbrellaHeader().catch((error) => {
|
|
75
|
+
console.error(`Failed to generate umbrella header: ${error.message}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plusui-native-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"description": "PlusUI Core framework (frontend + backend implementations)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"README.md"
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
|
-
"prepack": "node scripts/sync-core.mjs"
|
|
11
|
+
"prepack": "node ../../Core/scripts/generate-umbrella-header.mjs && node scripts/sync-core.mjs"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
14
|
"desktop",
|