Commit 44918b5e authored by Juan Corona's avatar Juan Corona

Clean up and refactor the multi frame support in CrossFrame

parent e11f88f2
...@@ -3,8 +3,9 @@ Plugin = require('../plugin') ...@@ -3,8 +3,9 @@ Plugin = require('../plugin')
AnnotationSync = require('../annotation-sync') AnnotationSync = require('../annotation-sync')
Bridge = require('../../shared/bridge') Bridge = require('../../shared/bridge')
Discovery = require('../../shared/discovery') Discovery = require('../../shared/discovery')
frameUtil = require('../util/frame-util') FrameUtil = require('../util/frame-util')
debounce = require('lodash.debounce')
# Extracts individual keys from an object and returns a new one. # Extracts individual keys from an object and returns a new one.
extract = extract = (obj, keys...) -> extract = extract = (obj, keys...) ->
...@@ -12,11 +13,17 @@ extract = extract = (obj, keys...) -> ...@@ -12,11 +13,17 @@ extract = extract = (obj, keys...) ->
ret[key] = obj[key] for key in keys when obj.hasOwnProperty(key) ret[key] = obj[key] for key in keys when obj.hasOwnProperty(key)
ret ret
# Find difference of two arrays
difference = (arrayA, arrayB) ->
arrayA.filter (x) -> !arrayB.includes(x)
# Class for establishing a messaging connection to the parent sidebar as well # Class for establishing a messaging connection to the parent sidebar as well
# as keeping the annotation state in sync with the sidebar application, this # as keeping the annotation state in sync with the sidebar application, this
# frame acts as the bridge client, the sidebar is the server. This plugin # frame acts as the bridge client, the sidebar is the server. This plugin
# can also be used to send messages through to the sidebar using the # can also be used to send messages through to the sidebar using the
# call method. # call method. This plugin also enables the discovery and management of
# not yet known frames in a multiple frame scenario.
module.exports = class CrossFrame extends Plugin module.exports = class CrossFrame extends Plugin
constructor: (elem, options) -> constructor: (elem, options) ->
super super
...@@ -29,21 +36,15 @@ module.exports = class CrossFrame extends Plugin ...@@ -29,21 +36,15 @@ module.exports = class CrossFrame extends Plugin
opts = extract(options, 'on', 'emit') opts = extract(options, 'on', 'emit')
annotationSync = new AnnotationSync(bridge, opts) annotationSync = new AnnotationSync(bridge, opts)
handledFrames = []
this.pluginInit = -> this.pluginInit = ->
onDiscoveryCallback = (source, origin, token) -> onDiscoveryCallback = (source, origin, token) ->
bridge.createChannel(source, origin, token) bridge.createChannel(source, origin, token)
discovery.startDiscovery(onDiscoveryCallback) discovery.startDiscovery(onDiscoveryCallback)
# THESIS TODO: Disabled until fully implemented. if options.enableMultiFrameSupport
# _setupFrameDetection()
# Find, and inject Hypothesis into Guest's iframes
# _discoverOwnFrames()
# Listen for DOM mutations, to know when iframes are added / removed
observer = new MutationObserver(_checkForIFrames)
config = {childList: true, subtree: true};
# THESIS TODO: Disabled until multi-guest support is fully implemented
# observer.observe(elem, config);
this.destroy = -> this.destroy = ->
# super doesnt work here :( # super doesnt work here :(
...@@ -63,36 +64,39 @@ module.exports = class CrossFrame extends Plugin ...@@ -63,36 +64,39 @@ module.exports = class CrossFrame extends Plugin
this.onConnect = (fn) -> this.onConnect = (fn) ->
bridge.onConnect(fn) bridge.onConnect(fn)
_discoverOwnFrames = () -> _setupFrameDetection = ->
# Discover existing iframes _discoverOwnFrames()
iframes = frameUtil.findIFrames(elem)
_handleIFrames(iframes) # Listen for DOM mutations, to know when frames are added / removed
observer = new MutationObserver(debounce(_discoverOwnFrames, 300))
_checkForIFrames = (mutations) -> observer.observe(elem, {childList: true, subtree: true});
for own key, mutation of mutations
addedNodes = mutation.addedNodes _discoverOwnFrames = ->
removedNodes = mutation.removedNodes frames = FrameUtil.findFrames(elem)
for frame in frames
# Add iframes if frame not in handledFrames
for own key, node of addedNodes _handleFrame(frame)
if (node.tagName == 'IFRAME' && node.className != 'h-sidebar-iframe') handledFrames.push(frame)
node.addEventListener 'load', ->
bridge.call('addedIFrame') for frame, i in difference(handledFrames, frames)
_handleIFrame(node) _iframeUnloaded(frame)
delete handledFrames[i]
# Remove iframes
for own key, node of removedNodes _injectToFrame = (frame) ->
if (node.tagName == 'IFRAME') if !FrameUtil.hasHypothesis(frame)
bridge.call('removedIFrame') FrameUtil.injectHypothesis(frame, options.embedScriptUrl)
frame.contentWindow.addEventListener 'unload', ->
_handleIFrame = (iframe) -> _iframeUnloaded(frame)
if !frameUtil.isAccessible(iframe) then return
_handleFrame = (frame) ->
if !frameUtil.hasHypothesis(iframe) if !FrameUtil.isAccessible(frame) then return
frameUtil.injectHypothesis(iframe) if frame.contentDocument.readyState != 'complete'
frame.addEventListener 'load', ->
_handleIFrames = (iframes) -> _injectToFrame(frame)
for own index, iframe of iframes else
_handleIFrame(iframe) _injectToFrame(frame)
_iframeUnloaded = (frame) ->
bridge.call('destroyFrame', frame.src);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment