-
Notifications
You must be signed in to change notification settings - Fork 194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove crossframe service and simplify communication with connected frames #116
Conversation
@@ -105,7 +108,8 @@ var update = { | |||
updatedTags[existing.$$tag] = true; | |||
} | |||
} else { | |||
added.push(initializeAnnot(annot)); | |||
added.push(initializeAnnot(annot, 't' + nextTag)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In master, annotations on both sides of the channel are given local tags generated with btoa(Math.random())
. The important thing about the tags is that they may be exposed to third-party JS, so shouldn't be connected to the original annotation ID at all.
Here I've gone for the simpler option of using t1
,t2
... tN
for annotations loaded via the API where N
is just a serial number that is incremented every time a new annotation is loaded via the API, on the basis that 3rd-party JS code in the page could observe the order in which annotations are loaded if it wanted to, so there isn't much point trying to hide that.
Annotations originating from the page still use the old scheme.
Thank you. Debugging my way through cross-frame communication has been a brain-melter, sounds like this will help, look forward to finding out. |
e2851d9
to
7d306bb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clicking on a highlight in the document doesn't seem to do anything for me?
events_.forEach(function (event) { | ||
inFrame.add(event.tag); | ||
annotationUI.updateAnchorStatus(null, event.tag, event.msg.$orphan); | ||
$rootScope.$broadcast(events.ANNOTATIONS_SYNCED, [event.tag]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would AFTER_ANNOTATION_ANCHORED
be a better name for this event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but this is an existing event which is referenced elsewhere in the code which I didn't want to touch as part of this PR. There is quite a bit of additional cleanup that can be done once this is merged.
Previously the communication between the sidebar and host frame was implemented by a shared AnnotationSync class, with a 'crossframe' service which abstracted the event bus on each side. This design however assumed that both sides wanted to listen to the same messages and react to them in similar ways. This is not the case, especially given the change to use Redux for state management in the sidebar app. This commit replaces the crossframe service and AnnotationSync class with a new 'frameSync' service which implements only the event listeners and sidebar -> page RPC calls that are actually needed. As a result, local annotation tags for annotations loaded via the API can now be assigned by the reducer in the Redux store, making this easier to test and getting us another step closer to making Annotation objects immutable in the sidebar app.
Now that AnnotationSync is no longer used in the sidebar app, we can remove all of the handlers for events and messages arriving through the channel which are not needed by the page itself.
7d306bb
to
b08aafe
Compare
Good catch. I missed the fact that listeners for selection/focus events in the frame are handled by the The entire |
Fantastic to see this part of the code base finally getting untangled. The new code is very easy to understand. Looking forward to further simplification that will now be possible. One thing I think we should watch out for is terminology. The terrible names given to everything in this part of the codebase is one of the things that makes it so hard to understand. There's quite a few different things to try and give good, distinct names to: the sidebar app itself, the sidebar app's iframe, the document that contains the sidebar app's iframe, the code of ours that runs inside this document, other iframes in the document and instances of our code that run inside them, and the various objects that are used to communicate between frames (bridge, crossframe, various things with "sync" in their name...). I think this PR makes a good start on that with |
This PR is an effort to make the flow of events that lead to an annotation loaded in the sidebar app via the API being anchored in the page easier to understand and change. It should also unblock future optimizations (such as batching certain inter-window messages together) and simplifications to other code.
Communication between the sidebar app and the frame, in master, consists of several pieces:
CrossFrame
- A service that sets up listeners from the "local" event bus (the annotator event bus in the frame, Angular's$rootScope
in the sidebar app) and invokes handlers inAnnotationSync
AnnotationSync
- A service that listens for annotation events on the "local" event bus, strips out most of the annotation properties except for the minimal information needed to identify and anchor them in the page, and sends them to the sidebar/host frame via thebridge
serviceBridge
- A wrapper around theframe-rpc
npm package for making RPC calls between windows using thewindow.postMessage
APIDiscovery
- A service that runs in either client or server mode and connects toDiscovery
services running in the opposite mode. When the "server" (the sidebar app) finds a "client" (the code running in the page), achannel
is created using theBridge
service which enables the two to communicateThe biggest problem with the above architecture is that the same code was used for the
AnnotationSync
service in both the sidebar app and the host frame, despite the fact that each side has different responsibilities and a significantly different environment.This PR removes the
CrossFrame
andAnnotationSync
services from the sidebar app, and replaces it with a minimalframeSync
service which listens to only the events/sends only the messages that the sidebar app needs to send. TheAnnotationSync
code meanwhile has been gutted of everything that was not relevant to host frame and moved to theannotator/
folder.The
Bridge
andDiscovery
services could likely be simplified in future, but I have continued to re-use them in the same way for the moment.