-
-
Save lwhorton/6ae745eca14a02796fa511479bfb3907 to your computer and use it in GitHub Desktop.
Ignore events that I don't want to see
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn prevent-events | |
"Take heed, young traveler, for here be dragons. | |
Occasionally we have a need on a global level to prevent events from | |
triggering handlers through the system. For example, when a user is filling | |
out a multi-page form, we want to prevent them from accidentally or | |
intentionally clicking on a top-level navigation button, which would cause | |
them to lose all their progress on said form. Actually, we don't *really* | |
wan't to *prevent* events, but we do want some mechanism for intercepting them | |
and then decide what to do from there. In the case of the form example, we | |
probably want to spit out a modal that warns the user their progress is about | |
to be lost. | |
Such a system should not be a giant global handler where we have to maintain a | |
big list of events from disparate features. We should be able to determine, | |
on a per-feature level, which events we allow. All events not specifically | |
allowed to pass through this feature will trigger another event where we will | |
determine what to do at the feature level. | |
In short, when a feature requiring prevent-events is initialized, it must | |
register with 1) a unique key, 2) a set of allowed events 3) an event to | |
dispatch when we detect an event *not* belong to the set of allowed events. | |
When a feature is done preventing events, it must 1) unregister with the same | |
unique key 2) decide whether or not to allow the most recent event which | |
triggered the :on-any-other-event to pass or to be gobbbled up after | |
unregistering. | |
{:register :unique-id | |
:allow-these-events #{:a :b ...} | |
:on-any-other-event [:handle-interruption-event]} | |
{:unregister :unique-id | |
:allow-last-event false} | |
" | |
[] | |
#_(atom {:register :unique-id | |
:allow-these-events #{:event-a :event-b} | |
:on-any-other-event [:single-event] | |
:intercepted (or :single-event [:array :of :events])}) | |
(let [registered (atom nil) | |
allowed-event? (fn [[evt & rst]] (contains? (:allow-these-events @registered) evt))] | |
(->interceptor | |
:id :prevent-events | |
:before (fn [ctx] | |
;; only prevent events if we have some preventer registered | |
(if-not @registered | |
ctx | |
(let [evt (get-in ctx [:coeffects :event])] | |
(if (allowed-event? evt) | |
ctx | |
;; when an event is not allowed, store it as the most | |
;; recently intercepted event, but also strip the | |
;; processing queue to prevent that event handler from | |
;; being invoked entirely ... and instead queue up the | |
;; on-any-other-event invocation for the next tick | |
(do | |
(swap! registered intercept evt) | |
(-> ctx | |
(update :queue (fn [queue] | |
(into #queue [] | |
(remove | |
(fn [intc] (contains? #{:fx-handler :db-handler} (:id intc))) | |
queue)))) | |
(update :effects assoc :dispatch (:on-any-other-event @registered)))))))) | |
:after (fn [ctx] | |
(let [{fx :effects} ctx | |
dsl (:prevent-events fx) | |
reg (:register dsl) | |
unreg (:unregister dsl)] | |
;; for all events, check to see if we're trying to register or | |
;; unregister a prevent-events | |
(cond | |
;; registering is easy - just store the fx | |
(some? reg) (do (swap! registered register dsl) ctx) | |
;; when unregistering, assuming that :allow-last-event is | |
;; true, dispatch the last intercepted event on the next | |
;; tick | |
(some? unreg) (let [ctx (if (:allow-last-event dsl true) | |
(assoc-in ctx [:effects :dispatch] (:intercepted @registered)) | |
ctx)] | |
(reset! registered nil) | |
ctx) | |
;; if we're not trying to reg/unreg, we have nothing to do | |
:else ctx)))))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment