Mercurial > hg > digilib-old
view webapp/src/main/webapp/jquery/annotator-dl.js @ 1125:f1be20adc98b
annotatorPlugins is now a list of plugin names (preserving order).
author | robcast |
---|---|
date | Fri, 09 Nov 2012 15:07:12 +0100 |
parents | 1fad569ccb4f |
children |
line wrap: on
line source
/* ** Annotator 1.2.5-dev-34a1d4e ** 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-08 19:26:45Z */ (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() { console.debug("DigilibIntegrator plugin init"); 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.selectedAreas != null) || (annotation.areas != null)) { console.debug("setupAnnotation for areas!"); 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);