Commit ea8fa20b by Sarina Canelake

Merge pull request #4504 from lduarte1991/lduarte-harvardx-pr11

Annotation Tools: Added Grouping Plug-In
parents 540d67a6 0ca9bfa7
.groupButton {
background-color: rgba(255, 255, 10, 0.3);
position: absolute;
width: 30px;
text-align: center;
right: -17px;
cursor: pointer;
font-size: 13px;
padding: 2px;
border: 1px solid black;
border-bottom-left-radius: 5px;
border-top-left-radius: 5px;
transition: 0.5s;
}
.groupButton:hover {
width: 60px;
transition: 0.5s;
}
.onOffGroupButton, .onOffGroupButton.buttonOn {
border: 1px solid blue;
background-color: rgba(255, 255, 10, 0.3);
padding: 5px;
cursor: pointer;
border-radius: 5px;
color: black;
position: relative;
margin-left: auto;
margin-bottom: 10px;
width: 220px;
font-weight: bold;
text-align: center;
}
.onOffGroupButton.buttonOff {
border: 1px solid black;
background-color: rgba(8, 8, 8, 0.3);
padding: 5px;
cursor: pointer;
border-radius: 5px;
color: black;
position: relative;
margin-left: auto;
margin-bottom: 10px;
width: 220px;
font-weight: bold;
text-align: center;
}
......@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//The name of the plugin that the user will write in the html
// The name of the plugin that the user will write in the html
window.CatchAnnotation = ("CatchAnnotation" in window) ? CatchAnnotation : {};
window.CatchSources = ("CatchSources" in window) ? CatchSources : {};
......@@ -284,7 +284,7 @@ CatchAnnotation = function (element, options) {
var defaultOptions = {
media: 'text',
userId: '', // this is an integer and its value is the userId to see user annotations
externalLink: false,//This is true if you want to open the link in a new URL. However, it is false if you want to open the url in the same page
externalLink: false, // This is true if you want to open the link in a new URL. However, it is false if you want to open the url in the same page
showMediaSelector: true, // whether show the selector of Media Annotations or not
showPublicPrivate: true, // Whether show Public or Private Annotation Selector
pagination: 50, // Number of Annotations per load in the pagination
......@@ -353,7 +353,7 @@ CatchAnnotation.prototype = {
// under the instructor's email. Calling changeUserId will update this.options.userId
// and most importantly refresh not only the highlights (from Annotator)
// but also the table below from the annotations database server (called Catch).
if(this.options.default_tab.toLowerCase() == 'instructor'){
if(this.options.default_tab.toLowerCase() === 'instructor'){
this.changeUserId(this.options.instructor_email);
}
},
......@@ -372,9 +372,9 @@ CatchAnnotation.prototype = {
var self = this;
var newInstance = newInstance || false;
annotations.forEach(function(annotation) {
var isMedia = annotation.media==self.options.media;
var isUser = (typeof self.options.userId!='undefined' && self.options.userId!='' && self.options.userId!=null)?
self.options.userId == annotation.user.id:true;
var isMedia = annotation.media === self.options.media;
var isUser = (typeof self.options.userId !== 'undefined' && self.options.userId !== '' && self.options.userId !== null)?
self.options.userId === annotation.user.id:true;
var isInList = newInstance?false:self._isInList(annotation);
if (isMedia && isUser && !isInList){
var item = jQuery.extend(true, {}, annotation);
......@@ -382,8 +382,8 @@ CatchAnnotation.prototype = {
// Authorized
var permissions = self.annotator.plugins.Permissions;
var authorized = permissions.options.userAuthorize('delete', annotation,permissions.user);
var updateAuthorized = permissions.options.userAuthorize('update', annotation,permissions.user);
var authorized = permissions.options.userAuthorize('delete', annotation, permissions.user);
var updateAuthorized = permissions.options.userAuthorize('update', annotation, permissions.user);
item.authToDeleteButton = authorized;
item.authToEditButton = updateAuthorized;
......@@ -426,13 +426,13 @@ CatchAnnotation.prototype = {
var SelButtons = el.find('.annotationList li').removeClass('active'); // reset
for (var index=0;index<SelButtons.length;index++) {
var span = $(SelButtons[index]);
if (span.attr("media")==this.options.media) $(SelButtons[index]).addClass('active');
if (span.attr("media") === this.options.media) $(SelButtons[index]).addClass('active');
}
// Set PublicPrivate
var PublicPrivateButtons = el.find('.annotationListButtons .PublicPrivate').removeClass('active'); // reset
for (var index=0;index<PublicPrivateButtons.length;index++) {
var span = $(PublicPrivateButtons[index]).find('span');
if (span.html().toLowerCase()==self.current_tab.toLowerCase()) {
if (span.html().toLowerCase() === self.current_tab.toLowerCase()) {
switch (self.current_tab.toLowerCase()){
case 'public':
self.options.userId = '';
......@@ -472,41 +472,41 @@ CatchAnnotation.prototype = {
// Close Button
el.on("click", ".annotationItem .detailHeader", closeAnnotationItem);
// Geolocation button
el.on("click",".annotationItem .detailHeader .geolocationIcon img", onGeolocationClick);
el.on("click", ".annotationItem .detailHeader .geolocationIcon img", onGeolocationClick);
// controlPanel buttons
el.on("click",".annotationItem .annotationDetail .controlPanel", onShareControlsClick);
el.on("click", ".annotationItem .annotationDetail .controlPanel", onShareControlsClick);
// VIDEO
if (this.options.media=='video') {
if (this.options.media === 'video') {
// PlaySelection button
el.on("click",".annotationItem .annotationDetail .playMediaButton", onPlaySelectionClick);
el.on("click", ".annotationItem .annotationDetail .playMediaButton", onPlaySelectionClick);
}
// TEXT
if (this.options.media=='text') {
if (this.options.media === 'text') {
// PlaySelection button
el.on("click",".annotationItem .annotationDetail .quote", onQuoteMediaButton);
el.on("click", ".annotationItem .annotationDetail .quote", onQuoteMediaButton);
}
// IMAGE
if (this.options.media=='image') {
if (this.options.media === 'image') {
// PlaySelection button
el.on("click",".annotationItem .annotationDetail .zoomToImageBounds", onZoomToImageBoundsButtonClick);
el.on("click", ".annotationItem .annotationDetail .zoomToImageBounds", onZoomToImageBoundsButtonClick);
}
// controlReplies
el.on("click",".annotationItem .controlReplies", onControlRepliesClick);
el.on("click", ".annotationItem .controlReplies", onControlRepliesClick);
// Selection Buttons
el.on("click",".annotationList li", onSelectionButtonClick);
el.on("click", ".annotationList li", onSelectionButtonClick);
// PublicPrivate Buttons
el.on("click",".annotationListButtons .PublicPrivate", onPublicPrivateButtonClick);
el.on("click", ".annotationListButtons .PublicPrivate", onPublicPrivateButtonClick);
// More Button
el.on("click",".annotationListButtons .moreButtonCatch", onMoreButtonClick);
el.on("click", ".annotationListButtons .moreButtonCatch", onMoreButtonClick);
// Search Button
el.on("click",".searchbox .search-icon", onSearchButtonClick);
el.on("click", ".searchbox .search-icon", onSearchButtonClick);
// Clear Search Button
el.on("click",".searchbox .clear-search-icon", onClearSearchButtonClick);
el.on("click", ".searchbox .clear-search-icon", onClearSearchButtonClick);
// Delete Reply Button
el.on("click", ".replies .replyItem .deleteReply", onDeleteReplyButtonClick);
......@@ -555,7 +555,7 @@ CatchAnnotation.prototype = {
var annotator = this.annotator;
var loadFromSearch = annotator.plugins.Store.options.loadFromSearch;
var loadedAn = this.element.find('.annotationList .annotationItem').length;
loadedAn = typeof loadedAn!='undefined' ?loadedAn:0;
loadedAn = typeof loadedAn !== 'undefined' ?loadedAn:0;
loadFromSearch.limit = this.options.pagination;
loadFromSearch.offset = loadedAn;
......@@ -636,9 +636,9 @@ CatchAnnotation.prototype = {
});
annotator.subscribe("annotationDeleted", function (annotation){
var annotations = annotator.plugins['Store'].annotations;
var tot = typeof annotations !='undefined'?annotations.length:0;
var tot = typeof annotations !== 'undefined'?annotations.length:0;
var attempts = 0; // max 100
if(annotation.media == "image"){
if(annotation.media === "image"){
self.refreshCatch(true);
self.checkTotAnnotations();
} else {
......@@ -647,14 +647,14 @@ CatchAnnotation.prototype = {
var new_tot = annotator.plugins['Store'].annotations.length;
if (attempts<100)
setTimeout(function(){
if (new_tot != tot){
if (new_tot !== tot){
self.refreshCatch(true);
self.checkTotAnnotations();
}else{
attempts++;
ischanged();
}
},100); // wait for the change in the annotations
}, 100); // wait for the change in the annotations
};
ischanged();
}
......@@ -668,12 +668,12 @@ CatchAnnotation.prototype = {
var ischanged = function(){
if (attempts<100)
setTimeout(function(){
if (typeof annotation.id!='undefined'){
if (typeof annotation.id !== 'undefined'){
// once it gets the annotation id, the table refreshes to show
// the edits
self.refreshCatch();
if (typeof annotation.parent != 'undefined' && annotation.parent != '0'){
if (typeof annotation.parent !== 'undefined' && annotation.parent !== '0'){
// if annotation made was actually a replay to an annotation
// i.e. the only difference is that annotations that are
......@@ -690,7 +690,7 @@ CatchAnnotation.prototype = {
attempts++;
ischanged();
}
},100); // wait for annotation id
}, 100); // wait for annotation id
};
ischanged();
});
......@@ -706,9 +706,9 @@ CatchAnnotation.prototype = {
_isVideoJS: function (an){
var annotator = this.annotator;
var rt = an.rangeTime;
var isOpenVideojs = (typeof annotator.mplayer != 'undefined');
var isVideo = (typeof an.media!='undefined' && an.media=='video');
var isNumber = (typeof rt!='undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
var isOpenVideojs = (typeof annotator.mplayer !== 'undefined');
var isVideo = (typeof an.media !== 'undefined' && an.media === 'video');
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
return (isOpenVideojs && isVideo && isNumber);
},
_isInList: function (an){
......@@ -716,7 +716,7 @@ CatchAnnotation.prototype = {
var isInList = false;
var list = $('#mainCatch .annotationList .annotationRow.item');
for (_i = 0, _len = list.length; _i < _len; _i++) {
if ($(list[_i]).parent().attr('annotationid') == an.id)
if ($(list[_i]).parent().attr('annotationid') === an.id)
isInList = true;
}
return isInList;
......@@ -726,22 +726,26 @@ CatchAnnotation.prototype = {
if(this._isVideoJS(item)){
// format time
item.rangeTime.start= typeof vjs!='undefined'?vjs.formatTime(item.rangeTime.start):item.rangeTime.start;
item.rangeTime.end= typeof vjs!='undefined'?vjs.formatTime(item.rangeTime.end):item.rangeTime.end;
item.rangeTime.start= typeof vjs !== 'undefined' ?
vjs.formatTime(item.rangeTime.start) :
item.rangeTime.start;
item.rangeTime.end= typeof vjs !== 'undefined'?
vjs.formatTime(item.rangeTime.end) :
item.rangeTime.end;
}
// format date
if(typeof item.updated!='undefined' && typeof createDateFromISO8601!='undefined')
if(typeof item.updated !== 'undefined' && typeof createDateFromISO8601 !== 'undefined')
item.updated = createDateFromISO8601(item.updated);
// format geolocation
if(typeof item.geolocation!='undefined' && (typeof item.geolocation.latitude=='undefined'||item.geolocation.latitude==''))
if(typeof item.geolocation !== 'undefined' && (typeof item.geolocation.latitude==='undefined'||item.geolocation.latitude===''))
delete item.geolocation;
/* NEW VARIABLES */
// set plainText for Catch
item.plainText = item.text.replace(/&(lt|gt);/g, function (strMatch, p1){
return (p1 == "lt")? "<" : ">";
});//Change to < and > tags
item.plainText = item.plainText.replace(/<\/?[^>]+(>|$)/g, "").replace('&nbsp;',''); // remove all the html tags
return (p1 === "lt")? "<" : ">";
}); // Change to < and > tags
item.plainText = item.plainText.replace(/<\/?[^>]+(>|$)/g, "").replace('&nbsp;', ''); // remove all the html tags
item.mediatypeforgrid = {};
item.mediatypeforgrid[item.media] = true;
......@@ -751,10 +755,10 @@ CatchAnnotation.prototype = {
};
// Flags
if(!this.options.flags && typeof item.tags != 'undefined' && item.tags.length > 0){
if(!this.options.flags && typeof item.tags !== 'undefined' && item.tags.length > 0){
for(var len=item.tags.length, index = len-1; index >= 0; --index){
var currTag = item.tags[index];
if(currTag.indexOf("flagged-") != -1){
if(currTag.indexOf("flagged-") !== -1){
item.tags.splice(index);
}
......@@ -776,16 +780,16 @@ CatchAnnotation.prototype = {
uri = shareControl.parent().find('.uri').html();
// remove the last share container
shareControl.find('.share-container-annotator').remove();
shareControl.append(annotator.plugins.Share.buildHTMLShareButton("",idAnnotation));
shareControl.append(annotator.plugins.Share.buildHTMLShareButton("", idAnnotation));
// Set actions button
annotator.plugins.Share.buttonsActions(shareControl[0],1,uri);
annotator.plugins.Share.buttonsActions(shareControl[0], 1, uri);
} else {
$(evt.currentTarget).closest(".annotationItem").removeClass("open").addClass("closed");
}
},
_closeAnnotationItem: function(evt) {
var existEvent = typeof evt.target!='undefined' && typeof evt.target.localName!='undefined';
if(existEvent && evt.target.parentNode.className!='geolocationIcon'){
var existEvent = typeof evt.target !== 'undefined' && typeof evt.target.localName !== 'undefined';
if(existEvent && evt.target.parentNode.className !== 'geolocationIcon'){
this._openAnnotationItem(evt);
}
},
......@@ -803,46 +807,46 @@ CatchAnnotation.prototype = {
uri += (uri.indexOf('?') >= 0)?'&ovaId='+id:'?ovaId='+id;
location.href = uri;
}else{
var isContainer = typeof this.annotator.an!='undefined' && typeof this.annotator.an[container]!='undefined',
var isContainer = typeof this.annotator.an !== 'undefined' && typeof this.annotator.an[container] !== 'undefined',
ovaInstance = isContainer? this.annotator.an[container]:null;
if(ovaInstance!=null){
if(ovaInstance !== null){
var allannotations = this.annotator.plugins['Store'].annotations,
ovaId = id,
player = ovaInstance.player;
for (var item in allannotations) {
var an = allannotations[item];
if (typeof an.id!='undefined' && an.id == ovaId){//this is the annotation
if(this._isVideoJS(an)){//It is a video
if (player.id_ == an.target.container && player.tech.options_.source.src == an.target.src){
if (typeof an.id !== 'undefined' && an.id === ovaId) { //this is the annotation
if (this._isVideoJS(an)) { //It is a video
if (player.id_ === an.target.container && player.tech.options_.source.src === an.target.src){
var anFound = an;
var playFunction = function(){
// Fix problem with youtube videos in the first play. The plugin don't have this trigger
if (player.techName == 'Youtube'){
if (player.techName === 'Youtube'){
var startAPI = function(){
ovaInstance.showAnnotation(anFound);
}
if (ovaInstance.loaded)
startAPI();
else
player.one('loadedRangeSlider', startAPI);//show Annotations once the RangeSlider is loaded
player.one('loadedRangeSlider', startAPI); // show Annotations once the RangeSlider is loaded
}else{
ovaInstance.showAnnotation(anFound);
}
$('html,body').animate({
$('html, body').animate({
scrollTop: $("#"+player.id_).offset().top},
'slow');
};
if (player.paused()) {
player.play();
player.one('playing',playFunction);
player.one('playing', playFunction);
}else{
playFunction();
}
return false;//this will stop the code to not set a new player.one.
return false; // this will stop the code to not set a new player.one.
}
}
}
......@@ -866,16 +870,16 @@ CatchAnnotation.prototype = {
var an = allannotations[item];
// Makes sure that all images are set to transparent in case one was
// previously selected.
an.highlights[0].style.background = "rgba(0,0,0,0)";
if (typeof an.id!='undefined' && an.id == osdaId){//this is the annotation
an.highlights[0].style.background = "rgba(0, 0, 0, 0)";
if (typeof an.id !== 'undefined' && an.id === osdaId) { // this is the annotation
var bounds = new OpenSeadragon.Rect(an.bounds.x, an.bounds.y, an.bounds.width, an.bounds.height);
osda.viewer.viewport.fitBounds(bounds, false);
$('html,body').animate({scrollTop: $("#"+an.target.container).offset().top},
$('html, body').animate({scrollTop: $("#"+an.target.container).offset().top},
'slow');
// signifies a selected annotation once OSD has zoomed in on the
// appropriate area, it turns the background a bit yellow
an.highlights[0].style.background = "rgba(255,255,10,0.2)";
an.highlights[0].style.background = "rgba(255, 255, 10, 0.2)";
}
}
},
......@@ -883,7 +887,7 @@ CatchAnnotation.prototype = {
var quote = $(evt.target).hasClass('quote')?$(evt.target):$(evt.target).parents('.quote:first');
var id = quote.find('.idAnnotation').html();
var uri = quote.find('.uri').html();
if (typeof id=='undefined' || id==''){
if (typeof id === 'undefined' || id === ''){
this.refreshCatch();
this.checkTotAnnotations();
id = quote.find('.idAnnotation').html();
......@@ -897,20 +901,20 @@ CatchAnnotation.prototype = {
var ovaId = id;
for (var item in allannotations) {
var an = allannotations[item];
if (typeof an.id!='undefined' && an.id == ovaId){//this is the annotation
if (typeof an.id !== 'undefined' && an.id === ovaId){ // this is the annotation
if(!this._isVideoJS(an)){
var hasRanges = typeof an.ranges!='undefined' && typeof an.ranges[0] !='undefined',
var hasRanges = typeof an.ranges !== 'undefined' && typeof an.ranges[0] !== 'undefined',
startOffset = hasRanges?an.ranges[0].startOffset:'',
endOffset = hasRanges?an.ranges[0].endOffset:'';
if(typeof startOffset!='undefined' && typeof endOffset!='undefined'){
if(typeof startOffset !== 'undefined' && typeof endOffset !== 'undefined'){
$(an.highlights).parent().find('.annotator-hl').removeClass('api');
// change the color
$(an.highlights).addClass('api');
// animate to the annotation
$('html,body').animate({
$('html, body').animate({
scrollTop: $(an.highlights[0]).offset().top},
'slow');
}
......@@ -934,9 +938,9 @@ CatchAnnotation.prototype = {
uri:loadFromSearchURI,
};
var onSuccess=function(data){
if (data == null) data = {};
if (data === null) data = {};
annotations = data.rows || [];
var _i,_len;
var _i, _len;
for (_i = 0, _len = annotations.length; _i < _len; _i++) {
self._formatCatch(annotations[_i]);
......@@ -945,16 +949,16 @@ CatchAnnotation.prototype = {
annotations: annotations
}));
var replyItems = $('.replies .replyItem');
if(typeof replyItems != 'undefined' && replyItems.length > 0){
if(typeof replyItems !== 'undefined' && replyItems.length > 0){
annotations.forEach(function(ann){
replyItems.each(function(item){
var id = $(replyItems[item]).attr('annotationid');
if(id == ann.id){
if(id === ann.id){
var perm = self.annotator.plugins.Permissions;
if(!perm.options.userAuthorize('delete',ann,perm.user)){
if(!perm.options.userAuthorize('delete', ann, perm.user)){
$(replyItems[item]).find('.deleteReply').remove();
}else{
$(replyItems[item]).data('annotation',ann);
$(replyItems[item]).data('annotation', ann);
}
}
......@@ -974,7 +978,7 @@ CatchAnnotation.prototype = {
_onControlRepliesClick: function(evt){
var action = $(evt.target)[0].className;
if(action=='newReply'){
if(action === 'newReply'){
var item = $(evt.target).parents('.annotationItem:first');
var id = item.attr('annotationId');
// Pre-show Adder
......@@ -1001,17 +1005,17 @@ CatchAnnotation.prototype = {
// Set vertical editor
this.annotator.editor.resetOrientation();
this.annotator.editor.invertY();
this.annotator.editor.element.find('.annotator-widget').css('min-width',replyElem.css('width'));
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");
parentValue.html(id);
var self = this;
}else if(action=='hideReplies'){
}else if(action === 'hideReplies'){
var oldAction = $(evt.target).html();
if (oldAction=='Show Replies'){
if (oldAction === 'Show Replies'){
$(evt.target).html('Hide Replies');
}else{
$(evt.target).html('Show Replies');
......@@ -1022,7 +1026,7 @@ CatchAnnotation.prototype = {
// search
this._refreshReplies(evt);
}else if(action=='deleteAnnotation'){
}else if(action === 'deleteAnnotation'){
if(confirm("Would you like to delete the annotation?")){
var annotator = this.annotator;
var item = $(evt.target).parents('.annotationItem:first');
......@@ -1032,14 +1036,14 @@ CatchAnnotation.prototype = {
var permissions = annotator.plugins.Permissions;
var annotation;
annotations.forEach(function(ann){
if(ann.id == id)
if(ann.id === id)
annotation = ann;
});
var authorized = permissions.options.userAuthorize('delete', annotation,permissions.user);
var authorized = permissions.options.userAuthorize('delete', annotation, permissions.user);
if(authorized)
annotator.deleteAnnotation(annotation);
}
}else if(action=='editAnnotation'){
}else if(action === 'editAnnotation'){
var annotator = this.annotator;
var item = $(evt.target).parents('.annotationItem:first');
......@@ -1049,10 +1053,10 @@ CatchAnnotation.prototype = {
var permissions = annotator.plugins.Permissions;
var annotation;
annotations.forEach(function(ann){
if(ann.id == id)
if(ann.id === id)
annotation = ann;
});
var authorized = permissions.options.userAuthorize('update', annotation,permissions.user);
var authorized = permissions.options.userAuthorize('update', annotation, permissions.user);
if(authorized){
// Get elements
var wrapper = $('.annotator-wrapper');
......@@ -1083,18 +1087,18 @@ CatchAnnotation.prototype = {
},
_onShareControlsClick: function(evt) {
var action = $(evt.target)[0].className;
if(action=='privacy_button'){
if(action === 'privacy_button'){
}else if(action=='groups_button'){
}else if(action === 'groups_button'){
alert("Coming soon...");
}else if(action=='reply_button'){
}else if(action === 'reply_button'){
var item = $(evt.target).parents('.annotationItem:first'),
id = item.attr('annotationId');
// New annotation
var an = this.annotator.setupAnnotation(this.annotator.createAnnotation());
an.text="010";
an.parent = id;
}else if(action=='share_button'){
}else if(action === 'share_button'){
}
......@@ -1116,6 +1120,16 @@ CatchAnnotation.prototype = {
break;
}
this.current_tab = action.html();
// checks to make sure that Grouping is redone when switching tags in text annotations
if (this.options.media === 'text') {
if (this.current_tab ==='public') {
this.annotator.plugins.Grouping.useGrouping = 0;
} else {
this.annotator.plugins.Grouping.useGrouping = 1;
}
this.annotator.publish("changedTabsInCatch");
}
// Change userid and refresh
this.changeUserId(userId);
},
......@@ -1133,12 +1147,12 @@ CatchAnnotation.prototype = {
_onMoreButtonClick: function(evt){
this.clean = false;
var moreBut = this.element.find('.annotationListButtons .moreButtonCatch');
var isLoading = moreBut.html()=='More'?false:true;
var isLoading = moreBut.html() === 'More'?false:true;
if(!isLoading)
this.loadAnnotations();
},
_refresh:function(searchtype,searchInput){
_refresh:function(searchtype, searchInput){
var searchtype = searchtype || "";
var searchInput = searchInput || "";
this.clean = true;
......@@ -1156,9 +1170,9 @@ CatchAnnotation.prototype = {
loadFromSearch.tag = "";
loadFromSearch.text = "";
if (searchtype == "Users"){
if (searchtype === "Users"){
loadFromSearch.username = searchInput;
} else if(searchtype == "Tags"){
} else if(searchtype === "Tags"){
loadFromSearch.tag = searchInput;
} else{
loadFromSearch.text = searchInput;
......@@ -1169,11 +1183,11 @@ CatchAnnotation.prototype = {
_onSearchButtonClick: function(evt){
var searchtype = this.element.find('.searchbox .dropdown-list').val();
var searchInput = this.element.find('.searchbox input').val();
this._refresh(searchtype,searchInput);
this._refresh(searchtype, searchInput);
},
_onClearSearchButtonClick: function(evt){
this._refresh('','');
this._refresh('', '');
},
_clearAnnotator: function(){
var annotator = this.annotator;
......@@ -1182,11 +1196,11 @@ CatchAnnotation.prototype = {
annotations.forEach(function(ann){
var child, h, _i, _len, _ref;
if (ann.highlights != null) {
if (ann.highlights !== null) {
_ref = ann.highlights;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
h = _ref[_i];
if (!(h.parentNode != null)) {
if (!(h.parentNode !== null)) {
continue;
}
child = h.childNodes[0];
......@@ -1202,7 +1216,7 @@ CatchAnnotation.prototype = {
var id = item.attr('annotationid');
var permissions = annotator.plugins.Permissions;
var annotation = item.data('annotation');
var authorized = permissions.options.userAuthorize('delete', annotation,permissions.user);
var authorized = permissions.options.userAuthorize('delete', annotation, permissions.user);
if(authorized){
if(confirm('Would you like to delete this reply?')){
annotator.plugins['Store']._apiRequest('destroy', annotation, function(){});
......
var _ref;
var __bind = function(fn, me) {
return function() {
return fn.apply(me, arguments);
};
};
var __hasProp = {}.hasOwnProperty;
var __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.Grouping = (function(_super) {
__extends(Grouping, _super);
// this plugin will have a threshold option (-1 = plugin should be removed)
Grouping.prototype.options = null;
// sets up the grouping structure for the plug-in
function Grouping(element, options) {
this.pluginInit = __bind(this.pluginInit, this);
this.reloadAnnotations = __bind(this.reloadAnnotations, this);
this.groupAndColor = __bind(this.groupAndColor, this);
this.clearGrouping = __bind(this.clearGrouping, this);
this.getPos = __bind(this.getPos, this);
this.groupingButtonPressed = __bind(this.groupingButtonPressed, this);
this.options = options;
_ref = Grouping.__super__.constructor.apply(this, arguments);
return _ref;
}
// instantiation of variables to be passed around below
Grouping.prototype.unfilteredAnnotations = null;
Grouping.prototype.groupedAnnotations = null;
Grouping.prototype.groupthreshold = 0;
Grouping.prototype.useGrouping = 1;
/**
* Gets the current position relative to the annotation wrapper
* @param {HTMLElement} el Element (assumed to be within annotator-wrapper) being measured.
* @return {Object} Position of element passed in using x, y coordinates
*/
Grouping.prototype.getPos = function(el) {
// gets the offset of the element and wrapper
var off = $(el).offset();
var wrapperOff = $($('.annotator-wrapper')[0]).offset();
// do height calculations from the wrapper
return {x:off.left, y:off.top-wrapperOff.top};
}
/**
* Initializes the plugin and its attributes.
*/
Grouping.prototype.pluginInit = function() {
// Check that annotator is working
if (!Annotator.supported()) {
console.log("Annotator is not supported");
return;
}
// makes sure that every time a change is made to annotations, the grouping is redone
this.annotator.subscribe('annotationsLoaded', this.reloadAnnotations);
this.annotator.subscribe('annotationUploaded', this.reloadAnnotations);
this.annotator.subscribe('annotationDeleted', this.reloadAnnotations);
this.annotator.subscribe('annotationCreated', this.reloadAnnotations);
this.annotator.subscribe('changedTabsInCatch', this.groupingButtonPressed);
// sets up the button that toggles the grouping on or off
var newdiv = document.createElement('div');
var className = 'onOffGroupButton';
newdiv.setAttribute('class', className);
// if the item is in public then it should default to grouping being on
if (options.optionsOVA.default_tab.toLowerCase() === 'public') {
newdiv.innerHTML = "Annotation Grouping: ON";
this.useGrouping = 1;
// we wait for HighlightTags to complete before reloading annotations
this.annotator.subscribe('colorizeCompleted', this.reloadAnnotations);
} else {
newdiv.innerHTML = "Annotation Grouping: OFF";
$(newdiv).addClass('buttonOff');
this.useGrouping = 0;
}
$($('.annotator-wrapper')[0]).prepend(newdiv);
$(newdiv).click(this.groupingButtonPressed);
// makes sure that if user resizes window, the annotations are regrouped
var self = this;
$(window).resize(function() {
self.reloadAnnotations();//resize just happened, pixels changed
});
};
/**
* Helper function that removes all of the side buttons and sets background to yellow
*/
Grouping.prototype.clearGrouping = function() {
$('.groupButton').remove();
$.each(this.unfilteredAnnotations, function(val) {
if (val.highlights !== undefined){
$.each(val.highlights, function(high){
$(high).css("background-color", "inherit");
});
}
});
}
/**
* Helper function that goes through and groups together annotations on the same line
*/
Grouping.prototype.groupAndColor = function() {
annotations = this.unfilteredAnnotations;
lineAnnDict = {};
var self = this;
// for each annotation, if they have highlights, get the positions and add them
// to a dictionary based on its initial line location
annotations.forEach(function(annot) {
if (annot.highlights !== undefined) {
var loc = Math.round(self.getPos(annot.highlights[0]).y);
if (lineAnnDict[loc] === undefined) {
lineAnnDict[loc] = [annot];
return;
} else {
lineAnnDict[loc].push(annot);
return;
}
}
});
this.groupedAnnotations = null;
this.groupedAnnotations = lineAnnDict;
// Then it goes through and sets the color based on the threshold set
var self = this;
$.each(lineAnnDict, function(key, val) {
if (val.length > self.groupthreshold) {
val.forEach(function(anno){
$.each(anno.highlights, function(key, anno) {
$(anno).css("background-color", "inherit");
});
});
} else {
val.forEach(function(anno) {
$.each(anno.highlights, function(key, anno) {
$(anno).css("background-color", "rgba(255, 255, 10, .3)");
});
});
}
});
}
/**
* Helper function that clears old groupings, regroups, and adds the side buttons.
*/
Grouping.prototype.reloadAnnotations = function() {
var annotations = this.annotator.plugins['Store'].annotations;
// clear the sidebuttons
this.unfilteredAnnotations = annotations;
this.clearGrouping();
if (this.useGrouping === 0) {
return;
}
this.groupAndColor();
var self = this;
// The following creates a sidebutton that is based on line location. it will
// contain a number referring to the number of hidden annotations
$.each(this.groupedAnnotations, function(key, val) {
if (val.length > self.groupthreshold) {
var newdiv = document.createElement('div');
var className = 'groupButton';
newdiv.setAttribute('class', className);
$(newdiv).css('top', "" + key + "px");
newdiv.innerHTML = val.length;
$(newdiv).attr('data-selected', '0');
$('.annotator-wrapper')[0].appendChild(newdiv);
$(newdiv).click(function(evt){
if($(evt.srcElement).attr("data-selected") === '0') {
annotations.forEach(function(annot){
$.each(annot.highlights, function(key, ann) {
$(ann).css("background-color", "inherit");
});
});
self.groupedAnnotations[$(evt.srcElement).css("top").replace("px", "")].forEach(function(item) {
$.each(item.highlights, function(key, ann) {
$(ann).css("background-color", "rgba(255, 255, 10, 0.3)");
});
});
$(evt.srcElement).attr("data-selected", '1');
} else {
annotations.forEach(function(item) {
$(item).css("background-color", "inherit");
});
self.groupAndColor();
$(evt.srcElement).attr("data-selected", '0');
}
});
}
});
var self = this;
var old = self.unfilteredAnnotations.length;
setTimeout(function() {
if (old !== self.unfilteredAnnotations.length) {
self.reloadAnnotations();
}
}, 500);
return;
};
/**
* Function activated to turn grouping on or off
*/
Grouping.prototype.groupingButtonPressed = function() {
if(this.useGrouping === 1) {
// grouping is cleared
this.useGrouping = 0;
this.clearGrouping();
// remove the grouping functions from being activated by events
this.annotator.unsubscribe('annotationsLoaded', this.reloadAnnotations);
this.annotator.unsubscribe('annotationUploaded', this.reloadAnnotations);
this.annotator.unsubscribe('annotationDeleted', this.reloadAnnotations);
this.annotator.unsubscribe('annotationCreated', this.reloadAnnotations);
// redraw button to turn grouping on/off
$(".onOffGroupButton").html("Annotation Grouping: OFF");
$(".onOffGroupButton").addClass("buttonOff");
this.annotator.plugins.Store.annotations.forEach(function(annot) {
$.each(annot.highlights, function(key, ann) {
$(ann).css("background-color", "");
});
});
// deals with the HighlightTags Plug-In
this.annotator.publish('externalCallToHighlightTags');
this.annotator.unsubscribe('colorizeCompleted', this.reloadAnnotations);
} else {
// runs reload/regroup annotations
this.useGrouping = 1;
this.reloadAnnotations();
// subscribe again to the events triggered by annotations
this.annotator.subscribe('annotationsLoaded', this.reloadAnnotations);
this.annotator.subscribe('annotationUploaded', this.reloadAnnotations);
this.annotator.subscribe('annotationDeleted', this.reloadAnnotations);
this.annotator.subscribe('annotationCreated', this.reloadAnnotations);
// redraw button to turn grouping on/off
$(".onOffGroupButton").html("Annotation Grouping: ON");
$(".onOffGroupButton").removeClass("buttonOff");
this.annotator.subscribe('colorizeCompleted', this.reloadAnnotations);
}
}
return Grouping;
})(Annotator.Plugin);
\ No newline at end of file
......@@ -902,6 +902,7 @@ Annotator.Plugin.HighlightTags = (function(_super) {
this.updateViewer = __bind(this.updateViewer, this);
this.colorize = __bind(this.colorize, this);
this.updateField = __bind(this.updateField, this);
this.externalCall = __bind(this.externalCall, this);
this.options = options;
_ref = HighlightTags.__super__.constructor.apply(this, arguments);
......@@ -950,6 +951,7 @@ Annotator.Plugin.HighlightTags = (function(_super) {
this.annotator.subscribe('annotationUpdated', this.colorize);
this.annotator.subscribe('flaggedAnnotation', this.updateViewer);
this.annotator.subscribe('annotationCreated', this.colorize);
this.annotator.subscribe('externalCallToHighlightTags', this.externalCall);
};
......@@ -1054,6 +1056,8 @@ Annotator.Plugin.HighlightTags = (function(_super) {
$(annotations[annNum]).css("background","");
}
}
this.annotator.publish('colorizeCompleted');
}
HighlightTags.prototype.updateField = function(field, annotation){
......@@ -1130,6 +1134,13 @@ Annotator.Plugin.HighlightTags = (function(_super) {
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(){
this.colorize();
this.annotator.publish('finishedExternalCallToHighlightTags');
}
return HighlightTags;
})(Annotator.Plugin);
......@@ -908,6 +908,7 @@ main_vendor_js = [
'js/vendor/ova/tags-annotator.js',
'js/vendor/ova/flagging-annotator.js',
'js/vendor/ova/diacritic-annotator.js',
'js/vendor/ova/grouping-annotator.js',
'js/vendor/ova/jquery-Watch.js',
'js/vendor/ova/openseadragon.js',
'js/vendor/ova/OpenSeaDragonAnnotation.js',
......@@ -939,6 +940,7 @@ PIPELINE_CSS = {
'css/vendor/ova/tags-annotator.css',
'css/vendor/ova/flagging-annotator.css',
'css/vendor/ova/diacritic-annotator.css',
'css/vendor/ova/grouping-annotator.css',
'css/vendor/ova/ova.css',
'js/vendor/ova/catch/css/main.css'
],
......
......@@ -154,7 +154,7 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
},
optionsVideoJS: {techOrder: ["html5","flash","youtube"]},
optionsRS: {},
optionsOVA: {posBigNew:'none'},
optionsOVA: {posBigNew:'none', default_tab:"${default_tab}"},
optionsRichText: {
tinymce:{
selector: "li.annotator-item textarea",
......@@ -177,6 +177,9 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
//Load the plugin Video/Text Annotation
var ova = new OpenVideoAnnotation.Annotator($('#textHolder'),options);
if (typeof Annotator.Plugin["Grouping"] === 'function')
ova.annotator.addPlugin("Grouping");
var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
'${instructor_email}':
'${user.email}';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment