element.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. use std::rc::Rc;
  2. use dioxus_core::ElementId;
  3. use dioxus_html::{
  4. geometry::{PixelsRect, PixelsSize, PixelsVector2D},
  5. MountedResult, RenderedElementBacking,
  6. };
  7. use crate::{desktop_context::DesktopContext, query::QueryEngine, WeakDesktopContext};
  8. #[derive(Clone)]
  9. /// A mounted element passed to onmounted events
  10. pub struct DesktopElement {
  11. id: ElementId,
  12. webview: WeakDesktopContext,
  13. query: QueryEngine,
  14. }
  15. impl DesktopElement {
  16. pub(crate) fn new(id: ElementId, webview: DesktopContext, query: QueryEngine) -> Self {
  17. let webview = Rc::downgrade(&webview);
  18. Self { id, webview, query }
  19. }
  20. }
  21. macro_rules! scripted_getter {
  22. ($meth_name:ident, $script:literal, $output_type:path) => {
  23. fn $meth_name(
  24. &self,
  25. ) -> std::pin::Pin<
  26. Box<dyn futures_util::Future<Output = dioxus_html::MountedResult<$output_type>>>,
  27. > {
  28. let script = format!($script, id = self.id.0);
  29. let webview = self
  30. .webview
  31. .upgrade()
  32. .expect("Webview should be alive if the element is being queried");
  33. let fut = self
  34. .query
  35. .new_query::<Option<$output_type>>(&script, webview)
  36. .resolve();
  37. Box::pin(async move {
  38. match fut.await {
  39. Ok(Some(res)) => Ok(res),
  40. Ok(None) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
  41. Box::new(DesktopQueryError::FailedToQuery),
  42. )),
  43. Err(err) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
  44. Box::new(err),
  45. )),
  46. }
  47. })
  48. }
  49. };
  50. }
  51. impl RenderedElementBacking for DesktopElement {
  52. fn as_any(&self) -> &dyn std::any::Any {
  53. self
  54. }
  55. scripted_getter!(
  56. get_scroll_offset,
  57. "return [window.interpreter.getScrollLeft({id}), window.interpreter.getScrollTop({id})]",
  58. PixelsVector2D
  59. );
  60. scripted_getter!(
  61. get_scroll_size,
  62. "return [window.interpreter.getScrollWidth({id}), window.interpreter.getScrollHeight({id})]",
  63. PixelsSize
  64. );
  65. scripted_getter!(
  66. get_client_rect,
  67. "return window.interpreter.getClientRect({id});",
  68. PixelsRect
  69. );
  70. fn scroll_to(
  71. &self,
  72. behavior: dioxus_html::ScrollBehavior,
  73. ) -> std::pin::Pin<Box<dyn futures_util::Future<Output = dioxus_html::MountedResult<()>>>> {
  74. let script = format!(
  75. "return window.interpreter.scrollTo({}, {});",
  76. self.id.0,
  77. serde_json::to_string(&behavior).expect("Failed to serialize ScrollBehavior")
  78. );
  79. let webview = self
  80. .webview
  81. .upgrade()
  82. .expect("Webview should be alive if the element is being queried");
  83. let fut = self.query.new_query::<bool>(&script, webview).resolve();
  84. Box::pin(async move {
  85. match fut.await {
  86. Ok(true) => Ok(()),
  87. Ok(false) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
  88. Box::new(DesktopQueryError::FailedToQuery),
  89. )),
  90. Err(err) => {
  91. MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
  92. }
  93. }
  94. })
  95. }
  96. fn set_focus(
  97. &self,
  98. focus: bool,
  99. ) -> std::pin::Pin<Box<dyn futures_util::Future<Output = dioxus_html::MountedResult<()>>>> {
  100. let script = format!(
  101. "return window.interpreter.setFocus({}, {});",
  102. self.id.0, focus
  103. );
  104. let webview = self
  105. .webview
  106. .upgrade()
  107. .expect("Webview should be alive if the element is being queried");
  108. let fut = self.query.new_query::<bool>(&script, webview).resolve();
  109. Box::pin(async move {
  110. match fut.await {
  111. Ok(true) => Ok(()),
  112. Ok(false) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
  113. Box::new(DesktopQueryError::FailedToQuery),
  114. )),
  115. Err(err) => {
  116. MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
  117. }
  118. }
  119. })
  120. }
  121. }
  122. #[derive(Debug)]
  123. enum DesktopQueryError {
  124. FailedToQuery,
  125. }
  126. impl std::fmt::Display for DesktopQueryError {
  127. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  128. match self {
  129. DesktopQueryError::FailedToQuery => write!(f, "Failed to query the element"),
  130. }
  131. }
  132. }
  133. impl std::error::Error for DesktopQueryError {}