Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Annotator release v1.2.6

  • Loading branch information...
commit c4fcdfeda8afa94c9f3d917b029ed7a3de3b91b1 1 parent acc65a0
@nickstenning nickstenning authored
Showing with 6,626 additions and 0 deletions.
  1. +2,737 −0 pkg/annotator/annotator-full.js
  2. +11 −0 pkg/annotator/annotator-full.min.js
  3. +117 −0 pkg/annotator/annotator.annotateitpermissions.js
  4. +10 −0 pkg/annotator/annotator.annotateitpermissions.min.js
  5. +203 −0 pkg/annotator/annotator.auth.js
  6. +10 −0 pkg/annotator/annotator.auth.min.js
  7. +888 −0 pkg/annotator/annotator.css
  8. +269 −0 pkg/annotator/annotator.filter.js
  9. +10 −0 pkg/annotator/annotator.filter.min.js
  10. +1,591 −0 pkg/annotator/annotator.js
  11. +68 −0 pkg/annotator/annotator.kitchensink.js
  12. +10 −0 pkg/annotator/annotator.kitchensink.min.js
  13. +48 −0 pkg/annotator/annotator.markdown.js
  14. +10 −0 pkg/annotator/annotator.markdown.min.js
  15. +1 −0  pkg/annotator/annotator.min.css
  16. +10 −0 pkg/annotator/annotator.min.js
  17. +190 −0 pkg/annotator/annotator.permissions.js
  18. +10 −0 pkg/annotator/annotator.permissions.min.js
  19. +238 −0 pkg/annotator/annotator.store.js
  20. +10 −0 pkg/annotator/annotator.store.min.js
  21. +121 −0 pkg/annotator/annotator.tags.js
  22. +10 −0 pkg/annotator/annotator.tags.min.js
  23. +44 −0 pkg/annotator/annotator.unsupported.js
  24. +10 −0 pkg/annotator/annotator.unsupported.min.js
