mirror of
https://github.com/emilk/egui.git
synced 2026-06-27 23:13:13 -04:00
Add web location info to egui_web/epi (#1258)
This adds all parts of the web "location" (URL) to frame.info().web_info, included a HashMap of the query parameters, percent-decoded and ready to go. This lets you easily pass key-value pairs to your eframe web app.
This commit is contained in:
@@ -81,6 +81,77 @@ impl epi::backend::RepaintSignal for NeedRepaint {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fn web_location() -> epi::Location {
|
||||
let location = web_sys::window().unwrap().location();
|
||||
|
||||
let hash = percent_decode(&location.hash().unwrap_or_default());
|
||||
|
||||
let query = location
|
||||
.search()
|
||||
.unwrap_or_default()
|
||||
.strip_prefix('?')
|
||||
.map(percent_decode)
|
||||
.unwrap_or_default();
|
||||
|
||||
let query_map = parse_query_map(&query)
|
||||
.iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect();
|
||||
|
||||
epi::Location {
|
||||
url: percent_decode(&location.href().unwrap_or_default()),
|
||||
protocol: percent_decode(&location.protocol().unwrap_or_default()),
|
||||
host: percent_decode(&location.host().unwrap_or_default()),
|
||||
hostname: percent_decode(&location.hostname().unwrap_or_default()),
|
||||
port: percent_decode(&location.port().unwrap_or_default()),
|
||||
hash,
|
||||
query,
|
||||
query_map,
|
||||
origin: percent_decode(&location.origin().unwrap_or_default()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_query_map(query: &str) -> BTreeMap<&str, &str> {
|
||||
query
|
||||
.split('&')
|
||||
.filter_map(|pair| {
|
||||
if pair.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(if let Some((key, value)) = pair.split_once('=') {
|
||||
(key, value)
|
||||
} else {
|
||||
(pair, "")
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_query() {
|
||||
assert_eq!(parse_query_map(""), BTreeMap::default());
|
||||
assert_eq!(parse_query_map("foo"), BTreeMap::from_iter([("foo", "")]));
|
||||
assert_eq!(
|
||||
parse_query_map("foo=bar"),
|
||||
BTreeMap::from_iter([("foo", "bar")])
|
||||
);
|
||||
assert_eq!(
|
||||
parse_query_map("foo=bar&baz=42"),
|
||||
BTreeMap::from_iter([("foo", "bar"), ("baz", "42")])
|
||||
);
|
||||
assert_eq!(
|
||||
parse_query_map("foo&baz=42"),
|
||||
BTreeMap::from_iter([("foo", ""), ("baz", "42")])
|
||||
);
|
||||
assert_eq!(
|
||||
parse_query_map("foo&baz&&"),
|
||||
BTreeMap::from_iter([("foo", ""), ("baz", "")])
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub struct AppRunner {
|
||||
pub(crate) frame: epi::Frame,
|
||||
egui_ctx: egui::Context,
|
||||
@@ -108,7 +179,7 @@ impl AppRunner {
|
||||
info: epi::IntegrationInfo {
|
||||
name: painter.name(),
|
||||
web_info: Some(epi::WebInfo {
|
||||
web_location_hash: location_hash().unwrap_or_default(),
|
||||
location: web_location(),
|
||||
}),
|
||||
prefer_dark_mode,
|
||||
cpu_usage: None,
|
||||
|
||||
@@ -33,6 +33,7 @@ pub use web_sys;
|
||||
|
||||
pub use painter::Painter;
|
||||
use std::cell::Cell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::prelude::*;
|
||||
@@ -353,9 +354,23 @@ pub fn open_url(url: &str, new_tab: bool) -> Option<()> {
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// e.g. "#fragment" part of "www.example.com/index.html#fragment"
|
||||
pub fn location_hash() -> Option<String> {
|
||||
web_sys::window()?.location().hash().ok()
|
||||
/// e.g. "#fragment" part of "www.example.com/index.html#fragment",
|
||||
///
|
||||
/// Percent decoded
|
||||
pub fn location_hash() -> String {
|
||||
percent_decode(
|
||||
&web_sys::window()
|
||||
.unwrap()
|
||||
.location()
|
||||
.hash()
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn percent_decode(s: &str) -> String {
|
||||
percent_encoding::percent_decode_str(s)
|
||||
.decode_utf8_lossy()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Web sends all keys as strings, so it is up to us to figure out if it is
|
||||
@@ -661,7 +676,7 @@ fn install_document_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
||||
|
||||
// `epi::Frame::info(&self)` clones `epi::IntegrationInfo`, but we need to modify the original here
|
||||
if let Some(web_info) = &mut frame_lock.info.web_info {
|
||||
web_info.web_location_hash = location_hash().unwrap_or_default();
|
||||
web_info.location.hash = location_hash();
|
||||
}
|
||||
}) as Box<dyn FnMut()>);
|
||||
window.add_event_listener_with_callback("hashchange", closure.as_ref().unchecked_ref())?;
|
||||
|
||||
Reference in New Issue
Block a user