mirror of
https://github.com/webui-dev/webui.git
synced 2024-09-11 22:17:13 +03:00
Adding webui_navigate
- Adding webui_navigate() - Now when using all events webui_bind(MyWindow, "", events), WebUI will block all href requests - Fix https://github.com/webui-dev/webui/issues/228
This commit is contained in:
parent
2ca3b793c4
commit
6a634cc680
File diff suppressed because it is too large
Load Diff
@ -46,13 +46,14 @@ class WebuiBridge {
|
||||
#hasEvents = false
|
||||
#fnId = 1
|
||||
#fnPromiseResolve: (((data: string) => unknown) | undefined)[] = []
|
||||
#allowNavigation = false
|
||||
|
||||
// WebUI const
|
||||
#HEADER_SIGNATURE = 221
|
||||
#HEADER_JS = 254
|
||||
#HEADER_JS_QUICK = 253
|
||||
#HEADER_CLICK = 252
|
||||
#HEADER_SWITCH = 251
|
||||
#HEADER_NAVIGATION = 251
|
||||
#HEADER_CLOSE = 250
|
||||
#HEADER_CALL_FUNC = 249
|
||||
#HEADER_SEND_RAW = 248
|
||||
@ -116,8 +117,17 @@ class WebuiBridge {
|
||||
// Handle navigation server side
|
||||
if ('navigation' in globalThis) {
|
||||
globalThis.navigation.addEventListener('navigate', (event) => {
|
||||
const url = new URL(event.destination.url)
|
||||
this.#sendEventNavigation(url.href)
|
||||
if(!this.#allowNavigation) {
|
||||
event.preventDefault()
|
||||
const url = new URL(event.destination.url)
|
||||
if (this.#hasEvents) {
|
||||
if (this.#log) console.log(`WebUI -> DOM -> Navigation Event [${url.href}]`)
|
||||
this.#sendEventNavigation(url.href)
|
||||
}
|
||||
else {
|
||||
this.#close(this.#HEADER_NAVIGATION, url.href)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Handle all link click to prevent natural navigation
|
||||
@ -127,12 +137,21 @@ class WebuiBridge {
|
||||
'a',
|
||||
'click',
|
||||
(event) => {
|
||||
event.preventDefault()
|
||||
const { href } = event.target as HTMLAnchorElement
|
||||
if (this.#isExternalLink(href)) {
|
||||
this.#close(this.#HEADER_SWITCH, href)
|
||||
} else {
|
||||
this.#sendEventNavigation(href)
|
||||
if(!this.#allowNavigation) {
|
||||
event.preventDefault()
|
||||
const { href } = event.target as HTMLAnchorElement
|
||||
if (this.#hasEvents) {
|
||||
if (this.#log) console.log(`WebUI -> DOM -> Navigation Click Event [${href}]`)
|
||||
// if (this.#isExternalLink(href)) {
|
||||
// this.#close(this.#HEADER_NAVIGATION, href)
|
||||
// } else {
|
||||
// this.#sendEventNavigation(href)
|
||||
// }
|
||||
this.#sendEventNavigation(href)
|
||||
}
|
||||
else {
|
||||
this.#close(this.#HEADER_NAVIGATION, href)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -161,7 +180,7 @@ class WebuiBridge {
|
||||
}
|
||||
|
||||
#close(reason = 0, value = '') {
|
||||
if (reason === this.#HEADER_SWITCH) this.#sendEventNavigation(value)
|
||||
// if (reason === this.#HEADER_NAVIGATION) this.#sendEventNavigation(value)
|
||||
this.#wsStatus = false
|
||||
this.#closeReason = reason
|
||||
this.#closeValue = value
|
||||
@ -217,14 +236,13 @@ class WebuiBridge {
|
||||
|
||||
this.#ws.onclose = (event) => {
|
||||
this.#wsStatus = false
|
||||
if (this.#closeReason === this.#HEADER_SWITCH) {
|
||||
if (this.#closeReason === this.#HEADER_NAVIGATION) {
|
||||
if (this.#log) {
|
||||
console.log(
|
||||
`WebUI -> Connection lost -> Navigation to [${
|
||||
this.#closeValue
|
||||
}]`
|
||||
`WebUI -> Connection closed -> Navigation to [${this.#closeValue}]`
|
||||
)
|
||||
}
|
||||
this.#allowNavigation = true
|
||||
globalThis.location.replace(this.#closeValue)
|
||||
} else {
|
||||
if (this.#log) {
|
||||
@ -258,12 +276,12 @@ class WebuiBridge {
|
||||
const callId = buffer8[2]
|
||||
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> Call Response [${callResponse}]`)
|
||||
console.log(`WebUI -> CMD -> Call Response [${callResponse}]`)
|
||||
}
|
||||
if (this.#fnPromiseResolve[callId]) {
|
||||
if (this.#log) {
|
||||
console.log(
|
||||
`WebUI -> Resolving Response #${callId}...`
|
||||
`WebUI -> CMD -> Resolving Response #${callId}...`
|
||||
)
|
||||
}
|
||||
this.#fnPromiseResolve[callId]?.(callResponse)
|
||||
@ -271,15 +289,15 @@ class WebuiBridge {
|
||||
}
|
||||
}
|
||||
break
|
||||
case this.#HEADER_SWITCH:
|
||||
case this.#HEADER_NAVIGATION:
|
||||
// Command Packet
|
||||
// 0: [Signature]
|
||||
// 1: [CMD]
|
||||
// 2: [URL]
|
||||
|
||||
const url = this.#getDataStrFromPacket(buffer8, 2)
|
||||
console.log(`WebUI -> Switch [${url}]`)
|
||||
this.#close(this.#HEADER_SWITCH, url)
|
||||
console.log(`WebUI -> CMD -> Navigation [${url}]`)
|
||||
this.#close(this.#HEADER_NAVIGATION, url)
|
||||
break
|
||||
case this.#HEADER_NEW_ID:
|
||||
// Command Packet
|
||||
@ -288,7 +306,7 @@ class WebuiBridge {
|
||||
// 2: [New Element]
|
||||
|
||||
const newElement = this.#getDataStrFromPacket(buffer8, 2)
|
||||
console.log(`WebUI -> New Bind ID [${newElement}]`)
|
||||
console.log(`WebUI -> CMD -> New Bind ID [${newElement}]`)
|
||||
if(!this.#bindList.includes(newElement))
|
||||
this.#bindList.push(newElement)
|
||||
break
|
||||
@ -308,7 +326,7 @@ class WebuiBridge {
|
||||
)
|
||||
|
||||
if (this.#log)
|
||||
console.log(`WebUI -> JS [${scriptSanitize}]`)
|
||||
console.log(`WebUI -> CMD -> JS [${scriptSanitize}]`)
|
||||
|
||||
// Get callback result
|
||||
let FunReturn = 'undefined'
|
||||
@ -326,9 +344,9 @@ class WebuiBridge {
|
||||
|
||||
// Logging
|
||||
if (this.#log && !FunError)
|
||||
console.log(`WebUI -> JS -> Return [${FunReturn}]`)
|
||||
console.log(`WebUI -> CMD -> JS -> Return [${FunReturn}]`)
|
||||
if (this.#log && FunError)
|
||||
console.log(`WebUI -> JS -> Error [${FunReturn}]`)
|
||||
console.log(`WebUI -> CMD -> JS -> Error [${FunReturn}]`)
|
||||
|
||||
// Response Packet
|
||||
// 0: [Signature]
|
||||
@ -355,7 +373,7 @@ class WebuiBridge {
|
||||
if (!this.#log)
|
||||
globalThis.close()
|
||||
else {
|
||||
console.log(`WebUI -> Close`)
|
||||
console.log(`WebUI -> CMD -> Close`)
|
||||
this.#ws.close()
|
||||
}
|
||||
break
|
||||
@ -381,6 +399,9 @@ class WebuiBridge {
|
||||
// Get the raw data
|
||||
const rawDataIndex: number = 2 + functionName.length + 1
|
||||
const userRawData = buffer8.subarray(rawDataIndex);
|
||||
|
||||
if (this.#log)
|
||||
console.log(`WebUI -> CMD -> Send Raw ${buffer8.length} bytes to [${functionName}()]`)
|
||||
|
||||
// Call the user function, and pass the raw data
|
||||
if (typeof window[functionName] === 'function')
|
||||
@ -432,23 +453,32 @@ class WebuiBridge {
|
||||
0
|
||||
)
|
||||
this.#ws.send(packet.buffer)
|
||||
if (this.#log) console.log(`WebUI -> Click [${elem}]`)
|
||||
if (this.#log) console.log(`WebUI -> Send Click [${elem}]`)
|
||||
}
|
||||
}
|
||||
|
||||
#sendEventNavigation(url: string) {
|
||||
if (this.#hasEvents && this.#wsStatus && url !== '') {
|
||||
const packet = Uint8Array.of(
|
||||
// Response Packet
|
||||
// 0: [Signature]
|
||||
// 1: [CMD]
|
||||
// 2: [URL]
|
||||
this.#HEADER_SIGNATURE,
|
||||
this.#HEADER_SWITCH,
|
||||
...new TextEncoder().encode(url)
|
||||
)
|
||||
this.#ws.send(packet.buffer)
|
||||
if (this.#log) console.log(`WebUI -> Navigation [${url}]`)
|
||||
if(url !== '') {
|
||||
if(this.#hasEvents) {
|
||||
if (this.#log) console.log(`WebUI -> Send Navigation Event [${url}]`)
|
||||
if (this.#wsStatus && this.#hasEvents) {
|
||||
const packet = Uint8Array.of(
|
||||
// Packet
|
||||
// 0: [Signature]
|
||||
// 1: [CMD]
|
||||
// 2: [URL]
|
||||
this.#HEADER_SIGNATURE,
|
||||
this.#HEADER_NAVIGATION,
|
||||
...new TextEncoder().encode(url)
|
||||
)
|
||||
this.#ws.send(packet.buffer)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.#log) console.log(`WebUI -> Navigation To [${url}]`)
|
||||
this.#allowNavigation = true
|
||||
globalThis.location.replace(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,14 @@ void events(webui_event_t* e) {
|
||||
printf("Disconnected. \n");
|
||||
else if(e->event_type == WEBUI_EVENT_MOUSE_CLICK)
|
||||
printf("Click. \n");
|
||||
else if(e->event_type == WEBUI_EVENT_NAVIGATION)
|
||||
else if(e->event_type == WEBUI_EVENT_NAVIGATION) {
|
||||
printf("Starting navigation to: %s \n", (char *)e->data);
|
||||
|
||||
// Because we used `webui_bind(MyWindow, "", events);`
|
||||
// then all `href` link clicks will be blocked by WebUI, so
|
||||
// we need to use `webui_navigate()` to control the navigation
|
||||
webui_navigate(e->window, (char *)e->data);
|
||||
}
|
||||
}
|
||||
|
||||
void switch_to_second_page(webui_event_t* e) {
|
||||
|
@ -427,6 +427,16 @@ WEBUI_EXPORT void webui_set_profile(size_t window, const char* name, const char*
|
||||
*/
|
||||
WEBUI_EXPORT const char* webui_get_url(size_t window);
|
||||
|
||||
/**
|
||||
* @brief Navigate to a specific URL
|
||||
*
|
||||
* @param window The window number
|
||||
* @param url Full HTTP URL
|
||||
*
|
||||
* @example webui_navigate(myWindow, "http://domain.com");
|
||||
*/
|
||||
WEBUI_EXPORT void webui_navigate(size_t window, const char* url);
|
||||
|
||||
// -- JavaScript ----------------------
|
||||
|
||||
// Run JavaScript without waiting for the response.
|
||||
|
47
src/webui.c
47
src/webui.c
@ -24,7 +24,7 @@
|
||||
#define WEBUI_HEADER_JS 0xFE // JavaScript result in frontend
|
||||
#define WEBUI_HEADER_JS_QUICK 0xFD // JavaScript result in frontend
|
||||
#define WEBUI_HEADER_CLICK 0xFC // Click event
|
||||
#define WEBUI_HEADER_SWITCH 0xFB // Frontend refresh
|
||||
#define WEBUI_HEADER_NAVIGATION 0xFB // Frontend navigation
|
||||
#define WEBUI_HEADER_CLOSE 0xFA // Close window
|
||||
#define WEBUI_HEADER_CALL_FUNC 0xF9 // Backend function call
|
||||
#define WEBUI_HEADER_SEND_RAW 0xF8 // Send raw binary data to the UI
|
||||
@ -701,6 +701,39 @@ void webui_set_icon(size_t window, const char* icon, const char* icon_type) {
|
||||
win->icon_type = icon_type_cpy;
|
||||
}
|
||||
|
||||
void webui_navigate(size_t window, const char* url) {
|
||||
|
||||
#ifdef WEBUI_LOG
|
||||
printf("[User] webui_navigate([%zu], [%s])...\n", window, url);
|
||||
#endif
|
||||
|
||||
// Initialization
|
||||
_webui_init();
|
||||
|
||||
// Dereference
|
||||
if(_webui_core.exit_now || _webui_core.wins[window] == NULL) return;
|
||||
_webui_window_t* win = _webui_core.wins[window];
|
||||
|
||||
if(!win->connected)
|
||||
return;
|
||||
|
||||
// 0: [Signature]
|
||||
// 1: [CMD]
|
||||
// 2: [URL]
|
||||
|
||||
// Prepare packets
|
||||
size_t packet_len = 2 + _webui_strlen(url); // [header][url]
|
||||
char* packet = (char*) _webui_malloc(packet_len);
|
||||
packet[0] = WEBUI_HEADER_SIGNATURE; // Signature
|
||||
packet[1] = WEBUI_HEADER_NAVIGATION; // CMD
|
||||
for(size_t i = 0; i < _webui_strlen(url); i++) // URL
|
||||
packet[i + 2] = url[i];
|
||||
|
||||
// Send the packet
|
||||
_webui_window_send(win, packet, packet_len);
|
||||
_webui_free_mem((void*)packet);
|
||||
}
|
||||
|
||||
bool webui_show(size_t window, const char* content) {
|
||||
|
||||
#ifdef WEBUI_LOG
|
||||
@ -4282,9 +4315,9 @@ static bool _webui_show(_webui_window_t* win, const char* content, size_t browse
|
||||
|
||||
if(
|
||||
strstr(content_cpy, "<html") ||
|
||||
strstr(content_cpy, "<!DOCTYPE html>") ||
|
||||
strstr(content_cpy, "<!doctype html>") ||
|
||||
strstr(content_cpy, "<!Doctype html>")
|
||||
strstr(content_cpy, "<!DOCTYPE") ||
|
||||
strstr(content_cpy, "<!doctype") ||
|
||||
strstr(content_cpy, "<!Doctype")
|
||||
) {
|
||||
|
||||
// Embedded HTML
|
||||
@ -4398,7 +4431,7 @@ static bool _webui_show_window(_webui_window_t* win, const char* content, bool i
|
||||
size_t packet_len = 2 + _webui_strlen(url); // [header][url]
|
||||
char* packet = (char*) _webui_malloc(packet_len);
|
||||
packet[0] = WEBUI_HEADER_SIGNATURE; // Signature
|
||||
packet[1] = WEBUI_HEADER_SWITCH; // CMD
|
||||
packet[1] = WEBUI_HEADER_NAVIGATION; // CMD
|
||||
for(size_t i = 0; i < _webui_strlen(win->url); i++) // URL
|
||||
packet[i + 2] = win->url[i];
|
||||
|
||||
@ -4646,7 +4679,7 @@ static void _webui_window_receive(_webui_window_t* win, const char* packet, size
|
||||
// Send ready signal to webui_script()
|
||||
_webui_core.run_done[run_id] = true;
|
||||
}
|
||||
else if((unsigned char) packet[1] == WEBUI_HEADER_SWITCH) {
|
||||
else if((unsigned char) packet[1] == WEBUI_HEADER_NAVIGATION) {
|
||||
|
||||
// Navigation Event
|
||||
|
||||
@ -4670,7 +4703,7 @@ static void _webui_window_receive(_webui_window_t* win, const char* packet, size
|
||||
}
|
||||
|
||||
#ifdef WEBUI_LOG
|
||||
printf("[Core]\t\t_webui_window_receive() -> WEBUI_HEADER_SWITCH \n");
|
||||
printf("[Core]\t\t_webui_window_receive() -> WEBUI_HEADER_NAVIGATION \n");
|
||||
printf("[Core]\t\t_webui_window_receive() -> URL size: %zu bytes \n", url_len);
|
||||
printf("[Core]\t\t_webui_window_receive() -> URL: [%s] \n", url);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user