Commit 32e96681 by lduarte1991

Image Annotation Tool: create xmodule and install js files

parent c2425200
...@@ -139,7 +139,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): ...@@ -139,7 +139,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
# response HTML # response HTML
self.check_components_on_page( self.check_components_on_page(
ADVANCED_COMPONENT_TYPES, ADVANCED_COMPONENT_TYPES,
['Word cloud', 'Annotation', 'Text Annotation', 'Video Annotation', ['Word cloud', 'Annotation', 'Text Annotation', 'Video Annotation', 'Image Annotation',
'Open Response Assessment', 'Peer Grading Interface', 'openassessment'], 'Open Response Assessment', 'Peer Grading Interface', 'openassessment'],
) )
......
...@@ -36,6 +36,7 @@ XMODULES = [ ...@@ -36,6 +36,7 @@ XMODULES = [
"annotatable = xmodule.annotatable_module:AnnotatableDescriptor", "annotatable = xmodule.annotatable_module:AnnotatableDescriptor",
"textannotation = xmodule.textannotation_module:TextAnnotationDescriptor", "textannotation = xmodule.textannotation_module:TextAnnotationDescriptor",
"videoannotation = xmodule.videoannotation_module:VideoAnnotationDescriptor", "videoannotation = xmodule.videoannotation_module:VideoAnnotationDescriptor",
"imageannotation = xmodule.imageannotation_module:ImageAnnotationDescriptor",
"foldit = xmodule.foldit_module:FolditDescriptor", "foldit = xmodule.foldit_module:FolditDescriptor",
"word_cloud = xmodule.word_cloud_module:WordCloudDescriptor", "word_cloud = xmodule.word_cloud_module:WordCloudDescriptor",
"hidden = xmodule.hidden_module:HiddenDescriptor", "hidden = xmodule.hidden_module:HiddenDescriptor",
......
"""
Module for Image annotations using annotator.
"""
from lxml import etree
from pkg_resources import resource_string
from xmodule.x_module import XModule
from xmodule.raw_module import RawDescriptor
from xblock.core import Scope, String
from xmodule.annotator_mixin import get_instructions, html_to_text
from xmodule.annotator_token import retrieve_token
import textwrap
class AnnotatableFields(object):
""" Fields for `ImageModule` and `ImageDescriptor`. """
data = String(help="XML data for the annotation", scope=Scope.content, default=textwrap.dedent("""\
<annotatable>
<instructions>
<p>
Add the instructions to the assignment here.
</p>
</instructions>
<p>
Lorem ipsum dolor sit amet, at amet animal petentium nec. Id augue nemore postulant mea. Ex eam dicant noluisse expetenda, alia admodum abhorreant qui et. An ceteros expetenda mea, tale natum ipsum quo no, ut pro paulo alienum noluisse.
</p>
<json>
navigatorSizeRatio: 0.25,
wrapHorizontal: false,
showNavigator: true,
navigatorPosition: "BOTTOM_LEFT",
showNavigationControl: true,
tileSources: [{
Image: {
xmlns: "http://schemas.microsoft.com/deepzoom/2009",
Url: "http://static.seadragon.com/content/misc/milwaukee_files/",
TileSize: "254",
Overlap: "1",
Format: "jpg",
ServerFormat: "Default",
Size: {
Width: "15497",
Height: "5378"
}
}
},],
</json>
</annotatable>
"""))
display_name = String(
display_name="Display Name",
help="Display name for this module",
scope=Scope.settings,
default='Image Annotation',
)
instructor_tags = String(
display_name="Tags for Assignments",
help="Add tags that automatically highlight in a certain color using the comma-separated form, i.e. imagery:red,parallelism:blue",
scope=Scope.settings,
default='professor:green,teachingAssistant:blue',
)
annotation_storage_url = String(help="Location of Annotation backend", scope=Scope.settings, default="http://your_annotation_storage.com", display_name="Url for Annotation Storage")
annotation_token_secret = String(help="Secret string for annotation storage", scope=Scope.settings, default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", display_name="Secret Token String for Annotation")
class ImageAnnotationModule(AnnotatableFields, XModule):
'''Image Annotation Module'''
js = {
'coffee': [
resource_string(__name__, 'js/src/javascript_loader.coffee'),
resource_string(__name__, 'js/src/html/display.coffee'),
resource_string(__name__, 'js/src/annotatable/display.coffee'),
],
'js': [
resource_string(__name__, 'js/src/collapsible.js'),
]
}
css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]}
icon_class = 'imageannotation'
def __init__(self, *args, **kwargs):
super(ImageAnnotationModule, self).__init__(*args, **kwargs)
xmltree = etree.fromstring(self.data)
self.instructions = self._extract_instructions(xmltree)
self.openseadragonjson = html_to_text(etree.tostring(xmltree.find('json'), encoding='unicode'))
self.user = ""
if self.runtime.get_real_user is not None:
self.user = self.runtime.get_real_user(self.runtime.anonymous_student_id).email
def _extract_instructions(self, xmltree):
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
return get_instructions(xmltree)
def get_html(self):
""" Renders parameters to template. """
context = {
'display_name': self.display_name_with_default,
'instructions_html': self.instructions,
'annotation_storage': self.annotation_storage_url,
'token':retrieve_token(self.user, self.annotation_token_secret),
'tag': self.instructor_tags,
'openseadragonjson': self.openseadragonjson,
}
return self.system.render_template('imageannotation.html', context)
class ImageAnnotationDescriptor(AnnotatableFields, RawDescriptor):
''' Image annotation descriptor '''
module_class = ImageAnnotationModule
mako_template = "widgets/raw-edit.html"
@property
def non_editable_metadata_fields(self):
non_editable_fields = super(ImageAnnotationDescriptor, self).non_editable_metadata_fields
non_editable_fields.extend([
ImageAnnotationDescriptor.annotation_storage_url,
ImageAnnotationDescriptor.annotation_token_secret,
])
return non_editable_fields
\ No newline at end of file
# -*- coding: utf-8 -*-
"Test for Image Annotation Xmodule functional logic."
import unittest
from mock import Mock
from lxml import etree
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
from xmodule.imageannotation_module import ImageAnnotationModule
from . import get_test_system
class ImageAnnotationModuleTestCase(unittest.TestCase):
''' Image Annotation Module Test Case '''
sample_xml = '''
<annotatable>
<instructions><p>Image Test Instructions.</p></instructions>
<json>
navigatorSizeRatio: 0.25,
wrapHorizontal: false,
showNavigator: true,
navigatorPosition: "BOTTOM_LEFT",
showNavigationControl: true,
tileSources: [{
Image: {
xmlns: "http://schemas.microsoft.com/deepzoom/2009",
Url: "http://static.seadragon.com/content/misc/milwaukee_files/",
TileSize: "254",
Overlap: "1",
Format: "jpg",
ServerFormat: "Default",
Size: {
Width: "15497",
Height: "5378"
}
}
},],
</json>
</annotatable>
'''
def setUp(self):
"""
Makes sure that the Module is declared and mocked with the sample xml above.
"""
self.mod = ImageAnnotationModule(
Mock(),
get_test_system(),
DictFieldData({'data': self.sample_xml}),
ScopeIds(None, None, None, None)
)
def test_extract_instructions(self):
"""
Tests to make sure that the instructions are correctly pulled from the sample xml above.
It also makes sure that if no instructions exist, that it does in fact return nothing.
"""
xmltree = etree.fromstring(self.sample_xml)
expected_xml = u"<div><p>Image Test Instructions.</p></div>"
actual_xml = self.mod._extract_instructions(xmltree) # pylint: disable=W0212
self.assertIsNotNone(actual_xml)
self.assertEqual(expected_xml.strip(), actual_xml.strip())
xmltree = etree.fromstring('<annotatable>foo</annotatable>')
actual = self.mod._extract_instructions(xmltree) # pylint: disable=W0212
self.assertIsNone(actual)
def test_get_html(self):
"""
Tests the function that passes in all the information in the context that will be used in templates/textannotation.html
"""
context = self.mod.get_html()
for key in ['display_name', 'instructions_html', 'annotation_storage', 'token', 'tag', 'openseadragonjson']:
self.assertIn(key, context)
\ No newline at end of file
/*
Grid Annotation Plugin v1.0
Copyright (C) 2014 Daniel Cebrian Robles and Luis Duarte
License: https://github.com/danielcebrian/share-annotator/blob/master/License.rst
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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.CatchAnnotation = ("CatchAnnotation" in window) ? CatchAnnotation : {};
window.CatchSources = ("CatchSources" in window) ? CatchSources : {}; window.CatchSources = ("CatchSources" in window) ? CatchSources : {};
...@@ -76,13 +95,10 @@ annotationMediaSelector: ...@@ -76,13 +95,10 @@ annotationMediaSelector:
'<li class="ui-state-default" media="video">'+ '<li class="ui-state-default" media="video">'+
'Video'+ 'Video'+
'</li>'+ '</li>'+
'li class="ui-state-default" media="image">'+
'Image'+
'</li>'+
'</ul>', '</ul>',
// '<div class="selButtonCatch">Text<span class="action">text</span></div>'+
// '<div class="selButtonCatch">Video<span class="action">video</span></div>',
// '<div class="selButtonCatch">Images<span class="action">image</span></div>'+
// '<div class="selButtonCatch">Audio<span class="action">audio</span></div>'+
// '<div class="selButtonCatch">Maps<span class="action">map</span></div>'+
// '<div class="selButtonCatch">3D studio<span class="action">3d</span></div>',
//Main->ContainerRow //Main->ContainerRow
annotationItem: annotationItem:
...@@ -162,7 +178,15 @@ annotationRow: ...@@ -162,7 +178,15 @@ annotationRow:
//Main->ContainerRow->DetailRow //Main->ContainerRow->DetailRow
annotationDetail: annotationDetail:
'{{#if mediatypeforgrid.text}}'+
'<div class="annotationDetail">'+ '<div class="annotationDetail">'+
'{{/if}}'+
'{{#if mediatypeforgrid.video}}'+
'<div class="annotationDetail videoAnnotationDetail">'+
'{{/if}}'+
'{{#if mediatypeforgrid.image}}'+
'<div class="annotationDetail imageAnnotationDetail">'+
'{{/if}}'+
'<div class="detailHeader">'+ '<div class="detailHeader">'+
'<span class="closeDetailIcon">'+ '<span class="closeDetailIcon">'+
'<img src="'+root+'closeIcon.png" alt="Hide Details" />'+ '<img src="'+root+'closeIcon.png" alt="Hide Details" />'+
...@@ -181,77 +205,25 @@ annotationDetail: ...@@ -181,77 +205,25 @@ annotationDetail:
'{{/if}}'+ '{{/if}}'+
'</div>'+ '</div>'+
'{{#if mediatypeforgrid.text}}'+
'<div class="quote">'+ '<div class="quote">'+
'<div style="text-align: center">'+ '<div style="text-align: center">'+
'<div class="quoteItem">“</div><div class="quoteText">{{{ quote }}}</div><div class="quoteItem">”</div></div>'+ '<div class="quoteItem">“</div><div class="quoteText">{{{ quote }}}</div><div class="quoteItem">”</div></div>'+
'<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+ '<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+
'<span class="uri" style="display:none">{{{uri}}}</span>'+ '<span class="uri" style="display:none">{{{uri}}}</span>'+
'</div>'+ '</div>'+
'<div class="body">'+
'{{{ text }}}'+
'</div>'+
'<div class="controlReplies">'+
'<div class="newReply" style="text-decoration:underline">Reply</div>&nbsp;'+
'<div class="hideReplies" style="text-decoration:underline;display:{{#if hasReplies}}block{{else}}none{{/if}}">Show Replies</div>&nbsp;'+
'{{#if authToEditButton}}'+
'<div class="editAnnotation" style="text-decoration:underline">Edit</div>'+
'{{/if}}'+
'{{#if authToDeleteButton}}'+
'<div class="deleteAnnotation" style="text-decoration:underline">Delete</div>'+
'{{/if}}'+
'</div>'+
'<div class="replies"></div>'+
'{{#if tags}}'+
'<div class="tags">'+
'<h3>Tags:</h3>'+
'{{#each tags}}'+
'<div class="tag">'+
'{{this}}'+
'</div>'+
'{{/each}}'+
'</div>'+
'{{/if}}'+ '{{/if}}'+
'{{#if mediatypeforgrid.video}}'+
'<div class="controlPanel">'+
//'<img class="privacy_button" src="'+root+'privacy_icon.png" width="36" height="36" alt="Privacy Settings" title="Privacy Settings">'+
// '<img class="groups_button" src="'+root+'groups_icon.png" width="36" height="36" alt="Groups Access" title="Groups Access">'+
//'<img class="share_button" src="'+root+'share_icon.png" width="36" height="36" alt="Share Annotation" title="Share Annotation"/>'+
'</div>'+
'</div>',
//Main->ContainerRow->DetailRow (Video)
videoAnnotationDetail:
'<div class="annotationDetail videoAnnotationDetail">'+
'<div class="detailHeader">'+
'<span class="closeDetailIcon">'+
'<img src="'+root+'closeIcon.png" alt="Hide Details" />'+
'</span>'+
'On {{ updated }} <!--<a href="index.php?r=user/user/view&id={{{user.id}}}">-->{{{ user.name }}}<!--</a>-->{{#if geolocation}}, wrote from {{/if}}'+
'{{#if geolocation}}'+
'<span class="geolocationIcon">'+
'<img src="'+root+'geolocation_icon.png"width="25" height="25" alt="Location Map" title="Show Location Map" data-dropdown="myLocationMap"/>'+
'<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+
'<span class="latitude" style="display:none">{{{ geolocation.latitude }}}</span>'+
'<span class="longitude" style="display:none">{{{ geolocation.longitude }}}</span>'+
'</span>'+
'<div id="myLocationMap" data-dropdown-content class="f-dropdown content">'+
'<div class="map"></div>'+
'</div>'+
'{{/if}}'+
'</div>'+
'<div class="playMediaButton">'+ '<div class="playMediaButton">'+
'Play segment {{{ rangeTime.start }}} - {{{ rangeTime.end }}}'+ 'Play segment {{{ rangeTime.start }}} - {{{ rangeTime.end }}}'+
'<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+ '<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+
'<span class="uri" style="display:none">{{{uri}}}</span>'+ '<span class="uri" style="display:none">{{{uri}}}</span>'+
'<span class="container" style="display:none">{{{target.container}}}</span>'+ '<span class="container" style="display:none">{{{target.container}}}</span>'+
'</div>'+ '</div>'+
'{{/if}}'+
'{{#if mediatypeforgrid.image}}'+
'<img src="http://www.paraemigrantes.com/wp-content/themes/daily/images/default-thumb.gif">'+
'{{/if}}'+
'<div class="body">'+ '<div class="body">'+
'{{{ text }}}'+ '{{{ text }}}'+
'</div>'+ '</div>'+
...@@ -343,7 +315,6 @@ CatchAnnotation.prototype = { ...@@ -343,7 +315,6 @@ CatchAnnotation.prototype = {
"annotationReply",//Main->ContainerRow->Reply "annotationReply",//Main->ContainerRow->Reply
"annotationRow", //Main->ContainerRow->Row "annotationRow", //Main->ContainerRow->Row
"annotationDetail",//Main->ContainerRow->DetailRow "annotationDetail",//Main->ContainerRow->DetailRow
"videoAnnotationDetail"//Main->ContainerRow->DetailRow (Video)
]; ];
//annotator //annotator
var wrapper = $('.annotator-wrapper').parent()[0], var wrapper = $('.annotator-wrapper').parent()[0],
...@@ -400,7 +371,7 @@ CatchAnnotation.prototype = { ...@@ -400,7 +371,7 @@ CatchAnnotation.prototype = {
evenOrOdd: index % 2 ? "odd" : "even", evenOrOdd: index % 2 ? "odd" : "even",
openOrClosed: "closed", openOrClosed: "closed",
annotationRow: self.TEMPLATES.annotationRow(item), annotationRow: self.TEMPLATES.annotationRow(item),
annotationDetail: (mediaType === "video") ? self.TEMPLATES.videoAnnotationDetail(item):self.TEMPLATES.annotationDetail(item), annotationDetail: self.TEMPLATES.annotationDetail(item),
}); });
index++; index++;
annotationItems.push(html); annotationItems.push(html);
...@@ -568,7 +539,6 @@ CatchAnnotation.prototype = { ...@@ -568,7 +539,6 @@ CatchAnnotation.prototype = {
var moreBut = this.element.find('.annotationListButtons .moreButtonCatch'); var moreBut = this.element.find('.annotationListButtons .moreButtonCatch');
moreBut.html('More'); moreBut.html('More');
setTimeout();
}, },
// //
...@@ -678,6 +648,9 @@ CatchAnnotation.prototype = { ...@@ -678,6 +648,9 @@ CatchAnnotation.prototype = {
});//Change to < and > tags });//Change to < and > tags
item.plainText = item.plainText.replace(/<\/?[^>]+(>|$)/g, "").replace('&nbsp;',''); //remove all the html tags item.plainText = item.plainText.replace(/<\/?[^>]+(>|$)/g, "").replace('&nbsp;',''); //remove all the html tags
item.mediatypeforgrid = {};
item.mediatypeforgrid[item.media] = true;
//Flags //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){ for(var len=item.tags.length, index = len-1; index >= 0; --index){
...@@ -1095,7 +1068,6 @@ CatchAnnotation.prototype = { ...@@ -1095,7 +1068,6 @@ CatchAnnotation.prototype = {
annotation = item.data('annotation'); 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(authorized){
//annotator.deleteAnnotation(annotation);
if(confirm('Would you like to delete this reply?')){ if(confirm('Would you like to delete this reply?')){
annotator.plugins['Store']._apiRequest('destroy', annotation, function(){}); annotator.plugins['Store']._apiRequest('destroy', annotation, function(){});
item.remove(); item.remove();
...@@ -1103,5 +1075,3 @@ CatchAnnotation.prototype = { ...@@ -1103,5 +1075,3 @@ CatchAnnotation.prototype = {
} }
} }
} }
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -845,6 +845,8 @@ main_vendor_js = [ ...@@ -845,6 +845,8 @@ main_vendor_js = [
'js/vendor/ova/tags-annotator.js', 'js/vendor/ova/tags-annotator.js',
'js/vendor/ova/flagging-annotator.js', 'js/vendor/ova/flagging-annotator.js',
'js/vendor/ova/jquery-Watch.js', 'js/vendor/ova/jquery-Watch.js',
'js/vendor/ova/openseadragon.js',
'js/vendor/ova/OpenSeaDragonAnnotation.js',
'js/vendor/ova/ova.js', 'js/vendor/ova/ova.js',
'js/vendor/ova/catch/js/catch.js', 'js/vendor/ova/catch/js/catch.js',
'js/vendor/ova/catch/js/handlebars-1.1.2.js', 'js/vendor/ova/catch/js/handlebars-1.1.2.js',
......
<%! from django.utils.translation import ugettext as _ %>
<%namespace name='static' file='/static_content.html'/>
${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)}
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/tinymce.full.min.js', raw=True)}" />
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js', raw=True)}" />
<style type="text/css">
.openseadragon1{
width: 100%;
height: 600px;
cursor: all-scroll;
}
</style>
<div class="annotatable-wrapper">
<div class="annotatable-header">
% if display_name is not UNDEFINED and display_name is not None:
<div class="annotatable-title">${display_name}</div>
% endif
</div>
% if instructions_html is not UNDEFINED and instructions_html is not None:
<div class="annotatable-section shaded">
<div class="annotatable-section-title">
${_('Instructions')}
<a class="annotatable-toggle annotatable-toggle-instructions expanded" href="javascript:void(0)">${_('Collapse Instructions')}</a>
</div>
<div class="annotatable-section-body annotatable-instructions">
${instructions_html}
</div>
</div>
% endif
<div class="annotatable-section">
<div class="annotatable-content">
<div id="imageHolder" class="openseadragon1">
</div>
<div id="catchDIV">
<div class="annotationListContainer">${_('You do not have any notes.')}</div>
</div>
</div>
</div>
</div>
<script>
function onClickHideInstructions(){
//Reset function if there is more than one event handler
$(this).off();
$(this).on('click',onClickHideInstructions);
var hide = $(this).html()=='Collapse Instructions'?true:false,
cls, txt,slideMethod;
txt = (hide ? 'Expand' : 'Collapse') + ' Instructions';
cls = (hide ? ['expanded', 'collapsed'] : ['collapsed', 'expanded']);
slideMethod = (hide ? 'slideUp' : 'slideDown');
$(this).text(txt).removeClass(cls[0]).addClass(cls[1]);
$(this).parents('.annotatable-section:first').find('.annotatable-instructions')[slideMethod]();
}
$('.annotatable-toggle-instructions').on('click', onClickHideInstructions);
//Grab uri of the course
var parts = window.location.href.split("/"),
uri = '',
courseid;
for (var index = 0; index <= 9; index += 1) uri += parts[index]+"/"; //Get the unit url
courseid = parts[4] + "/" + parts[5] + "/" + parts[6];
//Change uri in cms
var lms_location = $('.sidebar .preview-button').attr('href');
if (typeof lms_location!='undefined'){
courseid = parts[4].split(".").join("/");
uri = window.location.protocol;
for (var index = 0; index <= 9; index += 1) uri += lms_location.split("/")[index]+"/"; //Get the unit url
}
var unit_id = $('#sequence-list').find('.active').attr("data-element");
uri += unit_id;
var pagination = 100,
is_staff = !('${user.is_staff}'=='False'),
options = {
optionsAnnotator: {
permissions:{
user: {
id:"${user.email}",
name:"${user.username}"
},
userString: function (user) {
if (user && user.name)
return user.name;
return user;
},
userId: function (user) {
if (user && user.id)
return user.id;
return user;
},
permissions: {
'read': [],
'update': ["${user.email}"],
'delete': ["${user.email}"],
'admin': ["${user.email}"]
},
showViewPermissionsCheckbox: true,
showEditPermissionsCheckbox: false,
userAuthorize: function(action, annotation, user) {
var token, tokens, _i, _len;
if (annotation.permissions) {
tokens = annotation.permissions[action] || [];
if (is_staff){
return true;
}
if (tokens.length === 0) {
return true;
}
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
token = tokens[_i];
if (this.userId(user) === token) {
return true;
}
}
return false;
} else if (annotation.user) {
if (user) {
return this.userId(user) === this.userId(annotation.user);
} else {
return false;
}
}
return true;
},
},
auth: {
token: "${token}"
},
store: {
// The endpoint of the store on your server.
prefix: "${annotation_storage}",
annotationData: {
uri: uri,
},
urls: {
// These are the default URLs.
create: '/create',
read: '/read/:id',
update: '/update/:id',
destroy: '/delete/:id',
search: '/search'
},
loadFromSearch:{
limit:pagination,
offset:0,
uri:uri,
media:'image',
userid:'${user.email}',
}
},
highlightTags:{
tag: "${tag}",
},
richText: {
tinymce:{
selector: "li.annotator-item textarea",
plugins: "image codemirror",
menubar: false,
toolbar_items_size: 'small',
extended_valid_elements : "iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]",
toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image rubric | code ",
}
},
},
optionsOpenSeadragon:{
id: "imageHolder",
prefixUrl: "${settings.STATIC_URL}" + "js/vendor/ova/images/",
${openseadragonjson}
},
optionsOSDA:{},
};
tinymce.baseURL = "${settings.STATIC_URL}" + "js/vendor/tinymce/js/tinymce";
var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/";
if (typeof Annotator != 'undefined'){
//remove old instances
if (Annotator._instances.length !== 0) {
$('#imageHolder').annotator("destroy");
}
delete osda;
//Load the plugin Image/Text Annotation
var osda = new OpenSeadragonAnnotation($('#imageHolder'),options);
//Catch
var annotator = osda.annotator,
catchOptions = {
media:'image',
externalLink:false,
imageUrlRoot:imgURLRoot,
showMediaSelector: false,
showPublicPrivate: true,
userId:'${user.email}',
pagination:pagination,//Number of Annotations per load in the pagination,
flags:is_staff
},
Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
}
</script>
\ No newline at end of file
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