Commit a5a8fdc0 authored by Juan Corona's avatar Juan Corona

Remove the annotator.js vendor dependency

In order to avoid heavy refactoring some classes from Annotator were moved over to this codebase.
This includes the class for the `Document` plugin and Annotator’s base class `Delegator`.

The class `Guest` is now responsible for loading the remaining Annotator-style plugin modules.
The base class for `Guest` is now `Delegator` instead of `Annotator`.
parent 46ba01cf
$ = 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
...@@ -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('annotator') Delegator = require('./delegator')
$ = 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 Annotator module.exports = class Guest extends Delegator
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.
...@@ -51,21 +51,39 @@ module.exports = class Guest extends Annotator ...@@ -51,21 +51,39 @@ module.exports = class Guest extends Annotator
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>'
plugins: {}
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) ->
...@@ -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()
...@@ -365,7 +373,7 @@ module.exports = class Guest extends Annotator ...@@ -365,7 +373,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 +383,7 @@ module.exports = class Guest extends Annotator ...@@ -375,7 +383,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 +395,7 @@ module.exports = class Guest extends Annotator ...@@ -387,7 +395,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');
......
Annotator = require('annotator') $ = require('jquery')
$ = Annotator.$
Guest = require('./guest') Guest = require('./guest')
......
...@@ -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);
......
Delegator = require('./delegator')
module.exports = class Plugin extends Delegator
constructor: (element, options) ->
super
pluginInit: () ->
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">
......
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()
......
$ = 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
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
......
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:
......
/*
** 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
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment