plusui-native-core 0.1.52 → 0.1.53
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/CMakeLists.txt +2 -3
- package/Core/Features/App/app.cpp +58 -1
- package/Core/Features/Connection/ARCHITECTURE.md +369 -0
- package/Core/Features/Connection/README.md +165 -0
- package/Core/Features/Connection/connection.cpp +57 -0
- package/Core/Features/Connection/connection.ts +186 -0
- package/Core/Features/Connection/examples/simple_tags_example.hpp +130 -0
- package/Core/Features/Connection/examples/simple_tags_example.ts +247 -0
- package/Core/Features/Window/window.cpp +187 -151
- package/Core/generated/bridge.hpp +302 -0
- package/Core/include/plusui/connection.hpp +145 -0
- package/Core/include/plusui/plusui.hpp +1 -3
- package/Core/include/plusui/window.hpp +17 -19
- package/package.json +1 -1
- package/Core/Features/Bindings/ARCHITECTURE.md +0 -328
- package/Core/Features/Bindings/CustomBindings/custom_bindings.cpp +0 -55
- package/Core/Features/Bindings/CustomBindings/custom_bindings.ts +0 -35
- package/Core/Features/Bindings/EXAMPLE_USAGE.hpp +0 -143
- package/Core/Features/Bindings/EXAMPLE_USAGE.tsx +0 -210
- package/Core/Features/Bindings/IPC_GUIDE.md +0 -325
- package/Core/Features/Bindings/NativeBindings/native_bindings.cpp +0 -30
- package/Core/Features/Bindings/NativeBindings/native_bindings.ts +0 -29
- package/Core/Features/Bindings/UNIFIED_SYSTEM.md +0 -351
- package/Core/Features/Event/Events.ts +0 -166
- package/Core/Features/Event/events.cpp +0 -200
- package/Core/include/plusui/bindings.hpp +0 -65
- package/Core/include/plusui/custom_bindings.hpp +0 -17
- package/Core/include/plusui/events.hpp +0 -58
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
#include <iostream>
|
|
4
4
|
#include <map>
|
|
5
5
|
#include <plusui/display.hpp>
|
|
6
|
-
#include <plusui/events.hpp>
|
|
7
6
|
#include <plusui/tray.hpp>
|
|
8
7
|
#include <plusui/webgpu.hpp>
|
|
9
8
|
#include <plusui/window.hpp>
|
|
@@ -12,7 +11,7 @@
|
|
|
12
11
|
|
|
13
12
|
#ifdef _WIN32
|
|
14
13
|
#pragma warning(push)
|
|
15
|
-
#pragma warning(disable: 4996)
|
|
14
|
+
#pragma warning(disable : 4996)
|
|
16
15
|
#include <WebView2.h>
|
|
17
16
|
#include <windows.h>
|
|
18
17
|
#include <wrl.h>
|
|
@@ -20,8 +19,9 @@ using namespace Microsoft::WRL;
|
|
|
20
19
|
#pragma warning(pop)
|
|
21
20
|
#elif defined(__APPLE__)
|
|
22
21
|
#include <Cocoa/Cocoa.h>
|
|
23
|
-
#include <objc/objc-runtime.h>
|
|
24
22
|
#import <WebKit/WebKit.h>
|
|
23
|
+
#include <objc/objc-runtime.h>
|
|
24
|
+
|
|
25
25
|
#else
|
|
26
26
|
#include <gtk/gtk.h>
|
|
27
27
|
#include <webkit2/webkit2.h>
|
|
@@ -89,14 +89,22 @@ static std::string mimeTypeFromPath(const std::string &path) {
|
|
|
89
89
|
std::string ext = path.substr(dot);
|
|
90
90
|
for (char &ch : ext)
|
|
91
91
|
ch = static_cast<char>(tolower(static_cast<unsigned char>(ch)));
|
|
92
|
-
if (ext == ".png")
|
|
93
|
-
|
|
94
|
-
if (ext == ".
|
|
95
|
-
|
|
96
|
-
if (ext == ".
|
|
97
|
-
|
|
98
|
-
if (ext == ".
|
|
99
|
-
|
|
92
|
+
if (ext == ".png")
|
|
93
|
+
return "image/png";
|
|
94
|
+
if (ext == ".jpg" || ext == ".jpeg")
|
|
95
|
+
return "image/jpeg";
|
|
96
|
+
if (ext == ".gif")
|
|
97
|
+
return "image/gif";
|
|
98
|
+
if (ext == ".webp")
|
|
99
|
+
return "image/webp";
|
|
100
|
+
if (ext == ".svg")
|
|
101
|
+
return "image/svg+xml";
|
|
102
|
+
if (ext == ".txt")
|
|
103
|
+
return "text/plain";
|
|
104
|
+
if (ext == ".json")
|
|
105
|
+
return "application/json";
|
|
106
|
+
if (ext == ".pdf")
|
|
107
|
+
return "application/pdf";
|
|
100
108
|
return "application/octet-stream";
|
|
101
109
|
}
|
|
102
110
|
#endif
|
|
@@ -120,9 +128,7 @@ struct Window::Impl {
|
|
|
120
128
|
std::string pendingNavigation;
|
|
121
129
|
std::string pendingHTML;
|
|
122
130
|
std::string pendingFile;
|
|
123
|
-
std::map<std::string, JSCallback> bindings;
|
|
124
131
|
std::unique_ptr<TrayManager> trayManager;
|
|
125
|
-
std::map<std::string, std::function<void(const std::string &)>> events;
|
|
126
132
|
WebGPU webgpu;
|
|
127
133
|
NavigationCallback navigationCallback;
|
|
128
134
|
LoadCallback loadStartCallback;
|
|
@@ -130,6 +136,8 @@ struct Window::Impl {
|
|
|
130
136
|
LoadCallback navigationCompleteCallback;
|
|
131
137
|
ErrorCallback errorCallback;
|
|
132
138
|
ConsoleCallback consoleCallback;
|
|
139
|
+
MessageCallback messageCallback;
|
|
140
|
+
FileDropCallback fileDropCallback;
|
|
133
141
|
|
|
134
142
|
std::vector<MoveCallback> moveCallbacks;
|
|
135
143
|
std::vector<ResizeCallback> resizeCallbacks;
|
|
@@ -230,11 +238,10 @@ struct Window::Impl {
|
|
|
230
238
|
|
|
231
239
|
if (i > 0)
|
|
232
240
|
filesJson += ",";
|
|
233
|
-
filesJson +=
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
std::to_string(sizeBytes) + "}";
|
|
241
|
+
filesJson += "{\"path\":\"" + jsonEscape(path) + "\",\"name\":\"" +
|
|
242
|
+
jsonEscape(name) + "\",\"type\":\"" +
|
|
243
|
+
jsonEscape(mimeTypeFromPath(path)) +
|
|
244
|
+
"\",\"size\":" + std::to_string(sizeBytes) + "}";
|
|
238
245
|
}
|
|
239
246
|
filesJson += "]";
|
|
240
247
|
|
|
@@ -250,7 +257,8 @@ struct Window::Impl {
|
|
|
250
257
|
");"
|
|
251
258
|
"if(!el) return false;"
|
|
252
259
|
"if(!el.closest) return false;"
|
|
253
|
-
"return !!el.closest('[data-dropzone=\\\"true\\\"],
|
|
260
|
+
"return !!el.closest('[data-dropzone=\\\"true\\\"], "
|
|
261
|
+
".filedrop-zone, .dropzone');"
|
|
254
262
|
"}catch(_){return false;}})();";
|
|
255
263
|
|
|
256
264
|
targetImpl->webview->ExecuteScript(
|
|
@@ -270,11 +278,14 @@ struct Window::Impl {
|
|
|
270
278
|
return S_OK;
|
|
271
279
|
|
|
272
280
|
std::string eventScript =
|
|
273
|
-
"window.dispatchEvent(new
|
|
281
|
+
"window.dispatchEvent(new "
|
|
282
|
+
"CustomEvent('plusui:fileDrop.filesDropped',"
|
|
274
283
|
" { detail: { files: " +
|
|
275
284
|
filesJson + " } }));";
|
|
276
285
|
|
|
277
|
-
|
|
286
|
+
if (targetImpl->fileDropCallback) {
|
|
287
|
+
targetImpl->fileDropCallback(filesJson);
|
|
288
|
+
}
|
|
278
289
|
|
|
279
290
|
targetImpl->webview->ExecuteScript(
|
|
280
291
|
std::wstring(eventScript.begin(), eventScript.end())
|
|
@@ -466,7 +477,8 @@ void Window::setTitle(const std::string &title) {
|
|
|
466
477
|
}
|
|
467
478
|
|
|
468
479
|
std::string Window::getTitle() const {
|
|
469
|
-
if (!pImpl->currentTitle.empty())
|
|
480
|
+
if (!pImpl->currentTitle.empty())
|
|
481
|
+
return pImpl->currentTitle;
|
|
470
482
|
return pImpl->config.title;
|
|
471
483
|
}
|
|
472
484
|
|
|
@@ -965,13 +977,13 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
965
977
|
GetClientRect(parentHwnd, &bounds);
|
|
966
978
|
controller->put_Bounds(bounds);
|
|
967
979
|
Window::Impl::embeddedWebviewByParent[parentHwnd] =
|
|
968
|
-
|
|
980
|
+
pImpl.get();
|
|
969
981
|
|
|
970
982
|
ComPtr<ICoreWebView2Controller4> controller4;
|
|
971
983
|
if (controller &&
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
984
|
+
SUCCEEDED(controller->QueryInterface(
|
|
985
|
+
IID_PPV_ARGS(&controller4))) &&
|
|
986
|
+
controller4) {
|
|
975
987
|
bool allowExternalDrop =
|
|
976
988
|
!(pImpl->config.enableFileDrop ||
|
|
977
989
|
pImpl->config.disableWebviewDragDrop);
|
|
@@ -1009,7 +1021,8 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1009
1021
|
|
|
1010
1022
|
// Disable webview drag & drop behavior if requested
|
|
1011
1023
|
// This prevents files from being loaded in the browser
|
|
1012
|
-
// and allows the native FileDrop API to handle them
|
|
1024
|
+
// and allows the native FileDrop API to handle them
|
|
1025
|
+
// instead
|
|
1013
1026
|
if (pImpl->config.disableWebviewDragDrop) {
|
|
1014
1027
|
std::string disableDragDropScript = R"(
|
|
1015
1028
|
(function() {
|
|
@@ -1084,16 +1097,30 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1084
1097
|
if (!message)
|
|
1085
1098
|
return S_OK;
|
|
1086
1099
|
std::wstring wmsg(message);
|
|
1087
|
-
|
|
1088
|
-
|
|
1100
|
+
#pragma warning(push)
|
|
1101
|
+
#pragma warning(disable : 4244) // Suppress wchar_t to char conversion warning
|
|
1089
1102
|
std::string msg(wmsg.begin(), wmsg.end());
|
|
1090
|
-
|
|
1103
|
+
#pragma warning(pop)
|
|
1091
1104
|
CoTaskMemFree(message);
|
|
1092
1105
|
|
|
1093
1106
|
// Debug: log received message
|
|
1094
1107
|
std::cout << "[PlusUI] Received: " << msg
|
|
1095
1108
|
<< std::endl;
|
|
1096
1109
|
|
|
1110
|
+
// New Generic Message Handler
|
|
1111
|
+
if (pImpl->messageCallback) {
|
|
1112
|
+
pImpl->messageCallback(msg);
|
|
1113
|
+
// If handled by generic handler, do we
|
|
1114
|
+
// stop? For now, let's allow legacy to run
|
|
1115
|
+
// too for backward compat UNLESS the
|
|
1116
|
+
// message is clearly for the new system.
|
|
1117
|
+
// The new system uses "kind" field.
|
|
1118
|
+
if (msg.find("\"kind\"") !=
|
|
1119
|
+
std::string::npos) {
|
|
1120
|
+
return S_OK;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1097
1124
|
// Parse JSON-RPC: {"id":"...",
|
|
1098
1125
|
// "method":"window.minimize", "params":[...]}
|
|
1099
1126
|
std::string id, method;
|
|
@@ -1141,42 +1168,46 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1141
1168
|
if (method.find("window.") == 0) {
|
|
1142
1169
|
std::string winMethod = method.substr(7);
|
|
1143
1170
|
if (winMethod == "minimize") {
|
|
1144
|
-
if (pImpl->window)
|
|
1171
|
+
if (pImpl->window)
|
|
1172
|
+
pImpl->window->minimize();
|
|
1145
1173
|
success = true;
|
|
1146
1174
|
} else if (winMethod == "maximize") {
|
|
1147
|
-
if (pImpl->window)
|
|
1175
|
+
if (pImpl->window)
|
|
1176
|
+
pImpl->window->maximize();
|
|
1148
1177
|
success = true;
|
|
1149
1178
|
} else if (winMethod == "restore") {
|
|
1150
|
-
if (pImpl->window)
|
|
1179
|
+
if (pImpl->window)
|
|
1180
|
+
pImpl->window->restore();
|
|
1151
1181
|
success = true;
|
|
1152
1182
|
} else if (winMethod == "close") {
|
|
1153
|
-
if (pImpl->window)
|
|
1183
|
+
if (pImpl->window)
|
|
1184
|
+
pImpl->window->close();
|
|
1154
1185
|
success = true;
|
|
1155
1186
|
} else if (winMethod == "show") {
|
|
1156
|
-
if (pImpl->window)
|
|
1187
|
+
if (pImpl->window)
|
|
1188
|
+
pImpl->window->show();
|
|
1157
1189
|
success = true;
|
|
1158
1190
|
} else if (winMethod == "hide") {
|
|
1159
|
-
if (pImpl->window)
|
|
1191
|
+
if (pImpl->window)
|
|
1192
|
+
pImpl->window->hide();
|
|
1160
1193
|
success = true;
|
|
1161
1194
|
} else if (winMethod == "getSize") {
|
|
1162
1195
|
if (pImpl->window) {
|
|
1163
1196
|
int w, h;
|
|
1164
1197
|
pImpl->window->getSize(w, h);
|
|
1165
|
-
result =
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
"}";
|
|
1198
|
+
result =
|
|
1199
|
+
"{\"width\":" + std::to_string(w) +
|
|
1200
|
+
",\"height\":" + std::to_string(h) +
|
|
1201
|
+
"}";
|
|
1170
1202
|
}
|
|
1171
1203
|
success = true;
|
|
1172
1204
|
} else if (winMethod == "getPosition") {
|
|
1173
1205
|
if (pImpl->window) {
|
|
1174
1206
|
int x, y;
|
|
1175
1207
|
pImpl->window->getPosition(x, y);
|
|
1176
|
-
result =
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
"}";
|
|
1208
|
+
result = "{\"x\":" + std::to_string(x) +
|
|
1209
|
+
",\"y\":" + std::to_string(y) +
|
|
1210
|
+
"}";
|
|
1180
1211
|
}
|
|
1181
1212
|
success = true;
|
|
1182
1213
|
} else if (winMethod == "setSize") {
|
|
@@ -1190,7 +1221,8 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1190
1221
|
int w = 0, h = 0;
|
|
1191
1222
|
sscanf(params.c_str(), "%d, %d", &w,
|
|
1192
1223
|
&h);
|
|
1193
|
-
if (pImpl->window)
|
|
1224
|
+
if (pImpl->window)
|
|
1225
|
+
pImpl->window->setSize(w, h);
|
|
1194
1226
|
}
|
|
1195
1227
|
success = true;
|
|
1196
1228
|
} else if (winMethod == "setPosition") {
|
|
@@ -1203,7 +1235,8 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1203
1235
|
int x = 0, y = 0;
|
|
1204
1236
|
sscanf(params.c_str(), "%d, %d", &x,
|
|
1205
1237
|
&y);
|
|
1206
|
-
if (pImpl->window)
|
|
1238
|
+
if (pImpl->window)
|
|
1239
|
+
pImpl->window->setPosition(x, y);
|
|
1207
1240
|
}
|
|
1208
1241
|
success = true;
|
|
1209
1242
|
} else if (winMethod == "setTitle") {
|
|
@@ -1213,7 +1246,8 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1213
1246
|
p2 != std::string::npos) {
|
|
1214
1247
|
std::string title =
|
|
1215
1248
|
msg.substr(p1 + 2, p2 - p1 - 2);
|
|
1216
|
-
if (pImpl->window)
|
|
1249
|
+
if (pImpl->window)
|
|
1250
|
+
pImpl->window->setTitle(title);
|
|
1217
1251
|
}
|
|
1218
1252
|
success = true;
|
|
1219
1253
|
} else if (winMethod == "setFullscreen") {
|
|
@@ -1223,9 +1257,10 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1223
1257
|
p2 != std::string::npos) {
|
|
1224
1258
|
std::string params =
|
|
1225
1259
|
msg.substr(p1 + 1, p2 - p1 - 1);
|
|
1226
|
-
if (pImpl->window)
|
|
1227
|
-
|
|
1228
|
-
|
|
1260
|
+
if (pImpl->window)
|
|
1261
|
+
pImpl->window->setFullscreen(
|
|
1262
|
+
params.find("true") !=
|
|
1263
|
+
std::string::npos);
|
|
1229
1264
|
}
|
|
1230
1265
|
success = true;
|
|
1231
1266
|
} else if (winMethod == "setAlwaysOnTop") {
|
|
@@ -1235,9 +1270,10 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1235
1270
|
p2 != std::string::npos) {
|
|
1236
1271
|
std::string params =
|
|
1237
1272
|
msg.substr(p1 + 1, p2 - p1 - 1);
|
|
1238
|
-
if (pImpl->window)
|
|
1239
|
-
|
|
1240
|
-
|
|
1273
|
+
if (pImpl->window)
|
|
1274
|
+
pImpl->window->setAlwaysOnTop(
|
|
1275
|
+
params.find("true") !=
|
|
1276
|
+
std::string::npos);
|
|
1241
1277
|
}
|
|
1242
1278
|
success = true;
|
|
1243
1279
|
} else if (winMethod == "setResizable") {
|
|
@@ -1247,30 +1283,33 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1247
1283
|
p2 != std::string::npos) {
|
|
1248
1284
|
std::string params =
|
|
1249
1285
|
msg.substr(p1 + 1, p2 - p1 - 1);
|
|
1250
|
-
if (pImpl->window)
|
|
1251
|
-
|
|
1252
|
-
|
|
1286
|
+
if (pImpl->window)
|
|
1287
|
+
pImpl->window->setResizable(
|
|
1288
|
+
params.find("true") !=
|
|
1289
|
+
std::string::npos);
|
|
1253
1290
|
}
|
|
1254
1291
|
success = true;
|
|
1255
1292
|
} else if (winMethod == "isMaximized") {
|
|
1256
|
-
result =
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1293
|
+
result = (pImpl->window &&
|
|
1294
|
+
pImpl->window->isMaximized())
|
|
1295
|
+
? "true"
|
|
1296
|
+
: "false";
|
|
1260
1297
|
success = true;
|
|
1261
1298
|
} else if (winMethod == "isMinimized") {
|
|
1262
|
-
result =
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1299
|
+
result = (pImpl->window &&
|
|
1300
|
+
pImpl->window->isMinimized())
|
|
1301
|
+
? "true"
|
|
1302
|
+
: "false";
|
|
1266
1303
|
success = true;
|
|
1267
1304
|
} else if (winMethod == "isVisible") {
|
|
1268
|
-
result = (pImpl->window &&
|
|
1305
|
+
result = (pImpl->window &&
|
|
1306
|
+
pImpl->window->isVisible())
|
|
1269
1307
|
? "true"
|
|
1270
1308
|
: "false";
|
|
1271
1309
|
success = true;
|
|
1272
1310
|
} else if (winMethod == "center") {
|
|
1273
|
-
if (pImpl->window)
|
|
1311
|
+
if (pImpl->window)
|
|
1312
|
+
pImpl->window->center();
|
|
1274
1313
|
success = true;
|
|
1275
1314
|
}
|
|
1276
1315
|
} else if (method.find("browser.") == 0) {
|
|
@@ -1321,7 +1360,8 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1321
1360
|
success = true;
|
|
1322
1361
|
}
|
|
1323
1362
|
} else if (method.find("fileDrop.") == 0) {
|
|
1324
|
-
std::string fileDropMethod =
|
|
1363
|
+
std::string fileDropMethod =
|
|
1364
|
+
method.substr(9);
|
|
1325
1365
|
if (fileDropMethod == "setEnabled") {
|
|
1326
1366
|
size_t p1 = msg.find("[");
|
|
1327
1367
|
size_t p2 = msg.find("]");
|
|
@@ -1329,9 +1369,8 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1329
1369
|
p2 != std::string::npos) {
|
|
1330
1370
|
std::string params =
|
|
1331
1371
|
msg.substr(p1 + 1, p2 - p1 - 1);
|
|
1332
|
-
bool enabled =
|
|
1333
|
-
|
|
1334
|
-
std::string::npos;
|
|
1372
|
+
bool enabled = params.find("true") !=
|
|
1373
|
+
std::string::npos;
|
|
1335
1374
|
pImpl->config.enableFileDrop = enabled;
|
|
1336
1375
|
|
|
1337
1376
|
HWND targetHwnd = nullptr;
|
|
@@ -1355,10 +1394,10 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1355
1394
|
if (SUCCEEDED(pImpl->controller.As(
|
|
1356
1395
|
&controller4)) &&
|
|
1357
1396
|
controller4) {
|
|
1358
|
-
bool allowExternalDrop =
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1397
|
+
bool allowExternalDrop = !(
|
|
1398
|
+
pImpl->config.enableFileDrop ||
|
|
1399
|
+
pImpl->config
|
|
1400
|
+
.disableWebviewDragDrop);
|
|
1362
1401
|
controller4->put_AllowExternalDrop(
|
|
1363
1402
|
allowExternalDrop ? TRUE
|
|
1364
1403
|
: FALSE);
|
|
@@ -1448,56 +1487,68 @@ Window Window::create(void *windowHandle, const WindowConfig &config) {
|
|
|
1448
1487
|
|
|
1449
1488
|
// Disable webview drag & drop behavior to allow native FileDrop API
|
|
1450
1489
|
if (win.pImpl->config.disableWebviewDragDrop) {
|
|
1451
|
-
NSString *disableDragDropScript =
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1490
|
+
NSString *disableDragDropScript =
|
|
1491
|
+
@"(function() {"
|
|
1492
|
+
"if (window.__plusui_nativeFileDropOnly) return;"
|
|
1493
|
+
"window.__plusui_nativeFileDropOnly = true;"
|
|
1494
|
+
"var isOverDropZone = function(e) {"
|
|
1495
|
+
"if (!e) return false;"
|
|
1496
|
+
"var target = null;"
|
|
1497
|
+
"if (typeof e.clientX === 'number' && typeof e.clientY === 'number' "
|
|
1498
|
+
"&& document.elementFromPoint) { target = "
|
|
1499
|
+
"document.elementFromPoint(e.clientX, e.clientY); }"
|
|
1500
|
+
"if (!target && e.target && e.target.nodeType === 1) { target = "
|
|
1501
|
+
"e.target; }"
|
|
1502
|
+
"if (!target || !target.closest) return false;"
|
|
1503
|
+
"return !!target.closest('[data-dropzone=\\\"true\\\"], "
|
|
1504
|
+
".filedrop-zone, .dropzone');"
|
|
1505
|
+
"};"
|
|
1506
|
+
"var zoneActive = false;"
|
|
1507
|
+
"var emitZoneState = function(next) {"
|
|
1508
|
+
"if (next === zoneActive) return;"
|
|
1509
|
+
"zoneActive = next;"
|
|
1510
|
+
"window.dispatchEvent(new CustomEvent(next ? "
|
|
1511
|
+
"'plusui:fileDrop.dragEnter' : 'plusui:fileDrop.dragLeave', { detail: "
|
|
1512
|
+
"{} }));"
|
|
1513
|
+
"};"
|
|
1514
|
+
"var block = function(e) {"
|
|
1515
|
+
"if (!e) return false;"
|
|
1516
|
+
"var overDropZone = isOverDropZone(e);"
|
|
1517
|
+
"if (e.type === 'drop') { emitZoneState(false); } else { "
|
|
1518
|
+
"emitZoneState(overDropZone); }"
|
|
1519
|
+
"e.preventDefault();"
|
|
1520
|
+
"e.stopPropagation();"
|
|
1521
|
+
"if (typeof e.stopImmediatePropagation === 'function') "
|
|
1522
|
+
"e.stopImmediatePropagation();"
|
|
1523
|
+
"if (e.dataTransfer) { try { e.dataTransfer.dropEffect = overDropZone "
|
|
1524
|
+
"? 'copy' : 'none'; } catch (_) {} }"
|
|
1525
|
+
"return false;"
|
|
1526
|
+
"};"
|
|
1527
|
+
"window.__plusui_dragDropEvents = "
|
|
1528
|
+
"['dragenter','dragover','dragleave','drop'];"
|
|
1529
|
+
"window.__plusui_dragDropBlocker = block;"
|
|
1530
|
+
"window.__plusui_dragDropEvents.forEach(function(eventName) {"
|
|
1531
|
+
"window.addEventListener(eventName, block, true);"
|
|
1532
|
+
"document.addEventListener(eventName, block, true);"
|
|
1533
|
+
"});"
|
|
1534
|
+
"})();";
|
|
1485
1535
|
|
|
1486
1536
|
WKUserScript *userScript = [[WKUserScript alloc]
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1537
|
+
initWithSource:disableDragDropScript
|
|
1538
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
|
|
1539
|
+
forMainFrameOnly:NO];
|
|
1490
1540
|
[config.userContentController addUserScript:userScript];
|
|
1491
1541
|
}
|
|
1492
1542
|
|
|
1493
1543
|
// Hide scrollbars if disabled
|
|
1494
1544
|
if (!win.pImpl->config.scrollbars) {
|
|
1495
|
-
NSString *scrollbarScript =
|
|
1545
|
+
NSString *scrollbarScript =
|
|
1546
|
+
[NSString stringWithUTF8String:kHideScrollbarsScript];
|
|
1496
1547
|
|
|
1497
1548
|
WKUserScript *scrollScript = [[WKUserScript alloc]
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1549
|
+
initWithSource:scrollbarScript
|
|
1550
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
|
|
1551
|
+
forMainFrameOnly:NO];
|
|
1501
1552
|
[config.userContentController addUserScript:scrollScript];
|
|
1502
1553
|
}
|
|
1503
1554
|
|
|
@@ -1560,17 +1611,6 @@ void Window::setWindow(std::shared_ptr<Window> win) {
|
|
|
1560
1611
|
#endif
|
|
1561
1612
|
}
|
|
1562
1613
|
|
|
1563
|
-
void Window::on(const std::string &event,
|
|
1564
|
-
std::function<void(const std::string &)> callback) {
|
|
1565
|
-
pImpl->events[event] = callback;
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
void Window::emit(const std::string &event, const std::string &data) {
|
|
1569
|
-
std::string js = "window.dispatchEvent(new CustomEvent('" + event +
|
|
1570
|
-
"', {detail: " + data + "}))";
|
|
1571
|
-
executeScript(js);
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
1614
|
void Window::navigate(const std::string &url) {
|
|
1575
1615
|
pImpl->currentURL = url;
|
|
1576
1616
|
pImpl->loading = true;
|
|
@@ -1595,10 +1635,27 @@ void Window::navigate(const std::string &url) {
|
|
|
1595
1635
|
#endif
|
|
1596
1636
|
}
|
|
1597
1637
|
|
|
1598
|
-
void Window::
|
|
1599
|
-
|
|
1638
|
+
void Window::onMessage(MessageCallback callback) {
|
|
1639
|
+
pImpl->messageCallback = callback;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
void Window::postMessage(const std::string &message) {
|
|
1643
|
+
#ifdef _WIN32
|
|
1644
|
+
if (pImpl->webview) {
|
|
1645
|
+
std::wstring wmsg(message.begin(), message.end());
|
|
1646
|
+
pImpl->webview->PostWebMessageAsJson(wmsg.c_str());
|
|
1647
|
+
}
|
|
1648
|
+
#elif defined(__APPLE__)
|
|
1649
|
+
// TODO: formatting for Apple
|
|
1650
|
+
#endif
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
void Window::onFileDrop(FileDropCallback callback) {
|
|
1654
|
+
pImpl->fileDropCallback = callback;
|
|
1600
1655
|
}
|
|
1601
1656
|
|
|
1657
|
+
void Window::loadURL(const std::string &url) { navigate(url); }
|
|
1658
|
+
|
|
1602
1659
|
void Window::loadHTML(const std::string &html) {
|
|
1603
1660
|
loadHTML(html, "about:blank");
|
|
1604
1661
|
}
|
|
@@ -1768,7 +1825,7 @@ void Window::executeScript(const std::string &script) {
|
|
|
1768
1825
|
}
|
|
1769
1826
|
|
|
1770
1827
|
void Window::executeScript(const std::string &script,
|
|
1771
|
-
|
|
1828
|
+
std::function<void(const std::string &)> callback) {
|
|
1772
1829
|
#ifdef _WIN32
|
|
1773
1830
|
if (pImpl->webview) {
|
|
1774
1831
|
pImpl->webview->ExecuteScript(
|
|
@@ -1805,27 +1862,6 @@ void Window::executeScript(const std::string &script,
|
|
|
1805
1862
|
#endif
|
|
1806
1863
|
}
|
|
1807
1864
|
|
|
1808
|
-
void Window::bind(const std::string &name, JSCallback callback) {
|
|
1809
|
-
pImpl->bindings[name] = callback;
|
|
1810
|
-
|
|
1811
|
-
// Inject bridge code to expose function to JavaScript
|
|
1812
|
-
std::string bridgeScript = R"(
|
|
1813
|
-
window.)" + name + R"( = function(...args) {
|
|
1814
|
-
return window.plusui.invoke('webview.)" +
|
|
1815
|
-
name + R"(', args);
|
|
1816
|
-
};
|
|
1817
|
-
)";
|
|
1818
|
-
|
|
1819
|
-
executeScript(bridgeScript);
|
|
1820
|
-
}
|
|
1821
|
-
|
|
1822
|
-
void Window::unbind(const std::string &name) {
|
|
1823
|
-
pImpl->bindings.erase(name);
|
|
1824
|
-
|
|
1825
|
-
std::string script = "delete window." + name + ";";
|
|
1826
|
-
executeScript(script);
|
|
1827
|
-
}
|
|
1828
|
-
|
|
1829
1865
|
void Window::openDevTools() {
|
|
1830
1866
|
#ifdef _WIN32
|
|
1831
1867
|
if (pImpl->webview) {
|