View
2,737 pkg/annotator/annotator-full.js
@@ -0,0 +1,2737 @@
+/*
+** Annotator v1.2.6
+** 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: 2013-01-21 09:43:44Z
+*/
+
+(function() {
+ var $, Annotator, Delegator, LinkParser, Range, base64Decode, base64UrlDecode, createDateFromISO8601, fn, functions, g, gettext, parseToken, util, _Annotator, _gettext, _i, _j, _len, _len2, _ref, _ref2, _t,
+ __slice = Array.prototype.slice,
+ __hasProp = Object.prototype.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 = Array.prototype.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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+ };
+
+ $.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, _len2 = functions.length; _j < _len2; _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, _ref2, _ref3, _results;
+ _ref2 = this.events;
+ _results = [];
+ for (sel in _ref2) {
+ functionName = _ref2[sel];
+ _ref3 = sel.split(' '), selector = 2 <= _ref3.length ? __slice.call(_ref3, 0, _k = _ref3.length - 1) : (_k = 0, []), event = _ref3[_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 _ref2, _results;
+ _ref2 = jQuery.event.special;
+ _results = [];
+ for (key in _ref2) {
+ if (!__hasProp.call(_ref2, key)) continue;
+ val = _ref2[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, _len3, _ref2, _results;
+ _ref2 = xpath.split('/');
+ _results = [];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ segment = _ref2[_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, _len3, _ref2;
+ if (this.tainted) {
+ console.error(_t("You may only call normalize() once on a BrowserRange!"));
+ return false;
+ } else {
+ this.tainted = true;
+ }
+ r = {};
+ nr = {};
+ _ref2 = ['start', 'end'];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ p = _ref2[_k];
+ node = this[p + 'Container'];
+ offset = this[p + 'Offset'];
+ 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, _len3, _ref2;
+ 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();
+ _ref2 = $(this.end).parents();
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ parent = _ref2[_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, _len3;
+ 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, _len3 = nodes.length; _k < _len3; _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, _len3, _ref2, _results;
+ _ref2 = this.textNodes();
+ _results = [];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ node = _ref2[_k];
+ _results.push(node.nodeValue);
+ }
+ return _results;
+ }).call(this)).join('');
+ };
+
+ NormalizedRange.prototype.textNodes = function() {
+ var end, start, textNodes, _ref2;
+ textNodes = $(this.commonAncestor).textNodes();
+ _ref2 = [textNodes.index(this.start), textNodes.index(this.end)], start = _ref2[0], end = _ref2[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, _len3, _len4, _ref2, _ref3;
+ range = {};
+ _ref2 = ['start', 'end'];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ p = _ref2[_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;
+ _ref3 = $(node).textNodes();
+ for (_l = 0, _len4 = _ref3.length; _l < _len4; _l++) {
+ tn = _ref3[_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().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, _len3, _results;
+ _results = [];
+ for (_k = 0, _len3 = $elements.length; _k < _len3; _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, _len3, _ref2, _results;
+ _ref2 = ['adder', 'outer', 'notice', 'filter'];
+ _results = [];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ x = _ref2[_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, _len3;
+ selection = util.getGlobal().getSelection();
+ ranges = [];
+ rangesToIgnore = [];
+ if (!selection.isCollapsed) {
+ ranges = (function() {
+ var _ref2, _results;
+ _results = [];
+ for (i = 0, _ref2 = selection.rangeCount; 0 <= _ref2 ? i < _ref2 : i > _ref2; 0 <= _ref2 ? i++ : i--) {
+ 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, _len3 = rangesToIgnore.length; _k < _len3; _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, _len3, _len4, _ref2;
+ if (fireEvents == null) fireEvents = true;
+ root = this.wrapper[0];
+ annotation.ranges || (annotation.ranges = this.selectedRanges);
+ normedRanges = [];
+ _ref2 = annotation.ranges;
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ r = _ref2[_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, _len4 = normedRanges.length; _l < _len4; _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, _len3, _ref2;
+ _ref2 = annotation.highlights;
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ h = _ref2[_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, _len3;
+ if (annList == null) annList = [];
+ now = annList.splice(0, 10);
+ for (_k = 0, _len3 = now.length; _k < _len3; _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, _len3, _ref2, _results;
+ if (cssClass == null) cssClass = 'annotator-hl';
+ white = /^\s*$/;
+ hl = $("<span class='" + cssClass + "'></span>");
+ _ref2 = normedRange.textNodes();
+ _results = [];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ node = _ref2[_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, _len3;
+ if (cssClass == null) cssClass = 'annotator-hl';
+ highlights = [];
+ for (_k = 0, _len3 = normedRanges.length; _k < _len3; _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, _len3, _ref2;
+ this.mouseIsDown = false;
+ if (this.ignoreMouseup) return;
+ this.selectedRanges = this.getSelectedRanges();
+ _ref2 = this.selectedRanges;
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ range = _ref2[_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, _len3, _ref2, _results;
+ _ref2 = this.selectedRanges;
+ _results = [];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ r = _ref2[_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, _len3, _results;
+ _results = [];
+ for (_k = 0, _len3 = highlights.length; _k < _len3; _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 (!(((_ref2 = g.document) != null ? _ref2.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, _len3, _ref3;
+ this.annotation = annotation;
+ this.publish('load', [this.annotation]);
+ _ref3 = this.fields;
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ field = _ref3[_k];
+ field.load(field.element, this.annotation);
+ }
+ return this.show();
+ };
+
+ Editor.prototype.submit = function(event) {
+ var field, _k, _len3, _ref3;
+ util.preventEventDefault(event);
+ _ref3 = this.fields;
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ field = _ref3[_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, _len3, _len4, _ref3, _ref4;
+ this.annotations = annotations || [];
+ list = this.element.find('ul:first').empty();
+ _ref3 = this.annotations;
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ annotation = _ref3[_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');
+ }
+ };
+ }
+ _ref4 = this.fields;
+ for (_l = 0, _len4 = _ref4.length; _l < _len4; _l++) {
+ field = _ref4[_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, _len3, _ref3, _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;
+ })();
+ _ref3 = this.data;
+ _results = [];
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ d = _ref3[_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() {
+ 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, _ref3;
+ 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 *= (_ref3 = d[15] === '-') != null ? _ref3 : {
+ 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, _ref3;
+ m = data.length % 4;
+ if (m !== 0) {
+ for (i = 0, _ref3 = 4 - m; 0 <= _ref3 ? i < _ref3 : i > _ref3; 0 <= _ref3 ? i++ : i--) {
+ data += '=';
+ }
+ }
+ data = data.replace(/-/g, '+');
+ data = data.replace(/_/g, '/');
+ return base64Decode(data);
+ };
+
+ parseToken = function(token) {
+ var head, payload, sig, _ref3;
+ _ref3 = token.split('.'), head = _ref3[0], payload = _ref3[1], sig = _ref3[2];
+ return JSON.parse(base64UrlDecode(payload));
+ };
+
+ Annotator.Plugin.Auth = (function(_super) {
+
+ __extends(Auth, _super);
+
+ Auth.prototype.options = {
+ token: null,
+ tokenUrl: '/auth/token',
+ autoFetch: true
+ };
+
+ 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',
+ xhrFields: {
+ withCredentials: true
+ }
+ }).done(function(data, status, xhr) {
+ return _this.setToken(data);
+ }).fail(function(xhr, status, err) {
+ var msg;
+ 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, _len3, _ref3, _results;
+ _ref3 = this.annotations;
+ _results = [];
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ ann = _ref3[_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 != null ? 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, _len3;
+ if (annotation.permissions) {
+ tokens = annotation.permissions[action] || [];
+ if (tokens.length === 0) return true;
+ for (_k = 0, _len3 = tokens.length; _k < _len3; _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, _len3, _ref3;
+ user = _this.options.userString(user);
+ if (!(input && user)) return false;
+ _ref3 = input.split(/\s*/);
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ keyword = _ref3[_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.AnnotateItPermissions = (function(_super) {
+
+ __extends(AnnotateItPermissions, _super);
+
+ function AnnotateItPermissions() {
+ this._setAuthFromToken = __bind(this._setAuthFromToken, this);
+ this.updateAnnotationPermissions = __bind(this.updateAnnotationPermissions, this);
+ this.updatePermissionsField = __bind(this.updatePermissionsField, this);
+ this.addFieldsToAnnotation = __bind(this.addFieldsToAnnotation, this);
+ AnnotateItPermissions.__super__.constructor.apply(this, arguments);
+ }
+
+ AnnotateItPermissions.prototype.options = {
+ showViewPermissionsCheckbox: true,
+ showEditPermissionsCheckbox: true,
+ groups: {
+ world: 'group:__world__',
+ authenticated: 'group:__authenticated__',
+ consumer: 'group:__consumer__'
+ },
+ userId: function(user) {
+ return user.userId;
+ },
+ userString: function(user) {
+ return user.userId;
+ },
+ userAuthorize: function(action, annotation, user) {
+ var action_field, permissions, _ref3, _ref4, _ref5, _ref6;
+ permissions = annotation.permissions || {};
+ action_field = permissions[action] || [];
+ if (_ref3 = this.groups.world, __indexOf.call(action_field, _ref3) >= 0) {
+ return true;
+ } else if ((user != null) && (user.userId != null) && (user.consumerKey != null)) {
+ if (user.userId === annotation.user && user.consumerKey === annotation.consumer) {
+ return true;
+ } else if (_ref4 = this.groups.authenticated, __indexOf.call(action_field, _ref4) >= 0) {
+ return true;
+ } else if (user.consumerKey === annotation.consumer && (_ref5 = this.groups.consumer, __indexOf.call(action_field, _ref5) >= 0)) {
+ return true;
+ } else if (user.consumerKey === annotation.consumer && (_ref6 = user.userId, __indexOf.call(action_field, _ref6) >= 0)) {
+ return true;
+ } else if (user.consumerKey === annotation.consumer && user.admin) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ },
+ permissions: {
+ 'read': ['group:__world__'],
+ 'update': [],
+ 'delete': [],
+ 'admin': []
+ }
+ };
+
+ AnnotateItPermissions.prototype.addFieldsToAnnotation = function(annotation) {
+ AnnotateItPermissions.__super__.addFieldsToAnnotation.apply(this, arguments);
+ if (annotation && this.user) {
+ return annotation.consumer = this.user.consumerKey;
+ }
+ };
+
+ AnnotateItPermissions.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.user && this.authorize(action, annotation || {}, {
+ userId: '__nonexistentuser__',
+ consumerKey: this.user.consumerKey
+ })) {
+ return input.attr('checked', 'checked');
+ } else {
+ return input.removeAttr('checked');
+ }
+ };
+
+ AnnotateItPermissions.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] = [type === 'read' ? this.options.groups.world : this.options.groups.consumer];
+ } else {
+ return annotation.permissions[type] = [];
+ }
+ };
+
+ AnnotateItPermissions.prototype._setAuthFromToken = function(token) {
+ return this.setUser(token);
+ };
+
+ return AnnotateItPermissions;
+
+ })(Annotator.Plugin.Permissions);
+
+ 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, _len3, _ref3;
+ if (!(input && property)) return false;
+ _ref3 = input.split(/\s*/);
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ keyword = _ref3[_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, _len3, _ref3;
+ _ref3 = this.options.filters;
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ filter = _ref3[_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, _len3;
+ events = ['annotationsLoaded', 'annotationCreated', 'annotationUpdated', 'annotationDeleted'];
+ for (_k = 0, _len3 = events.length; _k < _len3; _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, _len3, _ref3, _results;
+ _ref3 = this.filters;
+ _results = [];
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ f = _ref3[_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, _len3, _ref3;
+ filter.annotations = [];
+ this.updateHighlights();
+ this.resetHighlights();
+ input = $.trim(filter.element.find('input').val());
+ if (input) {
+ annotations = this.highlights.map(function() {
+ return $(this).data('annotation');
+ });
+ _ref3 = $.makeArray(annotations);
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ annotation = _ref3[_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, _len3, _ref3;
+ activeFilters = $.grep(this.filters, function(filter) {
+ return !!filter.annotations.length;
+ });
+ filtered = ((_ref3 = activeFilters[0]) != null ? _ref3.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 = 0, _len3 = filtered.length; index < _len3; index++) {
+ 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;
+ };
+