///|
pub struct EventListener {
id : String
name : String
target : EventTarget
once : Bool
} derive(Debug, Eq)
///|
pub struct EventDelivery {
listener_id : String
target : EventTarget
event : Event
} derive(Debug, Eq)
///|
pub struct EventBus {
mut next_listener_sequence : Int
listeners : Map[String, EventListener]
order : Array[String]
} derive(Debug, Eq)
///|
pub fn EventTarget::kind(self : EventTarget) -> String {
match self {
AppTarget => "app"
WindowTarget(_) => "window"
WebviewTarget(_) => "webview"
}
}
///|
pub fn EventTarget::label(self : EventTarget) -> String? {
match self {
AppTarget => None
WindowTarget(label) | WebviewTarget(label) => Some(label)
}
}
///|
pub fn EventTarget::validate(self : EventTarget) -> Array[String] {
let problems : Array[String] = []
match self {
AppTarget => ()
WindowTarget(label) =>
if label == "" {
problems.push("event target window label is required")
}
WebviewTarget(label) =>
if label == "" {
problems.push("event target webview label is required")
}
}
problems
}
///|
pub fn EventListener::id(self : EventListener) -> String {
self.id
}
///|
pub fn EventListener::name(self : EventListener) -> String {
self.name
}
///|
pub fn EventListener::target(self : EventListener) -> EventTarget {
self.target
}
///|
pub fn EventListener::once(self : EventListener) -> Bool {
self.once
}
///|
pub fn EventListener::to_json(self : EventListener) -> String {
[
"{",
"\"id\":\{self.id.json_string()},",
"\"name\":\{self.name.json_string()},",
"\"target\":\{self.target.to_json()},",
"\"once\":\{self.once.json_bool()}",
"}",
].join("")
}
///|
pub fn EventDelivery::listener_id(self : EventDelivery) -> String {
self.listener_id
}
///|
pub fn EventDelivery::target(self : EventDelivery) -> EventTarget {
self.target
}
///|
pub fn EventDelivery::event(self : EventDelivery) -> Event {
self.event
}
///|
pub fn EventDelivery::to_json(self : EventDelivery) -> String {
[
"{",
"\"listenerId\":\{self.listener_id.json_string()},",
"\"target\":\{self.target.to_json()},",
"\"event\":\{self.event.to_json()}",
"}",
].join("")
}
///|
pub fn EventBus::new() -> EventBus {
{ next_listener_sequence: 1, listeners: {}, order: [] }
}
///|
pub fn EventBus::listen(
self : EventBus,
name : String,
target? : EventTarget = AppTarget,
once? : Bool = false,
) -> Result[EventListener, Array[String]] {
let problems = event_listener_problems(name, target)
if !problems.is_empty() {
return Err(problems)
}
let sequence = self.next_listener_sequence
self.next_listener_sequence += 1
let id = "listener-\{sequence}"
let listener = { id, name, target, once }
self.listeners[id] = listener
self.order.push(id)
Ok(listener)
}
///|
pub fn EventBus::once(
self : EventBus,
name : String,
target? : EventTarget = AppTarget,
) -> Result[EventListener, Array[String]] {
self.listen(name, target~, once=true)
}
///|
pub fn EventBus::listener(self : EventBus, id : String) -> EventListener? {
self.listeners.get(id)
}
///|
pub fn EventBus::listeners(self : EventBus) -> Array[EventListener] {
let listeners : Array[EventListener] = []
for id in self.order {
match self.listeners.get(id) {
Some(listener) => listeners.push(listener)
None => ()
}
}
listeners
}
///|
pub fn EventBus::listener_count(self : EventBus) -> Int {
self.listeners.length()
}
///|
pub fn EventBus::listeners_for(
self : EventBus,
name : String,
target? : EventTarget = AppTarget,
) -> Array[EventListener] {
self
.listeners()
.filter(fn(listener) {
listener.name() == name && event_target_accepts(listener.target(), target)
})
}
///|
pub fn EventBus::emit(
self : EventBus,
event : Event,
target? : EventTarget = AppTarget,
) -> Result[Array[EventDelivery], Array[String]] {
let problems = event.validate()
for problem in target.validate() {
problems.push(problem)
}
if !problems.is_empty() {
return Err(problems)
}
let deliveries : Array[EventDelivery] = []
let once_ids : Array[String] = []
for listener in self.listeners() {
if listener.name() == event.name() &&
event_target_accepts(listener.target(), target) {
deliveries.push({ listener_id: listener.id(), target, event })
if listener.once() {
once_ids.push(listener.id())
}
}
}
for id in once_ids {
ignore(self.unlisten(id))
}
Ok(deliveries)
}
///|
pub fn EventBus::unlisten(
self : EventBus,
id : String,
) -> Result[EventListener, String] {
match self.listeners.get(id) {
Some(listener) => {
self.listeners.remove(id)
self.remove_ordered_listener(id)
Ok(listener)
}
None => Err("event listener not found: \{id}")
}
}
///|
pub fn EventBus::remove_target(
self : EventBus,
target : EventTarget,
) -> Array[EventListener] {
let removed : Array[EventListener] = []
for listener in self.listeners() {
if listener.target() == target {
match self.unlisten(listener.id()) {
Ok(removed_listener) => removed.push(removed_listener)
Err(_) => ()
}
}
}
removed
}
///|
pub fn EventBus::clear(self : EventBus) -> Array[EventListener] {
let listeners = self.listeners()
self.listeners.clear()
self.order.clear()
listeners
}
///|
pub fn EventBus::to_json(self : EventBus) -> String {
[
"{",
"\"nextListenerSequence\":\{self.next_listener_sequence},",
"\"listeners\":[\{self.listeners().map(fn(listener) { listener.to_json() }).join(",")}]",
"}",
].join("")
}
///|
fn event_listener_problems(
name : String,
target : EventTarget,
) -> Array[String] {
let problems = Event::new(name).validate()
for problem in target.validate() {
problems.push(problem)
}
problems
}
///|
fn event_target_accepts(
listener_target : EventTarget,
emit_target : EventTarget,
) -> Bool {
emit_target is AppTarget ||
listener_target is AppTarget ||
listener_target == emit_target
}
///|
fn EventBus::remove_ordered_listener(self : EventBus, id : String) -> Unit {
match self.order.search(id) {
Some(index) => ignore(self.order.remove(index))
None => ()
}
}