diff --git a/common/static/css/vendor/ova/richText-annotator.css b/common/static/css/vendor/ova/richText-annotator.css index 9512fad0a0..f3c39a2bda 100644 --- a/common/static/css/vendor/ova/richText-annotator.css +++ b/common/static/css/vendor/ova/richText-annotator.css @@ -47,3 +47,8 @@ div.mce-tinymce.mce-container.mce-panel { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QkBBB07nraNoQAAAhZJREFUKM+NkstrE1EUxr+5c08ykztpJtVoazHBF8FgQQzonyBKEZS6FrQKLl0EXBRT0ZULJSs3oii4TyHgu90IlTaL6qouWlv7Ck1N0BSnmZk714WbPHz07M4534+Pw3eAHdTY8A9+Nd9/bshU1DpnO4HXjh2ZY2J9/OSTxHTrnP8PvJYf+BDQ6qEDaQBB43jrTusUFy4oPjsYWYzF+VS91nxLYfdhKgONaQT3W/KMxr1XY5e+qj86f8zsKYYsZ6AvjWFzA8ORHkAnwN8So7evzL/8pzMAXL/Hq8mMv1up371T7Z+/c3n9cKeuDS6Xy6dN07zLuZ56Onk2Ed2/ANJsnE/PQMpgyffle+kYzwazB1+3waVS6X48Hr9BRPB9H57nYXplFKeSt8D1Hriug9XKF0x+Lmw+ys8m2m42DOOn4zhQSsGyLOi6jqONm9isbmFVFlDbaGKx8QaB1rvdlbNhGLAsC0IIGIYBIQSy2ROQ0oOp7wOPraHXEugRvDtnzjmi0SiICEIIEBGklAB9B6cmbG0AUnrY5m73h+m6DsYYTNMEYwxEBMY0hGNVhHkcZigBO9qHlDHS7cwYg23bAIBQKAQigud7IH0XwtxDoHwEIQ9SLKx0wa7rPiaivYyxESklXNeFBg0mjyNQTQSuATMSm6ipuYt//eVcLhdeXl5+UKlUlur1upqamVAv3j3/VCyOD3VqfwF6uLp3q+vMcgAAAABJRU5ErkJggg=='); background-repeat: no-repeat; } + +/* Fixes conflicting design between tinymce css and annotator css */ +.mce-ico.mce-i-resize { + font-family: 'tinymce'; +} diff --git a/common/static/js/vendor/ova/OpenSeaDragonAnnotation.js b/common/static/js/vendor/ova/OpenSeaDragonAnnotation.js index 3b65823abd..e6bcfade41 100644 --- a/common/static/js/vendor/ova/OpenSeaDragonAnnotation.js +++ b/common/static/js/vendor/ova/OpenSeaDragonAnnotation.js @@ -187,7 +187,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. } // if the colored highlights by tags plugin it is notified to colorize - annotator.publish('colorizeHighlight', [an]); + annotator.publish('externalCallToHighlightTags', [an]); }, /** @@ -231,7 +231,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. var span = document.createElement('span'); var rectPosition = an.rangePosition; span.className = "annotator-hl"; - span.style.border = '2px solid rgba(0,0,0,0.5)'; + + // outline and border below create a double line one black and one white + // so to be able to differentiate when selecting dark or light images + span.style.border = '2px solid rgb(255, 255, 255)'; + span.style.outline = '2px solid rgb(0, 0, 0)'; span.style.background = 'rgba(0,0,0,0)'; // Adds listening items for the viewer and editor @@ -305,7 +309,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. viewer.innerTracker.setTracking(false); this.rect = document.createElement('div'); this.rect.style.background = 'rgba(0,0,0,0)'; - this.rect.style.border = '2px solid rgba(0,0,0,0.5)'; + + // outline and border below create a double line one black and one white + // so to be able to differentiate when selecting dark or light images + this.rect.style.border = '2px solid rgb(255, 255, 255)'; + this.rect.style.outline = '2px solid rgb(0, 0, 0)'; + this.rect.style.position = 'absolute'; this.rect.className = 'DrawingRect'; // set the initial position @@ -1026,6 +1035,10 @@ OpenSeadragonAnnotation = function (element, options) { function reloadEditor(){ tinymce.EditorManager.execCommand('mceRemoveEditor',true, "annotator-field-0"); tinymce.EditorManager.execCommand('mceAddEditor',true, "annotator-field-0"); + + // if person hits into/out of fullscreen before closing the editor should close itself + // ideally we would want to keep it open and reposition, this would make a great TODO in the future + annotator.editor.hide(); } var self = this; @@ -1044,6 +1057,14 @@ OpenSeadragonAnnotation = function (element, options) { document.addEventListener("msfullscreenchange", function () { reloadEditor(); }, false); + + // for some reason the above doesn't work when person hits ESC to exit full screen... + $(document).keyup(function(e) { + // esc key reloads editor as well + if (e.keyCode == 27) { + reloadEditor(); + } + }); this.options = options; diff --git a/common/static/js/vendor/ova/catch/js/catch.js b/common/static/js/vendor/ova/catch/js/catch.js index 75f037fc8d..01e445c47c 100644 --- a/common/static/js/vendor/ova/catch/js/catch.js +++ b/common/static/js/vendor/ova/catch/js/catch.js @@ -504,6 +504,13 @@ CatchAnnotation.prototype = { // Search Button el.on("click", ".searchbox .search-icon", onSearchButtonClick); + // Search should also run when user hits ENTER + $('input[name=search]').keyup(function(e) { + // ENTER == 13 + if(e.which == 13) { + onSearchButtonClick(); + } + }); // Clear Search Button el.on("click", ".searchbox .clear-search-icon", onClearSearchButtonClick); @@ -1001,6 +1008,9 @@ CatchAnnotation.prototype = { var positionAnnotator = videojs.findPosition(wrapper[0]); var positionAdder = {}; + // the following addition to display makes sure the editor shows up + // after opening TinyMCE/editor within the image source + positionAdder.display = "block"; positionAdder.left = positionLeft.left - positionAnnotator.left; positionAdder.top = positionLeft.top + 20 - positionAnnotator.top; @@ -1010,9 +1020,9 @@ CatchAnnotation.prototype = { this.annotator.onAdderClick(); // Set vertical editor + $(this.annotator.editor.element).css(positionAdder); this.annotator.editor.resetOrientation(); this.annotator.editor.invertY(); - this.annotator.editor.element.find('.annotator-widget').css('min-width', replyElem.css('width')); // set parent var parentValue = $(this.annotator.editor.element).find(".reply-item span.parent-annotation"); diff --git a/common/static/js/vendor/ova/reply-annotator.js b/common/static/js/vendor/ova/reply-annotator.js index cf3f31daa1..b75d43b597 100644 --- a/common/static/js/vendor/ova/reply-annotator.js +++ b/common/static/js/vendor/ova/reply-annotator.js @@ -64,14 +64,24 @@ Annotator.Plugin.Reply = (function(_super) { // New JSON for the database Reply.prototype.pluginSubmit = function(field, annotation) { - var replyItem = $(this.annotator.editor.element).find(".reply-item span.parent-annotation"), - parent = replyItem.html()!=''?replyItem.html():'0'; - console.log(parent); - console.log(replyItem.html()); - if (parent!='0') annotation.media = 'comment'; - annotation.parent = parent;//set 0, because it is not a reply - console.log(annotation.parent); - return annotation.parent; + // since each annotation has their own reply item, this "find" is element specific + var replyItem = $(this.annotator.editor.element).find(".reply-item span.parent-annotation"); + // checks to see if the current annotation is a reply by checking parent numbers + var parent = replyItem.html() !== '' ? replyItem.html() : '0'; + // if the parent number is not empty or zero, we know that this is a comment + if (parent !== '0') { + annotation.media = 'comment'; + } + + // apparently some browsers continue adding tags here for nonreplies + // this will check and set to 0 (nonreply) if it fails + if (parseInt(parent, 10) === NaN){ + parent = '0'; + } + + // set 0, because it is not a reply + annotation.parent = parent; + return annotation.parent; }; diff --git a/common/static/js/vendor/ova/richText-annotator.js b/common/static/js/vendor/ova/richText-annotator.js index d036c2ea00..0b87a8eb1a 100644 --- a/common/static/js/vendor/ova/richText-annotator.js +++ b/common/static/js/vendor/ova/richText-annotator.js @@ -93,6 +93,17 @@ Annotator.Plugin.RichText = (function(_super) { // set the modification in the textarea of annotator $(editor.element).find('textarea')[0].value = tinymce.activeEditor.getContent(); }); + + // creates a function called whenever editor is resized + ed.on('init', function(mceInstance) { + + // get win means this event activates when window is resized + tinymce.dom.Event.bind(ed.getWin(), 'resize', function(e){ + + // mceInstance.target gets the editor, its id is used to retrieved iframe + $("#"+mceInstance.target.id+"_ifr").css('min-width', '400px'); + }); + }); // new button to add Rubrics of the url https://gteavirtual.org/rubric ed.addButton('rubric', { icon: 'rubric', diff --git a/common/static/js/vendor/ova/tags-annotator.js b/common/static/js/vendor/ova/tags-annotator.js index d418f65a92..9970682863 100644 --- a/common/static/js/vendor/ova/tags-annotator.js +++ b/common/static/js/vendor/ova/tags-annotator.js @@ -293,6 +293,8 @@ $.TokenList = function (input, url_or_data, settings) { case KEY.COMMA: if(selected_dropdown_item) { add_token($(selected_dropdown_item).data("tokeninput")); + // this allows for tags to be color-coded based on instructor set-up + annotator.publish("colorEditorTags") hidden_input.change(); return false; } else{ @@ -903,6 +905,7 @@ Annotator.Plugin.HighlightTags = (function(_super) { this.colorize = __bind(this.colorize, this); this.updateField = __bind(this.updateField, this); this.externalCall = __bind(this.externalCall, this); + this.colorizeEditorTags = __bind(this.colorizeEditorTags, this); this.options = options; _ref = HighlightTags.__super__.constructor.apply(this, arguments); @@ -947,12 +950,14 @@ Annotator.Plugin.HighlightTags = (function(_super) { this.colors = this.getHighlightTags(); var self = this; - this.annotator.subscribe('annotationsLoaded', function(){setTimeout(function(){self.colorize()},1000)}); - this.annotator.subscribe('annotationUpdated', this.colorize); - this.annotator.subscribe('flaggedAnnotation', this.updateViewer); - this.annotator.subscribe('annotationCreated', this.colorize); - this.annotator.subscribe('externalCallToHighlightTags', this.externalCall); + // all of these need time for the annotations database to respond + this.annotator.subscribe('annotationsLoaded', function(){setTimeout(function(){self.colorize()}, 1000)}); + this.annotator.subscribe('annotationUpdated', function(){setTimeout(function(){self.colorize()}, 1000)}); + this.annotator.subscribe('flaggedAnnotation', this.updateViewer); + this.annotator.subscribe('annotationCreated', function(){setTimeout(function(){self.colorize()}, 1000)}); + this.annotator.subscribe('externalCallToHighlightTags', function(){setTimeout(function(){self.externalCall()}, 1000)}); + this.annotator.subscribe('colorEditorTags', this.colorizeEditorTags); }; HighlightTags.prototype.getHighlightTags = function(){ @@ -1023,75 +1028,130 @@ Annotator.Plugin.HighlightTags = (function(_super) { return getColorValues(item) } - HighlightTags.prototype.colorize = function(){ + HighlightTags.prototype.colorize = function() { var annotations = Array.prototype.slice.call($(".annotator-hl")); - for (annNum = 0; annNum < annotations.length; ++annNum){ + for (annNum = 0; annNum < annotations.length; ++annNum) { var anns = $.data(annotations[annNum],"annotation"); - if (typeof anns.tags != "undefined" && anns.tags.length == 0) { - $(annotations[annNum]).css("background-color",""); - } - if (typeof anns.tags != "undefined" && this.colors !== {}) { + if (typeof anns.tags !== "undefined" && anns.tags.length == 0) { - for(var index = 0; index < anns.tags.length; ++index){ - if(anns.tags[index].indexOf("flagged-") == -1){ - if (typeof this.colors[anns.tags[index]] != "undefined") { + // image annotations should not change the background of the highlight + // only the border so as not to block the image behind it. + if (anns.media !== "image") { + $(annotations[annNum]).css("background-color", ""); + } else { + $(annotations[annNum]).css("border", "2px solid rgb(255, 255, 255)"); + $(annotations[annNum]).css("outline", "2px solid rgb(0, 0, 0)"); + } + } + + if (typeof anns.tags !== "undefined" && this.colors !== {}) { + + for (var index = 0; index < anns.tags.length; ++index) { + if (anns.tags[index].indexOf("flagged-") == -1) { + if (typeof this.colors[anns.tags[index]] !== "undefined") { var finalcolor = this.colors[anns.tags[index]]; - $(annotations[annNum]).css( - "background", - // last value, 0.3 is the standard highlight opacity for annotator - "rgba(" + finalcolor.red + ", " + finalcolor.green + ", " + finalcolor.blue + ", 0.3)" - ); - }else{ - $(annotations[annNum]).css( - "background", - // returns the value to the inherited value without the above - "" - ); + // if it's a text change the background + if (anns.media !== "image") { + $(annotations[annNum]).css( + "background", + // last value, 0.3 is the standard highlight opacity for annotator + "rgba(" + finalcolor.red + ", " + finalcolor.green + ", " + finalcolor.blue + ", 0.3)" + ); + } + // if it's an image change the dark border/outline leave the white one as is + else { + $(annotations[annNum]).css( + "outline", + "2px solid rgb(" + finalcolor.red + ", " + finalcolor.green + ", " + finalcolor.blue + ")" + ); + } + } else { + // if the last tag was not predetermined by instrutor background should go back to default + if (anns.media !== "image") { + $(annotations[annNum]).css( + "background", + // returns the value to the inherited value without the above + "" + ); + } } } } - }else{ - $(annotations[annNum]).css("background",""); + } else { + // if there are no tags or predefined colors, keep the background at default + if (anns.media !== "image") { + $(annotations[annNum]).css("background",""); + } } } this.annotator.publish('colorizeCompleted'); } - HighlightTags.prototype.updateField = function(field, annotation){ - - - if(this.isFirstTime){ - var tags = this.options.tag.split(","); - var tokensavailable = []; - tags.forEach (function(tagnames){ - lonename = tagnames.split(":"); - - tokensavailable.push({'id': lonename[0], 'name':lonename[0]}); - }); - $("#tag-input").tokenInput(tokensavailable); - this.isFirstTime = false; - } - $('#token-input-tag-input').attr('placeholder','Add tags...'); - $('#tag-input').tokenInput('clear'); - if (typeof annotation.tags != "undefined") { - for (tagnum = 0; tagnum < annotation.tags.length; tagnum++){ - var n = annotation.tags[tagnum]; - if (typeof this.annotator.plugins["HighlightTags"] != 'undefined') { - if (annotation.tags[tagnum].indexOf("flagged-")==-1){ - $('#tag-input').tokenInput('add',{'id':n,'name':n}); - } - } else{ - $('#tag-input').tokenInput('add',{'id':n,'name':n}); - } + HighlightTags.prototype.updateField = function(field, annotation) { + // the first time that this plug in runs, the predetermined instructor tags are + // added and stored for the dropdown list + if(this.isFirstTime) { + var tags = this.options.tag.split(","); + var tokensavailable = []; + + // tags are given the structure that the dropdown/token function requires + tags.forEach (function(tagnames) { + lonename = tagnames.split(":"); + tokensavailable.push({'id': lonename[0], 'name': lonename[0]}); + }); + + // they are then added to the appropriate input for tags in annotator + $("#tag-input").tokenInput(tokensavailable); + this.isFirstTime = false; + } + + $('#token-input-tag-input').attr('placeholder', 'Add tags...'); + $('#tag-input').tokenInput('clear'); + + // loops through the tags already in the annotation and "add" them to this annotation + if (typeof annotation.tags !== "undefined") { + for (tagnum = 0; tagnum < annotation.tags.length; tagnum++) { + var n = annotation.tags[tagnum]; + if (typeof this.annotator.plugins["HighlightTags"] !== 'undefined') { + // if there are flags, we must ignore them + if (annotation.tags[tagnum].indexOf("flagged-") == -1) { + $('#tag-input').tokenInput('add',{'id':n,'name':n}); + } + } else { + $('#tag-input').tokenInput('add', {'id': n, 'name': n}); } } - + } + this.colorizeEditorTags(); + } + + // this function adds the appropriate color to the tag divs for each annotation + HighlightTags.prototype.colorizeEditorTags = function() { + var self = this; + $.each($('.annotator-editor .token-input-token'), function(key, tagdiv) { + // default colors are black for text and the original powder blue (already default) + var rgbColor = ""; + var textColor = "color:#000;"; + var par = $(tagdiv).find("p"); + + // if the tag has a predetermined color attached to it, + // then it changes the background and turns text white + if (typeof self.colors[par.html()] !== "undefined") { + var finalcolor = self.colors[par.html()]; + rgbColor = "background-color:rgba(" + finalcolor.red + ", " + finalcolor.green + ", " + finalcolor.blue + ", 0.5);"; + textColor = "color:#fff;"; + } + + // note that to change the text color you must change it in the paragraph tag, not the div + $(tagdiv).attr('style', rgbColor); + par.attr('style', textColor); + }); } - //The following function is run when a person hits submit. + // The following function is run when a person hits submit. HighlightTags.prototype.pluginSubmit = function(field, annotation) { var tokens = Array.prototype.slice.call($(".token-input-input-token").parent().find('.token-input-token')); var arr = []; @@ -1102,41 +1162,63 @@ Annotator.Plugin.HighlightTags = (function(_super) { annotation.tags = arr; } - //The following allows you to edit the annotation popup when the viewer has already - //hit submit and is just viewing the annotation. + // The following allows you to edit the annotation popup when the viewer has already + // hit submit and is just viewing the annotation. HighlightTags.prototype.updateViewer = function(field, annotation) { if (typeof annotation.tags != "undefined") { + + // if there are no tags, the space for tags in the pop up is removed and function ends if (annotation.tags.length == 0) { $(field).remove(); return; } + + // otherwise we prepare to loop through them var nonFlagTags = true; var tokenList = ""; $(field).append(tokenList); + + // the field for tags is removed also if all the tags ended up being flags if (nonFlagTags) { $(field).remove(); } - } else{ + } else { $(field).remove(); } this.annotator.publish("finishedDrawingTags"); } - //The following will call the colorize function during an external call and then return - //an event signaling completion. - HighlightTags.prototype.externalCall = function(){ + // The following will call the colorize function during an external call and then return + // an event signaling completion. + HighlightTags.prototype.externalCall = function() { this.colorize(); this.annotator.publish('finishedExternalCallToHighlightTags'); }