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.
Files changed (28) hide show
  1. package/Core/CMakeLists.txt +2 -3
  2. package/Core/Features/App/app.cpp +58 -1
  3. package/Core/Features/Connection/ARCHITECTURE.md +369 -0
  4. package/Core/Features/Connection/README.md +165 -0
  5. package/Core/Features/Connection/connection.cpp +57 -0
  6. package/Core/Features/Connection/connection.ts +186 -0
  7. package/Core/Features/Connection/examples/simple_tags_example.hpp +130 -0
  8. package/Core/Features/Connection/examples/simple_tags_example.ts +247 -0
  9. package/Core/Features/Window/window.cpp +187 -151
  10. package/Core/generated/bridge.hpp +302 -0
  11. package/Core/include/plusui/connection.hpp +145 -0
  12. package/Core/include/plusui/plusui.hpp +1 -3
  13. package/Core/include/plusui/window.hpp +17 -19
  14. package/package.json +1 -1
  15. package/Core/Features/Bindings/ARCHITECTURE.md +0 -328
  16. package/Core/Features/Bindings/CustomBindings/custom_bindings.cpp +0 -55
  17. package/Core/Features/Bindings/CustomBindings/custom_bindings.ts +0 -35
  18. package/Core/Features/Bindings/EXAMPLE_USAGE.hpp +0 -143
  19. package/Core/Features/Bindings/EXAMPLE_USAGE.tsx +0 -210
  20. package/Core/Features/Bindings/IPC_GUIDE.md +0 -325
  21. package/Core/Features/Bindings/NativeBindings/native_bindings.cpp +0 -30
  22. package/Core/Features/Bindings/NativeBindings/native_bindings.ts +0 -29
  23. package/Core/Features/Bindings/UNIFIED_SYSTEM.md +0 -351
  24. package/Core/Features/Event/Events.ts +0 -166
  25. package/Core/Features/Event/events.cpp +0 -200
  26. package/Core/include/plusui/bindings.hpp +0 -65
  27. package/Core/include/plusui/custom_bindings.hpp +0 -17
  28. 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") return "image/png";
93
- if (ext == ".jpg" || ext == ".jpeg") return "image/jpeg";
94
- if (ext == ".gif") return "image/gif";
95
- if (ext == ".webp") return "image/webp";
96
- if (ext == ".svg") return "image/svg+xml";
97
- if (ext == ".txt") return "text/plain";
98
- if (ext == ".json") return "application/json";
99
- if (ext == ".pdf") return "application/pdf";
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
- "{\"path\":\"" + jsonEscape(path) + "\",\"name\":\"" +
235
- jsonEscape(name) + "\",\"type\":\"" +
236
- jsonEscape(mimeTypeFromPath(path)) + "\",\"size\":" +
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\\\"], .filedrop-zone, .dropzone');"
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 CustomEvent('plusui:fileDrop.filesDropped',"
281
+ "window.dispatchEvent(new "
282
+ "CustomEvent('plusui:fileDrop.filesDropped',"
274
283
  " { detail: { files: " +
275
284
  filesJson + " } }));";
276
285
 
277
- event::emit("fileDrop.filesDropped", filesJson);
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()) return pImpl->currentTitle;
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
- pImpl.get();
980
+ pImpl.get();
969
981
 
970
982
  ComPtr<ICoreWebView2Controller4> controller4;
971
983
  if (controller &&
972
- SUCCEEDED(controller->QueryInterface(
973
- IID_PPV_ARGS(&controller4))) &&
974
- controller4) {
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 instead
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
- #pragma warning(push)
1088
- #pragma warning(disable: 4244) // Suppress wchar_t to char conversion warning
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
- #pragma warning(pop)
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) pImpl->window->minimize();
1171
+ if (pImpl->window)
1172
+ pImpl->window->minimize();
1145
1173
  success = true;
