7#include <emscripten/html5.h>
9#include <unordered_map>
11#include "absl/strings/str_format.h"
17int WasmFileDialog::next_callback_id_ = 1;
18std::unordered_map<int, WasmFileDialog::PendingOperation> WasmFileDialog::pending_operations_;
19std::mutex WasmFileDialog::operations_mutex_;
22EM_JS(
void, openFileDialog_impl, (
const char* accept,
int callback_id,
bool is_text), {
23 var input = document.createElement(
'input');
25 input.accept = UTF8ToString(accept);
26 input.style.display =
'none';
27 input.onchange = function(e) {
28 var file = e.target.files[0];
30 var errPtr = allocateUTF8(
"No file selected");
31 Module._yazeHandleFileError(callback_id, errPtr);
35 var reader =
new FileReader();
36 reader.onload = function() {
37 var filename = file.name;
38 var filenamePtr = allocateUTF8(filename);
40 var contentPtr = allocateUTF8(reader.result);
41 Module._yazeHandleTextFileLoaded(callback_id, filenamePtr, contentPtr);
44 var data =
new Uint8Array(reader.result);
45 var dataPtr = Module._malloc(data.length);
46 Module.HEAPU8.set(data, dataPtr);
47 Module._yazeHandleFileLoaded(callback_id, filenamePtr, dataPtr, data.length);
48 Module._free(dataPtr);
52 reader.onerror = function() {
53 var errPtr = allocateUTF8(
"Failed to read file");
54 Module._yazeHandleFileError(callback_id, errPtr);
58 reader.readAsText(file);
60 reader.readAsArrayBuffer(file);
63 document.body.appendChild(input);
65 setTimeout(function() { document.body.removeChild(input); }, 100);
68EM_JS(
void, downloadFile_impl, (
const char* filename,
const uint8_t* data,
size_t size,
const char* mime_type), {
69 var dataArray = HEAPU8.subarray(data, data + size);
70 var blob =
new Blob([dataArray], { type: UTF8ToString(mime_type) });
71 var url = URL.createObjectURL(blob);
72 var a = document.createElement(
'a');
74 a.download = UTF8ToString(filename);
75 a.style.display =
'none';
76 document.body.appendChild(a);
78 setTimeout(function() {
79 document.body.removeChild(a);
80 URL.revokeObjectURL(url);
84EM_JS(
void, downloadTextFile_impl, (
const char* filename,
const char* content,
const char* mime_type), {
85 var blob =
new Blob([UTF8ToString(content)], { type: UTF8ToString(mime_type) });
86 var url = URL.createObjectURL(blob);
87 var a = document.createElement(
'a');
89 a.download = UTF8ToString(filename);
90 a.style.display =
'none';
91 document.body.appendChild(a);
93 setTimeout(function() {
94 document.body.removeChild(a);
95 URL.revokeObjectURL(url);
99EM_JS(
bool, isFileApiSupported, (), {
100 return (typeof File !==
'undefined' && typeof FileReader !==
'undefined' && typeof Blob !==
'undefined' && typeof URL !==
'undefined' && typeof URL.createObjectURL !==
'undefined');
104void WasmFileDialog::OpenFileDialog(
const std::string& accept, FileLoadCallback on_load, ErrorCallback on_error) {
106 op.binary_callback = on_load;
107 op.error_callback = on_error;
109 int callback_id = RegisterCallback(std::move(op));
110 openFileDialog_impl(accept.c_str(), callback_id,
false);
113void WasmFileDialog::OpenTextFileDialog(
const std::string& accept,
114 std::function<
void(
const std::string&,
const std::string&)> on_load,
115 ErrorCallback on_error) {
117 op.text_callback = on_load;
118 op.error_callback = on_error;
120 int callback_id = RegisterCallback(std::move(op));
121 openFileDialog_impl(accept.c_str(), callback_id,
true);
124absl::Status WasmFileDialog::DownloadFile(
const std::string& filename,
const std::vector<uint8_t>& data) {
125 if (!IsSupported()) {
126 return absl::FailedPreconditionError(
"File API not supported in this browser");
129 return absl::InvalidArgumentError(
"Cannot download empty file");
131 downloadFile_impl(filename.c_str(), data.data(), data.size(),
"application/octet-stream");
132 return absl::OkStatus();
135absl::Status WasmFileDialog::DownloadTextFile(
const std::string& filename,
const std::string& content,
const std::string& mime_type) {
136 if (!IsSupported()) {
137 return absl::FailedPreconditionError(
"File API not supported in this browser");
139 downloadTextFile_impl(filename.c_str(), content.c_str(), mime_type.c_str());
140 return absl::OkStatus();
143bool WasmFileDialog::IsSupported() {
144 return isFileApiSupported();
148int WasmFileDialog::RegisterCallback(PendingOperation operation) {
149 std::lock_guard<std::mutex> lock(operations_mutex_);
150 int id = next_callback_id_++;
152 pending_operations_[id] = std::move(operation);
156std::unique_ptr<WasmFileDialog::PendingOperation> WasmFileDialog::GetPendingOperation(
int callback_id) {
157 std::lock_guard<std::mutex> lock(operations_mutex_);
158 auto it = pending_operations_.find(callback_id);
159 if (it == pending_operations_.end()) {
162 auto op = std::make_unique<PendingOperation>(std::move(it->second));
163 pending_operations_.erase(it);
167void WasmFileDialog::HandleFileLoaded(
int callback_id,
const char* filename,
const uint8_t* data,
size_t size) {
168 auto op = GetPendingOperation(callback_id);
170 emscripten_log(EM_LOG_WARN,
"Unknown callback ID: %d", callback_id);
173 if (op->binary_callback) {
174 std::vector<uint8_t> file_data(data, data + size);
175 op->binary_callback(filename, file_data);
179void WasmFileDialog::HandleTextFileLoaded(
int callback_id,
const char* filename,
const char* content) {
180 auto op = GetPendingOperation(callback_id);
182 emscripten_log(EM_LOG_WARN,
"Unknown callback ID: %d", callback_id);
185 if (op->text_callback) {
186 op->text_callback(filename, content);
190void WasmFileDialog::HandleFileError(
int callback_id,
const char* error_message) {
191 auto op = GetPendingOperation(callback_id);
193 emscripten_log(EM_LOG_WARN,
"Unknown callback ID: %d", callback_id);
196 if (op->error_callback) {
197 op->error_callback(error_message);
199 emscripten_log(EM_LOG_ERROR,
"File operation error: %s", error_message);
210void yazeHandleFileLoaded(
int callback_id,
const char* filename,
const uint8_t* data,
size_t size) {
211 yaze::platform::WasmFileDialog::HandleFileLoaded(callback_id, filename, data, size);
215void yazeHandleTextFileLoaded(
int callback_id,
const char* filename,
const char* content) {
216 yaze::platform::WasmFileDialog::HandleTextFileLoaded(callback_id, filename, content);
220void yazeHandleFileError(
int callback_id,
const char* error_message) {
221 yaze::platform::WasmFileDialog::HandleFileError(callback_id, error_message);
EM_JS(void, CallJsAiDriver,(const char *history_json), { if(window.yaze &&window.yaze.ai &&window.yaze.ai.processAgentRequest) { window.yaze.ai.processAgentRequest(UTF8ToString(history_json));} else { console.error("AI Driver not found in window.yaze.ai.processAgentRequest");} })