MonacoEditPage.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #include "pch.h"
  2. #include "MonacoEditPage.h"
  3. #if __has_include("MonacoEditPage.g.cpp")
  4. #include "MonacoEditPage.g.cpp"
  5. #endif
  6. #include <winrt/Microsoft.Web.WebView2.Core.h>
  7. #include <nlohmann/json.hpp>
  8. using namespace winrt;
  9. using namespace Windows::Storage;
  10. using namespace Windows::UI::Xaml;
  11. namespace winrt::Maple_App::implementation
  12. {
  13. MonacoEditPage::MonacoEditPage()
  14. {
  15. InitializeComponent();
  16. }
  17. fire_and_forget MonacoEditPage::Page_Loaded(IInspectable const& sender, RoutedEventArgs const& e)
  18. {
  19. auto const lifetime{ get_strong() };
  20. co_await initializeWebView();
  21. }
  22. void MonacoEditPage::Page_Unloaded(IInspectable const& sender, RoutedEventArgs const& e)
  23. {
  24. //
  25. }
  26. IAsyncAction MonacoEditPage::initializeWebView() {
  27. auto const lifetime{ get_strong() };
  28. auto const webview = WebView();
  29. co_await webview.EnsureCoreWebView2Async();
  30. if (std::exchange(m_webviewInitialized, true))
  31. {
  32. co_return;
  33. }
  34. auto const packagePath = Windows::ApplicationModel::Package::Current().InstalledPath();
  35. auto const configPath = Windows::Storage::ApplicationData::Current().LocalFolder().Path() + L"\\config";
  36. webview.CoreWebView2().SetVirtualHostNameToFolderMapping(
  37. L"maple-monaco-editor-app-root.com",
  38. packagePath,
  39. Microsoft::Web::WebView2::Core::CoreWebView2HostResourceAccessKind::DenyCors
  40. );
  41. webview.CoreWebView2().SetVirtualHostNameToFolderMapping(
  42. L"maple-monaco-editor-config-root.com",
  43. configPath,
  44. Microsoft::Web::WebView2::Core::CoreWebView2HostResourceAccessKind::Allow
  45. );
  46. webview.Source(Uri{ L"http://maple-monaco-editor-app-root.com/MonacoEditor/editor.html" });
  47. }
  48. fire_and_forget MonacoEditPage::OnNavigatedTo(NavigationEventArgs const& e) {
  49. auto const lifetime{ get_strong() };
  50. auto const param = e.Parameter().as<Maple_App::ConfigViewModel>();
  51. co_await initializeWebView();
  52. SaveModifiedContent = [weak = weak_ref{ lifetime }]()->IAsyncAction
  53. {
  54. if (auto const lifetime{ weak.get() })
  55. {
  56. lifetime->WebView().ExecuteScriptAsync(hstring{ L"window.mapleHostApi.triggerSave()" });
  57. }
  58. co_return;
  59. };
  60. if (m_webviewDOMLoaded)
  61. {
  62. co_await lifetime->WebView().ExecuteScriptAsync(hstring{ L"window.mapleHostApi.loadFile(`http://maple-monaco-editor-config-root.com/" } +
  63. param.File().Name() +
  64. L"`)");
  65. }
  66. else {
  67. if (!m_webviewDOMLoadedToken) {
  68. m_webviewDOMLoadedToken = WebView().CoreWebView2().DOMContentLoaded([=](auto, auto)
  69. {
  70. lifetime->m_webviewDOMLoaded = true;
  71. lifetime->WebView().CoreWebView2().DOMContentLoaded(lifetime->m_webviewDOMLoadedToken);
  72. lifetime->WebView().ExecuteScriptAsync(hstring{ L"window.mapleHostApi.loadFile(`" } +
  73. CONFIG_ROOT_VIRTUAL_HOSTW +
  74. lifetime->m_initialFileName +
  75. L"`)");
  76. lifetime->WebView().WebMessageReceived([](auto const&, auto const& args)
  77. {
  78. auto const json{ args.WebMessageAsJson() };
  79. handleEvent(json);
  80. });
  81. });
  82. }
  83. m_initialFileName = param.File().Name();
  84. }
  85. }
  86. fire_and_forget MonacoEditPage::OnNavigatedFrom(NavigationEventArgs const& e)
  87. {
  88. // Although editor page will trigger a save before loading new files, there are cases where it does not load a
  89. // new file, e.g. user selected a .mmdb file.
  90. // TODO: trigger save
  91. co_return;
  92. }
  93. IAsyncAction MonacoEditPage::handleEvent(hstring const& eventJson)
  94. {
  95. nlohmann::json doc;
  96. try {
  97. doc = nlohmann::json::parse(to_string(eventJson));
  98. }
  99. catch (...) {}
  100. if (doc["cmd"] == "save")
  101. {
  102. try {
  103. auto const configDir{ co_await ApplicationData::Current().LocalFolder().CreateFolderAsync(L"config", CreationCollisionOption::OpenIfExists) };
  104. auto const configDirPath{ to_string(configDir.Path()) + "\\" };
  105. std::string path{ doc["path"] };
  106. if (auto const pos{ path.find(CONFIG_ROOT_VIRTUAL_HOST) }; pos != std::string::npos)
  107. {
  108. path = path.replace(pos, strlen(CONFIG_ROOT_VIRTUAL_HOST), configDirPath);
  109. }
  110. auto const file{ co_await StorageFile::GetFileFromPathAsync(to_hstring(path)) };
  111. std::string const data{ doc["text"] };
  112. co_await FileIO::WriteBytesAsync(file, array_view{
  113. reinterpret_cast<uint8_t const*>(data.data()),
  114. static_cast<uint32_t>(data.size())
  115. });
  116. }
  117. catch (...) {}
  118. }
  119. co_return;
  120. }
  121. }