Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
c5f11c91
Commit
c5f11c91
authored
Jan 28, 2015
by
Gerben
Committed by
Aron Carroll
Feb 04, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make Bridge plugin use extracted cross-frame code
parent
3e4b617e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
32 additions
and
308 deletions
+32
-308
bridge.coffee
h/static/scripts/annotator/plugin/bridge.coffee
+9
-290
guest.coffee
h/static/scripts/guest.coffee
+23
-18
No files found.
h/static/scripts/annotator/plugin/bridge.coffee
View file @
c5f11c91
$
=
Annotator
.
$
class
Annotator
.
Plugin
.
Bridge
extends
Annotator
.
Plugin
# These events maintain the awareness of annotations between the two
# communicating annotators.
events
:
'beforeAnnotationCreated'
:
'beforeAnnotationCreated'
'annotationCreated'
:
'annotationCreated'
'annotationUpdated'
:
'annotationUpdated'
'annotationDeleted'
:
'annotationDeleted'
'annotationsLoaded'
:
'annotationsLoaded'
# Plugin configuration
options
:
# Origins allowed to communicate on the channel
origin
:
'*'
# Scope identifier to distinguish this channel from any others
scope
:
'annotator:bridge'
# When this is true, this bridge will act as a gateway and, similar to DHCP,
# offer to connect to bridges in other frames it discovers.
gateway
:
false
# A callback to invoke when a connection is established. The function is
# passed two arguments, the source window and origin of the other frame.
onConnect
:
->
true
# Formats an annotation for sending across the bridge
formatter
:
(
annotation
)
->
annotation
# Parses an annotation received from the bridge
parser
:
(
annotation
)
->
annotation
# Merge function. If specified, it will be called with the local copy of
# an annotation and a parsed copy received as an argument to an RPC call
# to reconcile any differences. The default behavior is to merge all
# keys of the remote object into the local copy
merge
:
(
local
,
remote
)
->
for
k
,
v
of
remote
local
[
k
]
=
v
local
# Cache of annotations which have crossed the bridge for fast, encapsulated
# association of annotations received in arguments to window-local copies.
cache
:
null
# Connected bridge links
links
:
null
constructor
:
(
elem
,
options
)
->
super
@
cache
=
{}
@
links
=
[]
@
discovery
=
new
CrossFrameDiscovery
(
options
.
discoveryOptions
)
@
bridge
=
new
CrossFrameBridge
(
options
.
bridgeOptions
)
@
annotationSync
=
new
AnnotationSync
(
options
.
annotationSyncOptions
,
@
bridge
)
pluginInit
:
->
$
(
window
).
on
'message'
,
this
.
_onMessage
this
.
_beacon
()
onDiscoveryCallback
=
(
source
,
origin
,
token
)
=>
@
bridge
.
createChannel
(
source
,
origin
,
token
)
@
discovery
.
startDiscovery
(
onDiscoveryCallback
)
destroy
:
->
super
$
(
window
).
off
'message'
,
this
.
_onMessage
# Assign a non-enumerable tag to objects which cross the bridge.
# This tag is used to identify the objects between message.
_tag
:
(
msg
,
tag
)
->
return
msg
if
msg
.
$
$tag
tag
=
tag
or
(
window
.
btoa
Math
.
random
())
Object
.
defineProperty
msg
,
'$$tag'
,
value
:
tag
@
cache
[
tag
]
=
msg
msg
# Parse an annotation from a RPC with the configured parser
_parse
:
({
tag
,
msg
})
->
local
=
@
cache
[
tag
]
remote
=
@
options
.
parser
msg
if
local
?
merged
=
@
options
.
merge
local
,
remote
else
merged
=
remote
this
.
_tag
merged
,
tag
# Format an annotation for RPC with the configured formatter
_format
:
(
annotation
)
->
this
.
_tag
annotation
msg
=
@
options
.
formatter
annotation
tag
:
annotation
.
$
$tag
msg
:
msg
# Construct a channel to another frame
_build
:
(
options
)
->
# jschannel chokes on FF and Chrome extension origins.
if
(
options
.
origin
.
match
/^chrome-extension:\/\//
)
or
(
options
.
origin
.
match
/^resource:\/\//
)
options
.
origin
=
'*'
channel
=
Channel
.
build
(
options
)
## Remote method call bindings
.
bind
(
'beforeCreateAnnotation'
,
(
txn
,
annotation
)
=>
annotation
=
this
.
_parse
annotation
delete
@
cache
[
annotation
.
$
$tag
]
@
annotator
.
publish
'beforeAnnotationCreated'
,
annotation
@
cache
[
annotation
.
$
$tag
]
=
annotation
this
.
_format
annotation
)
.
bind
(
'createAnnotation'
,
(
txn
,
annotation
)
=>
annotation
=
this
.
_parse
annotation
delete
@
cache
[
annotation
.
$
$tag
]
@
annotator
.
publish
'annotationCreated'
,
annotation
@
cache
[
annotation
.
$
$tag
]
=
annotation
this
.
_format
annotation
)
.
bind
(
'updateAnnotation'
,
(
txn
,
annotation
)
=>
annotation
=
this
.
_parse
annotation
delete
@
cache
[
annotation
.
$
$tag
]
annotation
=
@
annotator
.
updateAnnotation
annotation
@
cache
[
annotation
.
$
$tag
]
=
annotation
this
.
_format
annotation
)
.
bind
(
'deleteAnnotation'
,
(
txn
,
annotation
)
=>
annotation
=
this
.
_parse
annotation
delete
@
cache
[
annotation
.
$
$tag
]
annotation
=
@
annotator
.
deleteAnnotation
annotation
res
=
this
.
_format
annotation
delete
@
cache
[
annotation
.
$
$tag
]
res
)
.
bind
(
'sync'
,
(
ctx
,
annotations
)
=>
(
this
.
_format
(
this
.
_parse
a
)
for
a
in
annotations
)
)
## Notifications
.
bind
(
'loadAnnotations'
,
(
txn
,
annotations
)
=>
annotations
=
(
this
.
_parse
a
for
a
in
annotations
)
@
annotator
.
loadAnnotations
annotations
)
# Send out a beacon to let other frames know to connect to us
_beacon
:
->
queue
=
[
window
.
top
]
while
queue
.
length
parent
=
queue
.
shift
()
if
parent
isnt
window
parent
.
postMessage
'__annotator_dhcp_discovery'
,
@
options
.
origin
for
child
in
parent
.
frames
queue
.
push
child
# Make a method call on all links
_call
:
(
options
)
->
_makeDestroyFn
=
(
c
)
=>
(
error
,
reason
)
=>
c
.
destroy
()
@
links
=
(
l
for
l
in
@
links
when
l
.
channel
isnt
c
)
deferreds
=
@
links
.
map
(
l
)
->
d
=
$
.
Deferred
().
fail
(
_makeDestroyFn
l
.
channel
)
options
=
$
.
extend
{},
options
,
success
:
(
result
)
->
d
.
resolve
result
error
:
(
error
,
reason
)
->
if
error
isnt
'timeout_error'
d
.
reject
error
,
reason
else
d
.
resolve
null
timeout
:
1000
l
.
channel
.
call
options
d
.
promise
()
$
.
when
(
deferreds
...)
.
then
(
results
...)
=>
if
Array
.
isArray
(
results
[
0
])
acc
=
[]
foldFn
=
(
_
,
cur
)
=>
(
this
.
_parse
(
a
)
for
a
in
cur
)
else
acc
=
{}
foldFn
=
(
_
,
cur
)
=>
this
.
_parse
(
cur
)
options
.
callback
?
null
,
results
.
reduce
(
foldFn
,
acc
)
.
fail
(
failure
)
=>
options
.
callback
?
failure
# Publish a notification to all links
_notify
:
(
options
)
->
for
l
in
@
links
l
.
channel
.
notify
options
_onMessage
:
(
e
)
=>
{
source
,
origin
,
data
}
=
e
.
originalEvent
match
=
data
.
match
?
/^__annotator_dhcp_(discovery|ack|offer)(:\d+)?$/
return
unless
match
if
match
[
1
]
is
'discovery'
if
@
options
.
gateway
scope
=
':'
+
(
''
+
Math
.
random
()).
replace
(
/\D/g
,
''
)
source
.
postMessage
'__annotator_dhcp_offer'
+
scope
,
origin
else
source
.
postMessage
'__annotator_dhcp_ack'
,
origin
return
else
if
match
[
1
]
is
'ack'
if
@
options
.
gateway
scope
=
':'
+
(
''
+
Math
.
random
()).
replace
(
/\D/g
,
''
)
source
.
postMessage
'__annotator_dhcp_offer'
+
scope
,
origin
else
return
else
if
match
[
1
]
is
'offer'
if
@
options
.
gateway
return
else
scope
=
match
[
2
]
scope
=
@
options
.
scope
+
scope
options
=
$
.
extend
{},
@
options
,
window
:
source
origin
:
origin
scope
:
scope
onReady
:
=>
options
.
onConnect
.
call
@
annotator
,
source
,
origin
,
scope
annotations
=
(
this
.
_format
a
for
t
,
a
of
@
cache
)
if
annotations
.
length
channel
.
notify
method
:
'loadAnnotations'
params
:
annotations
channel
=
this
.
_build
options
@
links
.
push
channel
:
channel
window
:
source
beforeAnnotationCreated
:
(
annotation
)
=>
return
if
annotation
.
$
$tag
?
this
.
beforeCreateAnnotation
annotation
this
annotationCreated
:
(
annotation
)
=>
return
unless
annotation
.
$
$tag
?
and
@
cache
[
annotation
.
$
$tag
]
this
.
createAnnotation
annotation
this
annotationUpdated
:
(
annotation
)
=>
return
unless
annotation
.
$
$tag
?
and
@
cache
[
annotation
.
$
$tag
]
this
.
updateAnnotation
annotation
this
annotationDeleted
:
(
annotation
)
=>
return
unless
annotation
.
$
$tag
?
and
@
cache
[
annotation
.
$
$tag
]
this
.
deleteAnnotation
annotation
,
(
err
)
=>
if
err
then
@
annotator
.
setupAnnotation
annotation
else
delete
@
cache
[
annotation
.
$
$tag
]
this
annotationsLoaded
:
(
annotations
)
=>
annotations
=
(
this
.
_format
a
for
a
in
annotations
when
not
a
.
$
$tag
)
return
unless
annotations
.
length
this
.
_notify
method
:
'loadAnnotations'
params
:
annotations
this
beforeCreateAnnotation
:
(
annotation
,
cb
)
->
this
.
_call
method
:
'beforeCreateAnnotation'
params
:
this
.
_format
annotation
callback
:
cb
annotation
createAnnotation
:
(
annotation
,
cb
)
->
this
.
_call
method
:
'createAnnotation'
params
:
this
.
_format
annotation
callback
:
cb
annotation
updateAnnotation
:
(
annotation
,
cb
)
->
this
.
_call
method
:
'updateAnnotation'
params
:
this
.
_format
annotation
callback
:
cb
annotation
deleteAnnotation
:
(
annotation
,
cb
)
->
this
.
_call
method
:
'deleteAnnotation'
params
:
this
.
_format
annotation
callback
:
cb
annotation
@
discovery
.
stopDiscovery
()
return
sync
:
(
annotations
,
cb
)
->
annotations
=
(
this
.
_format
a
for
a
in
annotations
)
this
.
_call
method
:
'sync'
params
:
annotations
callback
:
cb
this
@
annotationSync
.
sync
(
annotations
,
cb
)
h/static/scripts/guest.coffee
View file @
c5f11c91
...
...
@@ -52,24 +52,29 @@ class Annotator.Guest extends Annotator
delete
@
options
.
app
this
.
addPlugin
'Bridge'
,
formatter
:
(
annotation
)
=>
formatted
=
{}
formatted
[
'uri'
]
=
@
getHref
()
for
k
,
v
of
annotation
when
k
isnt
'anchors'
formatted
[
k
]
=
v
# Work around issue in jschannel where a repeated object is considered
# recursive, even if it is not its own ancestor.
if
formatted
.
document
?
.
title
formatted
.
document
.
title
=
formatted
.
document
.
title
.
slice
()
formatted
onConnect
:
(
source
,
origin
,
scope
)
=>
@
panel
=
this
.
_setupXDM
window
:
source
origin
:
origin
scope
:
"
#{
scope
}
:provider"
onReady
:
=>
this
.
publish
(
'panelReady'
)
bridgePluginOptions
=
discoveryOptions
:
{}
bridgeOptions
:
onConnect
:
(
source
,
origin
,
scope
)
=>
# TODO
@
panel
=
this
.
_setupXDM
window
:
source
origin
:
origin
scope
:
"
#{
scope
}
:provider"
onReady
:
=>
this
.
publish
(
'panelReady'
)
annotationSyncOptions
:
formatter
:
(
annotation
)
=>
formatted
=
{}
formatted
[
'uri'
]
=
@
getHref
()
for
k
,
v
of
annotation
when
k
isnt
'anchors'
formatted
[
k
]
=
v
# Work around issue in jschannel where a repeated object is considered
# recursive, even if it is not its own ancestor.
if
formatted
.
document
?
.
title
formatted
.
document
.
title
=
formatted
.
document
.
title
.
slice
()
formatted
this
.
addPlugin
'Bridge'
,
bridgePluginOptions
# Load plugins
for
own
name
,
opts
of
@
options
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment