Generalize Query system for use in use_eval and node querys
This commit is contained in:
1 parent
7636c046fa
commit
fa9f0d0f6c
8 files changed
+186
-282
No files matched your search
@@ -3,9 +3,9 @@ use std::rc::Rc;
|
||||
use std::rc::Weak;
|
||||
|
||||
use crate::create_new_window;
|
||||
use crate::element::QueryEngine;
|
||||
use crate::eval::EvalResult;
|
||||
use crate::events::IpcMessage;
|
||||
use crate::query::QueryEngine;
|
||||
use crate::shortcut::IntoKeyCode;
|
||||
use crate::shortcut::IntoModifersState;
|
||||
use crate::shortcut::ShortcutId;
|
||||
@@ -17,7 +17,6 @@ use dioxus_core::ScopeState;
|
||||
use dioxus_core::VirtualDom;
|
||||
#[cfg(all(feature = "hot-reload", debug_assertions))]
|
||||
use dioxus_hot_reload::HotReloadMsg;
|
||||
use serde_json::Value;
|
||||
use slab::Slab;
|
||||
use wry::application::event::Event;
|
||||
use wry::application::event_loop::EventLoopProxy;
|
||||
@@ -60,10 +59,7 @@ pub struct DesktopContext {
|
||||
/// The proxy to the event loop
|
||||
pub proxy: ProxyType,
|
||||
|
||||
/// The receiver for eval results since eval is async
|
||||
pub(super) eval: tokio::sync::broadcast::Sender<Value>,
|
||||
|
||||
/// The receiver for queries about elements
|
||||
/// The receiver for queries about the current window
|
||||
pub(super) query: QueryEngine,
|
||||
|
||||
pub(super) pending_windows: WebviewQueue,
|
||||
@@ -100,7 +96,6 @@ impl DesktopContext {
|
||||
webview,
|
||||
proxy,
|
||||
event_loop,
|
||||
eval: tokio::sync::broadcast::channel(8).0,
|
||||
query: Default::default(),
|
||||
pending_windows: webviews,
|
||||
event_handlers,
|
||||
@@ -215,28 +210,10 @@ impl DesktopContext {
|
||||
|
||||
/// Evaluate a javascript expression
|
||||
pub fn eval(&self, code: &str) -> EvalResult {
|
||||
// Embed the return of the eval in a function so we can send it back to the main thread
|
||||
let script = format!(
|
||||
r#"
|
||||
window.ipc.postMessage(
|
||||
JSON.stringify({{
|
||||
"method":"eval_result",
|
||||
"params": (
|
||||
function(){{
|
||||
{code}
|
||||
}}
|
||||
)()
|
||||
}})
|
||||
);
|
||||
"#
|
||||
);
|
||||
// the query id lets us keep track of the eval result and send it back to the main thread
|
||||
let query = self.query.new_query(code, &self.webview);
|
||||
|
||||
if let Err(e) = self.webview.evaluate_script(&script) {
|
||||
// send an error to the eval receiver
|
||||
log::warn!("Eval script error: {e}");
|
||||
}
|
||||
|
||||
EvalResult::new(self.eval.clone())
|
||||
EvalResult::new(query)
|
||||
}
|
||||
|
||||
/// Create a wry event handler that listens for wry events.
|
||||
|
||||
+41
-124
@@ -1,13 +1,11 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::rc::Rc;
|
||||
|
||||
use dioxus_core::ElementId;
|
||||
use dioxus_html::{
|
||||
MountedResult, MountedReturn, MountedReturnData, NodeUpdate, NodeUpdateData,
|
||||
RenderedElementBacking,
|
||||
};
|
||||
use slab::Slab;
|
||||
use dioxus_html::{geometry::euclid::Rect, MountedResult, RenderedElementBacking};
|
||||
use wry::webview::WebView;
|
||||
|
||||
use crate::query::QueryEngine;
|
||||
|
||||
/// A mounted element passed to onmounted events
|
||||
pub struct DesktopElement {
|
||||
id: ElementId,
|
||||
@@ -19,16 +17,6 @@ impl DesktopElement {
|
||||
pub(crate) fn new(id: ElementId, webview: Rc<WebView>, query: QueryEngine) -> Self {
|
||||
Self { id, webview, query }
|
||||
}
|
||||
|
||||
/// Get the id of the element
|
||||
pub fn id(&self) -> ElementId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Get the webview the element is mounted in
|
||||
pub fn webview(&self) -> &Rc<WebView> {
|
||||
&self.webview
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderedElementBacking for DesktopElement {
|
||||
@@ -45,19 +33,21 @@ impl RenderedElementBacking for DesktopElement {
|
||||
>,
|
||||
>,
|
||||
> {
|
||||
let script = format!("return window.interpreter.GetClientRect({});", self.id.0);
|
||||
|
||||
let fut = self
|
||||
.query
|
||||
.new_query(self.id, NodeUpdateData::GetClientRect {}, &self.webview)
|
||||
.new_query::<Option<Rect<f64, f64>>>(&script, &self.webview)
|
||||
.resolve();
|
||||
Box::pin(async move {
|
||||
match fut.await {
|
||||
Some(MountedReturnData::GetClientRect(rect)) => Ok(rect),
|
||||
Some(_) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||
Box::new(DesktopQueryError::MismatchedReturn),
|
||||
Ok(Some(rect)) => Ok(rect),
|
||||
Ok(None) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||
Box::new(DesktopQueryError::FailedToQuery),
|
||||
)),
|
||||
None => MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(
|
||||
DesktopQueryError::FailedToQuery,
|
||||
))),
|
||||
Err(err) => {
|
||||
MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -66,23 +56,25 @@ impl RenderedElementBacking for DesktopElement {
|
||||
&self,
|
||||
behavior: dioxus_html::ScrollBehavior,
|
||||
) -> std::pin::Pin<Box<dyn futures_util::Future<Output = dioxus_html::MountedResult<()>>>> {
|
||||
let script = format!(
|
||||
"return window.interpreter.ScrollTo({}, {});",
|
||||
self.id.0,
|
||||
serde_json::to_string(&behavior).expect("Failed to serialize ScrollBehavior")
|
||||
);
|
||||
|
||||
let fut = self
|
||||
.query
|
||||
.new_query(
|
||||
self.id,
|
||||
NodeUpdateData::ScrollTo { behavior },
|
||||
&self.webview,
|
||||
)
|
||||
.new_query::<bool>(&script, &self.webview)
|
||||
.resolve();
|
||||
Box::pin(async move {
|
||||
match fut.await {
|
||||
Some(MountedReturnData::ScrollTo(())) => Ok(()),
|
||||
Some(_) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||
Box::new(DesktopQueryError::MismatchedReturn),
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||
Box::new(DesktopQueryError::FailedToQuery),
|
||||
)),
|
||||
None => MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(
|
||||
DesktopQueryError::FailedToQuery,
|
||||
))),
|
||||
Err(err) => {
|
||||
MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -91,116 +83,41 @@ impl RenderedElementBacking for DesktopElement {
|
||||
&self,
|
||||
focus: bool,
|
||||
) -> std::pin::Pin<Box<dyn futures_util::Future<Output = dioxus_html::MountedResult<()>>>> {
|
||||
let script = format!(
|
||||
"return window.interpreter.SetFocus({}, {});",
|
||||
self.id.0, focus
|
||||
);
|
||||
|
||||
println!("script: {}", script);
|
||||
let fut = self
|
||||
.query
|
||||
.new_query(self.id, NodeUpdateData::SetFocus { focus }, &self.webview)
|
||||
.new_query::<bool>(&script, &self.webview)
|
||||
.resolve();
|
||||
println!("fut");
|
||||
|
||||
Box::pin(async move {
|
||||
match fut.await {
|
||||
Some(MountedReturnData::SetFocus(())) => Ok(()),
|
||||
Some(_) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||
Box::new(DesktopQueryError::MismatchedReturn),
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||
Box::new(DesktopQueryError::FailedToQuery),
|
||||
)),
|
||||
None => MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(
|
||||
DesktopQueryError::FailedToQuery,
|
||||
))),
|
||||
Err(err) => {
|
||||
MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct SharedSlab {
|
||||
slab: Rc<RefCell<Slab<()>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct QueryEngine {
|
||||
sender: Rc<tokio::sync::broadcast::Sender<MountedReturn>>,
|
||||
active_requests: SharedSlab,
|
||||
}
|
||||
|
||||
impl Default for QueryEngine {
|
||||
fn default() -> Self {
|
||||
let (sender, _) = tokio::sync::broadcast::channel(8);
|
||||
Self {
|
||||
sender: Rc::new(sender),
|
||||
active_requests: SharedSlab::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryEngine {
|
||||
fn new_query(&self, id: ElementId, update: NodeUpdateData, webview: &WebView) -> Query {
|
||||
let request_id = self.active_requests.slab.borrow_mut().insert(());
|
||||
|
||||
let update = NodeUpdate {
|
||||
id: id.0 as u32,
|
||||
request_id,
|
||||
data: update,
|
||||
};
|
||||
|
||||
// start the query
|
||||
webview
|
||||
.evaluate_script(&format!(
|
||||
"window.interpreter.handleNodeUpdate({})",
|
||||
serde_json::to_string(&update).unwrap()
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
Query {
|
||||
slab: self.active_requests.clone(),
|
||||
id: request_id,
|
||||
reciever: self.sender.subscribe(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, data: MountedReturn) {
|
||||
self.sender.send(data).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
struct Query {
|
||||
slab: SharedSlab,
|
||||
id: usize,
|
||||
reciever: tokio::sync::broadcast::Receiver<MountedReturn>,
|
||||
}
|
||||
|
||||
impl Query {
|
||||
async fn resolve(mut self) -> Option<MountedReturnData> {
|
||||
let result = loop {
|
||||
match self.reciever.recv().await {
|
||||
Ok(result) => {
|
||||
if result.id == self.id {
|
||||
break result.data;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
break None;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Remove the query from the slab
|
||||
self.slab.slab.borrow_mut().remove(self.id);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum DesktopQueryError {
|
||||
FailedToQuery,
|
||||
MismatchedReturn,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DesktopQueryError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
DesktopQueryError::FailedToQuery => write!(f, "Failed to query the element"),
|
||||
DesktopQueryError::MismatchedReturn => {
|
||||
write!(f, "The return type did not match the query")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,32 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::query::Query;
|
||||
use crate::query::QueryError;
|
||||
use crate::use_window;
|
||||
use dioxus_core::ScopeState;
|
||||
use serde::de::Error;
|
||||
use std::future::Future;
|
||||
use std::future::IntoFuture;
|
||||
use std::pin::Pin;
|
||||
|
||||
/// A future that resolves to the result of a JavaScript evaluation.
|
||||
pub struct EvalResult {
|
||||
pub(crate) broadcast: tokio::sync::broadcast::Sender<serde_json::Value>,
|
||||
pub(crate) query: Query<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl EvalResult {
|
||||
pub(crate) fn new(sender: tokio::sync::broadcast::Sender<serde_json::Value>) -> Self {
|
||||
Self { broadcast: sender }
|
||||
pub(crate) fn new(query: Query<serde_json::Value>) -> Self {
|
||||
Self { query }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFuture for EvalResult {
|
||||
type Output = Result<serde_json::Value, serde_json::Error>;
|
||||
type Output = Result<serde_json::Value, QueryError>;
|
||||
|
||||
type IntoFuture = Pin<Box<dyn Future<Output = Result<serde_json::Value, serde_json::Error>>>>;
|
||||
type IntoFuture = Pin<Box<dyn Future<Output = Result<serde_json::Value, QueryError>>>>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
Box::pin(async move {
|
||||
let mut reciever = self.broadcast.subscribe();
|
||||
match reciever.recv().await {
|
||||
Ok(result) => Ok(result),
|
||||
Err(_) => Err(serde_json::Error::custom("No result returned")),
|
||||
}
|
||||
}) as Pin<Box<dyn Future<Output = Result<serde_json::Value, serde_json::Error>>>>
|
||||
Box::pin(self.query.resolve())
|
||||
as Pin<Box<dyn Future<Output = Result<serde_json::Value, QueryError>>>>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-37
@@ -10,17 +10,19 @@ mod escape;
|
||||
mod eval;
|
||||
mod events;
|
||||
mod protocol;
|
||||
mod query;
|
||||
mod shortcut;
|
||||
mod waker;
|
||||
mod webview;
|
||||
|
||||
use crate::query::QueryResult;
|
||||
pub use cfg::Config;
|
||||
pub use desktop_context::{
|
||||
use_window, use_wry_event_handler, DesktopContext, WryEventHandler, WryEventHandlerId,
|
||||
};
|
||||
use desktop_context::{EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers};
|
||||
use dioxus_core::*;
|
||||
use dioxus_html::{HtmlEvent, MountedData, MountedReturn};
|
||||
use dioxus_html::{HtmlEvent, MountedData};
|
||||
use element::DesktopElement;
|
||||
pub use eval::{use_eval, EvalResult};
|
||||
use futures_util::{pin_mut, FutureExt};
|
||||
@@ -259,30 +261,21 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
|
||||
send_edits(view.dom.render_immediate(), &view.webview);
|
||||
}
|
||||
|
||||
EventData::Ipc(msg) if msg.method() == "node_update" => {
|
||||
// When the webview sends a query, we need to send it to the query manager which handles dispatching the data to the correct pending query
|
||||
EventData::Ipc(msg) if msg.method() == "query" => {
|
||||
let params = msg.params();
|
||||
println!("node_update: {:?}", params);
|
||||
|
||||
// check for a mounted event
|
||||
let evt = match serde_json::from_value::<MountedReturn>(params) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
println!("node_update: {:?}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Ok(result) = dbg!(serde_json::from_value::<QueryResult>(params)) {
|
||||
let view = webviews.get(&event.1).unwrap();
|
||||
let query = view
|
||||
.dom
|
||||
.base_scope()
|
||||
.consume_context::<DesktopContext>()
|
||||
.unwrap()
|
||||
.query;
|
||||
|
||||
let view = webviews.get(&event.1).unwrap();
|
||||
let query = view
|
||||
.dom
|
||||
.base_scope()
|
||||
.consume_context::<DesktopContext>()
|
||||
.unwrap()
|
||||
.query;
|
||||
|
||||
println!("node_update: {:?}", evt);
|
||||
|
||||
query.send(evt);
|
||||
query.send(result);
|
||||
}
|
||||
}
|
||||
|
||||
EventData::Ipc(msg) if msg.method() == "initialize" => {
|
||||
@@ -290,21 +283,6 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
|
||||
send_edits(view.dom.rebuild(), &view.webview);
|
||||
}
|
||||
|
||||
// When the webview chirps back with the result of the eval, we send it to the active receiver
|
||||
//
|
||||
// This currently doesn't perform any targeting to the callsite, so if you eval multiple times at once,
|
||||
// you might the wrong result. This should be fixed
|
||||
EventData::Ipc(msg) if msg.method() == "eval_result" => {
|
||||
webviews[&event.1]
|
||||
.dom
|
||||
.base_scope()
|
||||
.consume_context::<DesktopContext>()
|
||||
.unwrap()
|
||||
.eval
|
||||
.send(msg.params())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
EventData::Ipc(msg) if msg.method() == "browser_open" => {
|
||||
if let Some(temp) = msg.params().as_object() {
|
||||
if temp.contains_key("href") {
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::Value;
|
||||
use slab::Slab;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::broadcast::error::RecvError;
|
||||
use wry::webview::WebView;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct SharedSlab {
|
||||
slab: Rc<RefCell<Slab<()>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct QueryEngine {
|
||||
sender: Rc<tokio::sync::broadcast::Sender<QueryResult>>,
|
||||
active_requests: SharedSlab,
|
||||
}
|
||||
|
||||
impl Default for QueryEngine {
|
||||
fn default() -> Self {
|
||||
let (sender, _) = tokio::sync::broadcast::channel(8);
|
||||
Self {
|
||||
sender: Rc::new(sender),
|
||||
active_requests: SharedSlab::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryEngine {
|
||||
pub fn new_query<V: DeserializeOwned>(&self, script: &str, webview: &WebView) -> Query<V> {
|
||||
let request_id = self.active_requests.slab.borrow_mut().insert(());
|
||||
|
||||
// start the query
|
||||
// We embed the return of the eval in a function so we can send it back to the main thread
|
||||
if let Err(err) = webview.evaluate_script(&format!(
|
||||
r#"window.ipc.postMessage(
|
||||
JSON.stringify({{
|
||||
"method":"query",
|
||||
"params": {{
|
||||
"id": {request_id},
|
||||
"data": (function(){{{script}}})()
|
||||
}}
|
||||
}})
|
||||
);"#
|
||||
)) {
|
||||
log::warn!("Query error: {err}");
|
||||
}
|
||||
|
||||
Query {
|
||||
slab: self.active_requests.clone(),
|
||||
id: request_id,
|
||||
reciever: self.sender.subscribe(),
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, data: QueryResult) {
|
||||
let _ = self.sender.send(data);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Query<V: DeserializeOwned> {
|
||||
slab: SharedSlab,
|
||||
id: usize,
|
||||
reciever: tokio::sync::broadcast::Receiver<QueryResult>,
|
||||
phantom: std::marker::PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<V: DeserializeOwned> Query<V> {
|
||||
pub async fn resolve(mut self) -> Result<V, QueryError> {
|
||||
let result = loop {
|
||||
match self.reciever.recv().await {
|
||||
Ok(result) => {
|
||||
if result.id == self.id {
|
||||
break V::deserialize(result.data).map_err(QueryError::DeserializeError);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
break Err(QueryError::RecvError(err));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Remove the query from the slab
|
||||
self.slab.slab.borrow_mut().remove(self.id);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum QueryError {
|
||||
#[error("Error receiving query result: {0}")]
|
||||
RecvError(RecvError),
|
||||
#[error("Error deserializing query result: {0}")]
|
||||
DeserializeError(serde_json::Error),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub(crate) struct QueryResult {
|
||||
id: usize,
|
||||
data: Value,
|
||||
}
|
||||
@@ -79,13 +79,16 @@ impl MountedData {
|
||||
}
|
||||
|
||||
/// Scroll to make the element visible
|
||||
pub async fn scroll_to(&self, behavior: ScrollBehavior) -> MountedResult<()> {
|
||||
self.inner.scroll_to(behavior).await
|
||||
pub fn scroll_to(
|
||||
&self,
|
||||
behavior: ScrollBehavior,
|
||||
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
self.inner.scroll_to(behavior)
|
||||
}
|
||||
|
||||
/// Set the focus on the element
|
||||
pub async fn set_focus(&self, focus: bool) -> MountedResult<()> {
|
||||
self.inner.set_focus(focus).await
|
||||
pub fn set_focus(&self, focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
self.inner.set_focus(focus)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::{any::Any, rc::Rc};
|
||||
|
||||
use crate::events::*;
|
||||
use dioxus_core::ElementId;
|
||||
use euclid::Rect;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||
@@ -221,49 +220,3 @@ fn test_back_and_forth() {
|
||||
|
||||
assert_eq!(data, p);
|
||||
}
|
||||
|
||||
/// Message to update a node to support MountedData
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct NodeUpdate {
|
||||
/// The id of the node to update
|
||||
pub id: u32,
|
||||
/// The id of the request
|
||||
pub request_id: usize,
|
||||
/// The data to update the node with
|
||||
pub data: NodeUpdateData,
|
||||
}
|
||||
|
||||
/// Message to update a node to support MountedData
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
serde(tag = "type")
|
||||
)]
|
||||
pub enum NodeUpdateData {
|
||||
SetFocus { focus: bool },
|
||||
GetClientRect {},
|
||||
ScrollTo { behavior: ScrollBehavior },
|
||||
}
|
||||
|
||||
/// The result of a element query
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct MountedReturn {
|
||||
/// A unique id for the query
|
||||
pub id: usize,
|
||||
/// The result of the query
|
||||
pub data: Option<MountedReturnData>,
|
||||
}
|
||||
|
||||
/// The data of a element query
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
serde(tag = "type")
|
||||
)]
|
||||
pub enum MountedReturnData {
|
||||
SetFocus(()),
|
||||
GetClientRect(Rect<f64, f64>),
|
||||
ScrollTo(()),
|
||||
}
|
||||
@@ -227,51 +227,26 @@ class Interpreter {
|
||||
ScrollTo(id, behavior) {
|
||||
const node = this.nodes[id];
|
||||
if (!node) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
node.scrollIntoView({
|
||||
behavior: behavior
|
||||
});
|
||||
return {
|
||||
type: "ScrollTo",
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Set the focus on the element
|
||||
SetFocus(id, focus) {
|
||||
const node = this.nodes[id];
|
||||
if (!node) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (focus) {
|
||||
node.focus();
|
||||
} else {
|
||||
node.blur();
|
||||
}
|
||||
return {
|
||||
type: "SetFocus",
|
||||
};
|
||||
}
|
||||
|
||||
handleNodeUpdate(edit) {
|
||||
let data;
|
||||
switch (edit.data.type) {
|
||||
case "SetFocus":
|
||||
data = this.SetFocus(edit.id, edit.data.focus);
|
||||
break;
|
||||
case "ScrollTo":
|
||||
data = this.ScrollTo(edit.id, edit.data.behavior);
|
||||
break;
|
||||
case "GetClientRect":
|
||||
data = this.GetClientRect(edit.id);
|
||||
break;
|
||||
}
|
||||
window.ipc.postMessage(
|
||||
serializeIpcMessage("node_update", {
|
||||
id: edit.request_id,
|
||||
data: data
|
||||
})
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
handleEdits(edits) {
|
||||
|
||||
Reference in new issue
Block a user