Replies: 1 comment
-
We ended up just keeping the basic Global bus. Fixtures all have access to the instance API, so they just emit/listen to it. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
(note this exists in HackMD but duplicating here to keep a this repo full)
Also see #344 afterwards for more things that were discovered and discussed after implementing the stuff below.
Challenges
We want to achieve a number of things that tend to conflict with each other.
A few ideas have been batted around, but have either pointed towards anarchy (e.g. global events with random things reacting in random order) or authoritarianism (e.g. specific functions on specifically named fixtures expecting to be called at a specific point in time).
Idea: Opening up the Event Architecture
Of the many ideas considered, a common issue that keeps appearing is that we have no idea what a 3rd party fixture will want to do. Building an internal system that handles all eventualities is pretty much impossible.
So the idea is to allow a site author to make their own rules, and have an out-of-the-box rule set for vanilla R4MP. We leave it up to the author to work out whatever special logic is required for their specific needs.
Everything is presented as a concept for now. Names, parameter orderings, etc, are always up for debate.
Also, for simplicity, the examples are done assuming certain design choices. Further down there are options that may change how the examples would be coded.
Event Name Party
Fixtures will have named events. The event names for our out-of-box fixture should be well documented in our docsite.
The event handler registrations will also have names. The out-of-box handlers for vanilla configuration will have nice and documented names. 3rd party handlers can be author defined, or system generated if not.
The main reason for introducing names on the handlers is that we will have out-of-box handlers existing at startup. The name makes it easy for someone to remove it, rather than having to derive a function memory address somehow. A secondary benefit is it allows someone debugging to easily see what handlers are lurking, and can allow for simple programmatic checks for handler existence.
The registration of the out-of-box handlers must be designed so they are added before a 3rd party can start manipulating event handlers.
Adding Event Handlers
The fixture base class will have a public function
.on(eventName, eventHandler, handlerName?)
to register an event handler.Non-existing event names or duplicate handler names will throw an error. Not providing the handler name will generate a name something like
<FixtureName>_<eventName>CustomHandler<AutoNumber>
.Removing Event Handlers
The fixture base class will have a public function
.off(eventName, handlerName)
to de-register an event handler.Non-existing event names or handler names will throw an error. Possible discussion: have it return a boolean indicating if it found and removed the event handler rather than an error bomb.
Inspecting Event Handlers
The fixture base class will have a public function
.activeHandlers(eventName)
that returns an array of the names of all handlers registered to the event.We can also consider a function like
.availableEvents()
that returns an array of all the event names fixture exposes.Examples
Example 1: Out of the Box: Legend Opens Grid
This would be part of our standard setup, so if the site author does not interfere, this code would be done as part of the startup.
Example 2: Extra Listener, Random
In this case, we want our grid to still open from the legend, but want a second graph fixture to open as well. The order in which the grid and chart fixture open may be random
Example 3: Extra Listener, Specific Control
Like Example 2, we have the chart opening with the grid. However now we take over the default event handlers. Note that while we have shared variable declarations to keep the sample uncluttered, in the real case this would be implemented across two different files (the core startup and the host page script).
Example 4: Inspection Party
A power flex. Assuming the setup of Example 2, a chart and grid, not connected. Imagine a custom fixture button exists to toggle if the chart should appear. The custom fixture exposes an event called
'chart-toggle-button-click'
Benefits
Downsides
Possible Enhancement - Disabling Events
A use case that might be useful to support is the concept of disabling an event handler. In Example 4, we add and remove the event handler to support a toggle button effect. Being able to disable or enable the event would be simpler.
We can imagine a suite of event management methods would be something like
add event hander
,remove event handler
,enable event handler
,disable event handler
. Alternately the enable and disable could be replaced with atoggle event
function that changes the enabled/disabled state.Further, adding this would merit a
.disabledEvents()
method that returns the names of all the disabled event handlers.Naming Fun Never Ends
Entertaining the abitlity to enable and disable events means our proposed functions
on()
andoff()
can be confusing. At a glance they could hint that they control the enable and disable instead of the add and remove.If we come to it, we can figure out ideal method names for the suite. Potential fun pairs:
on, off
,enable, disable
,add, remove
,listen, unlisten
. Some of these may want more explicit names. E.g.fixture.add()
isn't clear that it would effect event handlers, so perhapsfixture.addListner()
is more appropriate.Possible Enhancement - Bulk Registration
A way to register a batch of events could be a niceity for initialization blocks.
The following is a basic example. It doesn't allow for providing event names. Once the guts of this event framework are solidified this concept can be revisited and optimal parameter signatures can be proposed.
Possible Enhancement - Replace Handler
Another use case that may be good to support is the idea of replacing a handler. Of course this can be done with a remove then add.
The original spec for
on()
above indicates an error is thrown if an event handler name is used twice. We could consider changing this behavior to do a replace. This idea is a risky one, as it opens up unintentional overwrites. An optional booleanforce
parameter could be added to theon()
signature to help ensure the caller understands the consequences.A different approach is to make a dedicated
update()
function for event handlers. This gets rid of any unintentional consequences. But it also removes the ability to easily support the use case of "I don't care what the current event handler is, nor if it exists at all, I decree the handler to now be this new handler". That usecase would need an if-exists check first.If we decide to not have a replace mechanism and just use
off()
thenon()
, it would help if we chose the implementation ofoff()
that does not error if removing a non-existing handler and just returnsfalse
Event Bus of Madness
The above examples all act as if each fixture is handling its own event bus. The actual implementation is a bit more complex, and we have some options to consider.
Current Global Event Bus
We have a global event-bus and it can be accessed from the API instance:
Any code can use this including fixtures, panels, and the host page.
This event bus comes from the Vue core framework. This matters as creating multiple event busses mean spinning up a
Vue()
instance for each, which is more expensive than, say, a dirty fake event system that GeoAPI uses by wrapping an array of callbacks.Option 1 - Fixture Has Own Bus
Give each fixture its own event bus to emit events on. This easily aligns with the proposed convention on setting event handlers on fixtures themselves:
The default Vue event bus functions would need some wrapping to allow for handler name parameter.
Pros
Cons
Option 2 - Leveraging the Global Bus
Reuse the global event bus for all fixture events. This will require some wrapping of the global even bus functions to help distinguish events from different fixture (since you can't trust people to name things correctly):
Pros
Cons
Option 3 - Decoupled Fixture Bus
We keep the idea of a bus-per-fixture from Option 1, but the bus lives in a decoupled global area, like an
EventSheriff
. Each bus in the Sheriff is keyed by fixture key-name.Pros
Cons
Discussion
Beta Was this translation helpful? Give feedback.
All reactions