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
4efa180a
Commit
4efa180a
authored
May 16, 2017
by
Sean Roberts
Committed by
GitHub
May 16, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #380 from evidentpoint/remove-annotator-dep
Remove dependency Annotator.js
parents
5e284a96
54d8378f
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
629 additions
and
2333 deletions
+629
-2333
delegator.coffee
src/annotator/delegator.coffee
+265
-0
guest.coffee
src/annotator/guest.coffee
+44
-22
host.coffee
src/annotator/host.coffee
+3
-4
main.js
src/annotator/main.js
+21
-22
plugin.coffee
src/annotator/plugin.coffee
+8
-0
bucket-bar.coffee
src/annotator/plugin/bucket-bar.coffee
+3
-3
cross-frame.coffee
src/annotator/plugin/cross-frame.coffee
+11
-6
document.coffee
src/annotator/plugin/document.coffee
+170
-0
pdf.coffee
src/annotator/plugin/pdf.coffee
+2
-3
cross-frame-test.coffee
src/annotator/plugin/test/cross-frame-test.coffee
+25
-9
toolbar.coffee
src/annotator/plugin/toolbar.coffee
+3
-3
sidebar.coffee
src/annotator/sidebar.coffee
+1
-0
guest-test.coffee
src/annotator/test/guest-test.coffee
+50
-10
host-test.coffee
src/annotator/test/host-test.coffee
+4
-8
anchoring-test.js
src/annotator/test/integration/anchoring-test.js
+3
-4
sidebar-test.coffee
src/annotator/test/sidebar-test.coffee
+16
-6
annotator.document.js
src/annotator/vendor/annotator.document.js
+0
-285
annotator.js
src/annotator/vendor/annotator.js
+0
-1948
No files found.
src/annotator/delegator.coffee
0 → 100644
View file @
4efa180a
$
=
require
(
'jquery'
)
###
** Adapted from:
** https://github.com/openannotation/annotator/blob/v1.2.x/src/class.coffee
**
** Annotator v1.2.10
** https://github.com/openannotation/annotator
**
** Copyright 2015, the Annotator project contributors.
** Dual licensed under the MIT and GPLv3 licenses.
** https://github.com/openannotation/annotator/blob/master/LICENSE
###
# Public: Delegator is the base class that all of Annotators objects inherit
# from. It provides basic functionality such as instance options, event
# delegation and pub/sub methods.
module
.
exports
=
class
Delegator
# Public: Events object. This contains a key/pair hash of events/methods that
# should be bound. See Delegator#addEvents() for usage.
events
:
{}
# Public: Options object. Extended on initialisation.
options
:
{}
# A jQuery object wrapping the DOM Element provided on initialisation.
element
:
null
# Public: Constructor function that sets up the instance. Binds the @events
# hash and extends the @options object.
#
# element - The DOM element that this instance represents.
# options - An Object literal of options.
#
# Examples
#
# element = document.getElementById('my-element')
# instance = new Delegator(element, {
# option: 'my-option'
# })
#
# Returns a new instance of Delegator.
constructor
:
(
element
,
options
)
->
@
options
=
$
.
extend
(
true
,
{},
@
options
,
options
)
@
element
=
$
(
element
)
# Delegator creates closures for each event it binds. This is a private
# registry of created closures, used to enable event unbinding.
@
_closures
=
{}
this
.
on
=
this
.
subscribe
this
.
addEvents
()
# Public: Destroy the instance, unbinding all events.
#
# Returns nothing.
destroy
:
->
this
.
removeEvents
()
# Public: binds the function names in the @events Object to their events.
#
# The @events Object should be a set of key/value pairs where the key is the
# event name with optional CSS selector. The value should be a String method
# name on the current class.
#
# This is called by the default Delegator constructor and so shouldn't usually
# need to be called by the user.
#
# Examples
#
# # This will bind the clickedElement() method to the click event on @element.
# @options = {"click": "clickedElement"}
#
# # This will delegate the submitForm() method to the submit event on the
# # form within the @element.
# @options = {"form submit": "submitForm"}
#
# # This will bind the updateAnnotationStore() method to the custom
# # annotation:save event. NOTE: Because this is a custom event the
# # Delegator#subscribe() method will be used and updateAnnotationStore()
# # will not receive an event parameter like the previous two examples.
# @options = {"annotation:save": "updateAnnotationStore"}
#
# Returns nothing.
addEvents
:
->
for
event
in
Delegator
.
_parseEvents
(
@
events
)
this
.
_addEvent
event
.
selector
,
event
.
event
,
event
.
functionName
# Public: unbinds functions previously bound to events by addEvents().
#
# The @events Object should be a set of key/value pairs where the key is the
# event name with optional CSS selector. The value should be a String method
# name on the current class.
#
# Returns nothing.
removeEvents
:
->
for
event
in
Delegator
.
_parseEvents
(
@
events
)
this
.
_removeEvent
event
.
selector
,
event
.
event
,
event
.
functionName
# Binds an event to a callback function represented by a String. A selector
# can be provided in order to watch for events on a child element.
#
# The event can be any standard event supported by jQuery or a custom String.
# If a custom string is used the callback function will not recieve an
# event object as it's first parameter.
#
# selector - Selector String matching child elements. (default: '')
# event - The event to listen for.
# functionName - A String function name to bind to the event.
#
# Examples
#
# # Listens for all click events on instance.element.
# instance._addEvent('', 'click', 'onClick')
#
# # Delegates the instance.onInputFocus() method to focus events on all
# # form inputs within instance.element.
# instance._addEvent('form :input', 'focus', 'onInputFocus')
#
# Returns itself.
_addEvent
:
(
selector
,
event
,
functionName
)
->
closure
=
=>
this
[
functionName
].
apply
(
this
,
arguments
)
if
selector
==
''
and
Delegator
.
_isCustomEvent
(
event
)
this
.
subscribe
(
event
,
closure
)
else
@
element
.
delegate
(
selector
,
event
,
closure
)
@
_closures
[
"
#{
selector
}
/
#{
event
}
/
#{
functionName
}
"
]
=
closure
this
# Unbinds a function previously bound to an event by the _addEvent method.
#
# Takes the same arguments as _addEvent(), and an event will only be
# successfully unbound if the arguments to removeEvent() are exactly the same
# as the original arguments to _addEvent(). This would usually be called by
# _removeEvents().
#
# selector - Selector String matching child elements. (default: '')
# event - The event to listen for.
# functionName - A String function name to bind to the event.
#
# Returns itself.
_removeEvent
:
(
selector
,
event
,
functionName
)
->
closure
=
@
_closures
[
"
#{
selector
}
/
#{
event
}
/
#{
functionName
}
"
]
if
selector
==
''
and
Delegator
.
_isCustomEvent
(
event
)
this
.
unsubscribe
(
event
,
closure
)
else
@
element
.
undelegate
(
selector
,
event
,
closure
)
delete
@
_closures
[
"
#{
selector
}
/
#{
event
}
/
#{
functionName
}
"
]
this
# Public: Fires an event and calls all subscribed callbacks with any parameters
# provided. This is essentially an alias of @element.triggerHandler() but
# should be used to fire custom events.
#
# NOTE: Events fired using .publish() will not bubble up the DOM.
#
# event - A String event name.
# params - An Array of parameters to provide to callbacks.
#
# Examples
#
# instance.subscribe('annotation:save', (msg) -> console.log(msg))
# instance.publish('annotation:save', ['Hello World'])
# # => Outputs "Hello World"
#
# Returns itself.
publish
:
()
->
@
element
.
triggerHandler
.
apply
@
element
,
arguments
this
# Public: Listens for custom event which when published will call the provided
# callback. This is essentially a wrapper around @element.bind() but removes
# the event parameter that jQuery event callbacks always recieve. These
# parameters are unnessecary for custom events.
#
# event - A String event name.
# callback - A callback function called when the event is published.
#
# Examples
#
# instance.subscribe('annotation:save', (msg) -> console.log(msg))
# instance.publish('annotation:save', ['Hello World'])
# # => Outputs "Hello World"
#
# Returns itself.
subscribe
:
(
event
,
callback
)
->
closure
=
->
callback
.
apply
(
this
,
[].
slice
.
call
(
arguments
,
1
))
# Ensure both functions have the same unique id so that jQuery will accept
# callback when unbinding closure.
closure
.
guid
=
callback
.
guid
=
(
$
.
guid
+=
1
)
@
element
.
bind
event
,
closure
this
# Public: Unsubscribes a callback from an event. The callback will no longer
# be called when the event is published.
#
# event - A String event name.
# callback - A callback function to be removed.
#
# Examples
#
# callback = (msg) -> console.log(msg)
# instance.subscribe('annotation:save', callback)
# instance.publish('annotation:save', ['Hello World'])
# # => Outputs "Hello World"
#
# instance.unsubscribe('annotation:save', callback)
# instance.publish('annotation:save', ['Hello Again'])
# # => No output.
#
# Returns itself.
unsubscribe
:
->
@
element
.
unbind
.
apply
@
element
,
arguments
this
# Parse the @events object of a Delegator into an array of objects containing
# string-valued "selector", "event", and "func" keys.
Delegator
.
_parseEvents
=
(
eventsObj
)
->
events
=
[]
for
sel
,
functionName
of
eventsObj
[
selector
...,
event
]
=
sel
.
split
' '
events
.
push
({
selector
:
selector
.
join
(
' '
),
event
:
event
,
functionName
:
functionName
})
return
events
# Native jQuery events that should recieve an event object. Plugins can
# add their own methods to this if required.
Delegator
.
natives
=
do
->
specials
=
(
key
for
own
key
,
val
of
$
.
event
.
special
)
"""
blur focus focusin focusout load resize scroll unload click dblclick
mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave
change select submit keydown keypress keyup error
"""
.
split
(
/[^a-z]+/
).
concat
(
specials
)
# Checks to see if the provided event is a DOM event supported by jQuery or
# a custom user event.
#
# event - String event name.
#
# Examples
#
# Delegator._isCustomEvent('click') # => false
# Delegator._isCustomEvent('mousedown') # => false
# Delegator._isCustomEvent('annotation:created') # => true
#
# Returns true if event is a custom user event.
Delegator
.
_isCustomEvent
=
(
event
)
->
[
event
]
=
event
.
split
(
'.'
)
$
.
inArray
(
event
,
Delegator
.
natives
)
==
-
1
src/annotator/guest.coffee
View file @
4efa180a
...
@@ -3,8 +3,8 @@ extend = require('extend')
...
@@ -3,8 +3,8 @@ extend = require('extend')
raf
=
require
(
'raf'
)
raf
=
require
(
'raf'
)
scrollIntoView
=
require
(
'scroll-into-view'
)
scrollIntoView
=
require
(
'scroll-into-view'
)
Annotator
=
require
(
'annot
ator'
)
Delegator
=
require
(
'./deleg
ator'
)
$
=
Annotator
.
$
$
=
require
(
'jquery'
)
adder
=
require
(
'./adder'
)
adder
=
require
(
'./adder'
)
highlighter
=
require
(
'./highlighter'
)
highlighter
=
require
(
'./highlighter'
)
...
@@ -31,7 +31,7 @@ normalizeURI = (uri, baseURI) ->
...
@@ -31,7 +31,7 @@ normalizeURI = (uri, baseURI) ->
# See https://github.com/hypothesis/h/issues/3471#issuecomment-226713750
# See https://github.com/hypothesis/h/issues/3471#issuecomment-226713750
return
url
.
toString
().
replace
(
/#.*/
,
''
);
return
url
.
toString
().
replace
(
/#.*/
,
''
);
module
.
exports
=
class
Guest
extends
Annot
ator
module
.
exports
=
class
Guest
extends
Deleg
ator
SHOW_HIGHLIGHTS_CLASS
=
'annotator-highlights-always-on'
SHOW_HIGHLIGHTS_CLASS
=
'annotator-highlights-always-on'
# Events to be bound on Annotator#element.
# Events to be bound on Annotator#element.
...
@@ -48,24 +48,41 @@ module.exports = class Guest extends Annotator
...
@@ -48,24 +48,41 @@ module.exports = class Guest extends Annotator
anchoring
:
require
(
'./anchoring/html'
)
anchoring
:
require
(
'./anchoring/html'
)
# Internal state
# Internal state
plugins
:
null
anchors
:
null
anchors
:
null
visibleHighlights
:
false
visibleHighlights
:
false
html
:
extend
{},
Annotator
::
html
,
html
:
adder
:
'<hypothesis-adder></hypothesis-adder>'
;
adder
:
'<hypothesis-adder></hypothesis-adder>'
wrapper
:
'<div class="annotator-wrapper"></div>'
addPlugin
:
(
name
,
options
)
->
if
@
plugins
[
name
]
console
.
error
(
"You cannot have more than one instance of any plugin."
)
else
klass
=
@
options
.
pluginClasses
[
name
]
if
typeof
klass
is
'function'
@
plugins
[
name
]
=
new
klass
(
@
element
[
0
],
options
)
@
plugins
[
name
].
annotator
=
this
@
plugins
[
name
].
pluginInit
?
()
else
console
.
error
(
"Could not load "
+
name
+
" plugin. Have you included the appropriate <script> tag?"
)
this
# allow chaining
constructor
:
(
element
,
options
)
->
constructor
:
(
element
,
options
)
->
super
super
this
.
adder
=
$
(
this
.
html
.
adder
).
appendTo
(
@
element
).
hide
()
self
=
this
self
=
this
this
.
adderCtrl
=
new
adder
.
Adder
(
@
adder
[
0
],
{
this
.
adderCtrl
=
new
adder
.
Adder
(
@
adder
[
0
],
{
onAnnotate
:
->
onAnnotate
:
->
self
.
createAnnotation
()
self
.
createAnnotation
()
Annotator
.
Util
.
getGlobal
()
.
getSelection
().
removeAllRanges
()
document
.
getSelection
().
removeAllRanges
()
onHighlight
:
->
onHighlight
:
->
self
.
setVisibleHighlights
(
true
)
self
.
setVisibleHighlights
(
true
)
self
.
createHighlight
()
self
.
createHighlight
()
Annotator
.
Util
.
getGlobal
()
.
getSelection
().
removeAllRanges
()
document
.
getSelection
().
removeAllRanges
()
})
})
this
.
selections
=
selections
(
document
).
subscribe
this
.
selections
=
selections
(
document
).
subscribe
next
:
(
range
)
->
next
:
(
range
)
->
...
@@ -74,6 +91,7 @@ module.exports = class Guest extends Annotator
...
@@ -74,6 +91,7 @@ module.exports = class Guest extends Annotator
else
else
self
.
_onClearSelection
()
self
.
_onClearSelection
()
this
.
plugins
=
{}
this
.
anchors
=
[]
this
.
anchors
=
[]
cfOptions
=
cfOptions
=
...
@@ -91,7 +109,7 @@ module.exports = class Guest extends Annotator
...
@@ -91,7 +109,7 @@ module.exports = class Guest extends Annotator
# Load plugins
# Load plugins
for
own
name
,
opts
of
@
options
for
own
name
,
opts
of
@
options
if
not
@
plugins
[
name
]
and
Annotator
.
Plugin
[
name
]
if
not
@
plugins
[
name
]
and
@
options
.
pluginClasses
[
name
]
this
.
addPlugin
(
name
,
opts
)
this
.
addPlugin
(
name
,
opts
)
# Get the document info
# Get the document info
...
@@ -142,16 +160,6 @@ module.exports = class Guest extends Annotator
...
@@ -142,16 +160,6 @@ module.exports = class Guest extends Annotator
crossframe
.
on
'setVisibleHighlights'
,
(
state
)
=>
crossframe
.
on
'setVisibleHighlights'
,
(
state
)
=>
this
.
setVisibleHighlights
(
state
)
this
.
setVisibleHighlights
(
state
)
_setupWrapper
:
->
@
wrapper
=
@
element
this
# These methods aren't used in the iframe-hosted configuration of Annotator.
_setupViewer
:
->
this
_setupEditor
:
->
this
_setupDocumentEvents
:
->
this
_setupDynamicStyle
:
->
this
destroy
:
->
destroy
:
->
$
(
'#annotator-dynamic-style'
).
remove
()
$
(
'#annotator-dynamic-style'
).
remove
()
...
@@ -167,7 +175,7 @@ module.exports = class Guest extends Annotator
...
@@ -167,7 +175,7 @@ module.exports = class Guest extends Annotator
for
name
,
plugin
of
@
plugins
for
name
,
plugin
of
@
plugins
@
plugins
[
name
].
destroy
()
@
plugins
[
name
].
destroy
()
this
.
removeEvents
()
super
anchor
:
(
annotation
)
->
anchor
:
(
annotation
)
->
self
=
this
self
=
this
...
@@ -348,6 +356,20 @@ module.exports = class Guest extends Annotator
...
@@ -348,6 +356,20 @@ module.exports = class Guest extends Annotator
annotation
annotation
# Public: Deletes the annotation by removing the highlight from the DOM.
# Publishes the 'annotationDeleted' event on completion.
#
# annotation - An annotation Object to delete.
#
# Returns deleted annotation.
deleteAnnotation
:
(
annotation
)
->
if
annotation
.
highlights
?
for
h
in
annotation
.
highlights
when
h
.
parentNode
?
$
(
h
).
replaceWith
(
h
.
childNodes
)
this
.
publish
(
'annotationDeleted'
,
[
annotation
])
annotation
showAnnotations
:
(
annotations
)
->
showAnnotations
:
(
annotations
)
->
tags
=
(
a
.
$tag
for
a
in
annotations
)
tags
=
(
a
.
$tag
for
a
in
annotations
)
@
crossframe
?
.
call
(
'showAnnotations'
,
tags
)
@
crossframe
?
.
call
(
'showAnnotations'
,
tags
)
...
@@ -365,7 +387,7 @@ module.exports = class Guest extends Annotator
...
@@ -365,7 +387,7 @@ module.exports = class Guest extends Annotator
@
crossframe
?
.
call
(
'focusAnnotations'
,
tags
)
@
crossframe
?
.
call
(
'focusAnnotations'
,
tags
)
_onSelection
:
(
range
)
->
_onSelection
:
(
range
)
->
selection
=
Annotator
.
Util
.
getGlobal
()
.
getSelection
()
selection
=
document
.
getSelection
()
isBackwards
=
rangeUtil
.
isSelectionBackwards
(
selection
)
isBackwards
=
rangeUtil
.
isSelectionBackwards
(
selection
)
focusRect
=
rangeUtil
.
selectionFocusRect
(
selection
)
focusRect
=
rangeUtil
.
selectionFocusRect
(
selection
)
if
!
focusRect
if
!
focusRect
...
@@ -375,7 +397,7 @@ module.exports = class Guest extends Annotator
...
@@ -375,7 +397,7 @@ module.exports = class Guest extends Annotator
@
selectedRanges
=
[
range
]
@
selectedRanges
=
[
range
]
Annotator
.
$
(
'.annotator-toolbar .h-icon-note'
)
$
(
'.annotator-toolbar .h-icon-note'
)
.
attr
(
'title'
,
'New Annotation'
)
.
attr
(
'title'
,
'New Annotation'
)
.
removeClass
(
'h-icon-note'
)
.
removeClass
(
'h-icon-note'
)
.
addClass
(
'h-icon-annotate'
);
.
addClass
(
'h-icon-annotate'
);
...
@@ -387,7 +409,7 @@ module.exports = class Guest extends Annotator
...
@@ -387,7 +409,7 @@ module.exports = class Guest extends Annotator
this
.
adderCtrl
.
hide
()
this
.
adderCtrl
.
hide
()
@
selectedRanges
=
[]
@
selectedRanges
=
[]
Annotator
.
$
(
'.annotator-toolbar .h-icon-annotate'
)
$
(
'.annotator-toolbar .h-icon-annotate'
)
.
attr
(
'title'
,
'New Page Note'
)
.
attr
(
'title'
,
'New Page Note'
)
.
removeClass
(
'h-icon-annotate'
)
.
removeClass
(
'h-icon-annotate'
)
.
addClass
(
'h-icon-note'
);
.
addClass
(
'h-icon-note'
);
...
...
src/annotator/host.coffee
View file @
4efa180a
Annotator
=
require
(
'annotator'
)
$
=
require
(
'jquery'
)
$
=
Annotator
.
$
Guest
=
require
(
'./guest'
)
Guest
=
require
(
'./guest'
)
module
.
exports
=
class
Host
extends
Guest
module
.
exports
=
class
Host
extends
Guest
constructor
:
(
element
,
options
)
->
constructor
:
(
element
,
options
)
->
# Make a copy of all options except `options.app`, the app base URL
.
# Make a copy of all options except `options.app`, the app base URL
, and `options.pluginClasses`
configParam
=
'config='
+
encodeURIComponent
(
configParam
=
'config='
+
encodeURIComponent
(
JSON
.
stringify
(
Object
.
assign
({},
options
,
{
app
:
undefined
}))
JSON
.
stringify
(
Object
.
assign
({},
options
,
{
app
:
undefined
,
pluginClasses
:
undefined
}))
)
)
if
options
.
app
and
'?'
in
options
.
app
if
options
.
app
and
'?'
in
options
.
app
options
.
app
+=
'&'
+
configParam
options
.
app
+=
'&'
+
configParam
...
...
src/annotator/main.js
View file @
4efa180a
...
@@ -2,7 +2,6 @@
...
@@ -2,7 +2,6 @@
require
(
'../shared/polyfills'
);
require
(
'../shared/polyfills'
);
var
Annotator
=
require
(
'annotator'
);
// Polyfills
// Polyfills
...
@@ -13,44 +12,44 @@ var Annotator = require('annotator');
...
@@ -13,44 +12,44 @@ var Annotator = require('annotator');
if
(
!
window
.
document
.
evaluate
)
{
if
(
!
window
.
document
.
evaluate
)
{
require
(
'./vendor/wgxpath.install'
);
require
(
'./vendor/wgxpath.install'
);
}
}
var
g
=
Annotator
.
Util
.
getGlobal
();
if
(
window
.
wgxpath
)
{
if
(
g
.
wgxpath
)
{
window
.
wgxpath
.
install
();
g
.
wgxpath
.
install
();
}
}
var
$
=
require
(
'jquery'
);
// Applications
// Applications
Annotator
.
Guest
=
require
(
'./guest'
);
var
Sidebar
=
require
(
'./sidebar'
);
Annotator
.
Host
=
require
(
'./host'
);
var
PdfSidebar
=
require
(
'./pdf-sidebar'
);
Annotator
.
Sidebar
=
require
(
'./sidebar'
);
Annotator
.
PdfSidebar
=
require
(
'./pdf-sidebar'
);
// UI plugins
var
pluginClasses
=
{
Annotator
.
Plugin
.
BucketBar
=
require
(
'./plugin/bucket-bar'
);
// UI plugins
Annotator
.
Plugin
.
Toolbar
=
require
(
'./plugin/toolbar'
);
BucketBar
:
require
(
'./plugin/bucket-bar'
),
Toolbar
:
require
(
'./plugin/toolbar'
),
// Document type plugins
// Document type plugins
Annotator
.
Plugin
.
PDF
=
require
(
'./plugin/pdf'
);
PDF
:
require
(
'./plugin/pdf'
),
require
(
'./vendor/annotator.document'
);
// Does not export the plugin :(
Document
:
require
(
'./plugin/document'
),
// Cross-frame communication
// Cross-frame communication
Annotator
.
Plugin
.
CrossFrame
=
require
(
'./plugin/cross-frame'
);
CrossFrame
:
require
(
'./plugin/cross-frame'
),
Annotator
.
Plugin
.
CrossFrame
.
AnnotationSync
=
require
(
'./annotation-sync'
);
};
Annotator
.
Plugin
.
CrossFrame
.
Bridge
=
require
(
'../shared/bridge'
);
Annotator
.
Plugin
.
CrossFrame
.
Discovery
=
require
(
'../shared/discovery'
);
var
appLinkEl
=
var
appLinkEl
=
document
.
querySelector
(
'link[type="application/annotator+html"]'
);
document
.
querySelector
(
'link[type="application/annotator+html"]'
);
var
options
=
require
(
'./config'
)(
window
);
var
options
=
require
(
'./config'
)(
window
);
Annotator
.
noConflict
().
$
.
noConflict
(
true
)(
function
()
{
$
.
noConflict
(
true
)(
function
()
{
var
Klass
=
window
.
PDFViewerApplication
?
var
Klass
=
window
.
PDFViewerApplication
?
Annotator
.
PdfSidebar
:
PdfSidebar
:
Annotator
.
Sidebar
;
Sidebar
;
if
(
options
.
hasOwnProperty
(
'constructor'
))
{
if
(
options
.
hasOwnProperty
(
'constructor'
))
{
Klass
=
options
.
constructor
;
Klass
=
options
.
constructor
;
delete
options
.
constructor
;
delete
options
.
constructor
;
}
}
options
.
pluginClasses
=
pluginClasses
;
window
.
annotator
=
new
Klass
(
document
.
body
,
options
);
window
.
annotator
=
new
Klass
(
document
.
body
,
options
);
appLinkEl
.
addEventListener
(
'destroy'
,
function
()
{
appLinkEl
.
addEventListener
(
'destroy'
,
function
()
{
appLinkEl
.
parentElement
.
removeChild
(
appLinkEl
);
appLinkEl
.
parentElement
.
removeChild
(
appLinkEl
);
...
...
src/annotator/plugin.coffee
0 → 100644
View file @
4efa180a
Delegator
=
require
(
'./delegator'
)
module
.
exports
=
class
Plugin
extends
Delegator
constructor
:
(
element
,
options
)
->
super
pluginInit
:
()
->
src/annotator/plugin/bucket-bar.coffee
View file @
4efa180a
raf
=
require
(
'raf'
)
raf
=
require
(
'raf'
)
Annotator
=
require
(
'annotator
'
)
$
=
require
(
'jquery
'
)
$
=
Annotator
.
$
Plugin
=
require
(
'../plugin'
)
scrollIntoView
=
require
(
'scroll-into-view'
)
scrollIntoView
=
require
(
'scroll-into-view'
)
...
@@ -42,7 +42,7 @@ scrollToClosest = (anchors, direction) ->
...
@@ -42,7 +42,7 @@ scrollToClosest = (anchors, direction) ->
scrollIntoView
(
next
.
highlights
[
0
])
scrollIntoView
(
next
.
highlights
[
0
])
module
.
exports
=
class
BucketBar
extends
Annotator
.
Plugin
module
.
exports
=
class
BucketBar
extends
Plugin
# svg skeleton
# svg skeleton
html
:
"""
html
:
"""
<div class="annotator-bucket-bar">
<div class="annotator-bucket-bar">
...
...
src/annotator/plugin/cross-frame.coffee
View file @
4efa180a
Annotator
=
require
(
'annotator'
)
Plugin
=
require
(
'../plugin'
)
AnnotationSync
=
require
(
'../annotation-sync'
)
Bridge
=
require
(
'../../shared/bridge'
)
Discovery
=
require
(
'../../shared/discovery'
)
# 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
...)
->
...
@@ -11,17 +16,17 @@ extract = extract = (obj, keys...) ->
...
@@ -11,17 +16,17 @@ extract = extract = (obj, keys...) ->
# 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.
module
.
exports
=
class
CrossFrame
extends
Annotator
.
Plugin
module
.
exports
=
class
CrossFrame
extends
Plugin
constructor
:
(
elem
,
options
)
->
constructor
:
(
elem
,
options
)
->
super
super
opts
=
extract
(
options
,
'server'
)
opts
=
extract
(
options
,
'server'
)
discovery
=
new
CrossFrame
.
Discovery
(
window
,
opts
)
discovery
=
new
Discovery
(
window
,
opts
)
bridge
=
new
CrossFrame
.
Bridge
()
bridge
=
new
Bridge
()
opts
=
extract
(
options
,
'on'
,
'emit'
)
opts
=
extract
(
options
,
'on'
,
'emit'
)
annotationSync
=
new
CrossFrame
.
AnnotationSync
(
bridge
,
opts
)
annotationSync
=
new
AnnotationSync
(
bridge
,
opts
)
this
.
pluginInit
=
->
this
.
pluginInit
=
->
onDiscoveryCallback
=
(
source
,
origin
,
token
)
->
onDiscoveryCallback
=
(
source
,
origin
,
token
)
->
...
@@ -30,7 +35,7 @@ module.exports = class CrossFrame extends Annotator.Plugin
...
@@ -30,7 +35,7 @@ module.exports = class CrossFrame extends Annotator.Plugin
this
.
destroy
=
->
this
.
destroy
=
->
# super doesnt work here :(
# super doesnt work here :(
Annotator
.
Plugin
::
destroy
.
apply
(
this
,
arguments
)
Plugin
::
destroy
.
apply
(
this
,
arguments
)
bridge
.
destroy
()
bridge
.
destroy
()
discovery
.
stopDiscovery
()
discovery
.
stopDiscovery
()
...
...
src/annotator/plugin/document.coffee
0 → 100644
View file @
4efa180a
$
=
require
(
'jquery'
)
Plugin
=
require
(
'../plugin'
)
###
** Adapted from:
** https://github.com/openannotation/annotator/blob/v1.2.x/src/plugin/document.coffee
**
** Annotator v1.2.10
** https://github.com/openannotation/annotator
**
** Copyright 2015, the Annotator project contributors.
** Dual licensed under the MIT and GPLv3 licenses.
** https://github.com/openannotation/annotator/blob/master/LICENSE
###
module
.
exports
=
class
Document
extends
Plugin
events
:
'beforeAnnotationCreated'
:
'beforeAnnotationCreated'
pluginInit
:
->
this
.
getDocumentMetadata
()
# returns the primary URI for the document being annotated
uri
:
=>
uri
=
decodeURIComponent
document
.
location
.
href
for
link
in
@
metadata
.
link
if
link
.
rel
==
"canonical"
uri
=
link
.
href
return
uri
# returns all uris for the document being annotated
uris
:
=>
uniqueUrls
=
{}
for
link
in
@
metadata
.
link
uniqueUrls
[
link
.
href
]
=
true
if
link
.
href
return
(
href
for
href
of
uniqueUrls
)
beforeAnnotationCreated
:
(
annotation
)
=>
annotation
.
document
=
@
metadata
getDocumentMetadata
:
=>
@
metadata
=
{}
# first look for some common metadata types
# TODO: look for microdata/rdfa?
this
.
_getHighwire
()
this
.
_getDublinCore
()
this
.
_getFacebook
()
this
.
_getEprints
()
this
.
_getPrism
()
this
.
_getTwitter
()
this
.
_getFavicon
()
# extract out/normalize some things
this
.
_getTitle
()
this
.
_getLinks
()
return
@
metadata
_getHighwire
:
=>
return
@
metadata
.
highwire
=
this
.
_getMetaTags
(
"citation"
,
"name"
,
"_"
)
_getFacebook
:
=>
return
@
metadata
.
facebook
=
this
.
_getMetaTags
(
"og"
,
"property"
,
":"
)
_getTwitter
:
=>
return
@
metadata
.
twitter
=
this
.
_getMetaTags
(
"twitter"
,
"name"
,
":"
)
_getDublinCore
:
=>
return
@
metadata
.
dc
=
this
.
_getMetaTags
(
"dc"
,
"name"
,
"."
)
_getPrism
:
=>
return
@
metadata
.
prism
=
this
.
_getMetaTags
(
"prism"
,
"name"
,
"."
)
_getEprints
:
=>
return
@
metadata
.
eprints
=
this
.
_getMetaTags
(
"eprints"
,
"name"
,
"."
)
_getMetaTags
:
(
prefix
,
attribute
,
delimiter
)
=>
tags
=
{}
for
meta
in
$
(
"meta"
)
name
=
$
(
meta
).
attr
(
attribute
)
content
=
$
(
meta
).
prop
(
"content"
)
if
name
match
=
name
.
match
(
RegExp
(
"^
#{
prefix
}#{
delimiter
}
(.+)$"
,
"i"
))
if
match
n
=
match
[
1
]
if
tags
[
n
]
tags
[
n
].
push
(
content
)
else
tags
[
n
]
=
[
content
]
return
tags
_getTitle
:
=>
if
@
metadata
.
highwire
.
title
@
metadata
.
title
=
@
metadata
.
highwire
.
title
[
0
]
else
if
@
metadata
.
eprints
.
title
@
metadata
.
title
=
@
metadata
.
eprints
.
title
[
0
]
else
if
@
metadata
.
prism
.
title
@
metadata
.
title
=
@
metadata
.
prism
.
title
[
0
]
else
if
@
metadata
.
facebook
.
title
@
metadata
.
title
=
@
metadata
.
facebook
.
title
[
0
]
else
if
@
metadata
.
twitter
.
title
@
metadata
.
title
=
@
metadata
.
twitter
.
title
[
0
]
else
if
@
metadata
.
dc
.
title
@
metadata
.
title
=
@
metadata
.
dc
.
title
[
0
]
else
@
metadata
.
title
=
$
(
"head title"
).
text
()
_getLinks
:
=>
# we know our current location is a link for the document
@
metadata
.
link
=
[
href
:
document
.
location
.
href
]
# look for some relevant link relations
for
link
in
$
(
"link"
)
l
=
$
(
link
)
href
=
this
.
_absoluteUrl
(
l
.
prop
(
'href'
))
# get absolute url
rel
=
l
.
prop
(
'rel'
)
type
=
l
.
prop
(
'type'
)
lang
=
l
.
prop
(
'hreflang'
)
if
rel
not
in
[
"alternate"
,
"canonical"
,
"bookmark"
,
"shortlink"
]
then
continue
if
rel
is
'alternate'
# Ignore feeds resources
if
type
and
type
.
match
/^application\/(rss|atom)\+xml/
then
continue
# Ignore alternate languages
if
lang
then
continue
@
metadata
.
link
.
push
(
href
:
href
,
rel
:
rel
,
type
:
type
)
# look for links in scholar metadata
for
name
,
values
of
@
metadata
.
highwire
if
name
==
"pdf_url"
for
url
in
values
@
metadata
.
link
.
push
href
:
this
.
_absoluteUrl
(
url
)
type
:
"application/pdf"
# kind of a hack to express DOI identifiers as links but it's a
# convenient place to look them up later, and somewhat sane since
# they don't have a type
if
name
==
"doi"
for
doi
in
values
if
doi
[
0
..
3
]
!=
"doi:"
doi
=
"doi:"
+
doi
@
metadata
.
link
.
push
(
href
:
doi
)
# look for links in dublincore data
for
name
,
values
of
@
metadata
.
dc
if
name
==
"identifier"
for
id
in
values
if
id
[
0
..
3
]
==
"doi:"
@
metadata
.
link
.
push
(
href
:
id
)
_getFavicon
:
=>
for
link
in
$
(
"link"
)
if
$
(
link
).
prop
(
"rel"
)
in
[
"shortcut icon"
,
"icon"
]
@
metadata
[
"favicon"
]
=
this
.
_absoluteUrl
(
link
.
href
)
# hack to get a absolute url from a possibly relative one
_absoluteUrl
:
(
url
)
->
d
=
document
.
createElement
(
'a'
)
d
.
href
=
url
d
.
href
src/annotator/plugin/pdf.coffee
View file @
4efa180a
extend
=
require
(
'extend'
)
Plugin
=
require
(
'../plugin'
)
Annotator
=
require
(
'annotator'
)
RenderingStates
=
require
(
'../pdfjs-rendering-states'
)
RenderingStates
=
require
(
'../pdfjs-rendering-states'
)
module
.
exports
=
class
PDF
extends
Annotator
.
Plugin
module
.
exports
=
class
PDF
extends
Plugin
documentLoaded
:
null
documentLoaded
:
null
observer
:
null
observer
:
null
pdfViewer
:
null
pdfViewer
:
null
...
...
src/annotator/plugin/test/cross-frame-test.coffee
View file @
4efa180a
CrossFrame
=
require
(
'../cross-frame'
)
proxyquire
=
require
(
'proxyquire'
)
Plugin
=
require
(
'../../plugin'
)
CrossFrame
=
null
describe
'Annotator.Plugin.CrossFrame'
,
->
describe
'Annotator.Plugin.CrossFrame'
,
->
fakeDiscovery
=
null
fakeDiscovery
=
null
fakeBridge
=
null
fakeBridge
=
null
fakeAnnotationSync
=
null
fakeAnnotationSync
=
null
proxyDiscovery
=
null
proxyBridge
=
null
proxyAnnotationSync
=
null
sandbox
=
sinon
.
sandbox
.
create
()
sandbox
=
sinon
.
sandbox
.
create
()
createCrossFrame
=
(
options
)
->
createCrossFrame
=
(
options
)
->
...
@@ -28,9 +36,17 @@ describe 'Annotator.Plugin.CrossFrame', ->
...
@@ -28,9 +36,17 @@ describe 'Annotator.Plugin.CrossFrame', ->
fakeAnnotationSync
=
fakeAnnotationSync
=
sync
:
sandbox
.
stub
()
sync
:
sandbox
.
stub
()
CrossFrame
.
AnnotationSync
=
sandbox
.
stub
().
returns
(
fakeAnnotationSync
)
proxyAnnotationSync
=
sandbox
.
stub
().
returns
(
fakeAnnotationSync
)
CrossFrame
.
Discovery
=
sandbox
.
stub
().
returns
(
fakeDiscovery
)
proxyDiscovery
=
sandbox
.
stub
().
returns
(
fakeDiscovery
)
CrossFrame
.
Bridge
=
sandbox
.
stub
().
returns
(
fakeBridge
)
proxyBridge
=
sandbox
.
stub
().
returns
(
fakeBridge
)
CrossFrame
=
proxyquire
(
'../cross-frame'
,
{
'../plugin'
:
Plugin
,
'../annotation-sync'
:
proxyAnnotationSync
,
'../../shared/bridge'
:
proxyBridge
,
'../../shared/discovery'
:
proxyDiscovery
})
afterEach
->
afterEach
->
sandbox
.
restore
()
sandbox
.
restore
()
...
@@ -38,23 +54,23 @@ describe 'Annotator.Plugin.CrossFrame', ->
...
@@ -38,23 +54,23 @@ describe 'Annotator.Plugin.CrossFrame', ->
describe
'CrossFrame constructor'
,
->
describe
'CrossFrame constructor'
,
->
it
'instantiates the Discovery component'
,
->
it
'instantiates the Discovery component'
,
->
createCrossFrame
()
createCrossFrame
()
assert
.
calledWith
(
CrossFrame
.
Discovery
,
window
)
assert
.
calledWith
(
proxy
Discovery
,
window
)
it
'passes the options along to the bridge'
,
->
it
'passes the options along to the bridge'
,
->
createCrossFrame
(
server
:
true
)
createCrossFrame
(
server
:
true
)
assert
.
calledWith
(
CrossFrame
.
Discovery
,
window
,
server
:
true
)
assert
.
calledWith
(
proxy
Discovery
,
window
,
server
:
true
)
it
'instantiates the CrossFrame component'
,
->
it
'instantiates the CrossFrame component'
,
->
createCrossFrame
()
createCrossFrame
()
assert
.
calledWith
(
CrossFrame
.
Discovery
)
assert
.
calledWith
(
proxy
Discovery
)
it
'instantiates the AnnotationSync component'
,
->
it
'instantiates the AnnotationSync component'
,
->
createCrossFrame
()
createCrossFrame
()
assert
.
called
(
CrossFrame
.
AnnotationSync
)
assert
.
called
(
proxy
AnnotationSync
)
it
'passes along options to AnnotationSync'
,
->
it
'passes along options to AnnotationSync'
,
->
createCrossFrame
()
createCrossFrame
()
assert
.
calledWith
(
CrossFrame
.
AnnotationSync
,
fakeBridge
,
{
assert
.
calledWith
(
proxy
AnnotationSync
,
fakeBridge
,
{
on
:
sinon
.
match
.
func
on
:
sinon
.
match
.
func
emit
:
sinon
.
match
.
func
emit
:
sinon
.
match
.
func
})
})
...
...
src/annotator/plugin/toolbar.coffee
View file @
4efa180a
Annotator
=
require
(
'annotator
'
)
Plugin
=
require
(
'../plugin
'
)
$
=
Annotator
.
$
$
=
require
(
'jquery'
)
makeButton
=
(
item
)
->
makeButton
=
(
item
)
->
anchor
=
$
(
'<button></button>'
)
anchor
=
$
(
'<button></button>'
)
...
@@ -12,7 +12,7 @@ makeButton = (item) ->
...
@@ -12,7 +12,7 @@ makeButton = (item) ->
button
=
$
(
'<li></li>'
).
append
(
anchor
)
button
=
$
(
'<li></li>'
).
append
(
anchor
)
return
button
[
0
]
return
button
[
0
]
module
.
exports
=
class
Toolbar
extends
Annotator
.
Plugin
module
.
exports
=
class
Toolbar
extends
Plugin
HIDE_CLASS
=
'annotator-hide'
HIDE_CLASS
=
'annotator-hide'
events
:
events
:
...
...
src/annotator/sidebar.coffee
View file @
4efa180a
...
@@ -43,6 +43,7 @@ module.exports = class Sidebar extends Host
...
@@ -43,6 +43,7 @@ module.exports = class Sidebar extends Host
@
onSignupRequest
=
serviceConfig
.
onSignupRequest
@
onSignupRequest
=
serviceConfig
.
onSignupRequest
this
.
_setupSidebarEvents
()
this
.
_setupSidebarEvents
()
this
.
_setupDocumentEvents
()
_setupDocumentEvents
:
->
_setupDocumentEvents
:
->
sidebarTrigger
(
document
.
body
,
=>
this
.
show
())
sidebarTrigger
(
document
.
body
,
=>
this
.
show
())
...
...
src/annotator/test/guest-test.coffee
View file @
4efa180a
Annotator
=
require
(
'annotator'
)
proxyquire
=
require
(
'proxyquire'
)
proxyquire
=
require
(
'proxyquire'
)
adder
=
require
(
'../adder'
)
adder
=
require
(
'../adder'
)
Observable
=
require
(
'../util/observable'
).
Observable
Observable
=
require
(
'../util/observable'
).
Observable
Plugin
=
require
(
'../plugin'
)
$
=
Annotator
.
$
Delegator
=
require
(
'../delegator'
)
Annotator
[
'@noCallThru'
]
=
true
;
$
=
require
(
'jquery'
)
Delegator
[
'@noCallThru'
]
=
true
Guest
=
null
Guest
=
null
anchoring
=
{}
anchoring
=
{}
...
@@ -29,6 +30,18 @@ class FakeAdder
...
@@ -29,6 +30,18 @@ class FakeAdder
this
.
showAt
=
sinon
.
stub
()
this
.
showAt
=
sinon
.
stub
()
this
.
target
=
sinon
.
stub
()
this
.
target
=
sinon
.
stub
()
class
FakePlugin
extends
Plugin
instance
:
null
events
:
'customEvent'
:
'customEventHandler'
constructor
:
->
FakePlugin
::
instance
=
this
super
pluginInit
:
sinon
.
stub
()
customEventHandler
:
sinon
.
stub
()
# A little helper which returns a promise that resolves after a timeout
# A little helper which returns a promise that resolves after a timeout
timeoutPromise
=
(
millis
=
0
)
->
timeoutPromise
=
(
millis
=
0
)
->
new
Promise
((
resolve
)
->
setTimeout
(
resolve
,
millis
))
new
Promise
((
resolve
)
->
setTimeout
(
resolve
,
millis
))
...
@@ -37,10 +50,12 @@ describe 'Guest', ->
...
@@ -37,10 +50,12 @@ describe 'Guest', ->
sandbox
=
sinon
.
sandbox
.
create
()
sandbox
=
sinon
.
sandbox
.
create
()
CrossFrame
=
null
CrossFrame
=
null
fakeCrossFrame
=
null
fakeCrossFrame
=
null
guestOptions
=
null
createGuest
=
(
options
)
->
createGuest
=
(
options
=
{})
->
options
=
Object
.
assign
({},
guestOptions
,
options
)
element
=
document
.
createElement
(
'div'
)
element
=
document
.
createElement
(
'div'
)
return
new
Guest
(
element
,
options
||
{}
)
return
new
Guest
(
element
,
options
)
beforeEach
->
beforeEach
->
FakeAdder
::
instance
=
null
FakeAdder
::
instance
=
null
...
@@ -49,6 +64,7 @@ describe 'Guest', ->
...
@@ -49,6 +64,7 @@ describe 'Guest', ->
selectionFocusRect
:
sinon
.
stub
()
selectionFocusRect
:
sinon
.
stub
()
}
}
selections
=
null
selections
=
null
guestOptions
=
{
pluginClasses
:
{}}
Guest
=
proxyquire
(
'../guest'
,
{
Guest
=
proxyquire
(
'../guest'
,
{
'./adder'
:
{
Adder
:
FakeAdder
},
'./adder'
:
{
Adder
:
FakeAdder
},
...
@@ -60,7 +76,7 @@ describe 'Guest', ->
...
@@ -60,7 +76,7 @@ describe 'Guest', ->
selections
=
obs
selections
=
obs
return
()
->
return
()
->
)
)
'
annotator'
:
Annot
ator
,
'
./delegator'
:
Deleg
ator
,
'raf'
:
raf
,
'raf'
:
raf
,
'scroll-into-view'
:
scrollIntoView
,
'scroll-into-view'
:
scrollIntoView
,
})
})
...
@@ -69,15 +85,39 @@ describe 'Guest', ->
...
@@ -69,15 +85,39 @@ describe 'Guest', ->
onConnect
:
sinon
.
stub
()
onConnect
:
sinon
.
stub
()
on
:
sinon
.
stub
()
on
:
sinon
.
stub
()
sync
:
sinon
.
stub
()
sync
:
sinon
.
stub
()
destroy
:
sinon
.
stub
()
}
}
CrossFrame
=
sandbox
.
stub
()
CrossFrame
=
sandbox
.
stub
().
returns
(
fakeCrossFrame
)
CrossFrame
.
returns
(
fakeCrossFrame
)
guestOptions
.
pluginClasses
[
'CrossFrame'
]
=
CrossFrame
Annotator
.
Plugin
.
CrossFrame
=
CrossFrame
afterEach
->
afterEach
->
sandbox
.
restore
()
sandbox
.
restore
()
delete
Annotator
.
Plugin
.
CrossFrame
describe
'plugins'
,
->
fakePlugin
=
null
guest
=
null
beforeEach
->
FakePlugin
::
instance
=
null
guestOptions
.
pluginClasses
[
'FakePlugin'
]
=
FakePlugin
guest
=
createGuest
(
FakePlugin
:
{})
fakePlugin
=
FakePlugin
::
instance
it
'load and "pluginInit" gets called'
,
->
assert
.
calledOnce
(
fakePlugin
.
pluginInit
)
it
'hold reference to instance'
,
->
assert
.
equal
(
fakePlugin
.
annotator
,
guest
)
it
'subscribe to events'
,
->
guest
.
publish
(
'customEvent'
,
[
'1'
,
'2'
])
assert
.
calledWith
(
fakePlugin
.
customEventHandler
,
'1'
,
'2'
)
it
'destroy when instance is destroyed'
,
->
sandbox
.
spy
(
fakePlugin
,
'destroy'
)
guest
.
destroy
()
assert
.
called
(
fakePlugin
.
destroy
)
describe
'cross frame'
,
->
describe
'cross frame'
,
->
...
...
src/annotator/test/host-test.coffee
View file @
4efa180a
Annotator
=
require
(
'annotator'
)
proxyquire
=
require
(
'proxyquire'
)
proxyquire
=
require
(
'proxyquire'
)
Host
=
proxyquire
(
'../host'
,
{
Host
=
proxyquire
(
'../host'
,
{})
'annotator'
:
Annotator
,
})
describe
'Host'
,
->
describe
'Host'
,
->
sandbox
=
sinon
.
sandbox
.
create
()
sandbox
=
sinon
.
sandbox
.
create
()
CrossFrame
=
null
CrossFrame
=
null
fakeCrossFrame
=
null
fakeCrossFrame
=
null
hostOptions
=
{
pluginClasses
:
{}}
createHost
=
(
options
=
{},
element
=
null
)
->
createHost
=
(
options
=
{},
element
=
null
)
->
options
=
Object
.
assign
({
app
:
'/base/annotator/test/empty.html'
},
options
)
options
=
Object
.
assign
({
app
:
'/base/annotator/test/empty.html'
},
hostOptions
,
options
)
if
!
element
if
!
element
element
=
document
.
createElement
(
'div'
)
element
=
document
.
createElement
(
'div'
)
return
new
Host
(
element
,
options
)
return
new
Host
(
element
,
options
)
...
@@ -27,11 +24,10 @@ describe 'Host', ->
...
@@ -27,11 +24,10 @@ describe 'Host', ->
CrossFrame
=
sandbox
.
stub
()
CrossFrame
=
sandbox
.
stub
()
CrossFrame
.
returns
(
fakeCrossFrame
)
CrossFrame
.
returns
(
fakeCrossFrame
)
Annotator
.
Plugin
.
CrossFrame
=
CrossFrame
hostOptions
.
pluginClasses
[
'CrossFrame'
]
=
CrossFrame
afterEach
->
afterEach
->
sandbox
.
restore
()
sandbox
.
restore
()
delete
Annotator
.
Plugin
.
CrossFrame
describe
'widget visibility'
,
->
describe
'widget visibility'
,
->
it
'starts hidden'
,
->
it
'starts hidden'
,
->
...
...
src/annotator/test/integration/anchoring-test.js
View file @
4efa180a
...
@@ -3,8 +3,6 @@
...
@@ -3,8 +3,6 @@
'use strict'
;
'use strict'
;
var
Annotator
=
require
(
'annotator'
);
var
unroll
=
require
(
'../../../shared/test/util'
).
unroll
;
var
unroll
=
require
(
'../../../shared/test/util'
).
unroll
;
var
Guest
=
require
(
'../../guest'
);
var
Guest
=
require
(
'../../guest'
);
...
@@ -48,17 +46,18 @@ function FakeCrossFrame() {
...
@@ -48,17 +46,18 @@ function FakeCrossFrame() {
describe
(
'anchoring'
,
function
()
{
describe
(
'anchoring'
,
function
()
{
var
guest
;
var
guest
;
var
guestOptions
;
var
container
;
var
container
;
before
(
function
()
{
before
(
function
()
{
Annotator
.
Plugin
.
CrossFrame
=
FakeCrossFrame
;
guestOptions
=
{
pluginClasses
:
{
CrossFrame
:
FakeCrossFrame
}}
;
});
});
beforeEach
(
function
()
{
beforeEach
(
function
()
{
container
=
document
.
createElement
(
'div'
);
container
=
document
.
createElement
(
'div'
);
container
.
innerHTML
=
require
(
'./test-page.html'
);
container
.
innerHTML
=
require
(
'./test-page.html'
);
document
.
body
.
appendChild
(
container
);
document
.
body
.
appendChild
(
container
);
guest
=
new
Guest
(
container
);
guest
=
new
Guest
(
container
,
guestOptions
);
});
});
afterEach
(
function
()
{
afterEach
(
function
()
{
...
...
src/annotator/test/sidebar-test.coffee
View file @
4efa180a
Annotator
=
require
(
'annotator'
)
events
=
require
(
'../../shared/bridge-events'
)
events
=
require
(
'../../shared/bridge-events'
)
proxyquire
=
require
(
'proxyquire'
)
proxyquire
=
require
(
'proxyquire'
)
Sidebar
=
proxyquire
(
'../sidebar'
,
{
Sidebar
=
proxyquire
(
'../sidebar'
,
{})
'annotator'
:
Annotator
,
})
describe
'Sidebar'
,
->
describe
'Sidebar'
,
->
sandbox
=
sinon
.
sandbox
.
create
()
sandbox
=
sinon
.
sandbox
.
create
()
CrossFrame
=
null
CrossFrame
=
null
fakeCrossFrame
=
null
fakeCrossFrame
=
null
sidebarOptions
=
{
pluginClasses
:
{}}
createSidebar
=
(
options
=
{})
->
createSidebar
=
(
options
=
{})
->
options
=
Object
.
assign
({},
sidebarOptions
,
options
)
element
=
document
.
createElement
(
'div'
)
element
=
document
.
createElement
(
'div'
)
return
new
Sidebar
(
element
,
options
)
return
new
Sidebar
(
element
,
options
)
...
@@ -20,14 +19,14 @@ describe 'Sidebar', ->
...
@@ -20,14 +19,14 @@ describe 'Sidebar', ->
fakeCrossFrame
.
onConnect
=
sandbox
.
stub
().
returns
(
fakeCrossFrame
)
fakeCrossFrame
.
onConnect
=
sandbox
.
stub
().
returns
(
fakeCrossFrame
)
fakeCrossFrame
.
on
=
sandbox
.
stub
().
returns
(
fakeCrossFrame
)
fakeCrossFrame
.
on
=
sandbox
.
stub
().
returns
(
fakeCrossFrame
)
fakeCrossFrame
.
call
=
sandbox
.
spy
()
fakeCrossFrame
.
call
=
sandbox
.
spy
()
fakeCrossFrame
.
destroy
=
sandbox
.
stub
()
CrossFrame
=
sandbox
.
stub
()
CrossFrame
=
sandbox
.
stub
()
CrossFrame
.
returns
(
fakeCrossFrame
)
CrossFrame
.
returns
(
fakeCrossFrame
)
Annotator
.
Plugin
.
CrossFrame
=
CrossFrame
sidebarOptions
.
pluginClasses
[
'CrossFrame'
]
=
CrossFrame
afterEach
->
afterEach
->
sandbox
.
restore
()
sandbox
.
restore
()
delete
Annotator
.
Plugin
.
CrossFrame
describe
'crossframe listeners'
,
->
describe
'crossframe listeners'
,
->
emitEvent
=
(
event
,
args
...)
->
emitEvent
=
(
event
,
args
...)
->
...
@@ -196,3 +195,14 @@ describe 'Sidebar', ->
...
@@ -196,3 +195,14 @@ describe 'Sidebar', ->
sidebar
.
show
()
sidebar
.
show
()
sidebar
.
element
.
trigger
(
event
)
sidebar
.
element
.
trigger
(
event
)
assert
.
isFalse
(
sidebar
.
isOpen
())
assert
.
isFalse
(
sidebar
.
isOpen
())
describe
'destruction'
,
->
sidebar
=
null
beforeEach
->
sidebar
=
createSidebar
({})
it
'the sidebar is destroyed and the frame is detached'
,
->
sidebar
.
destroy
()
assert
.
called
(
fakeCrossFrame
.
destroy
)
assert
.
equal
(
sidebar
.
frame
[
0
].
parentElement
,
null
)
src/annotator/vendor/annotator.document.js
deleted
100644 → 0
View file @
5e284a96
/*
** Annotator v1.2.10-dev-6536160
** https://github.com/okfn/annotator/
**
** Copyright 2015, the Annotator project contributors.
** Dual licensed under the MIT and GPLv3 licenses.
** https://github.com/okfn/annotator/blob/master/LICENSE
**
** Built at: 2015-05-11 18:53:38Z
*/
//
// Generated by CoffeeScript 1.6.3
(
function
()
{
var
_ref
,
__bind
=
function
(
fn
,
me
){
return
function
(){
return
fn
.
apply
(
me
,
arguments
);
};
},
__hasProp
=
{}.
hasOwnProperty
,
__extends
=
function
(
child
,
parent
)
{
for
(
var
key
in
parent
)
{
if
(
__hasProp
.
call
(
parent
,
key
))
child
[
key
]
=
parent
[
key
];
}
function
ctor
()
{
this
.
constructor
=
child
;
}
ctor
.
prototype
=
parent
.
prototype
;
child
.
prototype
=
new
ctor
();
child
.
__super__
=
parent
.
prototype
;
return
child
;
};
Annotator
.
Plugin
.
Document
=
(
function
(
_super
)
{
var
$
;
__extends
(
Document
,
_super
);
function
Document
()
{
this
.
_getFavicon
=
__bind
(
this
.
_getFavicon
,
this
);
this
.
_getLinks
=
__bind
(
this
.
_getLinks
,
this
);
this
.
_getTitle
=
__bind
(
this
.
_getTitle
,
this
);
this
.
_getMetaTags
=
__bind
(
this
.
_getMetaTags
,
this
);
this
.
_getEprints
=
__bind
(
this
.
_getEprints
,
this
);
this
.
_getPrism
=
__bind
(
this
.
_getPrism
,
this
);
this
.
_getDublinCore
=
__bind
(
this
.
_getDublinCore
,
this
);
this
.
_getTwitter
=
__bind
(
this
.
_getTwitter
,
this
);
this
.
_getFacebook
=
__bind
(
this
.
_getFacebook
,
this
);
this
.
_getHighwire
=
__bind
(
this
.
_getHighwire
,
this
);
this
.
getDocumentMetadata
=
__bind
(
this
.
getDocumentMetadata
,
this
);
this
.
beforeAnnotationCreated
=
__bind
(
this
.
beforeAnnotationCreated
,
this
);
this
.
uris
=
__bind
(
this
.
uris
,
this
);
this
.
uri
=
__bind
(
this
.
uri
,
this
);
_ref
=
Document
.
__super__
.
constructor
.
apply
(
this
,
arguments
);
return
_ref
;
}
$
=
Annotator
.
$
;
Document
.
prototype
.
events
=
{
'beforeAnnotationCreated'
:
'beforeAnnotationCreated'
};
Document
.
prototype
.
pluginInit
=
function
()
{
return
this
.
getDocumentMetadata
();
};
Document
.
prototype
.
uri
=
function
()
{
var
link
,
uri
,
_i
,
_len
,
_ref1
;
uri
=
decodeURIComponent
(
document
.
location
.
href
);
_ref1
=
this
.
metadata
.
link
;
for
(
_i
=
0
,
_len
=
_ref1
.
length
;
_i
<
_len
;
_i
++
)
{
link
=
_ref1
[
_i
];
if
(
link
.
rel
===
"canonical"
)
{
uri
=
link
.
href
;
}
}
return
uri
;
};
Document
.
prototype
.
uris
=
function
()
{
var
href
,
link
,
uniqueUrls
,
_i
,
_len
,
_ref1
;
uniqueUrls
=
{};
_ref1
=
this
.
metadata
.
link
;
for
(
_i
=
0
,
_len
=
_ref1
.
length
;
_i
<
_len
;
_i
++
)
{
link
=
_ref1
[
_i
];
if
(
link
.
href
)
{
uniqueUrls
[
link
.
href
]
=
true
;
}
}
return
(
function
()
{
var
_results
;
_results
=
[];
for
(
href
in
uniqueUrls
)
{
_results
.
push
(
href
);
}
return
_results
;
})();
};
Document
.
prototype
.
beforeAnnotationCreated
=
function
(
annotation
)
{
return
annotation
.
document
=
this
.
metadata
;
};
Document
.
prototype
.
getDocumentMetadata
=
function
()
{
this
.
metadata
=
{};
this
.
_getHighwire
();
this
.
_getDublinCore
();
this
.
_getFacebook
();
this
.
_getEprints
();
this
.
_getPrism
();
this
.
_getTwitter
();
this
.
_getFavicon
();
this
.
_getTitle
();
this
.
_getLinks
();
return
this
.
metadata
;
};
Document
.
prototype
.
_getHighwire
=
function
()
{
return
this
.
metadata
.
highwire
=
this
.
_getMetaTags
(
"citation"
,
"name"
,
"_"
);
};
Document
.
prototype
.
_getFacebook
=
function
()
{
return
this
.
metadata
.
facebook
=
this
.
_getMetaTags
(
"og"
,
"property"
,
":"
);
};
Document
.
prototype
.
_getTwitter
=
function
()
{
return
this
.
metadata
.
twitter
=
this
.
_getMetaTags
(
"twitter"
,
"name"
,
":"
);
};
Document
.
prototype
.
_getDublinCore
=
function
()
{
return
this
.
metadata
.
dc
=
this
.
_getMetaTags
(
"dc"
,
"name"
,
"."
);
};
Document
.
prototype
.
_getPrism
=
function
()
{
return
this
.
metadata
.
prism
=
this
.
_getMetaTags
(
"prism"
,
"name"
,
"."
);
};
Document
.
prototype
.
_getEprints
=
function
()
{
return
this
.
metadata
.
eprints
=
this
.
_getMetaTags
(
"eprints"
,
"name"
,
"."
);
};
Document
.
prototype
.
_getMetaTags
=
function
(
prefix
,
attribute
,
delimiter
)
{
var
content
,
match
,
meta
,
n
,
name
,
tags
,
_i
,
_len
,
_ref1
;
tags
=
{};
_ref1
=
$
(
"meta"
);
for
(
_i
=
0
,
_len
=
_ref1
.
length
;
_i
<
_len
;
_i
++
)
{
meta
=
_ref1
[
_i
];
name
=
$
(
meta
).
attr
(
attribute
);
content
=
$
(
meta
).
prop
(
"content"
);
if
(
name
)
{
match
=
name
.
match
(
RegExp
(
"^"
+
prefix
+
delimiter
+
"(.+)$"
,
"i"
));
if
(
match
)
{
n
=
match
[
1
];
if
(
tags
[
n
])
{
tags
[
n
].
push
(
content
);
}
else
{
tags
[
n
]
=
[
content
];
}
}
}
}
return
tags
;
};
Document
.
prototype
.
_getTitle
=
function
()
{
if
(
this
.
metadata
.
highwire
.
title
)
{
return
this
.
metadata
.
title
=
this
.
metadata
.
highwire
.
title
[
0
];
}
else
if
(
this
.
metadata
.
eprints
.
title
)
{
return
this
.
metadata
.
title
=
this
.
metadata
.
eprints
.
title
[
0
];
}
else
if
(
this
.
metadata
.
prism
.
title
)
{
return
this
.
metadata
.
title
=
this
.
metadata
.
prism
.
title
[
0
];
}
else
if
(
this
.
metadata
.
facebook
.
title
)
{
return
this
.
metadata
.
title
=
this
.
metadata
.
facebook
.
title
[
0
];
}
else
if
(
this
.
metadata
.
twitter
.
title
)
{
return
this
.
metadata
.
title
=
this
.
metadata
.
twitter
.
title
[
0
];
}
else
if
(
this
.
metadata
.
dc
.
title
)
{
return
this
.
metadata
.
title
=
this
.
metadata
.
dc
.
title
[
0
];
}
else
{
return
this
.
metadata
.
title
=
$
(
"head title"
).
text
();
}
};
Document
.
prototype
.
_getLinks
=
function
()
{
var
doi
,
href
,
id
,
l
,
lang
,
link
,
name
,
rel
,
type
,
url
,
values
,
_i
,
_j
,
_k
,
_len
,
_len1
,
_len2
,
_ref1
,
_ref2
,
_ref3
,
_results
;
this
.
metadata
.
link
=
[
{
href
:
document
.
location
.
href
}
];
_ref1
=
$
(
"link"
);
for
(
_i
=
0
,
_len
=
_ref1
.
length
;
_i
<
_len
;
_i
++
)
{
link
=
_ref1
[
_i
];
l
=
$
(
link
);
href
=
this
.
_absoluteUrl
(
l
.
prop
(
'href'
));
rel
=
l
.
prop
(
'rel'
);
type
=
l
.
prop
(
'type'
);
lang
=
l
.
prop
(
'hreflang'
);
if
(
rel
!==
"alternate"
&&
rel
!==
"canonical"
&&
rel
!==
"bookmark"
&&
rel
!==
"shortlink"
)
{
continue
;
}
if
(
rel
===
'alternate'
)
{
if
(
type
&&
type
.
match
(
/^application
\/(
rss|atom
)\+
xml/
))
{
continue
;
}
if
(
lang
)
{
continue
;
}
}
this
.
metadata
.
link
.
push
({
href
:
href
,
rel
:
rel
,
type
:
type
});
}
_ref2
=
this
.
metadata
.
highwire
;
for
(
name
in
_ref2
)
{
values
=
_ref2
[
name
];
if
(
name
===
"pdf_url"
)
{
for
(
_j
=
0
,
_len1
=
values
.
length
;
_j
<
_len1
;
_j
++
)
{
url
=
values
[
_j
];
this
.
metadata
.
link
.
push
({
href
:
this
.
_absoluteUrl
(
url
),
type
:
"application/pdf"
});
}
}
if
(
name
===
"doi"
)
{
for
(
_k
=
0
,
_len2
=
values
.
length
;
_k
<
_len2
;
_k
++
)
{
doi
=
values
[
_k
];
if
(
doi
.
slice
(
0
,
4
)
!==
"doi:"
)
{
doi
=
"doi:"
+
doi
;
}
this
.
metadata
.
link
.
push
({
href
:
doi
});
}
}
}
_ref3
=
this
.
metadata
.
dc
;
_results
=
[];
for
(
name
in
_ref3
)
{
values
=
_ref3
[
name
];
if
(
name
===
"identifier"
)
{
_results
.
push
((
function
()
{
var
_l
,
_len3
,
_results1
;
_results1
=
[];
for
(
_l
=
0
,
_len3
=
values
.
length
;
_l
<
_len3
;
_l
++
)
{
id
=
values
[
_l
];
if
(
id
.
slice
(
0
,
4
)
===
"doi:"
)
{
_results1
.
push
(
this
.
metadata
.
link
.
push
({
href
:
id
}));
}
else
{
_results1
.
push
(
void
0
);
}
}
return
_results1
;
}).
call
(
this
));
}
else
{
_results
.
push
(
void
0
);
}
}
return
_results
;
};
Document
.
prototype
.
_getFavicon
=
function
()
{
var
link
,
_i
,
_len
,
_ref1
,
_ref2
,
_results
;
_ref1
=
$
(
"link"
);
_results
=
[];
for
(
_i
=
0
,
_len
=
_ref1
.
length
;
_i
<
_len
;
_i
++
)
{
link
=
_ref1
[
_i
];
if
((
_ref2
=
$
(
link
).
prop
(
"rel"
))
===
"shortcut icon"
||
_ref2
===
"icon"
)
{
_results
.
push
(
this
.
metadata
[
"favicon"
]
=
this
.
_absoluteUrl
(
link
.
href
));
}
else
{
_results
.
push
(
void
0
);
}
}
return
_results
;
};
Document
.
prototype
.
_absoluteUrl
=
function
(
url
)
{
var
d
;
d
=
document
.
createElement
(
'a'
);
d
.
href
=
url
;
return
d
.
href
;
};
return
Document
;
})(
Annotator
.
Plugin
);
}).
call
(
this
);
//
//# sourceMappingURL=annotator.document.map
\ No newline at end of file
src/annotator/vendor/annotator.js
deleted
100644 → 0
View file @
5e284a96
/*
** Annotator v1.2.10-dev-6536160
** https://github.com/okfn/annotator/
**
** Copyright 2015, the Annotator project contributors.
** Dual licensed under the MIT and GPLv3 licenses.
** https://github.com/okfn/annotator/blob/master/LICENSE
**
** Built at: 2015-05-11 18:53:38Z
*/
//
// Generated by CoffeeScript 1.6.3
(
function
()
{
var
$
,
Annotator
,
Delegator
,
LinkParser
,
Range
,
Util
,
findChild
,
fn
,
functions
,
g
,
getNodeName
,
getNodePosition
,
gettext
,
simpleXPathJQuery
,
simpleXPathPure
,
_Annotator
,
_gettext
,
_i
,
_j
,
_len
,
_len1
,
_ref
,
_ref1
,
_t
,
__slice
=
[].
slice
,
__hasProp
=
{}.
hasOwnProperty
,
__extends
=
function
(
child
,
parent
)
{
for
(
var
key
in
parent
)
{
if
(
__hasProp
.
call
(
parent
,
key
))
child
[
key
]
=
parent
[
key
];
}
function
ctor
()
{
this
.
constructor
=
child
;
}
ctor
.
prototype
=
parent
.
prototype
;
child
.
prototype
=
new
ctor
();
child
.
__super__
=
parent
.
prototype
;
return
child
;
},
__bind
=
function
(
fn
,
me
){
return
function
(){
return
fn
.
apply
(
me
,
arguments
);
};
};
simpleXPathJQuery
=
function
(
relativeRoot
)
{
var
jq
;
jq
=
this
.
map
(
function
()
{
var
elem
,
idx
,
path
,
tagName
;
path
=
''
;
elem
=
this
;
while
((
elem
!=
null
?
elem
.
nodeType
:
void
0
)
===
Node
.
ELEMENT_NODE
&&
elem
!==
relativeRoot
)
{
tagName
=
elem
.
tagName
.
replace
(
":"
,
"
\\
:"
);
idx
=
$
(
elem
.
parentNode
).
children
(
tagName
).
index
(
elem
)
+
1
;
idx
=
"["
+
idx
+
"]"
;
path
=
"/"
+
elem
.
tagName
.
toLowerCase
()
+
idx
+
path
;
elem
=
elem
.
parentNode
;
}
return
path
;
});
return
jq
.
get
();
};
simpleXPathPure
=
function
(
relativeRoot
)
{
var
getPathSegment
,
getPathTo
,
jq
,
rootNode
;
getPathSegment
=
function
(
node
)
{
var
name
,
pos
;
name
=
getNodeName
(
node
);
pos
=
getNodePosition
(
node
);
return
""
+
name
+
"["
+
pos
+
"]"
;
};
rootNode
=
relativeRoot
;
getPathTo
=
function
(
node
)
{
var
xpath
;
xpath
=
''
;
while
(
node
!==
rootNode
)
{
if
(
node
==
null
)
{
throw
new
Error
(
"Called getPathTo on a node which was not a descendant of @rootNode. "
+
rootNode
);
}
xpath
=
(
getPathSegment
(
node
))
+
'/'
+
xpath
;
node
=
node
.
parentNode
;
}
xpath
=
'/'
+
xpath
;
xpath
=
xpath
.
replace
(
/
\/
$/
,
''
);
return
xpath
;
};
jq
=
this
.
map
(
function
()
{
var
path
;
path
=
getPathTo
(
this
);
return
path
;
});
return
jq
.
get
();
};
findChild
=
function
(
node
,
type
,
index
)
{
var
child
,
children
,
found
,
name
,
_i
,
_len
;
if
(
!
node
.
hasChildNodes
())
{
throw
new
Error
(
"XPath error: node has no children!"
);
}
children
=
node
.
childNodes
;
found
=
0
;
for
(
_i
=
0
,
_len
=
children
.
length
;
_i
<
_len
;
_i
++
)
{
child
=
children
[
_i
];
name
=
getNodeName
(
child
);
if
(
name
===
type
)
{
found
+=
1
;
if
(
found
===
index
)
{
return
child
;
}
}
}
throw
new
Error
(
"XPath error: wanted child not found."
);
};
getNodeName
=
function
(
node
)
{
var
nodeName
;
nodeName
=
node
.
nodeName
.
toLowerCase
();
switch
(
nodeName
)
{
case
"#text"
:
return
"text()"
;
case
"#comment"
:
return
"comment()"
;
case
"#cdata-section"
:
return
"cdata-section()"
;
default
:
return
nodeName
;
}
};
getNodePosition
=
function
(
node
)
{
var
pos
,
tmp
;
pos
=
0
;
tmp
=
node
;
while
(
tmp
)
{
if
(
tmp
.
nodeName
===
node
.
nodeName
)
{
pos
++
;
}
tmp
=
tmp
.
previousSibling
;
}
return
pos
;
};
gettext
=
null
;
if
(
typeof
Gettext
!==
"undefined"
&&
Gettext
!==
null
)
{
_gettext
=
new
Gettext
({
domain
:
"annotator"
});
gettext
=
function
(
msgid
)
{
return
_gettext
.
gettext
(
msgid
);
};
}
else
{
gettext
=
function
(
msgid
)
{
return
msgid
;
};
}
_t
=
function
(
msgid
)
{
return
gettext
(
msgid
);
};
if
(
!
(
typeof
jQuery
!==
"undefined"
&&
jQuery
!==
null
?
(
_ref
=
jQuery
.
fn
)
!=
null
?
_ref
.
jquery
:
void
0
:
void
0
))
{
console
.
error
(
_t
(
"Annotator requires jQuery: have you included lib/vendor/jquery.js?"
));
}
if
(
!
(
JSON
&&
JSON
.
parse
&&
JSON
.
stringify
))
{
console
.
error
(
_t
(
"Annotator requires a JSON implementation: have you included lib/vendor/json2.js?"
));
}
$
=
jQuery
;
Util
=
{};
Util
.
flatten
=
function
(
array
)
{
var
flatten
;
flatten
=
function
(
ary
)
{
var
el
,
flat
,
_i
,
_len
;
flat
=
[];
for
(
_i
=
0
,
_len
=
ary
.
length
;
_i
<
_len
;
_i
++
)
{
el
=
ary
[
_i
];
flat
=
flat
.
concat
(
el
&&
$
.
isArray
(
el
)
?
flatten
(
el
)
:
el
);
}
return
flat
;
};
return
flatten
(
array
);
};
Util
.
contains
=
function
(
parent
,
child
)
{
var
node
;
node
=
child
;
while
(
node
!=
null
)
{
if
(
node
===
parent
)
{
return
true
;
}
node
=
node
.
parentNode
;
}
return
false
;
};
Util
.
getTextNodes
=
function
(
jq
)
{
var
getTextNodes
;
getTextNodes
=
function
(
node
)
{
var
nodes
;
if
(
node
&&
node
.
nodeType
!==
Node
.
TEXT_NODE
)
{
nodes
=
[];
if
(
node
.
nodeType
!==
Node
.
COMMENT_NODE
)
{
node
=
node
.
lastChild
;
while
(
node
)
{
nodes
.
push
(
getTextNodes
(
node
));
node
=
node
.
previousSibling
;
}
}
return
nodes
.
reverse
();
}
else
{
return
node
;
}
};
return
jq
.
map
(
function
()
{
return
Util
.
flatten
(
getTextNodes
(
this
));
});
};
Util
.
getLastTextNodeUpTo
=
function
(
n
)
{
var
result
;
switch
(
n
.
nodeType
)
{
case
Node
.
TEXT_NODE
:
return
n
;
case
Node
.
ELEMENT_NODE
:
if
(
n
.
lastChild
!=
null
)
{
result
=
Util
.
getLastTextNodeUpTo
(
n
.
lastChild
);
if
(
result
!=
null
)
{
return
result
;
}
}
break
;
}
n
=
n
.
previousSibling
;
if
(
n
!=
null
)
{
return
Util
.
getLastTextNodeUpTo
(
n
);
}
else
{
return
null
;
}
};
Util
.
getFirstTextNodeNotBefore
=
function
(
n
)
{
var
result
;
switch
(
n
.
nodeType
)
{
case
Node
.
TEXT_NODE
:
return
n
;
case
Node
.
ELEMENT_NODE
:
if
(
n
.
firstChild
!=
null
)
{
result
=
Util
.
getFirstTextNodeNotBefore
(
n
.
firstChild
);
if
(
result
!=
null
)
{
return
result
;
}
}
break
;
}
n
=
n
.
nextSibling
;
if
(
n
!=
null
)
{
return
Util
.
getFirstTextNodeNotBefore
(
n
);
}
else
{
return
null
;
}
};
Util
.
readRangeViaSelection
=
function
(
range
)
{
var
sel
;
sel
=
Util
.
getGlobal
().
getSelection
();
sel
.
removeAllRanges
();
sel
.
addRange
(
range
.
toRange
());
return
sel
.
toString
();
};
Util
.
xpathFromNode
=
function
(
el
,
relativeRoot
)
{
var
exception
,
result
;
try
{
result
=
simpleXPathJQuery
.
call
(
el
,
relativeRoot
);
}
catch
(
_error
)
{
exception
=
_error
;
console
.
log
(
"jQuery-based XPath construction failed! Falling back to manual."
);
result
=
simpleXPathPure
.
call
(
el
,
relativeRoot
);
}
return
result
;
};
Util
.
nodeFromXPath
=
function
(
xp
,
root
)
{
var
idx
,
name
,
node
,
step
,
steps
,
_i
,
_len
,
_ref1
;
steps
=
xp
.
substring
(
1
).
split
(
"/"
);
node
=
root
;
for
(
_i
=
0
,
_len
=
steps
.
length
;
_i
<
_len
;
_i
++
)
{
step
=
steps
[
_i
];
_ref1
=
step
.
split
(
"["
),
name
=
_ref1
[
0
],
idx
=
_ref1
[
1
];
idx
=
idx
!=
null
?
parseInt
((
idx
!=
null
?
idx
.
split
(
"]"
)
:
void
0
)[
0
])
:
1
;
node
=
findChild
(
node
,
name
.
toLowerCase
(),
idx
);
}
return
node
;
};
Util
.
escape
=
function
(
html
)
{
return
html
.
replace
(
/&
(?!\w
+;
)
/g
,
'&'
).
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
).
replace
(
/"/g
,
'"'
);
};
Util
.
uuid
=
(
function
()
{
var
counter
;
counter
=
0
;
return
function
()
{
return
counter
++
;
};
})();
Util
.
getGlobal
=
function
()
{
return
(
function
()
{
return
this
;
})();
};
Util
.
maxZIndex
=
function
(
$elements
)
{
var
all
,
el
;
all
=
(
function
()
{
var
_i
,
_len
,
_results
;
_results
=
[];
for
(
_i
=
0
,
_len
=
$elements
.
length
;
_i
<
_len
;
_i
++
)
{
el
=
$elements
[
_i
];
if
(
$
(
el
).
css
(
'position'
)
===
'static'
)
{
_results
.
push
(
-
1
);
}
else
{
_results
.
push
(
parseFloat
(
$
(
el
).
css
(
'z-index'
))
||
-
1
);
}
}
return
_results
;
})();
return
Math
.
max
.
apply
(
Math
,
all
);
};
Util
.
mousePosition
=
function
(
e
,
offsetEl
)
{
var
offset
,
_ref1
;
if
((
_ref1
=
$
(
offsetEl
).
css
(
'position'
))
!==
'absolute'
&&
_ref1
!==
'fixed'
&&
_ref1
!==
'relative'
)
{
offsetEl
=
$
(
offsetEl
).
offsetParent
()[
0
];
}
offset
=
$
(
offsetEl
).
offset
();
return
{
top
:
e
.
pageY
-
offset
.
top
,
left
:
e
.
pageX
-
offset
.
left
};
};
Util
.
preventEventDefault
=
function
(
event
)
{
return
event
!=
null
?
typeof
event
.
preventDefault
===
"function"
?
event
.
preventDefault
()
:
void
0
:
void
0
;
};
functions
=
[
"log"
,
"debug"
,
"info"
,
"warn"
,
"exception"
,
"assert"
,
"dir"
,
"dirxml"
,
"trace"
,
"group"
,
"groupEnd"
,
"groupCollapsed"
,
"time"
,
"timeEnd"
,
"profile"
,
"profileEnd"
,
"count"
,
"clear"
,
"table"
,
"error"
,
"notifyFirebug"
,
"firebug"
,
"userObjects"
];
if
(
typeof
console
!==
"undefined"
&&
console
!==
null
)
{
if
(
console
.
group
==
null
)
{
console
.
group
=
function
(
name
)
{
return
console
.
log
(
"GROUP: "
,
name
);
};
}
if
(
console
.
groupCollapsed
==
null
)
{
console
.
groupCollapsed
=
console
.
group
;
}
for
(
_i
=
0
,
_len
=
functions
.
length
;
_i
<
_len
;
_i
++
)
{
fn
=
functions
[
_i
];
if
(
console
[
fn
]
==
null
)
{
console
[
fn
]
=
function
()
{
return
console
.
log
(
_t
(
"Not implemented:"
)
+
(
" console."
+
name
));
};
}
}
}
else
{
this
.
console
=
{};
for
(
_j
=
0
,
_len1
=
functions
.
length
;
_j
<
_len1
;
_j
++
)
{
fn
=
functions
[
_j
];
this
.
console
[
fn
]
=
function
()
{};
}
this
.
console
[
'error'
]
=
function
()
{
var
args
;
args
=
1
<=
arguments
.
length
?
__slice
.
call
(
arguments
,
0
)
:
[];
return
alert
(
"ERROR: "
+
(
args
.
join
(
', '
)));
};
this
.
console
[
'warn'
]
=
function
()
{
var
args
;
args
=
1
<=
arguments
.
length
?
__slice
.
call
(
arguments
,
0
)
:
[];
return
alert
(
"WARNING: "
+
(
args
.
join
(
', '
)));
};
}
Delegator
=
(
function
()
{
Delegator
.
prototype
.
events
=
{};
Delegator
.
prototype
.
options
=
{};
Delegator
.
prototype
.
element
=
null
;
function
Delegator
(
element
,
options
)
{
this
.
options
=
$
.
extend
(
true
,
{},
this
.
options
,
options
);
this
.
element
=
$
(
element
);
this
.
_closures
=
{};
this
.
on
=
this
.
subscribe
;
this
.
addEvents
();
}
Delegator
.
prototype
.
destroy
=
function
()
{
return
this
.
removeEvents
();
};
Delegator
.
prototype
.
addEvents
=
function
()
{
var
event
,
_k
,
_len2
,
_ref1
,
_results
;
_ref1
=
Delegator
.
_parseEvents
(
this
.
events
);
_results
=
[];
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
event
=
_ref1
[
_k
];
_results
.
push
(
this
.
_addEvent
(
event
.
selector
,
event
.
event
,
event
.
functionName
));
}
return
_results
;
};
Delegator
.
prototype
.
removeEvents
=
function
()
{
var
event
,
_k
,
_len2
,
_ref1
,
_results
;
_ref1
=
Delegator
.
_parseEvents
(
this
.
events
);
_results
=
[];
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
event
=
_ref1
[
_k
];
_results
.
push
(
this
.
_removeEvent
(
event
.
selector
,
event
.
event
,
event
.
functionName
));
}
return
_results
;
};
Delegator
.
prototype
.
_addEvent
=
function
(
selector
,
event
,
functionName
)
{
var
closure
,
_this
=
this
;
closure
=
function
()
{
return
_this
[
functionName
].
apply
(
_this
,
arguments
);
};
if
(
selector
===
''
&&
Delegator
.
_isCustomEvent
(
event
))
{
this
.
subscribe
(
event
,
closure
);
}
else
{
this
.
element
.
delegate
(
selector
,
event
,
closure
);
}
this
.
_closures
[
""
+
selector
+
"/"
+
event
+
"/"
+
functionName
]
=
closure
;
return
this
;
};
Delegator
.
prototype
.
_removeEvent
=
function
(
selector
,
event
,
functionName
)
{
var
closure
;
closure
=
this
.
_closures
[
""
+
selector
+
"/"
+
event
+
"/"
+
functionName
];
if
(
selector
===
''
&&
Delegator
.
_isCustomEvent
(
event
))
{
this
.
unsubscribe
(
event
,
closure
);
}
else
{
this
.
element
.
undelegate
(
selector
,
event
,
closure
);
}
delete
this
.
_closures
[
""
+
selector
+
"/"
+
event
+
"/"
+
functionName
];
return
this
;
};
Delegator
.
prototype
.
publish
=
function
()
{
this
.
element
.
triggerHandler
.
apply
(
this
.
element
,
arguments
);
return
this
;
};
Delegator
.
prototype
.
subscribe
=
function
(
event
,
callback
)
{
var
closure
;
closure
=
function
()
{
return
callback
.
apply
(
this
,
[].
slice
.
call
(
arguments
,
1
));
};
closure
.
guid
=
callback
.
guid
=
(
$
.
guid
+=
1
);
this
.
element
.
bind
(
event
,
closure
);
return
this
;
};
Delegator
.
prototype
.
unsubscribe
=
function
()
{
this
.
element
.
unbind
.
apply
(
this
.
element
,
arguments
);
return
this
;
};
return
Delegator
;
})();
Delegator
.
_parseEvents
=
function
(
eventsObj
)
{
var
event
,
events
,
functionName
,
sel
,
selector
,
_k
,
_ref1
;
events
=
[];
for
(
sel
in
eventsObj
)
{
functionName
=
eventsObj
[
sel
];
_ref1
=
sel
.
split
(
' '
),
selector
=
2
<=
_ref1
.
length
?
__slice
.
call
(
_ref1
,
0
,
_k
=
_ref1
.
length
-
1
)
:
(
_k
=
0
,
[]),
event
=
_ref1
[
_k
++
];
events
.
push
({
selector
:
selector
.
join
(
' '
),
event
:
event
,
functionName
:
functionName
});
}
return
events
;
};
Delegator
.
natives
=
(
function
()
{
var
key
,
specials
,
val
;
specials
=
(
function
()
{
var
_ref1
,
_results
;
_ref1
=
jQuery
.
event
.
special
;
_results
=
[];
for
(
key
in
_ref1
)
{
if
(
!
__hasProp
.
call
(
_ref1
,
key
))
continue
;
val
=
_ref1
[
key
];
_results
.
push
(
key
);
}
return
_results
;
})();
return
"blur focus focusin focusout load resize scroll unload click dblclick
\n
mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave
\n
change select submit keydown keypress keyup error"
.
split
(
/
[^
a-z
]
+/
).
concat
(
specials
);
})();
Delegator
.
_isCustomEvent
=
function
(
event
)
{
event
=
event
.
split
(
'.'
)[
0
];
return
$
.
inArray
(
event
,
Delegator
.
natives
)
===
-
1
;
};
Range
=
{};
Range
.
sniff
=
function
(
r
)
{
if
(
r
.
commonAncestorContainer
!=
null
)
{
return
new
Range
.
BrowserRange
(
r
);
}
else
if
(
typeof
r
.
start
===
"string"
)
{
return
new
Range
.
SerializedRange
(
r
);
}
else
if
(
r
.
start
&&
typeof
r
.
start
===
"object"
)
{
return
new
Range
.
NormalizedRange
(
r
);
}
else
{
console
.
error
(
_t
(
"Could not sniff range type"
));
return
false
;
}
};
Range
.
nodeFromXPath
=
function
(
xpath
,
root
)
{
var
customResolver
,
evaluateXPath
,
namespace
,
node
,
segment
;
if
(
root
==
null
)
{
root
=
document
;
}
evaluateXPath
=
function
(
xp
,
nsResolver
)
{
var
exception
;
if
(
nsResolver
==
null
)
{
nsResolver
=
null
;
}
try
{
return
document
.
evaluate
(
'.'
+
xp
,
root
,
nsResolver
,
XPathResult
.
FIRST_ORDERED_NODE_TYPE
,
null
).
singleNodeValue
;
}
catch
(
_error
)
{
exception
=
_error
;
console
.
log
(
"XPath evaluation failed."
);
console
.
log
(
"Trying fallback..."
);
return
Util
.
nodeFromXPath
(
xp
,
root
);
}
};
if
(
!
$
.
isXMLDoc
(
document
.
documentElement
))
{
return
evaluateXPath
(
xpath
);
}
else
{
customResolver
=
document
.
createNSResolver
(
document
.
ownerDocument
===
null
?
document
.
documentElement
:
document
.
ownerDocument
.
documentElement
);
node
=
evaluateXPath
(
xpath
,
customResolver
);
if
(
!
node
)
{
xpath
=
((
function
()
{
var
_k
,
_len2
,
_ref1
,
_results
;
_ref1
=
xpath
.
split
(
'/'
);
_results
=
[];
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
segment
=
_ref1
[
_k
];
if
(
segment
&&
segment
.
indexOf
(
':'
)
===
-
1
)
{
_results
.
push
(
segment
.
replace
(
/^
([
a-z
]
+
)
/
,
'xhtml:$1'
));
}
else
{
_results
.
push
(
segment
);
}
}
return
_results
;
})()).
join
(
'/'
);
namespace
=
document
.
lookupNamespaceURI
(
null
);
customResolver
=
function
(
ns
)
{
if
(
ns
===
'xhtml'
)
{
return
namespace
;
}
else
{
return
document
.
documentElement
.
getAttribute
(
'xmlns:'
+
ns
);
}
};
node
=
evaluateXPath
(
xpath
,
customResolver
);
}
return
node
;
}
};
Range
.
RangeError
=
(
function
(
_super
)
{
__extends
(
RangeError
,
_super
);
function
RangeError
(
type
,
message
,
parent
)
{
this
.
type
=
type
;
this
.
message
=
message
;
this
.
parent
=
parent
!=
null
?
parent
:
null
;
RangeError
.
__super__
.
constructor
.
call
(
this
,
this
.
message
);
}
return
RangeError
;
})(
Error
);
Range
.
BrowserRange
=
(
function
()
{
function
BrowserRange
(
obj
)
{
this
.
commonAncestorContainer
=
obj
.
commonAncestorContainer
;
this
.
startContainer
=
obj
.
startContainer
;
this
.
startOffset
=
obj
.
startOffset
;
this
.
endContainer
=
obj
.
endContainer
;
this
.
endOffset
=
obj
.
endOffset
;
}
BrowserRange
.
prototype
.
normalize
=
function
(
root
)
{
var
n
,
node
,
nr
,
r
;
if
(
this
.
tainted
)
{
console
.
error
(
_t
(
"You may only call normalize() once on a BrowserRange!"
));
return
false
;
}
else
{
this
.
tainted
=
true
;
}
r
=
{};
if
(
this
.
startContainer
.
nodeType
===
Node
.
ELEMENT_NODE
)
{
r
.
start
=
Util
.
getFirstTextNodeNotBefore
(
this
.
startContainer
.
childNodes
[
this
.
startOffset
]);
r
.
startOffset
=
0
;
}
else
{
r
.
start
=
this
.
startContainer
;
r
.
startOffset
=
this
.
startOffset
;
}
if
(
this
.
endContainer
.
nodeType
===
Node
.
ELEMENT_NODE
)
{
node
=
this
.
endContainer
.
childNodes
[
this
.
endOffset
];
if
(
node
!=
null
)
{
n
=
node
;
while
((
n
!=
null
)
&&
(
n
.
nodeType
!==
Node
.
TEXT_NODE
))
{
n
=
n
.
firstChild
;
}
if
(
n
!=
null
)
{
r
.
end
=
n
;
r
.
endOffset
=
0
;
}
}
if
(
r
.
end
==
null
)
{
node
=
this
.
endContainer
.
childNodes
[
this
.
endOffset
-
1
];
r
.
end
=
Util
.
getLastTextNodeUpTo
(
node
);
r
.
endOffset
=
r
.
end
.
nodeValue
.
length
;
}
}
else
{
r
.
end
=
this
.
endContainer
;
r
.
endOffset
=
this
.
endOffset
;
}
nr
=
{};
if
(
r
.
startOffset
>
0
)
{
if
(
!
r
.
start
.
nextSibling
||
r
.
start
.
nodeValue
.
length
>
r
.
startOffset
)
{
nr
.
start
=
r
.
start
.
splitText
(
r
.
startOffset
);
}
else
{
nr
.
start
=
r
.
start
.
nextSibling
;
}
}
else
{
nr
.
start
=
r
.
start
;
}
if
(
r
.
start
===
r
.
end
)
{
if
(
nr
.
start
.
nodeValue
.
length
>
(
r
.
endOffset
-
r
.
startOffset
))
{
nr
.
start
.
splitText
(
r
.
endOffset
-
r
.
startOffset
);
}
nr
.
end
=
nr
.
start
;
}
else
{
if
(
r
.
end
.
nodeValue
.
length
>
r
.
endOffset
)
{
r
.
end
.
splitText
(
r
.
endOffset
);
}
nr
.
end
=
r
.
end
;
}
nr
.
commonAncestor
=
this
.
commonAncestorContainer
;
while
(
nr
.
commonAncestor
.
nodeType
!==
Node
.
ELEMENT_NODE
)
{
nr
.
commonAncestor
=
nr
.
commonAncestor
.
parentNode
;
}
return
new
Range
.
NormalizedRange
(
nr
);
};
BrowserRange
.
prototype
.
serialize
=
function
(
root
,
ignoreSelector
)
{
return
this
.
normalize
(
root
).
serialize
(
root
,
ignoreSelector
);
};
return
BrowserRange
;
})();
Range
.
NormalizedRange
=
(
function
()
{
function
NormalizedRange
(
obj
)
{
this
.
commonAncestor
=
obj
.
commonAncestor
;
this
.
start
=
obj
.
start
;
this
.
end
=
obj
.
end
;
}
NormalizedRange
.
prototype
.
normalize
=
function
(
root
)
{
return
this
;
};
NormalizedRange
.
prototype
.
limit
=
function
(
bounds
)
{
var
nodes
,
parent
,
startParents
,
_k
,
_len2
,
_ref1
;
nodes
=
$
.
grep
(
this
.
textNodes
(),
function
(
node
)
{
return
node
.
parentNode
===
bounds
||
$
.
contains
(
bounds
,
node
.
parentNode
);
});
if
(
!
nodes
.
length
)
{
return
null
;
}
this
.
start
=
nodes
[
0
];
this
.
end
=
nodes
[
nodes
.
length
-
1
];
startParents
=
$
(
this
.
start
).
parents
();
_ref1
=
$
(
this
.
end
).
parents
();
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
parent
=
_ref1
[
_k
];
if
(
startParents
.
index
(
parent
)
!==
-
1
)
{
this
.
commonAncestor
=
parent
;
break
;
}
}
return
this
;
};
NormalizedRange
.
prototype
.
serialize
=
function
(
root
,
ignoreSelector
)
{
var
end
,
serialization
,
start
;
serialization
=
function
(
node
,
isEnd
)
{
var
n
,
nodes
,
offset
,
origParent
,
textNodes
,
xpath
,
_k
,
_len2
;
if
(
ignoreSelector
)
{
origParent
=
$
(
node
).
parents
(
":not("
+
ignoreSelector
+
")"
).
eq
(
0
);
}
else
{
origParent
=
$
(
node
).
parent
();
}
xpath
=
Util
.
xpathFromNode
(
origParent
,
root
)[
0
];
textNodes
=
Util
.
getTextNodes
(
origParent
);
nodes
=
textNodes
.
slice
(
0
,
textNodes
.
index
(
node
));
offset
=
0
;
for
(
_k
=
0
,
_len2
=
nodes
.
length
;
_k
<
_len2
;
_k
++
)
{
n
=
nodes
[
_k
];
offset
+=
n
.
nodeValue
.
length
;
}
if
(
isEnd
)
{
return
[
xpath
,
offset
+
node
.
nodeValue
.
length
];
}
else
{
return
[
xpath
,
offset
];
}
};
start
=
serialization
(
this
.
start
);
end
=
serialization
(
this
.
end
,
true
);
return
new
Range
.
SerializedRange
({
start
:
start
[
0
],
end
:
end
[
0
],
startOffset
:
start
[
1
],
endOffset
:
end
[
1
]
});
};
NormalizedRange
.
prototype
.
text
=
function
()
{
var
node
;
return
((
function
()
{
var
_k
,
_len2
,
_ref1
,
_results
;
_ref1
=
this
.
textNodes
();
_results
=
[];
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
node
=
_ref1
[
_k
];
_results
.
push
(
node
.
nodeValue
);
}
return
_results
;
}).
call
(
this
)).
join
(
''
);
};
NormalizedRange
.
prototype
.
textNodes
=
function
()
{
var
end
,
start
,
textNodes
,
_ref1
;
textNodes
=
Util
.
getTextNodes
(
$
(
this
.
commonAncestor
));
_ref1
=
[
textNodes
.
index
(
this
.
start
),
textNodes
.
index
(
this
.
end
)],
start
=
_ref1
[
0
],
end
=
_ref1
[
1
];
return
$
.
makeArray
(
textNodes
.
slice
(
start
,
+
end
+
1
||
9
e9
));
};
NormalizedRange
.
prototype
.
toRange
=
function
()
{
var
range
;
range
=
document
.
createRange
();
range
.
setStartBefore
(
this
.
start
);
range
.
setEndAfter
(
this
.
end
);
return
range
;
};
return
NormalizedRange
;
})();
Range
.
SerializedRange
=
(
function
()
{
function
SerializedRange
(
obj
)
{
this
.
start
=
obj
.
start
;
this
.
startOffset
=
obj
.
startOffset
;
this
.
end
=
obj
.
end
;
this
.
endOffset
=
obj
.
endOffset
;
}
SerializedRange
.
prototype
.
normalize
=
function
(
root
)
{
var
contains
,
e
,
length
,
node
,
p
,
range
,
targetOffset
,
tn
,
_k
,
_l
,
_len2
,
_len3
,
_ref1
,
_ref2
;
range
=
{};
_ref1
=
[
'start'
,
'end'
];
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
p
=
_ref1
[
_k
];
try
{
node
=
Range
.
nodeFromXPath
(
this
[
p
],
root
);
}
catch
(
_error
)
{
e
=
_error
;
throw
new
Range
.
RangeError
(
p
,
(
"Error while finding "
+
p
+
" node: "
+
this
[
p
]
+
": "
)
+
e
,
e
);
}
if
(
!
node
)
{
throw
new
Range
.
RangeError
(
p
,
"Couldn't find "
+
p
+
" node: "
+
this
[
p
]);
}
length
=
0
;
targetOffset
=
this
[
p
+
'Offset'
];
if
(
p
===
'end'
)
{
targetOffset
--
;
}
_ref2
=
Util
.
getTextNodes
(
$
(
node
));
for
(
_l
=
0
,
_len3
=
_ref2
.
length
;
_l
<
_len3
;
_l
++
)
{
tn
=
_ref2
[
_l
];
if
(
length
+
tn
.
nodeValue
.
length
>
targetOffset
)
{
range
[
p
+
'Container'
]
=
tn
;
range
[
p
+
'Offset'
]
=
this
[
p
+
'Offset'
]
-
length
;
break
;
}
else
{
length
+=
tn
.
nodeValue
.
length
;
}
}
if
(
range
[
p
+
'Offset'
]
==
null
)
{
throw
new
Range
.
RangeError
(
""
+
p
+
"offset"
,
"Couldn't find offset "
+
this
[
p
+
'Offset'
]
+
" in element "
+
this
[
p
]);
}
}
contains
=
document
.
compareDocumentPosition
==
null
?
function
(
a
,
b
)
{
return
a
.
contains
(
b
);
}
:
function
(
a
,
b
)
{
return
a
.
compareDocumentPosition
(
b
)
&
16
;
};
$
(
range
.
startContainer
).
parents
().
each
(
function
()
{
if
(
contains
(
this
,
range
.
endContainer
))
{
range
.
commonAncestorContainer
=
this
;
return
false
;
}
});
return
new
Range
.
BrowserRange
(
range
).
normalize
(
root
);
};
SerializedRange
.
prototype
.
serialize
=
function
(
root
,
ignoreSelector
)
{
return
this
.
normalize
(
root
).
serialize
(
root
,
ignoreSelector
);
};
SerializedRange
.
prototype
.
toObject
=
function
()
{
return
{
start
:
this
.
start
,
startOffset
:
this
.
startOffset
,
end
:
this
.
end
,
endOffset
:
this
.
endOffset
};
};
return
SerializedRange
;
})();
_Annotator
=
this
.
Annotator
;
Annotator
=
(
function
(
_super
)
{
__extends
(
Annotator
,
_super
);
Annotator
.
prototype
.
events
=
{
".annotator-adder button click"
:
"onAdderClick"
,
".annotator-adder button mousedown"
:
"onAdderMousedown"
,
".annotator-hl mouseover"
:
"onHighlightMouseover"
,
".annotator-hl mouseout"
:
"startViewerHideTimer"
};
Annotator
.
prototype
.
html
=
{
adder
:
'<div class="annotator-adder"><button>'
+
_t
(
'Annotate'
)
+
'</button></div>'
,
wrapper
:
'<div class="annotator-wrapper"></div>'
};
Annotator
.
prototype
.
options
=
{
readOnly
:
false
};
Annotator
.
prototype
.
plugins
=
{};
Annotator
.
prototype
.
editor
=
null
;
Annotator
.
prototype
.
viewer
=
null
;
Annotator
.
prototype
.
selectedRanges
=
null
;
Annotator
.
prototype
.
mouseIsDown
=
false
;
Annotator
.
prototype
.
ignoreMouseup
=
false
;
Annotator
.
prototype
.
viewerHideTimer
=
null
;
function
Annotator
(
element
,
options
)
{
this
.
onDeleteAnnotation
=
__bind
(
this
.
onDeleteAnnotation
,
this
);
this
.
onEditAnnotation
=
__bind
(
this
.
onEditAnnotation
,
this
);
this
.
onAdderClick
=
__bind
(
this
.
onAdderClick
,
this
);
this
.
onAdderMousedown
=
__bind
(
this
.
onAdderMousedown
,
this
);
this
.
onHighlightMouseover
=
__bind
(
this
.
onHighlightMouseover
,
this
);
this
.
checkForEndSelection
=
__bind
(
this
.
checkForEndSelection
,
this
);
this
.
checkForStartSelection
=
__bind
(
this
.
checkForStartSelection
,
this
);
this
.
clearViewerHideTimer
=
__bind
(
this
.
clearViewerHideTimer
,
this
);
this
.
startViewerHideTimer
=
__bind
(
this
.
startViewerHideTimer
,
this
);
this
.
showViewer
=
__bind
(
this
.
showViewer
,
this
);
this
.
onEditorSubmit
=
__bind
(
this
.
onEditorSubmit
,
this
);
this
.
onEditorHide
=
__bind
(
this
.
onEditorHide
,
this
);
this
.
showEditor
=
__bind
(
this
.
showEditor
,
this
);
Annotator
.
__super__
.
constructor
.
apply
(
this
,
arguments
);
this
.
plugins
=
{};
if
(
!
Annotator
.
supported
())
{
return
this
;
}
if
(
!
this
.
options
.
readOnly
)
{
this
.
_setupDocumentEvents
();
}
this
.
_setupWrapper
().
_setupViewer
().
_setupEditor
();
this
.
_setupDynamicStyle
();
this
.
adder
=
$
(
this
.
html
.
adder
).
appendTo
(
this
.
wrapper
).
hide
();
Annotator
.
_instances
.
push
(
this
);
}
Annotator
.
prototype
.
_setupWrapper
=
function
()
{
this
.
wrapper
=
$
(
this
.
html
.
wrapper
);
this
.
element
.
find
(
'script'
).
remove
();
this
.
element
.
wrapInner
(
this
.
wrapper
);
this
.
wrapper
=
this
.
element
.
find
(
'.annotator-wrapper'
);
return
this
;
};
Annotator
.
prototype
.
_setupViewer
=
function
()
{
var
_this
=
this
;
this
.
viewer
=
new
Annotator
.
Viewer
({
readOnly
:
this
.
options
.
readOnly
});
this
.
viewer
.
hide
().
on
(
"edit"
,
this
.
onEditAnnotation
).
on
(
"delete"
,
this
.
onDeleteAnnotation
).
addField
({
load
:
function
(
field
,
annotation
)
{
if
(
annotation
.
text
)
{
$
(
field
).
html
(
Util
.
escape
(
annotation
.
text
));
}
else
{
$
(
field
).
html
(
"<i>"
+
(
_t
(
'No Comment'
))
+
"</i>"
);
}
return
_this
.
publish
(
'annotationViewerTextField'
,
[
field
,
annotation
]);
}
}).
element
.
appendTo
(
this
.
wrapper
).
bind
({
"mouseover"
:
this
.
clearViewerHideTimer
,
"mouseout"
:
this
.
startViewerHideTimer
});
return
this
;
};
Annotator
.
prototype
.
_setupEditor
=
function
()
{
this
.
editor
=
new
Annotator
.
Editor
();
this
.
editor
.
hide
().
on
(
'hide'
,
this
.
onEditorHide
).
on
(
'save'
,
this
.
onEditorSubmit
).
addField
({
type
:
'textarea'
,
label
:
_t
(
'Comments'
)
+
'
\
u2026'
,
load
:
function
(
field
,
annotation
)
{
return
$
(
field
).
find
(
'textarea'
).
val
(
annotation
.
text
||
''
);
},
submit
:
function
(
field
,
annotation
)
{
return
annotation
.
text
=
$
(
field
).
find
(
'textarea'
).
val
();
}
});
this
.
editor
.
element
.
appendTo
(
this
.
wrapper
);
return
this
;
};
Annotator
.
prototype
.
_setupDocumentEvents
=
function
()
{
$
(
document
).
bind
({
"mouseup"
:
this
.
checkForEndSelection
,
"mousedown"
:
this
.
checkForStartSelection
});
return
this
;
};
Annotator
.
prototype
.
_setupDynamicStyle
=
function
()
{
var
max
,
sel
,
style
,
x
;
style
=
$
(
'#annotator-dynamic-style'
);
if
(
!
style
.
length
)
{
style
=
$
(
'<style id="annotator-dynamic-style"></style>'
).
appendTo
(
document
.
head
);
}
sel
=
'*'
+
((
function
()
{
var
_k
,
_len2
,
_ref1
,
_results
;
_ref1
=
[
'adder'
,
'outer'
,
'notice'
,
'filter'
];
_results
=
[];
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
x
=
_ref1
[
_k
];
_results
.
push
(
":not(.annotator-"
+
x
+
")"
);
}
return
_results
;
})()).
join
(
''
);
max
=
Util
.
maxZIndex
(
$
(
document
.
body
).
find
(
sel
));
max
=
Math
.
max
(
max
,
1000
);
style
.
text
([
".annotator-adder, .annotator-outer, .annotator-notice {"
,
" z-index: "
+
(
max
+
20
)
+
";"
,
"}"
,
".annotator-filter {"
,
" z-index: "
+
(
max
+
10
)
+
";"
,
"}"
].
join
(
"
\n
"
));
return
this
;
};
Annotator
.
prototype
.
destroy
=
function
()
{
var
idx
,
name
,
plugin
,
_base
,
_ref1
;
Annotator
.
__super__
.
destroy
.
apply
(
this
,
arguments
);
$
(
document
).
unbind
({
"mouseup"
:
this
.
checkForEndSelection
,
"mousedown"
:
this
.
checkForStartSelection
});
$
(
'#annotator-dynamic-style'
).
remove
();
this
.
adder
.
remove
();
this
.
viewer
.
destroy
();
this
.
editor
.
destroy
();
this
.
wrapper
.
find
(
'.annotator-hl'
).
each
(
function
()
{
$
(
this
).
contents
().
insertBefore
(
this
);
return
$
(
this
).
remove
();
});
this
.
wrapper
.
contents
().
insertBefore
(
this
.
wrapper
);
this
.
wrapper
.
remove
();
this
.
element
.
data
(
'annotator'
,
null
);
_ref1
=
this
.
plugins
;
for
(
name
in
_ref1
)
{
plugin
=
_ref1
[
name
];
if
(
typeof
(
_base
=
this
.
plugins
[
name
]).
destroy
===
"function"
)
{
_base
.
destroy
();
}
}
idx
=
Annotator
.
_instances
.
indexOf
(
this
);
if
(
idx
!==
-
1
)
{
return
Annotator
.
_instances
.
splice
(
idx
,
1
);
}
};
Annotator
.
prototype
.
getSelectedRanges
=
function
()
{
var
browserRange
,
i
,
normedRange
,
r
,
ranges
,
rangesToIgnore
,
selection
,
_k
,
_len2
;
selection
=
Util
.
getGlobal
().
getSelection
();
ranges
=
[];
rangesToIgnore
=
[];
if
(
!
selection
.
isCollapsed
)
{
ranges
=
(
function
()
{
var
_k
,
_ref1
,
_results
;
_results
=
[];
for
(
i
=
_k
=
0
,
_ref1
=
selection
.
rangeCount
;
0
<=
_ref1
?
_k
<
_ref1
:
_k
>
_ref1
;
i
=
0
<=
_ref1
?
++
_k
:
--
_k
)
{
r
=
selection
.
getRangeAt
(
i
);
browserRange
=
new
Range
.
BrowserRange
(
r
);
normedRange
=
browserRange
.
normalize
().
limit
(
this
.
wrapper
[
0
]);
if
(
normedRange
===
null
)
{
rangesToIgnore
.
push
(
r
);
}
_results
.
push
(
normedRange
);
}
return
_results
;
}).
call
(
this
);
selection
.
removeAllRanges
();
}
for
(
_k
=
0
,
_len2
=
rangesToIgnore
.
length
;
_k
<
_len2
;
_k
++
)
{
r
=
rangesToIgnore
[
_k
];
selection
.
addRange
(
r
);
}
return
$
.
grep
(
ranges
,
function
(
range
)
{
if
(
range
)
{
selection
.
addRange
(
range
.
toRange
());
}
return
range
;
});
};
Annotator
.
prototype
.
createAnnotation
=
function
()
{
var
annotation
;
annotation
=
{};
this
.
publish
(
'beforeAnnotationCreated'
,
[
annotation
]);
return
annotation
;
};
Annotator
.
prototype
.
setupAnnotation
=
function
(
annotation
)
{
var
e
,
normed
,
normedRanges
,
r
,
root
,
_k
,
_l
,
_len2
,
_len3
,
_ref1
;
root
=
this
.
wrapper
[
0
];
annotation
.
ranges
||
(
annotation
.
ranges
=
this
.
selectedRanges
);
normedRanges
=
[];
_ref1
=
annotation
.
ranges
;
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
r
=
_ref1
[
_k
];
try
{
normedRanges
.
push
(
Range
.
sniff
(
r
).
normalize
(
root
));
}
catch
(
_error
)
{
e
=
_error
;
if
(
e
instanceof
Range
.
RangeError
)
{
this
.
publish
(
'rangeNormalizeFail'
,
[
annotation
,
r
,
e
]);
}
else
{
throw
e
;
}
}
}
annotation
.
quote
=
[];
annotation
.
ranges
=
[];
annotation
.
highlights
=
[];
for
(
_l
=
0
,
_len3
=
normedRanges
.
length
;
_l
<
_len3
;
_l
++
)
{
normed
=
normedRanges
[
_l
];
annotation
.
quote
.
push
(
$
.
trim
(
normed
.
text
()));
annotation
.
ranges
.
push
(
normed
.
serialize
(
this
.
wrapper
[
0
],
'.annotator-hl'
));
$
.
merge
(
annotation
.
highlights
,
this
.
highlightRange
(
normed
));
}
annotation
.
quote
=
annotation
.
quote
.
join
(
' / '
);
$
(
annotation
.
highlights
).
data
(
'annotation'
,
annotation
);
$
(
annotation
.
highlights
).
attr
(
'data-annotation-id'
,
annotation
.
id
);
return
annotation
;
};
Annotator
.
prototype
.
updateAnnotation
=
function
(
annotation
)
{
this
.
publish
(
'beforeAnnotationUpdated'
,
[
annotation
]);
$
(
annotation
.
highlights
).
attr
(
'data-annotation-id'
,
annotation
.
id
);
this
.
publish
(
'annotationUpdated'
,
[
annotation
]);
return
annotation
;
};
Annotator
.
prototype
.
deleteAnnotation
=
function
(
annotation
)
{
var
child
,
h
,
_k
,
_len2
,
_ref1
;
if
(
annotation
.
highlights
!=
null
)
{
_ref1
=
annotation
.
highlights
;
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
h
=
_ref1
[
_k
];
if
(
!
(
h
.
parentNode
!=
null
))
{
continue
;
}
child
=
h
.
childNodes
[
0
];
$
(
h
).
replaceWith
(
h
.
childNodes
);
}
}
this
.
publish
(
'annotationDeleted'
,
[
annotation
]);
return
annotation
;
};
Annotator
.
prototype
.
loadAnnotations
=
function
(
annotations
)
{
var
clone
,
loader
,
_this
=
this
;
if
(
annotations
==
null
)
{
annotations
=
[];
}
loader
=
function
(
annList
)
{
var
n
,
now
,
_k
,
_len2
;
if
(
annList
==
null
)
{
annList
=
[];
}
now
=
annList
.
splice
(
0
,
10
);
for
(
_k
=
0
,
_len2
=
now
.
length
;
_k
<
_len2
;
_k
++
)
{
n
=
now
[
_k
];
_this
.
setupAnnotation
(
n
);
}
if
(
annList
.
length
>
0
)
{
return
setTimeout
((
function
()
{
return
loader
(
annList
);
}),
10
);
}
else
{
return
_this
.
publish
(
'annotationsLoaded'
,
[
clone
]);
}
};
clone
=
annotations
.
slice
();
loader
(
annotations
);
return
this
;
};
Annotator
.
prototype
.
dumpAnnotations
=
function
()
{
if
(
this
.
plugins
[
'Store'
])
{
return
this
.
plugins
[
'Store'
].
dumpAnnotations
();
}
else
{
console
.
warn
(
_t
(
"Can't dump annotations without Store plugin."
));
return
false
;
}
};
Annotator
.
prototype
.
highlightRange
=
function
(
normedRange
,
cssClass
)
{
var
hl
,
node
,
white
,
_k
,
_len2
,
_ref1
,
_results
;
if
(
cssClass
==
null
)
{
cssClass
=
'annotator-hl'
;
}
white
=
/^
\s
*$/
;
hl
=
$
(
"<span class='"
+
cssClass
+
"'></span>"
);
_ref1
=
normedRange
.
textNodes
();
_results
=
[];
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
node
=
_ref1
[
_k
];
if
(
!
white
.
test
(
node
.
nodeValue
))
{
_results
.
push
(
$
(
node
).
wrapAll
(
hl
).
parent
().
show
()[
0
]);
}
}
return
_results
;
};
Annotator
.
prototype
.
highlightRanges
=
function
(
normedRanges
,
cssClass
)
{
var
highlights
,
r
,
_k
,
_len2
;
if
(
cssClass
==
null
)
{
cssClass
=
'annotator-hl'
;
}
highlights
=
[];
for
(
_k
=
0
,
_len2
=
normedRanges
.
length
;
_k
<
_len2
;
_k
++
)
{
r
=
normedRanges
[
_k
];
$
.
merge
(
highlights
,
this
.
highlightRange
(
r
,
cssClass
));
}
return
highlights
;
};
Annotator
.
prototype
.
addPlugin
=
function
(
name
,
options
)
{
var
klass
,
_base
;
if
(
this
.
plugins
[
name
])
{
console
.
error
(
_t
(
"You cannot have more than one instance of any plugin."
));
}
else
{
klass
=
Annotator
.
Plugin
[
name
];
if
(
typeof
klass
===
'function'
)
{
this
.
plugins
[
name
]
=
new
klass
(
this
.
element
[
0
],
options
);
this
.
plugins
[
name
].
annotator
=
this
;
if
(
typeof
(
_base
=
this
.
plugins
[
name
]).
pluginInit
===
"function"
)
{
_base
.
pluginInit
();
}
}
else
{
console
.
error
(
_t
(
"Could not load "
)
+
name
+
_t
(
" plugin. Have you included the appropriate <script> tag?"
));
}
}
return
this
;
};
Annotator
.
prototype
.
showEditor
=
function
(
annotation
,
location
)
{
this
.
editor
.
element
.
css
(
location
);
this
.
editor
.
load
(
annotation
);
this
.
publish
(
'annotationEditorShown'
,
[
this
.
editor
,
annotation
]);
return
this
;
};
Annotator
.
prototype
.
onEditorHide
=
function
()
{
this
.
publish
(
'annotationEditorHidden'
,
[
this
.
editor
]);
return
this
.
ignoreMouseup
=
false
;
};
Annotator
.
prototype
.
onEditorSubmit
=
function
(
annotation
)
{
return
this
.
publish
(
'annotationEditorSubmit'
,
[
this
.
editor
,
annotation
]);
};
Annotator
.
prototype
.
showViewer
=
function
(
annotations
,
location
)
{
this
.
viewer
.
element
.
css
(
location
);
this
.
viewer
.
load
(
annotations
);
return
this
.
publish
(
'annotationViewerShown'
,
[
this
.
viewer
,
annotations
]);
};
Annotator
.
prototype
.
startViewerHideTimer
=
function
()
{
if
(
!
this
.
viewerHideTimer
)
{
return
this
.
viewerHideTimer
=
setTimeout
(
this
.
viewer
.
hide
,
250
);
}
};
Annotator
.
prototype
.
clearViewerHideTimer
=
function
()
{
clearTimeout
(
this
.
viewerHideTimer
);
return
this
.
viewerHideTimer
=
false
;
};
Annotator
.
prototype
.
checkForStartSelection
=
function
(
event
)
{
if
(
!
(
event
&&
this
.
isAnnotator
(
event
.
target
)))
{
this
.
startViewerHideTimer
();
}
return
this
.
mouseIsDown
=
true
;
};
Annotator
.
prototype
.
checkForEndSelection
=
function
(
event
)
{
var
container
,
range
,
_k
,
_len2
,
_ref1
;
this
.
mouseIsDown
=
false
;
if
(
this
.
ignoreMouseup
)
{
return
;
}
this
.
selectedRanges
=
this
.
getSelectedRanges
();
_ref1
=
this
.
selectedRanges
;
for
(
_k
=
0
,
_len2
=
_ref1
.
length
;
_k
<
_len2
;
_k
++
)
{
range
=
_ref1
[
_k
];
container
=
range
.
commonAncestor
;
if
(
this
.
isAnnotator
(
container
))
{
return
;
}
}
if
(
event
&&
this
.
selectedRanges
.
length
)
{
return
this
.
adder
.
css
(
Util
.
mousePosition
(
event
,
this
.
wrapper
[
0
])).
show
();
}
else
{
return
this
.
adder
.
hide
();
}
};
Annotator
.
prototype
.
isAnnotator
=
function
(
element
)
{
return
!!
$
(
element
).
parents
().
addBack
().
filter
(
'[class^=annotator-]'
).
not
(
'[class=annotator-hl]'
).
not
(
this
.
wrapper
).
length
;
};
Annotator
.
prototype
.
onHighlightMouseover
=
function
(
event
)
{
var
annotations
;
this
.
clearViewerHideTimer
();
if
(
this
.
mouseIsDown
)
{
return
false
;
}
if
(
this
.
viewer
.
isShown
())
{
this
.
viewer
.
hide
();
}
annotations
=
$
(
event
.
target
).
parents
(
'.annotator-hl'
).
addBack
().
map
(
function
()
{
return
$
(
this
).
data
(
"annotation"
);
}).
toArray
();
return
this
.
showViewer
(
annotations
,
Util
.
mousePosition
(
event
,
this
.
wrapper
[
0
]));
};
Annotator
.
prototype
.
onAdderMousedown
=
function
(
event
)
{
if
(
event
!=
null
)
{
event
.
preventDefault
();
}
return
this
.
ignoreMouseup
=
true
;
};
Annotator
.
prototype
.
onAdderClick
=
function
(
event
)
{
var
annotation
,
cancel
,
cleanup
,
position
,
save
,
_this
=
this
;
if
(
event
!=
null
)
{
event
.
preventDefault
();
}
position
=
this
.
adder
.
position
();
this
.
adder
.
hide
();
annotation
=
this
.
setupAnnotation
(
this
.
createAnnotation
());
$
(
annotation
.
highlights
).
addClass
(
'annotator-hl-temporary'
);
save
=
function
()
{
cleanup
();
$
(
annotation
.
highlights
).
removeClass
(
'annotator-hl-temporary'
);
return
_this
.
publish
(
'annotationCreated'
,
[
annotation
]);
};
cancel
=
function
()
{
cleanup
();
return
_this
.
deleteAnnotation
(
annotation
);
};
cleanup
=
function
()
{
_this
.
unsubscribe
(
'annotationEditorHidden'
,
cancel
);
return
_this
.
unsubscribe
(
'annotationEditorSubmit'
,
save
);
};
this
.
subscribe
(
'annotationEditorHidden'
,
cancel
);
this
.
subscribe
(
'annotationEditorSubmit'
,
save
);
return
this
.
showEditor
(
annotation
,
position
);
};
Annotator
.
prototype
.
onEditAnnotation
=
function
(
annotation
)
{
var
cleanup
,
offset
,
update
,
_this
=
this
;
offset
=
this
.
viewer
.
element
.
position
();
update
=
function
()
{
cleanup
();
return
_this
.
updateAnnotation
(
annotation
);
};
cleanup
=
function
()
{
_this
.
unsubscribe
(
'annotationEditorHidden'
,
cleanup
);
return
_this
.
unsubscribe
(
'annotationEditorSubmit'
,
update
);
};
this
.
subscribe
(
'annotationEditorHidden'
,
cleanup
);
this
.
subscribe
(
'annotationEditorSubmit'
,
update
);
this
.
viewer
.
hide
();
return
this
.
showEditor
(
annotation
,
offset
);
};
Annotator
.
prototype
.
onDeleteAnnotation
=
function
(
annotation
)
{
this
.
viewer
.
hide
();
return
this
.
deleteAnnotation
(
annotation
);
};
return
Annotator
;
})(
Delegator
);
Annotator
.
Plugin
=
(
function
(
_super
)
{
__extends
(
Plugin
,
_super
);
function
Plugin
(
element
,
options
)
{
Plugin
.
__super__
.
constructor
.
apply
(
this
,
arguments
);
}
Plugin
.
prototype
.
pluginInit
=
function
()
{};
return
Plugin
;
})(
Delegator
);
g
=
Util
.
getGlobal
();
if
(((
_ref1
=
g
.
document
)
!=
null
?
_ref1
.
evaluate
:
void
0
)
==
null
)
{
$
.
getScript
(
'http://assets.annotateit.org/vendor/xpath.min.js'
);
}
if
(
g
.
getSelection
==
null
)
{
$
.
getScript
(
'http://assets.annotateit.org/vendor/ierange.min.js'
);
}
if
(
g
.
JSON
==
null
)
{
$
.
getScript
(
'http://assets.annotateit.org/vendor/json2.min.js'
);
}
if
(
g
.
Node
==
null
)
{
g
.
Node
=
{
ELEMENT_NODE
:
1
,
ATTRIBUTE_NODE
:
2
,
TEXT_NODE
:
3
,
CDATA_SECTION_NODE
:
4
,
ENTITY_REFERENCE_NODE
:
5
,
ENTITY_NODE
:
6
,
PROCESSING_INSTRUCTION_NODE
:
7
,
COMMENT_NODE
:
8
,
DOCUMENT_NODE
:
9
,
DOCUMENT_TYPE_NODE
:
10
,
DOCUMENT_FRAGMENT_NODE
:
11
,
NOTATION_NODE
:
12
};
}
Annotator
.
$
=
$
;
Annotator
.
Delegator
=
Delegator
;
Annotator
.
Range
=
Range
;
Annotator
.
Util
=
Util
;
Annotator
.
_instances
=
[];
Annotator
.
_t
=
_t
;
Annotator
.
supported
=
function
()
{
return
(
function
()
{
return
!!
this
.
getSelection
;
})();
};
Annotator
.
noConflict
=
function
()
{
Util
.
getGlobal
().
Annotator
=
_Annotator
;
return
this
;
};
$
.
fn
.
annotator
=
function
(
options
)
{
var
args
;
args
=
Array
.
prototype
.
slice
.
call
(
arguments
,
1
);
return
this
.
each
(
function
()
{
var
instance
;
instance
=
$
.
data
(
this
,
'annotator'
);
if
(
options
===
'destroy'
)
{
$
.
removeData
(
this
,
'annotator'
);
return
instance
!=
null
?
instance
.
destroy
(
args
)
:
void
0
;
}
else
if
(
instance
)
{
return
options
&&
instance
[
options
].
apply
(
instance
,
args
);
}
else
{
instance
=
new
Annotator
(
this
,
options
);
return
$
.
data
(
this
,
'annotator'
,
instance
);
}
});
};
this
.
Annotator
=
Annotator
;
Annotator
.
Widget
=
(
function
(
_super
)
{
__extends
(
Widget
,
_super
);
Widget
.
prototype
.
classes
=
{
hide
:
'annotator-hide'
,
invert
:
{
x
:
'annotator-invert-x'
,
y
:
'annotator-invert-y'
}
};
function
Widget
(
element
,
options
)
{
Widget
.
__super__
.
constructor
.
apply
(
this
,
arguments
);
this
.
classes
=
$
.
extend
({},
Annotator
.
Widget
.
prototype
.
classes
,
this
.
classes
);
}
Widget
.
prototype
.
destroy
=
function
()
{
this
.
removeEvents
();
return
this
.
element
.
remove
();
};
Widget
.
prototype
.
checkOrientation
=
function
()
{
var
current
,
offset
,
viewport
,
widget
,
window
;
this
.
resetOrientation
();
window
=
$
(
Annotator
.
Util
.
getGlobal
());
widget
=
this
.
element
.
children
(
":first"
);
offset
=
widget
.
offset
();
viewport
=
{
top
:
window
.
scrollTop
(),
right
:
window
.
width
()
+
window
.
scrollLeft
()
};
current
=
{
top
:
offset
.
top
,
right
:
offset
.
left
+
widget
.
width
()
};
if
((
current
.
top
-
viewport
.
top
)
<
0
)
{
this
.
invertY
();
}
if
((
current
.
right
-
viewport
.
right
)
>
0
)
{
this
.
invertX
();
}
return
this
;
};
Widget
.
prototype
.
resetOrientation
=
function
()
{
this
.
element
.
removeClass
(
this
.
classes
.
invert
.
x
).
removeClass
(
this
.
classes
.
invert
.
y
);
return
this
;
};
Widget
.
prototype
.
invertX
=
function
()
{
this
.
element
.
addClass
(
this
.
classes
.
invert
.
x
);
return
this
;
};
Widget
.
prototype
.
invertY
=
function
()
{
this
.
element
.
addClass
(
this
.
classes
.
invert
.
y
);
return
this
;
};
Widget
.
prototype
.
isInvertedY
=
function
()
{
return
this
.
element
.
hasClass
(
this
.
classes
.
invert
.
y
);
};
Widget
.
prototype
.
isInvertedX
=
function
()
{
return
this
.
element
.
hasClass
(
this
.
classes
.
invert
.
x
);
};
return
Widget
;
})(
Delegator
);
Annotator
.
Editor
=
(
function
(
_super
)
{
__extends
(
Editor
,
_super
);
Editor
.
prototype
.
events
=
{
"form submit"
:
"submit"
,
".annotator-save click"
:
"submit"
,
".annotator-cancel click"
:
"hide"
,
".annotator-cancel mouseover"
:
"onCancelButtonMouseover"
,
"textarea keydown"
:
"processKeypress"
};
Editor
.
prototype
.
classes
=
{
hide
:
'annotator-hide'
,
focus
:
'annotator-focus'
};
Editor
.
prototype
.
html
=
"<div class=
\"
annotator-outer annotator-editor
\"
>
\n
<form class=
\"
annotator-widget
\"
>
\n
<ul class=
\"
annotator-listing
\"
></ul>
\n
<div class=
\"
annotator-controls
\"
>
\n
<a href=
\"
#cancel
\"
class=
\"
annotator-cancel
\"
>"
+
_t
(
'Cancel'
)
+
"</a>
\n
<a href=
\"
#save
\"
class=
\"
annotator-save annotator-focus
\"
>"
+
_t
(
'Save'
)
+
"</a>
\n
</div>
\n
</form>
\n
</div>"
;
Editor
.
prototype
.
options
=
{};
function
Editor
(
options
)
{
this
.
onCancelButtonMouseover
=
__bind
(
this
.
onCancelButtonMouseover
,
this
);
this
.
processKeypress
=
__bind
(
this
.
processKeypress
,
this
);
this
.
submit
=
__bind
(
this
.
submit
,
this
);
this
.
load
=
__bind
(
this
.
load
,
this
);
this
.
hide
=
__bind
(
this
.
hide
,
this
);
this
.
show
=
__bind
(
this
.
show
,
this
);
Editor
.
__super__
.
constructor
.
call
(
this
,
$
(
this
.
html
)[
0
],
options
);
this
.
fields
=
[];
this
.
annotation
=
{};
}
Editor
.
prototype
.
show
=
function
(
event
)
{
Annotator
.
Util
.
preventEventDefault
(
event
);
this
.
element
.
removeClass
(
this
.
classes
.
hide
);
this
.
element
.
find
(
'.annotator-save'
).
addClass
(
this
.
classes
.
focus
);
this
.
checkOrientation
();
this
.
element
.
find
(
":input:first"
).
focus
();
this
.
setupDraggables
();
return
this
.
publish
(
'show'
);
};
Editor
.
prototype
.
hide
=
function
(
event
)
{
Annotator
.
Util
.
preventEventDefault
(
event
);
this
.
element
.
addClass
(
this
.
classes
.
hide
);
return
this
.
publish
(
'hide'
);
};
Editor
.
prototype
.
load
=
function
(
annotation
)
{
var
field
,
_k
,
_len2
,
_ref2
;
this
.
annotation
=
annotation
;
this
.
publish
(
'load'
,
[
this
.
annotation
]);
_ref2
=
this
.
fields
;
for
(
_k
=
0
,
_len2
=
_ref2
.
length
;
_k
<
_len2
;
_k
++
)
{
field
=
_ref2
[
_k
];
field
.
load
(
field
.
element
,
this
.
annotation
);
}
return
this
.
show
();
};
Editor
.
prototype
.
submit
=
function
(
event
)
{
var
field
,
_k
,
_len2
,
_ref2
;
Annotator
.
Util
.
preventEventDefault
(
event
);
_ref2
=
this
.
fields
;
for
(
_k
=
0
,
_len2
=
_ref2
.
length
;
_k
<
_len2
;
_k
++
)
{
field
=
_ref2
[
_k
];
field
.
submit
(
field
.
element
,
this
.
annotation
);
}
this
.
publish
(
'save'
,
[
this
.
annotation
]);
return
this
.
hide
();
};
Editor
.
prototype
.
addField
=
function
(
options
)
{
var
element
,
field
,
input
;
field
=
$
.
extend
({
id
:
'annotator-field-'
+
Annotator
.
Util
.
uuid
(),
type
:
'input'
,
label
:
''
,
load
:
function
()
{},
submit
:
function
()
{}
},
options
);
input
=
null
;
element
=
$
(
'<li class="annotator-item" />'
);
field
.
element
=
element
[
0
];
switch
(
field
.
type
)
{
case
'textarea'
:
input
=
$
(
'<textarea />'
);
break
;
case
'input'
:
case
'checkbox'
:
input
=
$
(
'<input />'
);
break
;
case
'select'
:
input
=
$
(
'<select />'
);
}
element
.
append
(
input
);
input
.
attr
({
id
:
field
.
id
,
placeholder
:
field
.
label
});
if
(
field
.
type
===
'checkbox'
)
{
input
[
0
].
type
=
'checkbox'
;
element
.
addClass
(
'annotator-checkbox'
);
element
.
append
(
$
(
'<label />'
,
{
"for"
:
field
.
id
,
html
:
field
.
label
}));
}
this
.
element
.
find
(
'ul:first'
).
append
(
element
);
this
.
fields
.
push
(
field
);
return
field
.
element
;
};
Editor
.
prototype
.
checkOrientation
=
function
()
{
var
controls
,
list
;
Editor
.
__super__
.
checkOrientation
.
apply
(
this
,
arguments
);
list
=
this
.
element
.
find
(
'ul'
);
controls
=
this
.
element
.
find
(
'.annotator-controls'
);
if
(
this
.
element
.
hasClass
(
this
.
classes
.
invert
.
y
))
{
controls
.
insertBefore
(
list
);
}
else
if
(
controls
.
is
(
':first-child'
))
{
controls
.
insertAfter
(
list
);
}
return
this
;
};
Editor
.
prototype
.
processKeypress
=
function
(
event
)
{
if
(
event
.
keyCode
===
27
)
{
return
this
.
hide
();
}
else
if
(
event
.
keyCode
===
13
&&
!
event
.
shiftKey
)
{
return
this
.
submit
();
}
};
Editor
.
prototype
.
onCancelButtonMouseover
=
function
()
{
return
this
.
element
.
find
(
'.'
+
this
.
classes
.
focus
).
removeClass
(
this
.
classes
.
focus
);
};
Editor
.
prototype
.
setupDraggables
=
function
()
{
var
classes
,
controls
,
cornerItem
,
editor
,
mousedown
,
onMousedown
,
onMousemove
,
onMouseup
,
resize
,
textarea
,
throttle
,
_this
=
this
;
this
.
element
.
find
(
'.annotator-resize'
).
remove
();
if
(
this
.
element
.
hasClass
(
this
.
classes
.
invert
.
y
))
{
cornerItem
=
this
.
element
.
find
(
'.annotator-item:last'
);
}
else
{
cornerItem
=
this
.
element
.
find
(
'.annotator-item:first'
);
}
if
(
cornerItem
)
{
$
(
'<span class="annotator-resize"></span>'
).
appendTo
(
cornerItem
);
}
mousedown
=
null
;
classes
=
this
.
classes
;
editor
=
this
.
element
;
textarea
=
null
;
resize
=
editor
.
find
(
'.annotator-resize'
);
controls
=
editor
.
find
(
'.annotator-controls'
);
throttle
=
false
;
onMousedown
=
function
(
event
)
{
if
(
event
.
target
===
this
)
{
mousedown
=
{
element
:
this
,
top
:
event
.
pageY
,
left
:
event
.
pageX
};
textarea
=
editor
.
find
(
'textarea:first'
);
$
(
window
).
bind
({
'mouseup.annotator-editor-resize'
:
onMouseup
,
'mousemove.annotator-editor-resize'
:
onMousemove
});
return
event
.
preventDefault
();
}
};
onMouseup
=
function
()
{
mousedown
=
null
;
return
$
(
window
).
unbind
(
'.annotator-editor-resize'
);
};
onMousemove
=
function
(
event
)
{
var
diff
,
directionX
,
directionY
,
height
,
width
;
if
(
mousedown
&&
throttle
===
false
)
{
diff
=
{
top
:
event
.
pageY
-
mousedown
.
top
,
left
:
event
.
pageX
-
mousedown
.
left
};
if
(
mousedown
.
element
===
resize
[
0
])
{
height
=
textarea
.
height
();
width
=
textarea
.
width
();
directionX
=
editor
.
hasClass
(
classes
.
invert
.
x
)
?
-
1
:
1
;
directionY
=
editor
.
hasClass
(
classes
.
invert
.
y
)
?
1
:
-
1
;
textarea
.
height
(
height
+
(
diff
.
top
*
directionY
));
textarea
.
width
(
width
+
(
diff
.
left
*
directionX
));
if
(
textarea
.
height
()
!==
height
)
{
mousedown
.
top
=
event
.
pageY
;
}
if
(
textarea
.
width
()
!==
width
)
{
mousedown
.
left
=
event
.
pageX
;
}
}
else
if
(
mousedown
.
element
===
controls
[
0
])
{
editor
.
css
({
top
:
parseInt
(
editor
.
css
(
'top'
),
10
)
+
diff
.
top
,
left
:
parseInt
(
editor
.
css
(
'left'
),
10
)
+
diff
.
left
});
mousedown
.
top
=
event
.
pageY
;
mousedown
.
left
=
event
.
pageX
;
}
throttle
=
true
;
return
setTimeout
(
function
()
{
return
throttle
=
false
;
},
1000
/
60
);
}
};
resize
.
bind
(
'mousedown'
,
onMousedown
);
return
controls
.
bind
(
'mousedown'
,
onMousedown
);
};
return
Editor
;
})(
Annotator
.
Widget
);
Annotator
.
Viewer
=
(
function
(
_super
)
{
__extends
(
Viewer
,
_super
);
Viewer
.
prototype
.
events
=
{
".annotator-edit click"
:
"onEditClick"
,
".annotator-delete click"
:
"onDeleteClick"
};
Viewer
.
prototype
.
classes
=
{
hide
:
'annotator-hide'
,
showControls
:
'annotator-visible'
};
Viewer
.
prototype
.
html
=
{
element
:
"<div class=
\"
annotator-outer annotator-viewer
\"
>
\n
<ul class=
\"
annotator-widget annotator-listing
\"
></ul>
\n
</div>"
,
item
:
"<li class=
\"
annotator-annotation annotator-item
\"
>
\n
<span class=
\"
annotator-controls
\"
>
\n
<a href=
\"
#
\"
title=
\"
View as webpage
\"
class=
\"
annotator-link
\"
>View as webpage</a>
\n
<button title=
\"
Edit
\"
class=
\"
annotator-edit
\"
>Edit</button>
\n
<button title=
\"
Delete
\"
class=
\"
annotator-delete
\"
>Delete</button>
\n
</span>
\n
</li>"
};
Viewer
.
prototype
.
options
=
{
readOnly
:
false
};
function
Viewer
(
options
)
{
this
.
onDeleteClick
=
__bind
(
this
.
onDeleteClick
,
this
);
this
.
onEditClick
=
__bind
(
this
.
onEditClick
,
this
);
this
.
load
=
__bind
(
this
.
load
,
this
);
this
.
hide
=
__bind
(
this
.
hide
,
this
);
this
.
show
=
__bind
(
this
.
show
,
this
);
Viewer
.
__super__
.
constructor
.
call
(
this
,
$
(
this
.
html
.
element
)[
0
],
options
);
this
.
item
=
$
(
this
.
html
.
item
)[
0
];
this
.
fields
=
[];
this
.
annotations
=
[];
}
Viewer
.
prototype
.
show
=
function
(
event
)
{
var
controls
,
_this
=
this
;
Annotator
.
Util
.
preventEventDefault
(
event
);
controls
=
this
.
element
.
find
(
'.annotator-controls'
).
addClass
(
this
.
classes
.
showControls
);
setTimeout
((
function
()
{
return
controls
.
removeClass
(
_this
.
classes
.
showControls
);
}),
500
);
this
.
element
.
removeClass
(
this
.
classes
.
hide
);
return
this
.
checkOrientation
().
publish
(
'show'
);
};
Viewer
.
prototype
.
isShown
=
function
()
{
return
!
this
.
element
.
hasClass
(
this
.
classes
.
hide
);
};
Viewer
.
prototype
.
hide
=
function
(
event
)
{
Annotator
.
Util
.
preventEventDefault
(
event
);
this
.
element
.
addClass
(
this
.
classes
.
hide
);
return
this
.
publish
(
'hide'
);
};
Viewer
.
prototype
.
load
=
function
(
annotations
)
{
var
annotation
,
controller
,
controls
,
del
,
edit
,
element
,
field
,
item
,
link
,
links
,
list
,
_k
,
_l
,
_len2
,
_len3
,
_ref2
,
_ref3
;
this
.
annotations
=
annotations
||
[];
list
=
this
.
element
.
find
(
'ul:first'
).
empty
();
_ref2
=
this
.
annotations
;
for
(
_k
=
0
,
_len2
=
_ref2
.
length
;
_k
<
_len2
;
_k
++
)
{
annotation
=
_ref2
[
_k
];
item
=
$
(
this
.
item
).
clone
().
appendTo
(
list
).
data
(
'annotation'
,
annotation
);
controls
=
item
.
find
(
'.annotator-controls'
);
link
=
controls
.
find
(
'.annotator-link'
);
edit
=
controls
.
find
(
'.annotator-edit'
);
del
=
controls
.
find
(
'.annotator-delete'
);
links
=
new
LinkParser
(
annotation
.
links
||
[]).
get
(
'alternate'
,
{
'type'
:
'text/html'
});
if
(
links
.
length
===
0
||
(
links
[
0
].
href
==
null
))
{
link
.
remove
();
}
else
{
link
.
attr
(
'href'
,
links
[
0
].
href
);
}
if
(
this
.
options
.
readOnly
)
{
edit
.
remove
();
del
.
remove
();
}
else
{
controller
=
{
showEdit
:
function
()
{
return
edit
.
removeAttr
(
'disabled'
);
},
hideEdit
:
function
()
{
return
edit
.
attr
(
'disabled'
,
'disabled'
);
},
showDelete
:
function
()
{
return
del
.
removeAttr
(
'disabled'
);
},
hideDelete
:
function
()
{
return
del
.
attr
(
'disabled'
,
'disabled'
);
}
};
}
_ref3
=
this
.
fields
;
for
(
_l
=
0
,
_len3
=
_ref3
.
length
;
_l
<
_len3
;
_l
++
)
{
field
=
_ref3
[
_l
];
element
=
$
(
field
.
element
).
clone
().
appendTo
(
item
)[
0
];
field
.
load
(
element
,
annotation
,
controller
);
}
}
this
.
publish
(
'load'
,
[
this
.
annotations
]);
return
this
.
show
();
};
Viewer
.
prototype
.
addField
=
function
(
options
)
{
var
field
;
field
=
$
.
extend
({
load
:
function
()
{}
},
options
);
field
.
element
=
$
(
'<div />'
)[
0
];
this
.
fields
.
push
(
field
);
field
.
element
;
return
this
;
};
Viewer
.
prototype
.
onEditClick
=
function
(
event
)
{
return
this
.
onButtonClick
(
event
,
'edit'
);
};
Viewer
.
prototype
.
onDeleteClick
=
function
(
event
)
{
return
this
.
onButtonClick
(
event
,
'delete'
);
};
Viewer
.
prototype
.
onButtonClick
=
function
(
event
,
type
)
{
var
item
;
item
=
$
(
event
.
target
).
parents
(
'.annotator-annotation'
);
return
this
.
publish
(
type
,
[
item
.
data
(
'annotation'
)]);
};
return
Viewer
;
})(
Annotator
.
Widget
);
LinkParser
=
(
function
()
{
function
LinkParser
(
data
)
{
this
.
data
=
data
;
}
LinkParser
.
prototype
.
get
=
function
(
rel
,
cond
)
{
var
d
,
k
,
keys
,
match
,
v
,
_k
,
_len2
,
_ref2
,
_results
;
if
(
cond
==
null
)
{
cond
=
{};
}
cond
=
$
.
extend
({},
cond
,
{
rel
:
rel
});
keys
=
(
function
()
{
var
_results
;
_results
=
[];
for
(
k
in
cond
)
{
if
(
!
__hasProp
.
call
(
cond
,
k
))
continue
;
v
=
cond
[
k
];
_results
.
push
(
k
);
}
return
_results
;
})();
_ref2
=
this
.
data
;
_results
=
[];
for
(
_k
=
0
,
_len2
=
_ref2
.
length
;
_k
<
_len2
;
_k
++
)
{
d
=
_ref2
[
_k
];
match
=
keys
.
reduce
((
function
(
m
,
k
)
{
return
m
&&
(
d
[
k
]
===
cond
[
k
]);
}),
true
);
if
(
match
)
{
_results
.
push
(
d
);
}
else
{
continue
;
}
}
return
_results
;
};
return
LinkParser
;
})();
Annotator
=
Annotator
||
{};
Annotator
.
Notification
=
(
function
(
_super
)
{
__extends
(
Notification
,
_super
);
Notification
.
prototype
.
events
=
{
"click"
:
"hide"
};
Notification
.
prototype
.
options
=
{
html
:
"<div class='annotator-notice'></div>"
,
classes
:
{
show
:
"annotator-notice-show"
,
info
:
"annotator-notice-info"
,
success
:
"annotator-notice-success"
,
error
:
"annotator-notice-error"
}
};
function
Notification
(
options
)
{
this
.
hide
=
__bind
(
this
.
hide
,
this
);
this
.
show
=
__bind
(
this
.
show
,
this
);
Notification
.
__super__
.
constructor
.
call
(
this
,
$
(
this
.
options
.
html
).
appendTo
(
document
.
body
)[
0
],
options
);
}
Notification
.
prototype
.
show
=
function
(
message
,
status
)
{
if
(
status
==
null
)
{
status
=
Annotator
.
Notification
.
INFO
;
}
this
.
currentStatus
=
status
;
$
(
this
.
element
).
addClass
(
this
.
options
.
classes
.
show
).
addClass
(
this
.
options
.
classes
[
this
.
currentStatus
]).
html
(
Util
.
escape
(
message
||
""
));
setTimeout
(
this
.
hide
,
5000
);
return
this
;
};
Notification
.
prototype
.
hide
=
function
()
{
if
(
this
.
currentStatus
==
null
)
{
this
.
currentStatus
=
Annotator
.
Notification
.
INFO
;
}
$
(
this
.
element
).
removeClass
(
this
.
options
.
classes
.
show
).
removeClass
(
this
.
options
.
classes
[
this
.
currentStatus
]);
return
this
;
};
return
Notification
;
})(
Delegator
);
Annotator
.
Notification
.
INFO
=
'info'
;
Annotator
.
Notification
.
SUCCESS
=
'success'
;
Annotator
.
Notification
.
ERROR
=
'error'
;
$
(
function
()
{
var
notification
;
notification
=
new
Annotator
.
Notification
;
Annotator
.
showNotification
=
notification
.
show
;
return
Annotator
.
hideNotification
=
notification
.
hide
;
});
}).
call
(
this
);
//
//# sourceMappingURL=annotator.map
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