triggersOutsideAny function
A stream of click, mouseup or focus events of any node none of whose parents pass the check inside function.
Implementation
Stream<Event> triggersOutsideAny(Predicate<Node> checkNodeInside) {
StreamController<Event>? controller;
StreamSubscription<MouseEvent>? clickListener;
StreamSubscription<MouseEvent>? mouseDownListener;
StreamSubscription<MouseEvent>? mouseUpListener;
EventListener? listener;
controller = StreamController.broadcast(
sync: true,
onListen: () {
Event? lastEvent;
Event? lastDownEvent;
listener = (Event e) {
lastEvent = e;
var node = e.target as Node?;
while (node != null) {
if (checkNodeInside(node)) {
return;
} else {
node = node.parent;
}
}
controller!.add(e);
};
mouseDownListener = document.onMouseDown.listen((MouseEvent e) {
lastDownEvent = e;
});
mouseUpListener = document.onMouseUp.listen((MouseEvent e) {
if (lastDownEvent == null || e.target == lastDownEvent!.target) {
listener!(e);
}
lastEvent = e;
});
clickListener = document.onClick.listen((MouseEvent e) {
if (lastEvent?.type == 'mouseup' && e.target == lastEvent?.target) {
return;
}
if (lastDownEvent == null || e.target == lastDownEvent!.target) {
listener!(e);
}
lastDownEvent = null;
});
document.addEventListener('focus', listener!, true);
document.addEventListener('touchend', listener!);
},
onCancel: () {
clickListener?.cancel();
clickListener = null;
mouseDownListener?.cancel();
mouseDownListener = null;
mouseUpListener?.cancel();
mouseUpListener = null;
document.removeEventListener('focus', listener!, true);
document.removeEventListener('touchend', listener!);
});
return controller!.stream;
}