Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
discourse-annotator / app / assets / javascripts / discourse-annotator / vendor / annotator-full.1.2.5.modified.js
Size: Mime:
// NOTE: Search for "damingo" to find modifications.

/*
** Annotator v1.2.5
** 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-06-22 12:25:24Z
*/

(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;

    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().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, _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'));
                // 2022-02-18 / damingo / Add code CSS class.
                $.merge(annotation.highlights, this.highlightRange(normed, 'annotator-hl', annotation.code_id));
            }
            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, id ) {
            var hl, node, white, _k, _len3, _ref2, _results;
            if (cssClass == null) cssClass = 'annotator-hl';
            white = /^\s*$/;
            hl = $("<span class='" + cssClass + "' data-code-id='"+id+"'></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) {

                // START damingo (Github ID), 2020-08-09, Set up one annotation for each tag. Required to display
                // the created codes in the popover.
                var firstTag = annotation.codes.shift();
                if (annotation.codes.length >= 1) {
                    for (var i = 0, len = annotation.codes.length; i < len; i++) {
                        var clonedAnnotation = Object.assign({}, annotation);
                        clonedAnnotation.codes = [annotation.codes[i]]
                        this.setupAnnotation(clonedAnnotation);
                    }
                }
                annotation.codes = [firstTag];
                // END

                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;
                // 2020-08-05 / damingo / https://github.com/openannotation/annotator/pull/480/files
                // 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) {
            // 2020-08-05 / damingo / https://github.com/openannotation/annotator/pull/480/files
            // return !!$(element).parents().andSelf().filter('[class^=annotator-]').not(this.wrapper).length;
            return !!$(element).parents().andSelf().filter('[class^=annotator-]').not('[class=annotator-hl]').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 || '/';
            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 (!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;
        };

        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);
            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({
                // 2020-08-05 / damingo / Adapt text.
                label: Annotator._t('Add code 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, _len3, _len4;
        if (tags == null) tags = [];
        matches = 0;
        keywords = [];
        if (input) {
            keywords = input.split(/\s+/g);
            for (_k = 0, _len3 = keywords.length; _k < _len3; _k++) {
                keyword = keywords[_k];
                if (tags.length) {
                    for (_l = 0, _len4 = tags.length; _l < _len4; _l++) {
                        tag = tags[_l];
                        if (tag.indexOf(keyword) !== -1) matches += 1;
                    }
                }
            }
        }
        return matches === keywords.length;
    };

    Annotator.prototype.setupPlugins = function(config, options) {
        var name, opts, pluginConfig, plugins, uri, win, _k, _len3, _results;
        if (config == null) config = {};
        if (options == null) options = {};
        win = util.getGlobal();
        plugins = ['Unsupported', 'Auth', 'Tags', 'Filter', 'Store', 'AnnotateItPermissions'];
        if (win.Showdown) plugins.push('Markdown');
        uri = win.location.href.split(/#|\?/).shift() || '';
        pluginConfig = {
            Tags: {},
            Filter: {
                filters: [
                    {
                        label: Annotator._t('User'),
                        property: 'user'
                    }, {
                        label: Annotator._t('Tags'),
                        property: 'tags'
                    }
                ]
            },
            Auth: {
                tokenUrl: config.tokenUrl || 'http://annotateit.org/api/token'
            },
            Store: {
                prefix: config.storeUrl || 'http://annotateit.org/api',
                annotationData: {
                    uri: uri
                },
                loadFromSearch: {
                    uri: uri
                }
            }
        };
        for (name in options) {
            if (!__hasProp.call(options, name)) continue;
            opts = options[name];
            if (__indexOf.call(plugins, name) < 0) plugins.push(name);
        }
        $.extend(true, pluginConfig, options);
        _results = [];
        for (_k = 0, _len3 = plugins.length; _k < _len3; _k++) {
            name = plugins[_k];
            if (!(name in pluginConfig) || pluginConfig[name]) {
                _results.push(this.addPlugin(name, pluginConfig[name]));
            } else {
                _results.push(void 0);
            }
        }
        return _results;
    };

}).call(this);