Merge pull request #3831 from lduarte1991/lduarte-harvardx-image
Installing Image Annotation Tool for Upcoming June 2014 Course
1
AUTHORS
@@ -147,3 +147,4 @@ David Bodor <david.gabor.bodor@gmail.com>
|
||||
Sébastien Hinderer <Sebastien.Hinderer@inria.fr>
|
||||
Kristin Stephens <ksteph@cs.berkeley.edu>
|
||||
Ben Patterson <bpatterson@edx.org>
|
||||
Luis Duarte <lduarte1991@gmail.com>
|
||||
|
||||
@@ -754,3 +754,5 @@ LMS: Option to email students when enroll/un-enroll them.
|
||||
|
||||
Blades: Added WAI-ARIA markup to the video player controls. These are now fully
|
||||
accessible by screen readers.
|
||||
|
||||
Common: Added advanced_module for annotating images to go with the ones for text and videos.
|
||||
|
||||
@@ -139,7 +139,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
|
||||
# response HTML
|
||||
self.check_components_on_page(
|
||||
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'],
|
||||
)
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ else:
|
||||
'annotatable',
|
||||
'textannotation', # module for annotating text (with annotation table)
|
||||
'videoannotation', # module for annotating video (with annotation table)
|
||||
'imageannotation', # module for annotating image (with annotation table)
|
||||
'word_cloud',
|
||||
'graphical_slider_tool',
|
||||
'lti',
|
||||
|
||||
@@ -36,6 +36,7 @@ XMODULES = [
|
||||
"annotatable = xmodule.annotatable_module:AnnotatableDescriptor",
|
||||
"textannotation = xmodule.textannotation_module:TextAnnotationDescriptor",
|
||||
"videoannotation = xmodule.videoannotation_module:VideoAnnotationDescriptor",
|
||||
"imageannotation = xmodule.imageannotation_module:ImageAnnotationDescriptor",
|
||||
"foldit = xmodule.foldit_module:FolditDescriptor",
|
||||
"word_cloud = xmodule.word_cloud_module:WordCloudDescriptor",
|
||||
"hidden = xmodule.hidden_module:HiddenDescriptor",
|
||||
|
||||
55
common/lib/xmodule/xmodule/annotator_mixin.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Annotations Tool Mixin
|
||||
This file contains global variables and functions used in the various Annotation Tools.
|
||||
"""
|
||||
from lxml import etree
|
||||
from urlparse import urlparse
|
||||
from os.path import splitext, basename
|
||||
from HTMLParser import HTMLParser
|
||||
|
||||
|
||||
def get_instructions(xmltree):
|
||||
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
|
||||
instructions = xmltree.find('instructions')
|
||||
if instructions is not None:
|
||||
instructions.tag = 'div'
|
||||
xmltree.remove(instructions)
|
||||
return etree.tostring(instructions, encoding='unicode')
|
||||
return None
|
||||
|
||||
|
||||
def get_extension(srcurl):
|
||||
"""get the extension of a given url """
|
||||
if 'youtu' in srcurl:
|
||||
return 'video/youtube'
|
||||
else:
|
||||
disassembled = urlparse(srcurl)
|
||||
file_ext = splitext(basename(disassembled.path))[1]
|
||||
return 'video/' + file_ext.replace('.', '')
|
||||
|
||||
|
||||
class MLStripper(HTMLParser):
|
||||
"helper function for html_to_text below"
|
||||
def __init__(self):
|
||||
HTMLParser.__init__(self)
|
||||
self.reset()
|
||||
self.fed = []
|
||||
|
||||
def handle_data(self, data):
|
||||
"""takes the data in separate chunks"""
|
||||
self.fed.append(data)
|
||||
|
||||
def handle_entityref(self, name):
|
||||
"""appends the reference to the body"""
|
||||
self.fed.append('&%s;' % name)
|
||||
|
||||
def get_data(self):
|
||||
"""joins together the seperate chunks into one cohesive string"""
|
||||
return ''.join(self.fed)
|
||||
|
||||
|
||||
def html_to_text(html):
|
||||
"strips the html tags off of the text to return plaintext"
|
||||
htmlstripper = MLStripper()
|
||||
htmlstripper.feed(html)
|
||||
return htmlstripper.get_data()
|
||||
@@ -25,7 +25,7 @@ def retrieve_token(userid, secret):
|
||||
delta = dtnow - dtutcnow
|
||||
newhour, newmin = divmod((delta.days * 24 * 60 * 60 + delta.seconds + 30) // 60, 60)
|
||||
newtime = "%s%+02d:%02d" % (dtnow.isoformat(), newhour, newmin)
|
||||
# uses the issued time (UTC plus timezone), the consumer key and the user's email to maintain a
|
||||
# uses the issued time (UTC plus timezone), the consumer key and the user's email to maintain a
|
||||
# federated system in the annotation backend server
|
||||
custom_data = {"issuedAt": newtime, "consumerKey": secret, "userId": userid, "ttl": 86400}
|
||||
newtoken = create_token(secret, custom_data)
|
||||
|
||||
120
common/lib/xmodule/xmodule/imageannotation_module.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
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: [{"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2", "scale_factors": [1, 2, 4, 8, 16, 32, 64], "tile_height": 1024, "height": 3466, "width": 113793, "tile_width": 1024, "qualities": ["native", "bitonal", "grey", "color"], "formats": ["jpg", "png", "gif"], "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", "@id": "http://54.187.32.48/loris/suzhou_orig.jp2"}],
|
||||
</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): # pylint: disable=abstract-method
|
||||
''' 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
|
||||
54
common/lib/xmodule/xmodule/tests/test_annotator_mixin.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
This test will run for annotator_mixin.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from lxml import etree
|
||||
|
||||
from xmodule.annotator_mixin import get_instructions, get_extension, html_to_text
|
||||
|
||||
|
||||
class HelperFunctionTest(unittest.TestCase):
|
||||
"""
|
||||
Tests to ensure that the following helper functions work for the annotation tool
|
||||
"""
|
||||
sample_xml = '''
|
||||
<annotatable>
|
||||
<instructions><p>Helper Test Instructions.</p></instructions>
|
||||
</annotatable>
|
||||
'''
|
||||
sample_sourceurl = "http://video-js.zencoder.com/oceans-clip.mp4"
|
||||
sample_youtubeurl = "http://www.youtube.com/watch?v=yxLIu-scR9Y"
|
||||
sample_html = '<p><b>Testing here</b> and not bolded here</p>'
|
||||
|
||||
def test_get_instructions(self):
|
||||
"""
|
||||
Function takes in an input of a specific xml string with surrounding instructions
|
||||
tags and returns a valid html string.
|
||||
"""
|
||||
xmltree = etree.fromstring(self.sample_xml)
|
||||
|
||||
expected_xml = u"<div><p>Helper Test Instructions.</p></div>"
|
||||
actual_xml = get_instructions(xmltree)
|
||||
self.assertIsNotNone(actual_xml)
|
||||
self.assertEqual(expected_xml.strip(), actual_xml.strip())
|
||||
|
||||
xmltree = etree.fromstring('<annotatable>foo</annotatable>')
|
||||
actual = get_instructions(xmltree)
|
||||
self.assertIsNone(actual)
|
||||
|
||||
def test_get_extension(self):
|
||||
"""
|
||||
Tests whether given a url if the video will return a youtube source or extension
|
||||
"""
|
||||
expectedyoutube = 'video/youtube'
|
||||
expectednotyoutube = 'video/mp4'
|
||||
result1 = get_extension(self.sample_sourceurl)
|
||||
result2 = get_extension(self.sample_youtubeurl)
|
||||
self.assertEqual(expectedyoutube, result2)
|
||||
self.assertEqual(expectednotyoutube, result1)
|
||||
|
||||
def test_html_to_text(self):
|
||||
expectedtext = "Testing here and not bolded here"
|
||||
result = html_to_text(self.sample_html)
|
||||
self.assertEqual(expectedtext, result)
|
||||
@@ -12,9 +12,12 @@ class TokenRetriever(unittest.TestCase):
|
||||
"""
|
||||
def test_token(self):
|
||||
"""
|
||||
Test for the token generator. Give an a random username and secret token, it should create the properly encoded string of text.
|
||||
Test for the token generator. Give an a random username and secret token,
|
||||
it should create the properly encoded string of text.
|
||||
"""
|
||||
expected = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3N1ZWRBdCI6ICIyMDE0LTAyLTI3VDE3OjAwOjQyLjQwNjQ0MSswOjAwIiwgImNvbnN1bWVyS2V5IjogImZha2Vfc2VjcmV0IiwgInVzZXJJZCI6ICJ1c2VybmFtZSIsICJ0dGwiOiA4NjQwMH0.Dx1PoF-7mqBOOSGDMZ9R_s3oaaLRPnn6CJgGGF2A5CQ"
|
||||
response = retrieve_token("username", "fake_secret")
|
||||
|
||||
# because the middle hashes are dependent on time, conly the header and footer are checked for secret key
|
||||
self.assertEqual(expected.split('.')[0], response.split('.')[0])
|
||||
self.assertNotEqual(expected.split('.')[2], response.split('.')[2])
|
||||
self.assertNotEqual(expected.split('.')[2], response.split('.')[2])
|
||||
|
||||
78
common/lib/xmodule/xmodule/tests/test_imageannotation.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# -*- 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=protected-access
|
||||
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=protected-access
|
||||
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)
|
||||
@@ -66,6 +66,6 @@ class VideoAnnotationModuleTestCase(unittest.TestCase):
|
||||
"""
|
||||
Tests to make sure variables passed in truly exist within the html once it is all rendered.
|
||||
"""
|
||||
context = self.mod.get_html() # pylint: disable=W0212
|
||||
context = self.mod.get_html()
|
||||
for key in ['display_name', 'instructions_html', 'sourceUrl', 'typeSource', 'poster', 'annotation_storage']:
|
||||
self.assertIn(key, context)
|
||||
|
||||
@@ -6,6 +6,7 @@ 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
|
||||
from xmodule.annotator_token import retrieve_token
|
||||
|
||||
import textwrap
|
||||
@@ -70,12 +71,7 @@ class TextAnnotationModule(AnnotatableFields, XModule):
|
||||
|
||||
def _extract_instructions(self, xmltree):
|
||||
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
|
||||
instructions = xmltree.find('instructions')
|
||||
if instructions is not None:
|
||||
instructions.tag = 'div'
|
||||
xmltree.remove(instructions)
|
||||
return etree.tostring(instructions, encoding='unicode')
|
||||
return None
|
||||
return get_instructions(xmltree)
|
||||
|
||||
def get_html(self):
|
||||
""" Renders parameters to template. """
|
||||
|
||||
@@ -7,6 +7,7 @@ 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, get_extension
|
||||
from xmodule.annotator_token import retrieve_token
|
||||
|
||||
import textwrap
|
||||
@@ -65,24 +66,11 @@ class VideoAnnotationModule(AnnotatableFields, XModule):
|
||||
|
||||
def _extract_instructions(self, xmltree):
|
||||
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
|
||||
instructions = xmltree.find('instructions')
|
||||
if instructions is not None:
|
||||
instructions.tag = 'div'
|
||||
xmltree.remove(instructions)
|
||||
return etree.tostring(instructions, encoding='unicode')
|
||||
return None
|
||||
return get_instructions(xmltree)
|
||||
|
||||
def _get_extension(self, srcurl):
|
||||
def _get_extension(self, src_url):
|
||||
''' get the extension of a given url '''
|
||||
if 'youtu' in srcurl:
|
||||
return 'video/youtube'
|
||||
else:
|
||||
spliturl = srcurl.split(".")
|
||||
extensionplus1 = spliturl[len(spliturl) - 1]
|
||||
spliturl = extensionplus1.split("?")
|
||||
extensionplus2 = spliturl[0]
|
||||
spliturl = extensionplus2.split("#")
|
||||
return 'video/' + spliturl[0]
|
||||
return get_extension(src_url)
|
||||
|
||||
def get_html(self):
|
||||
""" Renders parameters to template. """
|
||||
|
||||
@@ -16,10 +16,22 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.annotator-wrapper .mce-container {
|
||||
z-index:3000000000!important; /*To fix full-screen problems*/
|
||||
.mce-container-body {
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
.iframe[id="annotator-field"] {
|
||||
width: inherit;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
.mce-floatpanel {
|
||||
z-index: 700000000!important;
|
||||
}
|
||||
|
||||
div.mce-tinymce.mce-container.mce-panel {
|
||||
min-width:400px;
|
||||
}
|
||||
|
||||
/* Some change in the design of Annotator */
|
||||
.annotator-editor .annotator-widget{
|
||||
@@ -30,4 +42,4 @@
|
||||
.mce-ico.mce-i-rubric{
|
||||
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;
|
||||
}
|
||||
}
|
||||
832
common/static/js/vendor/ova/OpenSeaDragonAnnotation.js
vendored
Normal file
@@ -0,0 +1,832 @@
|
||||
/*
|
||||
OpenSeaDragonAnnotation v1.0 (http://)
|
||||
Copyright (C) 2014 CHS (Harvard University), Daniel Cebrián Robles and Phil Desenne
|
||||
License: https://github.com/CtrHellenicStudies/OpenSeaDragonAnnotation/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.
|
||||
*/
|
||||
(function($) {
|
||||
$.Viewer.prototype.annotation = function(options) {
|
||||
//-- wait for plugins --//
|
||||
var wrapper = jQuery('.annotator-wrapper').parent()[0],
|
||||
annotator = jQuery.data(wrapper, 'annotator'),
|
||||
self = this,
|
||||
isOpenViewer = false;
|
||||
|
||||
this.addHandler("open", function() {
|
||||
isOpenViewer = true;
|
||||
if (typeof self.annotationInstance!='undefined')
|
||||
self.annotationInstance.refreshDisplay();
|
||||
});
|
||||
|
||||
|
||||
annotator
|
||||
//-- Finished the Annotator DOM
|
||||
.subscribe("annotationsLoaded", function (annotations){
|
||||
if (!self.annotationInstance) {
|
||||
self.annotationInstance = new $._annotation({
|
||||
viewer: self,
|
||||
annotator: annotator,
|
||||
});
|
||||
annotator.osda = self.annotationInstance;
|
||||
//Wait until viewer is opened
|
||||
function refreshDisplay(){
|
||||
if(!isOpenViewer){
|
||||
setTimeout(refreshDisplay,200);
|
||||
}else{
|
||||
self.annotationInstance.refreshDisplay();
|
||||
}
|
||||
}
|
||||
refreshDisplay();
|
||||
} else {
|
||||
self.annotationInstance.refreshDisplay();
|
||||
}
|
||||
});
|
||||
};
|
||||
// INIT annotation
|
||||
$._annotation = function(options) {
|
||||
//options
|
||||
options = options || {};
|
||||
if (!options.viewer) {
|
||||
throw new Error("A viewer must be specified.");
|
||||
}
|
||||
|
||||
//variables
|
||||
this.viewer = options.viewer;
|
||||
this.annotator = options.annotator;
|
||||
this.options = options;
|
||||
this.isAnnotating = false; //If the user is annotating
|
||||
this.isDrawing = false; //if the user is drawing something
|
||||
this.rectPosition = undefined;
|
||||
|
||||
//Init
|
||||
this.init();
|
||||
};
|
||||
|
||||
//-- Methods
|
||||
$._annotation.prototype = {
|
||||
init: function(){
|
||||
var viewer = this.viewer;
|
||||
|
||||
//create Buttons
|
||||
this._createNewButton();
|
||||
|
||||
/* canvas Events */
|
||||
//- Bind canvas functions
|
||||
var onCanvasMouseDown = this.__bind(this._onCanvasMouseDown,this);
|
||||
var onCanvasMouseMove = this.__bind(this._onCanvasMouseMove,this);
|
||||
var onDocumentMouseUp = this.__bind(this._onDocumentMouseUp,this);
|
||||
|
||||
//- Add canvas events
|
||||
$.addEvent(viewer.canvas, "mousedown", onCanvasMouseDown, true);
|
||||
$.addEvent(viewer.canvas, "mousemove", onCanvasMouseMove, true);
|
||||
$.addEvent(document, "mouseup", onDocumentMouseUp, true);
|
||||
|
||||
//Viewer events
|
||||
var self = this;
|
||||
},
|
||||
newAnnotation:function(){
|
||||
var annotator = this.annotator;
|
||||
|
||||
//This variable is to say the editor that we want create an image annotation
|
||||
annotator.editor.OpenSeaDragon = this.viewer.id;
|
||||
|
||||
annotator.adder.show();
|
||||
|
||||
this._setOverShape(annotator.adder);
|
||||
|
||||
//Open a new annotator dialog
|
||||
annotator.onAdderClick();
|
||||
},
|
||||
editAnnotation: function(annotation,editor){
|
||||
//This will be usefull when we are going to edit an annotation.
|
||||
if (this._isOpenSeaDragon(annotation)){
|
||||
//this.hideDisplay();
|
||||
var editor = editor || this.annotator.editor;
|
||||
|
||||
//set the editor over the range slider
|
||||
this._setOverShape(editor.element);
|
||||
editor.checkOrientation();
|
||||
|
||||
//This variable is to say the editor that we want create an image annotation
|
||||
editor.OpenSeaDragon = this.viewer.id;
|
||||
}
|
||||
},
|
||||
refreshDisplay: function(){
|
||||
var allannotations = this.annotator.plugins['Store'].annotations;
|
||||
var annotator = this.annotator;
|
||||
|
||||
//Sort by date the Array
|
||||
this._sortByDate(allannotations);
|
||||
|
||||
//remove all the overlays
|
||||
this.viewer.drawer.clearOverlays();
|
||||
|
||||
for (var item in allannotations) {
|
||||
var an = allannotations[item];
|
||||
|
||||
//check if the annotation is an OpenSeaDragon annotation
|
||||
if (this._isOpenSeaDragon(an))
|
||||
this.drawRect(an);
|
||||
annotator.publish('colorizeHighlight', [an]);
|
||||
};
|
||||
},
|
||||
modeAnnotation:function(e){
|
||||
this._reset();
|
||||
var viewer = this.viewer;
|
||||
if (!this.isAnnotating){
|
||||
jQuery('.openseadragon1').css('cursor', 'crosshair');
|
||||
jQuery('.openseadragon1').css('border', '2px solid rgb(51,204,102)');
|
||||
e.eventSource.imgGroup.src = this.resolveUrl( viewer.prefixUrl,"newan_hover.png");
|
||||
e.eventSource.imgRest.src = this.resolveUrl( viewer.prefixUrl,"newan_hover.png");
|
||||
e.eventSource.imgHover.src = this.resolveUrl( viewer.prefixUrl,"newan_grouphover.png");
|
||||
}else{
|
||||
jQuery('.openseadragon1').css('cursor', 'all-scroll');
|
||||
jQuery('.openseadragon1').css('border', 'inherit');
|
||||
e.eventSource.imgGroup.src = this.resolveUrl( viewer.prefixUrl,"newan_grouphover.png");
|
||||
e.eventSource.imgRest.src = this.resolveUrl( viewer.prefixUrl,"newan_rest.png");
|
||||
e.eventSource.imgHover.src = this.resolveUrl( viewer.prefixUrl,"newan_hover.png");
|
||||
}
|
||||
this.isAnnotating = !this.isAnnotating?true:false;
|
||||
},
|
||||
drawRect:function(an){
|
||||
if (typeof an.rangePosition!='undefined'){
|
||||
var span = document.createElement('span');
|
||||
var rectPosition = an.rangePosition;
|
||||
//Span
|
||||
span.className = "annotator-hl";
|
||||
span.style.border = '1px solid rgba(0,0,0,0.5)';
|
||||
var onAnnotationMouseMove = this.__bind(this._onAnnotationMouseMove,this);
|
||||
var onAnnotationClick = this.__bind(this._onAnnotationClick,this);
|
||||
$.addEvent(span, "mousemove", onAnnotationMouseMove, true);
|
||||
$.addEvent(span, "click", onAnnotationClick, true);
|
||||
|
||||
//Set the object in the div
|
||||
jQuery.data(span, 'annotation', an);
|
||||
//Add the highlights to the annotation
|
||||
an.highlights = jQuery(span);
|
||||
|
||||
var olRect = new OpenSeadragon.Rect(rectPosition.left, rectPosition.top, rectPosition.width, rectPosition.height);
|
||||
return this.viewer.drawer.addOverlay({
|
||||
element: span,
|
||||
location: olRect,
|
||||
placement: OpenSeadragon.OverlayPlacement.TOP_LEFT
|
||||
});
|
||||
}
|
||||
return false;
|
||||
},
|
||||
//Change object(this.rectPosition)the rectangle Position using div element(this.rect)
|
||||
setRectPosition:function(){
|
||||
var left = parseInt(this.rect.style.left);
|
||||
var top = parseInt(this.rect.style.top);
|
||||
var width = parseInt(this.rect.style.left)+parseInt(this.rect.style.width);
|
||||
var height = parseInt(this.rect.style.top)+parseInt(this.rect.style.height);
|
||||
var startPoint = new $.Point(left,top);
|
||||
var endPoint = new $.Point(width,height);
|
||||
this.rectPosition = {left:this._physicalToLogicalXY(startPoint).x,
|
||||
top:this._physicalToLogicalXY(startPoint).y,
|
||||
width:this._physicalToLogicalXY(endPoint).x-this._physicalToLogicalXY(startPoint).x,
|
||||
height:this._physicalToLogicalXY(endPoint).y-this._physicalToLogicalXY(startPoint).y
|
||||
};
|
||||
},
|
||||
/* Handlers */
|
||||
_onCanvasMouseDown: function(event,seft) {
|
||||
if (this.isAnnotating){
|
||||
var viewer = this.viewer;
|
||||
event.preventDefault();
|
||||
|
||||
//reset the display
|
||||
this._reset();
|
||||
|
||||
//set mode drawing
|
||||
this.isDrawing = true;
|
||||
|
||||
//Create rect element
|
||||
var mouse = $.getMousePosition( event );
|
||||
var elementPosition = $.getElementPosition(viewer.canvas);
|
||||
var position = mouse.minus( elementPosition );
|
||||
viewer.innerTracker.setTracking(false);
|
||||
this.rect = document.createElement('div');
|
||||
this.rect.style.background = 'rgba(0,0,0,0.25)';
|
||||
this.rect.style.border = '1px solid rgba(0,0,0,0.5)';
|
||||
this.rect.style.position = 'absolute';
|
||||
this.rect.className = 'DrawingRect';
|
||||
//set the initial position
|
||||
this.rect.style.top = position.y+"px";
|
||||
this.rect.style.left = position.x+"px";
|
||||
this.rect.style.width = "1px";
|
||||
this.rect.style.height = "1px";
|
||||
|
||||
//save the start Position
|
||||
this.startPosition = position;
|
||||
//save rectPosition as initial rectangle parameter to Draw in the canvas
|
||||
this.setRectPosition();
|
||||
|
||||
//append Child to the canvas
|
||||
viewer.canvas.appendChild(this.rect);
|
||||
}
|
||||
},
|
||||
_onCanvasMouseMove: function(event) {
|
||||
if (this.isAnnotating && this.isDrawing){
|
||||
var viewer = this.viewer;
|
||||
|
||||
//Calculate the new end position
|
||||
var mouse = $.getMousePosition( event );
|
||||
var elementPosition = $.getElementPosition(viewer.canvas);
|
||||
var endPosition = mouse.minus( elementPosition );
|
||||
//retrieve start position
|
||||
var startPosition = this.startPosition;
|
||||
|
||||
var newWidth= endPosition.x-startPosition.x;
|
||||
var newHeight =endPosition.y-startPosition.y;
|
||||
|
||||
//Set new position
|
||||
this.rect.style.width = (newWidth<0) ? (-1*newWidth) +'px' : newWidth +'px';
|
||||
this.rect.style.left = (newWidth<0) ? (startPosition.x + newWidth) +'px' : startPosition.x +'px';
|
||||
this.rect.style.height = (newHeight<0) ? (-1*newHeight) +'px' : newHeight +'px';
|
||||
this.rect.style.top = (newHeight<0) ? (startPosition.y + newHeight) +'px' : startPosition.y +'px';
|
||||
|
||||
//Modify the rectPosition with the new this.rect values
|
||||
this.setRectPosition();
|
||||
|
||||
//Show adder and hide editor
|
||||
this.annotator.editor.element[0].style.display = 'none';
|
||||
this._setOverShape(this.annotator.adder);
|
||||
}
|
||||
},
|
||||
_onDocumentMouseUp: function() {
|
||||
if (this.isAnnotating && this.isDrawing){
|
||||
var viewer = this.viewer;
|
||||
|
||||
viewer.innerTracker.setTracking(true);
|
||||
this.isDrawing = false;
|
||||
|
||||
//Set the new position for the rectangle
|
||||
this.setRectPosition();
|
||||
|
||||
//Open Annotator editor
|
||||
this.newAnnotation();
|
||||
|
||||
//Hide adder and show editor
|
||||
this.annotator.editor.element[0].style.display = 'block';
|
||||
this._setOverShape(this.annotator.editor.element);
|
||||
this.annotator.editor.checkOrientation();
|
||||
}
|
||||
},
|
||||
_onAnnotationMouseMove: function(event){
|
||||
var annotator = this.annotator;
|
||||
var elem = jQuery(event.target).parents('.annotator-hl').andSelf();
|
||||
//if there is a opened annotation then show the new annotation mouse over
|
||||
if (typeof annotator!='undefined' && elem.hasClass("annotator-hl") && !this.isDrawing){
|
||||
//hide the last open viewer
|
||||
annotator.viewer.hide();
|
||||
//get the annotation over the mouse
|
||||
var annotations = jQuery(event.target.parentNode).find('.annotator-hl').map(function() {
|
||||
var self = jQuery(this);
|
||||
var offset = self.offset();
|
||||
var l = offset.left;
|
||||
var t = offset.top;
|
||||
var h = self.height();
|
||||
var w = self.width();
|
||||
var x = $.getMousePosition(event).x;
|
||||
var y = $.getMousePosition(event).y;
|
||||
|
||||
var maxx = l + w;
|
||||
var maxy = t + h;
|
||||
this.style.background = (y <= maxy && y >= t) && (x <= maxx && x >= l)?
|
||||
'rgba(12, 150, 0, 0.3)':'rgba(255, 255, 10, 0.3)';
|
||||
return (y <= maxy && y >= t) && (x <= maxx && x >= l)? jQuery(this).data("annotation") : null;
|
||||
});
|
||||
//show the annotation in the viewer
|
||||
var mousePosition = {
|
||||
top:$.getMousePosition(event).y,
|
||||
left:$.getMousePosition(event).x,
|
||||
};
|
||||
if (annotations.length>0) annotator.showViewer(jQuery.makeArray(annotations), mousePosition);
|
||||
}
|
||||
},
|
||||
_onAnnotationClick: function(event){
|
||||
var an = jQuery.data(event.target, 'annotation');
|
||||
var bounds = typeof an.bounds!='undefined'?an.bounds:{};
|
||||
var currentBounds = this.viewer.drawer.viewport.getBounds();
|
||||
if (typeof bounds.x!='undefined') currentBounds.x = bounds.x;
|
||||
if (typeof bounds.y!='undefined') currentBounds.y = bounds.y;
|
||||
if (typeof bounds.width!='undefined') currentBounds.width = bounds.width;
|
||||
if (typeof bounds.height!='undefined') currentBounds.height = bounds.height;
|
||||
//change the zoom to the saved
|
||||
this.viewer.drawer.viewport.fitBounds(currentBounds);
|
||||
},
|
||||
_onAnnotationMouseOut: function(event){
|
||||
var annotator = this.annotator;
|
||||
var elem = jQuery(event.target).parents('.annotator-hl').andSelf();
|
||||
//if there is a opened annotation then show the new annotation mouse over
|
||||
if (typeof annotator!='undefined' && elem.hasClass("annotator-hl") && !this.isDrawing){
|
||||
/*jQuery(event.target.parentNode).find('.annotator-hl').map(function() {
|
||||
return this.style.background = 'rgba(255, 255, 10, 0.3)';
|
||||
});*/
|
||||
}
|
||||
},
|
||||
/* Utilities */
|
||||
_sortByDate: function (annotations,type){
|
||||
var type = type || 'asc'; //asc => The value [0] will be the most recent date
|
||||
annotations.sort(function(a,b){
|
||||
a = new Date(typeof a.updated!='undefined'?createDateFromISO8601(a.updated):'');
|
||||
b = new Date(typeof b.updated!='undefined'?createDateFromISO8601(b.updated):'');
|
||||
if (type == 'asc')
|
||||
return b<a?-1:b>a?1:0;
|
||||
else
|
||||
return a<b?-1:a>b?1:0;
|
||||
});
|
||||
},
|
||||
_createNewButton:function(){
|
||||
var viewer = this.viewer;
|
||||
var onFocusHandler = $.delegate( this, onFocus );
|
||||
var onBlurHandler = $.delegate( this, onBlur );
|
||||
var onModeAnnotationHandler = $.delegate( this, this.modeAnnotation );
|
||||
/* Buttons */
|
||||
var viewer = this.viewer;
|
||||
var self = this;
|
||||
viewer.modeAnnotation = new $.Button({
|
||||
element: viewer.modeAnnotation ? $.getElement( viewer.modeAnnotation ) : null,
|
||||
clickTimeThreshold: viewer.clickTimeThreshold,
|
||||
clickDistThreshold: viewer.clickDistThreshold,
|
||||
tooltip: "New Annotation",
|
||||
srcRest: self.resolveUrl( viewer.prefixUrl,"newan_rest.png"),
|
||||
srcGroup: self.resolveUrl( viewer.prefixUrl,"newan_grouphover.png"),
|
||||
srcHover: self.resolveUrl( viewer.prefixUrl,"newan_hover.png"),
|
||||
srcDown: self.resolveUrl( viewer.prefixUrl,"newan_pressed.png"),
|
||||
onRelease: onModeAnnotationHandler,
|
||||
onFocus: onFocusHandler,
|
||||
onBlur: onBlurHandler
|
||||
});
|
||||
|
||||
//- Wrapper Annotation Menu
|
||||
viewer.wrapperAnnotation = new $.ButtonGroup({
|
||||
buttons: [
|
||||
viewer.modeAnnotation,
|
||||
],
|
||||
clickTimeThreshold: viewer.clickTimeThreshold,
|
||||
clickDistThreshold: viewer.clickDistThreshold
|
||||
});
|
||||
|
||||
/* Set elements to the control menu */
|
||||
viewer.annotatorControl = viewer.wrapperAnnotation.element;
|
||||
if( viewer.toolbar ){
|
||||
viewer.toolbar.addControl(
|
||||
viewer.annotatorControl,
|
||||
{anchor: $.ControlAnchor.BOTTOM_RIGHT}
|
||||
);
|
||||
}else{
|
||||
viewer.addControl(
|
||||
viewer.annotatorControl,
|
||||
{anchor: $.ControlAnchor.TOP_LEFT}
|
||||
);
|
||||
}
|
||||
},
|
||||
_reset: function(){
|
||||
//Find and remove DrawingRect. This is the previous rectangle
|
||||
this._removeElemsByClass('DrawingRect',this.viewer.canvas);
|
||||
//Show adder and hide editor
|
||||
this.annotator.editor.element[0].style.display = 'none';
|
||||
},
|
||||
__bind: function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
// Remove all the elements with a given name inside "inElement"
|
||||
_removeElemsByClass: function(className,inElement){
|
||||
var className = className || '';
|
||||
var inElement = inElement || {};
|
||||
divs = inElement.getElementsByClassName(className);
|
||||
for(var i = 0; i < divs.length; i++) {
|
||||
divs[i].remove();
|
||||
}
|
||||
},
|
||||
//Detect if the annotation is an image annotation
|
||||
_isOpenSeaDragon: function (an){
|
||||
var annotator = this.annotator;
|
||||
var rp = an.rangePosition;
|
||||
var isOpenSeaDragon = (typeof annotator.osda != 'undefined');
|
||||
var isContainer = (typeof an.target!='undefined' && an.target.container==this.viewer.id );
|
||||
var isImage = (typeof an.media!='undefined' && an.media=='image');
|
||||
var isRP = (typeof rp!='undefined');
|
||||
var isSource = false;
|
||||
//Save source url
|
||||
var source = this.viewer.source;
|
||||
var tilesUrl = typeof source.tilesUrl!='undefined'?source.tilesUrl:'';
|
||||
var functionUrl = typeof source.getTileUrl!='undefined'?source.getTileUrl:'';
|
||||
var compareUrl = tilesUrl!=''?tilesUrl:(''+functionUrl).replace(/\s+/g, ' ');
|
||||
if(isContainer) isSource = (an.target.src == compareUrl);
|
||||
return (isOpenSeaDragon && isContainer && isImage && isRP && isSource);
|
||||
},
|
||||
/* Annotator Utilities */
|
||||
_setOverShape: function(elem){
|
||||
//Calculate Point absolute positions
|
||||
var rectPosition = this.rectPosition || {};
|
||||
var startPoint = this._logicalToPhysicalXY(new $.Point(rectPosition.left,rectPosition.top));
|
||||
var endPoint = this._logicalToPhysicalXY(new $.Point(rectPosition.left+rectPosition.width,rectPosition.top+rectPosition.height));
|
||||
|
||||
//Calculate Point absolute positions
|
||||
var wrapper = jQuery('.annotator-wrapper')[0];
|
||||
var positionAnnotator = $.getElementPosition(wrapper);
|
||||
var positionCanvas = $.getElementPosition(this.viewer.canvas);
|
||||
var positionAdder = {};
|
||||
|
||||
//Fix with positionCanvas
|
||||
startPoint = startPoint.plus(positionCanvas);
|
||||
endPoint = endPoint.plus(positionCanvas);
|
||||
|
||||
elem[0].style.display = 'block'; //Show the adder
|
||||
|
||||
positionAdder.left = (startPoint.x - positionAnnotator.x) + (endPoint.x - startPoint.x) / 2;
|
||||
positionAdder.top = (startPoint.y - positionAnnotator.y) + (endPoint.y - startPoint.y) / 2; //It is not necessary fix with - positionAnnotator.y
|
||||
elem.css(positionAdder);
|
||||
},
|
||||
resolveUrl: function( prefix, url ) {
|
||||
return prefix ? prefix + url : url;
|
||||
},
|
||||
/* Canvas Utilities */
|
||||
// return a point with the values in percentage related to the Image
|
||||
// point is an object $.Point with the value of the canvas relative coordenates
|
||||
_physicalToLogicalXY: function(point){
|
||||
var point = typeof point!='undefined'?point:{};
|
||||
var boundX = this.viewer.viewport.getBounds(true).x;
|
||||
var boundY = this.viewer.viewport.getBounds(true).y;
|
||||
var boundWidth = this.viewer.viewport.getBounds(true).width;
|
||||
var boundHeight = this.viewer.viewport.getBounds(true).height;
|
||||
var containerSizeX = this.viewer.viewport.getContainerSize().x;
|
||||
var containerSizeY = this.viewer.viewport.getContainerSize().y;
|
||||
var x = typeof point.x!='undefined'?point.x:0;
|
||||
var y = typeof point.y!='undefined'?point.y:0;
|
||||
x = boundX + ((x / containerSizeX) * boundWidth);
|
||||
y = boundY + ((y / containerSizeY) * boundHeight);
|
||||
return new $.Point(x,y);
|
||||
},
|
||||
// return a point with the values in pixels related to the canvas element
|
||||
// point is an object $.Point with the value of the Image relative percentage
|
||||
_logicalToPhysicalXY: function(point){
|
||||
var point = typeof point!='undefined'?point:{};
|
||||
var boundX = this.viewer.viewport.getBounds(true).x;
|
||||
var boundY = this.viewer.viewport.getBounds(true).y;
|
||||
var boundWidth = this.viewer.viewport.getBounds(true).width;
|
||||
var boundHeight = this.viewer.viewport.getBounds(true).height;
|
||||
var containerSizeX = this.viewer.viewport.getContainerSize().x;
|
||||
var containerSizeY = this.viewer.viewport.getContainerSize().y;
|
||||
var x = typeof point.x!='undefined'?point.x:0;
|
||||
var y = typeof point.y!='undefined'?point.y:0;
|
||||
x = (x - boundX) * containerSizeX / boundWidth;
|
||||
y = (y - boundY) * containerSizeY / boundHeight;
|
||||
return new $.Point(x,y);
|
||||
},
|
||||
}
|
||||
|
||||
/* General functions */
|
||||
//initiates an animation to hide the controls
|
||||
function beginControlsAutoHide( viewer ) {
|
||||
if ( !viewer.autoHideControls ) {
|
||||
return;
|
||||
}
|
||||
viewer.controlsShouldFade = true;
|
||||
viewer.controlsFadeBeginTime =
|
||||
$.now() +
|
||||
viewer.controlsFadeDelay;
|
||||
|
||||
window.setTimeout( function(){
|
||||
scheduleControlsFade( viewer );
|
||||
}, viewer.controlsFadeDelay );
|
||||
}
|
||||
//stop the fade animation on the controls and show them
|
||||
function abortControlsAutoHide( viewer ) {
|
||||
var i;
|
||||
viewer.controlsShouldFade = false;
|
||||
for ( i = viewer.controls.length - 1; i >= 0; i-- ) {
|
||||
viewer.controls[ i ].setOpacity( 1.0 );
|
||||
}
|
||||
}
|
||||
function onFocus(){
|
||||
abortControlsAutoHide( this.viewer );
|
||||
}
|
||||
|
||||
function onBlur(){
|
||||
beginControlsAutoHide( this.viewer );
|
||||
}
|
||||
|
||||
|
||||
})(OpenSeadragon);
|
||||
|
||||
|
||||
|
||||
//----------------Plugin for Annotator to setup OpenSeaDragon----------------//
|
||||
|
||||
Annotator.Plugin.OpenSeaDragon = (function(_super) {
|
||||
__extends(OpenSeaDragon, _super);
|
||||
|
||||
//constructor
|
||||
function OpenSeaDragon() {
|
||||
this.pluginSubmit = __bind(this.pluginSubmit, this);
|
||||
_ref = OpenSeaDragon.__super__.constructor.apply(this, arguments);
|
||||
this.__indexOf = [].indexOf;
|
||||
if(!this.__indexOf){
|
||||
this.__indexOf = function(item) {
|
||||
for (var i = 0, l = this.length; i < l; i++) {
|
||||
if (i in this && this[i] === item)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
return _ref;
|
||||
}
|
||||
|
||||
OpenSeaDragon.prototype.field = null;
|
||||
OpenSeaDragon.prototype.input = null;
|
||||
|
||||
OpenSeaDragon.prototype.pluginInit = function() {
|
||||
//Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Editor
|
||||
this.field = this.annotator.editor.addField({
|
||||
id: 'osd-input-rangePosition-annotations',
|
||||
type: 'input', //options (textarea,input,select,checkbox)
|
||||
submit: this.pluginSubmit,
|
||||
EditOpenSeaDragonAn: this.EditOpenSeaDragonAn
|
||||
});
|
||||
|
||||
//Modify the element created with annotator to be an invisible span
|
||||
var select = '<li><span id="osd-input-rangePosition-annotations"></span></li>';
|
||||
var newfield = Annotator.$(select);
|
||||
Annotator.$(this.field).replaceWith(newfield);
|
||||
this.field=newfield[0];
|
||||
|
||||
//-- Listener for OpenSeaDragon Plugin
|
||||
this.initListeners();
|
||||
|
||||
return this.input = $(this.field).find(':input');
|
||||
}
|
||||
|
||||
|
||||
|
||||
// New JSON for the database
|
||||
OpenSeaDragon.prototype.pluginSubmit = function(field, annotation) {
|
||||
//Select the new JSON for the Object to save
|
||||
if (this.EditOpenSeaDragonAn()){
|
||||
var annotator = this.annotator;
|
||||
var osda = annotator.osda;
|
||||
var position = osda.rectPosition;
|
||||
var isNew = typeof annotation.media=='undefined';
|
||||
if (typeof annotation.media == 'undefined') annotation.media = "image"; // - media
|
||||
annotation.target = annotation.target || {}; // - target
|
||||
annotation.target.container = osda.viewer.id || ""; // - target.container
|
||||
//Save source url
|
||||
var source = osda.viewer.source;
|
||||
var tilesUrl = typeof source.tilesUrl!='undefined'?source.tilesUrl:'';
|
||||
var functionUrl = typeof source.getTileUrl!='undefined'?source.getTileUrl:'';
|
||||
annotation.target.src = tilesUrl!=''?tilesUrl:(''+functionUrl).replace(/\s+/g, ' '); // - target.src (media source)
|
||||
annotation.target.ext = source.fileFormat || ""; // - target.ext (extension)
|
||||
annotation.bounds = osda.viewer.drawer.viewport.getBounds() || {}; // - bounds
|
||||
|
||||
var finalimagelink = source["@id"].replace("/info.json", "");
|
||||
var highlightX = Math.round(position.left * source["width"]);
|
||||
var highlightY = Math.round(position.top * source["width"]);
|
||||
var highlightWidth = Math.round(position.width * source["width"]);
|
||||
var highlightHeight = Math.round(position.height * source["width"]);
|
||||
annotation.target.thumb = finalimagelink + "/" + highlightX + "," + highlightY + "," + highlightWidth + "," + highlightHeight + "/full/0/native." + source["formats"][0];
|
||||
if(isNew) annotation.rangePosition = position || {}; // - rangePosition
|
||||
annotation.updated = new Date().toISOString(); // - updated
|
||||
if (typeof annotation.created == 'undefined')
|
||||
annotation.created = annotation.updated; // - created
|
||||
}else{
|
||||
if (typeof annotation.media == 'undefined')
|
||||
annotation.media = "text"; // - media
|
||||
annotation.updated = new Date().toISOString(); // - updated
|
||||
if (typeof annotation.created == 'undefined')
|
||||
annotation.created = annotation.updated; // - created
|
||||
}
|
||||
return annotation.media;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------ Methods ------//
|
||||
//Detect if we are creating or editing an OpenSeaDragon annotation
|
||||
OpenSeaDragon.prototype.EditOpenSeaDragonAn = function (){
|
||||
var wrapper = $('.annotator-wrapper').parent()[0],
|
||||
annotator = window.annotator = $.data(wrapper, 'annotator'),
|
||||
isOpenSeaDragon = (typeof annotator.osda != 'undefined'),
|
||||
OpenSeaDragon = annotator.editor.OpenSeaDragon;
|
||||
return (isOpenSeaDragon && typeof OpenSeaDragon!='undefined' && OpenSeaDragon!==-1);
|
||||
};
|
||||
|
||||
//Detect if the annotation is an OpenSeaDragon annotation
|
||||
OpenSeaDragon.prototype.isOpenSeaDragon = function (an){
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = window.annotator = $.data(wrapper, 'annotator');
|
||||
var rp = an.rangePosition;
|
||||
var isOpenSeaDragon = (typeof annotator.osda != 'undefined');
|
||||
var isContainer = (typeof an.target!='undefined' && an.target.container==annotator.osda.viewer.id );
|
||||
var isImage = (typeof an.media!='undefined' && an.media=='image');
|
||||
var isRP = (typeof rp!='undefined');
|
||||
var isSource = false;
|
||||
//Save source url
|
||||
var source = annotator.osda.viewer.source;
|
||||
var tilesUrl = typeof source.tilesUrl!='undefined'?source.tilesUrl:'';
|
||||
var functionUrl = typeof source.getTileUrl!='undefined'?source.getTileUrl:'';
|
||||
var compareUrl = tilesUrl!=''?tilesUrl:(''+functionUrl).replace(/\s+/g, ' ');
|
||||
if(isContainer) isSource = (an.target.src == compareUrl);
|
||||
return (isOpenSeaDragon && isContainer && isImage && isRP && isSource);
|
||||
};
|
||||
|
||||
//Delete OpenSeaDragon Annotation
|
||||
OpenSeaDragon.prototype._deleteAnnotation = function(an){
|
||||
//Remove the annotation of the plugin Store
|
||||
var annotations = this.annotator.plugins['Store'].annotations;
|
||||
if (annotations.indexOf(an)>-1)
|
||||
annotations.splice(annotations.indexOf(an), 1);
|
||||
//Refresh the annotations in the display
|
||||
this.annotator.osda.refreshDisplay();
|
||||
};
|
||||
|
||||
|
||||
//--Listeners
|
||||
OpenSeaDragon.prototype.initListeners = function (){
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = $.data(wrapper, 'annotator');
|
||||
var EditOpenSeaDragonAn = this.EditOpenSeaDragonAn;
|
||||
var isOpenSeaDragon = this.isOpenSeaDragon;
|
||||
var self = this;
|
||||
|
||||
//local functions
|
||||
//-- Editor
|
||||
function annotationEditorHidden(editor) {
|
||||
if (EditOpenSeaDragonAn()){
|
||||
annotator.osda._reset();
|
||||
annotator.osda.refreshDisplay(); //Reload the display of annotations
|
||||
}
|
||||
annotator.editor.OpenSeaDragon=-1;
|
||||
annotator.unsubscribe("annotationEditorHidden", annotationEditorHidden);
|
||||
};
|
||||
function annotationEditorShown(editor,annotation) {
|
||||
annotator.osda.editAnnotation(annotation,editor);
|
||||
annotator.subscribe("annotationEditorHidden", annotationEditorHidden);
|
||||
};
|
||||
//-- Annotations
|
||||
function annotationDeleted(annotation) {
|
||||
if (isOpenSeaDragon(annotation))
|
||||
self._deleteAnnotation(annotation);
|
||||
};
|
||||
//-- Viewer
|
||||
function hideViewer(){
|
||||
jQuery(annotator.osda.viewer.canvas.parentNode).find('.annotator-hl').map(function() {
|
||||
return this.style.background = 'rgba(255, 255, 10, 0.3)';
|
||||
});
|
||||
annotator.viewer.unsubscribe("hide", hideViewer);
|
||||
};
|
||||
function annotationViewerShown(viewer,annotations) {
|
||||
var wrapper = jQuery('.annotator-wrapper').offset();
|
||||
|
||||
//Fix with positionCanvas
|
||||
var startPoint = {x: parseFloat(viewer.element[0].style.left),
|
||||
y: parseFloat(viewer.element[0].style.top)};
|
||||
|
||||
var separation = viewer.element.hasClass(viewer.classes.invert.y)?5:-5,
|
||||
newpos = {
|
||||
top: (startPoint.y - wrapper.top)+separation,
|
||||
left: (startPoint.x - wrapper.left)
|
||||
};
|
||||
viewer.element.css(newpos);
|
||||
|
||||
//Remove the time to wait until disapear, to be more faster that annotator by default
|
||||
viewer.element.find('.annotator-controls').removeClass(viewer.classes.showControls);
|
||||
|
||||
annotator.viewer.subscribe("hide", hideViewer);
|
||||
};
|
||||
//subscribe to Annotator
|
||||
annotator.subscribe("annotationEditorShown", annotationEditorShown)
|
||||
.subscribe("annotationDeleted", annotationDeleted)
|
||||
.subscribe("annotationViewerShown", annotationViewerShown);
|
||||
}
|
||||
|
||||
return OpenSeaDragon;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
|
||||
|
||||
//----------------PUBLIC OBJECT TO CONTROL THE ANNOTATIONS----------------//
|
||||
|
||||
//The name of the plugin that the user will write in the html
|
||||
OpenSeadragonAnnotation = ("OpenSeadragonAnnotation" in window) ? OpenSeadragonAnnotation : {};
|
||||
|
||||
OpenSeadragonAnnotation = function (element, options) {
|
||||
//local variables
|
||||
var $ = jQuery;
|
||||
var options = options || {};
|
||||
options.optionsOpenSeadragon = options.optionsOpenSeadragon || {};
|
||||
options.optionsOSDA = options.optionsOSDA || {};
|
||||
options.optionsAnnotator = options.optionsAnnotator || {};
|
||||
|
||||
//if there isn't store optinos it will create a uri and limit variables for the Back-end of Annotations
|
||||
if (typeof options.optionsAnnotator.store=='undefined')
|
||||
options.optionsAnnotator.store = {};
|
||||
var store = options.optionsAnnotator.store;
|
||||
if (typeof store.annotationData=='undefined')
|
||||
store.annotationData = {};
|
||||
if (typeof store.annotationData.uri=='undefined'){
|
||||
var uri = location.protocol + '//' + location.host + location.pathname;
|
||||
store.annotationData.store = {uri:uri};
|
||||
}
|
||||
if (typeof store.loadFromSearch=='undefined')
|
||||
store.loadFromSearch={};
|
||||
if (typeof store.loadFromSearch.uri=='undefined')
|
||||
store.loadFromSearch.uri = uri;
|
||||
if (typeof store.loadFromSearch.limit=='undefined')
|
||||
store.loadFromSearch.limit = 10000;
|
||||
|
||||
//global variables
|
||||
this.currentUser = null;
|
||||
|
||||
//-- Init all the classes --/
|
||||
//Annotator
|
||||
this.annotator = $(element).annotator(options.optionsAnnotator.annotator).data('annotator');
|
||||
|
||||
//-- Activate all the Annotator plugins --//
|
||||
if (typeof options.optionsAnnotator.auth!='undefined')
|
||||
this.annotator.addPlugin('Auth', options.optionsAnnotator.auth);
|
||||
|
||||
if (typeof options.optionsAnnotator.permissions!='undefined')
|
||||
this.annotator.addPlugin("Permissions", options.optionsAnnotator.permissions);
|
||||
|
||||
if (typeof options.optionsAnnotator.store!='undefined')
|
||||
this.annotator.addPlugin("Store", options.optionsAnnotator.store);
|
||||
|
||||
if (typeof Annotator.Plugin["Geolocation"] === 'function')
|
||||
this.annotator.addPlugin("Geolocation",options.optionsAnnotator.geolocation);
|
||||
|
||||
if (typeof Annotator.Plugin["Share"] === 'function')
|
||||
this.annotator.addPlugin("Share",options.optionsAnnotator.share);
|
||||
|
||||
if (typeof Annotator.Plugin["RichText"] === 'function')
|
||||
this.annotator.addPlugin("RichText",options.optionsAnnotator.richText);
|
||||
|
||||
if (typeof Annotator.Plugin["Reply"] === 'function')
|
||||
this.annotator.addPlugin("Reply");
|
||||
|
||||
if (typeof Annotator.Plugin["OpenSeaDragon"] === 'function')
|
||||
this.annotator.addPlugin("OpenSeaDragon");
|
||||
|
||||
if (typeof Annotator.Plugin["Flagging"] === 'function')
|
||||
this.annotator.addPlugin("Flagging");
|
||||
|
||||
if (typeof Annotator.Plugin["HighlightTags"] === 'function')
|
||||
this.annotator.addPlugin("HighlightTags", options.optionsAnnotator.highlightTags);
|
||||
|
||||
//- OpenSeaDragon
|
||||
this.viewer = OpenSeadragon(options.optionsOpenSeadragon);
|
||||
//- OpenSeaDragon Plugins
|
||||
this.viewer.annotation(options.optionsOSDA);
|
||||
|
||||
//Set annotator.editor.OpenSeaDragon by default
|
||||
this.annotator.editor.OpenSeaDragon=-1;
|
||||
|
||||
function reloadEditor(){
|
||||
tinymce.EditorManager.execCommand('mceRemoveEditor',true, "annotator-field-0");
|
||||
tinymce.EditorManager.execCommand('mceAddEditor',true, "annotator-field-0");
|
||||
}
|
||||
|
||||
var self = this;
|
||||
document.addEventListener("fullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
document.addEventListener("mozfullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
document.addEventListener("webkitfullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
document.addEventListener("msfullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
this.options = options;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
13
common/static/js/vendor/ova/catch/css/main.css
vendored
@@ -225,7 +225,14 @@
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#mainCatch .playMediaButton {
|
||||
#mainCatch .zoomToImageBounds {
|
||||
width: 20em;
|
||||
text-align:center;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#mainCatch .playMediaButton, #mainCatch .zoomToImageBounds {
|
||||
border-top: 2px solid #d3bd89;
|
||||
border-bottom: 2px solid #b3ad69;
|
||||
border-right: 2px solid #b3ad69;
|
||||
@@ -242,7 +249,7 @@
|
||||
border-radius: 24px;
|
||||
color: #000000;
|
||||
}
|
||||
#mainCatch .playMediaButton:hover {
|
||||
#mainCatch .playMediaButton:hover, #mainCatch .zoomToImageBounds:hover {
|
||||
border-top: 2px solid #d3bd89;
|
||||
border-bottom: 2px solid #b3ad69;
|
||||
border-right: 2px solid #b3ad69;
|
||||
@@ -250,7 +257,7 @@
|
||||
background: #f5c105;
|
||||
color: #080708;
|
||||
}
|
||||
#mainCatch .playMediaButton:active {
|
||||
#mainCatch .playMediaButton:active, #mainCatch .zoomToImageBounds:active {
|
||||
border-top: 2px solid #d3bd89;
|
||||
border-bottom: 2px solid #b3ad69;
|
||||
border-right: 2px solid #b3ad69;
|
||||
|
||||
197
common/static/js/vendor/ova/catch/js/catch.js
vendored
@@ -1,3 +1,22 @@
|
||||
/*
|
||||
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
|
||||
window.CatchAnnotation = ("CatchAnnotation" in window) ? CatchAnnotation : {};
|
||||
window.CatchSources = ("CatchSources" in window) ? CatchSources : {};
|
||||
@@ -76,13 +95,10 @@ annotationMediaSelector:
|
||||
'<li class="ui-state-default" media="video">'+
|
||||
'Video'+
|
||||
'</li>'+
|
||||
'li class="ui-state-default" media="image">'+
|
||||
'Image'+
|
||||
'</li>'+
|
||||
'</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
|
||||
annotationItem:
|
||||
@@ -162,7 +178,15 @@ annotationRow:
|
||||
|
||||
//Main->ContainerRow->DetailRow
|
||||
annotationDetail:
|
||||
'<div class="annotationDetail">'+
|
||||
'{{#if mediatypeforgrid.text}}'+
|
||||
'<div class="annotationDetail">'+
|
||||
'{{/if}}'+
|
||||
'{{#if mediatypeforgrid.video}}'+
|
||||
'<div class="annotationDetail videoAnnotationDetail">'+
|
||||
'{{/if}}'+
|
||||
'{{#if mediatypeforgrid.image}}'+
|
||||
'<div class="annotationDetail imageAnnotationDetail">'+
|
||||
'{{/if}}'+
|
||||
'<div class="detailHeader">'+
|
||||
'<span class="closeDetailIcon">'+
|
||||
'<img src="'+root+'closeIcon.png" alt="Hide Details" />'+
|
||||
@@ -181,77 +205,29 @@ annotationDetail:
|
||||
'{{/if}}'+
|
||||
'</div>'+
|
||||
|
||||
'{{#if mediatypeforgrid.text}}'+
|
||||
'<div class="quote">'+
|
||||
'<div style="text-align: center">'+
|
||||
'<div class="quoteItem">“</div><div class="quoteText">{{{ quote }}}</div><div class="quoteItem">”</div></div>'+
|
||||
'<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+
|
||||
'<span class="uri" style="display:none">{{{uri}}}</span>'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="body">'+
|
||||
'{{{ text }}}'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="controlReplies">'+
|
||||
'<div class="newReply" style="text-decoration:underline">Reply</div> '+
|
||||
'<div class="hideReplies" style="text-decoration:underline;display:{{#if hasReplies}}block{{else}}none{{/if}}">Show Replies</div> '+
|
||||
'{{#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}}'+
|
||||
|
||||
'<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>'+
|
||||
|
||||
'{{#if mediatypeforgrid.video}}'+
|
||||
'<div class="playMediaButton">'+
|
||||
'Play segment {{{ rangeTime.start }}} - {{{ rangeTime.end }}}'+
|
||||
'<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+
|
||||
'<span class="uri" style="display:none">{{{uri}}}</span>'+
|
||||
'<span class="container" style="display:none">{{{target.container}}}</span>'+
|
||||
'</div>'+
|
||||
|
||||
'{{/if}}'+
|
||||
'{{#if mediatypeforgrid.image}}'+
|
||||
'<div class="zoomToImageBounds">'+
|
||||
'<img src="{{{ thumbnailLink }}}">'+
|
||||
'<span class="idAnnotation" style="display:none">{{{ id }}}</span>'+
|
||||
'<span class="uri" style="display:none">{{{uri}}}</span>'+
|
||||
'</div>'+
|
||||
'{{/if}}'+
|
||||
'<div class="body">'+
|
||||
'{{{ text }}}'+
|
||||
'</div>'+
|
||||
@@ -282,10 +258,6 @@ videoAnnotationDetail:
|
||||
'{{/if}}'+
|
||||
|
||||
'<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="reply_button" src="'+root+'groups_icon.png" width="36" height="36" alt="Reply" title="Reply" idAnnotation="{{{ id }}}">'+
|
||||
//'<img class="share_button" src="'+root+'share_icon.png" width="36" height="36" alt="Share Annotation" title="Share Annotation"/>'+
|
||||
'</div>'+
|
||||
'</div>',
|
||||
};
|
||||
@@ -324,8 +296,8 @@ CatchAnnotation = function (element, options) {
|
||||
$( document ).ready(function() {
|
||||
self.init();
|
||||
self.refreshCatch(true);
|
||||
var moreBut = self.element.find('.annotationListButtons .moreButtonCatch');
|
||||
moreBut.hide();
|
||||
var moreBut = self.element.find('.annotationListButtons .moreButtonCatch');
|
||||
moreBut.hide();
|
||||
});
|
||||
|
||||
return this;
|
||||
@@ -343,7 +315,6 @@ CatchAnnotation.prototype = {
|
||||
"annotationReply",//Main->ContainerRow->Reply
|
||||
"annotationRow", //Main->ContainerRow->Row
|
||||
"annotationDetail",//Main->ContainerRow->DetailRow
|
||||
"videoAnnotationDetail"//Main->ContainerRow->DetailRow (Video)
|
||||
];
|
||||
//annotator
|
||||
var wrapper = $('.annotator-wrapper').parent()[0],
|
||||
@@ -400,7 +371,7 @@ CatchAnnotation.prototype = {
|
||||
evenOrOdd: index % 2 ? "odd" : "even",
|
||||
openOrClosed: "closed",
|
||||
annotationRow: self.TEMPLATES.annotationRow(item),
|
||||
annotationDetail: (mediaType === "video") ? self.TEMPLATES.videoAnnotationDetail(item):self.TEMPLATES.annotationDetail(item),
|
||||
annotationDetail: self.TEMPLATES.annotationDetail(item),
|
||||
});
|
||||
index++;
|
||||
annotationItems.push(html);
|
||||
@@ -441,18 +412,19 @@ CatchAnnotation.prototype = {
|
||||
el.off();
|
||||
|
||||
//Bind functions
|
||||
var openAnnotationItem = this.__bind(this._openAnnotationItem,this),
|
||||
closeAnnotationItem = this.__bind(this._closeAnnotationItem,this),
|
||||
onGeolocationClick = this.__bind(this._onGeolocationClick,this),
|
||||
onPlaySelectionClick = this.__bind(this._onPlaySelectionClick,this),
|
||||
onShareControlsClick = this.__bind(this._onShareControlsClick,this),
|
||||
onSelectionButtonClick = this.__bind(this._onSelectionButtonClick,this),
|
||||
onPublicPrivateButtonClick = this.__bind(this._onPublicPrivateButtonClick,this),
|
||||
onQuoteMediaButton = this.__bind(this._onQuoteMediaButton,this),
|
||||
onControlRepliesClick = this.__bind(this._onControlRepliesClick,this),
|
||||
onMoreButtonClick = this.__bind(this._onMoreButtonClick,this),
|
||||
var openAnnotationItem = this.__bind(this._openAnnotationItem, this),
|
||||
closeAnnotationItem = this.__bind(this._closeAnnotationItem, this),
|
||||
onGeolocationClick = this.__bind(this._onGeolocationClick, this),
|
||||
onPlaySelectionClick = this.__bind(this._onPlaySelectionClick, this),
|
||||
onShareControlsClick = this.__bind(this._onShareControlsClick, this),
|
||||
onSelectionButtonClick = this.__bind(this._onSelectionButtonClick, this),
|
||||
onPublicPrivateButtonClick = this.__bind(this._onPublicPrivateButtonClick, this),
|
||||
onQuoteMediaButton = this.__bind(this._onQuoteMediaButton, this),
|
||||
onControlRepliesClick = this.__bind(this._onControlRepliesClick, this),
|
||||
onMoreButtonClick = this.__bind(this._onMoreButtonClick, this),
|
||||
onSearchButtonClick = this.__bind(this._onSearchButtonClick, this),
|
||||
onDeleteReplyButtonClick = this.__bind(this._onDeleteReplyButtonClick,this);
|
||||
onDeleteReplyButtonClick = this.__bind(this._onDeleteReplyButtonClick, this),
|
||||
onZoomToImageBoundsButtonClick = this.__bind(this._onZoomToImageBoundsButtonClick, this);
|
||||
|
||||
//Open Button
|
||||
el.on("click", ".annotationItem .annotationRow", openAnnotationItem);
|
||||
@@ -472,6 +444,12 @@ CatchAnnotation.prototype = {
|
||||
//PlaySelection button
|
||||
el.on("click",".annotationItem .annotationDetail .quote", onQuoteMediaButton);
|
||||
}
|
||||
|
||||
//IMAGE
|
||||
if (this.options.media=='image') {
|
||||
//PlaySelection button
|
||||
el.on("click",".annotationItem .annotationDetail .zoomToImageBounds", onZoomToImageBoundsButtonClick);
|
||||
}
|
||||
|
||||
//controlReplies
|
||||
el.on("click",".annotationItem .controlReplies", onControlRepliesClick);
|
||||
@@ -493,16 +471,16 @@ CatchAnnotation.prototype = {
|
||||
changeMedia: function(media) {
|
||||
var media = media || 'text';
|
||||
this.options.media = media;
|
||||
this._refresh();
|
||||
this._refresh();
|
||||
this.refreshCatch(true);
|
||||
this.checkTotAnnotations();
|
||||
this.checkTotAnnotations();
|
||||
},
|
||||
changeUserId: function(userId) {
|
||||
var userId = userId || '';
|
||||
this.options.userId = userId;
|
||||
this._refresh();
|
||||
this.refreshCatch(true);
|
||||
this.checkTotAnnotations();
|
||||
this.checkTotAnnotations();
|
||||
},
|
||||
loadAnnotations: function() {
|
||||
var annotator = this.annotator,
|
||||
@@ -520,9 +498,9 @@ CatchAnnotation.prototype = {
|
||||
//annotator.plugins['Store'].loadAnnotationsFromSearch(loadFromSearch);
|
||||
|
||||
//Make sure to be openned all annotations for this pagination
|
||||
loadFromSearch.limit = this.options.pagination+loadedAn;
|
||||
loadFromSearch.offset = 0;
|
||||
annotator.plugins['Store'].loadAnnotationsFromSearch(loadFromSearch);
|
||||
loadFromSearch.limit = this.options.pagination+loadedAn;
|
||||
loadFromSearch.offset = 0;
|
||||
annotator.plugins['Store'].loadAnnotationsFromSearch(loadFromSearch);
|
||||
|
||||
//text loading annotations
|
||||
var moreBut = this.element.find('.annotationListButtons .moreButtonCatch');
|
||||
@@ -568,7 +546,6 @@ CatchAnnotation.prototype = {
|
||||
var moreBut = this.element.find('.annotationListButtons .moreButtonCatch');
|
||||
moreBut.html('More');
|
||||
|
||||
setTimeout();
|
||||
},
|
||||
|
||||
//
|
||||
@@ -598,7 +575,7 @@ CatchAnnotation.prototype = {
|
||||
setTimeout(function(){
|
||||
if (new_tot != tot){
|
||||
self.refreshCatch(true);
|
||||
self.checkTotAnnotations();
|
||||
self.checkTotAnnotations();
|
||||
}else{
|
||||
attempts++;
|
||||
ischanged();
|
||||
@@ -617,7 +594,7 @@ CatchAnnotation.prototype = {
|
||||
self.refreshCatch();
|
||||
if (typeof annotation.parent != 'undefined' && annotation.parent != '0'){
|
||||
var replies = $("[annotationid="+annotation.parent+"]").find(".controlReplies .hideReplies");
|
||||
replies.show();
|
||||
replies.show();
|
||||
replies.click();
|
||||
replies.click();
|
||||
}
|
||||
@@ -632,7 +609,7 @@ CatchAnnotation.prototype = {
|
||||
},
|
||||
__bind: function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
_compileTemplates: function() {
|
||||
var self = this;
|
||||
var self = this;
|
||||
//Change the html tags to functions
|
||||
this.TEMPLATENAMES.forEach(function(templateName) {
|
||||
self.TEMPLATES[templateName] = Handlebars.compile(self.HTMLTEMPLATES[templateName]);
|
||||
@@ -678,6 +655,13 @@ CatchAnnotation.prototype = {
|
||||
});//Change to < and > tags
|
||||
item.plainText = item.plainText.replace(/<\/?[^>]+(>|$)/g, "").replace(' ',''); //remove all the html tags
|
||||
|
||||
item.mediatypeforgrid = {};
|
||||
item.mediatypeforgrid[item.media] = true;
|
||||
|
||||
if (item.mediatypeforgrid.image) {
|
||||
item.thumbnailLink = item.target.thumb;
|
||||
};
|
||||
|
||||
//Flags
|
||||
if(!this.options.flags && typeof item.tags != 'undefined' && item.tags.length > 0){
|
||||
for(var len=item.tags.length, index = len-1; index >= 0; --index){
|
||||
@@ -778,6 +762,26 @@ CatchAnnotation.prototype = {
|
||||
}
|
||||
}
|
||||
},
|
||||
_onZoomToImageBoundsButtonClick: function(evt){
|
||||
var zoomToBounds = $(evt.target).hasClass('zoomToImageBounds')?$(evt.target):$(evt.target).parents('.zoomToImageBounds:first'),
|
||||
osdaId = zoomToBounds.find('.idAnnotation').html(),
|
||||
uri = zoomToBounds.find('.uri').html();
|
||||
|
||||
var allannotations = this.annotator.plugins['Store'].annotations,
|
||||
osda = this.annotator.osda;
|
||||
|
||||
for(var item in allannotations){
|
||||
var an = allannotations[item];
|
||||
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);
|
||||
|
||||
console.log(an.target.container);
|
||||
$('html,body').animate({scrollTop: $("#"+an.target.container).offset().top},
|
||||
'slow');
|
||||
}
|
||||
}
|
||||
},
|
||||
_onQuoteMediaButton: function(evt){
|
||||
var quote = $(evt.target).hasClass('quote')?$(evt.target):$(evt.target).parents('.quote:first'),
|
||||
id = quote.find('.idAnnotation').html(),
|
||||
@@ -1095,13 +1099,10 @@ CatchAnnotation.prototype = {
|
||||
annotation = item.data('annotation');
|
||||
var authorized = permissions.options.userAuthorize('delete', annotation,permissions.user);
|
||||
if(authorized){
|
||||
//annotator.deleteAnnotation(annotation);
|
||||
if(confirm('Would you like to delete this reply?')){
|
||||
annotator.plugins['Store']._apiRequest('destroy', annotation, function(){});
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -101,4 +101,4 @@ Annotator.Plugin.Flagging = (function(_super) {
|
||||
|
||||
return Flagging;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
})(Annotator.Plugin);
|
||||
|
||||
BIN
common/static/js/vendor/ova/images/fullpage_grouphover.png
vendored
Normal file
|
After Width: | Height: | Size: 698 B |
BIN
common/static/js/vendor/ova/images/fullpage_hover.png
vendored
Normal file
|
After Width: | Height: | Size: 831 B |
BIN
common/static/js/vendor/ova/images/fullpage_pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 817 B |
BIN
common/static/js/vendor/ova/images/fullpage_rest.png
vendored
Normal file
|
After Width: | Height: | Size: 698 B |
BIN
common/static/js/vendor/ova/images/home_grouphover.png
vendored
Normal file
|
After Width: | Height: | Size: 672 B |
BIN
common/static/js/vendor/ova/images/home_hover.png
vendored
Normal file
|
After Width: | Height: | Size: 737 B |
BIN
common/static/js/vendor/ova/images/home_pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 741 B |
BIN
common/static/js/vendor/ova/images/home_rest.png
vendored
Normal file
|
After Width: | Height: | Size: 672 B |
BIN
common/static/js/vendor/ova/images/newan_grouphover.png
vendored
Normal file
|
After Width: | Height: | Size: 746 B |
BIN
common/static/js/vendor/ova/images/newan_hover.png
vendored
Normal file
|
After Width: | Height: | Size: 815 B |
BIN
common/static/js/vendor/ova/images/newan_pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 828 B |
BIN
common/static/js/vendor/ova/images/newan_rest.png
vendored
Normal file
|
After Width: | Height: | Size: 746 B |
BIN
common/static/js/vendor/ova/images/next_grouphover.png
vendored
Normal file
|
After Width: | Height: | Size: 656 B |
BIN
common/static/js/vendor/ova/images/next_hover.png
vendored
Normal file
|
After Width: | Height: | Size: 753 B |
BIN
common/static/js/vendor/ova/images/next_pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 752 B |
BIN
common/static/js/vendor/ova/images/next_rest.png
vendored
Normal file
|
After Width: | Height: | Size: 656 B |
BIN
common/static/js/vendor/ova/images/previous_grouphover.png
vendored
Normal file
|
After Width: | Height: | Size: 661 B |
BIN
common/static/js/vendor/ova/images/previous_hover.png
vendored
Normal file
|
After Width: | Height: | Size: 755 B |
BIN
common/static/js/vendor/ova/images/previous_pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 755 B |
BIN
common/static/js/vendor/ova/images/previous_rest.png
vendored
Normal file
|
After Width: | Height: | Size: 661 B |
BIN
common/static/js/vendor/ova/images/zoomin_grouphover.png
vendored
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
common/static/js/vendor/ova/images/zoomin_hover.png
vendored
Normal file
|
After Width: | Height: | Size: 608 B |
BIN
common/static/js/vendor/ova/images/zoomin_pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 615 B |
BIN
common/static/js/vendor/ova/images/zoomin_rest.png
vendored
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
common/static/js/vendor/ova/images/zoomout_grouphover.png
vendored
Normal file
|
After Width: | Height: | Size: 504 B |
BIN
common/static/js/vendor/ova/images/zoomout_hover.png
vendored
Normal file
|
After Width: | Height: | Size: 559 B |
BIN
common/static/js/vendor/ova/images/zoomout_pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 561 B |
BIN
common/static/js/vendor/ova/images/zoomout_rest.png
vendored
Normal file
|
After Width: | Height: | Size: 504 B |
12946
common/static/js/vendor/ova/openseadragon.js
vendored
Normal file
@@ -82,6 +82,7 @@ Annotator.Plugin.Reply = (function(_super) {
|
||||
var string;
|
||||
return self;
|
||||
});
|
||||
field.remove();
|
||||
this.annotation = annotation;
|
||||
//Create the actions for the buttons
|
||||
return ret;
|
||||
|
||||
@@ -38,7 +38,7 @@ Annotator.Plugin.RichText = (function(_super) {
|
||||
}
|
||||
},
|
||||
codemirror: {
|
||||
path: "static/js/vendor"
|
||||
path: "/static/js/vendor"
|
||||
},
|
||||
plugins: "image link codemirror",
|
||||
menubar: false,
|
||||
@@ -78,7 +78,6 @@ Annotator.Plugin.RichText = (function(_super) {
|
||||
|
||||
annotator.subscribe("annotationEditorShown", function(){
|
||||
$(annotator.editor.element).find('.mce-tinymce')[0].style.display='block';
|
||||
$(annotator.editor.element).find('.mce-container').css('z-index',3000000000);
|
||||
annotator.editor.checkOrientation();
|
||||
});
|
||||
annotator.subscribe("annotationEditorHidden", function(){
|
||||
@@ -91,9 +90,6 @@ Annotator.Plugin.RichText = (function(_super) {
|
||||
//set the modification in the textarea of annotator
|
||||
$(editor.element).find('textarea')[0].value = tinymce.activeEditor.getContent();
|
||||
});
|
||||
ed.on('Init', function(ed){
|
||||
$('.mce-container').css('z-index','3090000000000000000');
|
||||
});
|
||||
//New button to add Rubrics of the url https://gteavirtual.org/rubric
|
||||
ed.addButton('rubric', {
|
||||
icon: 'rubric',
|
||||
|
||||
439
common/static/js/vendor/ova/tags-annotator.js
vendored
@@ -1,3 +1,27 @@
|
||||
/*
|
||||
HighlightTags Annotator Plugin v1.0 (https://github.com/lduarte1991/tags-annotator)
|
||||
Copyright (C) 2014 Luis F Duarte
|
||||
License: https://github.com/lduarte1991/tags-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.
|
||||
*/
|
||||
/*===============================================================================
|
||||
===============================================================================
|
||||
===============================================================================
|
||||
===============================================================================
|
||||
==============================================================================*/
|
||||
/*
|
||||
* jQuery Plugin: Tokenizing Autocomplete Text Entry
|
||||
* Version 1.6.0
|
||||
@@ -11,7 +35,7 @@
|
||||
(function ($) {
|
||||
// Default settings
|
||||
var DEFAULT_SETTINGS = {
|
||||
// Search settings
|
||||
// Search settings
|
||||
method: "GET",
|
||||
contentType: "json",
|
||||
queryParam: "q",
|
||||
@@ -20,33 +44,33 @@ var DEFAULT_SETTINGS = {
|
||||
propertyToSearch: "name",
|
||||
jsonContainer: null,
|
||||
|
||||
// Display settings
|
||||
// Display settings
|
||||
hintText: "Type in a search term",
|
||||
noResultsText: "No results",
|
||||
noResultsText: "Not Found. Hit ENTER to add a personal tag.",
|
||||
searchingText: "Searching...",
|
||||
deleteText: "×",
|
||||
animateDropdown: true,
|
||||
|
||||
// Tokenization settings
|
||||
// Tokenization settings
|
||||
tokenLimit: null,
|
||||
tokenDelimiter: ",",
|
||||
preventDuplicates: false,
|
||||
|
||||
// Output settings
|
||||
// Output settings
|
||||
tokenValue: "id",
|
||||
|
||||
// Prepopulation settings
|
||||
// Prepopulation settings
|
||||
prePopulate: null,
|
||||
processPrePopulate: false,
|
||||
|
||||
// Manipulation settings
|
||||
// Manipulation settings
|
||||
idPrefix: "token-input-",
|
||||
|
||||
// Formatters
|
||||
// Formatters
|
||||
resultsFormatter: function(item){ return "<li>" + item[this.propertyToSearch]+ "</li>" },
|
||||
tokenFormatter: function(item) { return "<li><p>" + item[this.propertyToSearch] + "</p></li>" },
|
||||
|
||||
// Callbacks
|
||||
// Callbacks
|
||||
onResult: null,
|
||||
onAdd: null,
|
||||
onDelete: null,
|
||||
@@ -115,8 +139,8 @@ var methods = {
|
||||
return this;
|
||||
},
|
||||
get: function() {
|
||||
return this.data("tokenInputObject").getTokens();
|
||||
}
|
||||
return this.data("tokenInputObject").getTokens();
|
||||
}
|
||||
}
|
||||
|
||||
// Expose the .tokenInput function to jQuery as a plugin
|
||||
@@ -271,7 +295,10 @@ $.TokenList = function (input, url_or_data, settings) {
|
||||
add_token($(selected_dropdown_item).data("tokeninput"));
|
||||
hidden_input.change();
|
||||
return false;
|
||||
}
|
||||
} else{
|
||||
add_token({id:$(this).val(), name:$(this).val()});
|
||||
hidden_input.change();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.ESCAPE:
|
||||
@@ -414,8 +441,8 @@ $.TokenList = function (input, url_or_data, settings) {
|
||||
}
|
||||
|
||||
this.getTokens = function() {
|
||||
return saved_tokens;
|
||||
}
|
||||
return saved_tokens;
|
||||
}
|
||||
|
||||
//
|
||||
// Private functions
|
||||
@@ -866,232 +893,232 @@ var _ref,
|
||||
__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.HighlightTags = (function(_super) {
|
||||
__extends(HighlightTags, _super);
|
||||
|
||||
HighlightTags.prototype.options = null;
|
||||
|
||||
__extends(HighlightTags, _super);
|
||||
|
||||
function HighlightTags(element,options) {
|
||||
this.pluginSubmit = __bind(this.pluginSubmit, this);
|
||||
this.updateViewer = __bind(this.updateViewer, this);
|
||||
this.colorize = __bind(this.colorize, this);
|
||||
this.updateField = __bind(this.updateField, this);
|
||||
HighlightTags.prototype.options = null;
|
||||
|
||||
|
||||
function HighlightTags(element,options) {
|
||||
this.pluginSubmit = __bind(this.pluginSubmit, this);
|
||||
this.updateViewer = __bind(this.updateViewer, this);
|
||||
this.colorize = __bind(this.colorize, this);
|
||||
this.updateField = __bind(this.updateField, this);
|
||||
|
||||
this.options = options;
|
||||
_ref = HighlightTags.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
_ref = HighlightTags.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
//example variables to be used to receive input in the annotator view
|
||||
HighlightTags.prototype.field = null;
|
||||
HighlightTags.prototype.input = null;
|
||||
HighlightTags.prototype.colors = null;
|
||||
HighlightTags.prototype.isFirstTime = true;
|
||||
HighlightTags.prototype.field = null;
|
||||
HighlightTags.prototype.input = null;
|
||||
HighlightTags.prototype.colors = null;
|
||||
HighlightTags.prototype.isFirstTime = true;
|
||||
|
||||
//this function will initialize the plug in. Create your fields here in the editor and viewer.
|
||||
HighlightTags.prototype.pluginInit = function() {
|
||||
console.log("HighlightTags-pluginInit");
|
||||
//Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.field = this.annotator.editor.addField({
|
||||
type: 'input',
|
||||
load: this.updateField,
|
||||
submit: this.pluginSubmit,
|
||||
});
|
||||
|
||||
|
||||
|
||||
var self = this;
|
||||
|
||||
var newfield = Annotator.$('<li class="annotator-item">'+ "<div><input placeholder =\"Add tags\" type=\"text\" id=\"tag-input\" name=\"tags\" /></div>"+'</li>');
|
||||
console.log("HighlightTags-pluginInit");
|
||||
//Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.field = this.annotator.editor.addField({
|
||||
type: 'input',
|
||||
load: this.updateField,
|
||||
submit: this.pluginSubmit,
|
||||
});
|
||||
|
||||
|
||||
|
||||
var self = this;
|
||||
|
||||
var newfield = Annotator.$('<li class="annotator-item">'+ "<div><input placeholder =\"Add tags\" type=\"text\" id=\"tag-input\" name=\"tags\" /></div>"+'</li>');
|
||||
Annotator.$(self.field).replaceWith(newfield);
|
||||
self.field=newfield[0];
|
||||
|
||||
//
|
||||
|
||||
|
||||
//-- Viewer
|
||||
var newview = this.annotator.viewer.addField({
|
||||
load: this.updateViewer,
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
HighlightTags.prototype.getHighlightTags = function(){
|
||||
if (typeof this.options.tag != 'undefined') {
|
||||
var self = this;
|
||||
var final = {}, prelim = this.options.tag.split(",");
|
||||
prelim.forEach(function(item){
|
||||
var temp = item.split(":");
|
||||
final[temp[0]] = self.getRGB(temp[1]);
|
||||
});
|
||||
return final;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
HighlightTags.prototype.getRGB = function(item){
|
||||
function getColorValues( color ){
|
||||
var values = { red:null, green:null, blue:null, alpha:null };
|
||||
if( typeof color == 'string' ){
|
||||
/* hex */
|
||||
if( color.indexOf('#') === 0 ){
|
||||
color = color.substr(1)
|
||||
if( color.length == 3 )
|
||||
values = {
|
||||
red: parseInt( color[0]+color[0], 16 ),
|
||||
green: parseInt( color[1]+color[1], 16 ),
|
||||
blue: parseInt( color[2]+color[2], 16 ),
|
||||
alpha: .3
|
||||
}
|
||||
else
|
||||
values = {
|
||||
red: parseInt( color.substr(0,2), 16 ),
|
||||
green: parseInt( color.substr(2,2), 16 ),
|
||||
blue: parseInt( color.substr(4,2), 16 ),
|
||||
alpha: .3
|
||||
}
|
||||
/* rgb */
|
||||
}else if( color.indexOf('rgb(') === 0 ){
|
||||
var pars = color.indexOf(',');
|
||||
values = {
|
||||
red: parseInt(color.substr(4,pars)),
|
||||
green: parseInt(color.substr(pars+1,color.indexOf(',',pars))),
|
||||
blue: parseInt(color.substr(color.indexOf(',',pars+1)+1,color.indexOf(')'))),
|
||||
alpha: .3
|
||||
}
|
||||
/* rgba */
|
||||
}else if( color.indexOf('rgba(') === 0 ){
|
||||
var pars = color.indexOf(','),
|
||||
repars = color.indexOf(',',pars+1);
|
||||
values = {
|
||||
red: parseInt(color.substr(5,pars)),
|
||||
green: parseInt(color.substr(pars+1,repars)),
|
||||
blue: parseInt(color.substr(color.indexOf(',',pars+1)+1,color.indexOf(',',repars))),
|
||||
alpha: parseFloat(color.substr(color.indexOf(',',repars+1)+1,color.indexOf(')')))
|
||||
}
|
||||
/* verbous */
|
||||
}else{
|
||||
var stdCol = { acqua:'#0ff', teal:'#008080', blue:'#00f', navy:'#000080',
|
||||
yellow:'#ff0', olive:'#808000', lime:'#0f0', green:'#008000',
|
||||
fuchsia:'#f0f', purple:'#800080', red:'#f00', maroon:'#800000',
|
||||
white:'#fff', gray:'#808080', silver:'#c0c0c0', black:'#000' };
|
||||
if( stdCol[color]!=undefined )
|
||||
values = getColorValues(stdCol[color]);
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
return getColorValues(item)
|
||||
}
|
||||
|
||||
HighlightTags.prototype.colorize = function(){
|
||||
|
||||
var annotations = Array.prototype.slice.call($(".annotator-hl"));
|
||||
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 !== {}) {
|
||||
|
||||
for(var index = 0; index < anns.tags.length; ++index){
|
||||
|
||||
if (typeof this.colors[anns.tags[index]] != "undefined") {
|
||||
var finalcolor = this.colors[anns.tags[index]];
|
||||
$(annotations[annNum]).css("background","rgba("+finalcolor.red+","+finalcolor.green+","+finalcolor.blue+",0.3");
|
||||
}else{
|
||||
$(annotations[annNum]).css("background","");
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
$(annotations[annNum]).css("background","");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HighlightTags.prototype.updateField = function(field, annotation){
|
||||
|
||||
|
||||
|
||||
//-- Viewer
|
||||
var newview = this.annotator.viewer.addField({
|
||||
load: this.updateViewer,
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
HighlightTags.prototype.getHighlightTags = function(){
|
||||
if (typeof this.options.tag != 'undefined') {
|
||||
var self = this;
|
||||
var final = {}, prelim = this.options.tag.split(",");
|
||||
prelim.forEach(function(item){
|
||||
var temp = item.split(":");
|
||||
final[temp[0]] = self.getRGB(temp[1]);
|
||||
});
|
||||
return final;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
HighlightTags.prototype.getRGB = function(item){
|
||||
function getColorValues( color ){
|
||||
var values = { red:null, green:null, blue:null, alpha:null };
|
||||
if( typeof color == 'string' ){
|
||||
/* hex */
|
||||
if( color.indexOf('#') === 0 ){
|
||||
color = color.substr(1)
|
||||
if( color.length == 3 )
|
||||
values = {
|
||||
red: parseInt( color[0]+color[0], 16 ),
|
||||
green: parseInt( color[1]+color[1], 16 ),
|
||||
blue: parseInt( color[2]+color[2], 16 ),
|
||||
alpha: .3
|
||||
}
|
||||
else
|
||||
values = {
|
||||
red: parseInt( color.substr(0,2), 16 ),
|
||||
green: parseInt( color.substr(2,2), 16 ),
|
||||
blue: parseInt( color.substr(4,2), 16 ),
|
||||
alpha: .3
|
||||
}
|
||||
/* rgb */
|
||||
}else if( color.indexOf('rgb(') === 0 ){
|
||||
var pars = color.indexOf(',');
|
||||
values = {
|
||||
red: parseInt(color.substr(4,pars)),
|
||||
green: parseInt(color.substr(pars+1,color.indexOf(',',pars))),
|
||||
blue: parseInt(color.substr(color.indexOf(',',pars+1)+1,color.indexOf(')'))),
|
||||
alpha: .3
|
||||
}
|
||||
/* rgba */
|
||||
}else if( color.indexOf('rgba(') === 0 ){
|
||||
var pars = color.indexOf(','),
|
||||
repars = color.indexOf(',',pars+1);
|
||||
values = {
|
||||
red: parseInt(color.substr(5,pars)),
|
||||
green: parseInt(color.substr(pars+1,repars)),
|
||||
blue: parseInt(color.substr(color.indexOf(',',pars+1)+1,color.indexOf(',',repars))),
|
||||
alpha: parseFloat(color.substr(color.indexOf(',',repars+1)+1,color.indexOf(')')))
|
||||
}
|
||||
/* verbous */
|
||||
}else{
|
||||
var stdCol = { acqua:'#0ff', teal:'#008080', blue:'#00f', navy:'#000080',
|
||||
yellow:'#ff0', olive:'#808000', lime:'#0f0', green:'#008000',
|
||||
fuchsia:'#f0f', purple:'#800080', red:'#f00', maroon:'#800000',
|
||||
white:'#fff', gray:'#808080', silver:'#c0c0c0', black:'#000' };
|
||||
if( stdCol[color]!=undefined )
|
||||
values = getColorValues(stdCol[color]);
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
return getColorValues(item)
|
||||
}
|
||||
|
||||
HighlightTags.prototype.colorize = function(){
|
||||
|
||||
var annotations = Array.prototype.slice.call($(".annotator-hl"));
|
||||
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 !== {}) {
|
||||
|
||||
for(var index = 0; index < anns.tags.length; ++index){
|
||||
|
||||
if (typeof this.colors[anns.tags[index]] != "undefined") {
|
||||
var finalcolor = this.colors[anns.tags[index]];
|
||||
$(annotations[annNum]).css("background","rgba("+finalcolor.red+","+finalcolor.green+","+finalcolor.blue+",0.3");
|
||||
}else{
|
||||
$(annotations[annNum]).css("background","");
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
$(annotations[annNum]).css("background","");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HighlightTags.prototype.updateField = function(field, annotation){
|
||||
|
||||
|
||||
if(this.isFirstTime){
|
||||
var tags = this.options.tag.split(",");
|
||||
var tokensavailable = [];
|
||||
var tokensavailable = [];
|
||||
tags.forEach (function(tagnames){
|
||||
lonename = tagnames.split(":");
|
||||
|
||||
tokensavailable.push({'id': lonename[0], 'name':lonename[0]});
|
||||
});
|
||||
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');
|
||||
$('#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});
|
||||
}
|
||||
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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//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 = [];
|
||||
tokens.forEach(function(element){
|
||||
tag = element.firstChild.firstChild;
|
||||
arr.push(tag.nodeValue);
|
||||
});
|
||||
annotation.tags = arr;
|
||||
var tokens = Array.prototype.slice.call($(".token-input-input-token").parent().find('.token-input-token'));
|
||||
var arr = [];
|
||||
tokens.forEach(function(element){
|
||||
tag = element.firstChild.firstChild;
|
||||
arr.push(tag.nodeValue);
|
||||
});
|
||||
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.
|
||||
HighlightTags.prototype.updateViewer = function(field, annotation) {
|
||||
if (typeof annotation.tags != "undefined") {
|
||||
if (annotation.tags.length == 0) {
|
||||
$(field).remove();
|
||||
return;
|
||||
}
|
||||
var nonFlagTags = true;
|
||||
HighlightTags.prototype.updateViewer = function(field, annotation) {
|
||||
if (typeof annotation.tags != "undefined") {
|
||||
if (annotation.tags.length == 0) {
|
||||
$(field).remove();
|
||||
return;
|
||||
}
|
||||
var nonFlagTags = true;
|
||||
var tokenList = "<ul class=\"token-input-list\">";
|
||||
for (tagnum = 0; tagnum < annotation.tags.length; ++tagnum){
|
||||
if (typeof this.annotator.plugins["Flagging"] != 'undefined') {
|
||||
if (annotation.tags[tagnum].indexOf("flagged-")==-1){
|
||||
tokenList += "<li class=\"token-input-token\"><p>"+ annotation.tags[tagnum]+"</p></span></li>";
|
||||
nonFlagTags = false;
|
||||
}
|
||||
} else{
|
||||
tokenList += "<li class=\"token-input-token\"><p>"+ annotation.tags[tagnum]+"</p></span></li>";
|
||||
}
|
||||
}
|
||||
for (tagnum = 0; tagnum < annotation.tags.length; ++tagnum){
|
||||
if (typeof this.annotator.plugins["Flagging"] != 'undefined') {
|
||||
if (annotation.tags[tagnum].indexOf("flagged-")==-1){
|
||||
tokenList += "<li class=\"token-input-token\"><p>"+ annotation.tags[tagnum]+"</p></span></li>";
|
||||
nonFlagTags = false;
|
||||
}
|
||||
} else{
|
||||
tokenList += "<li class=\"token-input-token\"><p>"+ annotation.tags[tagnum]+"</p></span></li>";
|
||||
}
|
||||
}
|
||||
tokenList += "</ul>";
|
||||
$(field).append(tokenList);
|
||||
if (nonFlagTags) {
|
||||
$(field).remove();
|
||||
}
|
||||
|
||||
} else{
|
||||
$(field).remove();
|
||||
}
|
||||
if (nonFlagTags) {
|
||||
$(field).remove();
|
||||
}
|
||||
|
||||
} else{
|
||||
$(field).remove();
|
||||
}
|
||||
this.annotator.publish("finishedDrawingTags");
|
||||
}
|
||||
|
||||
|
||||
@@ -845,6 +845,8 @@ main_vendor_js = [
|
||||
'js/vendor/ova/tags-annotator.js',
|
||||
'js/vendor/ova/flagging-annotator.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/catch/js/catch.js',
|
||||
'js/vendor/ova/catch/js/handlebars-1.1.2.js',
|
||||
|
||||
210
lms/templates/imageannotation.html
Normal file
@@ -0,0 +1,210 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
|
||||
<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">
|
||||
<%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)}" />
|
||||
</div>
|
||||
<div id="catchDIV">
|
||||
## Translators: Notes below refer to annotations. They wil later be put under a "Notes" section.
|
||||
<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>
|
||||