mod.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. mod listener;
  5. pub(crate) mod plugin;
  6. use std::{convert::Infallible, str::FromStr};
  7. pub(crate) use listener::Listeners;
  8. use serde::{Deserialize, Serialize};
  9. /// Checks if an event name is valid.
  10. pub fn is_event_name_valid(event: &str) -> bool {
  11. event
  12. .chars()
  13. .all(|c| c.is_alphanumeric() || c == '-' || c == '/' || c == ':' || c == '_')
  14. }
  15. pub fn assert_event_name_is_valid(event: &str) {
  16. assert!(
  17. is_event_name_valid(event),
  18. "Event name must include only alphanumeric characters, `-`, `/`, `:` and `_`."
  19. );
  20. }
  21. /// Unique id of an event.
  22. pub type EventId = u32;
  23. /// Event Target
  24. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
  25. #[serde(tag = "kind")]
  26. #[non_exhaustive]
  27. pub enum EventTarget {
  28. /// Any and all event targets.
  29. Any,
  30. /// Any [`Window`](crate::Window), [`Webview`](crate::Webview) or [`WebviewWindow`](crate::WebviewWindow) that have this label.
  31. AnyLabel {
  32. /// Target label.
  33. label: String,
  34. },
  35. /// [`App`](crate::App) and [`AppHandle`](crate::AppHandle) targets.
  36. App,
  37. /// [`Window`](crate::Window) target.
  38. Window {
  39. /// window label.
  40. label: String,
  41. },
  42. /// [`Webview`](crate::Webview) target.
  43. Webview {
  44. /// webview label.
  45. label: String,
  46. },
  47. /// [`WebviewWindow`](crate::WebviewWindow) target.
  48. WebviewWindow {
  49. /// webview window label.
  50. label: String,
  51. },
  52. }
  53. impl EventTarget {
  54. /// [`Self::Any`] target.
  55. pub fn any() -> Self {
  56. Self::Any
  57. }
  58. /// [`Self::App`] target.
  59. pub fn app() -> Self {
  60. Self::App
  61. }
  62. /// [`Self::AnyLabel`] target.
  63. pub fn labeled(label: impl Into<String>) -> Self {
  64. Self::AnyLabel {
  65. label: label.into(),
  66. }
  67. }
  68. /// [`Self::Window`] target.
  69. pub fn window(label: impl Into<String>) -> Self {
  70. Self::Window {
  71. label: label.into(),
  72. }
  73. }
  74. /// [`Self::Webview`] target.
  75. pub fn webview(label: impl Into<String>) -> Self {
  76. Self::Webview {
  77. label: label.into(),
  78. }
  79. }
  80. /// [`Self::WebviewWindow`] target.
  81. pub fn webview_window(label: impl Into<String>) -> Self {
  82. Self::WebviewWindow {
  83. label: label.into(),
  84. }
  85. }
  86. }
  87. impl<T: AsRef<str>> From<T> for EventTarget {
  88. fn from(value: T) -> Self {
  89. Self::AnyLabel {
  90. label: value.as_ref().to_string(),
  91. }
  92. }
  93. }
  94. impl FromStr for EventTarget {
  95. type Err = Infallible;
  96. fn from_str(s: &str) -> Result<Self, Self::Err> {
  97. Ok(Self::AnyLabel {
  98. label: s.to_string(),
  99. })
  100. }
  101. }
  102. /// Serialized emit arguments.
  103. #[derive(Clone)]
  104. pub struct EmitArgs {
  105. /// Raw event name.
  106. pub event_name: String,
  107. /// Serialized event name.
  108. pub event: String,
  109. /// Serialized payload.
  110. pub payload: String,
  111. }
  112. impl EmitArgs {
  113. pub fn new<S: Serialize>(event: &str, payload: S) -> crate::Result<Self> {
  114. #[cfg(feature = "tracing")]
  115. let _span = tracing::debug_span!("window::emit::serialize").entered();
  116. Ok(EmitArgs {
  117. event_name: event.into(),
  118. event: serde_json::to_string(event)?,
  119. payload: serde_json::to_string(&payload)?,
  120. })
  121. }
  122. }
  123. /// An event that was emitted.
  124. #[derive(Debug, Clone)]
  125. pub struct Event {
  126. id: EventId,
  127. data: String,
  128. }
  129. impl Event {
  130. fn new(id: EventId, data: String) -> Self {
  131. Self { id, data }
  132. }
  133. /// The [`EventId`] of the handler that was triggered.
  134. pub fn id(&self) -> EventId {
  135. self.id
  136. }
  137. /// The event payload.
  138. pub fn payload(&self) -> &str {
  139. &self.data
  140. }
  141. }
  142. pub fn listen_js_script(
  143. listeners_object_name: &str,
  144. serialized_target: &str,
  145. event: &str,
  146. event_id: EventId,
  147. handler: &str,
  148. ) -> String {
  149. format!(
  150. "(function () {{
  151. if (window['{listeners_object_name}'] === void 0) {{
  152. Object.defineProperty(window, '{listeners_object_name}', {{ value: Object.create(null) }});
  153. }}
  154. if (window['{listeners_object_name}']['{event}'] === void 0) {{
  155. Object.defineProperty(window['{listeners_object_name}'], '{event}', {{ value: Object.create(null) }});
  156. }}
  157. const eventListeners = window['{listeners_object_name}']['{event}']
  158. const listener = {{
  159. target: {serialized_target},
  160. handler: {handler}
  161. }};
  162. Object.defineProperty(eventListeners, '{event_id}', {{ value: listener, configurable: true }});
  163. }})()
  164. ",
  165. )
  166. }
  167. pub fn emit_js_script(
  168. event_emit_function_name: &str,
  169. emit_args: &EmitArgs,
  170. serialized_ids: &str,
  171. ) -> crate::Result<String> {
  172. Ok(format!(
  173. "(function () {{ const fn = window['{}']; fn && fn({{event: {}, payload: {}}}, {ids}) }})()",
  174. event_emit_function_name,
  175. emit_args.event,
  176. emit_args.payload,
  177. ids = serialized_ids,
  178. ))
  179. }
  180. pub fn unlisten_js_script(
  181. listeners_object_name: &str,
  182. event_name: &str,
  183. event_id: EventId,
  184. ) -> String {
  185. format!(
  186. "(function () {{
  187. const listeners = (window['{listeners_object_name}'] || {{}})['{event_name}']
  188. if (listeners) {{
  189. delete window['{listeners_object_name}']['{event_name}'][{event_id}];
  190. }}
  191. }})()
  192. ",
  193. )
  194. }
  195. pub fn event_initialization_script(function: &str, listeners: &str) -> String {
  196. format!(
  197. "Object.defineProperty(window, '{function}', {{
  198. value: function (eventData, ids) {{
  199. const listeners = (window['{listeners}'] && window['{listeners}'][eventData.event]) || []
  200. for (const id of ids) {{
  201. const listener = listeners[id]
  202. if (listener && listener.handler) {{
  203. eventData.id = id
  204. listener.handler(eventData)
  205. }}
  206. }}
  207. }}
  208. }});
  209. "
  210. )
  211. }