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
7faa6cec
Commit
7faa6cec
authored
Jan 17, 2015
by
csillag
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update Annotator to e2bea2d6 (typed-packaging branch)
parent
889c7533
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
372 additions
and
313 deletions
+372
-313
anchors.coffee
h/static/scripts/annotator/anchors.coffee
+0
-76
annotator.coffee
h/static/scripts/annotator/annotator.coffee
+11
-161
highlights.coffee
h/static/scripts/annotator/highlights.coffee
+3
-1
domtextmapper.coffee
h/static/scripts/annotator/plugin/domtextmapper.coffee
+4
-2
enhancedanchoring.coffee
h/static/scripts/annotator/plugin/enhancedanchoring.coffee
+249
-0
fuzzytextanchors.coffee
h/static/scripts/annotator/plugin/fuzzytextanchors.coffee
+28
-19
pdf.coffee
h/static/scripts/annotator/plugin/pdf.coffee
+7
-5
texthighlights.coffee
h/static/scripts/annotator/plugin/texthighlights.coffee
+7
-1
textposition.coffee
h/static/scripts/annotator/plugin/textposition.coffee
+26
-20
textquote.coffee
h/static/scripts/annotator/plugin/textquote.coffee
+14
-9
textrange.coffee
h/static/scripts/annotator/plugin/textrange.coffee
+20
-16
textselection.coffee
h/static/scripts/annotator/plugin/textselection.coffee
+3
-3
No files found.
h/static/scripts/annotator/anchors.coffee
deleted
100644 → 0
View file @
889c7533
# Abstract anchor class.
class
Anchor
constructor
:
(
@
annotator
,
@
annotation
,
@
target
@
startPage
,
@
endPage
,
@
quote
,
@
diffHTML
,
@
diffCaseOnly
)
->
unless
@
annotator
?
then
throw
"annotator is required!"
unless
@
annotation
?
then
throw
"annotation is required!"
unless
@
target
?
then
throw
"target is required!"
unless
@
startPage
?
then
"startPage is required!"
unless
@
endPage
?
then
throw
"endPage is required!"
unless
@
quote
?
then
throw
"quote is required!"
@
highlight
=
{}
# Return highlights for the given page
_createHighlight
:
(
page
)
->
throw
"Function not implemented"
# Create the missing highlights for this anchor
realize
:
()
=>
return
if
@
fullyRealized
# If we have everything, go home
# Collect the pages that are already rendered
renderedPages
=
[
@
startPage
..
@
endPage
].
filter
(
index
)
=>
@
annotator
.
domMapper
.
isPageMapped
index
# Collect the pages that are already rendered, but not yet anchored
pagesTodo
=
renderedPages
.
filter
(
index
)
=>
not
@
highlight
[
index
]
?
return
unless
pagesTodo
.
length
# Return if nothing to do
# Create the new highlights
created
=
for
page
in
pagesTodo
@
highlight
[
page
]
=
@
_createHighlight
page
# Check if everything is rendered now
@
fullyRealized
=
renderedPages
.
length
is
@
endPage
-
@
startPage
+
1
# Announce the creation of the highlights
@
annotator
.
publish
'highlightsCreated'
,
created
# Remove the highlights for the given set of pages
virtualize
:
(
pageIndex
)
=>
highlight
=
@
highlight
[
pageIndex
]
return
unless
highlight
?
# No highlight for this page
highlight
.
removeFromDocument
()
delete
@
highlight
[
pageIndex
]
# Mark this anchor as not fully rendered
@
fullyRealized
=
false
# Announce the removal of the highlight
@
annotator
.
publish
'highlightRemoved'
,
highlight
# Virtualize and remove an anchor from all involved pages
remove
:
->
# Go over all the pages
for
index
in
[
@
startPage
..
@
endPage
]
@
virtualize
index
anchors
=
@
annotator
.
anchors
[
index
]
# Remove the anchor from the list
i
=
anchors
.
indexOf
this
anchors
[
i
..
i
]
=
[]
# Kill the list if it's empty
delete
@
annotator
.
anchors
[
index
]
unless
anchors
.
length
# This is called when the underlying Annotator has been udpated
annotationUpdated
:
->
# Notify the highlights
for
index
in
[
@
startPage
..
@
endPage
]
@
highlight
[
index
]
?
.
annotationUpdated
()
h/static/scripts/annotator/annotator.coffee
View file @
7faa6cec
...
...
@@ -41,16 +41,6 @@ util =
# Store a reference to the current Annotator object.
_Annotator
=
this
.
Annotator
# Fake two-phase / pagination support, used for HTML documents
class
DummyDocumentAccess
@
applicable
:
->
true
getPageIndex
:
->
0
getPageCount
:
->
1
getPageIndexForPos
:
->
0
isPageMapped
:
->
true
scan
:
->
class
Annotator
extends
Delegator
# Events to be bound on Annotator#element.
events
:
...
...
@@ -104,75 +94,20 @@ class Annotator extends Delegator
constructor
:
(
element
,
options
)
->
super
@
plugins
=
{}
@
selectorCreators
=
[]
@
anchoringStrategies
=
[]
# Return early if the annotator is not supported.
return
this
unless
Annotator
.
supported
()
this
.
_setupDocumentEvents
()
unless
@
options
.
readOnly
this
.
_setupAnchorEvents
()
this
.
_setupWrapper
()
this
.
_setupDocumentAccessStrategies
()
this
.
_setupViewer
().
_setupEditor
()
this
.
_setupDynamicStyle
()
# Perform initial DOM scan, unless told not to.
this
.
_scan
()
unless
@
options
.
noScan
#
this._scan() unless @options.noScan
# Create adder
this
.
adder
=
$
(
this
.
html
.
adder
).
appendTo
(
@
wrapper
).
hide
()
# Initializes the available document access strategies
_setupDocumentAccessStrategies
:
->
@
documentAccessStrategies
=
[
# Default dummy strategy for simple HTML documents.
# The generic fallback.
name
:
"Dummy"
mapper
:
DummyDocumentAccess
]
this
# Initializes the components used for analyzing the document
_chooseAccessPolicy
:
->
if
@
domMapper
?
then
return
# Go over the available strategies
for
s
in
@
documentAccessStrategies
# Can we use this strategy for this document?
if
s
.
mapper
.
applicable
()
@
documentAccessStrategy
=
s
@
domMapper
=
new
s
.
mapper
()
@
anchors
=
{}
addEventListener
"docPageMapped"
,
(
evt
)
=>
@
_realizePage
evt
.
pageIndex
addEventListener
"docPageUnmapped"
,
(
evt
)
=>
@
_virtualizePage
evt
.
pageIndex
s
.
init
?
()
return
this
# Remove the current document access policy
_removeCurrentAccessPolicy
:
->
return
unless
@
domMapper
?
list
=
@
documentAccessStrategies
index
=
list
.
indexOf
@
documentAccessStrategy
list
.
splice
(
index
,
1
)
unless
index
is
-
1
@
domMapper
.
destroy
?
()
delete
@
domMapper
# Perform a scan of the DOM. Required for finding anchors.
_scan
:
->
# Ensure that we have a document access strategy
this
.
_chooseAccessPolicy
()
try
@
pendingScan
=
@
domMapper
.
scan
()
catch
@
_removeCurrentAccessPolicy
()
@
_scan
()
return
# Wraps the children of @element in a @wrapper div. NOTE: This method will also
# remove any script elements inside @element to prevent them re-executing.
#
...
...
@@ -243,14 +178,6 @@ class Annotator extends Delegator
})
this
# Sets up handlers to anchor-related events
_setupAnchorEvents
:
->
# When annotations are updated
@
on
'annotationUpdated'
,
(
annotation
)
=>
# Notify the anchors
for
anchor
in
annotation
.
anchors
or
[]
anchor
.
annotationUpdated
()
# Sets up any dynamically calculated CSS for the Annotator.
#
# Returns itself for chaining.
...
...
@@ -336,37 +263,6 @@ class Annotator extends Delegator
this
.
publish
(
'beforeAnnotationCreated'
,
[
annotation
])
annotation
# Do some normalization to get a "canonical" form of a string.
# Used to even out some browser differences.
normalizeString
:
(
string
)
->
string
.
replace
/\s{2,}/g
,
" "
# Find the given type of selector from an array of selectors, if it exists.
# If it does not exist, null is returned.
findSelector
:
(
selectors
,
type
)
->
for
selector
in
selectors
if
selector
.
type
is
type
then
return
selector
null
# Try to find the right anchoring point for a given target
#
# Returns an Anchor object if succeeded, null otherwise
createAnchor
:
(
annotation
,
target
)
->
unless
target
?
throw
new
Error
"Trying to find anchor for null target!"
error
=
null
anchor
=
null
for
s
in
@
anchoringStrategies
try
a
=
s
.
code
.
call
this
,
annotation
,
target
if
a
return
result
:
a
catch
error
console
.
log
"Strategy '"
+
s
.
name
+
"' has thrown an error."
,
error
.
stack
?
error
return
error
:
"No strategies worked."
# Public: Initialises an annotation either from an object representation or
# an annotation created with Annotator#createAnnotation(). It finds the
# selected range and higlights the selection in the DOM, extracts the
...
...
@@ -397,7 +293,7 @@ class Annotator extends Delegator
for
t
in
annotation
.
target
?
[]
try
# Create an anchor for this target
result
=
this
.
createAnchor
annotation
,
t
result
=
this
.
anchoring
.
createAnchor
annotation
,
t
anchor
=
result
.
result
if
result
.
error
?
instanceof
Range
.
RangeError
this
.
publish
'rangeNormalizeFail'
,
[
annotation
,
result
.
error
.
range
,
result
.
error
]
...
...
@@ -408,14 +304,6 @@ class Annotator extends Delegator
# Store this anchor for the annotation
annotation
.
anchors
.
push
anchor
# Store the anchor for all involved pages
for
pageIndex
in
[
anchor
.
startPage
..
anchor
.
endPage
]
@
anchors
[
pageIndex
]
?=
[]
@
anchors
[
pageIndex
].
push
anchor
# Realizing the anchor
anchor
.
realize
()
catch
exception
console
.
log
"Error in setupAnnotation for"
,
annotation
.
id
,
":"
,
exception
.
stack
?
exception
...
...
@@ -451,7 +339,7 @@ class Annotator extends Delegator
#
# Returns deleted annotation.
deleteAnnotation
:
(
annotation
)
->
if
annotation
.
anchors
?
if
annotation
.
anchors
?
for
a
in
annotation
.
anchors
a
.
remove
()
...
...
@@ -560,7 +448,7 @@ class Annotator extends Delegator
this
# Callback method called when the @editor fires the "hide" event. Itself
# publishes the 'annotationEditorHidden' event
# publishes the 'annotationEditorHidden' event
#
# Returns nothing.
onEditorHide
:
=>
...
...
@@ -624,19 +512,6 @@ class Annotator extends Delegator
this
.
startViewerHideTimer
()
@
mouseIsDown
=
true
# This is called to create a target from a raw selection,
# using selectors created by the registered selector creators
_getTargetFromSelection
:
(
selection
)
=>
selectors
=
[]
for
c
in
@
selectorCreators
description
=
c
.
describe
selection
for
selector
in
description
selectors
.
push
selector
# Create the target
source
:
@
getHref
()
selector
:
selectors
# This method is to be called by the mechanisms responsible for
# triggering annotation (and highlight) creation.
#
...
...
@@ -673,6 +548,12 @@ class Annotator extends Delegator
true
# This is called to create a target from a raw selection,
# using selectors created by the registered selector creators
_getTargetFromSelection
:
(
selection
)
->
source
:
@
getHref
()
selector
:
@
anchoring
.
getSelectorsFromSelection
(
selection
)
onFailedSelection
:
(
event
)
->
@
adder
.
hide
()
@
selectedTargets
=
[]
...
...
@@ -695,7 +576,7 @@ class Annotator extends Delegator
isAnnotator
:
(
element
)
->
!!
$
(
element
).
parents
().
andSelf
().
filter
(
'[class^=annotator-]'
).
not
(
@
wrapper
).
length
# Annotator#element callback.
# Annotator#element callback.
#
# event - A mousedown Event object
#
...
...
@@ -796,36 +677,6 @@ class Annotator extends Delegator
# Delete highlight elements.
this
.
deleteAnnotation
annotation
# Collect all the highlights (optionally for a given set of annotations)
getHighlights
:
(
annotations
)
->
results
=
[]
if
annotations
?
# Collect only the given set of annotations
for
annotation
in
annotations
for
anchor
in
annotation
.
anchors
for
page
,
hl
of
anchor
.
highlight
results
.
push
hl
else
# Collect from everywhere
for
page
,
anchors
of
@
anchors
$
.
merge
results
,
(
anchor
.
highlight
[
page
]
for
anchor
in
anchors
when
anchor
.
highlight
[
page
]
?
)
results
# Realize anchors on a given pages
_realizePage
:
(
index
)
->
# If the page is not mapped, give up
return
unless
@
domMapper
.
isPageMapped
index
# Go over all anchors related to this page
for
anchor
in
@
anchors
[
index
]
?
[]
anchor
.
realize
()
# Virtualize anchors on a given page
_virtualizePage
:
(
index
)
->
# Go over all anchors related to this page
for
anchor
in
@
anchors
[
index
]
?
[]
anchor
.
virtualize
index
onAnchorMouseover
:
(
event
)
->
# Cancel any pending hiding of the viewer.
this
.
clearViewerHideTimer
()
...
...
@@ -896,7 +747,6 @@ Annotator.Util = Util
Annotator
.
_instances
=
[]
Annotator
.
Highlight
=
Highlight
Annotator
.
Anchor
=
Anchor
# Bind gettext helper so plugins can use localisation.
Annotator
.
_t
=
_t
...
...
h/static/scripts/annotator/highlights.coffee
View file @
7faa6cec
...
...
@@ -2,8 +2,9 @@
class
Highlight
constructor
:
(
@
anchor
,
@
pageIndex
)
->
@
annotator
=
@
anchor
.
annotator
@
annotation
=
@
anchor
.
annotation
@
anchoring
=
@
anchor
.
anchoring
@
annotator
=
@
anchoring
.
annotator
# Mark/unmark this hl as temporary (while creating an annotation)
setTemporary
:
(
value
)
->
...
...
@@ -80,3 +81,4 @@ class Highlight
# Scroll down to the highlight, with a comfortable margin.
paddedScrollDownTo
:
->
@
paddedScrollTo
"down"
h/static/scripts/annotator/plugin/domtextmapper.coffee
View file @
7faa6cec
...
...
@@ -6,9 +6,11 @@ class Annotator.Plugin.DomTextMapper extends Annotator.Plugin
console
.
log
"Not registering DOM-Text-Mapper."
return
@
annotator
.
documentAccessStrategies
.
unshift
@
anchoring
=
@
annotator
.
anchoring
@
anchoring
.
documentAccessStrategies
.
unshift
# Document access strategy for simple HTML documents,
# with enhanced text extraction and mapping features.
name
:
"DOM-Text-Mapper"
mapper
:
window
.
DomTextMapper
init
:
=>
@
an
notator
.
domMapper
.
setRootNode
@
annotator
.
wrapper
[
0
]
init
:
=>
@
an
choring
.
document
.
setRootNode
@
annotator
.
wrapper
[
0
]
h/static/scripts/annotator/plugin/enhancedanchoring.coffee
0 → 100644
View file @
7faa6cec
# Fake two-phase / pagination support, used for HTML documents
class
DummyDocumentAccess
@
applicable
:
->
true
getPageIndex
:
->
0
getPageCount
:
->
1
getPageIndexForPos
:
->
0
isPageMapped
:
->
true
scan
:
->
# Abstract anchor class.
class
Anchor
constructor
:
(
@
anchoring
,
@
annotation
,
@
target
@
startPage
,
@
endPage
,
@
quote
,
@
diffHTML
,
@
diffCaseOnly
)
->
unless
@
anchoring
?
then
throw
"anchoring manager is required!"
unless
@
annotation
?
then
throw
"annotation is required!"
unless
@
target
?
then
throw
"target is required!"
unless
@
startPage
?
then
"startPage is required!"
unless
@
endPage
?
then
throw
"endPage is required!"
unless
@
quote
?
then
throw
"quote is required!"
@
highlight
=
{}
_getSegment
:
(
page
)
->
throw
"Function not implemented"
# Create the missing highlights for this anchor
realize
:
()
=>
return
if
@
fullyRealized
# If we have everything, go home
# Collect the pages that are already rendered
renderedPages
=
[
@
startPage
..
@
endPage
].
filter
(
index
)
=>
@
anchoring
.
document
.
isPageMapped
index
# Collect the pages that are already rendered, but not yet anchored
pagesTodo
=
renderedPages
.
filter
(
index
)
=>
not
@
highlight
[
index
]
?
return
unless
pagesTodo
.
length
# Return if nothing to do
# Create the new highlights
created
=
for
page
in
pagesTodo
# TODO: add a layer of abstraction here
# Don't call TextHighlight directly; instead, make a system
# For registering highlight creators, or publish an event, or
# whatever
@
highlight
[
page
]
=
@
Annotator
.
TextHighlight
.
createFrom
@
_getSegment
(
page
),
this
,
page
# Check if everything is rendered now
@
fullyRealized
=
renderedPages
.
length
is
@
endPage
-
@
startPage
+
1
# Announce the creation of the highlights
@
anchoring
.
annotator
.
publish
'highlightsCreated'
,
created
# Remove the highlights for the given set of pages
virtualize
:
(
pageIndex
)
=>
highlight
=
@
highlight
[
pageIndex
]
return
unless
highlight
?
# No highlight for this page
highlight
.
removeFromDocument
()
delete
@
highlight
[
pageIndex
]
# Mark this anchor as not fully rendered
@
fullyRealized
=
false
# Announce the removal of the highlight
@
anchoring
.
annotator
.
publish
'highlightRemoved'
,
highlight
# Virtualize and remove an anchor from all involved pages
remove
:
->
# Go over all the pages
for
index
in
[
@
startPage
..
@
endPage
]
@
virtualize
index
anchors
=
@
anchoring
.
anchors
[
index
]
# Remove the anchor from the list
i
=
anchors
.
indexOf
this
anchors
[
i
..
i
]
=
[]
# Kill the list if it's empty
delete
@
anchoring
.
anchors
[
index
]
unless
anchors
.
length
# This is called when the underlying Annotator has been udpated
annotationUpdated
:
->
# Notify the highlights
for
index
in
[
@
startPage
..
@
endPage
]
@
highlight
[
index
]
?
.
annotationUpdated
()
Annotator
.
Anchor
=
Anchor
# This plugin contains the enhanced anchoring framework.
class
Annotator
.
Plugin
.
EnhancedAnchoring
extends
Annotator
.
Plugin
constructor
:
->
# Initializes the available document access strategies
_setupDocumentAccessStrategies
:
->
@
documentAccessStrategies
=
[
# Default dummy strategy for simple HTML documents.
# The generic fallback.
name
:
"Dummy"
mapper
:
DummyDocumentAccess
]
this
# Sets up handlers to anchor-related events
_setupAnchorEvents
:
->
# When annotations are updated
@
annotator
.
on
'annotationUpdated'
,
(
annotation
)
=>
# Notify the anchors
for
anchor
in
annotation
.
anchors
or
[]
anchor
.
annotationUpdated
()
# Initializes the components used for analyzing the document
_chooseAccessPolicy
:
->
if
@
document
?
then
return
# Go over the available strategies
for
s
in
@
documentAccessStrategies
# Can we use this strategy for this document?
if
s
.
mapper
.
applicable
()
@
documentAccessStrategy
=
s
@
document
=
new
s
.
mapper
()
@
anchors
=
{}
addEventListener
"docPageMapped"
,
(
evt
)
=>
@
_realizePage
evt
.
pageIndex
addEventListener
"docPageUnmapped"
,
(
evt
)
=>
@
_virtualizePage
evt
.
pageIndex
s
.
init
?
()
return
this
# Remove the current document access policy
_removeCurrentAccessPolicy
:
->
return
unless
@
document
?
list
=
@
documentAccessStrategies
index
=
list
.
indexOf
@
documentAccessStrategy
list
.
splice
(
index
,
1
)
unless
index
is
-
1
@
document
.
destroy
?
()
delete
@
document
# Perform a scan of the DOM. Required for finding anchors.
_scan
:
->
# Ensure that we have a document access strategy
this
.
_chooseAccessPolicy
()
try
@
pendingScan
=
@
document
.
scan
()
catch
@
_removeCurrentAccessPolicy
()
@
_scan
()
return
# Plugin initialization
pluginInit
:
->
@
$
=
Annotator
.
$
@
selectorCreators
=
[]
@
strategies
=
[]
@
_setupDocumentAccessStrategies
()
this
.
_setupAnchorEvents
()
@
annotator
.
anchoring
=
this
# PUBLIC Try to find the right anchoring point for a given target
#
# Returns an Anchor object if succeeded, null otherwise
createAnchor
:
(
annotation
,
target
)
->
unless
target
?
throw
new
Error
"Trying to find anchor for null target!"
error
=
null
anchor
=
null
for
s
in
@
strategies
try
a
=
s
.
code
.
call
this
,
annotation
,
target
if
a
# Store the anchor for all involved pages
for
pageIndex
in
[
a
.
startPage
..
a
.
endPage
]
@
anchors
[
pageIndex
]
?=
[]
@
anchors
[
pageIndex
].
push
a
# Realizing the anchor
a
.
realize
()
return
result
:
a
catch
error
console
.
log
"Strategy '"
+
s
.
name
+
"' has thrown an error."
,
error
.
stack
?
error
return
error
:
"No strategies worked."
# Do some normalization to get a "canonical" form of a string.
# Used to even out some browser differences.
normalizeString
:
(
string
)
->
string
.
replace
/\s{2,}/g
,
" "
# Find the given type of selector from an array of selectors, if it exists.
# If it does not exist, null is returned.
findSelector
:
(
selectors
,
type
)
->
for
selector
in
selectors
if
selector
.
type
is
type
then
return
selector
null
# Realize anchors on a given pages
_realizePage
:
(
index
)
->
# If the page is not mapped, give up
return
unless
@
document
.
isPageMapped
index
# Go over all anchors related to this page
for
anchor
in
@
anchors
[
index
]
?
[]
anchor
.
realize
()
# Virtualize anchors on a given page
_virtualizePage
:
(
index
)
->
# Go over all anchors related to this page
for
anchor
in
@
anchors
[
index
]
?
[]
anchor
.
virtualize
index
# Collect all the highlights (optionally for a given set of annotations)
getHighlights
:
(
annotations
)
->
results
=
[]
if
annotations
?
# Collect only the given set of annotations
for
annotation
in
annotations
for
anchor
in
annotation
.
anchors
for
page
,
hl
of
anchor
.
highlight
results
.
push
hl
else
# Collect from everywhere
for
page
,
anchors
of
@
anchors
@
$
.
merge
results
,
(
anchor
.
highlight
[
page
]
for
anchor
in
anchors
when
anchor
.
highlight
[
page
]
?
)
results
# PUBLIC entry point 1:
# This is called to create a target from a raw selection,
# using selectors created by the registered selector creators
getSelectorsFromSelection
:
(
selection
)
=>
selectors
=
[]
for
c
in
@
selectorCreators
description
=
c
.
describe
selection
for
selector
in
description
selectors
.
push
selector
selectors
h/static/scripts/annotator/plugin/fuzzytextanchors.coffee
View file @
7faa6cec
...
...
@@ -3,24 +3,26 @@ class Annotator.Plugin.FuzzyTextAnchors extends Annotator.Plugin
pluginInit
:
->
# Do we have the basic text anchors plugin loaded?
unless
@
annotator
.
plugins
.
Text
Anchors
console
.
warn
"The FuzzyTextAnchors Annotator plugin requires the Text
Anchors
plugin. Skipping."
unless
@
annotator
.
plugins
.
Text
Position
console
.
warn
"The FuzzyTextAnchors Annotator plugin requires the Text
Position
plugin. Skipping."
return
@
Annotator
=
Annotator
@
anchoring
=
@
annotator
.
anchoring
# Initialize the text matcher library
@
textFinder
=
new
DomTextMatcher
=>
@
an
notator
.
domMapper
.
getCorpus
()
@
textFinder
=
new
DomTextMatcher
=>
@
an
choring
.
document
.
getCorpus
()
# Register our fuzzy strategies
@
an
notator
.
anchoringS
trategies
.
push
@
an
choring
.
s
trategies
.
push
# Two-phased fuzzy text matching strategy. (Using context and quote.)
# This can handle document structure changes,
# and also content changes.
name
:
"two-phase fuzzy"
code
:
this
.
twoPhaseFuzzyMatching
@
an
notator
.
anchoringS
trategies
.
push
@
an
choring
.
s
trategies
.
push
# Naive fuzzy text matching strategy. (Using only the quote.)
# This can handle document structure changes,
# and also content changes.
...
...
@@ -28,11 +30,14 @@ class Annotator.Plugin.FuzzyTextAnchors extends Annotator.Plugin
code
:
this
.
fuzzyMatching
twoPhaseFuzzyMatching
:
(
annotation
,
target
)
=>
document
=
@
anchoring
.
document
# This won't work without DTM
return
unless
@
annotator
.
domMapper
.
getInfoForNode
?
return
unless
document
.
getInfoForNode
?
# Fetch the quote and the context
quoteSelector
=
@
an
notator
.
findSelector
target
.
selector
,
"TextQuoteSelector"
quoteSelector
=
@
an
choring
.
findSelector
target
.
selector
,
"TextQuoteSelector"
prefix
=
quoteSelector
?
.
prefix
suffix
=
quoteSelector
?
.
suffix
quote
=
quoteSelector
?
.
exact
...
...
@@ -41,12 +46,12 @@ class Annotator.Plugin.FuzzyTextAnchors extends Annotator.Plugin
unless
(
prefix
?
and
suffix
?
)
then
return
null
# Fetch the expected start and end positions
posSelector
=
@
an
notator
.
findSelector
target
.
selector
,
"TextPositionSelector"
posSelector
=
@
an
choring
.
findSelector
target
.
selector
,
"TextPositionSelector"
expectedStart
=
posSelector
?
.
start
expectedEnd
=
posSelector
?
.
end
options
=
contextMatchDistance
:
@
annotator
.
domMapper
.
getCorpus
().
length
*
2
contextMatchDistance
:
document
.
getCorpus
().
length
*
2
contextMatchThreshold
:
0.5
patternMatchThreshold
:
0.5
flexContext
:
true
...
...
@@ -65,20 +70,23 @@ class Annotator.Plugin.FuzzyTextAnchors extends Annotator.Plugin
# OK, we have everything
# Create a TextPositionAnchor from this data
new
@
Annotator
.
TextPositionAnchor
@
an
notator
,
annotation
,
target
,
new
@
Annotator
.
TextPositionAnchor
@
an
choring
,
annotation
,
target
,
match
.
start
,
match
.
end
,
(
@
annotator
.
domMapper
.
getPageIndexForPos
match
.
start
),
(
@
annotator
.
domMapper
.
getPageIndexForPos
match
.
end
),
(
document
.
getPageIndexForPos
match
.
start
),
(
document
.
getPageIndexForPos
match
.
end
),
match
.
found
,
unless
match
.
exact
then
match
.
comparison
.
diffHTML
,
unless
match
.
exact
then
match
.
exactExceptCase
fuzzyMatching
:
(
annotation
,
target
)
=>
document
=
@
anchoring
.
document
# This won't work without DTM
return
unless
@
annotator
.
domMapper
.
getInfoForNode
?
return
unless
document
.
getInfoForNode
?
# Fetch the quote
quoteSelector
=
@
an
notator
.
findSelector
target
.
selector
,
"TextQuoteSelector"
quoteSelector
=
@
an
choring
.
findSelector
target
.
selector
,
"TextQuoteSelector"
quote
=
quoteSelector
?
.
exact
# No quote, no joy
...
...
@@ -89,11 +97,11 @@ class Annotator.Plugin.FuzzyTextAnchors extends Annotator.Plugin
return
unless
quote
.
length
>=
32
# Get a starting position for the search
posSelector
=
@
an
notator
.
findSelector
target
.
selector
,
"TextPositionSelector"
posSelector
=
@
an
choring
.
findSelector
target
.
selector
,
"TextPositionSelector"
expectedStart
=
posSelector
?
.
start
# Get full document length
len
=
@
annotator
.
domMapper
.
getCorpus
().
length
len
=
document
.
getCorpus
().
length
# If we don't have the position saved, start at the middle of the doc
expectedStart
?=
Math
.
floor
(
len
/
2
)
...
...
@@ -116,10 +124,11 @@ class Annotator.Plugin.FuzzyTextAnchors extends Annotator.Plugin
# OK, we have everything
# Create a TextPosutionAnchor from this data
new
@
Annotator
.
TextPositionAnchor
@
an
notator
,
annotation
,
target
,
new
@
Annotator
.
TextPositionAnchor
@
an
choring
,
annotation
,
target
,
match
.
start
,
match
.
end
,
(
@
annotator
.
domMapper
.
getPageIndexForPos
match
.
start
),
(
@
annotator
.
domMapper
.
getPageIndexForPos
match
.
end
),
(
document
.
getPageIndexForPos
match
.
start
),
(
document
.
getPageIndexForPos
match
.
end
),
match
.
found
,
unless
match
.
exact
then
match
.
comparison
.
diffHTML
,
unless
match
.
exact
then
match
.
exactExceptCase
h/static/scripts/annotator/plugin/pdf.coffee
View file @
7faa6cec
...
...
@@ -222,7 +222,9 @@ class Annotator.Plugin.PDF extends Annotator.Plugin
console
.
warn
"The PDF Annotator plugin requires the DomTextMapper plugin. Skipping."
return
@
annotator
.
documentAccessStrategies
.
unshift
@
anchoring
=
@
annotator
.
anchoring
@
anchoring
.
documentAccessStrategies
.
unshift
# Strategy to handle PDF documents rendered by PDF.js
name
:
"PDF.js"
mapper
:
PDFTextMapper
...
...
@@ -247,7 +249,7 @@ class Annotator.Plugin.PDF extends Annotator.Plugin
# Get a PDF fingerPrint-based URI
_getFingerPrintURI
:
->
fingerprint
=
@
an
notator
.
domMapper
.
getDocumentFingerprint
()
fingerprint
=
@
an
choring
.
document
.
getDocumentFingerprint
()
# This is an experimental URN,
# as per http://tools.ietf.org/html/rfc3406#section-3.0
...
...
@@ -266,7 +268,7 @@ class Annotator.Plugin.PDF extends Annotator.Plugin
# Try to extract the title; first from metadata, then HTML header
_getTitle
:
->
title
=
@
an
notator
.
domMapper
.
getDocumentInfo
().
Title
?
.
trim
()
title
=
@
an
choring
.
document
.
getDocumentInfo
().
Title
?
.
trim
()
if
title
?
and
title
isnt
""
title
else
...
...
@@ -291,8 +293,8 @@ class Annotator.Plugin.PDF extends Annotator.Plugin
# Public: Get metadata (when the doc is loaded). Returns a promise.
getMetaData
:
=>
new
Promise
(
resolve
,
reject
)
=>
if
@
an
notator
.
domMapper
.
waitForInit
?
@
an
notator
.
domMapper
.
waitForInit
().
then
=>
if
@
an
choring
.
document
.
waitForInit
?
@
an
choring
.
document
.
waitForInit
().
then
=>
try
resolve
@
_metadata
()
catch
error
...
...
h/static/scripts/annotator/plugin/texthighlights.coffee
View file @
7faa6cec
...
...
@@ -2,6 +2,12 @@
# required for annotating text.
class
TextHighlight
extends
Annotator
.
Highlight
@
createFrom
:
(
segment
,
anchor
,
page
)
->
return
null
if
segment
.
type
isnt
"magic range"
new
TextHighlight
anchor
,
page
,
segment
.
data
# XXX: This is a temporay workaround until the Highlighter extension
# PR will be merged which will restore separation properly
@
highlightClass
=
'annotator-hl'
...
...
@@ -110,7 +116,7 @@ class TextHighlight extends Annotator.Highlight
removeFromDocument
:
->
for
hl
in
@
_highlights
# Is this highlight actually the part of the document?
if
hl
.
parentNode
?
and
@
an
notator
.
domMapper
.
isPageMapped
@
pageIndex
if
hl
.
parentNode
?
and
@
an
choring
.
document
.
isPageMapped
@
pageIndex
# We should restore original state
child
=
hl
.
childNodes
[
0
]
@
$
(
hl
).
replaceWith
hl
.
childNodes
...
...
h/static/scripts/annotator/plugin/textposition.coffee
View file @
7faa6cec
...
...
@@ -4,11 +4,11 @@ class TextPositionAnchor extends Annotator.Anchor
@
Annotator
=
Annotator
constructor
:
(
an
notator
,
annotation
,
target
,
constructor
:
(
an
choring
,
annotation
,
target
,
@
start
,
@
end
,
startPage
,
endPage
,
quote
,
diffHTML
,
diffCaseOnly
)
->
super
an
notator
,
annotation
,
target
,
super
an
choring
,
annotation
,
target
,
startPage
,
endPage
,
quote
,
diffHTML
,
diffCaseOnly
...
...
@@ -20,10 +20,10 @@ class TextPositionAnchor extends Annotator.Anchor
@
Annotator
=
TextPositionAnchor
.
Annotator
# This is how we create a highlight out of this kind of anchor
_
createHighligh
t
:
(
page
)
->
_
getSegmen
t
:
(
page
)
->
# First we create the range from the stored stard and end offsets
mappings
=
@
an
notator
.
domMapper
.
getMappingsForCharRange
@
start
,
@
end
,
[
page
]
mappings
=
@
an
choring
.
document
.
getMappingsForCharRange
@
start
,
@
end
,
[
page
]
# Get the wanted range out of the response of DTM
realRange
=
mappings
.
sections
[
page
].
realRange
...
...
@@ -32,11 +32,10 @@ class TextPositionAnchor extends Annotator.Anchor
browserRange
=
new
@
Annotator
.
Range
.
BrowserRange
realRange
# Get a NormalizedRange
normedRange
=
browserRange
.
normalize
@
annotator
.
wrapper
[
0
]
# Create the highligh
new
@
Annotator
.
TextHighlight
this
,
page
,
normedRange
normedRange
=
browserRange
.
normalize
@
anchoring
.
annotator
.
wrapper
[
0
]
type
:
"magic range"
data
:
normedRange
# Annotator plugin for text position-based anchoring
class
Annotator
.
Plugin
.
TextPosition
extends
Annotator
.
Plugin
...
...
@@ -45,12 +44,14 @@ class Annotator.Plugin.TextPosition extends Annotator.Plugin
@
Annotator
=
Annotator
@
anchoring
=
@
annotator
.
anchoring
# Register the creator for text quote selectors
@
an
notator
.
selectorCreators
.
push
@
an
choring
.
selectorCreators
.
push
name
:
"TextPositionSelector"
describe
:
@
_getTextPositionSelector
@
an
notator
.
anchoringS
trategies
.
push
@
an
choring
.
s
trategies
.
push
# Position-based strategy. (The quote is verified.)
# This can handle document structure changes,
# but not the content changes.
...
...
@@ -65,11 +66,13 @@ class Annotator.Plugin.TextPosition extends Annotator.Plugin
# We only care about "text range" selections.
return
[]
unless
selection
.
type
is
"text range"
document
=
@
anchoring
.
document
# We need dom-text-mapper - style functionality
return
[]
unless
@
annotator
.
domMapper
.
getStartPosForNode
?
return
[]
unless
document
.
getStartPosForNode
?
startOffset
=
@
annotator
.
domMapper
.
getStartPosForNode
selection
.
range
.
start
endOffset
=
@
annotator
.
domMapper
.
getEndPosForNode
selection
.
range
.
end
startOffset
=
document
.
getStartPosForNode
selection
.
range
.
start
endOffset
=
document
.
getEndPosForNode
selection
.
range
.
end
if
startOffset
?
and
endOffset
?
[
...
...
@@ -95,7 +98,7 @@ class Annotator.Plugin.TextPosition extends Annotator.Plugin
createFromPositionSelector
:
(
annotation
,
target
)
=>
# We need the TextPositionSelector
selector
=
@
an
notator
.
findSelector
target
.
selector
,
"TextPositionSelector"
selector
=
@
an
choring
.
findSelector
target
.
selector
,
"TextPositionSelector"
return
unless
selector
?
unless
selector
.
start
?
...
...
@@ -106,13 +109,15 @@ class Annotator.Plugin.TextPosition extends Annotator.Plugin
console
.
log
"Warning: 'end' field is missing from TextPositionSelector. Skipping."
return
null
corpus
=
@
annotator
.
domMapper
.
getCorpus
?
()
document
=
@
anchoring
.
document
corpus
=
document
.
getCorpus
?
()
# This won't work without d-t-m
return
null
unless
corpus
content
=
corpus
[
selector
.
start
...
selector
.
end
].
trim
()
currentQuote
=
@
an
notator
.
normalizeString
content
savedQuote
=
@
an
notator
.
getQuoteForTarget
?
target
currentQuote
=
@
an
choring
.
normalizeString
content
savedQuote
=
@
an
choring
.
getQuoteForTarget
?
target
if
savedQuote
?
and
currentQuote
isnt
savedQuote
# We have a saved quote, let's compare it to current content
#console.log "Could not apply position selector" +
...
...
@@ -123,8 +128,9 @@ class Annotator.Plugin.TextPosition extends Annotator.Plugin
return
null
# Create a TextPositionAnchor from this data
new
TextPositionAnchor
@
an
notator
,
annotation
,
target
,
new
TextPositionAnchor
@
an
choring
,
annotation
,
target
,
selector
.
start
,
selector
.
end
,
(
@
annotator
.
domMapper
.
getPageIndexForPos
selector
.
start
),
(
@
annotator
.
domMapper
.
getPageIndexForPos
selector
.
end
),
(
document
.
getPageIndexForPos
selector
.
start
),
(
document
.
getPageIndexForPos
selector
.
end
),
currentQuote
h/static/scripts/annotator/plugin/textquote.coffee
View file @
7faa6cec
...
...
@@ -7,16 +7,18 @@ class Annotator.Plugin.TextQuote extends Annotator.Plugin
# Plugin initialization
pluginInit
:
->
@
anchoring
=
@
annotator
.
anchoring
# Register the creator for text quote selectors
@
an
notator
.
selectorCreators
.
push
@
an
choring
.
selectorCreators
.
push
name
:
"TextQuoteSelector"
describe
:
@
_getTextQuoteSelector
# Register function to get quote from this selector
@
an
notator
.
getQuoteForTarget
=
(
target
)
=>
selector
=
@
an
notator
.
findSelector
target
.
selector
,
"TextQuoteSelector"
@
an
choring
.
getQuoteForTarget
=
(
target
)
=>
selector
=
@
an
choring
.
findSelector
target
.
selector
,
"TextQuoteSelector"
if
selector
?
@
an
notator
.
normalizeString
selector
.
exact
@
an
choring
.
normalizeString
selector
.
exact
else
null
...
...
@@ -24,6 +26,8 @@ class Annotator.Plugin.TextQuote extends Annotator.Plugin
_getTextQuoteSelector
:
(
selection
)
=>
return
[]
unless
selection
.
type
is
"text range"
document
=
@
anchoring
.
document
unless
selection
.
range
?
throw
new
Error
"Called getTextQuoteSelector() with null range!"
...
...
@@ -34,15 +38,15 @@ class Annotator.Plugin.TextQuote extends Annotator.Plugin
unless
rangeEnd
?
throw
new
Error
"Called getTextQuoteSelector() on a range with no valid end."
if
@
annotator
.
domMapper
.
getStartPosForNode
?
if
document
.
getStartPosForNode
?
# Calculate the quote and context using DTM
startOffset
=
@
annotator
.
domMapper
.
getStartPosForNode
rangeStart
endOffset
=
@
annotator
.
domMapper
.
getEndPosForNode
rangeEnd
startOffset
=
document
.
getStartPosForNode
rangeStart
endOffset
=
document
.
getEndPosForNode
rangeEnd
if
startOffset
?
and
endOffset
?
quote
=
@
annotator
.
domMapper
.
getCorpus
()[
startOffset
..
endOffset
-
1
].
trim
()
[
prefix
,
suffix
]
=
@
annotator
.
domMapper
.
getContextForCharRange
startOffset
,
endOffset
quote
=
document
.
getCorpus
()[
startOffset
..
endOffset
-
1
].
trim
()
[
prefix
,
suffix
]
=
document
.
getContextForCharRange
startOffset
,
endOffset
[
type
:
"TextQuoteSelector"
...
...
@@ -61,3 +65,4 @@ class Annotator.Plugin.TextQuote extends Annotator.Plugin
type
:
"TextQuoteSelector"
exact
:
selection
.
range
.
text
().
trim
()
]
h/static/scripts/annotator/plugin/textrange.coffee
View file @
7faa6cec
...
...
@@ -30,11 +30,9 @@ class TextRangeAnchor extends Annotator.Anchor
@
Annotator
=
TextRangeAnchor
.
Annotator
# This is how we create a highlight out of this kind of anchor
_createHighlight
:
->
# Create the highligh
new
@
Annotator
.
TextHighlight
this
,
0
,
@
range
_getSegment
:
->
type
:
"magic range"
data
:
@
range
# Annotator plugin for creating, and anchoring based on text range
# selectors
...
...
@@ -44,13 +42,15 @@ class Annotator.Plugin.TextRange extends Annotator.Plugin
@
Annotator
=
Annotator
@
anchoring
=
@
annotator
.
anchoring
# Register the creator for range selectors
@
an
notator
.
selectorCreators
.
push
@
an
choring
.
selectorCreators
.
push
name
:
"RangeSelector"
describe
:
@
_getRangeSelector
# Register our anchoring strategies
@
an
notator
.
anchoringS
trategies
.
push
@
an
choring
.
s
trategies
.
push
# Simple strategy based on DOM Range
name
:
"range"
code
:
@
createFromRangeSelector
...
...
@@ -74,7 +74,10 @@ class Annotator.Plugin.TextRange extends Annotator.Plugin
# Create and anchor using the saved Range selector.
# The quote is verified.
createFromRangeSelector
:
(
annotation
,
target
)
=>
selector
=
@
annotator
.
findSelector
target
.
selector
,
"RangeSelector"
document
=
@
anchoring
.
document
selector
=
@
anchoring
.
findSelector
target
.
selector
,
"RangeSelector"
unless
selector
?
then
return
null
# Try to apply the saved XPath
...
...
@@ -85,24 +88,24 @@ class Annotator.Plugin.TextRange extends Annotator.Plugin
return
null
# Get the text of this range
if
@
annotator
.
domMapper
.
getInfoForNode
?
if
document
.
getInfoForNode
?
# Determine the current content of the given range using DTM
startInfo
=
@
annotator
.
domMapper
.
getInfoForNode
normedRange
.
start
startInfo
=
document
.
getInfoForNode
normedRange
.
start
return
null
unless
startInfo
# Don't fret if page is not mapped
startOffset
=
startInfo
.
start
endInfo
=
@
annotator
.
domMapper
.
getInfoForNode
normedRange
.
end
endInfo
=
document
.
getInfoForNode
normedRange
.
end
return
null
unless
endInfo
# Don't fret if page is not mapped
endOffset
=
endInfo
.
end
rawQuote
=
@
annotator
.
domMapper
.
getCorpus
()[
startOffset
..
endOffset
-
1
].
trim
()
rawQuote
=
document
.
getCorpus
()[
startOffset
..
endOffset
-
1
].
trim
()
else
# Determine the current content of the given range directly
rawQuote
=
normedRange
.
text
().
trim
()
currentQuote
=
@
an
notator
.
normalizeString
rawQuote
currentQuote
=
@
an
choring
.
normalizeString
rawQuote
# Look up the saved quote
savedQuote
=
@
an
notator
.
getQuoteForTarget
?
target
savedQuote
=
@
an
choring
.
getQuoteForTarget
?
target
if
savedQuote
?
and
currentQuote
isnt
savedQuote
#console.log "Could not apply XPath selector to current document, " +
# "because the quote has changed. (Saved quote is '#{savedQuote}'." +
...
...
@@ -113,12 +116,13 @@ class Annotator.Plugin.TextRange extends Annotator.Plugin
# Create a TextPositionAnchor from the start and end offsets
# of this range
# (to be used with dom-text-mapper)
new
@
Annotator
.
TextPositionAnchor
@
an
notator
,
annotation
,
target
,
new
@
Annotator
.
TextPositionAnchor
@
an
choring
,
annotation
,
target
,
startInfo
.
start
,
endInfo
.
end
,
(
startInfo
.
pageIndex
?
0
),
(
endInfo
.
pageIndex
?
0
),
currentQuote
else
# Create a TextRangeAnchor from this range
# (to be used whithout dom-text-mapper)
new
TextRangeAnchor
@
an
notator
,
annotation
,
target
,
new
TextRangeAnchor
@
an
choring
,
annotation
,
target
,
normedRange
,
currentQuote
h/static/scripts/annotator/plugin/text
anchors
.coffee
→
h/static/scripts/annotator/plugin/text
selection
.coffee
View file @
7faa6cec
# This plugin implements the UI code for creating text annotations
class
Annotator
.
Plugin
.
Text
Anchors
extends
Annotator
.
Plugin
class
Annotator
.
Plugin
.
Text
Selection
extends
Annotator
.
Plugin
# Plugin initialization
pluginInit
:
->
# We need text highlights
unless
@
annotator
.
plugins
.
TextHighlights
throw
new
Error
"The Text
Anchors
Annotator plugin requires the TextHighlights plugin."
throw
new
Error
"The Text
Selection
Annotator plugin requires the TextHighlights plugin."
@
Annotator
=
Annotator
@
$
=
Annotator
.
$
...
...
@@ -114,3 +113,4 @@ class Annotator.Plugin.TextAnchors extends Annotator.Plugin
@
annotator
.
onFailedSelection
event
# Strategies used for creating anchors from saved data
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