flagging-annotator.js 11.3 KB
Newer Older
daniel cebrian committed
1 2 3 4 5 6
var _ref,
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

Annotator.Plugin.Flagging = (function(_super) {
7 8
    __extends(Flagging, _super);
    
daniel cebrian committed
9
    Flagging.prototype.options = null;
10 11 12 13 14 15 16
    
    // declaration function, remember to set up submit and/or update as necessary, if you don't have
    // options, delete the options line below.
    function Flagging(element,options) {
        this.updateViewer = __bind(this.updateViewer, this);
        this.updateField = __bind(this.updateField, this);
        this.submitField = __bind(this.submitField, this);
daniel cebrian committed
17 18
        this.flagAnnotation = __bind(this.flagAnnotation, this);
        this.unflagAnnotation = __bind(this.unflagAnnotation, this);
19
        this.getTotalFlaggingTags = __bind(this.getTotalFlaggingTags, this);
daniel cebrian committed
20
        this.options = options;
21 22 23 24 25 26 27
        _ref = Flagging.__super__.constructor.apply(this, arguments);
        return _ref;
    }
    
    // variables to be used to receive input in the annotator view
    Flagging.prototype.field = null;
    Flagging.prototype.input = null;
daniel cebrian committed
28
    Flagging.prototype.hasPressed = false;
29 30
    Flagging.prototype.activeAnnotation = null;
    Flagging.prototype.mixedTags = null;
daniel cebrian committed
31
    
32
    // this function will initialize the plug-in
daniel cebrian committed
33
    Flagging.prototype.pluginInit = function() {
34 35 36 37 38 39
        console.log("Flagging-pluginInit");
        
        // Check that annotator is working
        if (!Annotator.supported()) {
            return;
        }
daniel cebrian committed
40
        
41 42 43 44 45 46 47 48 49 50
        // -- Editor
        //creates a checkbox to remove all flags
        var self = this;
        this.field = this.annotator.editor.addField({
            type: 'checkbox',
            load: this.updateField,
            // Translators: please note that this is not a literal flag, but rather a report
            label: Annotator._t(gettext('Check the box to remove all flags.')),
            submit: this.submitField,
        });
daniel cebrian committed
51
        
52 53 54 55
        // -- Viewer
        var newview = this.annotator.viewer.addField({
            load: this.updateViewer,
        });
daniel cebrian committed
56

57 58 59 60 61 62 63 64 65 66 67 68 69 70
        return this.input = $(this.field).find(':input');
    };
    
    /**
     * Gets the total number of tags associated with the flagging tool.
     * @param {Object} annotation Annotation item from Annotator.
     */
    Flagging.prototype.getTotalFlaggingTags = function(annotation){
        var tags = (typeof annotation.tags !== 'undefined') ? annotation.tags.slice() : [];
        // Goes through and gets the number of tags that contained the keyword "flagged"
        return $.grep(tags, function(tag, index){
            return (tag.indexOf('flagged') !== -1);
        }).length;
    }
daniel cebrian committed
71
    
72 73 74 75 76 77 78
    /**
     * Creates a new field in the editor in order to delete the flagged tags.
     * @param {HTMLElement} field The HTML element contained in the editor reserved for flagging.
     * @param {Object} annotation Annotation item from Annotator.
     */
    Flagging.prototype.updateField = function(field, annotation) {
        
79 80 81
        // figure out whether annotation is of type image or if ova is not defined (meaning it
        // it doesn't have a type yet, but it is still an image).
        var user_email = (annotation.media === "image" || typeof ova === 'undefined') ? 
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
                            osda.options.optionsAnnotator.permissions.user.id:
                            ova.options.optionsAnnotator.permissions.user.id;
        
        // get total number of flag tags as well as save a copy of the mixed tags
        var totalFlags = this.getTotalFlaggingTags(annotation);   
        this.mixedTags = annotation.tags;     
        var self = this;
        
        // only show this field if you are an instructor and there are flags to remove
        if(Catch.options.instructor_email === user_email && totalFlags > 0){
            // Translators: 'totalFlags' is the number of flags solely for that annotation
            var message = ngettext("Check the box to remove %(totalFlags)s flag.", "Check the box to remove %(totalFlags)s flags.", totalFlags);
            $(field).find('label')[0].innerHTML = interpolate(message, {totalFlags : totalFlags}, true);
            this.activeAnnotation = annotation;
            
            // add function to change the text when the user checks the box or removes the check
            $(field).find('input').change(function(evt){
                if(!$(field).find('input:checkbox:checked').val()){
                    var count = self.getTotalFlaggingTags(self.activeAnnotation);
                    // Translators: 'count' is the number of flags solely for that annotation that will be removed
                    var message = ngettext("Check the box to remove %(count)s flag.", "Check the box to remove %(count)s flags.", count)
                    $(field).find('label')[0].innerHTML = interpolate(message, {count: count}, true);
                } else {
                    $(field).find('label')[0].innerHTML = gettext("All flags have been removed. To undo, uncheck the box.");
                }
            });
            $(field).show();
        } else {
            $(field).hide();
        }
    }
daniel cebrian committed
113
    
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    /**
     * Makes last-minute changes to the annotation right before it is saved in the server.
     * @param {HTMLElement} field The HTML element contained in the editor reserved for flagging.
     * @param {Object} annotation Annotation item from Annotator.     
     */
    Flagging.prototype.submitField = function(field, annotation) {
        // if the user did not check the box go back and input all of the tags. 
        if (!$(field).find('input:checkbox:checked').val()){
            annotation.tags = this.mixedTags;
        }
    }
    
    /** 
     * The following allows you to edit the annotation popup when the viewer has already
     * hit submit and is just viewing the annotation.
     * @param {HTMLElement} field The HTML element contained in the editor reserved for flagging.
     * @param {Object} annotation Annotation item from Annotator.
     */
    Flagging.prototype.updateViewer = function(field, annotation) {
        var self = this;
daniel cebrian committed
134
        this.hasPressed = false;
135 136
        
        // perform routine to check if user has pressed the button before
daniel cebrian committed
137 138 139 140 141 142 143 144 145 146
        var tags = typeof annotation.tags != 'undefined'?annotation.tags:[];
        var user = this.annotator.plugins.Permissions.user.id;
        tags.forEach(function(t){
            if (t.indexOf("flagged")>=0) {
                var usertest = t.replace('flagged-','');
                if (usertest == user) 
                    self.hasPressed = true;
                
            }
        });
147 148

        // changes display based on check done above
daniel cebrian committed
149 150
        var fieldControl = $(this.annotator.viewer.element.find('.annotator-controls')).parent();
        if (this.hasPressed) {
151 152 153 154 155 156 157 158 159

            // make sure to use id when searching for the item so that only one of them gets changed
            var message = gettext("You have already reported this annotation.");
            fieldControl.prepend('<button title="' + message + '" class="flag-icon-used" id="' + annotation.id + '">');
            
            var flagEl = fieldControl.find('.flag-icon-used#' + annotation.id);
            var self = this;
            
            // sets function to unflag after next click
daniel cebrian committed
160
            flagEl.click(function(){self.unflagAnnotation(annotation,user,flagEl,field)});
161
        
daniel cebrian committed
162 163
        } else{
            
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
            // likewise, make sure to use id when searching for the item so that only one is changed
            var message = gettext("Report annotation as inappropriate or offensive.");
            fieldControl.prepend('<button title="' + message + '" class="flag-icon" id="' + annotation.id + '">');
            
            var flagEl = fieldControl.find('.flag-icon#' + annotation.id);
            var self = this;
            
            // sets function to flag after next click
            flagEl.click(function(){self.flagAnnotation(annotation,user,flagEl,field)});
        }
        
        var user_email = annotation.media === "image" ? 
                            osda.options.optionsAnnotator.permissions.user.id:
                            ova.options.optionsAnnotator.permissions.user.id;
        var totalFlags = this.getTotalFlaggingTags(annotation);
        
        // only show the number of times an annotation has been flagged if they are the instructors
        if(Catch.options.instructor_email === user_email && totalFlags > 0){
            // Translators: 'count' is the number of flags solely for that annotation
            var message = ngettext("This annotation has %(count)s flag.","This annotation has %(count)s flags.", totalFlags);
            $(field).append("<div class=\"flag-count\">" + interpolate(message, {count : totalFlags}, true) + "</div>");
        } else {
            $(field).remove(); // remove the empty div created by annotator
daniel cebrian committed
187 188 189
        }
    }
    
190 191 192 193
    /**
     * This function changes the visual aspects of flagging an Annotation and sends changes
     * to the database backend.
     */
daniel cebrian committed
194
    Flagging.prototype.flagAnnotation = function(annotation, userId, flagElement, field) {
195 196
        
        // changes the class and title to show user's flagging action worked
daniel cebrian committed
197
        flagElement.attr("class","flag-icon-used");
198 199 200
        flagElement.attr("title", gettext("You have already reported this annotation."));

        // it adds the appropriate tag with the user name to make sure it is added
daniel cebrian committed
201 202 203 204 205
        if (typeof annotation.tags == 'undefined') {
            annotation.tags = ['flagged-'+userId];
        } else{
            annotation.tags.push("flagged-"+userId);
        }
206 207

        // annotation gets updated and a warning is published that an annotation has been flagged
daniel cebrian committed
208 209 210
        this.annotator.plugins['Store'].annotationUpdated(annotation);
        this.annotator.publish("flaggedAnnotation",[field,annotation]);
        
211 212
        // now that it is flagged, it sets the click function to unflag
        flagElement.click(function(){self.unflagAnnotation(annotation,userId,flagElement,field)});
daniel cebrian committed
213 214
    }
    
215 216 217 218
    /**
     * This function changes the visual aspects of unflagging an Annotation and sends changes
     * to the database backend.
     */
daniel cebrian committed
219
    Flagging.prototype.unflagAnnotation = function(annotation, userId, flagElement, field) {
220 221
        
        // changes the class and title to show user's unflagging action worked
daniel cebrian committed
222
        flagElement.attr("class", "flag-icon");
223 224 225
        flagElement.attr("title", gettext("Report annotation as inappropriate or offensive."));
        
        // it removes the tag that signifies flagging
daniel cebrian committed
226
        annotation.tags.splice(annotation.tags.indexOf('flagged-'+userId));
227 228
        
        // annotation gets updated without the tag and a warning is published that flagging is changed
daniel cebrian committed
229 230
        this.annotator.plugins['Store'].annotationUpdated(annotation);
        this.annotator.publish("flaggedAnnotation",[field,annotation]);
231 232 233
        
        // now that it is unflagged, it sets the click function to flag
        flagElement.click(function(){self.unflagAnnotation(annotation,userId,flagElement,field)});
daniel cebrian committed
234 235 236 237
    }
    
    return Flagging;

238
})(Annotator.Plugin);