Mercurial > hg > digilib-old
diff webapp/src/main/webapp/jquery/annotator-dl.js @ 1146:94a9c2379ebb
new shape annotations work now.
author | robcast |
---|---|
date | Fri, 23 Nov 2012 11:33:08 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webapp/src/main/webapp/jquery/annotator-dl.js Fri Nov 23 11:33:08 2012 +0100 @@ -0,0 +1,2825 @@ +/* +** Annotator 1.2.5-dev-a4cd304 +** https://github.com/okfn/annotator/ +** +** Copyright 2012 Aron Carroll, Rufus Pollock, and Nick Stenning. +** Dual licensed under the MIT and GPLv3 licenses. +** https://github.com/okfn/annotator/blob/master/LICENSE +** +** Built at: 2012-11-23 09:46:08Z +*/ + + +(function() { + var $, Annotator, Delegator, LinkParser, Range, base64Decode, base64UrlDecode, createDateFromISO8601, fn, functions, g, gettext, parseToken, util, _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); }; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + 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.sub(); + + $.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); + }; + + $.plugin = function(name, object) { + return jQuery.fn[name] = function(options) { + var args; + args = Array.prototype.slice.call(arguments, 1); + return this.each(function() { + var instance; + instance = $.data(this, name); + if (instance) { + return options && instance[options].apply(instance, args); + } else { + instance = new object(this, options); + return $.data(this, name, instance); + } + }); + }; + }; + + $.fn.textNodes = function() { + var getTextNodes; + getTextNodes = function(node) { + var nodes; + if (node && node.nodeType !== 3) { + nodes = []; + if (node.nodeType !== 8) { + node = node.lastChild; + while (node) { + nodes.push(getTextNodes(node)); + node = node.previousSibling; + } + } + return nodes.reverse(); + } else { + return node; + } + }; + return this.map(function() { + return $.flatten(getTextNodes(this)); + }); + }; + + $.fn.xpath = function(relativeRoot) { + var jq; + jq = this.map(function() { + var elem, idx, path; + path = ''; + elem = this; + while (elem && elem.nodeType === 1 && elem !== relativeRoot) { + idx = $(elem.parentNode).children(elem.tagName).index(elem) + 1; + idx = "[" + idx + "]"; + path = "/" + elem.tagName.toLowerCase() + idx + path; + elem = elem.parentNode; + } + return path; + }); + return jq.get(); + }; + + $.escape = function(html) { + return html.replace(/&(?!\w+;)/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); + }; + + $.fn.escape = function(html) { + if (arguments.length) { + return this.html($.escape(html)); + } + return this.html(); + }; + + $.fn.reverse = []._reverse || [].reverse; + + 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.on = this.subscribe; + this.addEvents(); + } + + Delegator.prototype.addEvents = function() { + var event, functionName, sel, selector, _k, _ref1, _ref2, _results; + _ref1 = this.events; + _results = []; + for (sel in _ref1) { + functionName = _ref1[sel]; + _ref2 = sel.split(' '), selector = 2 <= _ref2.length ? __slice.call(_ref2, 0, _k = _ref2.length - 1) : (_k = 0, []), event = _ref2[_k++]; + _results.push(this.addEvent(selector.join(' '), event, functionName)); + } + return _results; + }; + + Delegator.prototype.addEvent = function(bindTo, event, functionName) { + var closure, isBlankSelector, + _this = this; + closure = function() { + return _this[functionName].apply(_this, arguments); + }; + isBlankSelector = typeof bindTo === 'string' && bindTo.replace(/\s+/g, '') === ''; + if (isBlankSelector) { + bindTo = this.element; + } + if (typeof bindTo === 'string') { + this.element.delegate(bindTo, event, closure); + } else { + if (this.isCustomEvent(event)) { + this.subscribe(event, closure); + } else { + $(bindTo).bind(event, closure); + } + } + return this; + }; + + Delegator.prototype.isCustomEvent = function(event) { + event = event.split('.')[0]; + return $.inArray(event, Delegator.natives) === -1; + }; + + 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.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\nmousedown mouseup mousemove mouseover mouseout mouseenter mouseleave\nchange select submit keydown keypress keyup error".split(/[^a-z]+/).concat(specials); + })(); + + 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) { + if (nsResolver == null) { + nsResolver = null; + } + return document.evaluate('.' + xp, root, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + }; + 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 it, node, nr, offset, p, r, _k, _len2, _ref1; + if (this.tainted) { + console.error(_t("You may only call normalize() once on a BrowserRange!")); + return false; + } else { + this.tainted = true; + } + r = {}; + nr = {}; + _ref1 = ['start', 'end']; + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + p = _ref1[_k]; + node = this[p + 'Container']; + offset = this[p + 'Offset']; + if (!((node != null) && (offset != null))) { + return false; + } + if (node.nodeType === 1) { + it = node.childNodes[offset]; + node = it || node.childNodes[offset - 1]; + if (node.nodeType === 1 && !node.firstChild) { + it = null; + node = node.previousSibling; + } + while (node.nodeType !== 3) { + node = node.firstChild; + } + offset = it ? 0 : node.nodeValue.length; + } + r[p] = node; + r[p + 'Offset'] = offset; + } + nr.start = r.startOffset > 0 ? r.start.splitText(r.startOffset) : r.start; + if (r.start === r.end) { + if ((r.endOffset - r.startOffset) < nr.start.nodeValue.length) { + nr.start.splitText(r.endOffset - r.startOffset); + } + nr.end = nr.start; + } else { + if (r.endOffset < r.end.nodeValue.length) { + r.end.splitText(r.endOffset); + } + nr.end = r.end; + } + nr.commonAncestor = this.commonAncestorContainer; + while (nr.commonAncestor.nodeType !== 1) { + 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 = origParent.xpath(root)[0]; + textNodes = origParent.textNodes(); + 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 = $(this.commonAncestor).textNodes(); + _ref1 = [textNodes.index(this.start), textNodes.index(this.end)], start = _ref1[0], end = _ref1[1]; + return $.makeArray(textNodes.slice(start, end + 1 || 9e9)); + }; + + 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, length, node, p, range, 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 (e) { + 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; + _ref2 = $(node).textNodes(); + for (_l = 0, _len3 = _ref2.length; _l < _len3; _l++) { + tn = _ref2[_l]; + if (length + tn.nodeValue.length >= this[p + 'Offset']) { + 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().reverse().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; + + })(); + + util = { + uuid: (function() { + var counter; + counter = 0; + return function() { + return counter++; + }; + })(), + getGlobal: function() { + return (function() { + return this; + })(); + }, + maxZIndex: function($elements) { + var all, el; + all = (function() { + var _k, _len2, _results; + _results = []; + for (_k = 0, _len2 = $elements.length; _k < _len2; _k++) { + el = $elements[_k]; + if ($(el).css('position') === 'static') { + _results.push(-1); + } else { + _results.push(parseInt($(el).css('z-index'), 10) || -1); + } + } + return _results; + })(); + return Math.max.apply(Math, all); + }, + mousePosition: function(e, offsetEl) { + var offset; + offset = $(offsetEl).offset(); + return { + top: e.pageY - offset.top, + left: e.pageX - offset.left + }; + }, + preventEventDefault: function(event) { + return event != null ? typeof event.preventDefault === "function" ? event.preventDefault() : void 0 : void 0; + } + }; + + _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.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).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.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, fireEvents) { + var normed, normedRanges, r, root, _k, _l, _len2, _len3, _ref1; + if (fireEvents == null) { + fireEvents = true; + } + 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 (e) { + 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); + if (fireEvents) { + this.publish('annotationCreated', [annotation]); + } + return annotation; + }; + + Annotator.prototype.updateAnnotation = function(annotation) { + this.publish('beforeAnnotationUpdated', [annotation]); + this.publish('annotationUpdated', [annotation]); + return annotation; + }; + + Annotator.prototype.deleteAnnotation = function(annotation) { + var h, _k, _len2, _ref1; + _ref1 = annotation.highlights; + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + h = _ref1[_k]; + $(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, false); + } + if (annList.length > 0) { + return setTimeout((function() { + return loader(annList); + }), 10); + } else { + return _this.publish('annotationsLoaded', [clone]); + } + }; + clone = annotations.slice(); + if (annotations.length) { + loader(annotations); + } + return this; + }; + + Annotator.prototype.dumpAnnotations = function() { + if (this.plugins['Store']) { + return this.plugins['Store'].dumpAnnotations(); + } else { + return console.warn(_t("Can't dump annotations without Store plugin.")); + } + }; + + 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) { + this.publish('annotationEditorSubmit', [this.editor, annotation]); + if (annotation.ranges === void 0) { + return this.setupAnnotation(annotation); + } else { + return this.updateAnnotation(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 ($(container).hasClass('annotator-hl')) { + container = $(container).parents('[class^=annotator-hl]')[0]; + } + 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().andSelf().filter('[class^=annotator-]').not(this.wrapper).length; + }; + + Annotator.prototype.onHighlightMouseover = function(event) { + var annotations; + this.clearViewerHideTimer(); + if (this.mouseIsDown || this.viewer.isShown()) { + return false; + } + annotations = $(event.target).parents('.annotator-hl').andSelf().map(function() { + return $(this).data("annotation"); + }); + return this.showViewer($.makeArray(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 highlights, position, r, ranges; + if (event != null) { + event.preventDefault(); + } + position = this.adder.position(); + this.adder.hide(); + if (this.selectedRanges && this.selectedRanges.length) { + ranges = (function() { + var _k, _len2, _ref1, _results; + _ref1 = this.selectedRanges; + _results = []; + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + r = _ref1[_k]; + _results.push(Range.sniff(r).normalize()); + } + return _results; + }).call(this); + highlights = this.highlightRanges(ranges, 'annotator-hl annotator-hl-temporary'); + this.editor.element.one('hide', function() { + var h, _k, _len2, _results; + _results = []; + for (_k = 0, _len2 = highlights.length; _k < _len2; _k++) { + h = highlights[_k]; + _results.push($(h).replaceWith(h.childNodes)); + } + return _results; + }); + } + return this.showEditor(this.createAnnotation(), position); + }; + + Annotator.prototype.onEditAnnotation = function(annotation) { + var offset; + offset = this.viewer.element.position(); + 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'); + } + + Annotator.$ = $; + + Annotator.Delegator = Delegator; + + Annotator.Range = Range; + + Annotator._t = _t; + + Annotator.supported = function() { + return (function() { + return !!this.getSelection; + })(); + }; + + Annotator.noConflict = function() { + util.getGlobal().Annotator = _Annotator; + return this; + }; + + $.plugin('annotator', Annotator); + + 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.checkOrientation = function() { + var current, offset, viewport, widget, window; + this.resetOrientation(); + window = $(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) { + 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) { + 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; + 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-' + 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 />'); + } + 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.outerHeight(); + width = textarea.outerWidth(); + 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.outerHeight() !== height) { + mousedown.top = event.pageY; + } + if (textarea.outerWidth() !== 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; + 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) { + 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.element).addClass(this.options.classes.show).addClass(this.options.classes[status]).escape(message || ""); + setTimeout(this.hide, 5000); + return this; + }; + + Notification.prototype.hide = function() { + $(this.element).removeClass(this.options.classes.show); + return this; + }; + + return Notification; + + })(Delegator); + + Annotator.Notification.INFO = 'show'; + + Annotator.Notification.SUCCESS = 'success'; + + Annotator.Notification.ERROR = 'error'; + + $(function() { + var notification; + notification = new Annotator.Notification; + Annotator.showNotification = notification.show; + return Annotator.hideNotification = notification.hide; + }); + + Annotator.Plugin.Unsupported = (function(_super) { + + __extends(Unsupported, _super); + + function Unsupported() { + return Unsupported.__super__.constructor.apply(this, arguments); + } + + Unsupported.prototype.options = { + message: Annotator._t("Sorry your current browser does not support the Annotator") + }; + + Unsupported.prototype.pluginInit = function() { + var _this = this; + if (!Annotator.supported()) { + return $(function() { + Annotator.showNotification(_this.options.message); + if ((window.XMLHttpRequest === void 0) && (ActiveXObject !== void 0)) { + return $('html').addClass('ie6'); + } + }); + } + }; + + return Unsupported; + + })(Annotator.Plugin); + + createDateFromISO8601 = function(string) { + var d, date, offset, regexp, time, _ref2; + regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" + "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"; + d = string.match(new RegExp(regexp)); + offset = 0; + date = new Date(d[1], 0, 1); + if (d[3]) { + date.setMonth(d[3] - 1); + } + if (d[5]) { + date.setDate(d[5]); + } + if (d[7]) { + date.setHours(d[7]); + } + if (d[8]) { + date.setMinutes(d[8]); + } + if (d[10]) { + date.setSeconds(d[10]); + } + if (d[12]) { + date.setMilliseconds(Number("0." + d[12]) * 1000); + } + if (d[14]) { + offset = (Number(d[16]) * 60) + Number(d[17]); + offset *= (_ref2 = d[15] === '-') != null ? _ref2 : { + 1: -1 + }; + } + offset -= date.getTimezoneOffset(); + time = Number(date) + (offset * 60 * 1000); + date.setTime(Number(time)); + return date; + }; + + base64Decode = function(data) { + var ac, b64, bits, dec, h1, h2, h3, h4, i, o1, o2, o3, tmp_arr; + if (typeof atob !== "undefined" && atob !== null) { + return atob(data); + } else { + b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + i = 0; + ac = 0; + dec = ""; + tmp_arr = []; + if (!data) { + return data; + } + data += ''; + while (i < data.length) { + h1 = b64.indexOf(data.charAt(i++)); + h2 = b64.indexOf(data.charAt(i++)); + h3 = b64.indexOf(data.charAt(i++)); + h4 = b64.indexOf(data.charAt(i++)); + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + o1 = bits >> 16 & 0xff; + o2 = bits >> 8 & 0xff; + o3 = bits & 0xff; + if (h3 === 64) { + tmp_arr[ac++] = String.fromCharCode(o1); + } else if (h4 === 64) { + tmp_arr[ac++] = String.fromCharCode(o1, o2); + } else { + tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); + } + } + return tmp_arr.join(''); + } + }; + + base64UrlDecode = function(data) { + var i, m, _k, _ref2; + m = data.length % 4; + if (m !== 0) { + for (i = _k = 0, _ref2 = 4 - m; 0 <= _ref2 ? _k < _ref2 : _k > _ref2; i = 0 <= _ref2 ? ++_k : --_k) { + data += '='; + } + } + data = data.replace(/-/g, '+'); + data = data.replace(/_/g, '/'); + return base64Decode(data); + }; + + parseToken = function(token) { + var head, payload, sig, _ref2; + _ref2 = token.split('.'), head = _ref2[0], payload = _ref2[1], sig = _ref2[2]; + return JSON.parse(base64UrlDecode(payload)); + }; + + Annotator.Plugin.Auth = (function(_super) { + + __extends(Auth, _super); + + Auth.prototype.options = { + token: null, + tokenUrl: '/auth/token', + autoFetch: true, + requestMethod: 'GET', + requestData: null, + unauthorizedCallback: null + }; + + function Auth(element, options) { + Auth.__super__.constructor.apply(this, arguments); + this.waitingForToken = []; + if (this.options.token) { + this.setToken(this.options.token); + } else { + this.requestToken(); + } + } + + Auth.prototype.requestToken = function() { + var _this = this; + this.requestInProgress = true; + return $.ajax({ + url: this.options.tokenUrl, + dataType: 'text', + data: this.options.requestData, + type: this.options.requestMethod, + xhrFields: { + withCredentials: true + } + }).done(function(data, status, xhr) { + return _this.setToken(data); + }).fail(function(xhr, status, err) { + var callback, msg; + if (xhr.status === 401) { + callback = _this.options.unauthorizedCallback; + if ((callback != null) && callback(_this)) { + _this.retryTimeout = setTimeout((function() { + return _this.requestToken(); + }), 1000); + return; + } + } + msg = Annotator._t("Couldn't get auth token:"); + console.error("" + msg + " " + err, xhr); + return Annotator.showNotification("" + msg + " " + xhr.responseText, Annotator.Notification.ERROR); + }).always(function() { + return _this.requestInProgress = false; + }); + }; + + Auth.prototype.setToken = function(token) { + var _results, + _this = this; + this.token = token; + this._unsafeToken = parseToken(token); + if (this.haveValidToken()) { + if (this.options.autoFetch) { + this.refreshTimeout = setTimeout((function() { + return _this.requestToken(); + }), (this.timeToExpiry() - 2) * 1000); + } + this.updateHeaders(); + _results = []; + while (this.waitingForToken.length > 0) { + _results.push(this.waitingForToken.pop()(this._unsafeToken)); + } + return _results; + } else { + console.warn(Annotator._t("Didn't get a valid token.")); + if (this.options.autoFetch) { + console.warn(Annotator._t("Getting a new token in 10s.")); + return setTimeout((function() { + return _this.requestToken(); + }), 10 * 1000); + } + } + }; + + Auth.prototype.haveValidToken = function() { + var allFields; + allFields = this._unsafeToken && this._unsafeToken.issuedAt && this._unsafeToken.ttl && this._unsafeToken.consumerKey; + return allFields && this.timeToExpiry() > 0; + }; + + Auth.prototype.timeToExpiry = function() { + var expiry, issue, now, timeToExpiry; + now = new Date().getTime() / 1000; + issue = createDateFromISO8601(this._unsafeToken.issuedAt).getTime() / 1000; + expiry = issue + this._unsafeToken.ttl; + timeToExpiry = expiry - now; + if (timeToExpiry > 0) { + return timeToExpiry; + } else { + return 0; + } + }; + + Auth.prototype.updateHeaders = function() { + var current; + current = this.element.data('annotator:headers'); + return this.element.data('annotator:headers', $.extend(current, { + 'x-annotator-auth-token': this.token + })); + }; + + Auth.prototype.withToken = function(callback) { + if (!(callback != null)) { + return; + } + if (this.haveValidToken()) { + return callback(this._unsafeToken); + } else { + this.waitingForToken.push(callback); + if (!this.requestInProgress) { + return this.requestToken(); + } + } + }; + + return Auth; + + })(Annotator.Plugin); + + Annotator.Plugin.Store = (function(_super) { + + __extends(Store, _super); + + Store.prototype.events = { + 'annotationCreated': 'annotationCreated', + 'annotationDeleted': 'annotationDeleted', + 'annotationUpdated': 'annotationUpdated' + }; + + Store.prototype.options = { + prefix: '/store', + autoFetch: true, + annotationData: {}, + loadFromSearch: false, + urls: { + create: '/annotations', + read: '/annotations/:id', + update: '/annotations/:id', + destroy: '/annotations/:id', + search: '/search' + } + }; + + function Store(element, options) { + this._onError = __bind(this._onError, this); + + this._onLoadAnnotationsFromSearch = __bind(this._onLoadAnnotationsFromSearch, this); + + this._onLoadAnnotations = __bind(this._onLoadAnnotations, this); + + this._getAnnotations = __bind(this._getAnnotations, this); + Store.__super__.constructor.apply(this, arguments); + this.annotations = []; + } + + Store.prototype.pluginInit = function() { + if (!Annotator.supported()) { + return; + } + if (this.annotator.plugins.Auth) { + return this.annotator.plugins.Auth.withToken(this._getAnnotations); + } else { + return this._getAnnotations(); + } + }; + + Store.prototype._getAnnotations = function() { + if (this.options.loadFromSearch) { + return this.loadAnnotationsFromSearch(this.options.loadFromSearch); + } else { + return this.loadAnnotations(); + } + }; + + Store.prototype.annotationCreated = function(annotation) { + var _this = this; + if (__indexOf.call(this.annotations, annotation) < 0) { + this.registerAnnotation(annotation); + return this._apiRequest('create', annotation, function(data) { + if (!(data.id != null)) { + console.warn(Annotator._t("Warning: No ID returned from server for annotation "), annotation); + } + return _this.updateAnnotation(annotation, data); + }); + } else { + return this.updateAnnotation(annotation, {}); + } + }; + + Store.prototype.annotationUpdated = function(annotation) { + var _this = this; + if (__indexOf.call(this.annotations, annotation) >= 0) { + return this._apiRequest('update', annotation, (function(data) { + return _this.updateAnnotation(annotation, data); + })); + } + }; + + Store.prototype.annotationDeleted = function(annotation) { + var _this = this; + if (__indexOf.call(this.annotations, annotation) >= 0) { + return this._apiRequest('destroy', annotation, (function() { + return _this.unregisterAnnotation(annotation); + })); + } + }; + + Store.prototype.registerAnnotation = function(annotation) { + return this.annotations.push(annotation); + }; + + Store.prototype.unregisterAnnotation = function(annotation) { + return this.annotations.splice(this.annotations.indexOf(annotation), 1); + }; + + Store.prototype.updateAnnotation = function(annotation, data) { + if (__indexOf.call(this.annotations, annotation) < 0) { + console.error(Annotator._t("Trying to update unregistered annotation!")); + } else { + $.extend(annotation, data); + } + return $(annotation.highlights).data('annotation', annotation); + }; + + Store.prototype.loadAnnotations = function() { + return this._apiRequest('read', null, this._onLoadAnnotations); + }; + + Store.prototype._onLoadAnnotations = function(data) { + if (data == null) { + data = []; + } + this.annotations = data; + return this.annotator.loadAnnotations(data.slice()); + }; + + Store.prototype.loadAnnotationsFromSearch = function(searchOptions) { + return this._apiRequest('search', searchOptions, this._onLoadAnnotationsFromSearch); + }; + + Store.prototype._onLoadAnnotationsFromSearch = function(data) { + if (data == null) { + data = {}; + } + return this._onLoadAnnotations(data.rows || []); + }; + + Store.prototype.dumpAnnotations = function() { + var ann, _k, _len2, _ref2, _results; + _ref2 = this.annotations; + _results = []; + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + ann = _ref2[_k]; + _results.push(JSON.parse(this._dataFor(ann))); + } + return _results; + }; + + Store.prototype._apiRequest = function(action, obj, onSuccess) { + var id, options, request, url; + id = obj && obj.id; + url = this._urlFor(action, id); + options = this._apiRequestOptions(action, obj, onSuccess); + request = $.ajax(url, options); + request._id = id; + request._action = action; + return request; + }; + + Store.prototype._apiRequestOptions = function(action, obj, onSuccess) { + var opts; + opts = { + type: this._methodFor(action), + headers: this.element.data('annotator:headers'), + dataType: "json", + success: onSuccess || function() {}, + error: this._onError + }; + if (action === "search") { + opts = $.extend(opts, { + data: obj + }); + } else { + opts = $.extend(opts, { + data: obj && this._dataFor(obj), + contentType: "application/json; charset=utf-8" + }); + } + return opts; + }; + + Store.prototype._urlFor = function(action, id) { + var replaceWith, url; + replaceWith = id != null ? '/' + id : ''; + url = this.options.prefix || '/'; + url += this.options.urls[action]; + url = url.replace(/\/:id/, replaceWith); + return url; + }; + + Store.prototype._methodFor = function(action) { + var table; + table = { + 'create': 'POST', + 'read': 'GET', + 'update': 'PUT', + 'destroy': 'DELETE', + 'search': 'GET' + }; + return table[action]; + }; + + Store.prototype._dataFor = function(annotation) { + var data, highlights; + highlights = annotation.highlights; + delete annotation.highlights; + $.extend(annotation, this.options.annotationData); + data = JSON.stringify(annotation); + if (highlights) { + annotation.highlights = highlights; + } + return data; + }; + + Store.prototype._onError = function(xhr) { + var action, message; + action = xhr._action; + message = Annotator._t("Sorry we could not ") + action + Annotator._t(" this annotation"); + if (xhr._action === 'search') { + message = Annotator._t("Sorry we could not search the store for annotations"); + } else if (xhr._action === 'read' && !xhr._id) { + message = Annotator._t("Sorry we could not ") + action + Annotator._t(" the annotations from the store"); + } + switch (xhr.status) { + case 401: + message = Annotator._t("Sorry you are not allowed to ") + action + Annotator._t(" this annotation"); + break; + case 404: + message = Annotator._t("Sorry we could not connect to the annotations store"); + break; + case 500: + message = Annotator._t("Sorry something went wrong with the annotation store"); + } + Annotator.showNotification(message, Annotator.Notification.ERROR); + return console.error(Annotator._t("API request failed:") + (" '" + xhr.status + "'")); + }; + + return Store; + + })(Annotator.Plugin); + + Annotator.Plugin.Permissions = (function(_super) { + + __extends(Permissions, _super); + + Permissions.prototype.events = { + 'beforeAnnotationCreated': 'addFieldsToAnnotation' + }; + + Permissions.prototype.options = { + showViewPermissionsCheckbox: true, + showEditPermissionsCheckbox: true, + userId: function(user) { + return user; + }, + userString: function(user) { + return user; + }, + userAuthorize: function(action, annotation, user) { + var token, tokens, _k, _len2; + if (annotation.permissions) { + tokens = annotation.permissions[action] || []; + if (tokens.length === 0) { + return true; + } + for (_k = 0, _len2 = tokens.length; _k < _len2; _k++) { + token = tokens[_k]; + if (this.userId(user) === token) { + return true; + } + } + return false; + } else if (annotation.user) { + return user && this.userId(user) === this.userId(annotation.user); + } + return true; + }, + user: '', + permissions: { + 'read': [], + 'update': [], + 'delete': [], + 'admin': [] + } + }; + + function Permissions(element, options) { + this._setAuthFromToken = __bind(this._setAuthFromToken, this); + + this.updateViewer = __bind(this.updateViewer, this); + + this.updateAnnotationPermissions = __bind(this.updateAnnotationPermissions, this); + + this.updatePermissionsField = __bind(this.updatePermissionsField, this); + + this.addFieldsToAnnotation = __bind(this.addFieldsToAnnotation, this); + Permissions.__super__.constructor.apply(this, arguments); + if (this.options.user) { + this.setUser(this.options.user); + delete this.options.user; + } + } + + Permissions.prototype.pluginInit = function() { + var createCallback, self, + _this = this; + if (!Annotator.supported()) { + return; + } + self = this; + createCallback = function(method, type) { + return function(field, annotation) { + return self[method].call(self, type, field, annotation); + }; + }; + if (!this.user && this.annotator.plugins.Auth) { + this.annotator.plugins.Auth.withToken(this._setAuthFromToken); + } + if (this.options.showViewPermissionsCheckbox === true) { + this.annotator.editor.addField({ + type: 'checkbox', + label: Annotator._t('Allow anyone to <strong>view</strong> this annotation'), + load: createCallback('updatePermissionsField', 'read'), + submit: createCallback('updateAnnotationPermissions', 'read') + }); + } + if (this.options.showEditPermissionsCheckbox === true) { + this.annotator.editor.addField({ + type: 'checkbox', + label: Annotator._t('Allow anyone to <strong>edit</strong> this annotation'), + load: createCallback('updatePermissionsField', 'update'), + submit: createCallback('updateAnnotationPermissions', 'update') + }); + } + this.annotator.viewer.addField({ + load: this.updateViewer + }); + if (this.annotator.plugins.Filter) { + return this.annotator.plugins.Filter.addFilter({ + label: Annotator._t('User'), + property: 'user', + isFiltered: function(input, user) { + var keyword, _k, _len2, _ref2; + user = _this.options.userString(user); + if (!(input && user)) { + return false; + } + _ref2 = input.split(/\s*/); + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + keyword = _ref2[_k]; + if (user.indexOf(keyword) === -1) { + return false; + } + } + return true; + } + }); + } + }; + + Permissions.prototype.setUser = function(user) { + return this.user = user; + }; + + Permissions.prototype.addFieldsToAnnotation = function(annotation) { + if (annotation) { + annotation.permissions = this.options.permissions; + if (this.user) { + return annotation.user = this.user; + } + } + }; + + Permissions.prototype.authorize = function(action, annotation, user) { + if (user === void 0) { + user = this.user; + } + if (this.options.userAuthorize) { + return this.options.userAuthorize.call(this.options, action, annotation, user); + } else { + return true; + } + }; + + Permissions.prototype.updatePermissionsField = function(action, field, annotation) { + var input; + field = $(field).show(); + input = field.find('input').removeAttr('disabled'); + if (!this.authorize('admin', annotation)) { + field.hide(); + } + if (this.authorize(action, annotation || {}, null)) { + return input.attr('checked', 'checked'); + } else { + return input.removeAttr('checked'); + } + }; + + Permissions.prototype.updateAnnotationPermissions = function(type, field, annotation) { + var dataKey; + if (!annotation.permissions) { + annotation.permissions = this.options.permissions; + } + dataKey = type + '-permissions'; + if ($(field).find('input').is(':checked')) { + return annotation.permissions[type] = []; + } else { + return annotation.permissions[type] = [this.user]; + } + }; + + Permissions.prototype.updateViewer = function(field, annotation, controls) { + var user, username; + field = $(field); + username = this.options.userString(annotation.user); + if (annotation.user && username && typeof username === 'string') { + user = Annotator.$.escape(this.options.userString(annotation.user)); + field.html(user).addClass('annotator-user'); + } else { + field.remove(); + } + if (controls) { + if (!this.authorize('update', annotation)) { + controls.hideEdit(); + } + if (!this.authorize('delete', annotation)) { + return controls.hideDelete(); + } + } + }; + + Permissions.prototype._setAuthFromToken = function(token) { + return this.setUser(token.userId); + }; + + return Permissions; + + })(Annotator.Plugin); + + Annotator.Plugin.Filter = (function(_super) { + + __extends(Filter, _super); + + Filter.prototype.events = { + ".annotator-filter-property input focus": "_onFilterFocus", + ".annotator-filter-property input blur": "_onFilterBlur", + ".annotator-filter-property input keyup": "_onFilterKeyup", + ".annotator-filter-previous click": "_onPreviousClick", + ".annotator-filter-next click": "_onNextClick", + ".annotator-filter-clear click": "_onClearClick" + }; + + Filter.prototype.classes = { + active: 'annotator-filter-active', + hl: { + hide: 'annotator-hl-filtered', + active: 'annotator-hl-active' + } + }; + + Filter.prototype.html = { + element: "<div class=\"annotator-filter\">\n <strong>" + Annotator._t('Navigate:') + "</strong>\n<span class=\"annotator-filter-navigation\">\n <button class=\"annotator-filter-previous\">" + Annotator._t('Previous') + "</button>\n<button class=\"annotator-filter-next\">" + Annotator._t('Next') + "</button>\n</span>\n<strong>" + Annotator._t('Filter by:') + "</strong>\n</div>", + filter: "<span class=\"annotator-filter-property\">\n <label></label>\n <input/>\n <button class=\"annotator-filter-clear\">" + Annotator._t('Clear') + "</button>\n</span>" + }; + + Filter.prototype.options = { + appendTo: 'body', + filters: [], + addAnnotationFilter: true, + isFiltered: function(input, property) { + var keyword, _k, _len2, _ref2; + if (!(input && property)) { + return false; + } + _ref2 = input.split(/\s*/); + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + keyword = _ref2[_k]; + if (property.indexOf(keyword) === -1) { + return false; + } + } + return true; + } + }; + + function Filter(element, options) { + this._onPreviousClick = __bind(this._onPreviousClick, this); + + this._onNextClick = __bind(this._onNextClick, this); + + this._onFilterKeyup = __bind(this._onFilterKeyup, this); + + this._onFilterBlur = __bind(this._onFilterBlur, this); + + this._onFilterFocus = __bind(this._onFilterFocus, this); + + this.updateHighlights = __bind(this.updateHighlights, this); + + var _base; + element = $(this.html.element).appendTo((options != null ? options.appendTo : void 0) || this.options.appendTo); + Filter.__super__.constructor.call(this, element, options); + (_base = this.options).filters || (_base.filters = []); + this.filter = $(this.html.filter); + this.filters = []; + this.current = 0; + } + + Filter.prototype.pluginInit = function() { + var filter, _k, _len2, _ref2; + _ref2 = this.options.filters; + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + filter = _ref2[_k]; + this.addFilter(filter); + } + this.updateHighlights(); + this._setupListeners()._insertSpacer(); + if (this.options.addAnnotationFilter === true) { + return this.addFilter({ + label: Annotator._t('Annotation'), + property: 'text' + }); + } + }; + + Filter.prototype._insertSpacer = function() { + var currentMargin, html; + html = $('html'); + currentMargin = parseInt(html.css('padding-top'), 10) || 0; + html.css('padding-top', currentMargin + this.element.outerHeight()); + return this; + }; + + Filter.prototype._setupListeners = function() { + var event, events, _k, _len2; + events = ['annotationsLoaded', 'annotationCreated', 'annotationUpdated', 'annotationDeleted']; + for (_k = 0, _len2 = events.length; _k < _len2; _k++) { + event = events[_k]; + this.annotator.subscribe(event, this.updateHighlights); + } + return this; + }; + + Filter.prototype.addFilter = function(options) { + var f, filter; + filter = $.extend({ + label: '', + property: '', + isFiltered: this.options.isFiltered + }, options); + if (!((function() { + var _k, _len2, _ref2, _results; + _ref2 = this.filters; + _results = []; + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + f = _ref2[_k]; + if (f.property === filter.property) { + _results.push(f); + } + } + return _results; + }).call(this)).length) { + filter.id = 'annotator-filter-' + filter.property; + filter.annotations = []; + filter.element = this.filter.clone().appendTo(this.element); + filter.element.find('label').html(filter.label).attr('for', filter.id); + filter.element.find('input').attr({ + id: filter.id, + placeholder: Annotator._t('Filter by ') + filter.label + '\u2026' + }); + filter.element.find('button').hide(); + filter.element.data('filter', filter); + this.filters.push(filter); + } + return this; + }; + + Filter.prototype.updateFilter = function(filter) { + var annotation, annotations, input, property, _k, _len2, _ref2; + filter.annotations = []; + this.updateHighlights(); + this.resetHighlights(); + input = $.trim(filter.element.find('input').val()); + if (input) { + annotations = this.highlights.map(function() { + return $(this).data('annotation'); + }); + _ref2 = $.makeArray(annotations); + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + annotation = _ref2[_k]; + property = annotation[filter.property]; + if (filter.isFiltered(input, property)) { + filter.annotations.push(annotation); + } + } + return this.filterHighlights(); + } + }; + + Filter.prototype.updateHighlights = function() { + this.highlights = this.annotator.element.find('.annotator-hl:visible'); + return this.filtered = this.highlights.not(this.classes.hl.hide); + }; + + Filter.prototype.filterHighlights = function() { + var activeFilters, annotation, annotations, filtered, highlights, index, uniques, _k, _len2, _ref2; + activeFilters = $.grep(this.filters, function(filter) { + return !!filter.annotations.length; + }); + filtered = ((_ref2 = activeFilters[0]) != null ? _ref2.annotations : void 0) || []; + if (activeFilters.length > 1) { + annotations = []; + $.each(activeFilters, function() { + return $.merge(annotations, this.annotations); + }); + uniques = []; + filtered = []; + $.each(annotations, function() { + if ($.inArray(this, uniques) === -1) { + return uniques.push(this); + } else { + return filtered.push(this); + } + }); + } + highlights = this.highlights; + for (index = _k = 0, _len2 = filtered.length; _k < _len2; index = ++_k) { + annotation = filtered[index]; + highlights = highlights.not(annotation.highlights); + } + highlights.addClass(this.classes.hl.hide); + this.filtered = this.highlights.not(this.classes.hl.hide); + return this; + }; + + Filter.prototype.resetHighlights = function() { + this.highlights.removeClass(this.classes.hl.hide); + this.filtered = this.highlights; + return this; + }; + + Filter.prototype._onFilterFocus = function(event) { + var input; + input = $(event.target); + input.parent().addClass(this.classes.active); + return input.next('button').show(); + }; + + Filter.prototype._onFilterBlur = function(event) { + var input; + if (!event.target.value) { + input = $(event.target); + input.parent().removeClass(this.classes.active); + return input.next('button').hide(); + } + }; + + Filter.prototype._onFilterKeyup = function(event) { + var filter; + filter = $(event.target).parent().data('filter'); + if (filter) { + return this.updateFilter(filter); + } + }; + + Filter.prototype._findNextHighlight = function(previous) { + var active, annotation, current, index, next, offset, operator, resetOffset; + if (!this.highlights.length) { + return this; + } + offset = previous ? 0 : -1; + resetOffset = previous ? -1 : 0; + operator = previous ? 'lt' : 'gt'; + active = this.highlights.not('.' + this.classes.hl.hide); + current = active.filter('.' + this.classes.hl.active); + if (!current.length) { + current = active.eq(offset); + } + annotation = current.data('annotation'); + index = active.index(current[0]); + next = active.filter(":" + operator + "(" + index + ")").not(annotation.highlights).eq(resetOffset); + if (!next.length) { + next = active.eq(resetOffset); + } + return this._scrollToHighlight(next.data('annotation').highlights); + }; + + Filter.prototype._onNextClick = function(event) { + return this._findNextHighlight(); + }; + + Filter.prototype._onPreviousClick = function(event) { + return this._findNextHighlight(true); + }; + + Filter.prototype._scrollToHighlight = function(highlight) { + highlight = $(highlight); + this.highlights.removeClass(this.classes.hl.active); + highlight.addClass(this.classes.hl.active); + return $('html, body').animate({ + scrollTop: highlight.offset().top - (this.element.height() + 20) + }, 150); + }; + + Filter.prototype._onClearClick = function(event) { + return $(event.target).prev('input').val('').keyup().blur(); + }; + + return Filter; + + })(Annotator.Plugin); + + Annotator.Plugin.Markdown = (function(_super) { + + __extends(Markdown, _super); + + Markdown.prototype.events = { + 'annotationViewerTextField': 'updateTextField' + }; + + function Markdown(element, options) { + this.updateTextField = __bind(this.updateTextField, this); + if ((typeof Showdown !== "undefined" && Showdown !== null ? Showdown.converter : void 0) != null) { + Markdown.__super__.constructor.apply(this, arguments); + this.converter = new Showdown.converter(); + } else { + console.error(Annotator._t("To use the Markdown plugin, you must include Showdown into the page first.")); + } + } + + Markdown.prototype.updateTextField = function(field, annotation) { + var text; + text = Annotator.$.escape(annotation.text || ''); + return $(field).html(this.convert(text)); + }; + + Markdown.prototype.convert = function(text) { + return this.converter.makeHtml(text); + }; + + return Markdown; + + })(Annotator.Plugin); + + Annotator.Plugin.Tags = (function(_super) { + + __extends(Tags, _super); + + function Tags() { + this.setAnnotationTags = __bind(this.setAnnotationTags, this); + + this.updateField = __bind(this.updateField, this); + return Tags.__super__.constructor.apply(this, arguments); + } + + Tags.prototype.options = { + parseTags: function(string) { + var tags; + string = $.trim(string); + tags = []; + if (string) { + tags = string.split(/\s+/); + } + return tags; + }, + stringifyTags: function(array) { + return array.join(" "); + } + }; + + Tags.prototype.field = null; + + Tags.prototype.input = null; + + Tags.prototype.pluginInit = function() { + if (!Annotator.supported()) { + return; + } + this.field = this.annotator.editor.addField({ + label: Annotator._t('Add some tags here') + '\u2026', + load: this.updateField, + submit: this.setAnnotationTags + }); + this.annotator.viewer.addField({ + load: this.updateViewer + }); + if (this.annotator.plugins.Filter) { + this.annotator.plugins.Filter.addFilter({ + label: Annotator._t('Tag'), + property: 'tags', + isFiltered: Annotator.Plugin.Tags.filterCallback + }); + } + return this.input = $(this.field).find(':input'); + }; + + Tags.prototype.parseTags = function(string) { + return this.options.parseTags(string); + }; + + Tags.prototype.stringifyTags = function(array) { + return this.options.stringifyTags(array); + }; + + Tags.prototype.updateField = function(field, annotation) { + var value; + value = ''; + if (annotation.tags) { + value = this.stringifyTags(annotation.tags); + } + return this.input.val(value); + }; + + Tags.prototype.setAnnotationTags = function(field, annotation) { + return annotation.tags = this.parseTags(this.input.val()); + }; + + Tags.prototype.updateViewer = function(field, annotation) { + field = $(field); + if (annotation.tags && $.isArray(annotation.tags) && annotation.tags.length) { + return field.addClass('annotator-tags').html(function() { + var string; + return string = $.map(annotation.tags, function(tag) { + return '<span class="annotator-tag">' + Annotator.$.escape(tag) + '</span>'; + }).join(' '); + }); + } else { + return field.remove(); + } + }; + + return Tags; + + })(Annotator.Plugin); + + Annotator.Plugin.Tags.filterCallback = function(input, tags) { + var keyword, keywords, matches, tag, _k, _l, _len2, _len3; + if (tags == null) { + tags = []; + } + matches = 0; + keywords = []; + if (input) { + keywords = input.split(/\s+/g); + for (_k = 0, _len2 = keywords.length; _k < _len2; _k++) { + keyword = keywords[_k]; + if (tags.length) { + for (_l = 0, _len3 = tags.length; _l < _len3; _l++) { + tag = tags[_l]; + if (tag.indexOf(keyword) !== -1) { + matches += 1; + } + } + } + } + } + return matches === keywords.length; + }; + + Annotator.Plugin.DigilibIntegrator = (function(_super) { + + __extends(DigilibIntegrator, _super); + + function DigilibIntegrator() { + return DigilibIntegrator.__super__.constructor.apply(this, arguments); + } + + DigilibIntegrator.prototype.events = { + 'annotationDeleted': 'annotationDeleted' + }; + + DigilibIntegrator.prototype.options = { + hooks: null + }; + + DigilibIntegrator.prototype.pluginInit = function() { + this.annotator.digilib = this.options.hooks; + this.annotator.setupRangeAnnotation = this.annotator.setupAnnotation; + this.annotator.setupAnnotation = this._setupAnnotation; + return this; + }; + + DigilibIntegrator.prototype._setupAnnotation = function(annotation, fireEvents) { + if (fireEvents == null) { + fireEvents = true; + } + if (this.selectedShapes || (annotation.shapes != null) || (this.selectedAreas != null) || (annotation.areas != null)) { + annotation.shapes || (annotation.shapes = this.selectedShapes); + annotation.areas || (annotation.areas = this.selectedAreas); + annotation.highlights = []; + annotation.ranges = []; + this.digilib.setupAnnotation(annotation); + if (fireEvents) { + this.publish('annotationCreated', [annotation]); + } + return annotation; + } else { + return this.setupRangeAnnotation.apply(this, arguments); + } + }; + + DigilibIntegrator.prototype.annotationDeleted = function(annotation) { + return this.options.hooks.annotationDeleted(annotation); + }; + + return DigilibIntegrator; + + })(Annotator.Plugin); + +}).call(this);