element.rs 4.0 KB

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