mirror of
https://github.com/webui-dev/webui
synced 2025-03-28 21:13:17 +00:00
refactor: ♻️ split webui source code and js bridge
Move js bridge outiside of webui.c source code to improve dev experience and simplify editing. It also allow to write types def for client. Use xxd to inject bridge into source code.
This commit is contained in:
parent
4877d1e4da
commit
0ff4101c9b
272
src/client/webui.js
Normal file
272
src/client/webui.js
Normal file
@ -0,0 +1,272 @@
|
||||
var _webui_log = _webui_log ?? false; //If webui.c define _webui_log then use it, instead set it to false
|
||||
var _webui_ws;
|
||||
var _webui_ws_status = false;
|
||||
var _webui_ws_status_once = false;
|
||||
var _webui_close_reason = 0;
|
||||
var _webui_close_value;
|
||||
var _webui_has_events = false;
|
||||
var _webui_fn_id = new Uint8Array(1);
|
||||
var _webui_fn_promise_resolve = [];
|
||||
const WEBUI_HEADER_SIGNATURE = 221;
|
||||
const WEBUI_HEADER_JS = 254;
|
||||
const WEBUI_HEADER_JS_QUICK = 253;
|
||||
const WEBUI_HEADER_CLICK = 252;
|
||||
const WEBUI_HEADER_SWITCH = 251;
|
||||
const WEBUI_HEADER_CLOSE = 250;
|
||||
const WEBUI_HEADER_CALL_FUNC = 249;
|
||||
function _webui_close(reason = 0, value = 0) {
|
||||
if(reason == WEBUI_HEADER_SWITCH) _webui_send_event_navigation(value);
|
||||
_webui_ws_status = false;
|
||||
_webui_close_reason = reason;
|
||||
_webui_close_value = value;
|
||||
_webui_ws.close();
|
||||
}
|
||||
function _webui_freeze_ui() {
|
||||
document.body.style.filter = 'contrast(1%)';
|
||||
}
|
||||
function _webui_start() {
|
||||
if('WebSocket' in window) {
|
||||
if(_webui_bind_list.includes(_webui_win_num + '/')) _webui_has_events = true;
|
||||
_webui_ws = new WebSocket('ws://localhost:' + _webui_port + '/_webui_ws_connect');
|
||||
_webui_ws.binaryType = 'arraybuffer';
|
||||
_webui_ws.onopen = function () {
|
||||
_webui_ws.binaryType = 'arraybuffer';
|
||||
_webui_ws_status = true;
|
||||
_webui_ws_status_once = true;
|
||||
_webui_fn_id[0] = 1;
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Connected');
|
||||
_webui_clicks_listener();
|
||||
};
|
||||
_webui_ws.onerror = function () {
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Connection Failed');
|
||||
_webui_freeze_ui();
|
||||
};
|
||||
_webui_ws.onclose = function (evt) {
|
||||
_webui_ws_status = false;
|
||||
if(_webui_close_reason === WEBUI_HEADER_SWITCH) {
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Connection lost -> Navigation to [' + _webui_close_value + ']');
|
||||
window.location.replace(_webui_close_value);
|
||||
} else {
|
||||
if(_webui_log) {
|
||||
console.log('WebUI -> Connection lost (' + evt.code + ')');
|
||||
_webui_freeze_ui();
|
||||
} else _webui_close_window_timer();
|
||||
}
|
||||
};
|
||||
_webui_ws.onmessage = function (evt) {
|
||||
const buffer8 = new Uint8Array(evt.data);
|
||||
if(buffer8.length < 4) return;
|
||||
if(buffer8[0] !== WEBUI_HEADER_SIGNATURE)
|
||||
return;
|
||||
var len = buffer8.length - 3;
|
||||
if(buffer8[buffer8.length - 1] === 0)
|
||||
len--; // Null byte (0x00) can break eval()
|
||||
data8 = new Uint8Array(len);
|
||||
for (i = 0; i < len; i++) data8[i] = buffer8[i + 3];
|
||||
var data8utf8 = new TextDecoder('utf-8').decode(data8);
|
||||
// Process Command
|
||||
if(buffer8[1] === WEBUI_HEADER_CALL_FUNC) {
|
||||
const call_id = buffer8[2];
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Func Reponse [' + data8utf8 + ']');
|
||||
if (_webui_fn_promise_resolve[call_id]) {
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Resolving reponse #' + call_id + '...');
|
||||
_webui_fn_promise_resolve[call_id](data8utf8);
|
||||
_webui_fn_promise_resolve[call_id] = null;
|
||||
}
|
||||
} else if(buffer8[1] === WEBUI_HEADER_SWITCH) {
|
||||
_webui_close(WEBUI_HEADER_SWITCH, data8utf8);
|
||||
} else if(buffer8[1] === WEBUI_HEADER_CLOSE) {
|
||||
window.close();
|
||||
} else if(buffer8[1] === WEBUI_HEADER_JS_QUICK || buffer8[1] === WEBUI_HEADER_JS) {
|
||||
data8utf8 = data8utf8.replace(/(?:\\r\\n|\\r|\\n)/g, \"\\\\n\");
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> JS [' + data8utf8 + ']');
|
||||
var FunReturn = 'undefined';
|
||||
var FunError = false;
|
||||
try { FunReturn = eval('(() => {' + data8utf8 + '})()'); } catch (e) { FunError = true; FunReturn = e.message }
|
||||
if(buffer8[1] === WEBUI_HEADER_JS_QUICK) return;
|
||||
if(typeof FunReturn === 'undefined' || FunReturn === undefined) FunReturn = 'undefined';
|
||||
if(_webui_log && !FunError) console.log('WebUI -> JS -> Return [' + FunReturn + ']');
|
||||
if(_webui_log && FunError) console.log('WebUI -> JS -> Error [' + FunReturn + ']');
|
||||
const FunReturn8 = new TextEncoder('utf-8').encode(FunReturn);
|
||||
var Return8 = new Uint8Array(4 + FunReturn8.length);
|
||||
Return8[0] = WEBUI_HEADER_SIGNATURE;
|
||||
Return8[1] = WEBUI_HEADER_JS;
|
||||
Return8[2] = buffer8[2];
|
||||
if(FunError) Return8[3] = 0;
|
||||
else Return8[3] = 1;
|
||||
var p = -1;
|
||||
for (i = 4; i < FunReturn8.length + 4; i++) Return8[i] = FunReturn8[++p];
|
||||
if(_webui_ws_status) _webui_ws.send(Return8.buffer);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
alert('Sorry. WebSocket not supported by your Browser.');
|
||||
if(!_webui_log) window.close();
|
||||
}
|
||||
}
|
||||
function _webui_clicks_listener() {
|
||||
Object.keys(window).forEach(key=>{
|
||||
if(/^on(click)/.test(key)) {
|
||||
window.addEventListener(key.slice(2),event=>{
|
||||
if(_webui_has_events || ((event.target.id !== '') && (_webui_bind_list.includes(_webui_win_num + '/' + event.target.id)))) {
|
||||
_webui_send_click(event.target.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function _webui_send_click(elem) {
|
||||
if(_webui_ws_status) {
|
||||
var packet;
|
||||
if(elem !== '') {
|
||||
const elem8 = new TextEncoder('utf-8').encode(elem);
|
||||
packet = new Uint8Array(3 + elem8.length);
|
||||
packet[0] = WEBUI_HEADER_SIGNATURE;
|
||||
packet[1] = WEBUI_HEADER_CLICK;
|
||||
packet[2] = 0;
|
||||
var p = -1;
|
||||
for (i = 3; i < elem8.length + 3; i++)
|
||||
packet[i] = elem8[++p];
|
||||
} else {
|
||||
packet = new Uint8Array(4);
|
||||
packet[0] = WEBUI_HEADER_SIGNATURE;
|
||||
packet[1] = WEBUI_HEADER_CLICK;
|
||||
packet[2] = 0;
|
||||
packet[3] = 0;
|
||||
}
|
||||
_webui_ws.send(packet.buffer);
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Click [' + elem + ']');
|
||||
}
|
||||
}
|
||||
function _webui_send_event_navigation(url) {
|
||||
if(_webui_has_events && _webui_ws_status && url !== '') {
|
||||
const url8 = new TextEncoder('utf-8').encode(url);
|
||||
var packet = new Uint8Array(3 + url8.length);
|
||||
packet[0] = WEBUI_HEADER_SIGNATURE;
|
||||
packet[1] = WEBUI_HEADER_SWITCH;
|
||||
packet[2] = 0;
|
||||
var p = -1;
|
||||
for (i = 3; i < url8.length + 3; i++)
|
||||
packet[i] = url8[++p];
|
||||
_webui_ws.send(packet.buffer);
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Navigation [' + url + ']');
|
||||
}
|
||||
}
|
||||
function _webui_is_external_link(url) {
|
||||
const currentUrl = new URL(window.location.href);
|
||||
const targetUrl = new URL(url, window.location.href);
|
||||
currentUrl.hash = '';
|
||||
targetUrl.hash = '';
|
||||
if (url.startsWith('#') || url === currentUrl.href + '#' || currentUrl.href === targetUrl.href) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function _webui_close_window_timer() {
|
||||
setTimeout(function(){window.close();},1000);
|
||||
}
|
||||
async function _webui_fn_promise(fn, value) {
|
||||
if(_webui_log)
|
||||
console.log('WebUI -> Func [' + fn + '](' + value + ')');
|
||||
const fn8 = new TextEncoder('utf-8').encode(fn);
|
||||
const value8 = new TextEncoder('utf-8').encode(value);
|
||||
var packet = new Uint8Array(3 + fn8.length + 1 + value8.length);
|
||||
const call_id = _webui_fn_id[0]++;
|
||||
packet[0] = WEBUI_HEADER_SIGNATURE;
|
||||
packet[1] = WEBUI_HEADER_CALL_FUNC;
|
||||
packet[2] = call_id;
|
||||
var p = 3;
|
||||
for (var i = 0; i < fn8.length; i++)
|
||||
{ packet[p] = fn8[i]; p++; }
|
||||
packet[p] = 0;
|
||||
p++;
|
||||
if(value8.length > 0) {
|
||||
for (var i = 0; i < value8.length; i++)
|
||||
{ packet[p] = value8[i]; p++; }
|
||||
} else { packet[p] = 0; }
|
||||
return new Promise((resolve) => {
|
||||
_webui_fn_promise_resolve[call_id] = resolve;
|
||||
_webui_ws.send(packet.buffer);
|
||||
});
|
||||
}
|
||||
// -- APIs --------------------------
|
||||
function webui_fn(fn, value) {
|
||||
if(!fn || !_webui_ws_status)
|
||||
return Promise.resolve();
|
||||
if(typeof value == 'undefined')
|
||||
var value = '';
|
||||
if(!_webui_has_events && !_webui_bind_list.includes(_webui_win_num + '/' + fn))
|
||||
return Promise.resolve();
|
||||
return _webui_fn_promise(fn, value);
|
||||
}
|
||||
function webui_log(status) {
|
||||
if(status) {
|
||||
console.log('WebUI -> Log Enabled.');
|
||||
_webui_log = true;
|
||||
} else {
|
||||
console.log('WebUI -> Log Disabled.');
|
||||
_webui_log = false;
|
||||
}
|
||||
}
|
||||
function webui_encode(str) {
|
||||
return btoa(str);
|
||||
}
|
||||
function webui_decode(str) {
|
||||
return atob(str);
|
||||
}
|
||||
// -- DOM ---------------------------
|
||||
document.addEventListener('keydown', function (e) {
|
||||
// Disable F5
|
||||
if(_webui_log) return;
|
||||
if(e.keyCode === 116) {
|
||||
e.preventDefault();
|
||||
e.returnValue = false;
|
||||
e.keyCode = 0;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
window.onbeforeunload = function () {
|
||||
_webui_ws.close();
|
||||
};
|
||||
setTimeout(function () {
|
||||
if(!_webui_ws_status_once) {
|
||||
_webui_freeze_ui();
|
||||
alert('WebUI failed to connect to the background application. Please try again.');
|
||||
if(!_webui_log) window.close();
|
||||
}
|
||||
}, 1500);
|
||||
window.addEventListener('unload', unload_handler, false);
|
||||
function unload_handler() {
|
||||
// Unload for 'back' & 'forward' navigation
|
||||
window.removeEventListener('unload', unload_handler, false);
|
||||
}
|
||||
// Links
|
||||
document.addEventListener('click', e => {
|
||||
const attribute = e.target.closest('a');
|
||||
if(attribute) {
|
||||
const link = attribute.href;
|
||||
if(_webui_is_external_link(link)) {
|
||||
e.preventDefault();
|
||||
_webui_close(WEBUI_HEADER_SWITCH, link);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(typeof navigation !== 'undefined') {
|
||||
navigation.addEventListener('navigate', (event) => {
|
||||
const url = new URL(event.destination.url);
|
||||
_webui_send_event_navigation(url);
|
||||
});
|
||||
}
|
||||
document.body.addEventListener('contextmenu', function(event){ event.preventDefault(); });
|
||||
const inputs = document.getElementsByTagName('input');
|
||||
for(var i = 0; i < inputs.length; i++){ inputs[i].addEventListener('contextmenu', function(event){ event.stopPropagation(); });}
|
||||
// Load
|
||||
window.addEventListener('load', _webui_start()); \n";
|
314
src/webui.c
314
src/webui.c
@ -15,291 +15,13 @@
|
||||
// -- WebUI ---------------------------
|
||||
#include "webui_core.h"
|
||||
|
||||
// -- WebUI JS API --------------------
|
||||
#include "client/webui.c"
|
||||
static char* webui_javascript_bridge = __webui_js;
|
||||
|
||||
// -- Heap ----------------------------
|
||||
static _webui_core_t _webui_core;
|
||||
|
||||
// -- WebUI JS-Bridge ---------
|
||||
// This is a uncompressed version to make the debugging
|
||||
// more easy in the browser using the builtin dev-tools
|
||||
#ifdef WEBUI_LOG
|
||||
#define WEBUI_JS_LOG "true"
|
||||
#else
|
||||
#define WEBUI_JS_LOG "false"
|
||||
#endif
|
||||
static const char* webui_javascript_bridge =
|
||||
"var _webui_log = " WEBUI_JS_LOG "; \n"
|
||||
"var _webui_ws; \n"
|
||||
"var _webui_ws_status = false; \n"
|
||||
"var _webui_ws_status_once = false; \n"
|
||||
"var _webui_close_reason = 0; \n"
|
||||
"var _webui_close_value; \n"
|
||||
"var _webui_has_events = false; \n"
|
||||
"var _webui_fn_id = new Uint8Array(1); \n"
|
||||
"var _webui_fn_promise_resolve = []; \n"
|
||||
"const WEBUI_HEADER_SIGNATURE = 221; \n"
|
||||
"const WEBUI_HEADER_JS = 254; \n"
|
||||
"const WEBUI_HEADER_JS_QUICK = 253; \n"
|
||||
"const WEBUI_HEADER_CLICK = 252; \n"
|
||||
"const WEBUI_HEADER_SWITCH = 251; \n"
|
||||
"const WEBUI_HEADER_CLOSE = 250; \n"
|
||||
"const WEBUI_HEADER_CALL_FUNC = 249; \n"
|
||||
"function _webui_close(reason = 0, value = 0) { \n"
|
||||
" if(reason == WEBUI_HEADER_SWITCH) _webui_send_event_navigation(value); \n"
|
||||
" _webui_ws_status = false; \n"
|
||||
" _webui_close_reason = reason; \n"
|
||||
" _webui_close_value = value; \n"
|
||||
" _webui_ws.close(); \n"
|
||||
"} \n"
|
||||
"function _webui_freeze_ui() { \n"
|
||||
" document.body.style.filter = 'contrast(1%)'; \n"
|
||||
"} \n"
|
||||
"function _webui_start() { \n"
|
||||
" if('WebSocket' in window) { \n"
|
||||
" if(_webui_bind_list.includes(_webui_win_num + '/')) _webui_has_events = true; \n"
|
||||
" _webui_ws = new WebSocket('ws://localhost:' + _webui_port + '/_webui_ws_connect'); \n"
|
||||
" _webui_ws.binaryType = 'arraybuffer'; \n"
|
||||
" _webui_ws.onopen = function () { \n"
|
||||
" _webui_ws.binaryType = 'arraybuffer'; \n"
|
||||
" _webui_ws_status = true; \n"
|
||||
" _webui_ws_status_once = true; \n"
|
||||
" _webui_fn_id[0] = 1; \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Connected'); \n"
|
||||
" _webui_clicks_listener(); \n"
|
||||
" }; \n"
|
||||
" _webui_ws.onerror = function () { \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Connection Failed'); \n"
|
||||
" _webui_freeze_ui(); \n"
|
||||
" }; \n"
|
||||
" _webui_ws.onclose = function (evt) { \n"
|
||||
" _webui_ws_status = false; \n"
|
||||
" if(_webui_close_reason === WEBUI_HEADER_SWITCH) { \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Connection lost -> Navigation to [' + _webui_close_value + ']'); \n"
|
||||
" window.location.replace(_webui_close_value); \n"
|
||||
" } else { \n"
|
||||
" if(_webui_log) { \n"
|
||||
" console.log('WebUI -> Connection lost (' + evt.code + ')'); \n"
|
||||
" _webui_freeze_ui(); \n"
|
||||
" } else _webui_close_window_timer(); \n"
|
||||
" } \n"
|
||||
" }; \n"
|
||||
" _webui_ws.onmessage = function (evt) { \n"
|
||||
" const buffer8 = new Uint8Array(evt.data); \n"
|
||||
" if(buffer8.length < 4) return; \n"
|
||||
" if(buffer8[0] !== WEBUI_HEADER_SIGNATURE) \n"
|
||||
" return; \n"
|
||||
" var len = buffer8.length - 3; \n"
|
||||
" if(buffer8[buffer8.length - 1] === 0) \n"
|
||||
" len--; // Null byte (0x00) can break eval() \n"
|
||||
" data8 = new Uint8Array(len); \n"
|
||||
" for (i = 0; i < len; i++) data8[i] = buffer8[i + 3]; \n"
|
||||
" var data8utf8 = new TextDecoder('utf-8').decode(data8); \n"
|
||||
" // Process Command \n"
|
||||
" if(buffer8[1] === WEBUI_HEADER_CALL_FUNC) { \n"
|
||||
" const call_id = buffer8[2];\n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Func Reponse [' + data8utf8 + ']'); \n"
|
||||
" if (_webui_fn_promise_resolve[call_id]) { \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Resolving reponse #' + call_id + '...'); \n"
|
||||
" _webui_fn_promise_resolve[call_id](data8utf8); \n"
|
||||
" _webui_fn_promise_resolve[call_id] = null; \n"
|
||||
" } \n"
|
||||
" } else if(buffer8[1] === WEBUI_HEADER_SWITCH) { \n"
|
||||
" _webui_close(WEBUI_HEADER_SWITCH, data8utf8); \n"
|
||||
" } else if(buffer8[1] === WEBUI_HEADER_CLOSE) { \n"
|
||||
" window.close(); \n"
|
||||
" } else if(buffer8[1] === WEBUI_HEADER_JS_QUICK || buffer8[1] === WEBUI_HEADER_JS) { \n"
|
||||
" data8utf8 = data8utf8.replace(/(?:\\r\\n|\\r|\\n)/g, \"\\\\n\"); \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> JS [' + data8utf8 + ']'); \n"
|
||||
" var FunReturn = 'undefined'; \n"
|
||||
" var FunError = false; \n"
|
||||
" try { FunReturn = eval('(() => {' + data8utf8 + '})()'); } catch (e) { FunError = true; FunReturn = e.message } \n"
|
||||
" if(buffer8[1] === WEBUI_HEADER_JS_QUICK) return; \n"
|
||||
" if(typeof FunReturn === 'undefined' || FunReturn === undefined) FunReturn = 'undefined'; \n"
|
||||
" if(_webui_log && !FunError) console.log('WebUI -> JS -> Return [' + FunReturn + ']'); \n"
|
||||
" if(_webui_log && FunError) console.log('WebUI -> JS -> Error [' + FunReturn + ']'); \n"
|
||||
" const FunReturn8 = new TextEncoder('utf-8').encode(FunReturn); \n"
|
||||
" var Return8 = new Uint8Array(4 + FunReturn8.length); \n"
|
||||
" Return8[0] = WEBUI_HEADER_SIGNATURE; \n"
|
||||
" Return8[1] = WEBUI_HEADER_JS; \n"
|
||||
" Return8[2] = buffer8[2]; \n"
|
||||
" if(FunError) Return8[3] = 0; \n"
|
||||
" else Return8[3] = 1; \n"
|
||||
" var p = -1; \n"
|
||||
" for (i = 4; i < FunReturn8.length + 4; i++) Return8[i] = FunReturn8[++p]; \n"
|
||||
" if(_webui_ws_status) _webui_ws.send(Return8.buffer); \n"
|
||||
" } \n"
|
||||
" }; \n"
|
||||
" } else { \n"
|
||||
" alert('Sorry. WebSocket not supported by your Browser.'); \n"
|
||||
" if(!_webui_log) window.close(); \n"
|
||||
" } \n"
|
||||
"} \n"
|
||||
"function _webui_clicks_listener() { \n"
|
||||
" Object.keys(window).forEach(key=>{ \n"
|
||||
" if(/^on(click)/.test(key)) { \n"
|
||||
" window.addEventListener(key.slice(2),event=>{ \n"
|
||||
" if(_webui_has_events || ((event.target.id !== '') && (_webui_bind_list.includes(_webui_win_num + '/' + event.target.id)))) { \n"
|
||||
" _webui_send_click(event.target.id); \n"
|
||||
" } \n"
|
||||
" }); \n"
|
||||
" } \n"
|
||||
" }); \n"
|
||||
"} \n"
|
||||
"function _webui_send_click(elem) { \n"
|
||||
" if(_webui_ws_status) { \n"
|
||||
" var packet; \n"
|
||||
" if(elem !== '') { \n"
|
||||
" const elem8 = new TextEncoder('utf-8').encode(elem); \n"
|
||||
" packet = new Uint8Array(3 + elem8.length); \n"
|
||||
" packet[0] = WEBUI_HEADER_SIGNATURE; \n"
|
||||
" packet[1] = WEBUI_HEADER_CLICK; \n"
|
||||
" packet[2] = 0; \n"
|
||||
" var p = -1; \n"
|
||||
" for (i = 3; i < elem8.length + 3; i++) \n"
|
||||
" packet[i] = elem8[++p]; \n"
|
||||
" } else { \n"
|
||||
" packet = new Uint8Array(4); \n"
|
||||
" packet[0] = WEBUI_HEADER_SIGNATURE; \n"
|
||||
" packet[1] = WEBUI_HEADER_CLICK; \n"
|
||||
" packet[2] = 0; \n"
|
||||
" packet[3] = 0; \n"
|
||||
" } \n"
|
||||
" _webui_ws.send(packet.buffer); \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Click [' + elem + ']'); \n"
|
||||
" } \n"
|
||||
"} \n"
|
||||
"function _webui_send_event_navigation(url) { \n"
|
||||
" if(_webui_has_events && _webui_ws_status && url !== '') { \n"
|
||||
" const url8 = new TextEncoder('utf-8').encode(url); \n"
|
||||
" var packet = new Uint8Array(3 + url8.length); \n"
|
||||
" packet[0] = WEBUI_HEADER_SIGNATURE; \n"
|
||||
" packet[1] = WEBUI_HEADER_SWITCH; \n"
|
||||
" packet[2] = 0; \n"
|
||||
" var p = -1; \n"
|
||||
" for (i = 3; i < url8.length + 3; i++) \n"
|
||||
" packet[i] = url8[++p]; \n"
|
||||
" _webui_ws.send(packet.buffer); \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Navigation [' + url + ']'); \n"
|
||||
" } \n"
|
||||
"} \n"
|
||||
"function _webui_is_external_link(url) { \n"
|
||||
" const currentUrl = new URL(window.location.href); \n"
|
||||
" const targetUrl = new URL(url, window.location.href); \n"
|
||||
" currentUrl.hash = ''; \n"
|
||||
" targetUrl.hash = ''; \n"
|
||||
" if (url.startsWith('#') || url === currentUrl.href + '#' || currentUrl.href === targetUrl.href) { \n"
|
||||
" return false; \n"
|
||||
" } \n"
|
||||
" return true; \n"
|
||||
"} \n"
|
||||
"function _webui_close_window_timer() { \n"
|
||||
" setTimeout(function(){window.close();},1000); \n"
|
||||
"} \n"
|
||||
"async function _webui_fn_promise(fn, value) { \n"
|
||||
" if(_webui_log) \n"
|
||||
" console.log('WebUI -> Func [' + fn + '](' + value + ')'); \n"
|
||||
" const fn8 = new TextEncoder('utf-8').encode(fn); \n"
|
||||
" const value8 = new TextEncoder('utf-8').encode(value); \n"
|
||||
" var packet = new Uint8Array(3 + fn8.length + 1 + value8.length); \n"
|
||||
" const call_id = _webui_fn_id[0]++; \n"
|
||||
" packet[0] = WEBUI_HEADER_SIGNATURE; \n"
|
||||
" packet[1] = WEBUI_HEADER_CALL_FUNC; \n"
|
||||
" packet[2] = call_id; \n"
|
||||
" var p = 3; \n"
|
||||
" for (var i = 0; i < fn8.length; i++) \n"
|
||||
" { packet[p] = fn8[i]; p++; } \n"
|
||||
" packet[p] = 0; \n"
|
||||
" p++; \n"
|
||||
" if(value8.length > 0) { \n"
|
||||
" for (var i = 0; i < value8.length; i++) \n"
|
||||
" { packet[p] = value8[i]; p++; } \n"
|
||||
" } else { packet[p] = 0; } \n"
|
||||
" return new Promise((resolve) => { \n"
|
||||
" _webui_fn_promise_resolve[call_id] = resolve; \n"
|
||||
" _webui_ws.send(packet.buffer); \n"
|
||||
" }); \n"
|
||||
"} \n"
|
||||
" // -- APIs -------------------------- \n"
|
||||
"function webui_fn(fn, value) { \n"
|
||||
" if(!fn || !_webui_ws_status) \n"
|
||||
" return Promise.resolve(); \n"
|
||||
" if(typeof value == 'undefined') \n"
|
||||
" var value = ''; \n"
|
||||
" if(!_webui_has_events && !_webui_bind_list.includes(_webui_win_num + '/' + fn)) \n"
|
||||
" return Promise.resolve(); \n"
|
||||
" return _webui_fn_promise(fn, value); \n"
|
||||
"} \n"
|
||||
"function webui_log(status) { \n"
|
||||
" if(status) { \n"
|
||||
" console.log('WebUI -> Log Enabled.'); \n"
|
||||
" _webui_log = true; \n"
|
||||
" } else { \n"
|
||||
" console.log('WebUI -> Log Disabled.'); \n"
|
||||
" _webui_log = false; \n"
|
||||
" } \n"
|
||||
"} \n"
|
||||
"function webui_encode(str) { \n"
|
||||
" return btoa(str); \n"
|
||||
"} \n"
|
||||
"function webui_decode(str) { \n"
|
||||
" return atob(str); \n"
|
||||
"} \n"
|
||||
" // -- DOM --------------------------- \n"
|
||||
"document.addEventListener('keydown', function (e) { \n"
|
||||
" // Disable F5 \n"
|
||||
" if(_webui_log) return; \n"
|
||||
" if(e.keyCode === 116) { \n"
|
||||
" e.preventDefault(); \n"
|
||||
" e.returnValue = false; \n"
|
||||
" e.keyCode = 0; \n"
|
||||
" return false; \n"
|
||||
" } \n"
|
||||
"}); \n"
|
||||
"window.onbeforeunload = function () { \n"
|
||||
" _webui_ws.close(); \n"
|
||||
"}; \n"
|
||||
"setTimeout(function () { \n"
|
||||
" if(!_webui_ws_status_once) { \n"
|
||||
" _webui_freeze_ui(); \n"
|
||||
" alert('WebUI failed to connect to the background application. Please try again.'); \n"
|
||||
" if(!_webui_log) window.close(); \n"
|
||||
" } \n"
|
||||
"}, 1500); \n"
|
||||
"window.addEventListener('unload', unload_handler, false); \n"
|
||||
"function unload_handler() { \n"
|
||||
" // Unload for 'back' & 'forward' navigation \n"
|
||||
" window.removeEventListener('unload', unload_handler, false); \n"
|
||||
"} \n"
|
||||
"// Links \n"
|
||||
"document.addEventListener('click', e => { \n"
|
||||
" const attribute = e.target.closest('a'); \n"
|
||||
" if(attribute) { \n"
|
||||
" const link = attribute.href; \n"
|
||||
" if(_webui_is_external_link(link)) { \n"
|
||||
" e.preventDefault(); \n"
|
||||
" _webui_close(WEBUI_HEADER_SWITCH, link); \n"
|
||||
" } \n"
|
||||
" } \n"
|
||||
"}); \n"
|
||||
"if(typeof navigation !== 'undefined') { \n"
|
||||
" navigation.addEventListener('navigate', (event) => { \n"
|
||||
" const url = new URL(event.destination.url); \n"
|
||||
" _webui_send_event_navigation(url); \n"
|
||||
" }); \n"
|
||||
"} \n"
|
||||
"document.body.addEventListener('contextmenu', function(event){ event.preventDefault(); }); \n"
|
||||
"const inputs = document.getElementsByTagName('input'); \n"
|
||||
"for(var i = 0; i < inputs.length; i++){ inputs[i].addEventListener('contextmenu', function(event){ event.stopPropagation(); });} \n"
|
||||
"// Load \n"
|
||||
"window.addEventListener('load', _webui_start()); \n";
|
||||
|
||||
// -- Heap ----------------------------
|
||||
static const char* webui_html_served = "<html><head><title>Access Denied</title><style>body{margin:0;background-repeat:no-repeat;background-attachment:fixed;background-color:#FF3CAC;background-image:linear-gradient(225deg,#FF3CAC 0%,#784BA0 45%,#2B86C5 100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</style></head><body><h2>⚠ Access Denied</h2><p>You can't access this content<br>because it's already processed.<br><br>The current security policy denies<br>multiple requests.</p><br><a href=\"https://www.webui.me\"><small>WebUI v" WEBUI_VERSION "<small></a></body></html>";
|
||||
static const char* webui_html_res_not_available = "<html><head><title>Resource Not Available</title><style>body{margin:0;background-repeat:no-repeat;background-attachment:fixed;background-color:#FF3CAC;background-image:linear-gradient(225deg,#FF3CAC 0%,#784BA0 45%,#2B86C5 100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</style></head><body><h2>⚠ Resource Not Available</h2><p>The requested resource is not available.</p><br><a href=\"https://www.webui.me\"><small>WebUI v" WEBUI_VERSION "<small></a></body></html>";
|
||||
@ -2171,11 +1893,6 @@ static int _webui_interpret_file(_webui_window_t* win, struct mg_connection *con
|
||||
}
|
||||
|
||||
static const char* _webui_generate_js_bridge(_webui_window_t* win) {
|
||||
|
||||
#ifdef WEBUI_LOG
|
||||
printf("[Core]\t\t_webui_generate_js_bridge()...\n");
|
||||
#endif
|
||||
|
||||
// Calculate the cb size
|
||||
size_t cb_mem_size = 64; // To hold 'const _webui_bind_list = ["elem1", "elem2",];'
|
||||
for(size_t i = 1; i < WEBUI_MAX_ARRAY; i++)
|
||||
@ -2195,12 +1912,23 @@ static const char* _webui_generate_js_bridge(_webui_window_t* win) {
|
||||
strcat(event_cb_js_array, "]; \n");
|
||||
|
||||
// Generate the full WebUI JS-Bridge
|
||||
size_t len = cb_mem_size + _webui_strlen(webui_javascript_bridge);
|
||||
char* js = (char*) _webui_malloc(len);
|
||||
sprintf(js,
|
||||
"_webui_port = %zu; \n_webui_win_num = %zu; \n%s \n%s \n",
|
||||
win->ws_port, win->window_number, event_cb_js_array, webui_javascript_bridge
|
||||
);
|
||||
#ifdef WEBUI_LOG
|
||||
char* webui_javascript_log = "var _webui_log = true;";
|
||||
size_t len = cb_mem_size + _webui_srtlen(webui_javascript_log) + _webui_strlen(webui_javascript_bridge);
|
||||
char* js = (char*) _webui_malloc(len);
|
||||
sprintf(js,
|
||||
"%s\n _webui_port = %zu; \n_webui_win_num = %zu; \n%s \n%s \n",
|
||||
webui_javascript_log, win->ws_port, win->window_number, event_cb_js_array, webui_javascript_bridge
|
||||
);
|
||||
printf("[Core]\t\t_webui_generate_js_bridge()...\n");
|
||||
#else
|
||||
size_t len = cb_mem_size + _webui_strlen(webui_javascript_bridge);
|
||||
char* js = (char*) _webui_malloc(len);
|
||||
sprintf(js,
|
||||
"_webui_port = %zu; \n_webui_win_num = %zu; \n%s \n%s \n",
|
||||
win->ws_port, win->window_number, event_cb_js_array, webui_javascript_bridge
|
||||
);
|
||||
#endif
|
||||
|
||||
return js;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user