1146
1174
  } else if (winMethod == "maximize") {
1147
- if (pImpl->window) pImpl->window->maximize();
1175
+ if (pImpl->window)
1176
+ pImpl->window->maximize();
1148
1177
  success = true;
1149
1178
  } else if (winMethod == "restore") {
1150
- if (pImpl->window) pImpl->window->restore();
1179
+ if (pImpl->window)
1180
+ pImpl->window->restore();
1151
1181
  success = true;
1152
1182
  } else if (winMethod == "close") {
1153
- if (pImpl->window) pImpl->window->close();
1183
+ if (pImpl->window)
1184
+ pImpl->window->close();
1154
1185
  success = true;
1155
1186
  } else if (winMethod == "show") {
1156
- if (pImpl->window) pImpl->window->show();
1187
+ if (pImpl->window)
1188
+ pImpl->window->show();
1157
1189
  success = true;
1158
1190
  } else if (winMethod == "hide") {
1159
- if (pImpl->window) pImpl->window->hide();
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 = "{\"width\":" +
1166
- std::to_string(w) +
1167
- ",\"height\":" +
1168
- std::to_string(h) +
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
- "{\"x\":" + std::to_string(x) +
1178
- ",\"y\":" + std::to_string(y) +
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) pImpl->window->setSize(w, h);
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) pImpl->window->setPosition(x, y);
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) pImpl->window->setTitle(title);
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) pImpl->window->setFullscreen(
1227
- params.find("true") !=
1228
- std::string::npos);
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) pImpl->window->setAlwaysOnTop(
1239
- params.find("true") !=
1240
- std::string::npos);
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) pImpl->window->setResizable(
1251
- params.find("true") !=
1252
- std::string::npos);
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
- (pImpl->window && pImpl->window->isMaximized())
1258
- ? "true"
1259
- : "false";
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
- (pImpl->window && pImpl->window->isMinimized())
1264
- ? "true"
1265
- : "false";
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 && pImpl->window->isVisible())
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) pImpl->window->center();
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 = method.substr(9);
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
- params.find("true") !=
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
- !(pImpl->config.enableFileDrop ||
1360
- pImpl->config
1361
- .disableWebviewDragDrop);
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 = @"(function() {"
1452
- "if (window.__plusui_nativeFileDropOnly) return;"
1453
- "window.__plusui_nativeFileDropOnly = true;"
1454
- "var isOverDropZone = function(e) {"
1455
- "if (!e) return false;"
1456
- "var target = null;"
1457
- "if (typeof e.clientX === 'number' && typeof e.clientY === 'number' && document.elementFromPoint) { target = document.elementFromPoint(e.clientX, e.clientY); }"
1458
- "if (!target && e.target && e.target.nodeType === 1) { target = e.target; }"
1459
- "if (!target || !target.closest) return false;"
1460
- "return !!target.closest('[data-dropzone=\\\"true\\\"], .filedrop-zone, .dropzone');"
1461
- "};"
1462
- "var zoneActive = false;"
1463
- "var emitZoneState = function(next) {"
1464
- "if (next === zoneActive) return;"
1465
- "zoneActive = next;"
1466
- "window.dispatchEvent(new CustomEvent(next ? 'plusui:fileDrop.dragEnter' : 'plusui:fileDrop.dragLeave', { detail: {} }));"
1467
- "};"
1468
- "var block = function(e) {"
1469
- "if (!e) return false;"
1470
- "var overDropZone = isOverDropZone(e);"
1471
- "if (e.type === 'drop') { emitZoneState(false); } else { emitZoneState(overDropZone); }"
1472
- "e.preventDefault();"
1473
- "e.stopPropagation();"
1474
- "if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();"
1475
- "if (e.dataTransfer) { try { e.dataTransfer.dropEffect = overDropZone ? 'copy' : 'none'; } catch (_) {} }"
1476
- "return false;"
1477
- "};"
1478
- "window.__plusui_dragDropEvents = ['dragenter','dragover','dragleave','drop'];"
1479
- "window.__plusui_dragDropBlocker = block;"
1480
- "window.__plusui_dragDropEvents.forEach(function(eventName) {"
1481
- "window.addEventListener(eventName, block, true);"
1482
- "document.addEventListener(eventName, block, true);"
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
- initWithSource:disableDragDropScript
1488
- injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
1489
- forMainFrameOnly:NO];
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 = [NSString stringWithUTF8String:kHideScrollbarsScript];
1545
+ NSString *scrollbarScript =
1546
+ [NSString stringWithUTF8String:kHideScrollbarsScript];
1496
1547
 
1497
1548
  WKUserScript *scrollScript = [[WKUserScript alloc]
1498
- initWithSource:scrollbarScript
1499
- injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
1500
- forMainFrameOnly:NO];
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::loadURL(const std::string &url) {
1599
- navigate(url);
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
- std::function<void(const std::string &)> callback) {
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) {